X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=4eb1d27069a59ce0dfe99b4d490dd3c2503ca1be;hb=52306a952075183d4bdb20d9dc446cf26ef3deac;hp=d3dacfcfb5300b0d55eb439273c277f2f7c0f0a5;hpb=6ec9b87c4ecf5144b5ea845a53a352dd9f2d173a;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index d3dacfcfb..4eb1d2706 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -92,6 +92,8 @@ #include "process-util.h" #include "random-util.h" #include "terminal-util.h" +#include "hostname-util.h" +#include "signal-util.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -571,13 +573,12 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo char quotechars[2] = {*current, '\0'}; *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || + if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || (current[*l + 2] && !strchr(separator, current[*l + 2]))) { /* right quote missing or garbage at the end */ *state = current; return NULL; } - assert(current[*l + 1] == quotechars[0]); *state = current++ + *l + 2; } else if (quoted) { *l = strcspn_escaped(current, separator); @@ -750,41 +751,6 @@ int readlink_and_canonicalize(const char *p, char **r) { return 0; } -int reset_all_signal_handlers(void) { - int sig, r = 0; - - for (sig = 1; sig < _NSIG; sig++) { - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - - /* These two cannot be caught... */ - if (sig == SIGKILL || sig == SIGSTOP) - continue; - - /* On Linux the first two RT signals are reserved by - * glibc, and sigaction() will return EINVAL for them. */ - if ((sigaction(sig, &sa, NULL) < 0)) - if (errno != EINVAL && r == 0) - r = -errno; - } - - return r; -} - -int reset_signal_mask(void) { - sigset_t ss; - - if (sigemptyset(&ss) < 0) - return -errno; - - if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) - return -errno; - - return 0; -} - char *strstrip(char *s) { char *e; @@ -1540,59 +1506,6 @@ int flush_fd(int fd) { } } -int sigaction_many(const struct sigaction *sa, ...) { - va_list ap; - int r = 0, sig; - - va_start(ap, sa); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int ignore_signals(int sig, ...) { - struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_RESTART, - }; - va_list ap; - int r = 0; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int default_signals(int sig, ...) { - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - va_list ap; - int r = 0; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - void safe_close_pair(int p[]) { assert(p); @@ -1697,7 +1610,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { int parse_size(const char *t, off_t base, off_t *size) { - /* Soo, sometimes we want to parse IEC binary suffxies, and + /* Soo, sometimes we want to parse IEC binary suffixes, and * sometimes SI decimal suffixes. This function can parse * both. Which one is the right way depends on the * context. Wikipedia suggests that SI is customary for @@ -1906,55 +1819,6 @@ void rename_process(const char name[8]) { } } -void sigset_add_many(sigset_t *ss, ...) { - va_list ap; - int sig; - - assert(ss); - - va_start(ap, ss); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(ss, sig) == 0); - va_end(ap); -} - -int sigprocmask_many(int how, ...) { - va_list ap; - sigset_t ss; - int sig; - - assert_se(sigemptyset(&ss) == 0); - - va_start(ap, how); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(&ss, sig) == 0); - va_end(ap); - - if (sigprocmask(how, &ss, NULL) < 0) - return -errno; - - return 0; -} - -char* gethostname_malloc(void) { - struct utsname u; - - assert_se(uname(&u) >= 0); - - if (!isempty(u.nodename) && !streq(u.nodename, "(none)")) - return strdup(u.nodename); - - return strdup(u.sysname); -} - -bool hostname_is_set(void) { - struct utsname u; - - assert_se(uname(&u) >= 0); - - return !isempty(u.nodename) && !streq(u.nodename, "(none)"); -} - char *lookup_uid(uid_t uid) { long bufsize; char *name; @@ -2343,18 +2207,6 @@ DIR *xopendirat(int fd, const char *name, int flags) { return d; } -int signal_from_string_try_harder(const char *s) { - int signo; - assert(s); - - signo = signal_from_string(s); - if (signo <= 0) - if (startswith(s, "SIG")) - return signal_from_string(s+3); - - return signo; -} - static char *tag_to_udev_node(const char *tagvalue, const char *by) { _cleanup_free_ char *t = NULL, *u = NULL; size_t enc_len; @@ -2586,79 +2438,6 @@ char* strshorten(char *s, size_t l) { return s; } -static bool hostname_valid_char(char c) { - return - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '-' || - c == '_' || - c == '.'; -} - -bool hostname_is_valid(const char *s) { - const char *p; - bool dot; - - if (isempty(s)) - return false; - - /* Doesn't accept empty hostnames, hostnames with trailing or - * leading dots, and hostnames with multiple dots in a - * sequence. Also ensures that the length stays below - * HOST_NAME_MAX. */ - - for (p = s, dot = true; *p; p++) { - if (*p == '.') { - if (dot) - return false; - - dot = true; - } else { - if (!hostname_valid_char(*p)) - return false; - - dot = false; - } - } - - if (dot) - return false; - - if (p-s > HOST_NAME_MAX) - return false; - - return true; -} - -char* hostname_cleanup(char *s, bool lowercase) { - char *p, *d; - bool dot; - - for (p = s, d = s, dot = true; *p; p++) { - if (*p == '.') { - if (dot) - continue; - - *(d++) = '.'; - dot = true; - } else if (hostname_valid_char(*p)) { - *(d++) = lowercase ? tolower(*p) : *p; - dot = false; - } - - } - - if (dot && d > s) - d[-1] = 0; - else - *d = 0; - - strshorten(s, HOST_NAME_MAX); - - return s; -} - bool machine_name_is_valid(const char *s) { if (!hostname_is_valid(s)) @@ -3384,81 +3163,6 @@ static const char* const ip_tos_table[] = { DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); -static const char *const __signal_table[] = { - [SIGHUP] = "HUP", - [SIGINT] = "INT", - [SIGQUIT] = "QUIT", - [SIGILL] = "ILL", - [SIGTRAP] = "TRAP", - [SIGABRT] = "ABRT", - [SIGBUS] = "BUS", - [SIGFPE] = "FPE", - [SIGKILL] = "KILL", - [SIGUSR1] = "USR1", - [SIGSEGV] = "SEGV", - [SIGUSR2] = "USR2", - [SIGPIPE] = "PIPE", - [SIGALRM] = "ALRM", - [SIGTERM] = "TERM", -#ifdef SIGSTKFLT - [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ -#endif - [SIGCHLD] = "CHLD", - [SIGCONT] = "CONT", - [SIGSTOP] = "STOP", - [SIGTSTP] = "TSTP", - [SIGTTIN] = "TTIN", - [SIGTTOU] = "TTOU", - [SIGURG] = "URG", - [SIGXCPU] = "XCPU", - [SIGXFSZ] = "XFSZ", - [SIGVTALRM] = "VTALRM", - [SIGPROF] = "PROF", - [SIGWINCH] = "WINCH", - [SIGIO] = "IO", - [SIGPWR] = "PWR", - [SIGSYS] = "SYS" -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); - -const char *signal_to_string(int signo) { - static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; - const char *name; - - name = __signal_to_string(signo); - if (name) - return name; - - if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); - else - snprintf(buf, sizeof(buf), "%d", signo); - - return buf; -} - -int signal_from_string(const char *s) { - int signo; - int offset = 0; - unsigned u; - - signo = __signal_from_string(s); - if (signo > 0) - return signo; - - if (startswith(s, "RTMIN+")) { - s += 6; - offset = SIGRTMIN; - } - if (safe_atou(s, &u) >= 0) { - signo = (int) u + offset; - if (signo > 0 && signo < _NSIG) - return signo; - } - return -EINVAL; -} - bool kexec_loaded(void) { bool loaded = false; char *s; @@ -4758,16 +4462,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { return -errno; } - if (setresgid(0, 0, 0) < 0) - return -errno; - - if (setgroups(0, NULL) < 0) - return -errno; - - if (setresuid(0, 0, 0) < 0) - return -errno; - - return 0; + return reset_uid_gid(); } int getpeercred(int fd, struct ucred *ucred) { @@ -4918,10 +4613,7 @@ unsigned long personality_from_string(const char *p) { return PER_LINUX; #endif - /* personality(7) documents that 0xffffffffUL is used for - * querying the current personality, hence let's use that here - * as error indicator. */ - return 0xffffffffUL; + return PERSONALITY_INVALID; } const char* personality_to_string(unsigned long p) { @@ -5356,23 +5048,6 @@ int tempfn_random_child(const char *p, char **ret) { return 0; } -/* make sure the hostname is not "localhost" */ -bool is_localhost(const char *hostname) { - assert(hostname); - - /* This tries to identify local host and domain names - * described in RFC6761 plus the redhatism of .localdomain */ - - return streq(hostname, "localhost") || - streq(hostname, "localhost.") || - streq(hostname, "localdomain.") || - streq(hostname, "localdomain") || - endswith(hostname, ".localhost") || - endswith(hostname, ".localhost.") || - endswith(hostname, ".localdomain") || - endswith(hostname, ".localdomain."); -} - int take_password_lock(const char *root) { struct flock flock = { @@ -5730,26 +5405,6 @@ int free_and_strdup(char **p, const char *s) { return 1; } -int sethostname_idempotent(const char *s) { - int r; - char buf[HOST_NAME_MAX + 1] = {}; - - assert(s); - - r = gethostname(buf, sizeof(buf)); - if (r < 0) - return -errno; - - if (streq(buf, s)) - return 0; - - r = sethostname(s, strlen(s)); - if (r < 0) - return -errno; - - return 1; -} - int ptsname_malloc(int fd, char **ret) { size_t l = 100; @@ -5956,6 +5611,71 @@ int fd_setcrtime(int fd, usec_t usec) { return 0; } +int same_fd(int a, int b) { + struct stat sta, stb; + pid_t pid; + int r, fa, fb; + + assert(a >= 0); + assert(b >= 0); + + /* Compares two file descriptors. Note that semantics are + * quite different depending on whether we have kcmp() or we + * don't. If we have kcmp() this will only return true for + * dup()ed file descriptors, but not otherwise. If we don't + * have kcmp() this will also return true for two fds of the same + * file, created by separate open() calls. Since we use this + * call mostly for filtering out duplicates in the fd store + * this difference hopefully doesn't matter too much. */ + + if (a == b) + return true; + + /* Try to use kcmp() if we have it. */ + pid = getpid(); + r = kcmp(pid, pid, KCMP_FILE, a, b); + if (r == 0) + return true; + if (r > 0) + return false; + if (errno != ENOSYS) + return -errno; + + /* We don't have kcmp(), use fstat() instead. */ + if (fstat(a, &sta) < 0) + return -errno; + + if (fstat(b, &stb) < 0) + return -errno; + + if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) + return false; + + /* We consider all device fds different, since two device fds + * might refer to quite different device contexts even though + * they share the same inode and backing dev_t. */ + + if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) + return false; + + if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) + return false; + + /* The fds refer to the same inode on disk, let's also check + * if they have the same fd flags. This is useful to + * distinguish the read and write side of a pipe created with + * pipe(). */ + fa = fcntl(a, F_GETFL); + if (fa < 0) + return -errno; + + fb = fcntl(b, F_GETFL); + if (fb < 0) + return -errno; + + return fa == fb; +} + int chattr_fd(int fd, unsigned value, unsigned mask) { unsigned old_attr, new_attr; struct stat st; @@ -6273,3 +5993,35 @@ int parse_mode(const char *s, mode_t *ret) { *ret = (mode_t) l; return 0; } + +int mount_move_root(const char *path) { + assert(path); + + if (chdir(path) < 0) + return -errno; + + if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (chdir("/") < 0) + return -errno; + + return 0; +} + +int reset_uid_gid(void) { + + if (setgroups(0, NULL) < 0) + return -errno; + + if (setresgid(0, 0, 0) < 0) + return -errno; + + if (setresuid(0, 0, 0) < 0) + return -errno; + + return 0; +}