systemd-units.c 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "systemd-internals.h"
  3. #ifdef ENABLE_SYSTEMD_DBUS
  4. #include <systemd/sd-bus.h>
  5. #define SYSTEMD_UNITS_MAX_PARAMS 10
  6. #define SYSTEMD_UNITS_DBUS_TYPES "(ssssssouso)"
  7. // ----------------------------------------------------------------------------
  8. // copied from systemd: string-table.h
  9. typedef char sd_char;
  10. #define XCONCATENATE(x, y) x ## y
  11. #define CONCATENATE(x, y) XCONCATENATE(x, y)
  12. #ifndef __COVERITY__
  13. # define VOID_0 ((void)0)
  14. #else
  15. # define VOID_0 ((void*)0)
  16. #endif
  17. #define ELEMENTSOF(x) \
  18. (__builtin_choose_expr( \
  19. !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
  20. sizeof(x)/sizeof((x)[0]), \
  21. VOID_0))
  22. #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
  23. #define UNIQ __COUNTER__
  24. #define __CMP(aq, a, bq, b) \
  25. ({ \
  26. const typeof(a) UNIQ_T(A, aq) = (a); \
  27. const typeof(b) UNIQ_T(B, bq) = (b); \
  28. UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \
  29. UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \
  30. })
  31. #define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b))
  32. static inline int strcmp_ptr(const sd_char *a, const sd_char *b) {
  33. if (a && b)
  34. return strcmp(a, b);
  35. return CMP(a, b);
  36. }
  37. static inline bool streq_ptr(const sd_char *a, const sd_char *b) {
  38. return strcmp_ptr(a, b) == 0;
  39. }
  40. ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
  41. if (!key || !*key)
  42. return -EINVAL;
  43. for (size_t i = 0; i < len; ++i)
  44. if (streq_ptr(table[i], key))
  45. return (ssize_t) i;
  46. return -EINVAL;
  47. }
  48. /* For basic lookup tables with strictly enumerated entries */
  49. #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
  50. scope const char *name##_to_string(type i) { \
  51. if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
  52. return NULL; \
  53. return name##_table[i]; \
  54. }
  55. #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
  56. scope type name##_from_string(const char *s) { \
  57. return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
  58. }
  59. #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
  60. _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
  61. _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)
  62. #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
  63. // ----------------------------------------------------------------------------
  64. // copied from systemd: unit-def.h
  65. typedef enum UnitType {
  66. UNIT_SERVICE,
  67. UNIT_MOUNT,
  68. UNIT_SWAP,
  69. UNIT_SOCKET,
  70. UNIT_TARGET,
  71. UNIT_DEVICE,
  72. UNIT_AUTOMOUNT,
  73. UNIT_TIMER,
  74. UNIT_PATH,
  75. UNIT_SLICE,
  76. UNIT_SCOPE,
  77. _UNIT_TYPE_MAX,
  78. _UNIT_TYPE_INVALID = -EINVAL,
  79. } UnitType;
  80. typedef enum UnitLoadState {
  81. UNIT_STUB,
  82. UNIT_LOADED,
  83. UNIT_NOT_FOUND, /* error condition #1: unit file not found */
  84. UNIT_BAD_SETTING, /* error condition #2: we couldn't parse some essential unit file setting */
  85. UNIT_ERROR, /* error condition #3: other "system" error, catchall for the rest */
  86. UNIT_MERGED,
  87. UNIT_MASKED,
  88. _UNIT_LOAD_STATE_MAX,
  89. _UNIT_LOAD_STATE_INVALID = -EINVAL,
  90. } UnitLoadState;
  91. typedef enum UnitActiveState {
  92. UNIT_ACTIVE,
  93. UNIT_RELOADING,
  94. UNIT_INACTIVE,
  95. UNIT_FAILED,
  96. UNIT_ACTIVATING,
  97. UNIT_DEACTIVATING,
  98. UNIT_MAINTENANCE,
  99. _UNIT_ACTIVE_STATE_MAX,
  100. _UNIT_ACTIVE_STATE_INVALID = -EINVAL,
  101. } UnitActiveState;
  102. typedef enum AutomountState {
  103. AUTOMOUNT_DEAD,
  104. AUTOMOUNT_WAITING,
  105. AUTOMOUNT_RUNNING,
  106. AUTOMOUNT_FAILED,
  107. _AUTOMOUNT_STATE_MAX,
  108. _AUTOMOUNT_STATE_INVALID = -EINVAL,
  109. } AutomountState;
  110. typedef enum DeviceState {
  111. DEVICE_DEAD,
  112. DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
  113. DEVICE_PLUGGED, /* announced by udev */
  114. _DEVICE_STATE_MAX,
  115. _DEVICE_STATE_INVALID = -EINVAL,
  116. } DeviceState;
  117. typedef enum MountState {
  118. MOUNT_DEAD,
  119. MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */
  120. MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */
  121. MOUNT_MOUNTED,
  122. MOUNT_REMOUNTING,
  123. MOUNT_UNMOUNTING,
  124. MOUNT_REMOUNTING_SIGTERM,
  125. MOUNT_REMOUNTING_SIGKILL,
  126. MOUNT_UNMOUNTING_SIGTERM,
  127. MOUNT_UNMOUNTING_SIGKILL,
  128. MOUNT_FAILED,
  129. MOUNT_CLEANING,
  130. _MOUNT_STATE_MAX,
  131. _MOUNT_STATE_INVALID = -EINVAL,
  132. } MountState;
  133. typedef enum PathState {
  134. PATH_DEAD,
  135. PATH_WAITING,
  136. PATH_RUNNING,
  137. PATH_FAILED,
  138. _PATH_STATE_MAX,
  139. _PATH_STATE_INVALID = -EINVAL,
  140. } PathState;
  141. typedef enum ScopeState {
  142. SCOPE_DEAD,
  143. SCOPE_START_CHOWN,
  144. SCOPE_RUNNING,
  145. SCOPE_ABANDONED,
  146. SCOPE_STOP_SIGTERM,
  147. SCOPE_STOP_SIGKILL,
  148. SCOPE_FAILED,
  149. _SCOPE_STATE_MAX,
  150. _SCOPE_STATE_INVALID = -EINVAL,
  151. } ScopeState;
  152. typedef enum ServiceState {
  153. SERVICE_DEAD,
  154. SERVICE_CONDITION,
  155. SERVICE_START_PRE,
  156. SERVICE_START,
  157. SERVICE_START_POST,
  158. SERVICE_RUNNING,
  159. SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
  160. SERVICE_RELOAD, /* Reloading via ExecReload= */
  161. SERVICE_RELOAD_SIGNAL, /* Reloading via SIGHUP requested */
  162. SERVICE_RELOAD_NOTIFY, /* Waiting for READY=1 after RELOADING=1 notify */
  163. SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
  164. SERVICE_STOP_WATCHDOG,
  165. SERVICE_STOP_SIGTERM,
  166. SERVICE_STOP_SIGKILL,
  167. SERVICE_STOP_POST,
  168. SERVICE_FINAL_WATCHDOG, /* In case the STOP_POST executable needs to be aborted. */
  169. SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
  170. SERVICE_FINAL_SIGKILL,
  171. SERVICE_FAILED,
  172. SERVICE_DEAD_BEFORE_AUTO_RESTART,
  173. SERVICE_FAILED_BEFORE_AUTO_RESTART,
  174. SERVICE_DEAD_RESOURCES_PINNED, /* Like SERVICE_DEAD, but with pinned resources */
  175. SERVICE_AUTO_RESTART,
  176. SERVICE_AUTO_RESTART_QUEUED,
  177. SERVICE_CLEANING,
  178. _SERVICE_STATE_MAX,
  179. _SERVICE_STATE_INVALID = -EINVAL,
  180. } ServiceState;
  181. typedef enum SliceState {
  182. SLICE_DEAD,
  183. SLICE_ACTIVE,
  184. _SLICE_STATE_MAX,
  185. _SLICE_STATE_INVALID = -EINVAL,
  186. } SliceState;
  187. typedef enum SocketState {
  188. SOCKET_DEAD,
  189. SOCKET_START_PRE,
  190. SOCKET_START_CHOWN,
  191. SOCKET_START_POST,
  192. SOCKET_LISTENING,
  193. SOCKET_RUNNING,
  194. SOCKET_STOP_PRE,
  195. SOCKET_STOP_PRE_SIGTERM,
  196. SOCKET_STOP_PRE_SIGKILL,
  197. SOCKET_STOP_POST,
  198. SOCKET_FINAL_SIGTERM,
  199. SOCKET_FINAL_SIGKILL,
  200. SOCKET_FAILED,
  201. SOCKET_CLEANING,
  202. _SOCKET_STATE_MAX,
  203. _SOCKET_STATE_INVALID = -EINVAL,
  204. } SocketState;
  205. typedef enum SwapState {
  206. SWAP_DEAD,
  207. SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */
  208. SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
  209. SWAP_ACTIVE,
  210. SWAP_DEACTIVATING,
  211. SWAP_DEACTIVATING_SIGTERM,
  212. SWAP_DEACTIVATING_SIGKILL,
  213. SWAP_FAILED,
  214. SWAP_CLEANING,
  215. _SWAP_STATE_MAX,
  216. _SWAP_STATE_INVALID = -EINVAL,
  217. } SwapState;
  218. typedef enum TargetState {
  219. TARGET_DEAD,
  220. TARGET_ACTIVE,
  221. _TARGET_STATE_MAX,
  222. _TARGET_STATE_INVALID = -EINVAL,
  223. } TargetState;
  224. typedef enum TimerState {
  225. TIMER_DEAD,
  226. TIMER_WAITING,
  227. TIMER_RUNNING,
  228. TIMER_ELAPSED,
  229. TIMER_FAILED,
  230. _TIMER_STATE_MAX,
  231. _TIMER_STATE_INVALID = -EINVAL,
  232. } TimerState;
  233. typedef enum FreezerState {
  234. FREEZER_RUNNING,
  235. FREEZER_FREEZING,
  236. FREEZER_FROZEN,
  237. FREEZER_THAWING,
  238. _FREEZER_STATE_MAX,
  239. _FREEZER_STATE_INVALID = -EINVAL,
  240. } FreezerState;
  241. // ----------------------------------------------------------------------------
  242. // copied from systemd: unit-def.c
  243. static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
  244. [UNIT_SERVICE] = "service",
  245. [UNIT_SOCKET] = "socket",
  246. [UNIT_TARGET] = "target",
  247. [UNIT_DEVICE] = "device",
  248. [UNIT_MOUNT] = "mount",
  249. [UNIT_AUTOMOUNT] = "automount",
  250. [UNIT_SWAP] = "swap",
  251. [UNIT_TIMER] = "timer",
  252. [UNIT_PATH] = "path",
  253. [UNIT_SLICE] = "slice",
  254. [UNIT_SCOPE] = "scope",
  255. };
  256. DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
  257. static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
  258. [UNIT_STUB] = "stub",
  259. [UNIT_LOADED] = "loaded",
  260. [UNIT_NOT_FOUND] = "not-found",
  261. [UNIT_BAD_SETTING] = "bad-setting",
  262. [UNIT_ERROR] = "error",
  263. [UNIT_MERGED] = "merged",
  264. [UNIT_MASKED] = "masked"
  265. };
  266. DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
  267. static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
  268. [UNIT_ACTIVE] = "active",
  269. [UNIT_RELOADING] = "reloading",
  270. [UNIT_INACTIVE] = "inactive",
  271. [UNIT_FAILED] = "failed",
  272. [UNIT_ACTIVATING] = "activating",
  273. [UNIT_DEACTIVATING] = "deactivating",
  274. [UNIT_MAINTENANCE] = "maintenance",
  275. };
  276. DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
  277. static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
  278. [AUTOMOUNT_DEAD] = "dead",
  279. [AUTOMOUNT_WAITING] = "waiting",
  280. [AUTOMOUNT_RUNNING] = "running",
  281. [AUTOMOUNT_FAILED] = "failed"
  282. };
  283. DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
  284. static const char* const device_state_table[_DEVICE_STATE_MAX] = {
  285. [DEVICE_DEAD] = "dead",
  286. [DEVICE_TENTATIVE] = "tentative",
  287. [DEVICE_PLUGGED] = "plugged",
  288. };
  289. DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
  290. static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
  291. [MOUNT_DEAD] = "dead",
  292. [MOUNT_MOUNTING] = "mounting",
  293. [MOUNT_MOUNTING_DONE] = "mounting-done",
  294. [MOUNT_MOUNTED] = "mounted",
  295. [MOUNT_REMOUNTING] = "remounting",
  296. [MOUNT_UNMOUNTING] = "unmounting",
  297. [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
  298. [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
  299. [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
  300. [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
  301. [MOUNT_FAILED] = "failed",
  302. [MOUNT_CLEANING] = "cleaning",
  303. };
  304. DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
  305. static const char* const path_state_table[_PATH_STATE_MAX] = {
  306. [PATH_DEAD] = "dead",
  307. [PATH_WAITING] = "waiting",
  308. [PATH_RUNNING] = "running",
  309. [PATH_FAILED] = "failed"
  310. };
  311. DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
  312. static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
  313. [SCOPE_DEAD] = "dead",
  314. [SCOPE_START_CHOWN] = "start-chown",
  315. [SCOPE_RUNNING] = "running",
  316. [SCOPE_ABANDONED] = "abandoned",
  317. [SCOPE_STOP_SIGTERM] = "stop-sigterm",
  318. [SCOPE_STOP_SIGKILL] = "stop-sigkill",
  319. [SCOPE_FAILED] = "failed",
  320. };
  321. DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
  322. static const char* const service_state_table[_SERVICE_STATE_MAX] = {
  323. [SERVICE_DEAD] = "dead",
  324. [SERVICE_CONDITION] = "condition",
  325. [SERVICE_START_PRE] = "start-pre",
  326. [SERVICE_START] = "start",
  327. [SERVICE_START_POST] = "start-post",
  328. [SERVICE_RUNNING] = "running",
  329. [SERVICE_EXITED] = "exited",
  330. [SERVICE_RELOAD] = "reload",
  331. [SERVICE_RELOAD_SIGNAL] = "reload-signal",
  332. [SERVICE_RELOAD_NOTIFY] = "reload-notify",
  333. [SERVICE_STOP] = "stop",
  334. [SERVICE_STOP_WATCHDOG] = "stop-watchdog",
  335. [SERVICE_STOP_SIGTERM] = "stop-sigterm",
  336. [SERVICE_STOP_SIGKILL] = "stop-sigkill",
  337. [SERVICE_STOP_POST] = "stop-post",
  338. [SERVICE_FINAL_WATCHDOG] = "final-watchdog",
  339. [SERVICE_FINAL_SIGTERM] = "final-sigterm",
  340. [SERVICE_FINAL_SIGKILL] = "final-sigkill",
  341. [SERVICE_FAILED] = "failed",
  342. [SERVICE_DEAD_BEFORE_AUTO_RESTART] = "dead-before-auto-restart",
  343. [SERVICE_FAILED_BEFORE_AUTO_RESTART] = "failed-before-auto-restart",
  344. [SERVICE_DEAD_RESOURCES_PINNED] = "dead-resources-pinned",
  345. [SERVICE_AUTO_RESTART] = "auto-restart",
  346. [SERVICE_AUTO_RESTART_QUEUED] = "auto-restart-queued",
  347. [SERVICE_CLEANING] = "cleaning",
  348. };
  349. DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
  350. static const char* const slice_state_table[_SLICE_STATE_MAX] = {
  351. [SLICE_DEAD] = "dead",
  352. [SLICE_ACTIVE] = "active"
  353. };
  354. DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
  355. static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
  356. [SOCKET_DEAD] = "dead",
  357. [SOCKET_START_PRE] = "start-pre",
  358. [SOCKET_START_CHOWN] = "start-chown",
  359. [SOCKET_START_POST] = "start-post",
  360. [SOCKET_LISTENING] = "listening",
  361. [SOCKET_RUNNING] = "running",
  362. [SOCKET_STOP_PRE] = "stop-pre",
  363. [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
  364. [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
  365. [SOCKET_STOP_POST] = "stop-post",
  366. [SOCKET_FINAL_SIGTERM] = "final-sigterm",
  367. [SOCKET_FINAL_SIGKILL] = "final-sigkill",
  368. [SOCKET_FAILED] = "failed",
  369. [SOCKET_CLEANING] = "cleaning",
  370. };
  371. DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
  372. static const char* const swap_state_table[_SWAP_STATE_MAX] = {
  373. [SWAP_DEAD] = "dead",
  374. [SWAP_ACTIVATING] = "activating",
  375. [SWAP_ACTIVATING_DONE] = "activating-done",
  376. [SWAP_ACTIVE] = "active",
  377. [SWAP_DEACTIVATING] = "deactivating",
  378. [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
  379. [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
  380. [SWAP_FAILED] = "failed",
  381. [SWAP_CLEANING] = "cleaning",
  382. };
  383. DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
  384. static const char* const target_state_table[_TARGET_STATE_MAX] = {
  385. [TARGET_DEAD] = "dead",
  386. [TARGET_ACTIVE] = "active"
  387. };
  388. DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
  389. static const char* const timer_state_table[_TIMER_STATE_MAX] = {
  390. [TIMER_DEAD] = "dead",
  391. [TIMER_WAITING] = "waiting",
  392. [TIMER_RUNNING] = "running",
  393. [TIMER_ELAPSED] = "elapsed",
  394. [TIMER_FAILED] = "failed"
  395. };
  396. DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
  397. static const char* const freezer_state_table[_FREEZER_STATE_MAX] = {
  398. [FREEZER_RUNNING] = "running",
  399. [FREEZER_FREEZING] = "freezing",
  400. [FREEZER_FROZEN] = "frozen",
  401. [FREEZER_THAWING] = "thawing",
  402. };
  403. DEFINE_STRING_TABLE_LOOKUP(freezer_state, FreezerState);
  404. // ----------------------------------------------------------------------------
  405. // our code
  406. typedef struct UnitAttribute {
  407. union {
  408. int boolean;
  409. char *str;
  410. uint64_t uint64;
  411. int64_t int64;
  412. uint32_t uint32;
  413. int32_t int32;
  414. double dbl;
  415. };
  416. } UnitAttribute;
  417. struct UnitInfo;
  418. typedef void (*attribute_handler_t)(struct UnitInfo *u, UnitAttribute *ua);
  419. static void update_freezer_state(struct UnitInfo *u, UnitAttribute *ua);
  420. struct {
  421. const char *member;
  422. char value_type;
  423. const char *show_as;
  424. const char *info;
  425. RRDF_FIELD_OPTIONS options;
  426. RRDF_FIELD_FILTER filter;
  427. attribute_handler_t handler;
  428. } unit_attributes[] = {
  429. {
  430. .member = "Type",
  431. .value_type = SD_BUS_TYPE_STRING,
  432. .show_as = "ServiceType",
  433. .info = "Service Type",
  434. .options = RRDF_FIELD_OPTS_VISIBLE,
  435. .filter = RRDF_FIELD_FILTER_MULTISELECT,
  436. }, {
  437. .member = "Result",
  438. .value_type = SD_BUS_TYPE_STRING,
  439. .show_as = "Result",
  440. .info = "Result",
  441. .options = RRDF_FIELD_OPTS_VISIBLE,
  442. .filter = RRDF_FIELD_FILTER_MULTISELECT,
  443. }, {
  444. .member = "UnitFileState",
  445. .value_type = SD_BUS_TYPE_STRING,
  446. .show_as = "Enabled",
  447. .info = "Unit File State",
  448. .options = RRDF_FIELD_OPTS_NONE,
  449. .filter = RRDF_FIELD_FILTER_MULTISELECT,
  450. }, {
  451. .member = "UnitFilePreset",
  452. .value_type = SD_BUS_TYPE_STRING,
  453. .show_as = "Preset",
  454. .info = "Unit File Preset",
  455. .options = RRDF_FIELD_OPTS_NONE,
  456. .filter = RRDF_FIELD_FILTER_MULTISELECT,
  457. }, {
  458. .member = "FreezerState",
  459. .value_type = SD_BUS_TYPE_STRING,
  460. .show_as = "FreezerState",
  461. .info = "Freezer State",
  462. .options = RRDF_FIELD_OPTS_NONE,
  463. .filter = RRDF_FIELD_FILTER_MULTISELECT,
  464. .handler = update_freezer_state,
  465. },
  466. // { .member = "Id", .signature = "s", },
  467. // { .member = "LoadState", .signature = "s", },
  468. // { .member = "ActiveState", .signature = "s", },
  469. // { .member = "SubState", .signature = "s", },
  470. // { .member = "Description", .signature = "s", },
  471. // { .member = "Following", .signature = "s", },
  472. // { .member = "Documentation", .signature = "as", },
  473. // { .member = "FragmentPath", .signature = "s", },
  474. // { .member = "SourcePath", .signature = "s", },
  475. // { .member = "ControlGroup", .signature = "s", },
  476. // { .member = "DropInPaths", .signature = "as", },
  477. // { .member = "LoadError", .signature = "(ss)", },
  478. // { .member = "TriggeredBy", .signature = "as", },
  479. // { .member = "Triggers", .signature = "as", },
  480. // { .member = "InactiveExitTimestamp", .signature = "t", },
  481. // { .member = "InactiveExitTimestampMonotonic", .signature = "t", },
  482. // { .member = "ActiveEnterTimestamp", .signature = "t", },
  483. // { .member = "ActiveExitTimestamp", .signature = "t", },
  484. // { .member = "RuntimeMaxUSec", .signature = "t", },
  485. // { .member = "InactiveEnterTimestamp", .signature = "t", },
  486. // { .member = "NeedDaemonReload", .signature = "b", },
  487. // { .member = "Transient", .signature = "b", },
  488. // { .member = "ExecMainPID", .signature = "u", },
  489. // { .member = "MainPID", .signature = "u", },
  490. // { .member = "ControlPID", .signature = "u", },
  491. // { .member = "StatusText", .signature = "s", },
  492. // { .member = "PIDFile", .signature = "s", },
  493. // { .member = "StatusErrno", .signature = "i", },
  494. // { .member = "FileDescriptorStoreMax", .signature = "u", },
  495. // { .member = "NFileDescriptorStore", .signature = "u", },
  496. // { .member = "ExecMainStartTimestamp", .signature = "t", },
  497. // { .member = "ExecMainExitTimestamp", .signature = "t", },
  498. // { .member = "ExecMainCode", .signature = "i", },
  499. // { .member = "ExecMainStatus", .signature = "i", },
  500. // { .member = "LogNamespace", .signature = "s", },
  501. // { .member = "ConditionTimestamp", .signature = "t", },
  502. // { .member = "ConditionResult", .signature = "b", },
  503. // { .member = "Conditions", .signature = "a(sbbsi)", },
  504. // { .member = "AssertTimestamp", .signature = "t", },
  505. // { .member = "AssertResult", .signature = "b", },
  506. // { .member = "Asserts", .signature = "a(sbbsi)", },
  507. // { .member = "NextElapseUSecRealtime", .signature = "t", },
  508. // { .member = "NextElapseUSecMonotonic", .signature = "t", },
  509. // { .member = "NAccepted", .signature = "u", },
  510. // { .member = "NConnections", .signature = "u", },
  511. // { .member = "NRefused", .signature = "u", },
  512. // { .member = "Accept", .signature = "b", },
  513. // { .member = "Listen", .signature = "a(ss)", },
  514. // { .member = "SysFSPath", .signature = "s", },
  515. // { .member = "Where", .signature = "s", },
  516. // { .member = "What", .signature = "s", },
  517. // { .member = "MemoryCurrent", .signature = "t", },
  518. // { .member = "MemoryAvailable", .signature = "t", },
  519. // { .member = "DefaultMemoryMin", .signature = "t", },
  520. // { .member = "DefaultMemoryLow", .signature = "t", },
  521. // { .member = "DefaultStartupMemoryLow", .signature = "t", },
  522. // { .member = "MemoryMin", .signature = "t", },
  523. // { .member = "MemoryLow", .signature = "t", },
  524. // { .member = "StartupMemoryLow", .signature = "t", },
  525. // { .member = "MemoryHigh", .signature = "t", },
  526. // { .member = "StartupMemoryHigh", .signature = "t", },
  527. // { .member = "MemoryMax", .signature = "t", },
  528. // { .member = "StartupMemoryMax", .signature = "t", },
  529. // { .member = "MemorySwapMax", .signature = "t", },
  530. // { .member = "StartupMemorySwapMax", .signature = "t", },
  531. // { .member = "MemoryZSwapMax", .signature = "t", },
  532. // { .member = "StartupMemoryZSwapMax", .signature = "t", },
  533. // { .member = "MemoryLimit", .signature = "t", },
  534. // { .member = "CPUUsageNSec", .signature = "t", },
  535. // { .member = "TasksCurrent", .signature = "t", },
  536. // { .member = "TasksMax", .signature = "t", },
  537. // { .member = "IPIngressBytes", .signature = "t", },
  538. // { .member = "IPEgressBytes", .signature = "t", },
  539. // { .member = "IOReadBytes", .signature = "t", },
  540. // { .member = "IOWriteBytes", .signature = "t", },
  541. // { .member = "ExecCondition", .signature = "a(sasbttttuii)", },
  542. // { .member = "ExecConditionEx", .signature = "a(sasasttttuii)", },
  543. // { .member = "ExecStartPre", .signature = "a(sasbttttuii)", },
  544. // { .member = "ExecStartPreEx", .signature = "a(sasasttttuii)", },
  545. // { .member = "ExecStart", .signature = "a(sasbttttuii)", },
  546. // { .member = "ExecStartEx", .signature = "a(sasasttttuii)", },
  547. // { .member = "ExecStartPost", .signature = "a(sasbttttuii)", },
  548. // { .member = "ExecStartPostEx", .signature = "a(sasasttttuii)", },
  549. // { .member = "ExecReload", .signature = "a(sasbttttuii)", },
  550. // { .member = "ExecReloadEx", .signature = "a(sasasttttuii)", },
  551. // { .member = "ExecStopPre", .signature = "a(sasbttttuii)", },
  552. // { .member = "ExecStop", .signature = "a(sasbttttuii)", },
  553. // { .member = "ExecStopEx", .signature = "a(sasasttttuii)", },
  554. // { .member = "ExecStopPost", .signature = "a(sasbttttuii)", },
  555. // { .member = "ExecStopPostEx", .signature = "a(sasasttttuii)", },
  556. };
  557. #define _UNIT_ATTRIBUTE_MAX (sizeof(unit_attributes) / sizeof(unit_attributes[0]))
  558. typedef struct UnitInfo {
  559. char *id;
  560. char *type;
  561. char *description;
  562. char *load_state;
  563. char *active_state;
  564. char *sub_state;
  565. char *following;
  566. char *unit_path;
  567. uint32_t job_id;
  568. char *job_type;
  569. char *job_path;
  570. UnitType UnitType;
  571. UnitLoadState UnitLoadState;
  572. UnitActiveState UnitActiveState;
  573. FreezerState FreezerState;
  574. union {
  575. AutomountState AutomountState;
  576. DeviceState DeviceState;
  577. MountState MountState;
  578. PathState PathState;
  579. ScopeState ScopeState;
  580. ServiceState ServiceState;
  581. SliceState SliceState;
  582. SocketState SocketState;
  583. SwapState SwapState;
  584. TargetState TargetState;
  585. TimerState TimerState;
  586. };
  587. struct UnitAttribute attributes[_UNIT_ATTRIBUTE_MAX];
  588. FACET_ROW_SEVERITY severity;
  589. uint32_t prio;
  590. struct UnitInfo *prev, *next;
  591. } UnitInfo;
  592. static void update_freezer_state(UnitInfo *u, UnitAttribute *ua) {
  593. u->FreezerState = freezer_state_from_string(ua->str);
  594. }
  595. // ----------------------------------------------------------------------------
  596. // common helpers
  597. static void log_dbus_error(int r, const char *msg) {
  598. netdata_log_error("SYSTEMD_UNITS: %s failed with error %d (%s)", msg, r, strerror(-r));
  599. }
  600. // ----------------------------------------------------------------------------
  601. // attributes management
  602. static inline ssize_t unit_property_slot_from_string(const char *s) {
  603. if(!s || !*s)
  604. return -EINVAL;
  605. for(size_t i = 0; i < _UNIT_ATTRIBUTE_MAX ;i++)
  606. if(streq_ptr(unit_attributes[i].member, s))
  607. return (ssize_t)i;
  608. return -EINVAL;
  609. }
  610. static inline const char *unit_property_name_to_string_from_slot(ssize_t i) {
  611. if(i >= 0 && i < (ssize_t)_UNIT_ATTRIBUTE_MAX)
  612. return unit_attributes[i].member;
  613. return NULL;
  614. }
  615. static inline void systemd_unit_free_property(char type, struct UnitAttribute *at) {
  616. switch(type) {
  617. case SD_BUS_TYPE_STRING:
  618. case SD_BUS_TYPE_OBJECT_PATH:
  619. freez(at->str);
  620. at->str = NULL;
  621. break;
  622. default:
  623. break;
  624. }
  625. }
  626. static int systemd_unit_get_property(sd_bus_message *m, UnitInfo *u, const char *name) {
  627. int r;
  628. char type;
  629. r = sd_bus_message_peek_type(m, &type, NULL);
  630. if(r < 0) {
  631. log_dbus_error(r, "sd_bus_message_peek_type()");
  632. return r;
  633. }
  634. ssize_t slot = unit_property_slot_from_string(name);
  635. if(slot < 0) {
  636. // internal_error(true, "unused attribute '%s' for unit '%s'", name, u->id);
  637. sd_bus_message_skip(m, NULL);
  638. return 0;
  639. }
  640. systemd_unit_free_property(unit_attributes[slot].value_type, &u->attributes[slot]);
  641. if(unit_attributes[slot].value_type != type) {
  642. netdata_log_error("Type of field '%s' expected to be '%c' but found '%c'. Ignoring field.",
  643. unit_attributes[slot].member, unit_attributes[slot].value_type, type);
  644. sd_bus_message_skip(m, NULL);
  645. return 0;
  646. }
  647. switch (type) {
  648. case SD_BUS_TYPE_OBJECT_PATH:
  649. case SD_BUS_TYPE_STRING: {
  650. char *s;
  651. r = sd_bus_message_read_basic(m, type, &s);
  652. if(r < 0) {
  653. log_dbus_error(r, "sd_bus_message_read_basic()");
  654. return r;
  655. }
  656. if(s && *s)
  657. u->attributes[slot].str = strdupz(s);
  658. }
  659. break;
  660. case SD_BUS_TYPE_BOOLEAN: {
  661. r = sd_bus_message_read_basic(m, type, &u->attributes[slot].boolean);
  662. if(r < 0) {
  663. log_dbus_error(r, "sd_bus_message_read_basic()");
  664. return r;
  665. }
  666. }
  667. break;
  668. case SD_BUS_TYPE_UINT64: {
  669. r = sd_bus_message_read_basic(m, type, &u->attributes[slot].uint64);
  670. if(r < 0) {
  671. log_dbus_error(r, "sd_bus_message_read_basic()");
  672. return r;
  673. }
  674. }
  675. break;
  676. case SD_BUS_TYPE_INT64: {
  677. r = sd_bus_message_read_basic(m, type, &u->attributes[slot].int64);
  678. if(r < 0) {
  679. log_dbus_error(r, "sd_bus_message_read_basic()");
  680. return r;
  681. }
  682. }
  683. break;
  684. case SD_BUS_TYPE_UINT32: {
  685. r = sd_bus_message_read_basic(m, type, &u->attributes[slot].uint32);
  686. if(r < 0) {
  687. log_dbus_error(r, "sd_bus_message_read_basic()");
  688. return r;
  689. }
  690. }
  691. break;
  692. case SD_BUS_TYPE_INT32: {
  693. r = sd_bus_message_read_basic(m, type, &u->attributes[slot].int32);
  694. if(r < 0) {
  695. log_dbus_error(r, "sd_bus_message_read_basic()");
  696. return r;
  697. }
  698. }
  699. break;
  700. case SD_BUS_TYPE_DOUBLE: {
  701. r = sd_bus_message_read_basic(m, type, &u->attributes[slot].dbl);
  702. if(r < 0) {
  703. log_dbus_error(r, "sd_bus_message_read_basic()");
  704. return r;
  705. }
  706. }
  707. break;
  708. case SD_BUS_TYPE_ARRAY: {
  709. internal_error(true, "member '%s' is an array", name);
  710. sd_bus_message_skip(m, NULL);
  711. return 0;
  712. }
  713. break;
  714. default: {
  715. internal_error(true, "unknown field type '%c' for key '%s'", type, name);
  716. sd_bus_message_skip(m, NULL);
  717. return 0;
  718. }
  719. break;
  720. }
  721. if(unit_attributes[slot].handler)
  722. unit_attributes[slot].handler(u, &u->attributes[slot]);
  723. return 0;
  724. }
  725. static int systemd_unit_get_all_properties(sd_bus *bus, UnitInfo *u) {
  726. _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
  727. _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
  728. int r;
  729. r = sd_bus_call_method(bus,
  730. "org.freedesktop.systemd1",
  731. u->unit_path,
  732. "org.freedesktop.DBus.Properties",
  733. "GetAll",
  734. &error,
  735. &m,
  736. "s", "");
  737. if (r < 0) {
  738. log_dbus_error(r, "sd_bus_call_method(p1)");
  739. return r;
  740. }
  741. r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
  742. if (r < 0) {
  743. log_dbus_error(r, "sd_bus_message_enter_container(p2)");
  744. return r;
  745. }
  746. int c = 0;
  747. while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
  748. const char *member, *contents;
  749. c++;
  750. r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member);
  751. if (r < 0) {
  752. log_dbus_error(r, "sd_bus_message_read_basic(p3)");
  753. return r;
  754. }
  755. r = sd_bus_message_peek_type(m, NULL, &contents);
  756. if (r < 0) {
  757. log_dbus_error(r, "sd_bus_message_peek_type(p4)");
  758. return r;
  759. }
  760. r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
  761. if (r < 0) {
  762. log_dbus_error(r, "sd_bus_message_enter_container(p5)");
  763. return r;
  764. }
  765. systemd_unit_get_property(m, u, member);
  766. r = sd_bus_message_exit_container(m);
  767. if(r < 0) {
  768. log_dbus_error(r, "sd_bus_message_exit_container(p6)");
  769. return r;
  770. }
  771. r = sd_bus_message_exit_container(m);
  772. if(r < 0) {
  773. log_dbus_error(r, "sd_bus_message_exit_container(p7)");
  774. return r;
  775. }
  776. }
  777. if(r < 0) {
  778. log_dbus_error(r, "sd_bus_message_enter_container(p8)");
  779. return r;
  780. }
  781. r = sd_bus_message_exit_container(m);
  782. if(r < 0) {
  783. log_dbus_error(r, "sd_bus_message_exit_container(p9)");
  784. return r;
  785. }
  786. return 0;
  787. }
  788. static void systemd_units_get_all_properties(sd_bus *bus, UnitInfo *base) {
  789. for(UnitInfo *u = base ; u ;u = u->next)
  790. systemd_unit_get_all_properties(bus, u);
  791. }
  792. // ----------------------------------------------------------------------------
  793. // main unit info
  794. int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
  795. assert(message);
  796. assert(u);
  797. u->type = NULL;
  798. int r = sd_bus_message_read(
  799. message,
  800. SYSTEMD_UNITS_DBUS_TYPES,
  801. &u->id,
  802. &u->description,
  803. &u->load_state,
  804. &u->active_state,
  805. &u->sub_state,
  806. &u->following,
  807. &u->unit_path,
  808. &u->job_id,
  809. &u->job_type,
  810. &u->job_path);
  811. if(r <= 0)
  812. return r;
  813. char *dot;
  814. if(u->id && (dot = strrchr(u->id, '.')) != NULL)
  815. u->type = &dot[1];
  816. else
  817. u->type = "unknown";
  818. u->UnitType = unit_type_from_string(u->type);
  819. u->UnitLoadState = unit_load_state_from_string(u->load_state);
  820. u->UnitActiveState = unit_active_state_from_string(u->active_state);
  821. switch(u->UnitType) {
  822. case UNIT_SERVICE:
  823. u->ServiceState = service_state_from_string(u->sub_state);
  824. break;
  825. case UNIT_MOUNT:
  826. u->MountState = mount_state_from_string(u->sub_state);
  827. break;
  828. case UNIT_SWAP:
  829. u->SwapState = swap_state_from_string(u->sub_state);
  830. break;
  831. case UNIT_SOCKET:
  832. u->SocketState = socket_state_from_string(u->sub_state);
  833. break;
  834. case UNIT_TARGET:
  835. u->TargetState = target_state_from_string(u->sub_state);
  836. break;
  837. case UNIT_DEVICE:
  838. u->DeviceState = device_state_from_string(u->sub_state);
  839. break;
  840. case UNIT_AUTOMOUNT:
  841. u->AutomountState = automount_state_from_string(u->sub_state);
  842. break;
  843. case UNIT_TIMER:
  844. u->TimerState = timer_state_from_string(u->sub_state);
  845. break;
  846. case UNIT_PATH:
  847. u->PathState = path_state_from_string(u->sub_state);
  848. break;
  849. case UNIT_SLICE:
  850. u->SliceState = slice_state_from_string(u->sub_state);
  851. break;
  852. case UNIT_SCOPE:
  853. u->ScopeState = scope_state_from_string(u->sub_state);
  854. break;
  855. default:
  856. break;
  857. }
  858. return r;
  859. }
  860. static int hex_to_int(char c) {
  861. if (c >= '0' && c <= '9') return c - '0';
  862. if (c >= 'a' && c <= 'f') return c - 'a' + 10;
  863. if (c >= 'A' && c <= 'F') return c - 'A' + 10;
  864. return 0;
  865. }
  866. // un-escape hex sequences (\xNN) in id
  867. static void txt_decode(char *txt) {
  868. if(!txt || !*txt)
  869. return;
  870. char *src = txt, *dst = txt;
  871. size_t id_len = strlen(src);
  872. size_t s = 0, d = 0;
  873. for(; s < id_len ; s++) {
  874. if(src[s] == '\\' && src[s + 1] == 'x' && isxdigit(src[s + 2]) && isxdigit(src[s + 3])) {
  875. int value = (hex_to_int(src[s + 2]) << 4) + hex_to_int(src[s + 3]);
  876. dst[d++] = (char)value;
  877. s += 3;
  878. }
  879. else
  880. dst[d++] = src[s];
  881. }
  882. dst[d] = '\0';
  883. }
  884. static UnitInfo *systemd_units_get_all(void) {
  885. _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
  886. _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
  887. _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
  888. UnitInfo *base = NULL;
  889. int r;
  890. r = sd_bus_default_system(&bus);
  891. if (r < 0) {
  892. log_dbus_error(r, "sd_bus_default_system()");
  893. return base;
  894. }
  895. // This calls the ListUnits method of the org.freedesktop.systemd1.Manager interface
  896. // Replace "ListUnits" with "ListUnitsFiltered" to get specific units based on filters
  897. r = sd_bus_call_method(bus,
  898. "org.freedesktop.systemd1", /* service to contact */
  899. "/org/freedesktop/systemd1", /* object path */
  900. "org.freedesktop.systemd1.Manager", /* interface name */
  901. "ListUnits", /* method name */
  902. &error, /* object to return error in */
  903. &reply, /* return message on success */
  904. NULL); /* input signature */
  905. if (r < 0) {
  906. log_dbus_error(r, "sd_bus_call_method()");
  907. return base;
  908. }
  909. r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, SYSTEMD_UNITS_DBUS_TYPES);
  910. if (r < 0) {
  911. log_dbus_error(r, "sd_bus_message_enter_container()");
  912. return base;
  913. }
  914. UnitInfo u;
  915. memset(&u, 0, sizeof(u));
  916. while ((r = bus_parse_unit_info(reply, &u)) > 0) {
  917. UnitInfo *i = callocz(1, sizeof(u));
  918. *i = u;
  919. i->id = strdupz(u.id && *u.id ? u.id : "-");
  920. txt_decode(i->id);
  921. i->type = strdupz(u.type && *u.type ? u.type : "-");
  922. i->description = strdupz(u.description && *u.description ? u.description : "-");
  923. txt_decode(i->description);
  924. i->load_state = strdupz(u.load_state && *u.load_state ? u.load_state : "-");
  925. i->active_state = strdupz(u.active_state && *u.active_state ? u.active_state : "-");
  926. i->sub_state = strdupz(u.sub_state && *u.sub_state ? u.sub_state : "-");
  927. i->following = strdupz(u.following && *u.following ? u.following : "-");
  928. i->unit_path = strdupz(u.unit_path && *u.unit_path ? u.unit_path : "-");
  929. i->job_type = strdupz(u.job_type && *u.job_type ? u.job_type : "-");
  930. i->job_path = strdupz(u.job_path && *u.job_path ? u.job_path : "-");
  931. i->job_id = u.job_id;
  932. DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(base, i, prev, next);
  933. memset(&u, 0, sizeof(u));
  934. }
  935. if (r < 0) {
  936. log_dbus_error(r, "sd_bus_message_read()");
  937. return base;
  938. }
  939. r = sd_bus_message_exit_container(reply);
  940. if (r < 0) {
  941. log_dbus_error(r, "sd_bus_message_exit_container()");
  942. return base;
  943. }
  944. systemd_units_get_all_properties(bus, base);
  945. return base;
  946. }
  947. void systemd_units_free_all(UnitInfo *base) {
  948. while(base) {
  949. UnitInfo *u = base;
  950. DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(base, u, prev, next);
  951. freez((void *)u->id);
  952. freez((void *)u->type);
  953. freez((void *)u->description);
  954. freez((void *)u->load_state);
  955. freez((void *)u->active_state);
  956. freez((void *)u->sub_state);
  957. freez((void *)u->following);
  958. freez((void *)u->unit_path);
  959. freez((void *)u->job_type);
  960. freez((void *)u->job_path);
  961. for(int i = 0; i < (ssize_t)_UNIT_ATTRIBUTE_MAX ;i++)
  962. systemd_unit_free_property(unit_attributes[i].value_type, &u->attributes[i]);
  963. freez(u);
  964. }
  965. }
  966. // ----------------------------------------------------------------------------
  967. static void netdata_systemd_units_function_help(const char *transaction) {
  968. BUFFER *wb = buffer_create(0, NULL);
  969. buffer_sprintf(wb,
  970. "%s / %s\n"
  971. "\n"
  972. "%s\n"
  973. "\n"
  974. "The following parameters are supported:\n"
  975. "\n"
  976. " help\n"
  977. " Shows this help message.\n"
  978. "\n"
  979. " info\n"
  980. " Request initial configuration information about the plugin.\n"
  981. " The key entity returned is the required_params array, which includes\n"
  982. " all the available systemd journal sources.\n"
  983. " When `info` is requested, all other parameters are ignored.\n"
  984. "\n"
  985. , program_name
  986. , SYSTEMD_UNITS_FUNCTION_NAME
  987. , SYSTEMD_UNITS_FUNCTION_DESCRIPTION
  988. );
  989. netdata_mutex_lock(&stdout_mutex);
  990. pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "text/plain", now_realtime_sec() + 3600, wb);
  991. netdata_mutex_unlock(&stdout_mutex);
  992. buffer_free(wb);
  993. }
  994. static void netdata_systemd_units_function_info(const char *transaction) {
  995. BUFFER *wb = buffer_create(0, NULL);
  996. buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
  997. buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
  998. buffer_json_member_add_string(wb, "type", "table");
  999. buffer_json_member_add_string(wb, "help", SYSTEMD_UNITS_FUNCTION_DESCRIPTION);
  1000. buffer_json_finalize(wb);
  1001. netdata_mutex_lock(&stdout_mutex);
  1002. pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "text/plain", now_realtime_sec() + 3600, wb);
  1003. netdata_mutex_unlock(&stdout_mutex);
  1004. buffer_free(wb);
  1005. }
  1006. // ----------------------------------------------------------------------------
  1007. static void systemd_unit_priority(UnitInfo *u, size_t units) {
  1008. uint32_t prio;
  1009. switch(u->severity) {
  1010. case FACET_ROW_SEVERITY_CRITICAL:
  1011. prio = 0;
  1012. break;
  1013. default:
  1014. case FACET_ROW_SEVERITY_WARNING:
  1015. prio = 1;
  1016. break;
  1017. case FACET_ROW_SEVERITY_NOTICE:
  1018. prio = 2;
  1019. break;
  1020. case FACET_ROW_SEVERITY_NORMAL:
  1021. prio = 3;
  1022. break;
  1023. case FACET_ROW_SEVERITY_DEBUG:
  1024. prio = 4;
  1025. break;
  1026. }
  1027. prio = prio * (uint32_t)(_UNIT_TYPE_MAX + 1) + (uint32_t)u->UnitType;
  1028. u->prio = (prio * units) + u->prio;
  1029. }
  1030. #define if_less(current, max, target) ({ \
  1031. typeof(current) _wanted = (current); \
  1032. if((current) < (target)) \
  1033. _wanted = (target) > (max) ? (max) : (target); \
  1034. _wanted; \
  1035. })
  1036. #define if_normal(current, max, target) ({ \
  1037. typeof(current) _wanted = (current); \
  1038. if((current) == FACET_ROW_SEVERITY_NORMAL) \
  1039. _wanted = (target) > (max) ? (max) : (target); \
  1040. _wanted; \
  1041. })
  1042. FACET_ROW_SEVERITY system_unit_severity(UnitInfo *u) {
  1043. FACET_ROW_SEVERITY severity, max_severity;
  1044. switch(u->UnitLoadState) {
  1045. case UNIT_ERROR:
  1046. case UNIT_BAD_SETTING:
  1047. severity = FACET_ROW_SEVERITY_CRITICAL;
  1048. max_severity = FACET_ROW_SEVERITY_CRITICAL;
  1049. break;
  1050. default:
  1051. severity = FACET_ROW_SEVERITY_WARNING;
  1052. max_severity = FACET_ROW_SEVERITY_CRITICAL;
  1053. break;
  1054. case UNIT_NOT_FOUND:
  1055. severity = FACET_ROW_SEVERITY_NOTICE;
  1056. max_severity = FACET_ROW_SEVERITY_NOTICE;
  1057. break;
  1058. case UNIT_LOADED:
  1059. severity = FACET_ROW_SEVERITY_NORMAL;
  1060. max_severity = FACET_ROW_SEVERITY_CRITICAL;
  1061. break;
  1062. case UNIT_MERGED:
  1063. case UNIT_MASKED:
  1064. case UNIT_STUB:
  1065. severity = FACET_ROW_SEVERITY_DEBUG;
  1066. max_severity = FACET_ROW_SEVERITY_DEBUG;
  1067. break;
  1068. }
  1069. switch(u->UnitActiveState) {
  1070. case UNIT_FAILED:
  1071. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1072. break;
  1073. default:
  1074. case UNIT_RELOADING:
  1075. case UNIT_ACTIVATING:
  1076. case UNIT_DEACTIVATING:
  1077. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1078. break;
  1079. case UNIT_MAINTENANCE:
  1080. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1081. break;
  1082. case UNIT_ACTIVE:
  1083. break;
  1084. case UNIT_INACTIVE:
  1085. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1086. break;
  1087. }
  1088. switch(u->FreezerState) {
  1089. default:
  1090. case FREEZER_FROZEN:
  1091. case FREEZER_FREEZING:
  1092. case FREEZER_THAWING:
  1093. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1094. break;
  1095. case FREEZER_RUNNING:
  1096. break;
  1097. }
  1098. switch(u->UnitType) {
  1099. case UNIT_SERVICE:
  1100. switch(u->ServiceState) {
  1101. case SERVICE_FAILED:
  1102. case SERVICE_FAILED_BEFORE_AUTO_RESTART:
  1103. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1104. break;
  1105. default:
  1106. case SERVICE_STOP:
  1107. case SERVICE_STOP_WATCHDOG:
  1108. case SERVICE_STOP_SIGTERM:
  1109. case SERVICE_STOP_SIGKILL:
  1110. case SERVICE_STOP_POST:
  1111. case SERVICE_FINAL_WATCHDOG:
  1112. case SERVICE_FINAL_SIGTERM:
  1113. case SERVICE_FINAL_SIGKILL:
  1114. case SERVICE_AUTO_RESTART:
  1115. case SERVICE_AUTO_RESTART_QUEUED:
  1116. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1117. break;
  1118. case SERVICE_CONDITION:
  1119. case SERVICE_START_PRE:
  1120. case SERVICE_START:
  1121. case SERVICE_START_POST:
  1122. case SERVICE_RELOAD:
  1123. case SERVICE_RELOAD_SIGNAL:
  1124. case SERVICE_RELOAD_NOTIFY:
  1125. case SERVICE_DEAD_RESOURCES_PINNED:
  1126. case SERVICE_CLEANING:
  1127. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1128. break;
  1129. case SERVICE_EXITED:
  1130. case SERVICE_RUNNING:
  1131. break;
  1132. case SERVICE_DEAD:
  1133. case SERVICE_DEAD_BEFORE_AUTO_RESTART:
  1134. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1135. break;
  1136. }
  1137. break;
  1138. case UNIT_MOUNT:
  1139. switch(u->MountState) {
  1140. case MOUNT_FAILED:
  1141. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1142. break;
  1143. default:
  1144. case MOUNT_REMOUNTING_SIGTERM:
  1145. case MOUNT_REMOUNTING_SIGKILL:
  1146. case MOUNT_UNMOUNTING_SIGTERM:
  1147. case MOUNT_UNMOUNTING_SIGKILL:
  1148. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1149. break;
  1150. case MOUNT_MOUNTING:
  1151. case MOUNT_MOUNTING_DONE:
  1152. case MOUNT_REMOUNTING:
  1153. case MOUNT_UNMOUNTING:
  1154. case MOUNT_CLEANING:
  1155. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1156. break;
  1157. case MOUNT_MOUNTED:
  1158. break;
  1159. case MOUNT_DEAD:
  1160. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1161. break;
  1162. }
  1163. break;
  1164. case UNIT_SWAP:
  1165. switch(u->SwapState) {
  1166. case SWAP_FAILED:
  1167. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1168. break;
  1169. default:
  1170. case SWAP_DEACTIVATING_SIGTERM:
  1171. case SWAP_DEACTIVATING_SIGKILL:
  1172. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1173. break;
  1174. case SWAP_ACTIVATING:
  1175. case SWAP_ACTIVATING_DONE:
  1176. case SWAP_DEACTIVATING:
  1177. case SWAP_CLEANING:
  1178. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1179. break;
  1180. case SWAP_ACTIVE:
  1181. break;
  1182. case SWAP_DEAD:
  1183. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1184. break;
  1185. }
  1186. break;
  1187. case UNIT_SOCKET:
  1188. switch(u->SocketState) {
  1189. case SOCKET_FAILED:
  1190. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1191. break;
  1192. default:
  1193. case SOCKET_STOP_PRE_SIGTERM:
  1194. case SOCKET_STOP_PRE_SIGKILL:
  1195. case SOCKET_FINAL_SIGTERM:
  1196. case SOCKET_FINAL_SIGKILL:
  1197. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1198. break;
  1199. case SOCKET_START_PRE:
  1200. case SOCKET_START_CHOWN:
  1201. case SOCKET_START_POST:
  1202. case SOCKET_STOP_PRE:
  1203. case SOCKET_STOP_POST:
  1204. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1205. break;
  1206. case SOCKET_RUNNING:
  1207. case SOCKET_LISTENING:
  1208. break;
  1209. case SOCKET_DEAD:
  1210. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1211. break;
  1212. }
  1213. break;
  1214. case UNIT_TARGET:
  1215. switch(u->TargetState) {
  1216. default:
  1217. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1218. break;
  1219. case TARGET_ACTIVE:
  1220. break;
  1221. case TARGET_DEAD:
  1222. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1223. break;
  1224. }
  1225. break;
  1226. case UNIT_DEVICE:
  1227. switch(u->DeviceState) {
  1228. default:
  1229. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1230. break;
  1231. case DEVICE_TENTATIVE:
  1232. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1233. break;
  1234. case DEVICE_PLUGGED:
  1235. break;
  1236. case DEVICE_DEAD:
  1237. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1238. break;
  1239. }
  1240. break;
  1241. case UNIT_AUTOMOUNT:
  1242. switch(u->AutomountState) {
  1243. case AUTOMOUNT_FAILED:
  1244. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1245. break;
  1246. default:
  1247. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1248. break;
  1249. case AUTOMOUNT_WAITING:
  1250. case AUTOMOUNT_RUNNING:
  1251. break;
  1252. case AUTOMOUNT_DEAD:
  1253. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1254. break;
  1255. }
  1256. break;
  1257. case UNIT_TIMER:
  1258. switch(u->TimerState) {
  1259. case TIMER_FAILED:
  1260. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1261. break;
  1262. default:
  1263. case TIMER_ELAPSED:
  1264. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1265. break;
  1266. case TIMER_WAITING:
  1267. case TIMER_RUNNING:
  1268. break;
  1269. case TIMER_DEAD:
  1270. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1271. break;
  1272. }
  1273. break;
  1274. case UNIT_PATH:
  1275. switch(u->PathState) {
  1276. case PATH_FAILED:
  1277. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1278. break;
  1279. default:
  1280. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1281. break;
  1282. case PATH_WAITING:
  1283. case PATH_RUNNING:
  1284. break;
  1285. case PATH_DEAD:
  1286. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1287. break;
  1288. }
  1289. break;
  1290. case UNIT_SLICE:
  1291. switch(u->SliceState) {
  1292. default:
  1293. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1294. break;
  1295. case SLICE_ACTIVE:
  1296. break;
  1297. case SLICE_DEAD:
  1298. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1299. break;
  1300. }
  1301. break;
  1302. case UNIT_SCOPE:
  1303. switch(u->ScopeState) {
  1304. case SCOPE_FAILED:
  1305. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_CRITICAL);
  1306. break;
  1307. default:
  1308. case SCOPE_STOP_SIGTERM:
  1309. case SCOPE_STOP_SIGKILL:
  1310. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1311. break;
  1312. case SCOPE_ABANDONED:
  1313. case SCOPE_START_CHOWN:
  1314. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_NOTICE);
  1315. break;
  1316. case SCOPE_RUNNING:
  1317. break;
  1318. case SCOPE_DEAD:
  1319. severity = if_normal(severity, max_severity, FACET_ROW_SEVERITY_DEBUG);
  1320. break;
  1321. }
  1322. break;
  1323. default:
  1324. severity = if_less(severity, max_severity, FACET_ROW_SEVERITY_WARNING);
  1325. break;
  1326. }
  1327. u->severity = severity;
  1328. return severity;
  1329. }
  1330. int unit_info_compar(const void *a, const void *b) {
  1331. UnitInfo *u1 = *((UnitInfo **)a);
  1332. UnitInfo *u2 = *((UnitInfo **)b);
  1333. return strcasecmp(u1->id, u2->id);
  1334. }
  1335. void systemd_units_assign_priority(UnitInfo *base) {
  1336. size_t units = 0, c = 0, prio = 0;
  1337. for(UnitInfo *u = base; u ; u = u->next)
  1338. units++;
  1339. UnitInfo *array[units];
  1340. for(UnitInfo *u = base; u ; u = u->next)
  1341. array[c++] = u;
  1342. qsort(array, units, sizeof(UnitInfo *), unit_info_compar);
  1343. for(c = 0; c < units ; c++) {
  1344. array[c]->prio = prio++;
  1345. system_unit_severity(array[c]);
  1346. systemd_unit_priority(array[c], units);
  1347. }
  1348. }
  1349. void function_systemd_units(const char *transaction, char *function,
  1350. usec_t *stop_monotonic_ut __maybe_unused, bool *cancelled __maybe_unused,
  1351. BUFFER *payload __maybe_unused, const char *source __maybe_unused, void *data __maybe_unused) {
  1352. char *words[SYSTEMD_UNITS_MAX_PARAMS] = { NULL };
  1353. size_t num_words = quoted_strings_splitter_pluginsd(function, words, SYSTEMD_UNITS_MAX_PARAMS);
  1354. for(int i = 1; i < SYSTEMD_UNITS_MAX_PARAMS ;i++) {
  1355. char *keyword = get_word(words, num_words, i);
  1356. if(!keyword) break;
  1357. if(strcmp(keyword, "info") == 0) {
  1358. netdata_systemd_units_function_info(transaction);
  1359. return;
  1360. }
  1361. else if(strcmp(keyword, "help") == 0) {
  1362. netdata_systemd_units_function_help(transaction);
  1363. return;
  1364. }
  1365. }
  1366. UnitInfo *base = systemd_units_get_all();
  1367. systemd_units_assign_priority(base);
  1368. BUFFER *wb = buffer_create(0, NULL);
  1369. buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
  1370. buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
  1371. buffer_json_member_add_string(wb, "type", "table");
  1372. buffer_json_member_add_time_t(wb, "update_every", 10);
  1373. buffer_json_member_add_string(wb, "help", SYSTEMD_UNITS_FUNCTION_DESCRIPTION);
  1374. buffer_json_member_add_array(wb, "data");
  1375. size_t count[_UNIT_ATTRIBUTE_MAX] = { 0 };
  1376. struct UnitAttribute max[_UNIT_ATTRIBUTE_MAX];
  1377. for(UnitInfo *u = base; u ;u = u->next) {
  1378. buffer_json_add_array_item_array(wb);
  1379. {
  1380. buffer_json_add_array_item_string(wb, u->id);
  1381. buffer_json_add_array_item_object(wb);
  1382. {
  1383. buffer_json_member_add_string(wb, "severity", facets_severity_to_string(u->severity));
  1384. }
  1385. buffer_json_object_close(wb);
  1386. buffer_json_add_array_item_string(wb, u->type);
  1387. buffer_json_add_array_item_string(wb, u->description);
  1388. buffer_json_add_array_item_string(wb, u->load_state);
  1389. buffer_json_add_array_item_string(wb, u->active_state);
  1390. buffer_json_add_array_item_string(wb, u->sub_state);
  1391. buffer_json_add_array_item_string(wb, u->following);
  1392. buffer_json_add_array_item_string(wb, u->unit_path);
  1393. buffer_json_add_array_item_uint64(wb, u->job_id);
  1394. buffer_json_add_array_item_string(wb, u->job_type);
  1395. buffer_json_add_array_item_string(wb, u->job_path);
  1396. for(ssize_t i = 0; i < (ssize_t)_UNIT_ATTRIBUTE_MAX ;i++) {
  1397. switch(unit_attributes[i].value_type) {
  1398. case SD_BUS_TYPE_OBJECT_PATH:
  1399. case SD_BUS_TYPE_STRING:
  1400. buffer_json_add_array_item_string(wb, u->attributes[i].str && *u->attributes[i].str ? u->attributes[i].str : "-");
  1401. break;
  1402. case SD_BUS_TYPE_UINT64:
  1403. buffer_json_add_array_item_uint64(wb, u->attributes[i].uint64);
  1404. if(!count[i]++) max[i].uint64 = 0;
  1405. max[i].uint64 = MAX(max[i].uint64, u->attributes[i].uint64);
  1406. break;
  1407. case SD_BUS_TYPE_UINT32:
  1408. buffer_json_add_array_item_uint64(wb, u->attributes[i].uint32);
  1409. if(!count[i]++) max[i].uint32 = 0;
  1410. max[i].uint32 = MAX(max[i].uint32, u->attributes[i].uint32);
  1411. break;
  1412. case SD_BUS_TYPE_INT64:
  1413. buffer_json_add_array_item_uint64(wb, u->attributes[i].int64);
  1414. if(!count[i]++) max[i].uint64 = 0;
  1415. max[i].int64 = MAX(max[i].int64, u->attributes[i].int64);
  1416. break;
  1417. case SD_BUS_TYPE_INT32:
  1418. buffer_json_add_array_item_uint64(wb, u->attributes[i].int32);
  1419. if(!count[i]++) max[i].int32 = 0;
  1420. max[i].int32 = MAX(max[i].int32, u->attributes[i].int32);
  1421. break;
  1422. case SD_BUS_TYPE_DOUBLE:
  1423. buffer_json_add_array_item_double(wb, u->attributes[i].dbl);
  1424. if(!count[i]++) max[i].dbl = 0.0;
  1425. max[i].dbl = MAX(max[i].dbl, u->attributes[i].dbl);
  1426. break;
  1427. case SD_BUS_TYPE_BOOLEAN:
  1428. buffer_json_add_array_item_boolean(wb, u->attributes[i].boolean);
  1429. break;
  1430. default:
  1431. break;
  1432. }
  1433. }
  1434. buffer_json_add_array_item_uint64(wb, u->prio);
  1435. buffer_json_add_array_item_uint64(wb, 1); // count
  1436. }
  1437. buffer_json_array_close(wb);
  1438. }
  1439. buffer_json_array_close(wb); // data
  1440. buffer_json_member_add_object(wb, "columns");
  1441. {
  1442. size_t field_id = 0;
  1443. buffer_rrdf_table_add_field(wb, field_id++, "id", "Unit ID",
  1444. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1445. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1446. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1447. RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_WRAP | RRDF_FIELD_OPTS_FULL_WIDTH,
  1448. NULL);
  1449. buffer_rrdf_table_add_field(
  1450. wb, field_id++,
  1451. "rowOptions", "rowOptions",
  1452. RRDF_FIELD_TYPE_NONE,
  1453. RRDR_FIELD_VISUAL_ROW_OPTIONS,
  1454. RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
  1455. RRDF_FIELD_SORT_FIXED,
  1456. NULL,
  1457. RRDF_FIELD_SUMMARY_COUNT,
  1458. RRDF_FIELD_FILTER_NONE,
  1459. RRDF_FIELD_OPTS_DUMMY,
  1460. NULL);
  1461. buffer_rrdf_table_add_field(wb, field_id++, "type", "Unit Type",
  1462. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1463. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1464. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
  1465. RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_EXPANDED_FILTER,
  1466. NULL);
  1467. buffer_rrdf_table_add_field(wb, field_id++, "description", "Unit Description",
  1468. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1469. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1470. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1471. RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_WRAP | RRDF_FIELD_OPTS_FULL_WIDTH,
  1472. NULL);
  1473. buffer_rrdf_table_add_field(wb, field_id++, "loadState", "Unit Load State",
  1474. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1475. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1476. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
  1477. RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_EXPANDED_FILTER,
  1478. NULL);
  1479. buffer_rrdf_table_add_field(wb, field_id++, "activeState", "Unit Active State",
  1480. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1481. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1482. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
  1483. RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_EXPANDED_FILTER,
  1484. NULL);
  1485. buffer_rrdf_table_add_field(wb, field_id++, "subState", "Unit Sub State",
  1486. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1487. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1488. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
  1489. RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_EXPANDED_FILTER,
  1490. NULL);
  1491. buffer_rrdf_table_add_field(wb, field_id++, "following", "Unit Following",
  1492. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1493. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1494. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1495. RRDF_FIELD_OPTS_WRAP,
  1496. NULL);
  1497. buffer_rrdf_table_add_field(wb, field_id++, "path", "Unit Path",
  1498. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1499. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1500. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1501. RRDF_FIELD_OPTS_WRAP | RRDF_FIELD_OPTS_FULL_WIDTH,
  1502. NULL);
  1503. buffer_rrdf_table_add_field(wb, field_id++, "jobId", "Unit Job ID",
  1504. RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1505. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1506. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1507. RRDF_FIELD_OPTS_NONE,
  1508. NULL);
  1509. buffer_rrdf_table_add_field(wb, field_id++, "jobType", "Unit Job Type",
  1510. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1511. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1512. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
  1513. RRDF_FIELD_OPTS_NONE,
  1514. NULL);
  1515. buffer_rrdf_table_add_field(wb, field_id++, "jobPath", "Unit Job Path",
  1516. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1517. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1518. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1519. RRDF_FIELD_OPTS_WRAP | RRDF_FIELD_OPTS_FULL_WIDTH,
  1520. NULL);
  1521. for(ssize_t i = 0; i < (ssize_t)_UNIT_ATTRIBUTE_MAX ;i++) {
  1522. char key[256], name[256];
  1523. if(unit_attributes[i].show_as)
  1524. snprintfz(key, sizeof(key), "%s", unit_attributes[i].show_as);
  1525. else
  1526. snprintfz(key, sizeof(key), "attribute%s", unit_property_name_to_string_from_slot(i));
  1527. if(unit_attributes[i].info)
  1528. snprintfz(name, sizeof(name), "%s", unit_attributes[i].info);
  1529. else
  1530. snprintfz(name, sizeof(name), "Attribute %s", unit_property_name_to_string_from_slot(i));
  1531. RRDF_FIELD_OPTIONS options = unit_attributes[i].options;
  1532. RRDF_FIELD_FILTER filter = unit_attributes[i].filter;
  1533. switch(unit_attributes[i].value_type) {
  1534. case SD_BUS_TYPE_OBJECT_PATH:
  1535. case SD_BUS_TYPE_STRING:
  1536. buffer_rrdf_table_add_field(wb, field_id++, key, name,
  1537. RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1538. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1539. RRDF_FIELD_SUMMARY_COUNT, filter,
  1540. RRDF_FIELD_OPTS_WRAP | options,
  1541. NULL);
  1542. break;
  1543. case SD_BUS_TYPE_INT32:
  1544. case SD_BUS_TYPE_UINT32:
  1545. case SD_BUS_TYPE_INT64:
  1546. case SD_BUS_TYPE_UINT64: {
  1547. double m = 0.0;
  1548. if(unit_attributes[i].value_type == SD_BUS_TYPE_UINT64)
  1549. m = (double)max[i].uint64;
  1550. else if(unit_attributes[i].value_type == SD_BUS_TYPE_INT64)
  1551. m = (double)max[i].int64;
  1552. else if(unit_attributes[i].value_type == SD_BUS_TYPE_UINT32)
  1553. m = (double)max[i].uint32;
  1554. else if(unit_attributes[i].value_type == SD_BUS_TYPE_INT32)
  1555. m = (double)max[i].int32;
  1556. buffer_rrdf_table_add_field(wb, field_id++, key, name,
  1557. RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1558. 0, NULL, m, RRDF_FIELD_SORT_ASCENDING, NULL,
  1559. RRDF_FIELD_SUMMARY_SUM, filter,
  1560. RRDF_FIELD_OPTS_WRAP | options,
  1561. NULL);
  1562. }
  1563. break;
  1564. case SD_BUS_TYPE_DOUBLE:
  1565. buffer_rrdf_table_add_field(wb, field_id++, key, name,
  1566. RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1567. 2, NULL, max[i].dbl, RRDF_FIELD_SORT_ASCENDING, NULL,
  1568. RRDF_FIELD_SUMMARY_SUM, filter,
  1569. RRDF_FIELD_OPTS_WRAP | options,
  1570. NULL);
  1571. break;
  1572. case SD_BUS_TYPE_BOOLEAN:
  1573. buffer_rrdf_table_add_field(wb, field_id++, key, name,
  1574. RRDF_FIELD_TYPE_BOOLEAN, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1575. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1576. RRDF_FIELD_SUMMARY_COUNT, filter,
  1577. RRDF_FIELD_OPTS_WRAP | options,
  1578. NULL);
  1579. break;
  1580. default:
  1581. break;
  1582. }
  1583. }
  1584. buffer_rrdf_table_add_field(wb, field_id++, "priority", "Priority",
  1585. RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1586. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1587. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1588. RRDF_FIELD_OPTS_NONE,
  1589. NULL);
  1590. buffer_rrdf_table_add_field(wb, field_id++, "count", "Count",
  1591. RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
  1592. 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
  1593. RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_NONE,
  1594. RRDF_FIELD_OPTS_NONE,
  1595. NULL);
  1596. }
  1597. buffer_json_object_close(wb); // columns
  1598. buffer_json_member_add_string(wb, "default_sort_column", "priority");
  1599. buffer_json_member_add_object(wb, "charts");
  1600. {
  1601. buffer_json_member_add_object(wb, "count");
  1602. {
  1603. buffer_json_member_add_string(wb, "name", "count");
  1604. buffer_json_member_add_string(wb, "type", "stacked-bar");
  1605. buffer_json_member_add_array(wb, "columns");
  1606. {
  1607. buffer_json_add_array_item_string(wb, "count");
  1608. }
  1609. buffer_json_array_close(wb);
  1610. }
  1611. buffer_json_object_close(wb);
  1612. }
  1613. buffer_json_object_close(wb); // charts
  1614. buffer_json_member_add_array(wb, "default_charts");
  1615. {
  1616. buffer_json_add_array_item_array(wb);
  1617. buffer_json_add_array_item_string(wb, "count");
  1618. buffer_json_add_array_item_string(wb, "activeState");
  1619. buffer_json_array_close(wb);
  1620. buffer_json_add_array_item_array(wb);
  1621. buffer_json_add_array_item_string(wb, "count");
  1622. buffer_json_add_array_item_string(wb, "subState");
  1623. buffer_json_array_close(wb);
  1624. }
  1625. buffer_json_array_close(wb);
  1626. buffer_json_member_add_object(wb, "group_by");
  1627. {
  1628. buffer_json_member_add_object(wb, "type");
  1629. {
  1630. buffer_json_member_add_string(wb, "name", "Top Down Tree");
  1631. buffer_json_member_add_array(wb, "columns");
  1632. {
  1633. buffer_json_add_array_item_string(wb, "type");
  1634. buffer_json_add_array_item_string(wb, "loadState");
  1635. buffer_json_add_array_item_string(wb, "activeState");
  1636. buffer_json_add_array_item_string(wb, "subState");
  1637. }
  1638. buffer_json_array_close(wb);
  1639. }
  1640. buffer_json_object_close(wb);
  1641. buffer_json_member_add_object(wb, "subState");
  1642. {
  1643. buffer_json_member_add_string(wb, "name", "Bottom Up Tree");
  1644. buffer_json_member_add_array(wb, "columns");
  1645. {
  1646. buffer_json_add_array_item_string(wb, "subState");
  1647. buffer_json_add_array_item_string(wb, "activeState");
  1648. buffer_json_add_array_item_string(wb, "loadState");
  1649. buffer_json_add_array_item_string(wb, "type");
  1650. }
  1651. buffer_json_array_close(wb);
  1652. }
  1653. buffer_json_object_close(wb);
  1654. }
  1655. buffer_json_object_close(wb); // group_by
  1656. buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
  1657. buffer_json_finalize(wb);
  1658. netdata_mutex_lock(&stdout_mutex);
  1659. pluginsd_function_result_to_stdout(transaction, HTTP_RESP_OK, "application/json", now_realtime_sec() + 1, wb);
  1660. netdata_mutex_unlock(&stdout_mutex);
  1661. buffer_free(wb);
  1662. systemd_units_free_all(base);
  1663. }
  1664. #endif // ENABLE_SYSTEMD_DBUS