X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=0f44eb5afe7a8c57c8985a8397747339d4a11c75;hp=fdcf5719fa54d0b9b3b47de0c24e60a785c6107b;hb=ef309a681f4c761503e4cd4cc6884d7d6ef70436;hpb=1b6d7fa742e303611dff8d7ebfa86ee5fb8b7dc7 diff --git a/src/shared/util.c b/src/shared/util.c index fdcf5719f..0f44eb5af 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -1878,9 +1878,6 @@ int open_terminal(const char *name, int mode) { c++; } - if (fd < 0) - return -errno; - r = isatty(fd); if (r < 0) { safe_close(fd); @@ -2077,7 +2074,7 @@ int acquire_terminal( * ended our handle will be dead. It's important that * we do this after sleeping, so that we don't enter * an endless loop. */ - safe_close(fd); + fd = safe_close(fd); } safe_close(notify); @@ -2469,14 +2466,53 @@ char* dirname_malloc(const char *path) { } int dev_urandom(void *p, size_t n) { - _cleanup_close_ int fd; + static int have_syscall = -1; + int r, fd; ssize_t k; + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + /* Use the getrandom() syscall unless we know we don't have + * it, or when the requested size is too large for it. */ + if (have_syscall != 0 || (size_t) (int) n != n) { + r = getrandom(p, n, GRND_NONBLOCK); + if (r == (int) n) { + have_syscall = true; + return 0; + } + + if (r < 0) { + if (errno == ENOSYS) + /* we lack the syscall, continue with + * reading from /dev/urandom */ + have_syscall = false; + else if (errno == EAGAIN) + /* not enough entropy for now. Let's + * remember to use the syscall the + * next time, again, but also read + * from /dev/urandom for now, which + * doesn't care about the current + * amount of entropy. */ + have_syscall = true; + else + return -errno; + } else + /* too short read? */ + return -EIO; + } + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return errno == ENOENT ? -ENOSYS : -errno; k = loop_read(fd, p, n, true); + safe_close(fd); + if (k < 0) return (int) k; if ((size_t) k != n) @@ -2485,8 +2521,36 @@ int dev_urandom(void *p, size_t n) { return 0; } -void random_bytes(void *p, size_t n) { +void initialize_srand(void) { static bool srand_called = false; + unsigned x; +#ifdef HAVE_SYS_AUXV_H + void *auxv; +#endif + + if (srand_called) + return; + + x = 0; + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned*) auxv; +#endif + + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); + srand_called = true; +} + +void random_bytes(void *p, size_t n) { uint8_t *q; int r; @@ -2497,28 +2561,7 @@ void random_bytes(void *p, size_t n) { /* If some idiot made /dev/urandom unavailable to us, he'll * get a PRNG instead. */ - if (!srand_called) { - unsigned x = 0; - -#ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in - * auxv, so let's try to make use of that to seed the - * pseudo-random generator. It's better than - * nothing... */ - - void *auxv; - - auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; -#endif - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; - } + initialize_srand(); for (q = p; q < (uint8_t*) p + n; q ++) *q = rand(); @@ -2604,7 +2647,7 @@ bool hostname_is_set(void) { return !isempty(u.nodename) && !streq(u.nodename, "(none)"); } -static char *lookup_uid(uid_t uid) { +char *lookup_uid(uid_t uid) { long bufsize; char *name; _cleanup_free_ char *buf = NULL; @@ -3276,7 +3319,7 @@ unsigned columns(void) { c = 0; e = getenv("COLUMNS"); if (e) - safe_atoi(e, &c); + (void) safe_atoi(e, &c); if (c <= 0) c = fd_columns(STDOUT_FILENO); @@ -3310,7 +3353,7 @@ unsigned lines(void) { l = 0; e = getenv("LINES"); if (e) - safe_atou(e, &l); + (void) safe_atou(e, &l); if (l <= 0) l = fd_lines(STDOUT_FILENO); @@ -3911,7 +3954,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv } } - pids = hashmap_new(NULL, NULL); + pids = hashmap_new(NULL); if (!pids) { log_oom(); _exit(EXIT_FAILURE); @@ -4981,24 +5024,6 @@ bool kexec_loaded(void) { return loaded; } -int strdup_or_null(const char *a, char **b) { - char *c; - - assert(b); - - if (!a) { - *b = NULL; - return 0; - } - - c = strdup(a); - if (!c) - return -ENOMEM; - - *b = c; - return 0; -} - int prot_from_flags(int flags) { switch (flags & O_ACCMODE) { @@ -5102,9 +5127,9 @@ int fd_inc_rcvbuf(int fd, size_t n) { } int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { - pid_t parent_pid, agent_pid; - int fd; bool stdout_is_tty, stderr_is_tty; + pid_t parent_pid, agent_pid; + sigset_t ss, saved_ss; unsigned n, i; va_list ap; char **l; @@ -5112,16 +5137,25 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa assert(pid); assert(path); - parent_pid = getpid(); - /* Spawns a temporary TTY agent, making sure it goes away when * we go away */ + parent_pid = getpid(); + + /* First we temporarily block all signals, so that the new + * child has them blocked initially. This way, we can be sure + * that SIGTERMs are not lost we might send to the agent. */ + assert_se(sigfillset(&ss) >= 0); + assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0); + agent_pid = fork(); - if (agent_pid < 0) + if (agent_pid < 0) { + assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); return -errno; + } if (agent_pid != 0) { + assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); *pid = agent_pid; return 0; } @@ -5132,24 +5166,26 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) _exit(EXIT_FAILURE); + /* Make sure we actually can kill the agent, if we need to, in + * case somebody invoked us from a shell script that trapped + * SIGTERM or so... */ + reset_all_signal_handlers(); + reset_signal_mask(); + /* Check whether our parent died before we were able - * to set the death signal */ + * to set the death signal and unblock the signals */ if (getppid() != parent_pid) _exit(EXIT_SUCCESS); /* Don't leak fds to the agent */ close_all_fds(except, n_except); - /* Make sure we actually can kill the agent, if we need to, in - * case somebody invoked us from a shell script that trapped - * SIGTERM or so... */ - reset_all_signal_handlers(); - reset_signal_mask(); - stdout_is_tty = isatty(STDOUT_FILENO); stderr_is_tty = isatty(STDERR_FILENO); if (!stdout_is_tty || !stderr_is_tty) { + int fd; + /* Detach from stdout/stderr. and reopen * /dev/tty for them. This is important to * ensure that when systemctl is started via @@ -6701,7 +6737,7 @@ int bind_remount_recursive(const char *prefix, bool ro) { path_kill_slashes(cleaned); - done = set_new(string_hash_func, string_compare_func); + done = set_new(&string_hash_ops); if (!done) return -ENOMEM; @@ -6711,7 +6747,7 @@ int bind_remount_recursive(const char *prefix, bool ro) { bool top_autofs = false; char *x; - todo = set_new(string_hash_func, string_compare_func); + todo = set_new(&string_hash_ops); if (!todo) return -ENOMEM; @@ -6943,10 +6979,21 @@ int is_symlink(const char *path) { if (lstat(path, &info) < 0) return -errno; - if (S_ISLNK(info.st_mode)) - return 1; + return !!S_ISLNK(info.st_mode); +} - return 0; +int is_dir(const char* path, bool follow) { + struct stat st; + + if (follow) { + if (stat(path, &st) < 0) + return -errno; + } else { + if (lstat(path, &st) < 0) + return -errno; + } + + return !!S_ISDIR(st.st_mode); } int unquote_first_word(const char **p, char **ret) { @@ -7174,3 +7221,23 @@ int free_and_strdup(char **p, const char *s) { return 0; } + +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; +}