1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
31 #include <linux/magic.h>
32 #include <linux/oom.h>
33 #include <linux/sched.h>
44 #include <sys/ioctl.h>
46 #include <sys/mount.h>
47 #include <sys/personality.h>
48 #include <sys/prctl.h>
50 #include <sys/statvfs.h>
52 #include <sys/types.h>
53 #include <sys/utsname.h>
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(). */
65 #ifdef HAVE_SYS_AUXV_H
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! */
75 #include "device-nodes.h"
78 #include "exit-status.h"
81 #include "formats-util.h"
84 #include "hostname-util.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"
100 #include "terminal-util.h"
101 #include "user-util.h"
105 #include "dirent-util.h"
106 #include "stat-util.h"
108 /* Put this test here for a lack of better place */
109 assert_cc(EAGAIN
== EWOULDBLOCK
);
112 char **saved_argv
= NULL
;
114 size_t page_size(void) {
115 static thread_local
size_t pgsz
= 0;
118 if (_likely_(pgsz
> 0))
121 r
= sysconf(_SC_PAGESIZE
);
128 bool fstype_is_network(const char *fstype
) {
129 static const char table
[] =
144 x
= startswith(fstype
, "fuse.");
148 return nulstr_contains(table
, fstype
);
151 void rename_process(const char name
[8]) {
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
162 prctl(PR_SET_NAME
, name
);
164 if (program_invocation_name
)
165 strncpy(program_invocation_name
, name
, strlen(program_invocation_name
));
167 if (saved_argc
> 0) {
171 strncpy(saved_argv
[0], name
, strlen(saved_argv
[0]));
173 for (i
= 1; i
< saved_argc
; i
++) {
177 memzero(saved_argv
[i
], strlen(saved_argv
[i
]));
182 noreturn
void freeze(void) {
184 /* Make sure nobody waits for us on a socket anymore */
185 close_all_fds(NULL
, 0);
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
;
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 */
201 (void) reset_all_signal_handlers();
202 (void) reset_signal_mask();
204 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
206 pids
= hashmap_new(NULL
);
210 seen
= set_new(&string_hash_ops
);
214 STRV_FOREACH(directory
, directories
) {
215 _cleanup_closedir_
DIR *d
;
218 d
= opendir(*directory
);
223 return log_error_errno(errno
, "Failed to open directory %s: %m", *directory
);
226 FOREACH_DIRENT(de
, d
, break) {
227 _cleanup_free_
char *path
= NULL
;
231 if (!dirent_is_file(de
))
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
);
239 r
= set_put_strdup(seen
, de
->d_name
);
243 path
= strjoin(*directory
, "/", de
->d_name
, NULL
);
247 if (null_or_empty_path(path
)) {
248 log_debug("%s is empty (a mask).", path
);
254 log_error_errno(errno
, "Failed to fork: %m");
256 } else if (pid
== 0) {
259 assert_se(prctl(PR_SET_PDEATHSIG
, SIGTERM
) == 0);
269 return log_error_errno(errno
, "Failed to execute %s: %m", path
);
272 log_debug("Spawned %s as " PID_FMT
".", path
, pid
);
274 r
= hashmap_put(pids
, UINT_TO_PTR(pid
), path
);
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(). */
285 if (timeout
!= USEC_INFINITY
)
286 alarm((timeout
+ USEC_PER_SEC
- 1) / USEC_PER_SEC
);
288 while (!hashmap_isempty(pids
)) {
289 _cleanup_free_
char *path
= NULL
;
292 pid
= PTR_TO_UINT(hashmap_first_key(pids
));
295 path
= hashmap_remove(pids
, UINT_TO_PTR(pid
));
298 wait_for_terminate_and_warn(path
, pid
, true);
304 void execute_directories(const char* const* directories
, usec_t timeout
, char *argv
[]) {
308 char **dirs
= (char**) directories
;
310 assert(!strv_isempty(dirs
));
312 name
= basename(dirs
[0]);
313 assert(!isempty(name
));
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. */
320 executor_pid
= fork();
321 if (executor_pid
< 0) {
322 log_error_errno(errno
, "Failed to fork: %m");
325 } else if (executor_pid
== 0) {
326 r
= do_execute(dirs
, timeout
, argv
);
327 _exit(r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
330 wait_for_terminate_and_warn(name
, executor_pid
, true);
333 bool plymouth_running(void) {
334 return access("/run/plymouth/pid", F_OK
) >= 0;
337 bool display_is_local(const char *display
) {
346 int socket_from_display(const char *display
, char **path
) {
353 if (!display_is_local(display
))
356 k
= strspn(display
+1, "0123456789");
358 f
= new(char, strlen("/tmp/.X11-unix/X") + k
+ 1);
362 c
= stpcpy(f
, "/tmp/.X11-unix/X");
363 memcpy(c
, display
+1, k
);
371 int glob_exists(const char *path
) {
372 _cleanup_globfree_ glob_t g
= {};
378 k
= glob(path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
);
380 if (k
== GLOB_NOMATCH
)
382 else if (k
== GLOB_NOSPACE
)
385 return !strv_isempty(g
.gl_pathv
);
387 return errno
? -errno
: -EIO
;
390 int glob_extend(char ***strv
, const char *path
) {
391 _cleanup_globfree_ glob_t g
= {};
396 k
= glob(path
, GLOB_NOSORT
|GLOB_BRACE
, NULL
, &g
);
398 if (k
== GLOB_NOMATCH
)
400 else if (k
== GLOB_NOSPACE
)
402 else if (k
!= 0 || strv_isempty(g
.gl_pathv
))
403 return errno
? -errno
: -EIO
;
405 STRV_FOREACH(p
, g
.gl_pathv
) {
406 k
= strv_extend(strv
, *p
);
414 int block_get_whole_disk(dev_t d
, dev_t
*ret
) {
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)
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)
443 /* Get parent dev_t */
444 if (asprintf(&p
, "/sys/dev/block/%u:%u/../dev", major(d
), minor(d
)) < 0)
447 r
= read_one_line_file(p
, &s
);
453 r
= sscanf(s
, "%u:%u", &m
, &n
);
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)
467 *ret
= makedev(m
, n
);
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"
481 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class
, int, INT_MAX
);
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",
492 DEFINE_STRING_TABLE_LOOKUP(sigchld_code
, int);
494 static const char *const log_facility_unshifted_table
[LOG_NFACILITIES
] = {
495 [LOG_FAC(LOG_KERN
)] = "kern",
496 [LOG_FAC(LOG_USER
)] = "user",
497 [LOG_FAC(LOG_MAIL
)] = "mail",
498 [LOG_FAC(LOG_DAEMON
)] = "daemon",
499 [LOG_FAC(LOG_AUTH
)] = "auth",
500 [LOG_FAC(LOG_SYSLOG
)] = "syslog",
501 [LOG_FAC(LOG_LPR
)] = "lpr",
502 [LOG_FAC(LOG_NEWS
)] = "news",
503 [LOG_FAC(LOG_UUCP
)] = "uucp",
504 [LOG_FAC(LOG_CRON
)] = "cron",
505 [LOG_FAC(LOG_AUTHPRIV
)] = "authpriv",
506 [LOG_FAC(LOG_FTP
)] = "ftp",
507 [LOG_FAC(LOG_LOCAL0
)] = "local0",
508 [LOG_FAC(LOG_LOCAL1
)] = "local1",
509 [LOG_FAC(LOG_LOCAL2
)] = "local2",
510 [LOG_FAC(LOG_LOCAL3
)] = "local3",
511 [LOG_FAC(LOG_LOCAL4
)] = "local4",
512 [LOG_FAC(LOG_LOCAL5
)] = "local5",
513 [LOG_FAC(LOG_LOCAL6
)] = "local6",
514 [LOG_FAC(LOG_LOCAL7
)] = "local7"
517 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted
, int, LOG_FAC(~0));
519 bool log_facility_unshifted_is_valid(int facility
) {
520 return facility
>= 0 && facility
<= LOG_FAC(~0);
523 static const char *const log_level_table
[] = {
524 [LOG_EMERG
] = "emerg",
525 [LOG_ALERT
] = "alert",
528 [LOG_WARNING
] = "warning",
529 [LOG_NOTICE
] = "notice",
531 [LOG_DEBUG
] = "debug"
534 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level
, int, LOG_DEBUG
);
536 bool log_level_is_valid(int level
) {
537 return level
>= 0 && level
<= LOG_DEBUG
;
540 static const char* const sched_policy_table
[] = {
541 [SCHED_OTHER
] = "other",
542 [SCHED_BATCH
] = "batch",
543 [SCHED_IDLE
] = "idle",
544 [SCHED_FIFO
] = "fifo",
548 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy
, int, INT_MAX
);
550 bool kexec_loaded(void) {
554 if (read_one_line_file("/sys/kernel/kexec_loaded", &s
) >= 0) {
562 int prot_from_flags(int flags
) {
564 switch (flags
& O_ACCMODE
) {
573 return PROT_READ
|PROT_WRITE
;
580 void* memdup(const void *p
, size_t l
) {
593 int fork_agent(pid_t
*pid
, const int except
[], unsigned n_except
, const char *path
, ...) {
594 bool stdout_is_tty
, stderr_is_tty
;
595 pid_t parent_pid
, agent_pid
;
596 sigset_t ss
, saved_ss
;
604 /* Spawns a temporary TTY agent, making sure it goes away when
607 parent_pid
= getpid();
609 /* First we temporarily block all signals, so that the new
610 * child has them blocked initially. This way, we can be sure
611 * that SIGTERMs are not lost we might send to the agent. */
612 assert_se(sigfillset(&ss
) >= 0);
613 assert_se(sigprocmask(SIG_SETMASK
, &ss
, &saved_ss
) >= 0);
617 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
621 if (agent_pid
!= 0) {
622 assert_se(sigprocmask(SIG_SETMASK
, &saved_ss
, NULL
) >= 0);
629 * Make sure the agent goes away when the parent dies */
630 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
633 /* Make sure we actually can kill the agent, if we need to, in
634 * case somebody invoked us from a shell script that trapped
635 * SIGTERM or so... */
636 (void) reset_all_signal_handlers();
637 (void) reset_signal_mask();
639 /* Check whether our parent died before we were able
640 * to set the death signal and unblock the signals */
641 if (getppid() != parent_pid
)
644 /* Don't leak fds to the agent */
645 close_all_fds(except
, n_except
);
647 stdout_is_tty
= isatty(STDOUT_FILENO
);
648 stderr_is_tty
= isatty(STDERR_FILENO
);
650 if (!stdout_is_tty
|| !stderr_is_tty
) {
653 /* Detach from stdout/stderr. and reopen
654 * /dev/tty for them. This is important to
655 * ensure that when systemctl is started via
656 * popen() or a similar call that expects to
657 * read EOF we actually do generate EOF and
658 * not delay this indefinitely by because we
659 * keep an unused copy of stdin around. */
660 fd
= open("/dev/tty", O_WRONLY
);
662 log_error_errno(errno
, "Failed to open /dev/tty: %m");
667 dup2(fd
, STDOUT_FILENO
);
670 dup2(fd
, STDERR_FILENO
);
676 /* Count arguments */
678 for (n
= 0; va_arg(ap
, char*); n
++)
683 l
= alloca(sizeof(char *) * (n
+ 1));
685 /* Fill in arguments */
687 for (i
= 0; i
<= n
; i
++)
688 l
[i
] = va_arg(ap
, char*);
695 bool http_etag_is_valid(const char *etag
) {
699 if (!endswith(etag
, "\""))
702 if (!startswith(etag
, "\"") && !startswith(etag
, "W/\""))
708 bool http_url_is_valid(const char *url
) {
714 p
= startswith(url
, "http://");
716 p
= startswith(url
, "https://");
723 return ascii_is_valid(p
);
726 bool documentation_url_is_valid(const char *url
) {
732 if (http_url_is_valid(url
))
735 p
= startswith(url
, "file:/");
737 p
= startswith(url
, "info:");
739 p
= startswith(url
, "man:");
744 return ascii_is_valid(p
);
747 bool in_initrd(void) {
748 static int saved
= -1;
754 /* We make two checks here:
756 * 1. the flag file /etc/initrd-release must exist
757 * 2. the root file system must be a memory file system
759 * The second check is extra paranoia, since misdetecting an
760 * initrd can have bad bad consequences due the initrd
761 * emptying when transititioning to the main systemd.
764 saved
= access("/etc/initrd-release", F_OK
) >= 0 &&
765 statfs("/", &s
) >= 0 &&
771 /* hey glibc, APIs with callbacks without a user pointer are so useless */
772 void *xbsearch_r(const void *key
, const void *base
, size_t nmemb
, size_t size
,
773 int (*compar
) (const void *, const void *, void *), void *arg
) {
782 p
= (void *)(((const char *) base
) + (idx
* size
));
783 comparison
= compar(key
, p
, arg
);
786 else if (comparison
> 0)
794 int on_ac_power(void) {
795 bool found_offline
= false, found_online
= false;
796 _cleanup_closedir_
DIR *d
= NULL
;
798 d
= opendir("/sys/class/power_supply");
800 return errno
== ENOENT
? true : -errno
;
804 _cleanup_close_
int fd
= -1, device
= -1;
810 if (!de
&& errno
!= 0)
816 if (hidden_file(de
->d_name
))
819 device
= openat(dirfd(d
), de
->d_name
, O_DIRECTORY
|O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
821 if (errno
== ENOENT
|| errno
== ENOTDIR
)
827 fd
= openat(device
, "type", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
835 n
= read(fd
, contents
, sizeof(contents
));
839 if (n
!= 6 || memcmp(contents
, "Mains\n", 6))
843 fd
= openat(device
, "online", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
851 n
= read(fd
, contents
, sizeof(contents
));
855 if (n
!= 2 || contents
[1] != '\n')
858 if (contents
[0] == '1') {
861 } else if (contents
[0] == '0')
862 found_offline
= true;
867 return found_online
|| !found_offline
;
870 void* greedy_realloc(void **p
, size_t *allocated
, size_t need
, size_t size
) {
877 if (*allocated
>= need
)
880 newalloc
= MAX(need
* 2, 64u / size
);
883 /* check for overflows */
892 *allocated
= newalloc
;
896 void* greedy_realloc0(void **p
, size_t *allocated
, size_t need
, size_t size
) {
905 q
= greedy_realloc(p
, allocated
, need
, size
);
909 if (*allocated
> prev
)
910 memzero(q
+ prev
* size
, (*allocated
- prev
) * size
);
915 bool id128_is_valid(const char *s
) {
921 /* Simple formatted 128bit hex string */
923 for (i
= 0; i
< l
; i
++) {
926 if (!(c
>= '0' && c
<= '9') &&
927 !(c
>= 'a' && c
<= 'z') &&
928 !(c
>= 'A' && c
<= 'Z'))
932 } else if (l
== 36) {
936 for (i
= 0; i
< l
; i
++) {
939 if ((i
== 8 || i
== 13 || i
== 18 || i
== 23)) {
943 if (!(c
>= '0' && c
<= '9') &&
944 !(c
>= 'a' && c
<= 'z') &&
945 !(c
>= 'A' && c
<= 'Z'))
956 int container_get_leader(const char *machine
, pid_t
*pid
) {
957 _cleanup_free_
char *s
= NULL
, *class = NULL
;
965 if (!machine_name_is_valid(machine
))
968 p
= strjoina("/run/systemd/machines/", machine
);
969 r
= parse_env_file(p
, NEWLINE
, "LEADER", &s
, "CLASS", &class, NULL
);
977 if (!streq_ptr(class, "container"))
980 r
= parse_pid(s
, &leader
);
990 int namespace_open(pid_t pid
, int *pidns_fd
, int *mntns_fd
, int *netns_fd
, int *userns_fd
, int *root_fd
) {
991 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, netnsfd
= -1, usernsfd
= -1;
999 mntns
= procfs_file_alloca(pid
, "ns/mnt");
1000 mntnsfd
= open(mntns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1008 pidns
= procfs_file_alloca(pid
, "ns/pid");
1009 pidnsfd
= open(pidns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1017 netns
= procfs_file_alloca(pid
, "ns/net");
1018 netnsfd
= open(netns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1026 userns
= procfs_file_alloca(pid
, "ns/user");
1027 usernsfd
= open(userns
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1028 if (usernsfd
< 0 && errno
!= ENOENT
)
1035 root
= procfs_file_alloca(pid
, "root");
1036 rfd
= open(root
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
|O_DIRECTORY
);
1042 *pidns_fd
= pidnsfd
;
1045 *mntns_fd
= mntnsfd
;
1048 *netns_fd
= netnsfd
;
1051 *userns_fd
= usernsfd
;
1056 pidnsfd
= mntnsfd
= netnsfd
= usernsfd
= -1;
1061 int namespace_enter(int pidns_fd
, int mntns_fd
, int netns_fd
, int userns_fd
, int root_fd
) {
1062 if (userns_fd
>= 0) {
1063 /* Can't setns to your own userns, since then you could
1064 * escalate from non-root to root in your own namespace, so
1065 * check if namespaces equal before attempting to enter. */
1066 _cleanup_free_
char *userns_fd_path
= NULL
;
1068 if (asprintf(&userns_fd_path
, "/proc/self/fd/%d", userns_fd
) < 0)
1071 r
= files_same(userns_fd_path
, "/proc/self/ns/user");
1079 if (setns(pidns_fd
, CLONE_NEWPID
) < 0)
1083 if (setns(mntns_fd
, CLONE_NEWNS
) < 0)
1087 if (setns(netns_fd
, CLONE_NEWNET
) < 0)
1091 if (setns(userns_fd
, CLONE_NEWUSER
) < 0)
1095 if (fchdir(root_fd
) < 0)
1098 if (chroot(".") < 0)
1102 return reset_uid_gid();
1105 unsigned long personality_from_string(const char *p
) {
1107 /* Parse a personality specifier. We introduce our own
1108 * identifiers that indicate specific ABIs, rather than just
1109 * hints regarding the register size, since we want to keep
1110 * things open for multiple locally supported ABIs for the
1111 * same register size. We try to reuse the ABI identifiers
1112 * used by libseccomp. */
1114 #if defined(__x86_64__)
1116 if (streq(p
, "x86"))
1119 if (streq(p
, "x86-64"))
1122 #elif defined(__i386__)
1124 if (streq(p
, "x86"))
1127 #elif defined(__s390x__)
1129 if (streq(p
, "s390"))
1132 if (streq(p
, "s390x"))
1135 #elif defined(__s390__)
1137 if (streq(p
, "s390"))
1141 return PERSONALITY_INVALID
;
1144 const char* personality_to_string(unsigned long p
) {
1146 #if defined(__x86_64__)
1148 if (p
== PER_LINUX32
)
1154 #elif defined(__i386__)
1159 #elif defined(__s390x__)
1164 if (p
== PER_LINUX32
)
1167 #elif defined(__s390__)
1177 uint64_t physical_memory(void) {
1180 /* We return this as uint64_t in case we are running as 32bit
1181 * process on a 64bit kernel with huge amounts of memory */
1183 mem
= sysconf(_SC_PHYS_PAGES
);
1186 return (uint64_t) mem
* (uint64_t) page_size();
1189 int update_reboot_param_file(const char *param
) {
1193 r
= write_string_file(REBOOT_PARAM_FILE
, param
, WRITE_STRING_FILE_CREATE
);
1195 return log_error_errno(r
, "Failed to write reboot param to "REBOOT_PARAM_FILE
": %m");
1197 (void) unlink(REBOOT_PARAM_FILE
);
1202 int syslog_parse_priority(const char **p
, int *priority
, bool with_facility
) {
1203 int a
= 0, b
= 0, c
= 0;
1213 if (!strchr(*p
, '>'))
1216 if ((*p
)[2] == '>') {
1217 c
= undecchar((*p
)[1]);
1219 } else if ((*p
)[3] == '>') {
1220 b
= undecchar((*p
)[1]);
1221 c
= undecchar((*p
)[2]);
1223 } else if ((*p
)[4] == '>') {
1224 a
= undecchar((*p
)[1]);
1225 b
= undecchar((*p
)[2]);
1226 c
= undecchar((*p
)[3]);
1231 if (a
< 0 || b
< 0 || c
< 0 ||
1232 (!with_facility
&& (a
|| b
|| c
> 7)))
1236 *priority
= a
*100 + b
*10 + c
;
1238 *priority
= (*priority
& LOG_FACMASK
) | c
;
1245 puts(PACKAGE_STRING
"\n"
1250 bool fdname_is_valid(const char *s
) {
1253 /* Validates a name for $LISTEN_FDNAMES. We basically allow
1254 * everything ASCII that's not a control character. Also, as
1255 * special exception the ":" character is not allowed, as we
1256 * use that as field separator in $LISTEN_FDNAMES.
1258 * Note that the empty string is explicitly allowed
1259 * here. However, we limit the length of the names to 255
1265 for (p
= s
; *p
; p
++) {
1277 bool oom_score_adjust_is_valid(int oa
) {
1278 return oa
>= OOM_SCORE_ADJ_MIN
&& oa
<= OOM_SCORE_ADJ_MAX
;