chiark / gitweb /
cgroup2: use new fstype for unified hierarchy
[elogind.git] / src / basic / util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <alloca.h>
21 //#include <dirent.h>
22 //#include <errno.h>
23 //#include <fcntl.h>
24 #include <sched.h>
25 //#include <signal.h>
26 //#include <stdarg.h>
27 //#include <stdio.h>
28 #include <stdlib.h>
29 //#include <string.h>
30 //#include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/statfs.h>
33 #include <sys/sysmacros.h>
34 //#include <sys/types.h>
35 //#include <unistd.h>
36
37 #include "alloc-util.h"
38 #include "build.h"
39 //#include "def.h"
40 #include "dirent-util.h"
41 #include "fd-util.h"
42 #include "fileio.h"
43 //#include "formats-util.h"
44 #include "hashmap.h"
45 #include "hostname-util.h"
46 //#include "log.h"
47 #include "macro.h"
48 //#include "missing.h"
49 #include "parse-util.h"
50 //#include "path-util.h"
51 #include "process-util.h"
52 #include "set.h"
53 #include "signal-util.h"
54 #include "stat-util.h"
55 #include "string-util.h"
56 #include "strv.h"
57 #include "time-util.h"
58 #include "user-util.h"
59 #include "util.h"
60
61 /* Put this test here for a lack of better place */
62 assert_cc(EAGAIN == EWOULDBLOCK);
63
64 int saved_argc = 0;
65 char **saved_argv = NULL;
66
67 size_t page_size(void) {
68         static thread_local size_t pgsz = 0;
69         long r;
70
71         if (_likely_(pgsz > 0))
72                 return pgsz;
73
74         r = sysconf(_SC_PAGESIZE);
75         assert(r > 0);
76
77         pgsz = (size_t) r;
78         return pgsz;
79 }
80
81 static int do_execute(char **directories, usec_t timeout, char *argv[]) {
82         _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
83         _cleanup_set_free_free_ Set *seen = NULL;
84         char **directory;
85
86         /* We fork this all off from a child process so that we can
87          * somewhat cleanly make use of SIGALRM to set a time limit */
88
89         (void) reset_all_signal_handlers();
90         (void) reset_signal_mask();
91
92         assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
93
94         pids = hashmap_new(NULL);
95         if (!pids)
96                 return log_oom();
97
98         seen = set_new(&string_hash_ops);
99         if (!seen)
100                 return log_oom();
101
102         STRV_FOREACH(directory, directories) {
103                 _cleanup_closedir_ DIR *d;
104                 struct dirent *de;
105
106                 d = opendir(*directory);
107                 if (!d) {
108                         if (errno == ENOENT)
109                                 continue;
110
111                         return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
112                 }
113
114                 FOREACH_DIRENT(de, d, break) {
115                         _cleanup_free_ char *path = NULL;
116                         pid_t pid;
117                         int r;
118
119                         if (!dirent_is_file(de))
120                                 continue;
121
122                         if (set_contains(seen, de->d_name)) {
123                                 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
124                                 continue;
125                         }
126
127                         r = set_put_strdup(seen, de->d_name);
128                         if (r < 0)
129                                 return log_oom();
130
131                         path = strjoin(*directory, "/", de->d_name, NULL);
132                         if (!path)
133                                 return log_oom();
134
135                         if (null_or_empty_path(path)) {
136                                 log_debug("%s is empty (a mask).", path);
137                                 continue;
138                         }
139
140                         pid = fork();
141                         if (pid < 0) {
142                                 log_error_errno(errno, "Failed to fork: %m");
143                                 continue;
144                         } else if (pid == 0) {
145                                 char *_argv[2];
146
147                                 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
148
149                                 if (!argv) {
150                                         _argv[0] = path;
151                                         _argv[1] = NULL;
152                                         argv = _argv;
153                                 } else
154                                         argv[0] = path;
155
156                                 execv(path, argv);
157                                 return log_error_errno(errno, "Failed to execute %s: %m", path);
158                         }
159
160                         log_debug("Spawned %s as " PID_FMT ".", path, pid);
161
162                         r = hashmap_put(pids, PID_TO_PTR(pid), path);
163                         if (r < 0)
164                                 return log_oom();
165                         path = NULL;
166                 }
167         }
168
169         /* Abort execution of this process after the timout. We simply
170          * rely on SIGALRM as default action terminating the process,
171          * and turn on alarm(). */
172
173         if (timeout != USEC_INFINITY)
174                 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
175
176         while (!hashmap_isempty(pids)) {
177                 _cleanup_free_ char *path = NULL;
178                 pid_t pid;
179
180                 pid = PTR_TO_PID(hashmap_first_key(pids));
181                 assert(pid > 0);
182
183                 path = hashmap_remove(pids, PID_TO_PTR(pid));
184                 assert(path);
185
186                 wait_for_terminate_and_warn(path, pid, true);
187         }
188
189         return 0;
190 }
191
192 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
193         pid_t executor_pid;
194         int r;
195         char *name;
196         char **dirs = (char**) directories;
197
198         assert(!strv_isempty(dirs));
199
200         name = basename(dirs[0]);
201         assert(!isempty(name));
202
203         /* Executes all binaries in the directories in parallel and waits
204          * for them to finish. Optionally a timeout is applied. If a file
205          * with the same name exists in more than one directory, the
206          * earliest one wins. */
207
208         executor_pid = fork();
209         if (executor_pid < 0) {
210                 log_error_errno(errno, "Failed to fork: %m");
211                 return;
212
213         } else if (executor_pid == 0) {
214                 r = do_execute(dirs, timeout, argv);
215                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
216         }
217
218         wait_for_terminate_and_warn(name, executor_pid, true);
219 }
220
221 #if 0 /// UNNEEDED by elogind
222 bool plymouth_running(void) {
223         return access("/run/plymouth/pid", F_OK) >= 0;
224 }
225 #endif // 0
226
227 bool display_is_local(const char *display) {
228         assert(display);
229
230         return
231                 display[0] == ':' &&
232                 display[1] >= '0' &&
233                 display[1] <= '9';
234 }
235
236 int socket_from_display(const char *display, char **path) {
237         size_t k;
238         char *f, *c;
239
240         assert(display);
241         assert(path);
242
243         if (!display_is_local(display))
244                 return -EINVAL;
245
246         k = strspn(display+1, "0123456789");
247
248         f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
249         if (!f)
250                 return -ENOMEM;
251
252         c = stpcpy(f, "/tmp/.X11-unix/X");
253         memcpy(c, display+1, k);
254         c[k] = 0;
255
256         *path = f;
257
258         return 0;
259 }
260
261 #if 0 /// UNNEEDED by elogind
262 int block_get_whole_disk(dev_t d, dev_t *ret) {
263         char *p, *s;
264         int r;
265         unsigned n, m;
266
267         assert(ret);
268
269         /* If it has a queue this is good enough for us */
270         if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
271                 return -ENOMEM;
272
273         r = access(p, F_OK);
274         free(p);
275
276         if (r >= 0) {
277                 *ret = d;
278                 return 0;
279         }
280
281         /* If it is a partition find the originating device */
282         if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
283                 return -ENOMEM;
284
285         r = access(p, F_OK);
286         free(p);
287
288         if (r < 0)
289                 return -ENOENT;
290
291         /* Get parent dev_t */
292         if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
293                 return -ENOMEM;
294
295         r = read_one_line_file(p, &s);
296         free(p);
297
298         if (r < 0)
299                 return r;
300
301         r = sscanf(s, "%u:%u", &m, &n);
302         free(s);
303
304         if (r != 2)
305                 return -EINVAL;
306
307         /* Only return this if it is really good enough for us. */
308         if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
309                 return -ENOMEM;
310
311         r = access(p, F_OK);
312         free(p);
313
314         if (r >= 0) {
315                 *ret = makedev(m, n);
316                 return 0;
317         }
318
319         return -ENOENT;
320 }
321
322 bool kexec_loaded(void) {
323        bool loaded = false;
324        char *s;
325
326        if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
327                if (s[0] == '1')
328                        loaded = true;
329                free(s);
330        }
331        return loaded;
332 }
333
334 int prot_from_flags(int flags) {
335
336         switch (flags & O_ACCMODE) {
337
338         case O_RDONLY:
339                 return PROT_READ;
340
341         case O_WRONLY:
342                 return PROT_WRITE;
343
344         case O_RDWR:
345                 return PROT_READ|PROT_WRITE;
346
347         default:
348                 return -EINVAL;
349         }
350 }
351 #endif // 0
352
353 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
354         bool stdout_is_tty, stderr_is_tty;
355         pid_t parent_pid, agent_pid;
356         sigset_t ss, saved_ss;
357         unsigned n, i;
358         va_list ap;
359         char **l;
360
361         assert(pid);
362         assert(path);
363
364         /* Spawns a temporary TTY agent, making sure it goes away when
365          * we go away */
366
367         parent_pid = getpid();
368
369         /* First we temporarily block all signals, so that the new
370          * child has them blocked initially. This way, we can be sure
371          * that SIGTERMs are not lost we might send to the agent. */
372         assert_se(sigfillset(&ss) >= 0);
373         assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
374
375         agent_pid = fork();
376         if (agent_pid < 0) {
377                 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
378                 return -errno;
379         }
380
381         if (agent_pid != 0) {
382                 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
383                 *pid = agent_pid;
384                 return 0;
385         }
386
387         /* In the child:
388          *
389          * Make sure the agent goes away when the parent dies */
390         if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
391                 _exit(EXIT_FAILURE);
392
393         /* Make sure we actually can kill the agent, if we need to, in
394          * case somebody invoked us from a shell script that trapped
395          * SIGTERM or so... */
396         (void) reset_all_signal_handlers();
397         (void) reset_signal_mask();
398
399         /* Check whether our parent died before we were able
400          * to set the death signal and unblock the signals */
401         if (getppid() != parent_pid)
402                 _exit(EXIT_SUCCESS);
403
404         /* Don't leak fds to the agent */
405         close_all_fds(except, n_except);
406
407         stdout_is_tty = isatty(STDOUT_FILENO);
408         stderr_is_tty = isatty(STDERR_FILENO);
409
410         if (!stdout_is_tty || !stderr_is_tty) {
411                 int fd;
412
413                 /* Detach from stdout/stderr. and reopen
414                  * /dev/tty for them. This is important to
415                  * ensure that when systemctl is started via
416                  * popen() or a similar call that expects to
417                  * read EOF we actually do generate EOF and
418                  * not delay this indefinitely by because we
419                  * keep an unused copy of stdin around. */
420                 fd = open("/dev/tty", O_WRONLY);
421                 if (fd < 0) {
422                         log_error_errno(errno, "Failed to open /dev/tty: %m");
423                         _exit(EXIT_FAILURE);
424                 }
425
426                 if (!stdout_is_tty)
427                         dup2(fd, STDOUT_FILENO);
428
429                 if (!stderr_is_tty)
430                         dup2(fd, STDERR_FILENO);
431
432                 if (fd > 2)
433                         close(fd);
434         }
435
436         /* Count arguments */
437         va_start(ap, path);
438         for (n = 0; va_arg(ap, char*); n++)
439                 ;
440         va_end(ap);
441
442         /* Allocate strv */
443         l = alloca(sizeof(char *) * (n + 1));
444
445         /* Fill in arguments */
446         va_start(ap, path);
447         for (i = 0; i <= n; i++)
448                 l[i] = va_arg(ap, char*);
449         va_end(ap);
450
451         execv(path, l);
452         _exit(EXIT_FAILURE);
453 }
454
455 bool in_initrd(void) {
456         static int saved = -1;
457         struct statfs s;
458
459         if (saved >= 0)
460                 return saved;
461
462         /* We make two checks here:
463          *
464          * 1. the flag file /etc/initrd-release must exist
465          * 2. the root file system must be a memory file system
466          *
467          * The second check is extra paranoia, since misdetecting an
468          * initrd can have bad bad consequences due the initrd
469          * emptying when transititioning to the main systemd.
470          */
471
472         saved = access("/etc/initrd-release", F_OK) >= 0 &&
473                 statfs("/", &s) >= 0 &&
474                 is_temporary_fs(&s);
475
476         return saved;
477 }
478
479 #if 0 /// UNNEEDED by elogind
480 /* hey glibc, APIs with callbacks without a user pointer are so useless */
481 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
482                  int (*compar) (const void *, const void *, void *), void *arg) {
483         size_t l, u, idx;
484         const void *p;
485         int comparison;
486
487         l = 0;
488         u = nmemb;
489         while (l < u) {
490                 idx = (l + u) / 2;
491                 p = (void *)(((const char *) base) + (idx * size));
492                 comparison = compar(key, p, arg);
493                 if (comparison < 0)
494                         u = idx;
495                 else if (comparison > 0)
496                         l = idx + 1;
497                 else
498                         return (void *)p;
499         }
500         return NULL;
501 }
502
503 int on_ac_power(void) {
504         bool found_offline = false, found_online = false;
505         _cleanup_closedir_ DIR *d = NULL;
506
507         d = opendir("/sys/class/power_supply");
508         if (!d)
509                 return errno == ENOENT ? true : -errno;
510
511         for (;;) {
512                 struct dirent *de;
513                 _cleanup_close_ int fd = -1, device = -1;
514                 char contents[6];
515                 ssize_t n;
516
517                 errno = 0;
518                 de = readdir(d);
519                 if (!de && errno > 0)
520                         return -errno;
521
522                 if (!de)
523                         break;
524
525                 if (hidden_file(de->d_name))
526                         continue;
527
528                 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
529                 if (device < 0) {
530                         if (errno == ENOENT || errno == ENOTDIR)
531                                 continue;
532
533                         return -errno;
534                 }
535
536                 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
537                 if (fd < 0) {
538                         if (errno == ENOENT)
539                                 continue;
540
541                         return -errno;
542                 }
543
544                 n = read(fd, contents, sizeof(contents));
545                 if (n < 0)
546                         return -errno;
547
548                 if (n != 6 || memcmp(contents, "Mains\n", 6))
549                         continue;
550
551                 safe_close(fd);
552                 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
553                 if (fd < 0) {
554                         if (errno == ENOENT)
555                                 continue;
556
557                         return -errno;
558                 }
559
560                 n = read(fd, contents, sizeof(contents));
561                 if (n < 0)
562                         return -errno;
563
564                 if (n != 2 || contents[1] != '\n')
565                         return -EIO;
566
567                 if (contents[0] == '1') {
568                         found_online = true;
569                         break;
570                 } else if (contents[0] == '0')
571                         found_offline = true;
572                 else
573                         return -EIO;
574         }
575
576         return found_online || !found_offline;
577 }
578
579 bool id128_is_valid(const char *s) {
580         size_t i, l;
581
582         l = strlen(s);
583         if (l == 32) {
584
585                 /* Simple formatted 128bit hex string */
586
587                 for (i = 0; i < l; i++) {
588                         char c = s[i];
589
590                         if (!(c >= '0' && c <= '9') &&
591                             !(c >= 'a' && c <= 'z') &&
592                             !(c >= 'A' && c <= 'Z'))
593                                 return false;
594                 }
595
596         } else if (l == 36) {
597
598                 /* Formatted UUID */
599
600                 for (i = 0; i < l; i++) {
601                         char c = s[i];
602
603                         if ((i == 8 || i == 13 || i == 18 || i == 23)) {
604                                 if (c != '-')
605                                         return false;
606                         } else {
607                                 if (!(c >= '0' && c <= '9') &&
608                                     !(c >= 'a' && c <= 'z') &&
609                                     !(c >= 'A' && c <= 'Z'))
610                                         return false;
611                         }
612                 }
613
614         } else
615                 return false;
616
617         return true;
618 }
619 #endif // 0
620
621 int container_get_leader(const char *machine, pid_t *pid) {
622         _cleanup_free_ char *s = NULL, *class = NULL;
623         const char *p;
624         pid_t leader;
625         int r;
626
627         assert(machine);
628         assert(pid);
629
630         if (!machine_name_is_valid(machine))
631                 return -EINVAL;
632
633         p = strjoina("/run/systemd/machines/", machine);
634         r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
635         if (r == -ENOENT)
636                 return -EHOSTDOWN;
637         if (r < 0)
638                 return r;
639         if (!s)
640                 return -EIO;
641
642         if (!streq_ptr(class, "container"))
643                 return -EIO;
644
645         r = parse_pid(s, &leader);
646         if (r < 0)
647                 return r;
648         if (leader <= 1)
649                 return -EIO;
650
651         *pid = leader;
652         return 0;
653 }
654
655 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
656         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
657         int rfd = -1;
658
659         assert(pid >= 0);
660
661         if (mntns_fd) {
662                 const char *mntns;
663
664                 mntns = procfs_file_alloca(pid, "ns/mnt");
665                 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
666                 if (mntnsfd < 0)
667                         return -errno;
668         }
669
670         if (pidns_fd) {
671                 const char *pidns;
672
673                 pidns = procfs_file_alloca(pid, "ns/pid");
674                 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
675                 if (pidnsfd < 0)
676                         return -errno;
677         }
678
679         if (netns_fd) {
680                 const char *netns;
681
682                 netns = procfs_file_alloca(pid, "ns/net");
683                 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
684                 if (netnsfd < 0)
685                         return -errno;
686         }
687
688         if (userns_fd) {
689                 const char *userns;
690
691                 userns = procfs_file_alloca(pid, "ns/user");
692                 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
693                 if (usernsfd < 0 && errno != ENOENT)
694                         return -errno;
695         }
696
697         if (root_fd) {
698                 const char *root;
699
700                 root = procfs_file_alloca(pid, "root");
701                 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
702                 if (rfd < 0)
703                         return -errno;
704         }
705
706         if (pidns_fd)
707                 *pidns_fd = pidnsfd;
708
709         if (mntns_fd)
710                 *mntns_fd = mntnsfd;
711
712         if (netns_fd)
713                 *netns_fd = netnsfd;
714
715         if (userns_fd)
716                 *userns_fd = usernsfd;
717
718         if (root_fd)
719                 *root_fd = rfd;
720
721         pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
722
723         return 0;
724 }
725
726 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
727         if (userns_fd >= 0) {
728                 /* Can't setns to your own userns, since then you could
729                  * escalate from non-root to root in your own namespace, so
730                  * check if namespaces equal before attempting to enter. */
731                 _cleanup_free_ char *userns_fd_path = NULL;
732                 int r;
733                 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
734                         return -ENOMEM;
735
736                 r = files_same(userns_fd_path, "/proc/self/ns/user");
737                 if (r < 0)
738                         return r;
739                 if (r)
740                         userns_fd = -1;
741         }
742
743         if (pidns_fd >= 0)
744                 if (setns(pidns_fd, CLONE_NEWPID) < 0)
745                         return -errno;
746
747         if (mntns_fd >= 0)
748                 if (setns(mntns_fd, CLONE_NEWNS) < 0)
749                         return -errno;
750
751         if (netns_fd >= 0)
752                 if (setns(netns_fd, CLONE_NEWNET) < 0)
753                         return -errno;
754
755         if (userns_fd >= 0)
756                 if (setns(userns_fd, CLONE_NEWUSER) < 0)
757                         return -errno;
758
759         if (root_fd >= 0) {
760                 if (fchdir(root_fd) < 0)
761                         return -errno;
762
763                 if (chroot(".") < 0)
764                         return -errno;
765         }
766
767         return reset_uid_gid();
768 }
769
770 uint64_t physical_memory(void) {
771         long mem;
772
773         /* We return this as uint64_t in case we are running as 32bit
774          * process on a 64bit kernel with huge amounts of memory */
775
776         mem = sysconf(_SC_PHYS_PAGES);
777         assert(mem > 0);
778
779         return (uint64_t) mem * (uint64_t) page_size();
780 }
781
782 #if 0 /// UNNEEDED by elogind
783 int update_reboot_param_file(const char *param) {
784         int r = 0;
785
786         if (param) {
787                 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
788                 if (r < 0)
789                         return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
790         } else
791                 (void) unlink(REBOOT_PARAM_FILE);
792
793         return 0;
794 }
795 #endif // 0
796
797 int version(void) {
798         puts(PACKAGE_STRING "\n"
799              SYSTEMD_FEATURES);
800         return 0;
801 }