]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/util.c
util-lib: move string table stuff into its own string-table.[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 int running_in_chroot(void) {
183 int ret;
184
185 ret = files_same("/proc/1/root", "/");
186 if (ret < 0)
187 return ret;
188
189 return ret == 0;
190 }
191
192 noreturn void freeze(void) {
193
194 /* Make sure nobody waits for us on a socket anymore */
195 close_all_fds(NULL, 0);
196
197 sync();
198
199 for (;;)
200 pause();
201 }
202
203 static int do_execute(char **directories, usec_t timeout, char *argv[]) {
204 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
205 _cleanup_set_free_free_ Set *seen = NULL;
206 char **directory;
207
208 /* We fork this all off from a child process so that we can
209 * somewhat cleanly make use of SIGALRM to set a time limit */
210
211 (void) reset_all_signal_handlers();
212 (void) reset_signal_mask();
213
214 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
215
216 pids = hashmap_new(NULL);
217 if (!pids)
218 return log_oom();
219
220 seen = set_new(&string_hash_ops);
221 if (!seen)
222 return log_oom();
223
224 STRV_FOREACH(directory, directories) {
225 _cleanup_closedir_ DIR *d;
226 struct dirent *de;
227
228 d = opendir(*directory);
229 if (!d) {
230 if (errno == ENOENT)
231 continue;
232
233 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
234 }
235
236 FOREACH_DIRENT(de, d, break) {
237 _cleanup_free_ char *path = NULL;
238 pid_t pid;
239 int r;
240
241 if (!dirent_is_file(de))
242 continue;
243
244 if (set_contains(seen, de->d_name)) {
245 log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
246 continue;
247 }
248
249 r = set_put_strdup(seen, de->d_name);
250 if (r < 0)
251 return log_oom();
252
253 path = strjoin(*directory, "/", de->d_name, NULL);
254 if (!path)
255 return log_oom();
256
257 if (null_or_empty_path(path)) {
258 log_debug("%s is empty (a mask).", path);
259 continue;
260 }
261
262 pid = fork();
263 if (pid < 0) {
264 log_error_errno(errno, "Failed to fork: %m");
265 continue;
266 } else if (pid == 0) {
267 char *_argv[2];
268
269 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
270
271 if (!argv) {
272 _argv[0] = path;
273 _argv[1] = NULL;
274 argv = _argv;
275 } else
276 argv[0] = path;
277
278 execv(path, argv);
279 return log_error_errno(errno, "Failed to execute %s: %m", path);
280 }
281
282 log_debug("Spawned %s as " PID_FMT ".", path, pid);
283
284 r = hashmap_put(pids, UINT_TO_PTR(pid), path);
285 if (r < 0)
286 return log_oom();
287 path = NULL;
288 }
289 }
290
291 /* Abort execution of this process after the timout. We simply
292 * rely on SIGALRM as default action terminating the process,
293 * and turn on alarm(). */
294
295 if (timeout != USEC_INFINITY)
296 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
297
298 while (!hashmap_isempty(pids)) {
299 _cleanup_free_ char *path = NULL;
300 pid_t pid;
301
302 pid = PTR_TO_UINT(hashmap_first_key(pids));
303 assert(pid > 0);
304
305 path = hashmap_remove(pids, UINT_TO_PTR(pid));
306 assert(path);
307
308 wait_for_terminate_and_warn(path, pid, true);
309 }
310
311 return 0;
312 }
313
314 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
315 pid_t executor_pid;
316 int r;
317 char *name;
318 char **dirs = (char**) directories;
319
320 assert(!strv_isempty(dirs));
321
322 name = basename(dirs[0]);
323 assert(!isempty(name));
324
325 /* Executes all binaries in the directories in parallel and waits
326 * for them to finish. Optionally a timeout is applied. If a file
327 * with the same name exists in more than one directory, the
328 * earliest one wins. */
329
330 executor_pid = fork();
331 if (executor_pid < 0) {
332 log_error_errno(errno, "Failed to fork: %m");
333 return;
334
335 } else if (executor_pid == 0) {
336 r = do_execute(dirs, timeout, argv);
337 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
338 }
339
340 wait_for_terminate_and_warn(name, executor_pid, true);
341 }
342
343 bool plymouth_running(void) {
344 return access("/run/plymouth/pid", F_OK) >= 0;
345 }
346
347 bool display_is_local(const char *display) {
348 assert(display);
349
350 return
351 display[0] == ':' &&
352 display[1] >= '0' &&
353 display[1] <= '9';
354 }
355
356 int socket_from_display(const char *display, char **path) {
357 size_t k;
358 char *f, *c;
359
360 assert(display);
361 assert(path);
362
363 if (!display_is_local(display))
364 return -EINVAL;
365
366 k = strspn(display+1, "0123456789");
367
368 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
369 if (!f)
370 return -ENOMEM;
371
372 c = stpcpy(f, "/tmp/.X11-unix/X");
373 memcpy(c, display+1, k);
374 c[k] = 0;
375
376 *path = f;
377
378 return 0;
379 }
380
381 int glob_exists(const char *path) {
382 _cleanup_globfree_ glob_t g = {};
383 int k;
384
385 assert(path);
386
387 errno = 0;
388 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
389
390 if (k == GLOB_NOMATCH)
391 return 0;
392 else if (k == GLOB_NOSPACE)
393 return -ENOMEM;
394 else if (k == 0)
395 return !strv_isempty(g.gl_pathv);
396 else
397 return errno ? -errno : -EIO;
398 }
399
400 int glob_extend(char ***strv, const char *path) {
401 _cleanup_globfree_ glob_t g = {};
402 int k;
403 char **p;
404
405 errno = 0;
406 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
407
408 if (k == GLOB_NOMATCH)
409 return -ENOENT;
410 else if (k == GLOB_NOSPACE)
411 return -ENOMEM;
412 else if (k != 0 || strv_isempty(g.gl_pathv))
413 return errno ? -errno : -EIO;
414
415 STRV_FOREACH(p, g.gl_pathv) {
416 k = strv_extend(strv, *p);
417 if (k < 0)
418 break;
419 }
420
421 return k;
422 }
423
424 bool is_main_thread(void) {
425 static thread_local int cached = 0;
426
427 if (_unlikely_(cached == 0))
428 cached = getpid() == gettid() ? 1 : -1;
429
430 return cached > 0;
431 }
432
433 int block_get_whole_disk(dev_t d, dev_t *ret) {
434 char *p, *s;
435 int r;
436 unsigned n, m;
437
438 assert(ret);
439
440 /* If it has a queue this is good enough for us */
441 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
442 return -ENOMEM;
443
444 r = access(p, F_OK);
445 free(p);
446
447 if (r >= 0) {
448 *ret = d;
449 return 0;
450 }
451
452 /* If it is a partition find the originating device */
453 if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
454 return -ENOMEM;
455
456 r = access(p, F_OK);
457 free(p);
458
459 if (r < 0)
460 return -ENOENT;
461
462 /* Get parent dev_t */
463 if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
464 return -ENOMEM;
465
466 r = read_one_line_file(p, &s);
467 free(p);
468
469 if (r < 0)
470 return r;
471
472 r = sscanf(s, "%u:%u", &m, &n);
473 free(s);
474
475 if (r != 2)
476 return -EINVAL;
477
478 /* Only return this if it is really good enough for us. */
479 if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
480 return -ENOMEM;
481
482 r = access(p, F_OK);
483 free(p);
484
485 if (r >= 0) {
486 *ret = makedev(m, n);
487 return 0;
488 }
489
490 return -ENOENT;
491 }
492
493 static const char *const ioprio_class_table[] = {
494 [IOPRIO_CLASS_NONE] = "none",
495 [IOPRIO_CLASS_RT] = "realtime",
496 [IOPRIO_CLASS_BE] = "best-effort",
497 [IOPRIO_CLASS_IDLE] = "idle"
498 };
499
500 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
501
502 static const char *const sigchld_code_table[] = {
503 [CLD_EXITED] = "exited",
504 [CLD_KILLED] = "killed",
505 [CLD_DUMPED] = "dumped",
506 [CLD_TRAPPED] = "trapped",
507 [CLD_STOPPED] = "stopped",
508 [CLD_CONTINUED] = "continued",
509 };
510
511 DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
512
513 static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
514 [LOG_FAC(LOG_KERN)] = "kern",
515 [LOG_FAC(LOG_USER)] = "user",
516 [LOG_FAC(LOG_MAIL)] = "mail",
517 [LOG_FAC(LOG_DAEMON)] = "daemon",
518 [LOG_FAC(LOG_AUTH)] = "auth",
519 [LOG_FAC(LOG_SYSLOG)] = "syslog",
520 [LOG_FAC(LOG_LPR)] = "lpr",
521 [LOG_FAC(LOG_NEWS)] = "news",
522 [LOG_FAC(LOG_UUCP)] = "uucp",
523 [LOG_FAC(LOG_CRON)] = "cron",
524 [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
525 [LOG_FAC(LOG_FTP)] = "ftp",
526 [LOG_FAC(LOG_LOCAL0)] = "local0",
527 [LOG_FAC(LOG_LOCAL1)] = "local1",
528 [LOG_FAC(LOG_LOCAL2)] = "local2",
529 [LOG_FAC(LOG_LOCAL3)] = "local3",
530 [LOG_FAC(LOG_LOCAL4)] = "local4",
531 [LOG_FAC(LOG_LOCAL5)] = "local5",
532 [LOG_FAC(LOG_LOCAL6)] = "local6",
533 [LOG_FAC(LOG_LOCAL7)] = "local7"
534 };
535
536 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
537
538 bool log_facility_unshifted_is_valid(int facility) {
539 return facility >= 0 && facility <= LOG_FAC(~0);
540 }
541
542 static const char *const log_level_table[] = {
543 [LOG_EMERG] = "emerg",
544 [LOG_ALERT] = "alert",
545 [LOG_CRIT] = "crit",
546 [LOG_ERR] = "err",
547 [LOG_WARNING] = "warning",
548 [LOG_NOTICE] = "notice",
549 [LOG_INFO] = "info",
550 [LOG_DEBUG] = "debug"
551 };
552
553 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
554
555 bool log_level_is_valid(int level) {
556 return level >= 0 && level <= LOG_DEBUG;
557 }
558
559 static const char* const sched_policy_table[] = {
560 [SCHED_OTHER] = "other",
561 [SCHED_BATCH] = "batch",
562 [SCHED_IDLE] = "idle",
563 [SCHED_FIFO] = "fifo",
564 [SCHED_RR] = "rr"
565 };
566
567 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
568
569 bool kexec_loaded(void) {
570 bool loaded = false;
571 char *s;
572
573 if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
574 if (s[0] == '1')
575 loaded = true;
576 free(s);
577 }
578 return loaded;
579 }
580
581 int prot_from_flags(int flags) {
582
583 switch (flags & O_ACCMODE) {
584
585 case O_RDONLY:
586 return PROT_READ;
587
588 case O_WRONLY:
589 return PROT_WRITE;
590
591 case O_RDWR:
592 return PROT_READ|PROT_WRITE;
593
594 default:
595 return -EINVAL;
596 }
597 }
598
599 void* memdup(const void *p, size_t l) {
600 void *r;
601
602 assert(p);
603
604 r = malloc(l);
605 if (!r)
606 return NULL;
607
608 memcpy(r, p, l);
609 return r;
610 }
611
612 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
613 bool stdout_is_tty, stderr_is_tty;
614 pid_t parent_pid, agent_pid;
615 sigset_t ss, saved_ss;
616 unsigned n, i;
617 va_list ap;
618 char **l;
619
620 assert(pid);
621 assert(path);
622
623 /* Spawns a temporary TTY agent, making sure it goes away when
624 * we go away */
625
626 parent_pid = getpid();
627
628 /* First we temporarily block all signals, so that the new
629 * child has them blocked initially. This way, we can be sure
630 * that SIGTERMs are not lost we might send to the agent. */
631 assert_se(sigfillset(&ss) >= 0);
632 assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
633
634 agent_pid = fork();
635 if (agent_pid < 0) {
636 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
637 return -errno;
638 }
639
640 if (agent_pid != 0) {
641 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
642 *pid = agent_pid;
643 return 0;
644 }
645
646 /* In the child:
647 *
648 * Make sure the agent goes away when the parent dies */
649 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
650 _exit(EXIT_FAILURE);
651
652 /* Make sure we actually can kill the agent, if we need to, in
653 * case somebody invoked us from a shell script that trapped
654 * SIGTERM or so... */
655 (void) reset_all_signal_handlers();
656 (void) reset_signal_mask();
657
658 /* Check whether our parent died before we were able
659 * to set the death signal and unblock the signals */
660 if (getppid() != parent_pid)
661 _exit(EXIT_SUCCESS);
662
663 /* Don't leak fds to the agent */
664 close_all_fds(except, n_except);
665
666 stdout_is_tty = isatty(STDOUT_FILENO);
667 stderr_is_tty = isatty(STDERR_FILENO);
668
669 if (!stdout_is_tty || !stderr_is_tty) {
670 int fd;
671
672 /* Detach from stdout/stderr. and reopen
673 * /dev/tty for them. This is important to
674 * ensure that when systemctl is started via
675 * popen() or a similar call that expects to
676 * read EOF we actually do generate EOF and
677 * not delay this indefinitely by because we
678 * keep an unused copy of stdin around. */
679 fd = open("/dev/tty", O_WRONLY);
680 if (fd < 0) {
681 log_error_errno(errno, "Failed to open /dev/tty: %m");
682 _exit(EXIT_FAILURE);
683 }
684
685 if (!stdout_is_tty)
686 dup2(fd, STDOUT_FILENO);
687
688 if (!stderr_is_tty)
689 dup2(fd, STDERR_FILENO);
690
691 if (fd > 2)
692 close(fd);
693 }
694
695 /* Count arguments */
696 va_start(ap, path);
697 for (n = 0; va_arg(ap, char*); n++)
698 ;
699 va_end(ap);
700
701 /* Allocate strv */
702 l = alloca(sizeof(char *) * (n + 1));
703
704 /* Fill in arguments */
705 va_start(ap, path);
706 for (i = 0; i <= n; i++)
707 l[i] = va_arg(ap, char*);
708 va_end(ap);
709
710 execv(path, l);
711 _exit(EXIT_FAILURE);
712 }
713
714 bool http_etag_is_valid(const char *etag) {
715 if (isempty(etag))
716 return false;
717
718 if (!endswith(etag, "\""))
719 return false;
720
721 if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
722 return false;
723
724 return true;
725 }
726
727 bool http_url_is_valid(const char *url) {
728 const char *p;
729
730 if (isempty(url))
731 return false;
732
733 p = startswith(url, "http://");
734 if (!p)
735 p = startswith(url, "https://");
736 if (!p)
737 return false;
738
739 if (isempty(p))
740 return false;
741
742 return ascii_is_valid(p);
743 }
744
745 bool documentation_url_is_valid(const char *url) {
746 const char *p;
747
748 if (isempty(url))
749 return false;
750
751 if (http_url_is_valid(url))
752 return true;
753
754 p = startswith(url, "file:/");
755 if (!p)
756 p = startswith(url, "info:");
757 if (!p)
758 p = startswith(url, "man:");
759
760 if (isempty(p))
761 return false;
762
763 return ascii_is_valid(p);
764 }
765
766 bool in_initrd(void) {
767 static int saved = -1;
768 struct statfs s;
769
770 if (saved >= 0)
771 return saved;
772
773 /* We make two checks here:
774 *
775 * 1. the flag file /etc/initrd-release must exist
776 * 2. the root file system must be a memory file system
777 *
778 * The second check is extra paranoia, since misdetecting an
779 * initrd can have bad bad consequences due the initrd
780 * emptying when transititioning to the main systemd.
781 */
782
783 saved = access("/etc/initrd-release", F_OK) >= 0 &&
784 statfs("/", &s) >= 0 &&
785 is_temporary_fs(&s);
786
787 return saved;
788 }
789
790 /* hey glibc, APIs with callbacks without a user pointer are so useless */
791 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
792 int (*compar) (const void *, const void *, void *), void *arg) {
793 size_t l, u, idx;
794 const void *p;
795 int comparison;
796
797 l = 0;
798 u = nmemb;
799 while (l < u) {
800 idx = (l + u) / 2;
801 p = (void *)(((const char *) base) + (idx * size));
802 comparison = compar(key, p, arg);
803 if (comparison < 0)
804 u = idx;
805 else if (comparison > 0)
806 l = idx + 1;
807 else
808 return (void *)p;
809 }
810 return NULL;
811 }
812
813 void init_gettext(void) {
814 setlocale(LC_ALL, "");
815 textdomain(GETTEXT_PACKAGE);
816 }
817
818 bool is_locale_utf8(void) {
819 const char *set;
820 static int cached_answer = -1;
821
822 if (cached_answer >= 0)
823 goto out;
824
825 if (!setlocale(LC_ALL, "")) {
826 cached_answer = true;
827 goto out;
828 }
829
830 set = nl_langinfo(CODESET);
831 if (!set) {
832 cached_answer = true;
833 goto out;
834 }
835
836 if (streq(set, "UTF-8")) {
837 cached_answer = true;
838 goto out;
839 }
840
841 /* For LC_CTYPE=="C" return true, because CTYPE is effectly
842 * unset and everything can do to UTF-8 nowadays. */
843 set = setlocale(LC_CTYPE, NULL);
844 if (!set) {
845 cached_answer = true;
846 goto out;
847 }
848
849 /* Check result, but ignore the result if C was set
850 * explicitly. */
851 cached_answer =
852 STR_IN_SET(set, "C", "POSIX") &&
853 !getenv("LC_ALL") &&
854 !getenv("LC_CTYPE") &&
855 !getenv("LANG");
856
857 out:
858 return (bool) cached_answer;
859 }
860
861 const char *draw_special_char(DrawSpecialChar ch) {
862 static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
863
864 /* UTF-8 */ {
865 [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */
866 [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
867 [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
868 [DRAW_TREE_SPACE] = " ", /* */
869 [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
870 [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */
871 [DRAW_ARROW] = "\342\206\222", /* → */
872 [DRAW_DASH] = "\342\200\223", /* – */
873 },
874
875 /* ASCII fallback */ {
876 [DRAW_TREE_VERTICAL] = "| ",
877 [DRAW_TREE_BRANCH] = "|-",
878 [DRAW_TREE_RIGHT] = "`-",
879 [DRAW_TREE_SPACE] = " ",
880 [DRAW_TRIANGULAR_BULLET] = ">",
881 [DRAW_BLACK_CIRCLE] = "*",
882 [DRAW_ARROW] = "->",
883 [DRAW_DASH] = "-",
884 }
885 };
886
887 return draw_table[!is_locale_utf8()][ch];
888 }
889
890 int on_ac_power(void) {
891 bool found_offline = false, found_online = false;
892 _cleanup_closedir_ DIR *d = NULL;
893
894 d = opendir("/sys/class/power_supply");
895 if (!d)
896 return errno == ENOENT ? true : -errno;
897
898 for (;;) {
899 struct dirent *de;
900 _cleanup_close_ int fd = -1, device = -1;
901 char contents[6];
902 ssize_t n;
903
904 errno = 0;
905 de = readdir(d);
906 if (!de && errno != 0)
907 return -errno;
908
909 if (!de)
910 break;
911
912 if (hidden_file(de->d_name))
913 continue;
914
915 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
916 if (device < 0) {
917 if (errno == ENOENT || errno == ENOTDIR)
918 continue;
919
920 return -errno;
921 }
922
923 fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
924 if (fd < 0) {
925 if (errno == ENOENT)
926 continue;
927
928 return -errno;
929 }
930
931 n = read(fd, contents, sizeof(contents));
932 if (n < 0)
933 return -errno;
934
935 if (n != 6 || memcmp(contents, "Mains\n", 6))
936 continue;
937
938 safe_close(fd);
939 fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
940 if (fd < 0) {
941 if (errno == ENOENT)
942 continue;
943
944 return -errno;
945 }
946
947 n = read(fd, contents, sizeof(contents));
948 if (n < 0)
949 return -errno;
950
951 if (n != 2 || contents[1] != '\n')
952 return -EIO;
953
954 if (contents[0] == '1') {
955 found_online = true;
956 break;
957 } else if (contents[0] == '0')
958 found_offline = true;
959 else
960 return -EIO;
961 }
962
963 return found_online || !found_offline;
964 }
965
966 void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
967 size_t a, newalloc;
968 void *q;
969
970 assert(p);
971 assert(allocated);
972
973 if (*allocated >= need)
974 return *p;
975
976 newalloc = MAX(need * 2, 64u / size);
977 a = newalloc * size;
978
979 /* check for overflows */
980 if (a < size * need)
981 return NULL;
982
983 q = realloc(*p, a);
984 if (!q)
985 return NULL;
986
987 *p = q;
988 *allocated = newalloc;
989 return q;
990 }
991
992 void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
993 size_t prev;
994 uint8_t *q;
995
996 assert(p);
997 assert(allocated);
998
999 prev = *allocated;
1000
1001 q = greedy_realloc(p, allocated, need, size);
1002 if (!q)
1003 return NULL;
1004
1005 if (*allocated > prev)
1006 memzero(q + prev * size, (*allocated - prev) * size);
1007
1008 return q;
1009 }
1010
1011 bool id128_is_valid(const char *s) {
1012 size_t i, l;
1013
1014 l = strlen(s);
1015 if (l == 32) {
1016
1017 /* Simple formatted 128bit hex string */
1018
1019 for (i = 0; i < l; i++) {
1020 char c = s[i];
1021
1022 if (!(c >= '0' && c <= '9') &&
1023 !(c >= 'a' && c <= 'z') &&
1024 !(c >= 'A' && c <= 'Z'))
1025 return false;
1026 }
1027
1028 } else if (l == 36) {
1029
1030 /* Formatted UUID */
1031
1032 for (i = 0; i < l; i++) {
1033 char c = s[i];
1034
1035 if ((i == 8 || i == 13 || i == 18 || i == 23)) {
1036 if (c != '-')
1037 return false;
1038 } else {
1039 if (!(c >= '0' && c <= '9') &&
1040 !(c >= 'a' && c <= 'z') &&
1041 !(c >= 'A' && c <= 'Z'))
1042 return false;
1043 }
1044 }
1045
1046 } else
1047 return false;
1048
1049 return true;
1050 }
1051
1052 int shall_restore_state(void) {
1053 _cleanup_free_ char *value = NULL;
1054 int r;
1055
1056 r = get_proc_cmdline_key("systemd.restore_state=", &value);
1057 if (r < 0)
1058 return r;
1059 if (r == 0)
1060 return true;
1061
1062 return parse_boolean(value) != 0;
1063 }
1064
1065 int proc_cmdline(char **ret) {
1066 assert(ret);
1067
1068 if (detect_container() > 0)
1069 return get_process_cmdline(1, 0, false, ret);
1070 else
1071 return read_one_line_file("/proc/cmdline", ret);
1072 }
1073
1074 int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
1075 _cleanup_free_ char *line = NULL;
1076 const char *p;
1077 int r;
1078
1079 assert(parse_item);
1080
1081 r = proc_cmdline(&line);
1082 if (r < 0)
1083 return r;
1084
1085 p = line;
1086 for (;;) {
1087 _cleanup_free_ char *word = NULL;
1088 char *value = NULL;
1089
1090 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
1091 if (r < 0)
1092 return r;
1093 if (r == 0)
1094 break;
1095
1096 /* Filter out arguments that are intended only for the
1097 * initrd */
1098 if (!in_initrd() && startswith(word, "rd."))
1099 continue;
1100
1101 value = strchr(word, '=');
1102 if (value)
1103 *(value++) = 0;
1104
1105 r = parse_item(word, value);
1106 if (r < 0)
1107 return r;
1108 }
1109
1110 return 0;
1111 }
1112
1113 int get_proc_cmdline_key(const char *key, char **value) {
1114 _cleanup_free_ char *line = NULL, *ret = NULL;
1115 bool found = false;
1116 const char *p;
1117 int r;
1118
1119 assert(key);
1120
1121 r = proc_cmdline(&line);
1122 if (r < 0)
1123 return r;
1124
1125 p = line;
1126 for (;;) {
1127 _cleanup_free_ char *word = NULL;
1128 const char *e;
1129
1130 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
1131 if (r < 0)
1132 return r;
1133 if (r == 0)
1134 break;
1135
1136 /* Filter out arguments that are intended only for the
1137 * initrd */
1138 if (!in_initrd() && startswith(word, "rd."))
1139 continue;
1140
1141 if (value) {
1142 e = startswith(word, key);
1143 if (!e)
1144 continue;
1145
1146 r = free_and_strdup(&ret, e);
1147 if (r < 0)
1148 return r;
1149
1150 found = true;
1151 } else {
1152 if (streq(word, key))
1153 found = true;
1154 }
1155 }
1156
1157 if (value) {
1158 *value = ret;
1159 ret = NULL;
1160 }
1161
1162 return found;
1163
1164 }
1165
1166 int container_get_leader(const char *machine, pid_t *pid) {
1167 _cleanup_free_ char *s = NULL, *class = NULL;
1168 const char *p;
1169 pid_t leader;
1170 int r;
1171
1172 assert(machine);
1173 assert(pid);
1174
1175 if (!machine_name_is_valid(machine))
1176 return -EINVAL;
1177
1178 p = strjoina("/run/systemd/machines/", machine);
1179 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
1180 if (r == -ENOENT)
1181 return -EHOSTDOWN;
1182 if (r < 0)
1183 return r;
1184 if (!s)
1185 return -EIO;
1186
1187 if (!streq_ptr(class, "container"))
1188 return -EIO;
1189
1190 r = parse_pid(s, &leader);
1191 if (r < 0)
1192 return r;
1193 if (leader <= 1)
1194 return -EIO;
1195
1196 *pid = leader;
1197 return 0;
1198 }
1199
1200 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
1201 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
1202 int rfd = -1;
1203
1204 assert(pid >= 0);
1205
1206 if (mntns_fd) {
1207 const char *mntns;
1208
1209 mntns = procfs_file_alloca(pid, "ns/mnt");
1210 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1211 if (mntnsfd < 0)
1212 return -errno;
1213 }
1214
1215 if (pidns_fd) {
1216 const char *pidns;
1217
1218 pidns = procfs_file_alloca(pid, "ns/pid");
1219 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1220 if (pidnsfd < 0)
1221 return -errno;
1222 }
1223
1224 if (netns_fd) {
1225 const char *netns;
1226
1227 netns = procfs_file_alloca(pid, "ns/net");
1228 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1229 if (netnsfd < 0)
1230 return -errno;
1231 }
1232
1233 if (userns_fd) {
1234 const char *userns;
1235
1236 userns = procfs_file_alloca(pid, "ns/user");
1237 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1238 if (usernsfd < 0 && errno != ENOENT)
1239 return -errno;
1240 }
1241
1242 if (root_fd) {
1243 const char *root;
1244
1245 root = procfs_file_alloca(pid, "root");
1246 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1247 if (rfd < 0)
1248 return -errno;
1249 }
1250
1251 if (pidns_fd)
1252 *pidns_fd = pidnsfd;
1253
1254 if (mntns_fd)
1255 *mntns_fd = mntnsfd;
1256
1257 if (netns_fd)
1258 *netns_fd = netnsfd;
1259
1260 if (userns_fd)
1261 *userns_fd = usernsfd;
1262
1263 if (root_fd)
1264 *root_fd = rfd;
1265
1266 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
1267
1268 return 0;
1269 }
1270
1271 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
1272 if (userns_fd >= 0) {
1273 /* Can't setns to your own userns, since then you could
1274 * escalate from non-root to root in your own namespace, so
1275 * check if namespaces equal before attempting to enter. */
1276 _cleanup_free_ char *userns_fd_path = NULL;
1277 int r;
1278 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
1279 return -ENOMEM;
1280
1281 r = files_same(userns_fd_path, "/proc/self/ns/user");
1282 if (r < 0)
1283 return r;
1284 if (r)
1285 userns_fd = -1;
1286 }
1287
1288 if (pidns_fd >= 0)
1289 if (setns(pidns_fd, CLONE_NEWPID) < 0)
1290 return -errno;
1291
1292 if (mntns_fd >= 0)
1293 if (setns(mntns_fd, CLONE_NEWNS) < 0)
1294 return -errno;
1295
1296 if (netns_fd >= 0)
1297 if (setns(netns_fd, CLONE_NEWNET) < 0)
1298 return -errno;
1299
1300 if (userns_fd >= 0)
1301 if (setns(userns_fd, CLONE_NEWUSER) < 0)
1302 return -errno;
1303
1304 if (root_fd >= 0) {
1305 if (fchdir(root_fd) < 0)
1306 return -errno;
1307
1308 if (chroot(".") < 0)
1309 return -errno;
1310 }
1311
1312 return reset_uid_gid();
1313 }
1314
1315 unsigned long personality_from_string(const char *p) {
1316
1317 /* Parse a personality specifier. We introduce our own
1318 * identifiers that indicate specific ABIs, rather than just
1319 * hints regarding the register size, since we want to keep
1320 * things open for multiple locally supported ABIs for the
1321 * same register size. We try to reuse the ABI identifiers
1322 * used by libseccomp. */
1323
1324 #if defined(__x86_64__)
1325
1326 if (streq(p, "x86"))
1327 return PER_LINUX32;
1328
1329 if (streq(p, "x86-64"))
1330 return PER_LINUX;
1331
1332 #elif defined(__i386__)
1333
1334 if (streq(p, "x86"))
1335 return PER_LINUX;
1336
1337 #elif defined(__s390x__)
1338
1339 if (streq(p, "s390"))
1340 return PER_LINUX32;
1341
1342 if (streq(p, "s390x"))
1343 return PER_LINUX;
1344
1345 #elif defined(__s390__)
1346
1347 if (streq(p, "s390"))
1348 return PER_LINUX;
1349 #endif
1350
1351 return PERSONALITY_INVALID;
1352 }
1353
1354 const char* personality_to_string(unsigned long p) {
1355
1356 #if defined(__x86_64__)
1357
1358 if (p == PER_LINUX32)
1359 return "x86";
1360
1361 if (p == PER_LINUX)
1362 return "x86-64";
1363
1364 #elif defined(__i386__)
1365
1366 if (p == PER_LINUX)
1367 return "x86";
1368
1369 #elif defined(__s390x__)
1370
1371 if (p == PER_LINUX)
1372 return "s390x";
1373
1374 if (p == PER_LINUX32)
1375 return "s390";
1376
1377 #elif defined(__s390__)
1378
1379 if (p == PER_LINUX)
1380 return "s390";
1381
1382 #endif
1383
1384 return NULL;
1385 }
1386
1387 uint64_t physical_memory(void) {
1388 long mem;
1389
1390 /* We return this as uint64_t in case we are running as 32bit
1391 * process on a 64bit kernel with huge amounts of memory */
1392
1393 mem = sysconf(_SC_PHYS_PAGES);
1394 assert(mem > 0);
1395
1396 return (uint64_t) mem * (uint64_t) page_size();
1397 }
1398
1399 int update_reboot_param_file(const char *param) {
1400 int r = 0;
1401
1402 if (param) {
1403 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
1404 if (r < 0)
1405 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
1406 } else
1407 (void) unlink(REBOOT_PARAM_FILE);
1408
1409 return 0;
1410 }
1411
1412 int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
1413 int a = 0, b = 0, c = 0;
1414 int k;
1415
1416 assert(p);
1417 assert(*p);
1418 assert(priority);
1419
1420 if ((*p)[0] != '<')
1421 return 0;
1422
1423 if (!strchr(*p, '>'))
1424 return 0;
1425
1426 if ((*p)[2] == '>') {
1427 c = undecchar((*p)[1]);
1428 k = 3;
1429 } else if ((*p)[3] == '>') {
1430 b = undecchar((*p)[1]);
1431 c = undecchar((*p)[2]);
1432 k = 4;
1433 } else if ((*p)[4] == '>') {
1434 a = undecchar((*p)[1]);
1435 b = undecchar((*p)[2]);
1436 c = undecchar((*p)[3]);
1437 k = 5;
1438 } else
1439 return 0;
1440
1441 if (a < 0 || b < 0 || c < 0 ||
1442 (!with_facility && (a || b || c > 7)))
1443 return 0;
1444
1445 if (with_facility)
1446 *priority = a*100 + b*10 + c;
1447 else
1448 *priority = (*priority & LOG_FACMASK) | c;
1449
1450 *p += k;
1451 return 1;
1452 }
1453
1454 int version(void) {
1455 puts(PACKAGE_STRING "\n"
1456 SYSTEMD_FEATURES);
1457 return 0;
1458 }
1459
1460 bool fdname_is_valid(const char *s) {
1461 const char *p;
1462
1463 /* Validates a name for $LISTEN_FDNAMES. We basically allow
1464 * everything ASCII that's not a control character. Also, as
1465 * special exception the ":" character is not allowed, as we
1466 * use that as field separator in $LISTEN_FDNAMES.
1467 *
1468 * Note that the empty string is explicitly allowed
1469 * here. However, we limit the length of the names to 255
1470 * characters. */
1471
1472 if (!s)
1473 return false;
1474
1475 for (p = s; *p; p++) {
1476 if (*p < ' ')
1477 return false;
1478 if (*p >= 127)
1479 return false;
1480 if (*p == ':')
1481 return false;
1482 }
1483
1484 return p - s < 256;
1485 }
1486
1487 bool oom_score_adjust_is_valid(int oa) {
1488 return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
1489 }