diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-04-10 18:44:43 +0200 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-04-10 18:44:43 +0200 |
commit | f5865347037b779b94d56aaf23c05d8276857a9e (patch) | |
tree | 713fe76bcfeb88f155d9ee4a5408229b6feb3f41 | |
parent | fc5753fd51134d7b838ed457c2253e71090bdad1 (diff) | |
download | psutil-f5865347037b779b94d56aaf23c05d8276857a9e.tar.gz |
add winservice script and disablr start() and stop() methods
-rw-r--r-- | docs/index.rst | 2 | ||||
-rw-r--r-- | psutil/__init__.py | 39 | ||||
-rw-r--r-- | psutil/_pswindows.py | 60 | ||||
-rw-r--r-- | psutil/arch/windows/services.c | 2 | ||||
-rw-r--r-- | psutil/tests/test_windows.py | 16 | ||||
-rw-r--r-- | scripts/winservices.py | 56 |
6 files changed, 131 insertions, 44 deletions
diff --git a/docs/index.rst b/docs/index.rst index 2c831d85..c932de12 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1489,7 +1489,7 @@ Windows services .. function:: win_service_iter() Return an iterator yielding a :class:`WindowsService` class instance for all - installed Windows services. + Windows services installed. .. versionadded:: 4.2.0 Availability: Windows diff --git a/psutil/__init__.py b/psutil/__init__.py index d562cf57..832acd2a 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -1984,6 +1984,29 @@ def users(): return _psplatform.users() +# ===================================================================== +# --- Windows services +# ===================================================================== + + +if WINDOWS: + + def win_service_iter(): + """Return a generator yielding a WindowsService instance for all + Windows services installed. + """ + return _psplatform.win_service_iter() + + def win_service_get(name): + """Get a Windows service by name. + Raise NoSuchProcess if no service with such name exists. + """ + return _psplatform.win_service_get(name) + + +# ===================================================================== + + def test(): # pragma: no cover """List info of all currently running processes emulating ps aux output. @@ -2040,22 +2063,6 @@ def test(): # pragma: no cover pinfo['name'].strip() or '?')) -# ===================================================================== -# --- Windows services -# ===================================================================== - -if WINDOWS: - def win_service_iter(): - """Return a generator yielding a WindowsService instance for all - installed Windows services. - """ - return _psplatform.win_service_iter() - - def win_service_get(name): - """Get a Windows service by name.""" - return _psplatform.win_service_get(name) - - del memoize, division, deprecated_method if sys.version_info < (3, 0): del num diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 759574be..61947deb 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -39,7 +39,7 @@ else: # process priority constants, import from __init__.py: # http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx __extra__all__ = [ - "win_service_iter", + "win_service_iter", "win_service_get", "ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS", "HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS", @@ -397,27 +397,43 @@ class WindowsService(object): return d # actions - - def start(self, timeout=None): - with self._wrap_exceptions(): - cext.winservice_start(self.name()) - if timeout: - giveup_at = time.time() + timeout - while True: - if self.status() == "running": - return - else: - if time.time() > giveup_at: - raise TimeoutExpired(timeout) - else: - time.sleep(.1) - - def stop(self): - # Note: timeout is not implemented because it's just not - # possible, see: - # http://stackoverflow.com/questions/11973228/ - with self._wrap_exceptions(): - return cext.winservice_stop(self.name()) + # XXX: the necessary C bindings for start() and stop() are implemented + # but for now I prefer not to expose them. + # I may change my mind in the future. Reasons: + # - they require Administrator privileges + # - can't implement a timeout for stop() (unless by using a thread, + # which sucks) + # - would require adding ServiceAlreadyStarted and + # ServiceAlreadyStopped exceptions, adding two new APIs. + # - we might also want to have modify(), which would basically mean + # rewriting win32serviceutil.ChangeServiceConfig, which involves a + # lot of stuff (and API constants which would pollute the API), see: + # http://pyxr.sourceforge.net/PyXR/c/python24/lib/site-packages/ + # win32/lib/win32serviceutil.py.html#0175 + # - psutil is tipically about "read only" monitoring stuff; + # win_service_* APIs should only be used to retrieve a service and + # check whether it's running + + # def start(self, timeout=None): + # with self._wrap_exceptions(): + # cext.winservice_start(self.name()) + # if timeout: + # giveup_at = time.time() + timeout + # while True: + # if self.status() == "running": + # return + # else: + # if time.time() > giveup_at: + # raise TimeoutExpired(timeout) + # else: + # time.sleep(.1) + + # def stop(self): + # # Note: timeout is not implemented because it's just not + # # possible, see: + # # http://stackoverflow.com/questions/11973228/ + # with self._wrap_exceptions(): + # return cext.winservice_stop(self.name()) def win_service_iter(): diff --git a/psutil/arch/windows/services.c b/psutil/arch/windows/services.c index be1ef8f5..a2fe0bc5 100644 --- a/psutil/arch/windows/services.c +++ b/psutil/arch/windows/services.c @@ -356,6 +356,7 @@ error: /* * Start service. + * XXX - note: this is exposed but not used. */ PyObject * psutil_winservice_start(PyObject *self, PyObject *args) { @@ -387,6 +388,7 @@ error: /* * Stop service. + * XXX - note: this is exposed but not used. */ PyObject * psutil_winservice_stop(PyObject *self, PyObject *args) { diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py index 883e79c3..93225917 100644 --- a/psutil/tests/test_windows.py +++ b/psutil/tests/test_windows.py @@ -638,25 +638,31 @@ class TestServices(unittest.TestCase): self.assertEqual(cm.exception.name, name + '???') # test NoSuchProcess - s = psutil.win_service_get(name) + service = psutil.win_service_get(name) exc = WindowsError( psutil._psplatform.cext.ERROR_SERVICE_DOES_NOT_EXIST, "") with mock.patch("psutil._psplatform.cext.winservice_query_status", side_effect=exc): - self.assertRaises(psutil.NoSuchProcess, s.status) + self.assertRaises(psutil.NoSuchProcess, service.status) with mock.patch("psutil._psplatform.cext.winservice_query_config", side_effect=exc): - self.assertRaises(psutil.NoSuchProcess, s.username) + self.assertRaises(psutil.NoSuchProcess, service.username) # test AccessDenied exc = WindowsError( psutil._psplatform.cext.ERROR_ACCESS_DENIED, "") with mock.patch("psutil._psplatform.cext.winservice_query_status", side_effect=exc): - self.assertRaises(psutil.AccessDenied, s.status) + self.assertRaises(psutil.AccessDenied, service.status) with mock.patch("psutil._psplatform.cext.winservice_query_config", side_effect=exc): - self.assertRaises(psutil.AccessDenied, s.username) + self.assertRaises(psutil.AccessDenied, service.username) + + # test __str__ and __repr__ + self.assertIn(service.name(), str(service)) + self.assertIn(service.display_name(), str(service)) + self.assertIn(service.name(), repr(service)) + self.assertIn(service.display_name(), repr(service)) if __name__ == '__main__': diff --git a/scripts/winservices.py b/scripts/winservices.py new file mode 100644 index 00000000..fed6a734 --- /dev/null +++ b/scripts/winservices.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +List all Windows services installed. + +$ python scripts/winservices.py +AeLookupSvc (Application Experience) +status: stopped, start: manual, username: localSystem, pid: None +binpath: C:\Windows\system32\svchost.exe -k netsvcs + +ALG (Application Layer Gateway Service) +status: stopped, start: manual, username: NT AUTHORITY\LocalService, pid: None +binpath: C:\Windows\System32\alg.exe + +APNMCP (Ask Update Service) +status: running, start: automatic, username: LocalSystem, pid: 1108 +binpath: "C:\Program Files (x86)\AskPartnerNetwork\Toolbar\apnmcp.exe" + +AppIDSvc (Application Identity) +status: stopped, start: manual, username: NT Authority\LocalService, pid: None +binpath: C:\Windows\system32\svchost.exe -k LocalServiceAndNoImpersonation + +Appinfo (Application Information) +status: stopped, start: manual, username: LocalSystem, pid: None +binpath: C:\Windows\system32\svchost.exe -k netsvcs + +... +""" + + +import os +import sys + +import psutil + + +if os.name != 'nt': + sys.exit("platform not supported (Windows only)") + + +def main(): + for service in psutil.win_service_iter(): + info = service.as_dict() + print("%s (%s)" % (info['name'], info['display_name'])) + print("status: %s, start: %s, username: %s, pid: %s" % ( + info['status'], info['start_type'], info['username'], info['pid'])) + print("binpath: %s" % info['binpath']) + print("") + + +if __name__ == '__main__': + sys.exit(main()) |