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