]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/util.c
util-lib: split out syslog-related calls into syslog-util.[ch]
[thirdparty/systemd.git] / src / basic / util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
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
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
f6c2284a
LP
22#include <ctype.h>
23#include <dirent.h>
60918275 24#include <errno.h>
f6c2284a
LP
25#include <fcntl.h>
26#include <glob.h>
27#include <grp.h>
28#include <langinfo.h>
20f56fdd 29#include <libintl.h>
f6c2284a
LP
30#include <limits.h>
31#include <linux/magic.h>
257b0719 32#include <linux/oom.h>
ef886c6a 33#include <linux/sched.h>
f6c2284a 34#include <locale.h>
0a6f50c0 35#include <poll.h>
ef2f1067 36#include <pwd.h>
f6c2284a
LP
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>
87d2c1ff 45#include <sys/mman.h>
6d313367 46#include <sys/mount.h>
6afc95b7 47#include <sys/personality.h>
f6c2284a 48#include <sys/prctl.h>
f6c2284a 49#include <sys/stat.h>
abe4aa14 50#include <sys/statvfs.h>
f6c2284a
LP
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>
f6c2284a
LP
56#include <syslog.h>
57#include <unistd.h>
eef46c37
LP
58
59/* When we include libgen.h because we need dirname() we immediately
f6c2284a
LP
60 * undefine basename() since libgen.h defines it as a macro to the
61 * POSIX version which is really broken. We prefer GNU basename(). */
eef46c37 62#include <libgen.h>
2b6bf07d 63#undef basename
60918275 64
9bf3b535
LP
65#ifdef HAVE_SYS_AUXV_H
66#include <sys/auxv.h>
67#endif
68
f6c2284a
LP
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
3f6fd1ba 73#include "build.h"
f6c2284a
LP
74#include "def.h"
75#include "device-nodes.h"
76#include "env-util.h"
4f5dd394 77#include "escape.h"
f6c2284a 78#include "exit-status.h"
3ffd4af2 79#include "fd-util.h"
f6c2284a
LP
80#include "fileio.h"
81#include "formats-util.h"
82#include "gunicode.h"
83#include "hashmap.h"
84#include "hostname-util.h"
1dccbe19 85#include "ioprio.h"
a9f5d454 86#include "log.h"
f6c2284a
LP
87#include "macro.h"
88#include "missing.h"
c38dfac9 89#include "mkdir.h"
e4e73a63 90#include "hexdecoct.h"
6bedfcbb 91#include "parse-util.h"
9eb977db 92#include "path-util.h"
0b452006 93#include "process-util.h"
3df3e884 94#include "random-util.h"
24882e06 95#include "signal-util.h"
f6c2284a 96#include "sparse-endian.h"
8b43440b 97#include "string-table.h"
07630cea 98#include "string-util.h"
f6c2284a
LP
99#include "strv.h"
100#include "terminal-util.h"
b1d4f8e1 101#include "user-util.h"
f6c2284a 102#include "utf8.h"
4f5dd394 103#include "util.h"
3ffd4af2 104#include "virt.h"
a0956174 105#include "dirent-util.h"
8fcde012 106#include "stat-util.h"
56cf987f 107
012d7b42
ZJS
108/* Put this test here for a lack of better place */
109assert_cc(EAGAIN == EWOULDBLOCK);
110
9a0e6896
LP
111int saved_argc = 0;
112char **saved_argv = NULL;
9086e840 113
37f85e66 114size_t page_size(void) {
ec202eae 115 static thread_local size_t pgsz = 0;
37f85e66 116 long r;
117
87d2c1ff 118 if (_likely_(pgsz > 0))
37f85e66 119 return pgsz;
120
e67f47e5
LP
121 r = sysconf(_SC_PAGESIZE);
122 assert(r > 0);
37f85e66 123
124 pgsz = (size_t) r;
37f85e66 125 return pgsz;
126}
127
42856c10 128bool fstype_is_network(const char *fstype) {
a05f97b3 129 static const char table[] =
ba89821c 130 "afs\0"
a05f97b3
LP
131 "cifs\0"
132 "smbfs\0"
da92ca5e 133 "sshfs\0"
a05f97b3 134 "ncpfs\0"
dac70dc7 135 "ncp\0"
a05f97b3
LP
136 "nfs\0"
137 "nfs4\0"
138 "gfs\0"
67608cad
LP
139 "gfs2\0"
140 "glusterfs\0";
141
142 const char *x;
143
144 x = startswith(fstype, "fuse.");
145 if (x)
146 fstype = x;
42856c10 147
a05f97b3 148 return nulstr_contains(table, fstype);
42856c10
LP
149}
150
5b6319dc
LP
151void rename_process(const char name[8]) {
152 assert(name);
153
5d6b1584
LP
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 */
5b6319dc 161
5d6b1584 162 prctl(PR_SET_NAME, name);
5b6319dc
LP
163
164 if (program_invocation_name)
165 strncpy(program_invocation_name, name, strlen(program_invocation_name));
9a0e6896
LP
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
29804cc1 177 memzero(saved_argv[i], strlen(saved_argv[i]));
9a0e6896
LP
178 }
179 }
5b6319dc
LP
180}
181
919ce0b7 182noreturn void freeze(void) {
720ce21d
LP
183
184 /* Make sure nobody waits for us on a socket anymore */
185 close_all_fds(NULL, 0);
186
c29597a1
LP
187 sync();
188
3c14d26c
LP
189 for (;;)
190 pause();
191}
192
e801700e 193static int do_execute(char **directories, usec_t timeout, char *argv[]) {
49681057 194 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
e801700e
ZJS
195 _cleanup_set_free_free_ Set *seen = NULL;
196 char **directory;
83cc030f 197
49681057
ZJS
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 */
83cc030f 200
ce30c8dc
LP
201 (void) reset_all_signal_handlers();
202 (void) reset_signal_mask();
83cc030f 203
49681057 204 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 205
49681057
ZJS
206 pids = hashmap_new(NULL);
207 if (!pids)
208 return log_oom();
83cc030f 209
e801700e
ZJS
210 seen = set_new(&string_hash_ops);
211 if (!seen)
212 return log_oom();
83cc030f 213
e801700e
ZJS
214 STRV_FOREACH(directory, directories) {
215 _cleanup_closedir_ DIR *d;
216 struct dirent *de;
83cc030f 217
e801700e
ZJS
218 d = opendir(*directory);
219 if (!d) {
220 if (errno == ENOENT)
221 continue;
83cc030f 222
e801700e
ZJS
223 return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
224 }
83cc030f 225
e801700e
ZJS
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;
83cc030f 233
e801700e
ZJS
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;
7034e9db 250 }
83cc030f 251
e801700e
ZJS
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];
83cc030f 258
e801700e 259 assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
83cc030f 260
e801700e
ZJS
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);
83cc030f 273
e801700e
ZJS
274 r = hashmap_put(pids, UINT_TO_PTR(pid), path);
275 if (r < 0)
276 return log_oom();
277 path = NULL;
278 }
49681057 279 }
83cc030f 280
49681057
ZJS
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(). */
83cc030f 284
49681057
ZJS
285 if (timeout != USEC_INFINITY)
286 alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
83cc030f 287
49681057
ZJS
288 while (!hashmap_isempty(pids)) {
289 _cleanup_free_ char *path = NULL;
290 pid_t pid;
aa62a893 291
49681057
ZJS
292 pid = PTR_TO_UINT(hashmap_first_key(pids));
293 assert(pid > 0);
83cc030f 294
49681057
ZJS
295 path = hashmap_remove(pids, UINT_TO_PTR(pid));
296 assert(path);
aa62a893 297
49681057
ZJS
298 wait_for_terminate_and_warn(path, pid, true);
299 }
aa62a893 300
49681057
ZJS
301 return 0;
302}
aa62a893 303
e801700e 304void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
49681057
ZJS
305 pid_t executor_pid;
306 int r;
e801700e
ZJS
307 char *name;
308 char **dirs = (char**) directories;
309
310 assert(!strv_isempty(dirs));
83cc030f 311
e801700e
ZJS
312 name = basename(dirs[0]);
313 assert(!isempty(name));
aa62a893 314
e801700e
ZJS
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. */
83cc030f 319
49681057
ZJS
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) {
e801700e 326 r = do_execute(dirs, timeout, argv);
49681057 327 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
aa62a893 328 }
83cc030f 329
e801700e 330 wait_for_terminate_and_warn(name, executor_pid, true);
83cc030f
LP
331}
332
a88c8750
TG
333bool plymouth_running(void) {
334 return access("/run/plymouth/pid", F_OK) >= 0;
335}
336
4d6d6518
LP
337bool 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
346int 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
f8294e41 358 f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
4d6d6518
LP
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
8092a428 371int glob_exists(const char *path) {
7fd1b19b 372 _cleanup_globfree_ glob_t g = {};
8d98da3f 373 int k;
8092a428
LP
374
375 assert(path);
376
8092a428
LP
377 errno = 0;
378 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
379
380 if (k == GLOB_NOMATCH)
8d98da3f 381 return 0;
8092a428 382 else if (k == GLOB_NOSPACE)
8d98da3f 383 return -ENOMEM;
8092a428 384 else if (k == 0)
8d98da3f 385 return !strv_isempty(g.gl_pathv);
8092a428 386 else
8d98da3f
ZJS
387 return errno ? -errno : -EIO;
388}
8092a428 389
8d98da3f
ZJS
390int glob_extend(char ***strv, const char *path) {
391 _cleanup_globfree_ glob_t g = {};
392 int k;
393 char **p;
394
395 errno = 0;
a8ccacf5 396 k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
8d98da3f
ZJS
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;
8092a428
LP
412}
413
94959f0f
LP
414int 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
f41607a6
LP
474static 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
f8b69d1d 481DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
f41607a6
LP
482
483static 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
492DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
493
f41607a6
LP
494static 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
f8b69d1d 502DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
f41607a6 503
65457142
FC
504bool 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}
fb9de93d 515
87d2c1ff
LP
516int 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 }
7c99e0c1 532}
689b9a22 533
55d7bfc1
LP
534void* 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}
bb99a35a 546
9bdc770c 547int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
6bb92a16 548 bool stdout_is_tty, stderr_is_tty;
8a7c93d8
LP
549 pid_t parent_pid, agent_pid;
550 sigset_t ss, saved_ss;
6bb92a16
LP
551 unsigned n, i;
552 va_list ap;
553 char **l;
554
555 assert(pid);
556 assert(path);
557
6bb92a16
LP
558 /* Spawns a temporary TTY agent, making sure it goes away when
559 * we go away */
560
8a7c93d8
LP
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
6bb92a16 569 agent_pid = fork();
8a7c93d8
LP
570 if (agent_pid < 0) {
571 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16 572 return -errno;
8a7c93d8 573 }
6bb92a16
LP
574
575 if (agent_pid != 0) {
8a7c93d8 576 assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
6bb92a16
LP
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
8a7c93d8
LP
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... */
ce30c8dc
LP
590 (void) reset_all_signal_handlers();
591 (void) reset_signal_mask();
8a7c93d8 592
6bb92a16 593 /* Check whether our parent died before we were able
8a7c93d8 594 * to set the death signal and unblock the signals */
6bb92a16
LP
595 if (getppid() != parent_pid)
596 _exit(EXIT_SUCCESS);
597
598 /* Don't leak fds to the agent */
9bdc770c 599 close_all_fds(except, n_except);
6bb92a16
LP
600
601 stdout_is_tty = isatty(STDOUT_FILENO);
602 stderr_is_tty = isatty(STDERR_FILENO);
603
604 if (!stdout_is_tty || !stderr_is_tty) {
8a7c93d8
LP
605 int fd;
606
6bb92a16
LP
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) {
56f64d95 616 log_error_errno(errno, "Failed to open /dev/tty: %m");
6bb92a16
LP
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}
68faf98c 648
3d7415f4
LP
649bool 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
a2e03378
LP
662bool http_url_is_valid(const char *url) {
663 const char *p;
49dbfa7b 664
a2e03378
LP
665 if (isempty(url))
666 return false;
49dbfa7b 667
a2e03378
LP
668 p = startswith(url, "http://");
669 if (!p)
670 p = startswith(url, "https://");
671 if (!p)
672 return false;
49dbfa7b 673
a2e03378
LP
674 if (isempty(p))
675 return false;
49dbfa7b 676
a2e03378
LP
677 return ascii_is_valid(p);
678}
49dbfa7b 679
a2e03378
LP
680bool 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))
49dbfa7b
LP
687 return true;
688
a2e03378
LP
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);
49dbfa7b 699}
9be346c9
HH
700
701bool in_initrd(void) {
73020ab2 702 static int saved = -1;
825c6fe5 703 struct statfs s;
8f33b5b8 704
825c6fe5
LP
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 &&
943aad8c 720 is_temporary_fs(&s);
9be346c9 721
8f33b5b8 722 return saved;
9be346c9 723}
069cfc85 724
a9e12476
KS
725/* hey glibc, APIs with callbacks without a user pointer are so useless */
726void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
1c574591 727 int (*compar) (const void *, const void *, void *), void *arg) {
a9e12476
KS
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}
09017585 747
240dbaa4
LP
748int 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)
6d890034 754 return errno == ENOENT ? true : -errno;
240dbaa4
LP
755
756 for (;;) {
757 struct dirent *de;
240dbaa4
LP
758 _cleanup_close_ int fd = -1, device = -1;
759 char contents[6];
760 ssize_t n;
240dbaa4 761
3fd11280
FW
762 errno = 0;
763 de = readdir(d);
764 if (!de && errno != 0)
765 return -errno;
240dbaa4
LP
766
767 if (!de)
768 break;
769
a34bf9db 770 if (hidden_file(de->d_name))
240dbaa4
LP
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
03e334a1 796 safe_close(fd);
240dbaa4
LP
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}
fabe5c0e 823
ca2d3784
ZJS
824void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
825 size_t a, newalloc;
392d5b37
LP
826 void *q;
827
98088803 828 assert(p);
e93c33d4
SL
829 assert(allocated);
830
392d5b37
LP
831 if (*allocated >= need)
832 return *p;
833
ca2d3784
ZJS
834 newalloc = MAX(need * 2, 64u / size);
835 a = newalloc * size;
98088803
LP
836
837 /* check for overflows */
ca2d3784 838 if (a < size * need)
98088803
LP
839 return NULL;
840
392d5b37
LP
841 q = realloc(*p, a);
842 if (!q)
843 return NULL;
844
845 *p = q;
ca2d3784 846 *allocated = newalloc;
392d5b37
LP
847 return q;
848}
aa96c6cb 849
ca2d3784 850void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
98088803 851 size_t prev;
4545a231
DH
852 uint8_t *q;
853
98088803
LP
854 assert(p);
855 assert(allocated);
856
857 prev = *allocated;
858
ca2d3784 859 q = greedy_realloc(p, allocated, need, size);
4545a231
DH
860 if (!q)
861 return NULL;
862
863 if (*allocated > prev)
ca2d3784 864 memzero(q + prev * size, (*allocated - prev) * size);
4545a231
DH
865
866 return q;
867}
868
aa96c6cb
LP
869bool 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}
7085053a 909
bc9fd78c
LP
910int 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
b9a8d250
LP
919 if (!machine_name_is_valid(machine))
920 return -EINVAL;
921
63c372cb 922 p = strjoina("/run/systemd/machines/", machine);
bc9fd78c
LP
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
671c3419
RM
944int 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;
359a06aa 946 int rfd = -1;
bc9fd78c
LP
947
948 assert(pid >= 0);
bc9fd78c 949
878cd7e9
LP
950 if (mntns_fd) {
951 const char *mntns;
a4475f57 952
878cd7e9
LP
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 }
bc9fd78c 958
878cd7e9
LP
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
671c3419
RM
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
878cd7e9
LP
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;
bc9fd78c 997
878cd7e9
LP
998 if (mntns_fd)
999 *mntns_fd = mntnsfd;
1000
1001 if (netns_fd)
1002 *netns_fd = netnsfd;
1003
671c3419
RM
1004 if (userns_fd)
1005 *userns_fd = usernsfd;
1006
878cd7e9
LP
1007 if (root_fd)
1008 *root_fd = rfd;
1009
671c3419 1010 pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
bc9fd78c
LP
1011
1012 return 0;
1013}
1014
671c3419
RM
1015int 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 }
bc9fd78c 1031
878cd7e9
LP
1032 if (pidns_fd >= 0)
1033 if (setns(pidns_fd, CLONE_NEWPID) < 0)
1034 return -errno;
a4475f57 1035
878cd7e9
LP
1036 if (mntns_fd >= 0)
1037 if (setns(mntns_fd, CLONE_NEWNS) < 0)
1038 return -errno;
bc9fd78c 1039
878cd7e9
LP
1040 if (netns_fd >= 0)
1041 if (setns(netns_fd, CLONE_NEWNET) < 0)
1042 return -errno;
bc9fd78c 1043
671c3419
RM
1044 if (userns_fd >= 0)
1045 if (setns(userns_fd, CLONE_NEWUSER) < 0)
1046 return -errno;
1047
878cd7e9
LP
1048 if (root_fd >= 0) {
1049 if (fchdir(root_fd) < 0)
1050 return -errno;
1051
1052 if (chroot(".") < 0)
1053 return -errno;
1054 }
bc9fd78c 1055
b4da6d6b 1056 return reset_uid_gid();
bc9fd78c 1057}
bf108e55 1058
ac45f971 1059unsigned long personality_from_string(const char *p) {
6afc95b7
LP
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;
7517f51e
HB
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;
6afc95b7
LP
1093#endif
1094
050f7277 1095 return PERSONALITY_INVALID;
6afc95b7 1096}
ac45f971
LP
1097
1098const 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";
7517f51e
HB
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
ac45f971
LP
1126#endif
1127
1128 return NULL;
1129}
1c231f56
LP
1130
1131uint64_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}
6db615c1 1142
966bff26 1143int update_reboot_param_file(const char *param) {
c5220a94
MO
1144 int r = 0;
1145
1146 if (param) {
4c1fc3e4 1147 r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
c5220a94 1148 if (r < 0)
e53fc357 1149 return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
c5220a94 1150 } else
e53fc357 1151 (void) unlink(REBOOT_PARAM_FILE);
c5220a94 1152
e53fc357 1153 return 0;
c5220a94 1154}
6d313367 1155
3f6fd1ba
LP
1156int version(void) {
1157 puts(PACKAGE_STRING "\n"
1158 SYSTEMD_FEATURES);
1159 return 0;
1160}
8dd4c05b
LP
1161
1162bool fdname_is_valid(const char *s) {
1163 const char *p;
1164
0a3bb96e 1165 /* Validates a name for $LISTEN_FDNAMES. We basically allow
8dd4c05b
LP
1166 * everything ASCII that's not a control character. Also, as
1167 * special exception the ":" character is not allowed, as we
0a3bb96e 1168 * use that as field separator in $LISTEN_FDNAMES.
8dd4c05b 1169 *
0a3bb96e
LP
1170 * Note that the empty string is explicitly allowed
1171 * here. However, we limit the length of the names to 255
1172 * characters. */
8dd4c05b
LP
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}
257b0719
EV
1188
1189bool oom_score_adjust_is_valid(int oa) {
1190 return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
1191}