vmexec.py 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import sys
  2. import os
  3. import re
  4. class DecodeError(ValueError):
  5. pass
  6. ESCAPE_RE = re.compile(br'--|-([A-F0-9]{2})')
  7. def decode_part(part):
  8. if not re.match(r'^[a-zA-Z0-9._-]*$', part):
  9. raise DecodeError('illegal characters found')
  10. part = part.encode('ascii')
  11. # Check if no '-' remains outside of legal escape sequences.
  12. if b'-' in ESCAPE_RE.sub(b'', part):
  13. raise DecodeError("'-' can be used only in '-HH' or '--'")
  14. def convert(m):
  15. if m.group(0) == b'--':
  16. return b'-'
  17. num = int(m.group(1), 16)
  18. return bytes([num])
  19. return ESCAPE_RE.sub(convert, part)
  20. def decode(arg):
  21. '''
  22. Decode the argument for executing. The format is as follows:
  23. - individual parts are split by '+'
  24. - bytes are escaped as '-HH' (where HH is hex code, capital letters only)
  25. - literal '-' is encoded as '--'
  26. - otherwise, only [a-zA-Z0-9._] are allowed
  27. :param arg: argument, as a string
  28. :returns: list of exec arguments (each as bytes)
  29. '''
  30. return [decode_part(part) for part in arg.split('+')]
  31. def main(argv=sys.argv):
  32. if len(argv) != 2:
  33. print('This service requires exactly one argument', file=sys.stderr)
  34. exit(1)
  35. try:
  36. command = decode(argv[1])
  37. except DecodeError as e:
  38. print('Decode error: {}'.format(e), file=sys.stderr)
  39. exit(1)
  40. os.execvp(command[0], command)
  41. if __name__ == '__main__':
  42. main()