diff --git a/tools/win_admin.py b/tools/win_admin.py new file mode 100644 index 0000000..2d89488 --- /dev/null +++ b/tools/win_admin.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# -*- coding: utf-8 + +# (C) COPYRIGHT © Preston Landers 2010 +# Released under the same license as Python 2.6.5 + + +import sys +import os +import traceback +import types + +import win32api +import win32con +import win32event +import win32process + +from win32com.shell.shell import ShellExecuteEx +from win32com.shell import shellcon + + +def isUserAdmin(): + + if os.name == 'nt': + import ctypes + # WARNING: requires Windows XP SP2 or higher! + try: + return ctypes.windll.shell32.IsUserAnAdmin() + except: + traceback.print_exc() + print "Admin check failed, assuming not an admin." + return False + elif os.name == 'posix': + # Check for root on Posix + return os.getuid() == 0 + else: + raise RuntimeError, "Unsupported operating system for this module: %s" % (os.name,) + + +def runAsAdmin(cmdLine=None, wait=True): + + if os.name != 'nt': + raise RuntimeError, "This function is only implemented on Windows." + + python_exe = sys.executable + + if cmdLine is None: + # cmdLine = [python_exe] + sys.argv + cmdLine = sys.argv + elif type(cmdLine) not in (types.TupleType, types.ListType): + raise ValueError("cmdLine is not a sequence.") + + cmd = '"%s"' % (cmdLine[0],) + # XXX TODO: isn't there a function or something we can call to massage command line params? + params = " ".join(['"%s"' % (x,) for x in cmdLine[1:]]) + cmdDir = '' + showCmd = win32con.SW_SHOWNORMAL + #showCmd = win32con.SW_HIDE + lpVerb = 'runas' # causes UAC elevation prompt. + + # print "Running", cmd, params + + # ShellExecute() doesn't seem to allow us to fetch the PID or handle + # of the process, so we can't get anything useful from it. Therefore + # the more complex ShellExecuteEx() must be used. + + # procHandle = win32api.ShellExecute(0, lpVerb, cmd, params, cmdDir, showCmd) + + procInfo = ShellExecuteEx(nShow=showCmd, + fMask=shellcon.SEE_MASK_NOCLOSEPROCESS, + lpVerb=lpVerb, + lpFile=cmd, + lpParameters=params) + + if wait: + procHandle = procInfo['hProcess'] + obj = win32event.WaitForSingleObject(procHandle, win32event.INFINITE) + rc = win32process.GetExitCodeProcess(procHandle) + #print "Process handle %s returned code %s" % (procHandle, rc) + else: + rc = None + + return rc + + +def test(): + rc = 0 + if not isUserAdmin(): + print "You're not an admin.", os.getpid(), "params: ", sys.argv + #rc = runAsAdmin(["c:\\Windows\\notepad.exe"]) + rc = runAsAdmin() + else: + print "You are an admin!", os.getpid(), "params: ", sys.argv + rc = 0 + x = raw_input('Press Enter to exit.') + return rc + + +if __name__ == "__main__": + sys.exit(test()) diff --git a/updater.py b/updater.py index 1d65523..52dc037 100644 --- a/updater.py +++ b/updater.py @@ -32,6 +32,8 @@ import psutil +from tools import full_stack, win_admin + class CopyToLogger(object): """ @@ -57,14 +59,6 @@ def write(self, buf): for line in buf.rstrip().splitlines(): self.logger.log(self.log_level, line.rstrip()) - # if buf == '\n': - # self.orig_output.write(buf) - # else: - # if isinstance(buf, str): - # buf = unicode(buf, u'utf-8') - # for line in buf.rstrip().splitlines(): - # self.logger.log(self.log_level, line.rstrip()) - def __getattr__(self, name): return self.orig_output.__getattribute__(name) # pass all other methods to original fd @@ -194,26 +188,41 @@ def main(): if __name__ == "__main__": - os.chdir(os.path.dirname(sys.argv[0])) - - parser = argparse.ArgumentParser(description="Updater component for Woofer player. Script take downloaded package " - "and updates files in Woofer directory." - "This script should be always used only by Woofer player!") - parser.add_argument("installDir", type=str, - help="Where Woofer player files are stored") - parser.add_argument('pid', type=int, - help="PID of Woofer player process") - parser.add_argument('-r', '--restart', action='store_true', - help="ReOpen Woofer after update") - args = parser.parse_args() - - args.installDir = args.installDir.decode(sys.getfilesystemencoding()) # utf8 support - if not os.path.isdir(args.installDir): - raise Exception("Install dir '%s' does NOT exist!" % args.installDir) + if not win_admin.isUserAdmin(): + print "Have no admin rights, elevating rights now..." + win_admin.runAsAdmin() + print "Admin script launched, exit 0" - logger = setup_logging(log_dir=os.path.join(args.installDir, "log")) - - try: - main() - finally: - time.sleep(3) + else: + exception = False + try: + os.chdir(os.path.dirname(sys.argv[0])) + + parser = argparse.ArgumentParser(description="Updater component for Woofer player. Script take downloaded package " + "and updates files in Woofer directory." + "This script should be always used only by Woofer player!") + parser.add_argument("installDir", type=str, + help="Where Woofer player files are stored") + parser.add_argument('pid', type=int, + help="PID of Woofer player process") + parser.add_argument('-r', '--restart', action='store_true', + help="ReOpen Woofer after update") + args = parser.parse_args() + + args.installDir = args.installDir.decode(sys.getfilesystemencoding()) # utf8 support + if not os.path.isdir(args.installDir): + raise Exception("Install dir '%s' does NOT exist!" % args.installDir) + + logger = setup_logging(log_dir=os.path.join(args.installDir, "log")) + main() + + except Exception: + exception = True + print full_stack() + raise + + finally: + if exception: + x = raw_input('Press Enter to exit.') + else: + time.sleep(3)