]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/util.c
util-lib: split out syslog-related calls into syslog-util.[ch]
[thirdparty/systemd.git] / src / basic / util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <ctype.h>
23 #include <dirent.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <glob.h>
27 #include <grp.h>
28 #include <langinfo.h>
29 #include <libintl.h>
30 #include <limits.h>
31 #include <linux/magic.h>
32 #include <linux/oom.h>
33 #include <linux/sched.h>
34 #include <locale.h>
35 #include <poll.h>
36 #include <pwd.h>
37 #include <sched.h>
38 #include <signal.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/file.h>
44 #include <sys/ioctl.h>
45 #include <sys/mman.h>
46 #include <sys/mount.h>
47 #include <sys/personality.h>
48 #include <sys/prctl.h>
49 #include <sys/stat.h>
50 #include <sys/statvfs.h>
51 #include <sys/time.h>
52 #include <sys/types.h>
53 #include <sys/utsname.h>
54 #include <sys/vfs.h>
55 #include <sys/wait.h>
56 #include <syslog.h>
57 #include <unistd.h>
58
59 /* When we include libgen.h because we need dirname() we immediately
60 * undefine basename() since libgen.h defines it as a macro to the
61 * POSIX version which is really broken. We prefer GNU basename(). */
62 #include <libgen.h>
63 #undef basename
64
65 #ifdef HAVE_SYS_AUXV_H
66 #include <sys/auxv.h>
67 #endif
68
69 /* We include linux/fs.h as last of the system headers, as it
70 * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
71 #include <linux/fs.h>
72
73 #include "build.h"
74 #include "def.h"
75 #include "device-nodes.h"
76 #include "env-util.h"
77 #include "escape.h"
78 #include "exit-status.h"
79 #include "fd-util.h"
80 #include "fileio.h"
81 #include "formats-util.h"
82 #include "gunicode.h"
83 #include "hashmap.h"
84 #include "hostname-util.h"
85 #include "ioprio.h"
86 #include "log.h"
87 #include "macro.h"
88 #include "missing.h"
89 #include "mkdir.h"
90 #include "hexdecoct.h"
91 #include "parse-util.h"
92 #include "path-util.h"
93 #include "process-util.h"
94 #include "random-util.h"
95 #include "signal-util.h"
96 #include "sparse-endian.h"
97 #include "string-table.h"
98 #include "string-util.h"
99 #include "strv.h"
100 #include "terminal-util.h"
101 #include "user-util.h"
102 #include "utf8.h"
103 #include "util.h"
104 #include "virt.h"
105 #include "dirent-util.h"
106 #include "stat-util.h"
107
108 /* Put this test here for a lack of better place */
109 assert_cc(EAGAIN == EWOULDBLOCK);
110
111 int saved_argc = 0;
112 char **saved_argv = NULL;
113
114 size_t page_size(void) {
115 static thread_local size_t pgsz = 0;
116 long r;
117
118 if (_likely_(pgsz > 0))
119 return pgsz;
120
121 r = sysconf(_SC_PAGESIZE);
122 assert(r > 0);
123
124 pgsz = (size_t) r;
125 return pgsz;
126 }
127
128 bool fstype_is_network(const char *fstype) {
129 static const char table[] =
130 "afs\0"
131 "cifs\0"
132 "smbfs\0"
133 "sshfs\0"
134 "ncpfs\0"
135 "ncp\0"
136 "nfs\0"
137 "nfs4\0"
138 "gfs\0"
139 "gfs2\0"
140 "glusterfs\0";
141
142 const char *x;
143
144 x = startswith(fstype, "fuse.");
145 if (x)
146 fstype = x;
147
148 return nulstr_contains(table, fstype);
149 }
150
151 void rename_process(const char name[8]) {
152 assert(name);
153
154 /* This is a like a poor man's setproctitle(). It changes the
155 * comm field, argv[0], and also the glibc's internally used
156 * name of the process. For the first one a limit of 16 chars
157 * applies, to the second one usually one of 10 (i.e. length
158 * of "/sbin/init"), to the third one one of 7 (i.e. length of
159 * "systemd"). If you pass a longer string it will be
160 * truncated */
161
162 prctl(PR_SET_NAME, name);
163
164 if (program_invocation_name)
165 strncpy(program_invocation_name, name, strlen(program_invocation_name));
166
167 if (saved_argc > 0) {
168 int i;
169
170 if (saved_argv[0])
171 strncpy(saved_argv[0], name, strlen(saved_argv[0]));
172
173 for (i = 1; i < saved_argc; i++) {
174 if (!saved_argv[i])
175 break;
176
177 memzero(saved_argv[i], strlen(saved_argv[i]));
178 }
179 }
180 }
181
182 noreturn void freeze(void) {
183
184 /* Make sure nobody waits for us on a socket anymore */
185 close_all_fds(NULL, 0);
186
187 sync();
188
189 for (;;)
190 pause();
191 }
192
193 static int do_execute(char **directories, usec_t timeout, char *argv[]) {
194 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
195 _cleanup_set_free_free_ Set *seen = NULL;
196 char **directory;
197
198 /* We fork this all off from a child process so that we can
199 * somewhat cleanly make use of SIGALRM to set a time limit */
200
201 (void) reset_all_signal_handlers();
202 (void) reset_signal_mask();
203
204 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
205
206 pids = hashmap_new(NULL);
207 if (!pids)
208 return log_oom();
209
210 seen = set_new(&string_hash_ops);
211 if (!seen)
212 return log_oom();
213
214 STRV_FOREACH(directory, directories) {
215 _cleanup_closedir_ DIR *d;
216 struct dirent *de;
217
218 d = opendir(*directory);
219 if (!d) {
220 if (errno == ENOENT)
221 continue;
222
223 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
224 }
225
226 FOREACH_DIRENT(de, d, break) {
227 _cleanup_free_ char *path = NULL;
228 pid_t pid;
229 int r;
230
231 if (!dirent_is_file(de))
232 continue;
233
234 if (set_contains(seen, de->d_name)) {
235 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
236 continue;
237 }
238
239 r = set_put_strdup(seen, de->d_name);
240 if (r < 0)
241 return log_oom();
242
243 path = strjoin(*directory, "/", de->d_name, NULL);
244 if (!path)
245 return log_oom();
246
247 if (null_or_empty_path(path)) {
248 log_debug("%s is empty (a mask).", path);
249 continue;
250 }
251
252 pid = fork();
253 if (pid < 0) {
254 log_error_errno(errno, "Failed to fork: %m");
255 continue;
256 } else if (pid == 0) {
257 char *_argv[2];
258
259 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
260
261 if (!argv) {
262 _argv[0] = path;
263 _argv[1] = NULL;
264 argv = _argv;
265 } else
266 argv[0] = path;
267
268 execv(path, argv);
269 return log_error_errno(errno, "Failed to execute %s: %m", path);
270 }
271
272 log_debug("Spawned %s as " PID_FMT ".", path, pid);
273
274 r = hashmap_put(pids, UINT_TO_PTR(pid), path);
275 if (r < 0)
276 return log_oom();
277 path = NULL;
278 }
279 }
280
281 /* Abort execution of this process after the timout. We simply
282 * rely on SIGALRM as default action terminating the process,
283 * and turn on alarm(). */
284
285 if (timeout != USEC_INFINITY)
286 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
287
288 while (!hashmap_isempty(pids)) {
289 _cleanup_free_ char *path = NULL;
290 pid_t pid;
291
292 pid = PTR_TO_UINT(hashmap_first_key(pids));
293 assert(pid > 0);
294
295 path = hashmap_remove(pids, UINT_TO_PTR(pid));
296 assert(path);
297
298 wait_for_terminate_and_warn(path, pid, true);
299 }
300
301 return 0;
302 }
303
304 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
305 pid_t executor_pid;
306 int r;
307 char *name;
308 char **dirs = (char**) directories;
309
310 assert(!strv_isempty(dirs));
311
312 name = basename(dirs[0]);
313 assert(!isempty(name));
314
315 /* Executes all binaries in the directories in parallel and waits
316 * for them to finish. Optionally a timeout is applied. If a file
317 * with the same name exists in more than one directory, the
318 * earliest one wins. */
319
320 executor_pid = fork();
321 if (executor_pid < 0) {
322 log_error_errno(errno, "Failed to fork: %m");
323 return;
324
325 } else if (executor_pid == 0) {
326 r = do_execute(dirs, timeout, argv);
327 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
328 }
329
330 wait_for_terminate_and_warn(name, executor_pid, true);
331 }
332
333 bool plymouth_running(void) {
334 return access("/run/plymouth/pid", F_OK) >= 0;
335 }
336
337 bool display_is_local(const char *display) {
338 assert(display);
339
340 return
341 display[0] == ':' &&
342 display[1] >= '0' &&
343 display[1] <= '9';
344 }
345
346 int socket_from_display(const char *display, char **path) {
347 size_t k;
348 char *f, *c;
349
350 assert(display);
351 assert(path);
352
353 if (!display_is_local(display))
354 return -EINVAL;
355
356 k = strspn(display+1, "0123456789");
357
358 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
359 if (!f)
360 return -ENOMEM;
361
362 c = stpcpy(f, "/tmp/.X11-unix/X");
363 memcpy(c, display+1, k);
364 c[k] = 0;
365
366 *path = f;
367
368 return 0;
369 }
370
371 int glob_exists(const char *path) {
372 _cleanup_globfree_ glob_t g = {};
373 int k;
374
375 assert(path);
376
377 errno = 0;
378 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
379
380 if (k == GLOB_NOMATCH)
381 return 0;
382 else if (k == GLOB_NOSPACE)
383 return -ENOMEM;
384 else if (k == 0)
385 return !strv_isempty(g.gl_pathv);
386 else
387 return errno ? -errno : -EIO;
388 }
389
390 int glob_extend(char ***strv, const char *path) {
391 _cleanup_globfree_ glob_t g = {};
392 int k;
393 char **p;
394
395 errno = 0;
396 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
397
398 if (k == GLOB_NOMATCH)
399 return -ENOENT;
400 else if (k == GLOB_NOSPACE)
401 return -ENOMEM;
402 else if (k != 0 || strv_isempty(g.gl_pathv))
403 return errno ? -errno : -EIO;
404
405 STRV_FOREACH(p, g.gl_pathv) {
406 k = strv_extend(strv, *p);
407 if (k < 0)
408 break;
409 }
410
411 return k;
412 }
413
414 int block_get_whole_disk(dev_t d, dev_t *ret) {
415 char *p, *s;
416 int r;
417 unsigned n, m;
418
419 assert(ret);
420
421 /* If it has a queue this is good enough for us */
422 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
423 return -ENOMEM;
424
425 r = access(p, F_OK);
426 free(p);
427
428 if (r >= 0) {
429 *ret = d;
430 return 0;
431 }
432
433 /* If it is a partition find the originating device */
434 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
435 return -ENOMEM;
436
437 r = access(p, F_OK);
438 free(p);
439
440 if (r < 0)
441 return -ENOENT;
442
443 /* Get parent dev_t */
444 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
445 return -ENOMEM;
446
447 r = read_one_line_file(p, &s);
448 free(p);
449
450 if (r < 0)
451 return r;
452
453 r = sscanf(s, "%u:%u", &m, &n);
454 free(s);
455
456 if (r != 2)
457 return -EINVAL;
458
459 /* Only return this if it is really good enough for us. */
460 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
461 return -ENOMEM;
462
463 r = access(p, F_OK);
464 free(p);
465
466 if (r >= 0) {
467 *ret = makedev(m, n);
468 return 0;
469 }
470
471 return -ENOENT;
472 }
473
474 static const char *const ioprio_class_table[] = {
475 [IOPRIO_CLASS_NONE] = "none",
476 [IOPRIO_CLASS_RT] = "realtime",
477 [IOPRIO_CLASS_BE] = "best-effort",
478 [IOPRIO_CLASS_IDLE] = "idle"
479 };
480
481 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
482
483 static const char *const sigchld_code_table[] = {
484 [CLD_EXITED] = "exited",
485 [CLD_KILLED] = "killed",
486 [CLD_DUMPED] = "dumped",
487 [CLD_TRAPPED] = "trapped",
488 [CLD_STOPPED] = "stopped",
489 [CLD_CONTINUED] = "continued",
490 };
491
492 DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
493
494 static const char* const sched_policy_table[] = {
495 [SCHED_OTHER] = "other",
496 [SCHED_BATCH] = "batch",
497 [SCHED_IDLE] = "idle",
498 [SCHED_FIFO] = "fifo",
499 [SCHED_RR] = "rr"
500 };
501
502 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
503
504 bool kexec_loaded(void) {
505 bool loaded = false;
506 char *s;
507
508 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
509 if (s[0] == '1')
510 loaded = true;
511 free(s);
512 }
513 return loaded;
514 }
515
516 int prot_from_flags(int flags) {
517
518 switch (flags & O_ACCMODE) {
519
520 case O_RDONLY:
521 return PROT_READ;
522
523 case O_WRONLY:
524 return PROT_WRITE;
525
526 case O_RDWR:
527 return PROT_READ|PROT_WRITE;
528
529 default:
530 return -EINVAL;
531 }
532 }
533
534 void* memdup(const void *p, size_t l) {
535 void *r;
536
537 assert(p);
538
539 r = malloc(l);
540 if (!r)
541 return NULL;
542
543 memcpy(r, p, l);
544 return r;
545 }
546
547 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
548 bool stdout_is_tty, stderr_is_tty;
549 pid_t parent_pid, agent_pid;
550 sigset_t ss, saved_ss;
551 unsigned n, i;
552 va_list ap;
553 char **l;
554
555 assert(pid);
556 assert(path);
557
558 /* Spawns a temporary TTY agent, making sure it goes away when
559 * we go away */
560
561 parent_pid = getpid();
562
563 /* First we temporarily block all signals, so that the new
564 * child has them blocked initially. This way, we can be sure
565 * that SIGTERMs are not lost we might send to the agent. */
566 assert_se(sigfillset(&ss) >= 0);
567 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
568
569 agent_pid = fork();
570 if (agent_pid < 0) {
571 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
572 return -errno;
573 }
574
575 if (agent_pid != 0) {
576 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
577 *pid = agent_pid;
578 return 0;
579 }
580
581 /* In the child:
582 *
583 * Make sure the agent goes away when the parent dies */
584 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
585 _exit(EXIT_FAILURE);
586
587 /* Make sure we actually can kill the agent, if we need to, in
588 * case somebody invoked us from a shell script that trapped
589 * SIGTERM or so... */
590 (void) reset_all_signal_handlers();
591 (void) reset_signal_mask();
592
593 /* Check whether our parent died before we were able
594 * to set the death signal and unblock the signals */
595 if (getppid() != parent_pid)
596 _exit(EXIT_SUCCESS);
597
598 /* Don't leak fds to the agent */
599 close_all_fds(except, n_except);
600
601 stdout_is_tty = isatty(STDOUT_FILENO);
602 stderr_is_tty = isatty(STDERR_FILENO);
603
604 if (!stdout_is_tty || !stderr_is_tty) {
605 int fd;
606
607 /* Detach from stdout/stderr. and reopen
608 * /dev/tty for them. This is important to
609 * ensure that when systemctl is started via
610 * popen() or a similar call that expects to
611 * read EOF we actually do generate EOF and
612 * not delay this indefinitely by because we
613 * keep an unused copy of stdin around. */
614 fd = open("/dev/tty", O_WRONLY);
615 if (fd < 0) {
616 log_error_errno(errno, "Failed to open /dev/tty: %m");
617 _exit(EXIT_FAILURE);
618 }
619
620 if (!stdout_is_tty)
621 dup2(fd, STDOUT_FILENO);
622
623 if (!stderr_is_tty)
624 dup2(fd, STDERR_FILENO);
625
626 if (fd > 2)
627 close(fd);
628 }
629
630 /* Count arguments */
631 va_start(ap, path);
632 for (n = 0; va_arg(ap, char*); n++)
633 ;
634 va_end(ap);
635
636 /* Allocate strv */
637 l = alloca(sizeof(char *) * (n + 1));
638
639 /* Fill in arguments */
640 va_start(ap, path);
641 for (i = 0; i <= n; i++)
642 l[i] = va_arg(ap, char*);
643 va_end(ap);
644
645 execv(path, l);
646 _exit(EXIT_FAILURE);
647 }
648
649 bool http_etag_is_valid(const char *etag) {
650 if (isempty(etag))
651 return false;
652
653 if (!endswith(etag, "\""))
654 return false;
655
656 if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
657 return false;
658
659 return true;
660 }
661
662 bool http_url_is_valid(const char *url) {
663 const char *p;
664
665 if (isempty(url))
666 return false;
667
668 p = startswith(url, "http://");
669 if (!p)
670 p = startswith(url, "https://");
671 if (!p)
672 return false;
673
674 if (isempty(p))
675 return false;
676
677 return ascii_is_valid(p);
678 }
679
680 bool documentation_url_is_valid(const char *url) {
681 const char *p;
682
683 if (isempty(url))
684 return false;
685
686 if (http_url_is_valid(url))
687 return true;
688
689 p = startswith(url, "file:/");
690 if (!p)
691 p = startswith(url, "info:");
692 if (!p)
693 p = startswith(url, "man:");
694
695 if (isempty(p))
696 return false;
697
698 return ascii_is_valid(p);
699 }
700
701 bool in_initrd(void) {
702 static int saved = -1;
703 struct statfs s;
704
705 if (saved >= 0)
706 return saved;
707
708 /* We make two checks here:
709 *
710 * 1. the flag file /etc/initrd-release must exist
711 * 2. the root file system must be a memory file system
712 *
713 * The second check is extra paranoia, since misdetecting an
714 * initrd can have bad bad consequences due the initrd
715 * emptying when transititioning to the main systemd.
716 */
717
718 saved = access("/etc/initrd-release", F_OK) >= 0 &&
719 statfs("/", &s) >= 0 &&
720 is_temporary_fs(&s);
721
722 return saved;
723 }
724
725 /* hey glibc, APIs with callbacks without a user pointer are so useless */
726 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
727 int (*compar) (const void *, const void *, void *), void *arg) {
728 size_t l, u, idx;
729 const void *p;
730 int comparison;
731
732 l = 0;
733 u = nmemb;
734 while (l < u) {
735 idx = (l + u) / 2;
736 p = (void *)(((const char *) base) + (idx * size));
737 comparison = compar(key, p, arg);
738 if (comparison < 0)
739 u = idx;
740 else if (comparison > 0)
741 l = idx + 1;
742 else
743 return (void *)p;
744 }
745 return NULL;
746 }
747
748 int on_ac_power(void) {
749 bool found_offline = false, found_online = false;
750 _cleanup_closedir_ DIR *d = NULL;
751
752 d = opendir("/sys/class/power_supply");
753 if (!d)
754 return errno == ENOENT ? true : -errno;
755
756 for (;;) {
757 struct dirent *de;
758 _cleanup_close_ int fd = -1, device = -1;
759 char contents[6];
760 ssize_t n;
761
762 errno = 0;
763 de = readdir(d);
764 if (!de && errno != 0)
765 return -errno;
766
767 if (!de)
768 break;
769
770 if (hidden_file(de->d_name))
771 continue;
772
773 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
774 if (device < 0) {
775 if (errno == ENOENT || errno == ENOTDIR)
776 continue;
777
778 return -errno;
779 }
780
781 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
782 if (fd < 0) {
783 if (errno == ENOENT)
784 continue;
785
786 return -errno;
787 }
788
789 n = read(fd, contents, sizeof(contents));
790 if (n < 0)
791 return -errno;
792
793 if (n != 6 || memcmp(contents, "Mains\n", 6))
794 continue;
795
796 safe_close(fd);
797 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
798 if (fd < 0) {
799 if (errno == ENOENT)
800 continue;
801
802 return -errno;
803 }
804
805 n = read(fd, contents, sizeof(contents));
806 if (n < 0)
807 return -errno;
808
809 if (n != 2 || contents[1] != '\n')
810 return -EIO;
811
812 if (contents[0] == '1') {
813 found_online = true;
814 break;
815 } else if (contents[0] == '0')
816 found_offline = true;
817 else
818 return -EIO;
819 }
820
821 return found_online || !found_offline;
822 }
823
824 void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
825 size_t a, newalloc;
826 void *q;
827
828 assert(p);
829 assert(allocated);
830
831 if (*allocated >= need)
832 return *p;
833
834 newalloc = MAX(need * 2, 64u / size);
835 a = newalloc * size;
836
837 /* check for overflows */
838 if (a < size * need)
839 return NULL;
840
841 q = realloc(*p, a);
842 if (!q)
843 return NULL;
844
845 *p = q;
846 *allocated = newalloc;
847 return q;
848 }
849
850 void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
851 size_t prev;
852 uint8_t *q;
853
854 assert(p);
855 assert(allocated);
856
857 prev = *allocated;
858
859 q = greedy_realloc(p, allocated, need, size);
860 if (!q)
861 return NULL;
862
863 if (*allocated > prev)
864 memzero(q + prev * size, (*allocated - prev) * size);
865
866 return q;
867 }
868
869 bool id128_is_valid(const char *s) {
870 size_t i, l;
871
872 l = strlen(s);
873 if (l == 32) {
874
875 /* Simple formatted 128bit hex string */
876
877 for (i = 0; i < l; i++) {
878 char c = s[i];
879
880 if (!(c >= '0' && c <= '9') &&
881 !(c >= 'a' && c <= 'z') &&
882 !(c >= 'A' && c <= 'Z'))
883 return false;
884 }
885
886 } else if (l == 36) {
887
888 /* Formatted UUID */
889
890 for (i = 0; i < l; i++) {
891 char c = s[i];
892
893 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
894 if (c != '-')
895 return false;
896 } else {
897 if (!(c >= '0' && c <= '9') &&
898 !(c >= 'a' && c <= 'z') &&
899 !(c >= 'A' && c <= 'Z'))
900 return false;
901 }
902 }
903
904 } else
905 return false;
906
907 return true;
908 }
909
910 int container_get_leader(const char *machine, pid_t *pid) {
911 _cleanup_free_ char *s = NULL, *class = NULL;
912 const char *p;
913 pid_t leader;
914 int r;
915
916 assert(machine);
917 assert(pid);
918
919 if (!machine_name_is_valid(machine))
920 return -EINVAL;
921
922 p = strjoina("/run/systemd/machines/", machine);
923 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
924 if (r == -ENOENT)
925 return -EHOSTDOWN;
926 if (r < 0)
927 return r;
928 if (!s)
929 return -EIO;
930
931 if (!streq_ptr(class, "container"))
932 return -EIO;
933
934 r = parse_pid(s, &leader);
935 if (r < 0)
936 return r;
937 if (leader <= 1)
938 return -EIO;
939
940 *pid = leader;
941 return 0;
942 }
943
944 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
945 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
946 int rfd = -1;
947
948 assert(pid >= 0);
949
950 if (mntns_fd) {
951 const char *mntns;
952
953 mntns = procfs_file_alloca(pid, "ns/mnt");
954 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
955 if (mntnsfd < 0)
956 return -errno;
957 }
958
959 if (pidns_fd) {
960 const char *pidns;
961
962 pidns = procfs_file_alloca(pid, "ns/pid");
963 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
964 if (pidnsfd < 0)
965 return -errno;
966 }
967
968 if (netns_fd) {
969 const char *netns;
970
971 netns = procfs_file_alloca(pid, "ns/net");
972 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
973 if (netnsfd < 0)
974 return -errno;
975 }
976
977 if (userns_fd) {
978 const char *userns;
979
980 userns = procfs_file_alloca(pid, "ns/user");
981 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
982 if (usernsfd < 0 && errno != ENOENT)
983 return -errno;
984 }
985
986 if (root_fd) {
987 const char *root;
988
989 root = procfs_file_alloca(pid, "root");
990 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
991 if (rfd < 0)
992 return -errno;
993 }
994
995 if (pidns_fd)
996 *pidns_fd = pidnsfd;
997
998 if (mntns_fd)
999 *mntns_fd = mntnsfd;
1000
1001 if (netns_fd)
1002 *netns_fd = netnsfd;
1003
1004 if (userns_fd)
1005 *userns_fd = usernsfd;
1006
1007 if (root_fd)
1008 *root_fd = rfd;
1009
1010 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
1011
1012 return 0;
1013 }
1014
1015 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
1016 if (userns_fd >= 0) {
1017 /* Can't setns to your own userns, since then you could
1018 * escalate from non-root to root in your own namespace, so
1019 * check if namespaces equal before attempting to enter. */
1020 _cleanup_free_ char *userns_fd_path = NULL;
1021 int r;
1022 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
1023 return -ENOMEM;
1024
1025 r = files_same(userns_fd_path, "/proc/self/ns/user");
1026 if (r < 0)
1027 return r;
1028 if (r)
1029 userns_fd = -1;
1030 }
1031
1032 if (pidns_fd >= 0)
1033 if (setns(pidns_fd, CLONE_NEWPID) < 0)
1034 return -errno;
1035
1036 if (mntns_fd >= 0)
1037 if (setns(mntns_fd, CLONE_NEWNS) < 0)
1038 return -errno;
1039
1040 if (netns_fd >= 0)
1041 if (setns(netns_fd, CLONE_NEWNET) < 0)
1042 return -errno;
1043
1044 if (userns_fd >= 0)
1045 if (setns(userns_fd, CLONE_NEWUSER) < 0)
1046 return -errno;
1047
1048 if (root_fd >= 0) {
1049 if (fchdir(root_fd) < 0)
1050 return -errno;
1051
1052 if (chroot(".") < 0)
1053 return -errno;
1054 }
1055
1056 return reset_uid_gid();
1057 }
1058
1059 unsigned long personality_from_string(const char *p) {
1060
1061 /* Parse a personality specifier. We introduce our own
1062 * identifiers that indicate specific ABIs, rather than just
1063 * hints regarding the register size, since we want to keep
1064 * things open for multiple locally supported ABIs for the
1065 * same register size. We try to reuse the ABI identifiers
1066 * used by libseccomp. */
1067
1068 #if defined(__x86_64__)
1069
1070 if (streq(p, "x86"))
1071 return PER_LINUX32;
1072
1073 if (streq(p, "x86-64"))
1074 return PER_LINUX;
1075
1076 #elif defined(__i386__)
1077
1078 if (streq(p, "x86"))
1079 return PER_LINUX;
1080
1081 #elif defined(__s390x__)
1082
1083 if (streq(p, "s390"))
1084 return PER_LINUX32;
1085
1086 if (streq(p, "s390x"))
1087 return PER_LINUX;
1088
1089 #elif defined(__s390__)
1090
1091 if (streq(p, "s390"))
1092 return PER_LINUX;
1093 #endif
1094
1095 return PERSONALITY_INVALID;
1096 }
1097
1098 const char* personality_to_string(unsigned long p) {
1099
1100 #if defined(__x86_64__)
1101
1102 if (p == PER_LINUX32)
1103 return "x86";
1104
1105 if (p == PER_LINUX)
1106 return "x86-64";
1107
1108 #elif defined(__i386__)
1109
1110 if (p == PER_LINUX)
1111 return "x86";
1112
1113 #elif defined(__s390x__)
1114
1115 if (p == PER_LINUX)
1116 return "s390x";
1117
1118 if (p == PER_LINUX32)
1119 return "s390";
1120
1121 #elif defined(__s390__)
1122
1123 if (p == PER_LINUX)
1124 return "s390";
1125
1126 #endif
1127
1128 return NULL;
1129 }
1130
1131 uint64_t physical_memory(void) {
1132 long mem;
1133
1134 /* We return this as uint64_t in case we are running as 32bit
1135 * process on a 64bit kernel with huge amounts of memory */
1136
1137 mem = sysconf(_SC_PHYS_PAGES);
1138 assert(mem > 0);
1139
1140 return (uint64_t) mem * (uint64_t) page_size();
1141 }
1142
1143 int update_reboot_param_file(const char *param) {
1144 int r = 0;
1145
1146 if (param) {
1147 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
1148 if (r < 0)
1149 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
1150 } else
1151 (void) unlink(REBOOT_PARAM_FILE);
1152
1153 return 0;
1154 }
1155
1156 int version(void) {
1157 puts(PACKAGE_STRING "\n"
1158 SYSTEMD_FEATURES);
1159 return 0;
1160 }
1161
1162 bool fdname_is_valid(const char *s) {
1163 const char *p;
1164
1165 /* Validates a name for $LISTEN_FDNAMES. We basically allow
1166 * everything ASCII that's not a control character. Also, as
1167 * special exception the ":" character is not allowed, as we
1168 * use that as field separator in $LISTEN_FDNAMES.
1169 *
1170 * Note that the empty string is explicitly allowed
1171 * here. However, we limit the length of the names to 255
1172 * characters. */
1173
1174 if (!s)
1175 return false;
1176
1177 for (p = s; *p; p++) {
1178 if (*p < ' ')
1179 return false;
1180 if (*p >= 127)
1181 return false;
1182 if (*p == ':')
1183 return false;
1184 }
1185
1186 return p - s < 256;
1187 }
1188
1189 bool oom_score_adjust_is_valid(int oa) {
1190 return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
1191 }