utils-systemd: Offer way to set systemd's buses
[src/app-framework-main.git] / src / utils-systemd.c
1 /*
2  Copyright 2017 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
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
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
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.
17 */
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #ifndef NO_LIBSYSTEMD
31 # include <systemd/sd-bus.h>
32 # include <systemd/sd-bus-protocol.h>
33 #else
34   struct sd_bus;
35   struct sd_bus_message;
36   typedef struct { const char *name; const char *message; } sd_bus_error;
37 # define sd_bus_default_user(p)           ((*(p)=NULL),(-ENOTSUP))
38 # define sd_bus_default_system(p)         ((*(p)=NULL),(-ENOTSUP))
39 # define sd_bus_call_method(...)          (-ENOTSUP)
40 # define SD_BUS_ERROR_NULL                {NULL,NULL}
41 # define sd_bus_message_read_basic(...)   (-ENOTSUP)
42 # define sd_bus_message_unref(...)        (NULL)
43 # define sd_bus_get_property_string(...)  (-ENOTSUP)
44 # define sd_bus_get_property_trivial(...) (-ENOTSUP)
45 #endif
46
47 #include "utils-systemd.h"
48
49 #if !defined(SYSTEMD_UNITS_ROOT)
50 # define SYSTEMD_UNITS_ROOT "/usr/local/lib/systemd"
51 #endif
52
53 static const char sdb_path[] = "/org/freedesktop/systemd1";
54 static const char sdb_destination[] = "org.freedesktop.systemd1";
55 static const char sdbi_manager[] = "org.freedesktop.systemd1.Manager";
56 static const char sdbi_unit[] = "org.freedesktop.systemd1.Unit";
57 static const char sdbi_service[] = "org.freedesktop.systemd1.Service";
58 static const char sdbm_reload[] = "Reload";
59 static const char sdbm_start_unit[] = "StartUnit";
60 static const char sdbm_restart_unit[] = "RestartUnit";
61 static const char sdbm_stop_unit[] = "StopUnit";
62 static const char sdbm_start[] = "Start";
63 static const char sdbm_restart[] = "Restart";
64 static const char sdbm_stop[] = "Stop";
65 static const char sdbm_get_unit[] = "GetUnit";
66 static const char sdbm_get_unit_by_pid[] = "GetUnitByPID";
67 static const char sdbm_load_unit[] = "LoadUnit";
68 static const char sdbp_active_state[] = "ActiveState";
69 static const char sdbp_exec_main_pid[] = "ExecMainPID";
70
71 const char SysD_State_Inactive[] = "inactive";
72 const char SysD_State_Activating[] = "activating";
73 const char SysD_State_Active[] = "active";
74 const char SysD_State_Deactivating[] = "deactivating";
75 const char SysD_State_Reloading[] = "reloading";
76 const char SysD_State_Failed[] = "failed";
77
78 static struct sd_bus *sysbus;
79 static struct sd_bus *usrbus;
80
81 /*
82  * Translate systemd errors to errno errors
83  */
84 static int seterrno(int value)
85 {
86         errno = value;
87         return -1;
88 }
89
90 static int sderr2errno(int rc)
91 {
92         return rc < 0 ? seterrno(-rc) : rc;
93 }
94
95 static int errno2sderr(int rc)
96 {
97         return rc < 0 ? -errno : rc;
98 }
99
100 /*
101  * Returns in 'ret' either the system bus (if isuser==0)
102  * or the user bus (if isuser!=0).
103  * Returns 0 in case of success or -1 in case of error
104  */
105 int systemd_get_bus(int isuser, struct sd_bus **ret)
106 {
107         int rc;
108         struct sd_bus *bus;
109
110         bus = isuser ? usrbus : sysbus;
111         if (bus)
112                 *ret = bus;
113         else if (isuser) {
114                 rc = sd_bus_default_user(ret);
115                 if (rc < 0)
116                         goto error;
117                 usrbus = *ret;
118         } else {
119                 rc = sd_bus_default_system(ret);
120                 if (rc < 0)
121                         goto error;
122                 sysbus = *ret;
123         }
124         return 0;
125 error:
126         return sderr2errno(rc);
127 }
128
129 void systemd_set_bus(int isuser, struct sd_bus *bus)
130 {
131         struct sd_bus **target = isuser ? &usrbus : &sysbus;
132         if (*target)
133                 sd_bus_unref(*target);
134         *target = bus;
135 }
136
137 #if 0
138 /********************************************************************
139  * routines for escaping unit names to compute dbus path of units
140  *******************************************************************/
141 /*
142  * Should the char 'c' be escaped?
143  */
144 static inline int should_escape_for_path(char c)
145 {
146         if (c >= 'A') {
147                 return c <= (c >= 'a' ? 'z' : 'Z');
148         } else {
149                 return c >= '0' && c <= '9';
150         }
151 }
152
153 /*
154  * ascii char for the hexadecimal digit 'x'
155  */
156 static inline char d2h(int x)
157 {
158         return (char)(x + (x > 9 ? ('a' - 10) : '0'));
159 }
160
161 /*
162  * escapes in 'path' of 'pathlen' the 'unit'
163  * returns 0 in case of success or -1 in case of error
164  */
165 static int unit_escape_for_path(char *path, size_t pathlen, const char *unit)
166 {
167         size_t r, w;
168         char c;
169
170         c = unit[r = w = 0];
171         while (c) {
172                 if (should_escape_for_path(c)) {
173                         if (w + 2 >= pathlen)
174                                 goto toolong;
175                         path[w++] = '_';
176                         path[w++] = d2h((c >> 4) & 15);;
177                         path[w++] = d2h(c & 15);
178                 } else {
179                         if (w >= pathlen)
180                                 goto toolong;
181                         path[w++] = c;
182                 }
183                 c = unit[++r];
184         }
185         if (w >= pathlen)
186                 goto toolong;
187         path[w] = 0;
188         return 0;
189 toolong:
190         return seterrno(ENAMETOOLONG);
191 }
192 #endif
193
194 /********************************************************************
195  * Routines for getting paths
196  *******************************************************************/
197
198 static char *get_dpath(struct sd_bus_message *msg)
199 {
200         int rc;
201         const char *reply;
202         char *result;
203
204         rc = sd_bus_message_read_basic(msg, 'o', &reply);
205         rc = sderr2errno(rc);
206         if (rc < 0)
207                 result = NULL;
208         else {
209                 result = strdup(reply);
210                 if (!result)
211                         errno = ENOMEM;
212         }
213         sd_bus_message_unref(msg);
214         return result;
215 }
216
217 static char *get_unit_dpath(struct sd_bus *bus, const char *unit, int load)
218 {
219         int rc;
220         struct sd_bus_message *ret = NULL;
221         sd_bus_error err = SD_BUS_ERROR_NULL;
222
223         rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, load ? sdbm_load_unit : sdbm_get_unit, &err, &ret, "s", unit);
224         if (rc < 0)
225                 goto error;
226
227         return get_dpath(ret);
228 error:
229         sd_bus_message_unref(ret);
230         return NULL;
231 }
232
233 static char *get_unit_dpath_by_pid(struct sd_bus *bus, unsigned pid)
234 {
235         int rc;
236         struct sd_bus_message *ret = NULL;
237         sd_bus_error err = SD_BUS_ERROR_NULL;
238
239         rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_get_unit_by_pid, &err, &ret, "u", pid);
240         if (rc < 0)
241                 goto error;
242
243         return get_dpath(ret);
244 error:
245         sd_bus_message_unref(ret);
246         return NULL;
247 }
248
249 static int unit_pid(struct sd_bus *bus, const char *dpath)
250 {
251         int rc;
252         unsigned u = 0;
253         sd_bus_error err = SD_BUS_ERROR_NULL;
254
255         rc = sd_bus_get_property_trivial(bus, sdb_destination, dpath, sdbi_service, sdbp_exec_main_pid, &err, 'u', &u);
256         return rc < 0 ? rc : (int)u;
257 }
258
259 static const char *unit_state(struct sd_bus *bus, const char *dpath)
260 {
261         int rc;
262         char *st;
263         const char *resu;
264         sd_bus_error err = SD_BUS_ERROR_NULL;
265
266         rc = sd_bus_get_property_string(bus, sdb_destination, dpath, sdbi_unit, sdbp_active_state, &err, &st);
267         if (rc < 0) {
268                 errno = -rc;
269                 resu = NULL;
270         } else {
271                 if (!strcmp(st, SysD_State_Active))
272                         resu = SysD_State_Active;
273                 else if (!strcmp(st, SysD_State_Reloading))
274                         resu = SysD_State_Reloading;
275                 else if (!strcmp(st, SysD_State_Inactive))
276                         resu = SysD_State_Inactive;
277                 else if (!strcmp(st, SysD_State_Failed))
278                         resu = SysD_State_Failed;
279                 else if (!strcmp(st, SysD_State_Activating))
280                         resu = SysD_State_Activating;
281                 else if (!strcmp(st, SysD_State_Deactivating))
282                         resu = SysD_State_Deactivating;
283                 else {
284                         errno = EBADMSG;
285                         resu = NULL;
286                 }
287                 free(st);
288         }
289         return resu;
290 }
291
292 static int unit_start(struct sd_bus *bus, const char *dpath)
293 {
294         int rc;
295         struct sd_bus_message *ret = NULL;
296         sd_bus_error err = SD_BUS_ERROR_NULL;
297
298         rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_start, &err, &ret, "s", "replace");
299         sd_bus_message_unref(ret);
300         return rc;
301 }
302
303 static int unit_restart(struct sd_bus *bus, const char *dpath)
304 {
305         int rc;
306         struct sd_bus_message *ret = NULL;
307         sd_bus_error err = SD_BUS_ERROR_NULL;
308
309         rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_restart, &err, &ret, "s", "replace");
310         sd_bus_message_unref(ret);
311         return rc;
312 }
313
314 static int unit_stop(struct sd_bus *bus, const char *dpath)
315 {
316         int rc;
317         struct sd_bus_message *ret = NULL;
318         sd_bus_error err = SD_BUS_ERROR_NULL;
319
320         rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_stop, &err, &ret, "s", "replace");
321         sd_bus_message_unref(ret);
322         return rc;
323 }
324
325 static int unit_start_name(struct sd_bus *bus, const char *name)
326 {
327         int rc;
328         struct sd_bus_message *ret = NULL;
329         sd_bus_error err = SD_BUS_ERROR_NULL;
330
331         rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_start_unit, &err, &ret, "ss", name, "replace");
332         sd_bus_message_unref(ret);
333         return rc;
334 }
335
336 static int unit_restart_name(struct sd_bus *bus, const char *name)
337 {
338         int rc;
339         struct sd_bus_message *ret = NULL;
340         sd_bus_error err = SD_BUS_ERROR_NULL;
341
342         rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_restart_unit, &err, &ret, "ss", name, "replace");
343         sd_bus_message_unref(ret);
344         return rc;
345 }
346
347 static int unit_stop_name(struct sd_bus *bus, const char *name)
348 {
349         int rc;
350         struct sd_bus_message *ret = NULL;
351         sd_bus_error err = SD_BUS_ERROR_NULL;
352
353         rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_stop_unit, &err, &ret, "ss", name, "replace");
354         sd_bus_message_unref(ret);
355         return rc;
356 }
357
358 /********************************************************************
359  *
360  *******************************************************************/
361
362 static int check_snprintf_result(int rc, size_t buflen)
363 {
364         return (rc >= 0 && (size_t)rc >= buflen) ? seterrno(ENAMETOOLONG) : rc;
365 }
366
367 int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
368 {
369         int rc = snprintf(path, pathlen, "%s/%s",
370                         SYSTEMD_UNITS_ROOT,
371                         isuser ? "user" : "system");
372
373         return check_snprintf_result(rc, pathlen);
374 }
375
376 int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext)
377 {
378         int rc = snprintf(path, pathlen, "%s/%s/%s.%s",
379                         SYSTEMD_UNITS_ROOT,
380                         isuser ? "user" : "system",
381                         unit,
382                         uext);
383
384         return check_snprintf_result(rc, pathlen);
385 }
386
387 int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext)
388 {
389         int rc = snprintf(path, pathlen, "%s/%s/%s.wants/%s.%s",
390                         SYSTEMD_UNITS_ROOT,
391                         isuser ? "user" : "system",
392                         wanter,
393                         unit,
394                         uext);
395
396         return check_snprintf_result(rc, pathlen);
397 }
398
399 int systemd_get_wants_target(char *path, size_t pathlen, const char *unit, const char *uext)
400 {
401         int rc = snprintf(path, pathlen, "../%s.%s", unit, uext);
402
403         return check_snprintf_result(rc, pathlen);
404 }
405
406 int systemd_daemon_reload(int isuser)
407 {
408         int rc;
409         struct sd_bus *bus;
410         struct sd_bus_message *ret = NULL;
411         sd_bus_error err = SD_BUS_ERROR_NULL;
412
413         rc = systemd_get_bus(isuser, &bus);
414         if (rc >= 0) {
415                 /* TODO: asynchronous bind... */
416                 /* TODO: more diagnostic... */
417                 rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, &err, &ret, NULL);
418                 sd_bus_message_unref(ret);
419         }
420         return rc;
421 }
422
423 int systemd_unit_list(int isuser, int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
424 {
425         DIR *dir;
426         char path[PATH_MAX + 1];
427         struct dirent *dent;
428         int rc, isfile;
429         size_t offset, len;
430         struct stat st;
431
432         /* get the path */
433         rc = systemd_get_units_dir(path, sizeof path - 1, isuser);
434         if (rc < 0)
435                 return rc;
436         offset = (size_t)rc;
437
438         /* open the directory */
439         dir = opendir(path);
440         if (!dir)
441                 return -1;
442
443         /* prepare path */
444         path[offset++] = '/';
445
446         /* read the directory */
447         for(;;) {
448                 /* get next entry */
449                 errno = 0;
450                 dent = readdir(dir);
451                 if (dent == NULL) {
452                         /* end or error */
453                         rc = (!errno) - 1;
454                         break;
455                 }
456
457                 /* is a file? */
458                 if (dent->d_type == DT_REG)
459                         isfile = 1;
460                 else if (dent->d_type != DT_UNKNOWN)
461                         isfile = 0;
462                 else {
463                         rc = fstatat(dirfd(dir), dent->d_name, &st, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT);
464                         if (rc < 0)
465                                 break;
466                         isfile = S_ISREG(st.st_mode);
467                 }
468
469                 /* calls the callback if is a file */
470                 if (isfile) {
471                         len = strlen(dent->d_name);
472                         if (offset + len >= sizeof path) {
473                                 rc = seterrno(ENAMETOOLONG);
474                                 break;
475                         }
476                         memcpy(&path[offset], dent->d_name, 1 + len);
477                         rc = callback(closure, &path[offset], path, isuser);
478                         if (rc)
479                                 break;
480                 }
481         }
482         closedir(dir);
483         return rc;
484 }
485
486 int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
487 {
488         return systemd_unit_list(1, callback, closure) ? : systemd_unit_list(0, callback, closure);
489 }
490
491 char *systemd_unit_dpath_by_name(int isuser, const char *name, int load)
492 {
493         struct sd_bus *bus;
494
495         return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath(bus, name, load);
496 }
497
498 char *systemd_unit_dpath_by_pid(int isuser, unsigned pid)
499 {
500         struct sd_bus *bus;
501
502         return systemd_get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath_by_pid(bus, pid);
503 }
504
505 int systemd_unit_start_dpath(int isuser, const char *dpath)
506 {
507         int rc;
508         struct sd_bus *bus;
509
510         rc = systemd_get_bus(isuser, &bus);
511         return rc < 0 ? rc : unit_start(bus, dpath);
512 }
513
514 int systemd_unit_restart_dpath(int isuser, const char *dpath)
515 {
516         int rc;
517         struct sd_bus *bus;
518
519         rc = systemd_get_bus(isuser, &bus);
520         return rc < 0 ? rc : unit_restart(bus, dpath);
521 }
522
523 int systemd_unit_stop_dpath(int isuser, const char *dpath)
524 {
525         int rc;
526         struct sd_bus *bus;
527
528         rc = systemd_get_bus(isuser, &bus);
529         return rc < 0 ? rc : unit_stop(bus, dpath);
530 }
531
532 int systemd_unit_start_name(int isuser, const char *name)
533 {
534         int rc;
535         struct sd_bus *bus;
536
537         rc = systemd_get_bus(isuser, &bus);
538         if (rc >= 0)
539                 rc = unit_start_name(bus, name);
540         return rc;
541 }
542
543 int systemd_unit_restart_name(int isuser, const char *name)
544 {
545         int rc;
546         struct sd_bus *bus;
547
548         rc = systemd_get_bus(isuser, &bus);
549         if (rc >= 0)
550                 rc = unit_restart_name(bus, name);
551         return rc;
552 }
553
554 int systemd_unit_stop_name(int isuser, const char *name)
555 {
556         int rc;
557         struct sd_bus *bus;
558
559         rc = systemd_get_bus(isuser, &bus);
560         if (rc >= 0)
561                 rc = unit_stop_name(bus, name);
562         return rc;
563 }
564
565 int systemd_unit_stop_pid(int isuser, unsigned pid)
566 {
567         int rc;
568         struct sd_bus *bus;
569         char *dpath;
570
571         rc = systemd_get_bus(isuser, &bus);
572         if (rc >= 0) {
573                 dpath = get_unit_dpath_by_pid(bus, pid);
574                 if (!dpath)
575                         rc = -1;
576                 else {
577                         rc = unit_stop(bus, dpath);
578                         free(dpath);
579                 }
580         }
581         return rc;
582 }
583
584 int systemd_unit_pid_of_dpath(int isuser, const char *dpath)
585 {
586         int rc;
587         struct sd_bus *bus;
588
589         rc = systemd_get_bus(isuser, &bus);
590         return rc < 0 ? rc : unit_pid(bus, dpath);
591 }
592
593 const char *systemd_unit_state_of_dpath(int isuser, const char *dpath)
594 {
595         int rc;
596         struct sd_bus *bus;
597
598         rc = systemd_get_bus(isuser, &bus);
599         return rc < 0 ? NULL : unit_state(bus, dpath);
600 }
601