__init__.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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. import qubes.log
  29. class PropertyAction(argparse.Action):
  30. '''Action for argument parser that stores a property.'''
  31. # pylint: disable=redefined-builtin
  32. def __init__(self,
  33. option_strings,
  34. dest,
  35. metavar='NAME=VALUE',
  36. required=False,
  37. help='set property to a value'):
  38. super(PropertyAction, self).__init__(option_strings, 'properties',
  39. metavar=metavar, default={}, help=help)
  40. def __call__(self, parser, namespace, values, option_string=None):
  41. try:
  42. prop, value = values.split('=', 1)
  43. except ValueError:
  44. parser.error('invalid property token: {!r}'.format(token))
  45. getattr(namespace, self.dest)[prop] = value
  46. class SinglePropertyAction(argparse.Action):
  47. '''Action for argument parser that stores a property.'''
  48. # pylint: disable=redefined-builtin
  49. def __init__(self,
  50. option_strings,
  51. dest,
  52. metavar='VALUE',
  53. const=None,
  54. nargs=None,
  55. required=False,
  56. help=None):
  57. if help is None:
  58. help = 'set {!r} property to a value'.format(dest)
  59. if const is not None:
  60. help += ' {!r}'.format(const)
  61. if const is not None:
  62. nargs = 0
  63. super(SinglePropertyAction, self).__init__(option_strings, 'properties',
  64. metavar=metavar, help=help, default={}, const=const,
  65. nargs=nargs)
  66. self.name = dest
  67. def __call__(self, parser, namespace, values, option_string=None):
  68. getattr(namespace, self.dest)[self.name] = values \
  69. if self.const is None else self.const
  70. # TODO --verbose, logger setup
  71. def get_parser_base(want_force_root=False, **kwargs):
  72. '''Get base parser with options common to all Qubes OS tools.
  73. :param bool want_force_root: add ``--force-root`` option
  74. *kwargs* are passed to :py:class:`argparser.ArgumentParser`.
  75. Currently supported options: ``--force-root`` (optional), ``--xml``.
  76. '''
  77. parser = argparse.ArgumentParser(**kwargs)
  78. parser.add_argument('--xml', metavar='XMLFILE',
  79. action='store',
  80. help=argparse.SUPPRESS)
  81. parser.add_argument('--verbose', '-v',
  82. action='count',
  83. help='increase verbosity')
  84. parser.add_argument('--quiet', '-q',
  85. action='count',
  86. help='decrease verbosity')
  87. if want_force_root:
  88. parser.add_argument('--force-root',
  89. action='store_true', default=False,
  90. help='Force to run as root.')
  91. parser.set_defaults(verbose=1, quiet=0)
  92. return parser
  93. def get_parser_for_command(command):
  94. '''Get parser for given qvm-tool.
  95. :param str command: command name
  96. :rtype: argparse.ArgumentParser
  97. :raises ImportError: when command's module is not found
  98. :raises AttributeError: when parser was not found
  99. '''
  100. module = importlib.import_module(
  101. '.' + command.replace('-', '_'), 'qubes.tools')
  102. try:
  103. parser = module.parser
  104. except AttributeError:
  105. try:
  106. parser = module.get_parser()
  107. except AttributeError:
  108. raise AttributeError('cannot find parser in module')
  109. return parser
  110. def dont_run_as_root(parser, args):
  111. '''Prevent running as root.
  112. :param argparse.ArgumentParser parser: parser on which we invoke error
  113. :param argparse.Namespace args: if there is ``.force_root`` attribute set \
  114. to true, run anyway
  115. :return: If we should back off
  116. :rtype bool:
  117. '''
  118. try:
  119. euid = os.geteuid()
  120. except AttributeError: # no geteuid(), probably NT
  121. return
  122. if euid == 0 and not args.force_root:
  123. parser.error('refusing to run as root; add --force-root to override')
  124. def set_verbosity(parser, args):
  125. '''Apply a verbosity setting.
  126. This is done by configuring global logging.
  127. :param argparse.ArgumentParser parser: command parser
  128. :param argparse.Namespace args: args as parsed by parser
  129. '''
  130. verbose = args.verbose - args.quiet
  131. if verbose >= 2:
  132. qubes.log.enable_debug()
  133. elif verbose >= 1:
  134. qubes.log.enable()