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 sdbm_reload[] = "Reload";
60 static const char sdbm_start_unit[] = "StartUnit";
61 static const char sdbm_restart_unit[] = "RestartUnit";
62 static const char sdbm_stop_unit[] = "StopUnit";
63 static const char sdbm_start[] = "Start";
64 static const char sdbm_restart[] = "Restart";
65 static const char sdbm_stop[] = "Stop";
66 static const char sdbm_get_unit[] = "GetUnit";
67 static const char sdbm_get_unit_by_pid[] = "GetUnitByPID";
68 static const char sdbm_load_unit[] = "LoadUnit";
69 static const char sdbp_active_state[] = "ActiveState";
70 static const char sdbp_exec_main_pid[] = "ExecMainPID";
72 const char SysD_State_Inactive[] = "inactive";
73 const char SysD_State_Activating[] = "activating";
74 const char SysD_State_Active[] = "active";
75 const char SysD_State_Deactivating[] = "deactivating";
76 const char SysD_State_Reloading[] = "reloading";
77 const char SysD_State_Failed[] = "failed";
79 static struct sd_bus *sysbus;
80 static struct sd_bus *usrbus;
83 * Translate systemd errors to errno errors
85 static int seterrno(int value)
91 static int sderr2errno(int rc)
93 return rc < 0 ? seterrno(-rc) : rc;
96 static int errno2sderr(int rc)
98 return rc < 0 ? -errno : rc;
102 * Returns in 'ret' either the system bus (if isuser==0)
103 * or the user bus (if isuser!=0).
104 * Returns 0 in case of success or -1 in case of error
106 int systemd_get_bus(int isuser, struct sd_bus **ret)
111 bus = isuser ? usrbus : sysbus;
115 rc = sd_bus_default_user(ret);
120 rc = sd_bus_default_system(ret);
127 return sderr2errno(rc);
130 void systemd_set_bus(int isuser, struct sd_bus *bus)
132 struct sd_bus **target = isuser ? &usrbus : &sysbus;
134 sd_bus_unref(*target);
139 /********************************************************************
140 * routines for escaping unit names to compute dbus path of units
141 *******************************************************************/
143 * Should the char 'c' be escaped?
145 static inline int should_escape_for_path(char c)
148 return c <= (c >= 'a' ? 'z' : 'Z');
150 return c >= '0' && c <= '9';
155 * ascii char for the hexadecimal digit 'x'
157 static inline char d2h(int x)
159 return (char)(x + (x > 9 ? ('a' - 10) : '0'));
163 * escapes in 'path' of 'pathlen' the 'unit'
164 * returns 0 in case of success or -1 in case of error
166 static int unit_escape_for_path(char *path, size_t pathlen, const char *unit)
173 if (should_escape_for_path(c)) {
174 if (w + 2 >= pathlen)
177 path[w++] = d2h((c >> 4) & 15);;
178 path[w++] = d2h(c & 15);
191 return seterrno(ENAMETOOLONG);
195 /********************************************************************
196 * Routines for getting paths
197 *******************************************************************/
199 static char *get_dpath(struct sd_bus_message *msg)
205 rc = sd_bus_message_read_basic(msg, 'o', &reply);
206 rc = sderr2errno(rc);
210 result = strdup(reply);
214 sd_bus_message_unref(msg);
218 static char *get_unit_dpath(struct sd_bus *bus, const char *unit, int load)
221 struct sd_bus_message *ret = NULL;
222 sd_bus_error err = SD_BUS_ERROR_NULL;
224 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, load ? sdbm_load_unit : sdbm_get_unit, &err, &ret, "s", unit);
228 return get_dpath(ret);
230 sd_bus_message_unref(ret);
234 static char *get_unit_dpath_by_pid(struct sd_bus *bus, unsigned pid)
237 struct sd_bus_message *ret = NULL;
238 sd_bus_error err = SD_BUS_ERROR_NULL;
240 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_get_unit_by_pid, &err, &ret, "u", pid);
244 return get_dpath(ret);
246 sd_bus_message_unref(ret);
250 static int unit_pid(struct sd_bus *bus, const char *dpath)
254 sd_bus_error err = SD_BUS_ERROR_NULL;
256 rc = sd_bus_get_property_trivial(bus, sdb_destination, dpath, sdbi_service, sdbp_exec_main_pid, &err, 'u', &u);
257 return rc < 0 ? rc : (int)u;
260 static const char *unit_state(struct sd_bus *bus, const char *dpath)
265 sd_bus_error err = SD_BUS_ERROR_NULL;
267 rc = sd_bus_get_property_string(bus, sdb_destination, dpath, sdbi_unit, sdbp_active_state, &err, &st);
272 if (!strcmp(st, SysD_State_Active))
273 resu = SysD_State_Active;
274 else if (!strcmp(st, SysD_State_Reloading))
275 resu = SysD_State_Reloading;
276 else if (!strcmp(st, SysD_State_Inactive))
277 resu = SysD_State_Inactive;
278 else if (!strcmp(st, SysD_State_Failed))
279 resu = SysD_State_Failed;
280 else if (!strcmp(st, SysD_State_Activating))
281 resu = SysD_State_Activating;
282 else if (!strcmp(st, SysD_State_Deactivating))
283 resu = SysD_State_Deactivating;
293 static int unit_start(struct sd_bus *bus, const char *dpath)
296 struct sd_bus_message *ret = NULL;
297 sd_bus_error err = SD_BUS_ERROR_NULL;
299 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_start, &err, &ret, "s", "replace");
300 sd_bus_message_unref(ret);
304 static int unit_restart(struct sd_bus *bus, const char *dpath)
307 struct sd_bus_message *ret = NULL;
308 sd_bus_error err = SD_BUS_ERROR_NULL;
310 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_restart, &err, &ret, "s", "replace");
311 sd_bus_message_unref(ret);
315 static int unit_stop(struct sd_bus *bus, const char *dpath)
318 struct sd_bus_message *ret = NULL;
319 sd_bus_error err = SD_BUS_ERROR_NULL;
321 rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_stop, &err, &ret, "s", "replace");
322 sd_bus_message_unref(ret);
326 static int unit_start_name(struct sd_bus *bus, const char *name)
329 struct sd_bus_message *ret = NULL;
330 sd_bus_error err = SD_BUS_ERROR_NULL;
332 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_start_unit, &err, &ret, "ss", name, "replace");
333 sd_bus_message_unref(ret);
337 static int unit_restart_name(struct sd_bus *bus, const char *name)
340 struct sd_bus_message *ret = NULL;
341 sd_bus_error err = SD_BUS_ERROR_NULL;
343 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_restart_unit, &err, &ret, "ss", name, "replace");
344 sd_bus_message_unref(ret);
348 static int unit_stop_name(struct sd_bus *bus, const char *name)
351 struct sd_bus_message *ret = NULL;
352 sd_bus_error err = SD_BUS_ERROR_NULL;
354 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_stop_unit, &err, &ret, "ss", name, "replace");
355 sd_bus_message_unref(ret);
359 /********************************************************************
361 *******************************************************************/
363 static int check_snprintf_result(int rc, size_t buflen)
365 return (rc >= 0 && (size_t)rc >= buflen) ? seterrno(ENAMETOOLONG) : rc;
368 int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
370 int rc = snprintf(path, pathlen, "%s/%s",
372 isuser ? "user" : "system");
374 return check_snprintf_result(rc, pathlen);
377 int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext)
379 int rc = snprintf(path, pathlen, "%s/%s/%s.%s",
381 isuser ? "user" : "system",
385 return check_snprintf_result(rc, pathlen);
388 int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext)
390 int rc = snprintf(path, pathlen, "%s/%s/%s.wants/%s.%s",
392 isuser ? "user" : "system",
397 return check_snprintf_result(rc, pathlen);
400 int systemd_get_wants_target(char *path, size_t pathlen, const char *unit, const char *uext)
402 int rc = snprintf(path, pathlen, "../%s.%s", unit, uext);
404 return check_snprintf_result(rc, pathlen);
407 int systemd_daemon_reload(int isuser)
411 struct sd_bus_message *ret = NULL;
412 sd_bus_error err = SD_BUS_ERROR_NULL;
414 rc = systemd_get_bus(isuser, &bus);
416 /* TODO: asynchronous bind... */
417 /* TODO: more diagnostic... */
418 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, &err, &ret, NULL);
419 sd_bus_message_unref(ret);
424 int systemd_unit_list(int isuser, int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
427 char path[PATH_MAX + 1];
434 rc = systemd_get_units_dir(path, sizeof path - 1, isuser);
439 /* open the directory */
445 path[offset++] = '/';
447 /* read the directory */
459 if (dent->d_type == DT_REG)
461 else if (dent->d_type != DT_UNKNOWN)
464 rc = fstatat(dirfd(dir), dent->d_name, &st, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT);
467 isfile = S_ISREG(st.st_mode);
470 /* calls the callback if is a file */
472 len = strlen(dent->d_name);
473 if (offset + len >= sizeof path) {
474 rc = seterrno(ENAMETOOLONG);
477 memcpy(&path[offset], dent->d_name, 1 + len);
478 rc = callback(closure, &path[offset], path, isuser);
487 int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
489 return systemd_unit_list(1, callback, closure) ? : systemd_unit_list(0, callback, closure);
492 char *systemd_unit_dpath_by_name(int isuser, const char *name, int load)
496 return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath(bus, name, load);
499 char *systemd_unit_dpath_by_pid(int isuser, unsigned pid)
503 return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath_by_pid(bus, pid);
506 int systemd_unit_start_dpath(int isuser, const char *dpath)
511 rc = systemd_get_bus(isuser, &bus);
512 return rc < 0 ? rc : unit_start(bus, dpath);
515 int systemd_unit_restart_dpath(int isuser, const char *dpath)
520 rc = systemd_get_bus(isuser, &bus);
521 return rc < 0 ? rc : unit_restart(bus, dpath);
524 int systemd_unit_stop_dpath(int isuser, const char *dpath)
529 rc = systemd_get_bus(isuser, &bus);
530 return rc < 0 ? rc : unit_stop(bus, dpath);
533 int systemd_unit_start_name(int isuser, const char *name)
538 rc = systemd_get_bus(isuser, &bus);
540 rc = unit_start_name(bus, name);
544 int systemd_unit_restart_name(int isuser, const char *name)
549 rc = systemd_get_bus(isuser, &bus);
551 rc = unit_restart_name(bus, name);
555 int systemd_unit_stop_name(int isuser, const char *name)
560 rc = systemd_get_bus(isuser, &bus);
562 rc = unit_stop_name(bus, name);
566 int systemd_unit_stop_pid(int isuser, unsigned pid)
572 rc = systemd_get_bus(isuser, &bus);
574 dpath = get_unit_dpath_by_pid(bus, pid);
578 rc = unit_stop(bus, dpath);
585 int systemd_unit_pid_of_dpath(int isuser, const char *dpath)
590 rc = systemd_get_bus(isuser, &bus);
591 return rc < 0 ? rc : unit_pid(bus, dpath);
594 const char *systemd_unit_state_of_dpath(int isuser, const char *dpath)
599 rc = systemd_get_bus(isuser, &bus);
600 return rc < 0 ? NULL : unit_state(bus, dpath);