pvl/args.py
changeset 224 ed410776effd
parent 223 6842794c20e8
child 225 3c2d0dd42045
equal deleted inserted replaced
223:6842794c20e8 224:ed410776effd
     1 """
       
     2     CLI argument handling; common stuff: logging
       
     3 """
       
     4 
       
     5 import optparse
       
     6 import logging
       
     7 
       
     8 import pwd, grp, os, sys
       
     9 
       
    10 import logging; log = logging.getLogger('pvl.args')
       
    11 
       
    12 def parser (parser) :
       
    13     """
       
    14         Return an optparse.OptionGroup.
       
    15     """
       
    16 
       
    17     general = optparse.OptionGroup(parser, "General options")
       
    18 
       
    19     general.add_option('-q', '--quiet',     dest='loglevel', action='store_const', const=logging.ERROR, help="Less output")
       
    20     general.add_option('-v', '--verbose',   dest='loglevel', action='store_const', const=logging.INFO,  help="More output")
       
    21     general.add_option('-D', '--debug',     dest='loglevel', action='store_const', const=logging.DEBUG, help="Even more output")
       
    22     general.add_option('--log-file',                                                                    help="Log to file")
       
    23     general.add_option('--debug-module',    action='append', metavar='MODULE', 
       
    24             help="Enable logging for the given logger/module name")
       
    25     
       
    26     general.add_option('--uid',             help="Change uid")
       
    27     general.add_option('--gid',             help="Change gid")
       
    28 
       
    29     # defaults
       
    30     parser.set_defaults(
       
    31         logname             = parser.prog,
       
    32         loglevel            = logging.WARN,
       
    33         debug_module        = [],
       
    34     )
       
    35  
       
    36     return general
       
    37 
       
    38 def options (**options) :
       
    39     """
       
    40         Synthensise options.
       
    41     """
       
    42 
       
    43     return optparse.Values(options)
       
    44 
       
    45 def apply_setid (options, rootok=None) :
       
    46     """
       
    47         Drop privileges if running as root.
       
    48 
       
    49         XXX: this feature isn't very useful (import-time issues etc), but in certain cases (syslog-ng -> python),
       
    50         it's difficult to avoid this without some extra wrapper tool..?
       
    51     """
       
    52 
       
    53     # --uid -> pw
       
    54     if not options.uid :
       
    55         pw = None
       
    56     elif options.uid.isdigit() :
       
    57         pw = pwd.getpwuid(int(options.uid))
       
    58     else :
       
    59         pw = pwd.getpwnam(options.uid)
       
    60 
       
    61     # --gid -> gr
       
    62     if not options.gid and not pw :
       
    63         gr = None
       
    64     elif not options.gid :
       
    65         gr = grp.getgrgid(pw.pw_gid)
       
    66     elif options.gid.isdigit() :
       
    67         gr = grp.getgrgid(str(options.gid))
       
    68     else :
       
    69         gr = grp.getgrnam(options.gid)
       
    70     
       
    71     if gr :
       
    72         # XXX: secondary groups? seem to get cleared
       
    73         log.info("setgid: %s: %s", gr.gr_name, gr.gr_gid)
       
    74         os.setgid(gr.gr_gid)
       
    75 
       
    76     if pw :
       
    77         log.info("setuid: %s: %s", pw.pw_name, pw.pw_uid)
       
    78         os.setuid(pw.pw_uid)
       
    79     
       
    80     elif os.getuid() == 0 :
       
    81         if rootok :
       
    82             log.info("running as root")
       
    83         else :
       
    84             log.error("refusing to run as root, use --uid 0 to override")
       
    85             sys.exit(2)
       
    86 
       
    87 def apply (options, logname=None, rootok=True) :
       
    88     """
       
    89         Apply the optparse options.
       
    90     """
       
    91 
       
    92     if logname :
       
    93         prefix = options.logname + ': '
       
    94     else :
       
    95         prefix = ''
       
    96 
       
    97     # configure
       
    98     logging.basicConfig(
       
    99         # XXX: log Class.__init__ as Class, not __init__?
       
   100         format      = prefix + '%(name)-20s: %(levelname)5s %(funcName)s: %(message)s',
       
   101         level       = options.loglevel,
       
   102         filename    = options.log_file,
       
   103     )
       
   104 
       
   105     # TODO: use --quiet for stdout output?
       
   106     options.quiet = options.loglevel > logging.WARN
       
   107     
       
   108     if options.uid or options.gid or not rootok :
       
   109         # set uid/gid
       
   110         apply_setid(options, rootok=rootok)
       
   111 
       
   112     # enable debugging for specific targets
       
   113     for logger in options.debug_module :
       
   114         logging.getLogger(logger).setLevel(logging.DEBUG)
       
   115