X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=c824c3934e3dedc2c8cda61581fd0ee9b0ed1f1d;hp=2cf9fbe53e6f97c9b48e96f458d192741b185e10;hb=b4696bce07e0a596accf097b7bff84bf30198f25;hpb=919ce0b7affc6fbd68598b709faf477f56c22ac1 diff --git a/src/shared/util.c b/src/shared/util.c index 2cf9fbe53..c824c3934 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -61,6 +61,10 @@ #include #undef basename +#ifdef HAVE_SYS_AUXV_H +#include +#endif + #include "macro.h" #include "util.h" #include "ioprio.h" @@ -436,8 +440,7 @@ char *split_quoted(const char *c, size_t *l, char **state) { int get_parent_of_pid(pid_t pid, pid_t *_ppid) { int r; - _cleanup_fclose_ FILE *f = NULL; - char line[LINE_MAX]; + _cleanup_free_ char *line = NULL; long unsigned ppid; const char *p; @@ -450,14 +453,9 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { } p = procfs_file_alloca(pid, "stat"); - f = fopen(p, "re"); - if (!f) - return -errno; - - if (!fgets(line, sizeof(line), f)) { - r = feof(f) ? -EIO : -errno; + r = read_one_line_file(p, &line); + if (r < 0) return r; - } /* Let's skip the pid and comm fields. The latter is enclosed * in () but does not escape any () in its value, so let's @@ -484,28 +482,17 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { } int get_starttime_of_pid(pid_t pid, unsigned long long *st) { - _cleanup_fclose_ FILE *f = NULL; - char line[LINE_MAX]; + int r; + _cleanup_free_ char *line = NULL; const char *p; assert(pid >= 0); assert(st); - if (pid == 0) - p = "/proc/self/stat"; - else - p = procfs_file_alloca(pid, "stat"); - - f = fopen(p, "re"); - if (!f) - return errno == ENOENT ? -ESRCH : -errno; - - if (!fgets(line, sizeof(line), f)) { - if (ferror(f)) - return -errno; - - return -EIO; - } + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; /* Let's skip the pid and comm fields. The latter is enclosed * in () but does not escape any () in its value, so let's @@ -569,10 +556,7 @@ int get_process_comm(pid_t pid, char **name) { assert(name); assert(pid >= 0); - if (pid == 0) - p = "/proc/self/comm"; - else - p = procfs_file_alloca(pid, "comm"); + p = procfs_file_alloca(pid, "comm"); r = read_one_line_file(p, name); if (r == -ENOENT) @@ -590,10 +574,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * assert(line); assert(pid >= 0); - if (pid == 0) - p = "/proc/self/cmdline"; - else - p = procfs_file_alloca(pid, "cmdline"); + p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); if (!f) @@ -712,10 +693,7 @@ int get_process_capeff(pid_t pid, char **capeff) { assert(capeff); assert(pid >= 0); - if (pid == 0) - p = "/proc/self/status"; - else - p = procfs_file_alloca(pid, "status"); + p = procfs_file_alloca(pid, "status"); return get_status_field(p, "\nCapEff:", capeff); } @@ -728,10 +706,7 @@ int get_process_exe(pid_t pid, char **name) { assert(pid >= 0); assert(name); - if (pid == 0) - p = "/proc/self/exe"; - else - p = procfs_file_alloca(pid, "exe"); + p = procfs_file_alloca(pid, "exe"); r = readlink_malloc(p, name); if (r < 0) @@ -2306,7 +2281,6 @@ bool is_device_path(const char *path) { int dir_is_empty(const char *path) { _cleanup_closedir_ DIR *d; - int r; d = opendir(path); if (!d) @@ -2314,11 +2288,11 @@ int dir_is_empty(const char *path) { for (;;) { struct dirent *de; - union dirent_storage buf; - r = readdir_r(d, &buf.de, &de); - if (r > 0) - return -r; + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; if (!de) return 1; @@ -2346,42 +2320,48 @@ char* dirname_malloc(const char *path) { return dir; } -unsigned long long random_ull(void) { +void random_bytes(void *p, size_t n) { + static bool srand_called = false; _cleanup_close_ int fd; - uint64_t ull; - ssize_t r; + ssize_t k; + uint8_t *q; fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) goto fallback; - r = loop_read(fd, &ull, sizeof(ull), true); - if (r != sizeof(ull)) + k = loop_read(fd, p, n, true); + if (k < 0 || (size_t) k != n) goto fallback; - return ull; + return; fallback: - return random() * RAND_MAX + random(); -} -unsigned random_u(void) { - _cleanup_close_ int fd; - unsigned u; - ssize_t r; + if (!srand_called) { - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - goto fallback; +#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... */ - r = loop_read(fd, &u, sizeof(u), true); - if (r != sizeof(u)) - goto fallback; + void *auxv; - return u; + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + srand(*(unsigned*) auxv); + else +#endif + srand(time(NULL) + gettid()); -fallback: - return random() * RAND_MAX + random(); + srand_called = true; + } + + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ + for (q = p; q < (uint8_t*) p + n; q ++) + *q = rand(); } void rename_process(const char name[8]) { @@ -2533,24 +2513,17 @@ int getttyname_harder(int fd, char **r) { } int get_ctty_devnr(pid_t pid, dev_t *d) { - _cleanup_fclose_ FILE *f = NULL; - char line[LINE_MAX], *p; + int r; + _cleanup_free_ char *line = NULL; + const char *p; unsigned long ttynr; - const char *fn; assert(pid >= 0); - if (pid == 0) - fn = "/proc/self/stat"; - else - fn = procfs_file_alloca(pid, "stat"); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(line, sizeof(line), f)) - return feof(f) ? -EIO : -errno; + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; p = strrchr(line, ')'); if (!p) @@ -2660,14 +2633,15 @@ int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct for (;;) { struct dirent *de; - union dirent_storage buf; bool is_dir, keep_around; struct stat st; int r; - r = readdir_r(d, &buf.de, &de); - if (r != 0 && ret == 0) { - ret = -r; + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + if (ret == 0) + ret = -errno; break; } @@ -4137,7 +4111,7 @@ int symlink_atomic(const char *from, const char *to) { _cleanup_free_ char *t; const char *fn; size_t k; - unsigned long long ull; + uint64_t u; unsigned i; int r; @@ -4154,10 +4128,10 @@ int symlink_atomic(const char *from, const char *to) { t[k] = '.'; x = stpcpy(t+k+1, fn); - ull = random_ull(); + u = random_u64(); for (i = 0; i < 16; i++) { - *(x++) = hexchar(ull & 0xF); - ull >>= 4; + *(x++) = hexchar(u & 0xF); + u >>= 4; } *x = 0; @@ -4485,13 +4459,11 @@ int get_files_in_directory(const char *path, char ***list) { for (;;) { struct dirent *de; - union dirent_storage buf; - int k; - k = readdir_r(d, &buf.de, &de); - assert(k >= 0); - if (k > 0) - return -k; + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; if (!de) break; @@ -5087,10 +5059,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { assert(field); assert(_value); - if (pid == 0) - path = "/proc/self/environ"; - else - path = procfs_file_alloca(pid, "environ"); + path = procfs_file_alloca(pid, "environ"); f = fopen(path, "re"); if (!f) @@ -5617,15 +5586,14 @@ int on_ac_power(void) { for (;;) { struct dirent *de; - union dirent_storage buf; _cleanup_close_ int fd = -1, device = -1; char contents[6]; ssize_t n; - int k; - k = readdir_r(d, &buf.de, &de); - if (k != 0) - return -k; + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; if (!de) break; @@ -5987,8 +5955,20 @@ int proc_cmdline(char **ret) { int r; if (detect_container(NULL) > 0) { - *ret = NULL; - return 0; + char *buf, *p; + size_t sz = 0; + + r = read_full_file("/proc/1/cmdline", &buf, &sz); + if (r < 0) + return r; + + for (p = buf; p + 1 < buf + sz; p++) + if (*p == 0) + *p = ' '; + + *p = 0; + *ret = buf; + return 1; } r = read_one_line_file("/proc/cmdline", ret); @@ -6088,3 +6068,76 @@ int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) { return 0; } + +bool pid_valid(pid_t pid) { + if (pid <= 0) + return false; + + if (kill(pid, 0) >= 0) + return true; + + return errno != ESRCH; +} + +int getpeercred(int fd, struct ucred *ucred) { + socklen_t n = sizeof(struct ucred); + struct ucred u; + int r; + + assert(fd >= 0); + assert(ucred); + + r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); + if (r < 0) + return -errno; + + if (n != sizeof(struct ucred)) + return -EIO; + + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + + *ucred = u; + return 0; +} + +int getpeersec(int fd, char **ret) { + socklen_t n = 64; + char *s; + int r; + + assert(fd >= 0); + assert(ret); + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + + if (errno != ERANGE) + return -errno; + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + return -errno; + } + } + + if (isempty(s)) { + free(s); + return -ENOTSUP; + } + + *ret = s; + return 0; +}