2 Copyright (C) 2015-2020 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
27 #include <sys/types.h>
31 # include <systemd/sd-bus.h>
32 # include <systemd/sd-bus-protocol.h>
35 struct sd_bus_message;
36 typedef struct { const char *name; const char *message; } sd_bus_error;
37 # define sd_bus_unref(...) ((void)0)
38 # define sd_bus_default_user(p) ((*(p)=NULL),(-ENOTSUP))
39 # define sd_bus_default_system(p) ((*(p)=NULL),(-ENOTSUP))
40 # define sd_bus_call_method(...) (-ENOTSUP)
41 # define SD_BUS_ERROR_NULL {NULL,NULL}
42 # define sd_bus_message_read_basic(...) (-ENOTSUP)
43 # define sd_bus_message_unref(...) (NULL)
44 # define sd_bus_get_property_string(...) (-ENOTSUP)
45 # define sd_bus_get_property_trivial(...) (-ENOTSUP)
48 #include "utils-systemd.h"
50 #if !defined(SYSTEMD_UNITS_ROOT)
51 # define SYSTEMD_UNITS_ROOT "/usr/local/lib/systemd"
54 static const char sdb_path[] = "/org/freedesktop/systemd1";
55 static const char sdb_destination[] = "org.freedesktop.systemd1";
56 static const char sdbi_manager[] = "org.freedesktop.systemd1.Manager";
57 static const char sdbi_unit[] = "org.freedesktop.systemd1.Unit";
58 static const char sdbi_service[] = "org.freedesktop.systemd1.Service";
59 static const char sdbi_job[] = "org.freedesktop.systemd1.Job";
60 static const char sdbj_state[] = "State";
61 static const char sdbm_reload[] = "Reload";
62 static const char sdbm_start_unit[] = "StartUnit";
63 static const char sdbm_restart_unit[] = "RestartUnit";
64 static const char sdbm_stop_unit[] = "StopUnit";
65 static const char sdbm_start[] = "Start";
66 static const char sdbm_restart[] = "Restart";
67 static const char sdbm_stop[] = "Stop";
68 static const char sdbm_get_unit[] = "GetUnit";
69 static const char sdbm_get_unit_by_pid[] = "GetUnitByPID";
70 static const char sdbm_load_unit[] = "LoadUnit";
71 static const char sdbp_active_state[] = "ActiveState";
72 static const char sdbp_exec_main_pid[] = "ExecMainPID";
74 static const char *sds_state_names[] = {
84 static const char *sds_job_state_names[] = {
90 static struct sd_bus *sysbus;
91 static struct sd_bus *usrbus;
94 * Translate systemd errors to errno errors
96 static int seterrno(int value)
102 static int sderr2errno(int rc)
104 return rc < 0 ? seterrno(-rc) : rc;
107 static int errno2sderr(int rc)
109 return rc < 0 ? -errno : rc;
113 * Returns in 'ret' either the system bus (if isuser==0)
114 * or the user bus (if isuser!=0).
115 * Returns 0 in case of success or -1 in case of error
117 int systemd_get_bus(int isuser, struct sd_bus **ret)
122 bus = isuser ? usrbus : sysbus;
126 rc = sd_bus_default_user(ret);
131 rc = sd_bus_default_system(ret);
138 return sderr2errno(rc);
141 void systemd_set_bus(int isuser, struct sd_bus *bus)
143 struct sd_bus **target = isuser ? &usrbus : &sysbus;
145 sd_bus_unref(*target);
150 /********************************************************************
151 * routines for escaping unit names to compute dbus path of units
152 *******************************************************************/
154 * Should the char 'c' be escaped?
156 static inline int should_escape_for_path(char c)
159 return c <= (c >= 'a' ? 'z' : 'Z');
161 return c >= '0' && c <= '9';
166 * ascii char for the hexadecimal digit 'x'
168 static inline char d2h(int x)
170 return (char)(x + (x > 9 ? ('a' - 10) : '0'));
174 * escapes in 'path' of 'pathlen' the 'unit'
175 * returns 0 in case of success or -1 in case of error
177 static int unit_escape_for_path(char *path, size_t pathlen, const char *unit)
184 if (should_escape_for_path(c)) {
185 if (w + 2 >= pathlen)
188 path[w++] = d2h((c >> 4) & 15);;
189 path[w++] = d2h(c & 15);
202 return seterrno(ENAMETOOLONG);
206 /********************************************************************
207 * Routines for getting paths
208 *******************************************************************/
210 static char *get_dpath(struct sd_bus_message *msg)
216 rc = sd_bus_message_read_basic(msg, 'o', &reply);
217 rc = sderr2errno(rc);
221 result = strdup(reply);
225 sd_bus_message_unref(msg);
229 static char *get_unit_dpath(struct sd_bus *bus, const char *unit, int load)
232 struct sd_bus_message *ret = NULL;
233 sd_bus_error err = SD_BUS_ERROR_NULL;
235 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, load ? sdbm_load_unit : sdbm_get_unit, &err, &ret, "s", unit);
239 return get_dpath(ret);
241 sd_bus_message_unref(ret);
245 static char *get_unit_dpath_by_pid(struct sd_bus *bus, unsigned pid)
248 struct sd_bus_message *ret = NULL;
249 sd_bus_error err = SD_BUS_ERROR_NULL;
251 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_get_unit_by_pid, &err, &ret, "u", pid);
255 return get_dpath(ret);
257 sd_bus_message_unref(ret);
261 static int unit_pid(struct sd_bus *bus, const char *dpath)
265 sd_bus_error err = SD_BUS_ERROR_NULL;
267 rc = sd_bus_get_property_trivial(bus, sdb_destination, dpath, sdbi_service, sdbp_exec_main_pid, &err, 'u', &u);
268 return rc < 0 ? rc : (int)u;
271 static enum SysD_State unit_state(struct sd_bus *bus, const char *dpath)
275 enum SysD_State resu;
276 sd_bus_error err = SD_BUS_ERROR_NULL;
278 resu = SysD_State_INVALID;
279 rc = sd_bus_get_property_string(bus, sdb_destination, dpath, sdbi_unit, sdbp_active_state, &err, &st);
285 if (!strcmp(st, sds_state_names[SysD_State_Active]))
286 resu = SysD_State_Active;
287 else if (!strcmp(st, sds_state_names[SysD_State_Activating]))
288 resu = SysD_State_Activating;
291 if (!strcmp(st, sds_state_names[SysD_State_Deactivating]))
292 resu = SysD_State_Deactivating;
295 if (!strcmp(st, sds_state_names[SysD_State_Failed]))
296 resu = SysD_State_Failed;
299 if (!strcmp(st, sds_state_names[SysD_State_Inactive]))
300 resu = SysD_State_Inactive;
303 if (!strcmp(st, sds_state_names[SysD_State_Reloading]))
304 resu = SysD_State_Reloading;
316 static int job_wait(struct sd_bus *bus, struct sd_bus_message *job)
319 sd_bus_error err = SD_BUS_ERROR_NULL;
320 const char *jpath = NULL;
322 struct timespec tispec;
323 const int period_ms = 10;
324 const int trial_s = 10;
325 const int trial_count = (trial_s * 1000) / period_ms;
326 const int period_ns = period_ms * 1000000;
330 rc = sd_bus_message_read_basic(job, 'o', &jpath);
334 /* Wait for job to enter "running" state */
336 for (trial = 1 ; trial <= trial_count ; trial++) {
338 if(sd_bus_get_property_string(bus, sdb_destination, jpath, sdbi_job, sdbj_state, &err, &jstate) >= 0) {
339 if(jstate && strcmp(jstate, sds_job_state_names[SysD_Job_State_Running]) == 0) {
344 tispec.tv_nsec = period_ns;
345 nanosleep(&tispec, NULL);
350 if(trial > trial_count)
356 static int unit_start(struct sd_bus *bus, const char *dpath)
359 struct sd_bus_message *ret = NULL;
360 sd_bus_error err = SD_BUS_ERROR_NULL;
362 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_start, &err, &ret, "s", "replace");
364 rc = job_wait(bus, ret);
366 sd_bus_message_unref(ret);
370 static int unit_restart(struct sd_bus *bus, const char *dpath)
373 struct sd_bus_message *ret = NULL;
374 sd_bus_error err = SD_BUS_ERROR_NULL;
376 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_restart, &err, &ret, "s", "replace");
378 rc = job_wait(bus, ret);
380 sd_bus_message_unref(ret);
384 static int unit_stop(struct sd_bus *bus, const char *dpath)
387 struct sd_bus_message *ret = NULL;
388 sd_bus_error err = SD_BUS_ERROR_NULL;
390 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_stop, &err, &ret, "s", "replace");
391 sd_bus_message_unref(ret);
395 static int unit_start_name(struct sd_bus *bus, const char *name)
398 struct sd_bus_message *ret = NULL;
399 sd_bus_error err = SD_BUS_ERROR_NULL;
401 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_start_unit, &err, &ret, "ss", name, "replace");
403 rc = job_wait(bus, ret);
405 sd_bus_message_unref(ret);
409 static int unit_restart_name(struct sd_bus *bus, const char *name)
412 struct sd_bus_message *ret = NULL;
413 sd_bus_error err = SD_BUS_ERROR_NULL;
415 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_restart_unit, &err, &ret, "ss", name, "replace");
417 rc = job_wait(bus, ret);
419 sd_bus_message_unref(ret);
423 static int unit_stop_name(struct sd_bus *bus, const char *name)
426 struct sd_bus_message *ret = NULL;
427 sd_bus_error err = SD_BUS_ERROR_NULL;
429 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_stop_unit, &err, &ret, "ss", name, "replace");
430 sd_bus_message_unref(ret);
434 /********************************************************************
436 *******************************************************************/
438 static int check_snprintf_result(int rc, size_t buflen)
440 return (rc >= 0 && (size_t)rc >= buflen) ? seterrno(ENAMETOOLONG) : rc;
443 int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
445 int rc = snprintf(path, pathlen, "%s/%s",
447 isuser ? "user" : "system");
449 return check_snprintf_result(rc, pathlen);
452 int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext)
454 int rc = snprintf(path, pathlen, "%s/%s/%s.%s",
456 isuser ? "user" : "system",
460 return check_snprintf_result(rc, pathlen);
463 int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext)
465 int rc = snprintf(path, pathlen, "%s/%s/%s.wants/%s.%s",
467 isuser ? "user" : "system",
472 return check_snprintf_result(rc, pathlen);
475 int systemd_get_wants_target(char *path, size_t pathlen, const char *unit, const char *uext)
477 int rc = snprintf(path, pathlen, "../%s.%s", unit, uext);
479 return check_snprintf_result(rc, pathlen);
482 int systemd_daemon_reload(int isuser)
486 struct sd_bus_message *ret = NULL;
487 sd_bus_error err = SD_BUS_ERROR_NULL;
489 rc = systemd_get_bus(isuser, &bus);
491 /* TODO: asynchronous bind... */
492 /* TODO: more diagnostic... */
493 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, &err, &ret, NULL);
494 sd_bus_message_unref(ret);
499 int systemd_unit_list(int isuser, int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
502 char path[PATH_MAX + 1];
509 rc = systemd_get_units_dir(path, sizeof path - 1, isuser);
514 /* open the directory */
520 path[offset++] = '/';
522 /* read the directory */
534 if (dent->d_type == DT_REG)
536 else if (dent->d_type != DT_UNKNOWN)
539 rc = fstatat(dirfd(dir), dent->d_name, &st, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT);
542 isfile = S_ISREG(st.st_mode);
545 /* calls the callback if is a file */
547 len = strlen(dent->d_name);
548 if (offset + len >= sizeof path) {
549 rc = seterrno(ENAMETOOLONG);
552 memcpy(&path[offset], dent->d_name, 1 + len);
553 rc = callback(closure, &path[offset], path, isuser);
562 int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
564 return systemd_unit_list(1, callback, closure) ? : systemd_unit_list(0, callback, closure);
567 char *systemd_unit_dpath_by_name(int isuser, const char *name, int load)
571 return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath(bus, name, load);
574 char *systemd_unit_dpath_by_pid(int isuser, unsigned pid)
578 return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath_by_pid(bus, pid);
581 int systemd_unit_start_dpath(int isuser, const char *dpath)
586 rc = systemd_get_bus(isuser, &bus);
587 return rc < 0 ? rc : unit_start(bus, dpath);
590 int systemd_unit_restart_dpath(int isuser, const char *dpath)
595 rc = systemd_get_bus(isuser, &bus);
596 return rc < 0 ? rc : unit_restart(bus, dpath);
599 int systemd_unit_stop_dpath(int isuser, const char *dpath)
604 rc = systemd_get_bus(isuser, &bus);
605 return rc < 0 ? rc : unit_stop(bus, dpath);
608 int systemd_unit_start_name(int isuser, const char *name)
613 rc = systemd_get_bus(isuser, &bus);
615 rc = unit_start_name(bus, name);
619 int systemd_unit_restart_name(int isuser, const char *name)
624 rc = systemd_get_bus(isuser, &bus);
626 rc = unit_restart_name(bus, name);
630 int systemd_unit_stop_name(int isuser, const char *name)
635 rc = systemd_get_bus(isuser, &bus);
637 rc = unit_stop_name(bus, name);
641 int systemd_unit_stop_pid(int isuser, unsigned pid)
647 rc = systemd_get_bus(isuser, &bus);
649 dpath = get_unit_dpath_by_pid(bus, pid);
653 rc = unit_stop(bus, dpath);
660 int systemd_unit_pid_of_dpath(int isuser, const char *dpath)
665 rc = systemd_get_bus(isuser, &bus);
666 return rc < 0 ? rc : unit_pid(bus, dpath);
669 enum SysD_State systemd_unit_state_of_dpath(int isuser, const char *dpath)
674 rc = systemd_get_bus(isuser, &bus);
675 return rc < 0 ? SysD_State_INVALID : unit_state(bus, dpath);
678 const char *systemd_state_name(enum SysD_State state)
680 return sds_state_names[state];