X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=8d54049754c0495b2d4394483c9d2825fcc84f73;hp=ca769c22e6a62b2cbdd5956f5835435acf59a052;hb=3bfc71846c3eac9011f0182b0c8d5639a9549228;hpb=ccaa61498c7932cbd5c91540841840266914b10e diff --git a/src/util.c b/src/util.c index ca769c22e..8d5404975 100644 --- a/src/util.c +++ b/src/util.c @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include "macro.h" #include "util.h" @@ -71,7 +73,7 @@ size_t page_size(void) { static __thread size_t pgsz = 0; long r; - if (pgsz) + if (_likely_(pgsz)) return pgsz; assert_se((r = sysconf(_SC_PAGESIZE)) > 0); @@ -316,6 +318,26 @@ int parse_pid(const char *s, pid_t* ret_pid) { return 0; } +int parse_uid(const char *s, uid_t* ret_uid) { + unsigned long ul = 0; + uid_t uid; + int r; + + assert(s); + assert(ret_uid); + + if ((r = safe_atolu(s, &ul)) < 0) + return r; + + uid = (uid_t) ul; + + if ((unsigned long) uid != ul) + return -ERANGE; + + *ret_uid = uid; + return 0; +} + int safe_atou(const char *s, unsigned *ret_u) { char *x = NULL; unsigned long l; @@ -787,7 +809,7 @@ int parse_env_file( const char *separator, ...) { int r = 0; - char *contents, *p; + char *contents = NULL, *p; assert(fname); assert(separator); @@ -1156,6 +1178,29 @@ int readlink_and_make_absolute(const char *p, char **r) { return 0; } +int readlink_and_canonicalize(const char *p, char **r) { + char *t, *s; + int j; + + assert(p); + assert(r); + + j = readlink_and_make_absolute(p, &t); + if (j < 0) + return j; + + s = canonicalize_file_name(t); + if (s) { + free(t); + *r = s; + } else + *r = t; + + path_kill_slashes(*r); + + return 0; +} + int parent_of_path(const char *path, char **_r) { const char *e, *a = NULL, *b = NULL, *p; char *r; @@ -1221,8 +1266,6 @@ bool is_path(const char *p) { } char *path_make_absolute(const char *p, const char *prefix) { - char *r; - assert(p); /* Makes every item in the list an absolute path by prepending @@ -1231,10 +1274,7 @@ char *path_make_absolute(const char *p, const char *prefix) { if (path_is_absolute(p) || !prefix) return strdup(p); - if (asprintf(&r, "%s/%s", prefix, p) < 0) - return NULL; - - return r; + return join(prefix, "/", p, NULL); } char *path_make_absolute_cwd(const char *p) { @@ -1366,21 +1406,18 @@ int reset_all_signal_handlers(void) { } char *strstrip(char *s) { - char *e, *l = NULL; + char *e; /* Drops trailing whitespace. Modifies the string in * place. Returns pointer to first non-space character */ s += strspn(s, WHITESPACE); - for (e = s; *e; e++) - if (!strchr(WHITESPACE, *e)) - l = e; + for (e = strchr(s, 0); e > s; e --) + if (!strchr(WHITESPACE, e[-1])) + break; - if (l) - *(l+1) = 0; - else - *s = 0; + *e = 0; return s; } @@ -2947,6 +2984,10 @@ int make_stdio(int fd) { if (r < 0 || s < 0 || t < 0) return -errno; + fd_cloexec(STDIN_FILENO, false); + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); + return 0; } @@ -3727,7 +3768,7 @@ int columns(void) { static __thread int parsed_columns = 0; const char *e; - if (parsed_columns > 0) + if (_likely_(parsed_columns > 0)) return parsed_columns; if ((e = getenv("COLUMNS"))) @@ -3861,8 +3902,12 @@ char *normalize_env_assignment(const char *s) { } int wait_for_terminate(pid_t pid, siginfo_t *status) { + siginfo_t dummy; + assert(pid >= 1); - assert(status); + + if (!status) + status = &dummy; for (;;) { zero(*status); @@ -3935,6 +3980,17 @@ bool null_or_empty(struct stat *st) { return false; } +int null_or_empty_path(const char *fn) { + struct stat st; + + assert(fn); + + if (stat(fn, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + DIR *xopendirat(int fd, const char *name, int flags) { int nfd; DIR *d; @@ -4308,7 +4364,7 @@ int detect_virtualization(const char **id) { const char *_id; int r; - if (cached_id) { + if (_likely_(cached_id)) { if (cached_id == (const char*) -1) return 0; @@ -4758,7 +4814,7 @@ static int file_is_conf(const struct dirent *d, const char *suffix) { static int files_add(Hashmap *h, const char *path, const char *suffix) { DIR *dir; - struct dirent *de; + struct dirent buffer, *de; int r = 0; dir = opendir(path); @@ -4768,9 +4824,18 @@ static int files_add(Hashmap *h, const char *path, const char *suffix) { return -errno; } - for (de = readdir(dir); de; de = readdir(dir)) { + for (;;) { + int k; char *p, *f; - const char *base; + + k = readdir_r(dir, &buffer, &de); + if (k != 0) { + r = -k; + goto finish; + } + + if (!de) + break; if (!file_is_conf(de, suffix)) continue; @@ -4789,8 +4854,7 @@ static int files_add(Hashmap *h, const char *path, const char *suffix) { free(p); log_debug("found: %s\n", f); - base = f + strlen(path) + 1; - if (hashmap_put(h, base, f) <= 0) + if (hashmap_put(h, file_name_from_path(f), f) <= 0) free(f); } @@ -4896,7 +4960,7 @@ int hwclock_is_localtime(void) { return local; } -int hwclock_apply_localtime_delta(void) { +int hwclock_apply_localtime_delta(int *min) { const struct timeval *tv_null = NULL; struct timespec ts; struct tm *tm; @@ -4917,8 +4981,9 @@ int hwclock_apply_localtime_delta(void) { */ if (settimeofday(tv_null, &tz) < 0) return -errno; - - return minuteswest; + if (min) + *min = minuteswest; + return 0; } int hwclock_reset_localtime_delta(void) { @@ -5190,28 +5255,31 @@ int socket_from_display(const char *display, char **path) { int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) { struct passwd *p; - unsigned long lu; + uid_t u; assert(username); assert(*username); - assert(uid); - assert(gid); - assert(home); /* We enforce some special rules for uid=0: in order to avoid * NSS lookups for root we hardcode its data. */ if (streq(*username, "root") || streq(*username, "0")) { *username = "root"; - *uid = 0; - *gid = 0; - *home = "/root"; + + if (uid) + *uid = 0; + + if (gid) + *gid = 0; + + if (home) + *home = "/root"; return 0; } - if (safe_atolu(*username, &lu) >= 0) { + if (parse_uid(*username, &u) >= 0) { errno = 0; - p = getpwuid((uid_t) lu); + p = getpwuid(u); /* If there are multiple users with the same id, make * sure to leave $USER to the configured value instead @@ -5228,12 +5296,255 @@ int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **h if (!p) return errno != 0 ? -errno : -ESRCH; - *uid = p->pw_uid; - *gid = p->pw_gid; - *home = p->pw_dir; + if (uid) + *uid = p->pw_uid; + + if (gid) + *gid = p->pw_gid; + + if (home) + *home = p->pw_dir; + + return 0; +} + +int get_group_creds(const char **groupname, gid_t *gid) { + struct group *g; + gid_t id; + + assert(groupname); + + /* We enforce some special rules for gid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*groupname, "root") || streq(*groupname, "0")) { + *groupname = "root"; + + if (gid) + *gid = 0; + + return 0; + } + + if (parse_gid(*groupname, &id) >= 0) { + errno = 0; + g = getgrgid(id); + + if (g) + *groupname = g->gr_name; + } else { + errno = 0; + g = getgrnam(*groupname); + } + + if (!g) + return errno != 0 ? -errno : -ESRCH; + + if (gid) + *gid = g->gr_gid; + return 0; } +int glob_exists(const char *path) { + glob_t g; + int r, k; + + assert(path); + + zero(g); + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + r = 0; + else if (k == GLOB_NOSPACE) + r = -ENOMEM; + else if (k == 0) + r = !strv_isempty(g.gl_pathv); + else + r = errno ? -errno : -EIO; + + globfree(&g); + + return r; +} + +int dirent_ensure_type(DIR *d, struct dirent *de) { + struct stat st; + + assert(d); + assert(de); + + if (de->d_type != DT_UNKNOWN) + return 0; + + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + return -errno; + + de->d_type = + S_ISREG(st.st_mode) ? DT_REG : + S_ISDIR(st.st_mode) ? DT_DIR : + S_ISLNK(st.st_mode) ? DT_LNK : + S_ISFIFO(st.st_mode) ? DT_FIFO : + S_ISSOCK(st.st_mode) ? DT_SOCK : + S_ISCHR(st.st_mode) ? DT_CHR : + S_ISBLK(st.st_mode) ? DT_BLK : + DT_UNKNOWN; + + return 0; +} + +int in_search_path(const char *path, char **search) { + char **i, *parent; + int r; + + r = parent_of_path(path, &parent); + if (r < 0) + return r; + + r = 0; + + STRV_FOREACH(i, search) { + if (path_equal(parent, *i)) { + r = 1; + break; + } + } + + free(parent); + + return r; +} + +int get_files_in_directory(const char *path, char ***list) { + DIR *d; + int r = 0; + unsigned n = 0; + char **l = NULL; + + assert(path); + + /* Returns all files in a directory in *list, and the number + * of files as return value. If list is NULL returns only the + * number */ + + d = opendir(path); + for (;;) { + struct dirent buffer, *de; + int k; + + k = readdir_r(d, &buffer, &de); + if (k != 0) { + r = -k; + goto finish; + } + + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + if (list) { + if ((unsigned) r >= n) { + char **t; + + n = MAX(16, 2*r); + t = realloc(l, sizeof(char*) * n); + if (!t) { + r = -ENOMEM; + goto finish; + } + + l = t; + } + + assert((unsigned) r < n); + + l[r] = strdup(de->d_name); + if (!l[r]) { + r = -ENOMEM; + goto finish; + } + + l[++r] = NULL; + } else + r++; + } + +finish: + if (d) + closedir(d); + + if (r >= 0) { + if (list) + *list = l; + } else + strv_free(l); + + return r; +} + +char *join(const char *x, ...) { + va_list ap; + size_t l; + char *r, *p; + + va_start(ap, x); + + if (x) { + l = strlen(x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + l += strlen(t); + } + } else + l = 0; + + va_end(ap); + + r = new(char, l+1); + if (!r) + return NULL; + + if (x) { + p = stpcpy(r, x); + + va_start(ap, x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + } else + r[0] = 0; + + return r; +} + +bool is_main_thread(void) { + static __thread int cached = 0; + + if (_unlikely_(cached == 0)) + cached = getpid() == gettid() ? 1 : -1; + + return cached > 0; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime",