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>
32 # include <systemd/sd-bus.h>
33 # include <systemd/sd-bus-protocol.h>
36 struct sd_bus_message;
37 typedef struct { const char *name; const char *message; } sd_bus_error;
38 # define sd_bus_unref(...) ((void)0)
39 # define sd_bus_default_user(p) ((*(p)=NULL),(-ENOTSUP))
40 # define sd_bus_default_system(p) ((*(p)=NULL),(-ENOTSUP))
41 # define sd_bus_call_method(...) (-ENOTSUP)
42 # define SD_BUS_ERROR_NULL {NULL,NULL}
43 # define sd_bus_message_read_basic(...) (-ENOTSUP)
44 # define sd_bus_message_unref(...) (NULL)
45 # define sd_bus_get_property_string(...) (-ENOTSUP)
46 # define sd_bus_get_property_trivial(...) (-ENOTSUP)
49 #include "utils-systemd.h"
51 #if !defined(SYSTEMD_UNITS_ROOT)
52 # define SYSTEMD_UNITS_ROOT "/usr/local/lib/systemd"
55 static const char sdb_path[] = "/org/freedesktop/systemd1";
56 static const char sdb_destination[] = "org.freedesktop.systemd1";
57 static const char sdbi_manager[] = "org.freedesktop.systemd1.Manager";
58 static const char sdbi_unit[] = "org.freedesktop.systemd1.Unit";
59 static const char sdbi_service[] = "org.freedesktop.systemd1.Service";
60 static const char sdbi_job[] = "org.freedesktop.systemd1.Job";
61 static const char sdbj_state[] = "State";
62 static const char sdbm_reload[] = "Reload";
63 static const char sdbm_start_unit[] = "StartUnit";
64 static const char sdbm_restart_unit[] = "RestartUnit";
65 static const char sdbm_stop_unit[] = "StopUnit";
66 static const char sdbm_start[] = "Start";
67 static const char sdbm_restart[] = "Restart";
68 static const char sdbm_stop[] = "Stop";
69 static const char sdbm_get_unit[] = "GetUnit";
70 static const char sdbm_get_unit_by_pid[] = "GetUnitByPID";
71 static const char sdbm_load_unit[] = "LoadUnit";
72 static const char sdbp_active_state[] = "ActiveState";
73 static const char sdbp_exec_main_pid[] = "ExecMainPID";
75 static const char *sds_state_names[] = {
85 static const char *sds_job_state_names[] = {
91 static struct sd_bus *sysbus;
92 static struct sd_bus *usrbus;
95 * Translate systemd errors to errno errors
97 static int seterrno(int value)
103 static int sderr2errno(int rc)
105 return rc < 0 ? seterrno(-rc) : rc;
108 static int errno2sderr(int rc)
110 return rc < 0 ? -errno : rc;
114 * Returns in 'ret' either the system bus (if isuser==0)
115 * or the user bus (if isuser!=0).
116 * Returns 0 in case of success or -1 in case of error
118 int systemd_get_bus(int isuser, struct sd_bus **ret)
123 bus = isuser ? usrbus : sysbus;
127 rc = sd_bus_default_user(ret);
132 rc = sd_bus_default_system(ret);
139 return sderr2errno(rc);
142 void systemd_set_bus(int isuser, struct sd_bus *bus)
144 struct sd_bus **target = isuser ? &usrbus : &sysbus;
146 sd_bus_unref(*target);
151 /********************************************************************
152 * routines for escaping unit names to compute dbus path of units
153 *******************************************************************/
155 * Should the char 'c' be escaped?
157 static inline int should_escape_for_path(char c)
160 return c <= (c >= 'a' ? 'z' : 'Z');
162 return c >= '0' && c <= '9';
167 * ascii char for the hexadecimal digit 'x'
169 static inline char d2h(int x)
171 return (char)(x + (x > 9 ? ('a' - 10) : '0'));
175 * escapes in 'path' of 'pathlen' the 'unit'
176 * returns 0 in case of success or -1 in case of error
178 static int unit_escape_for_path(char *path, size_t pathlen, const char *unit)
185 if (should_escape_for_path(c)) {
186 if (w + 2 >= pathlen)
189 path[w++] = d2h((c >> 4) & 15);;
190 path[w++] = d2h(c & 15);
203 return seterrno(ENAMETOOLONG);
207 /********************************************************************
208 * Routines for getting paths
209 *******************************************************************/
211 static char *get_dpath(struct sd_bus_message *msg)
217 rc = sd_bus_message_read_basic(msg, 'o', &reply);
218 rc = sderr2errno(rc);
222 result = strdup(reply);
226 sd_bus_message_unref(msg);
230 static char *get_unit_dpath(struct sd_bus *bus, const char *unit, int load)
233 struct sd_bus_message *ret = NULL;
234 sd_bus_error err = SD_BUS_ERROR_NULL;
236 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, load ? sdbm_load_unit : sdbm_get_unit, &err, &ret, "s", unit);
240 return get_dpath(ret);
242 sd_bus_message_unref(ret);
246 static char *get_unit_dpath_by_pid(struct sd_bus *bus, unsigned pid)
249 struct sd_bus_message *ret = NULL;
250 sd_bus_error err = SD_BUS_ERROR_NULL;
252 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_get_unit_by_pid, &err, &ret, "u", pid);
256 return get_dpath(ret);
258 sd_bus_message_unref(ret);
262 static int unit_pid(struct sd_bus *bus, const char *dpath)
266 sd_bus_error err = SD_BUS_ERROR_NULL;
268 rc = sd_bus_get_property_trivial(bus, sdb_destination, dpath, sdbi_service, sdbp_exec_main_pid, &err, 'u', &u);
269 return rc < 0 ? rc : (int)u;
272 static enum SysD_State unit_state(struct sd_bus *bus, const char *dpath)
276 enum SysD_State resu;
277 sd_bus_error err = SD_BUS_ERROR_NULL;
279 resu = SysD_State_INVALID;
280 rc = sd_bus_get_property_string(bus, sdb_destination, dpath, sdbi_unit, sdbp_active_state, &err, &st);
286 if (!strcmp(st, sds_state_names[SysD_State_Active]))
287 resu = SysD_State_Active;
288 else if (!strcmp(st, sds_state_names[SysD_State_Activating]))
289 resu = SysD_State_Activating;
292 if (!strcmp(st, sds_state_names[SysD_State_Deactivating]))
293 resu = SysD_State_Deactivating;
296 if (!strcmp(st, sds_state_names[SysD_State_Failed]))
297 resu = SysD_State_Failed;
300 if (!strcmp(st, sds_state_names[SysD_State_Inactive]))
301 resu = SysD_State_Inactive;
304 if (!strcmp(st, sds_state_names[SysD_State_Reloading]))
305 resu = SysD_State_Reloading;
317 static int job_wait(struct sd_bus *bus, struct sd_bus_message *job)
320 sd_bus_error err = SD_BUS_ERROR_NULL;
321 const char *jpath = NULL;
323 struct timespec tispec;
324 const int period_ms = 10;
325 const int trial_s = 10;
326 const int trial_count = (trial_s * 1000) / period_ms;
327 const int period_ns = period_ms * 1000000;
331 rc = sd_bus_message_read_basic(job, 'o', &jpath);
335 /* Wait for job to enter "running" state */
337 for (trial = 1 ; trial <= trial_count ; trial++) {
339 if(sd_bus_get_property_string(bus, sdb_destination, jpath, sdbi_job, sdbj_state, &err, &jstate) >= 0) {
340 if(jstate && strcmp(jstate, sds_job_state_names[SysD_Job_State_Running]) == 0) {
345 tispec.tv_nsec = period_ns;
346 nanosleep(&tispec, NULL);
351 if(trial > trial_count)
357 static int unit_start(struct sd_bus *bus, const char *dpath)
360 struct sd_bus_message *ret = NULL;
361 sd_bus_error err = SD_BUS_ERROR_NULL;
363 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_start, &err, &ret, "s", "replace");
365 rc = job_wait(bus, ret);
367 sd_bus_message_unref(ret);
371 static int unit_restart(struct sd_bus *bus, const char *dpath)
374 struct sd_bus_message *ret = NULL;
375 sd_bus_error err = SD_BUS_ERROR_NULL;
377 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_restart, &err, &ret, "s", "replace");
379 rc = job_wait(bus, ret);
381 sd_bus_message_unref(ret);
385 static int unit_stop(struct sd_bus *bus, const char *dpath)
388 struct sd_bus_message *ret = NULL;
389 sd_bus_error err = SD_BUS_ERROR_NULL;
391 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_stop, &err, &ret, "s", "replace");
392 sd_bus_message_unref(ret);
396 static int unit_start_name(struct sd_bus *bus, const char *name)
399 struct sd_bus_message *ret = NULL;
400 sd_bus_error err = SD_BUS_ERROR_NULL;
402 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_start_unit, &err, &ret, "ss", name, "replace");
404 rc = job_wait(bus, ret);
406 sd_bus_message_unref(ret);
410 static int unit_restart_name(struct sd_bus *bus, const char *name)
413 struct sd_bus_message *ret = NULL;
414 sd_bus_error err = SD_BUS_ERROR_NULL;
416 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_restart_unit, &err, &ret, "ss", name, "replace");
418 rc = job_wait(bus, ret);
420 sd_bus_message_unref(ret);
424 static int unit_stop_name(struct sd_bus *bus, const char *name)
427 struct sd_bus_message *ret = NULL;
428 sd_bus_error err = SD_BUS_ERROR_NULL;
430 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_stop_unit, &err, &ret, "ss", name, "replace");
431 sd_bus_message_unref(ret);
435 /********************************************************************
437 *******************************************************************/
439 static int check_snprintf_result(int rc, size_t buflen)
441 return (rc >= 0 && (size_t)rc >= buflen) ? seterrno(ENAMETOOLONG) : rc;
444 int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
446 int rc = snprintf(path, pathlen, "%s/%s",
448 isuser ? "user" : "system");
450 return check_snprintf_result(rc, pathlen);
453 int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext)
455 int rc = snprintf(path, pathlen, "%s/%s/%s.%s",
457 isuser ? "user" : "system",
461 return check_snprintf_result(rc, pathlen);
464 int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext)
466 int rc = snprintf(path, pathlen, "%s/%s/%s.wants/%s.%s",
468 isuser ? "user" : "system",
473 return check_snprintf_result(rc, pathlen);
476 int systemd_get_wants_target(char *path, size_t pathlen, const char *unit, const char *uext)
478 int rc = snprintf(path, pathlen, "../%s.%s", unit, uext);
480 return check_snprintf_result(rc, pathlen);
483 int systemd_daemon_reload(int isuser)
487 struct sd_bus_message *ret = NULL;
488 sd_bus_error err = SD_BUS_ERROR_NULL;
490 rc = systemd_get_bus(isuser, &bus);
492 /* TODO: asynchronous bind... */
493 /* TODO: more diagnostic... */
494 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, &err, &ret, NULL);
495 sd_bus_message_unref(ret);
500 int systemd_unit_list(int isuser, int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
503 char path[PATH_MAX + 1];
510 rc = systemd_get_units_dir(path, sizeof path - 1, isuser);
515 /* open the directory */
521 path[offset++] = '/';
523 /* read the directory */
535 if (dent->d_type == DT_REG)
537 else if (dent->d_type != DT_UNKNOWN)
540 rc = fstatat(dirfd(dir), dent->d_name, &st, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT);
543 isfile = S_ISREG(st.st_mode);
546 /* calls the callback if is a file */
548 len = strlen(dent->d_name);
549 if (offset + len >= sizeof path) {
550 rc = seterrno(ENAMETOOLONG);
553 memcpy(&path[offset], dent->d_name, 1 + len);
554 rc = callback(closure, &path[offset], path, isuser);
563 int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
565 return systemd_unit_list(1, callback, closure) ? : systemd_unit_list(0, callback, closure);
568 char *systemd_unit_dpath_by_name(int isuser, const char *name, int load)
572 return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath(bus, name, load);
575 char *systemd_unit_dpath_by_pid(int isuser, unsigned pid)
579 return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath_by_pid(bus, pid);
582 int systemd_unit_start_dpath(int isuser, const char *dpath)
587 rc = systemd_get_bus(isuser, &bus);
588 return rc < 0 ? rc : unit_start(bus, dpath);
591 int systemd_unit_restart_dpath(int isuser, const char *dpath)
596 rc = systemd_get_bus(isuser, &bus);
597 return rc < 0 ? rc : unit_restart(bus, dpath);
600 int systemd_unit_stop_dpath(int isuser, const char *dpath)
605 rc = systemd_get_bus(isuser, &bus);
606 return rc < 0 ? rc : unit_stop(bus, dpath);
609 int systemd_unit_start_name(int isuser, const char *name)
614 rc = systemd_get_bus(isuser, &bus);
616 rc = unit_start_name(bus, name);
620 int systemd_unit_restart_name(int isuser, const char *name)
625 rc = systemd_get_bus(isuser, &bus);
627 rc = unit_restart_name(bus, name);
631 int systemd_unit_stop_name(int isuser, const char *name)
636 rc = systemd_get_bus(isuser, &bus);
638 rc = unit_stop_name(bus, name);
642 int systemd_unit_stop_pid(int isuser, unsigned pid)
648 rc = systemd_get_bus(isuser, &bus);
650 dpath = get_unit_dpath_by_pid(bus, pid);
654 rc = unit_stop(bus, dpath);
661 int systemd_unit_pid_of_dpath(int isuser, const char *dpath)
666 rc = systemd_get_bus(isuser, &bus);
667 return rc < 0 ? rc : unit_pid(bus, dpath);
670 enum SysD_State systemd_unit_state_of_dpath(int isuser, const char *dpath)
675 rc = systemd_get_bus(isuser, &bus);
676 return rc < 0 ? SysD_State_INVALID : unit_state(bus, dpath);
679 const char *systemd_state_name(enum SysD_State state)
681 return sds_state_names[state];