service.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Service management tool
  5. # Copyright (C) 2017, Suleyman POYRAZ (AquilaNipalensis)
  6. #
  7. # This program is free software; you can redistribute it and/or modify it
  8. # under the terms of the GNU General Public License as published by the
  9. # Free Software Foundation; either version 2 of the License, or (at your
  10. # option) any later version. Please read the COPYING file.
  11. #
  12. import os
  13. import sys
  14. import time
  15. import scom
  16. import dbus
  17. import socket
  18. import locale
  19. import subprocess
  20. # i18n
  21. import gettext
  22. __trans = gettext.translation('scomd', fallback=True)
  23. _ = __trans.gettext
  24. # Utilities
  25. def loadConfig(path):
  26. d = {}
  27. for line in open(path):
  28. if line != "" and not line.startswith("#") and "=" in line:
  29. key, value = line.split("=", 1)
  30. key = key.strip()
  31. value = value.strip()
  32. if value.startswith('"') or value.startswith("'"):
  33. value = value[1:-1]
  34. d[key] = value
  35. return d
  36. def waitBus(unix_name, timeout=10, wait=0.1, stream=True):
  37. if stream:
  38. sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  39. else:
  40. sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
  41. while timeout > 0:
  42. try:
  43. sock.connect(unix_name)
  44. return True
  45. except:
  46. timeout -= wait
  47. time.sleep(wait)
  48. return False
  49. # Operations
  50. class Service:
  51. types = {
  52. "local": _("local"),
  53. "script": _("script"),
  54. "server": _("server"),
  55. }
  56. def __init__(self, name, info=None):
  57. self.name = name
  58. self.running = ""
  59. self.autostart = ""
  60. if info:
  61. servicetype, self.description, state = info
  62. self.state = state
  63. self.servicetype = self.types[servicetype]
  64. if state in ("on", "started", "conditional_started"):
  65. self.running = _("running")
  66. if state in ("on", "stopped"):
  67. self.autostart = _("yes")
  68. if state in ("conditional_started", "conditional_stopped"):
  69. self.autostart = _("conditional")
  70. def format_service_list(services, use_color=True):
  71. if os.environ.get("TERM", "") == "xterm":
  72. colors = {
  73. "on": '[0;32m',
  74. "started": '[1;32m',
  75. "stopped": '[0;31m',
  76. "off": '[0m',
  77. "conditional_started": '[1;32m',
  78. "conditional_stopped": '[1;33m',
  79. }
  80. else:
  81. colors = {
  82. "on": '[1;32m',
  83. "started": '[0;32m',
  84. "stopped": '[1;31m',
  85. "off": '[0m',
  86. "conditional_started": '[0;32m',
  87. "conditional_stopped": '[0;33m',
  88. }
  89. run_title = _("Status")
  90. name_title = _("Service")
  91. auto_title = _("Autostart")
  92. desc_title = _("Description")
  93. run_size = max(max([len(x.running) for x in services]), len(run_title))
  94. name_size = max(max([len(x.name) for x in services]), len(name_title))
  95. auto_size = max(max([len(x.autostart) for x in services]), len(auto_title))
  96. desc_size = len(desc_title)
  97. line = "%s | %s | %s | %s" % (
  98. name_title.center(name_size),
  99. run_title.center(run_size),
  100. auto_title.center(auto_size),
  101. desc_title.center(desc_size)
  102. )
  103. print(line)
  104. print("-" * (len(line)))
  105. cstart = ""
  106. cend = ""
  107. if use_color:
  108. cend = "\x1b[0m"
  109. for service in services:
  110. if use_color:
  111. cstart = "\x1b%s" % colors[service.state]
  112. line = "%s%s%s | %s%s%s | %s%s%s | %s%s%s" % (
  113. cstart,
  114. service.name.ljust(name_size),
  115. cend, cstart,
  116. service.running.center(run_size),
  117. cend, cstart,
  118. service.autostart.center(auto_size),
  119. cend, cstart,
  120. service.description,
  121. cend
  122. )
  123. print(line)
  124. def readyService(service):
  125. try:
  126. link = scom.Link()
  127. link.setLocale()
  128. link.useAgent(False)
  129. link.System.Service[service].ready()
  130. except dbus.exceptions.DBusException as e:
  131. print(_("Unable to start %s:") % service)
  132. print(" %s" % e.args[0])
  133. def startService(service, quiet=False):
  134. try:
  135. link = scom.Link()
  136. link.setLocale()
  137. link.useAgent(False)
  138. link.System.Service[service].start()
  139. except dbus.exceptions.DBusException as e:
  140. print(_("Unable to start %s:") % service)
  141. print(" %s" % e.args[0])
  142. return
  143. if not quiet:
  144. print(_("Starting %s") % service)
  145. def stopService(service, quiet=False):
  146. try:
  147. link = scom.Link()
  148. link.setLocale()
  149. link.useAgent(False)
  150. link.System.Service[service].stop()
  151. except dbus.exceptions.DBusException as e:
  152. print(_("Unable to stop %s:") % service)
  153. print(" %s" % e.args[0])
  154. return
  155. if not quiet:
  156. print(_("Stopping %s") % service)
  157. def setServiceState(service, state, quiet=False):
  158. try:
  159. link = scom.Link()
  160. link.setLocale()
  161. link.useAgent(False)
  162. link.System.Service[service].setState(state)
  163. except dbus.exceptions.DBusException as e:
  164. print(_("Unable to set %s state:") % service)
  165. print(" %s" % e.args[0])
  166. return
  167. if not quiet:
  168. if state == "on":
  169. print(_("Service '%s' will be auto started.") % service)
  170. elif state == "off":
  171. print(_("Service '%s' won't be auto started.") % service)
  172. else:
  173. print(_("Service '%s' will be started if required.") % service)
  174. def reloadService(service, quiet=False):
  175. try:
  176. link = scom.Link()
  177. link.setLocale()
  178. link.useAgent(False)
  179. link.System.Service[service].reload()
  180. except dbus.exceptions.DBusException as e:
  181. print(_("Unable to reload %s:") % service)
  182. print(" %s" % e.args[0])
  183. return
  184. if not quiet:
  185. print(_("Reloading %s") % service)
  186. def getServiceInfo(service):
  187. link = scom.Link()
  188. link.setLocale()
  189. link.useAgent(False)
  190. return link.System.Service[service].info()
  191. def getServices():
  192. link = scom.Link()
  193. link.setLocale()
  194. link.useAgent(False)
  195. return list(link.System.Service)
  196. def list_services(use_color=True):
  197. services = []
  198. for service in getServices():
  199. services.append((service, getServiceInfo(service), ))
  200. if len(services) > 0:
  201. services.sort(key=lambda x: x[0])
  202. lala = []
  203. for service, info in services:
  204. lala.append(Service(service, info))
  205. format_service_list(lala, use_color)
  206. def manage_service(service, op, use_color=True, quiet=False):
  207. if op == "ready":
  208. readyService(service)
  209. elif op == "start":
  210. startService(service, quiet)
  211. elif op == "stop":
  212. stopService(service, quiet)
  213. elif op == "reload":
  214. reloadService(service, quiet)
  215. elif op == "on":
  216. setServiceState(service, "on", quiet)
  217. elif op == "off":
  218. setServiceState(service, "off", quiet)
  219. elif op == "conditional":
  220. setServiceState(service, "conditional", quiet)
  221. elif op in ["info", "status", "list"]:
  222. info = getServiceInfo(service)
  223. s = Service(service, info)
  224. format_service_list([s], use_color)
  225. elif op == "restart":
  226. manage_service(service, "stop", use_color, quiet)
  227. manage_service(service, "start", use_color, quiet)
  228. def run(*cmd):
  229. subprocess.call(cmd)
  230. def manage_dbus(op, use_color, quiet):
  231. if os.getuid() != 0 and op not in ["status", "info", "list"]:
  232. print(_("You must be root to use that."))
  233. return -1
  234. def cleanup():
  235. try:
  236. os.unlink("/run/dbus/pid")
  237. os.unlink("/run/dbus/system_bus_socket")
  238. except OSError:
  239. pass
  240. if op == "start":
  241. if not quiet:
  242. print(_("Starting %s") % "DBus")
  243. cleanup()
  244. if not os.path.exists("/var/lib/dbus/machine-id"):
  245. run("/usr/bin/dbus-uuidgen", "--ensure")
  246. run("/sbin/start-stop-daemon", "-b", "--start", "--quiet",
  247. "--pidfile", "/run/dbus/pid", "--exec", "/usr/bin/dbus-daemon",
  248. "--", "--system")
  249. if not waitBus("/run/dbus/system_bus_socket", timeout=20):
  250. print(_("Unable to start DBus"))
  251. return -1
  252. elif op == "stop":
  253. if not quiet:
  254. print(_("Stopping %s") % "DBus")
  255. run("/sbin/start-stop-daemon", "--stop", "--quiet", "--pidfile", "/run/dbus/pid")
  256. cleanup()
  257. elif op == "restart":
  258. manage_dbus("stop", use_color, quiet)
  259. manage_dbus("start", use_color, quiet)
  260. elif op in ["info", "status", "list"]:
  261. try:
  262. dbus.SystemBus()
  263. except dbus.exceptions.DBusException:
  264. print(_("DBus is not running."))
  265. return
  266. print(_("DBus is running."))
  267. # Usage
  268. def usage():
  269. print(_("""usage: service [<options>] [<service>] <command>
  270. where command is:
  271. list Display service list
  272. status Display service status
  273. info Display service status
  274. on Auto start the service
  275. off Don't auto start the service
  276. start Start the service
  277. stop Stop the service
  278. restart Stop the service, then start again
  279. reload Reload the configuration (if service supports this)
  280. and option is:
  281. -N, --no-color Don't use color in output
  282. -q, --quiet Don't print replies"""))
  283. # Main
  284. def main(args):
  285. operations = ("start", "stop", "info", "list", "restart", "reload", "status", "on", "off", "ready", "conditional")
  286. use_color = True
  287. quiet = False
  288. # Parameters
  289. if "--no-color" in args:
  290. args.remove("--no-color")
  291. use_color = False
  292. if "-N" in args:
  293. args.remove("-N")
  294. use_color = False
  295. if "--quiet" in args:
  296. args.remove("--quiet")
  297. quiet = True
  298. if "-q" in args:
  299. args.remove("-q")
  300. quiet = True
  301. # Operations
  302. if args == []:
  303. list_services(use_color)
  304. elif args[0] == "list" and len(args) == 1:
  305. list_services(use_color)
  306. elif args[0] == "help":
  307. usage()
  308. elif len(args) < 2:
  309. usage()
  310. elif args[1] in operations and args[0] == "dbus":
  311. manage_dbus(args[1], use_color, quiet)
  312. elif args[1] in operations:
  313. try:
  314. manage_service(args[0].replace("-", "_"), args[1], use_color, quiet)
  315. except dbus.exceptions.DBusException as e:
  316. if "Unable to find" in str(e):
  317. print(_("No such service: %s") % args[0])
  318. else:
  319. print(" %s" % e.args[0])
  320. return -1
  321. except ValueError as e:
  322. print(e)
  323. return -1
  324. else:
  325. usage()
  326. return 0
  327. if __name__ == "__main__":
  328. locale.setlocale(locale.LC_ALL, '')
  329. main(sys.argv[1:])