__init__.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. #!/usr/bin/python2 -O
  2. # vim: fileencoding=utf-8
  3. #
  4. # The Qubes OS Project, https://www.qubes-os.org/
  5. #
  6. # Copyright (C) 2015 Joanna Rutkowska <joanna@invisiblethingslab.com>
  7. # Copyright (C) 2015 Wojtek Porczyk <woju@invisiblethingslab.com>
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License along
  20. # with this program; if not, write to the Free Software Foundation, Inc.,
  21. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22. #
  23. '''Qubes' command line tools
  24. '''
  25. import argparse
  26. import importlib
  27. import os
  28. class PropertyAction(argparse.Action):
  29. '''Action for argument parser that stores a property.'''
  30. # pylint: disable=redefined-builtin
  31. def __init__(self,
  32. option_strings,
  33. dest,
  34. metavar='NAME=VALUE',
  35. required=False,
  36. help='set property to a value'):
  37. super(PropertyAction, self).__init__(option_strings, 'properties',
  38. metavar=metavar, default={}, help=help)
  39. def __call__(self, parser, namespace, values, option_string=None):
  40. try:
  41. prop, value = values.split('=', 1)
  42. except ValueError:
  43. parser.error('invalid property token: {!r}'.format(token))
  44. getattr(namespace, self.dest)[prop] = value
  45. class SinglePropertyAction(argparse.Action):
  46. '''Action for argument parser that stores a property.'''
  47. # pylint: disable=redefined-builtin
  48. def __init__(self,
  49. option_strings,
  50. dest,
  51. metavar='VALUE',
  52. const=None,
  53. nargs=None,
  54. required=False,
  55. help=None):
  56. if help is None:
  57. help = 'set {!r} property to a value'.format(dest)
  58. if const is not None:
  59. help += ' {!r}'.format(const)
  60. if const is not None:
  61. nargs = 0
  62. super(SinglePropertyAction, self).__init__(option_strings, 'properties',
  63. metavar=metavar, help=help, default={}, const=const,
  64. nargs=nargs)
  65. self.name = dest
  66. def __call__(self, parser, namespace, values, option_string=None):
  67. getattr(namespace, self.dest)[self.name] = values \
  68. if self.const is None else self.const
  69. # TODO --verbose, logger setup
  70. def get_parser_base(want_force_root=False, **kwargs):
  71. '''Get base parser with options common to all Qubes OS tools.
  72. :param bool want_force_root: add ``--force-root`` option
  73. *kwargs* are passed to :py:class:`argparser.ArgumentParser`.
  74. Currently supported options: ``--force-root`` (optional), ``--xml``.
  75. '''
  76. parser = argparse.ArgumentParser(**kwargs)
  77. parser.add_argument('--xml', metavar='XMLFILE',
  78. action='store',
  79. help='Qubes OS store file')
  80. if want_force_root:
  81. parser.add_argument('--force-root',
  82. action='store_true', default=False,
  83. help='Force to run as root.')
  84. return parser
  85. def get_parser_for_command(command):
  86. '''Get parser for given qvm-tool.
  87. :param str command: command name
  88. :rtype: argparse.ArgumentParser
  89. :raises ImportError: when command's module is not found
  90. :raises AttributeError: when parser was not found
  91. '''
  92. module = importlib.import_module(
  93. '.' + command.replace('-', '_'), 'qubes.tools')
  94. try:
  95. parser = module.parser
  96. except AttributeError:
  97. try:
  98. parser = module.get_parser()
  99. except AttributeError:
  100. raise AttributeError('cannot find parser in module')
  101. return parser
  102. def dont_run_as_root(parser, args):
  103. '''Prevent running as root.
  104. :param argparse.ArgumentParser parser: parser on which we invoke error
  105. :param argparse.Namespace args: if there is ``.force_root`` attribute set \
  106. to true, run anyway
  107. :return: If we should back off
  108. :rtype bool:
  109. '''
  110. try:
  111. euid = os.geteuid()
  112. except AttributeError: # no geteuid(), probably NT
  113. return
  114. if euid == 0 and not args.force_root:
  115. parser.error('refusing to run as root; add --force-root to override')