X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=10daff3036071a7944a826d1a080b1d4d2193caf;hp=f491708f4fa64e4f7b9667d49ddf40da06c35fcf;hb=1c231f56482546725c4dbd3303f70300bd3c63e9;hpb=ae98841e63a2624700db84ba44217f768b090d99 diff --git a/src/shared/util.c b/src/shared/util.c index f491708f4..10daff303 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #undef basename @@ -359,8 +360,23 @@ int safe_atod(const char *s, double *ret_d) { return 0; } +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + size_t n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + return n; + } + return n; +} + /* Split a string into words. */ -char *split(const char *c, size_t *l, const char *separator, char **state) { +char *split(const char *c, size_t *l, const char *separator, bool quoted, char **state) { char *current; current = *state ? *state : (char*) c; @@ -369,70 +385,19 @@ char *split(const char *c, size_t *l, const char *separator, char **state) { return NULL; current += strspn(current, separator); - *l = strcspn(current, separator); - *state = current+*l; - - return (char*) current; -} - -/* Split a string into words, but consider strings enclosed in '' and - * "" as words even if they include spaces. */ -char *split_quoted(const char *c, size_t *l, char **state) { - const char *current, *e; - bool escaped = false; - - assert(c); - assert(l); - assert(state); - - current = *state ? *state : c; - - current += strspn(current, WHITESPACE); - - if (*current == 0) + if (!*current) return NULL; - else if (*current == '\'') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\'') - break; - } - - *l = e-current; - *state = (char*) (*e == 0 ? e : e+1); - - } else if (*current == '\"') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\"') - break; - } - - *l = e-current; - *state = (char*) (*e == 0 ? e : e+1); - + if (quoted && strchr("\'\"", *current)) { + char quotechar = *(current++); + *l = strcspn_escaped(current, (char[]){quotechar, '\0'}); + *state = current+*l+1; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + *state = current+*l; } else { - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (strchr(WHITESPACE, *e)) - break; - } - *l = e-current; - *state = (char*) e; + *l = strcspn(current, separator); + *state = current+*l; } return (char*) current; @@ -440,8 +405,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; @@ -454,14 +418,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 @@ -488,28 +447,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 @@ -566,6 +514,31 @@ char *truncate_nl(char *s) { return s; } +int get_process_state(pid_t pid) { + const char *p; + char state; + int r; + _cleanup_free_ char *line = NULL; + + assert(pid >= 0); + + p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r < 0) + return r; + + p = strrchr(line, ')'); + if (!p) + return -EIO; + + p++; + + if (sscanf(p, " %c", &state) != 1) + return -EIO; + + return (unsigned char) state; +} + int get_process_comm(pid_t pid, char **name) { const char *p; int r; @@ -573,10 +546,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) @@ -594,10 +564,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) @@ -716,10 +683,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); } @@ -732,10 +696,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) @@ -826,28 +787,31 @@ char *strappend(const char *s, const char *suffix) { return strnappend(s, suffix, suffix ? strlen(suffix) : 0); } -int readlink_malloc(const char *p, char **r) { +int readlink_malloc(const char *p, char **ret) { size_t l = 100; + int r; assert(p); - assert(r); + assert(ret); for (;;) { char *c; ssize_t n; - if (!(c = new(char, l))) + c = new(char, l); + if (!c) return -ENOMEM; - if ((n = readlink(p, c, l-1)) < 0) { - int ret = -errno; + n = readlink(p, c, l-1); + if (n < 0) { + r = -errno; free(c); - return ret; + return r; } if ((size_t) n < l-1) { c[n] = 0; - *r = c; + *ret = c; return 0; } @@ -2102,45 +2066,31 @@ int close_pipe(int p[]) { } ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p; + uint8_t *p = buf; ssize_t n = 0; assert(fd >= 0); assert(buf); - p = buf; - while (nbytes > 0) { ssize_t k; - if ((k = read(fd, p, nbytes)) <= 0) { - - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; - - if (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; + k = read(fd, p, nbytes); + if (k < 0 && errno == EINTR) + continue; - return n > 0 ? n : -errno; - } + if (k < 0 && errno == EAGAIN && do_poll) { - /* We knowingly ignore the revents value here, - * and expect that any error/EOF is reported - * via read()/write() - */ + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ - continue; - } + fd_wait_for_event(fd, POLLIN, (usec_t) -1); + continue; + } + if (k <= 0) return n > 0 ? n : (k < 0 ? -errno : 0); - } p += k; nbytes -= k; @@ -2151,46 +2101,31 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { } ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p; + const uint8_t *p = buf; ssize_t n = 0; assert(fd >= 0); assert(buf); - p = buf; - while (nbytes > 0) { ssize_t k; k = write(fd, p, nbytes); - if (k <= 0) { - - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLOUT, - }; - - if (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; + if (k < 0 && errno == EINTR) + continue; - return n > 0 ? n : -errno; - } + if (k < 0 && errno == EAGAIN && do_poll) { - /* We knowingly ignore the revents value here, - * and expect that any error/EOF is reported - * via read()/write() - */ + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via write() */ - continue; - } + fd_wait_for_event(fd, POLLOUT, (usec_t) -1); + continue; + } + if (k <= 0) return n > 0 ? n : (k < 0 ? -errno : 0); - } p += k; nbytes -= k; @@ -2200,30 +2135,71 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return n; } -int parse_bytes(const char *t, off_t *bytes) { - static const struct { +int parse_size(const char *t, off_t base, off_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffxies, 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 + * hardrware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { const char *suffix; unsigned long long factor; - } table[] = { - { "B", 1 }, - { "K", 1024ULL }, - { "M", 1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + }; + + static const struct table iec[] = { { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "M", 1024ULL*1024ULL }, + { "K", 1024ULL }, + { "B", 1 }, + { "", 1 }, + }; + + static const struct table si[] = { + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "M", 1000ULL*1000ULL }, + { "K", 1000ULL }, + { "B", 1 }, { "", 1 }, }; + const struct table *table; const char *p; unsigned long long r = 0; + unsigned n_entries, start_pos = 0; assert(t); - assert(bytes); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } p = t; do { long long l; + unsigned long long l2; + double frac = 0; char *e; unsigned i; @@ -2239,14 +2215,32 @@ int parse_bytes(const char *t, off_t *bytes) { if (e == p) return -EINVAL; + if (*e == '.') { + e++; + if (*e >= '0' && *e <= '9') { + char *e2; + + /* strotoull itself would accept space/+/- */ + l2 = strtoull(e, &e2, 10); + + if (errno == ERANGE) + return -errno; + + /* Ignore failure. E.g. 10.M is valid */ + frac = l2; + for (; e < e2; e++) + frac /= 10; + } + } + e += strspn(e, WHITESPACE); - for (i = 0; i < ELEMENTSOF(table); i++) + for (i = start_pos; i < n_entries; i++) if (startswith(e, table[i].suffix)) { unsigned long long tmp; - if ((unsigned long long) l > ULLONG_MAX / table[i].factor) + if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor) return -ERANGE; - tmp = l * table[i].factor; + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); if (tmp > ULLONG_MAX - r) return -ERANGE; @@ -2255,15 +2249,17 @@ int parse_bytes(const char *t, off_t *bytes) { return -ERANGE; p = e + strlen(table[i].suffix); + + start_pos = i + 1; break; } - if (i >= ELEMENTSOF(table)) + if (i >= n_entries) return -EINVAL; } while (*p); - *bytes = r; + *size = r; return 0; } @@ -2349,25 +2345,37 @@ char* dirname_malloc(const char *path) { return dir; } -void random_bytes(void *p, size_t n) { - static bool srand_called = false; +int dev_urandom(void *p, size_t n) { _cleanup_close_ int fd; ssize_t k; - uint8_t *q; fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) - goto fallback; + return errno == ENOENT ? -ENOSYS : -errno; k = loop_read(fd, p, n, true); - if (k < 0 || (size_t) k != n) - goto fallback; + if (k < 0) + return (int) k; + if ((size_t) k != n) + return -EIO; - return; + return 0; +} -fallback: +void random_bytes(void *p, size_t n) { + static bool srand_called = false; + uint8_t *q; + int r; + + r = dev_urandom(p, n); + if (r >= 0) + return; + + /* 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 @@ -2379,16 +2387,16 @@ fallback: auxv = (void*) getauxval(AT_RANDOM); if (auxv) - srand(*(unsigned*) auxv); - else + x ^= *(unsigned*) auxv; #endif - srand(time(NULL) + gettid()); + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); 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(); } @@ -2419,7 +2427,7 @@ void rename_process(const char name[8]) { if (!saved_argv[i]) break; - memset(saved_argv[i], 0, strlen(saved_argv[i])); + memzero(saved_argv[i], strlen(saved_argv[i])); } } } @@ -2542,24 +2550,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) @@ -2586,9 +2587,11 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { } int get_ctty(pid_t pid, dev_t *_devnr, char **r) { - int k; - char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *s, *b, *p; + char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL; + _cleanup_free_ char *s = NULL; + const char *p; dev_t devnr; + int k; assert(r); @@ -2606,14 +2609,8 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { /* This is an ugly hack */ if (major(devnr) == 136) { - if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; + asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)); + goto finish; } /* Probably something like the ptys which have no @@ -2621,14 +2618,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { * vaguely useful. */ b = strdup(fn + 5); - if (!b) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; + goto finish; } if (startswith(s, "/dev/")) @@ -2639,8 +2629,8 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { p = s; b = strdup(p); - free(s); +finish: if (!b) return -ENOMEM; @@ -2989,24 +2979,6 @@ int status_printf(const char *status, bool ellipse, bool ephemeral, const char * return r; } -int status_welcome(void) { - _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; - int r; - - r = parse_env_file("/etc/os-release", NEWLINE, - "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color, - NULL); - - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/os-release: %s", strerror(-r)); - - return status_printf(NULL, false, false, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); -} - char *replace_env(const char *format, char **env) { enum { WORD, @@ -3924,12 +3896,13 @@ char* hostname_cleanup(char *s, bool lowercase) { } int pipe_eof(int fd) { - int r; struct pollfd pollfd = { .fd = fd, .events = POLLIN|POLLHUP, }; + int r; + r = poll(&pollfd, 1, 0); if (r < 0) return -errno; @@ -3941,13 +3914,16 @@ int pipe_eof(int fd) { } int fd_wait_for_event(int fd, int event, usec_t t) { - int r; + struct pollfd pollfd = { .fd = fd, .events = event, }; - r = poll(&pollfd, 1, t == (usec_t) -1 ? -1 : (int) (t / USEC_PER_MSEC)); + struct timespec ts; + int r; + + r = ppoll(&pollfd, 1, t == (usec_t) -1 ? NULL : timespec_store(&ts, t), NULL); if (r < 0) return -errno; @@ -3978,7 +3954,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { t[k] = '.'; stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); - fd = mkostemp(t, O_WRONLY|O_CLOEXEC); + fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); if (fd < 0) { free(t); return -errno; @@ -5095,10 +5071,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) @@ -5698,7 +5671,7 @@ static int search_and_fopen_internal(const char *path, const char *mode, char ** assert(mode); assert(_f); - if (!path_strv_canonicalize_uniq(search)) + if (!path_strv_canonicalize_absolute_uniq(search, NULL)) return -ENOMEM; STRV_FOREACH(i, search) { @@ -5880,7 +5853,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need) { return NULL; if (*allocated > prev) - memset(&q[prev], 0, *allocated - prev); + memzero(&q[prev], *allocated - prev); return q; } @@ -5926,20 +5899,6 @@ bool id128_is_valid(const char *s) { return true; } -void parse_user_at_host(char *arg, char **user, char **host) { - assert(arg); - assert(user); - assert(host); - - *host = strchr(arg, '@'); - if (*host == NULL) - *host = arg; - else { - *host[0]++ = '\0'; - *user = arg; - } -} - int split_pair(const char *s, const char *sep, char **l, char **r) { char *x, *a, *b; @@ -5994,7 +5953,7 @@ int proc_cmdline(char **ret) { int r; if (detect_container(NULL) > 0) { - char *buf, *p; + char *buf = NULL, *p; size_t sz = 0; r = read_full_file("/proc/1/cmdline", &buf, &sz); @@ -6017,6 +5976,35 @@ int proc_cmdline(char **ret) { return 1; } +int parse_proc_cmdline(int (*parse_word)(const char *word)) { + _cleanup_free_ char *line = NULL; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); + if (r <= 0) + return 0; + + FOREACH_WORD_QUOTED(w, l, line, state) { + _cleanup_free_ char *word; + + word = strndup(w, l); + if (!word) + return log_oom(); + + r = parse_word(word); + if (r < 0) { + log_error("Failed on cmdline argument %s: %s", word, strerror(-r)); + return r; + } + } + + return 0; +} + int container_get_leader(const char *machine, pid_t *pid) { _cleanup_free_ char *s = NULL, *class = NULL; const char *p; @@ -6108,7 +6096,9 @@ int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) { return 0; } -bool pid_valid(pid_t pid) { +bool pid_is_unwaited(pid_t pid) { + /* Checks whether a PID is still valid at all, including a zombie */ + if (pid <= 0) return false; @@ -6118,6 +6108,21 @@ bool pid_valid(pid_t pid) { return errno != ESRCH; } +bool pid_is_alive(pid_t pid) { + int r; + + /* Checks whether a PID is still valid and not a zombie */ + + if (pid <= 0) + return false; + + r = get_process_state(pid); + if (r == -ENOENT || r == 'Z') + return false; + + return true; +} + int getpeercred(int fd, struct ucred *ucred) { socklen_t n = sizeof(struct ucred); struct ucred u; @@ -6180,3 +6185,121 @@ int getpeersec(int fd, char **ret) { *ret = s; return 0; } + +/* This is much like like mkostemp() but is subject to umask(). */ +int mkostemp_safe(char *pattern, int flags) { + _cleanup_umask_ mode_t u; + int fd; + + assert(pattern); + + u = umask(077); + + fd = mkostemp(pattern, flags); + if (fd < 0) + return -errno; + + return fd; +} + +int open_tmpfile(const char *path, int flags) { + char *p; + int fd; + + assert(path); + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strappenda(path, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + unlink(p); + return fd; +} + +int fd_warn_permissions(const char *path, int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st.st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid() == 1 && (st.st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + +unsigned long personality_from_string(const char *p) { + + /* Parse a personality specifier. We introduce our own + * identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep + * things open for multiple locally supported ABIs for the + * same register size. We try to reuse the ABI identifiers + * used by libseccomp. */ + +#if defined(__x86_64__) + + if (streq(p, "x86")) + return PER_LINUX32; + + if (streq(p, "x86-64")) + return PER_LINUX; + +#elif defined(__i386__) + + if (streq(p, "x86")) + 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; +} + +const char* personality_to_string(unsigned long p) { + +#if defined(__x86_64__) + + if (p == PER_LINUX32) + return "x86"; + + if (p == PER_LINUX) + return "x86-64"; + +#elif defined(__i386__) + + if (p == PER_LINUX) + return "x86"; +#endif + + return NULL; +} + +uint64_t physical_memory(void) { + long mem; + + /* We return this as uint64_t in case we are running as 32bit + * process on a 64bit kernel with huge amounts of memory */ + + mem = sysconf(_SC_PHYS_PAGES); + assert(mem > 0); + + return (uint64_t) mem * (uint64_t) page_size(); +}