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