X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=util.c;h=c7b2ca8516fa663f0d65158850e29088241dd143;hp=3ef190fa2a172faad91439124f0cc10ca576c960;hb=acbb02252a38214ecba3aa8a5c9b3669f9c9317e;hpb=6091827530d6dd43479d6709fb6e9f745c11e900 diff --git a/util.c b/util.c index 3ef190fa2..c7b2ca851 100644 --- a/util.c +++ b/util.c @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include "macro.h" #include "util.h" @@ -80,7 +83,7 @@ bool startswith(const char *s, const char *prefix) { return memcmp(s, prefix, pl) == 0; } -int nointr_close(int fd) { +int close_nointr(int fd) { assert(fd >= 0); for (;;) { @@ -93,3 +96,375 @@ int nointr_close(int fd) { return r; } } + +int parse_boolean(const char *v) { + assert(v); + + if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) + return 1; + else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) + return 0; + + return -EINVAL; +} + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || *x || errno) + return errno ? -errno : -EINVAL; + + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +int safe_atoi(const char *s, int *ret_i) { + char *x = NULL; + long l; + + assert(s); + assert(ret_i); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || *x || errno) + return errno ? -errno : -EINVAL; + + if ((long) (int) l != l) + return -ERANGE; + + *ret_i = (int) l; + return 0; +} + +int safe_atolu(const char *s, long unsigned *ret_lu) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_lu); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_lu = l; + return 0; +} + +int safe_atoli(const char *s, long int *ret_li) { + char *x = NULL; + long l; + + assert(s); + assert(ret_li); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_li = l; + return 0; +} + +int safe_atollu(const char *s, long long unsigned *ret_llu) { + char *x = NULL; + unsigned long long l; + + assert(s); + assert(ret_llu); + + errno = 0; + l = strtoull(s, &x, 0); + + if (!x || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_llu = l; + return 0; +} + +int safe_atolli(const char *s, long long int *ret_lli) { + char *x = NULL; + long long l; + + assert(s); + assert(ret_lli); + + errno = 0; + l = strtoll(s, &x, 0); + + if (!x || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_lli = l; + return 0; +} + +/* Split a string into words. */ +char *split_spaces(const char *c, size_t *l, char **state) { + char *current; + + current = *state ? *state : (char*) c; + + if (!*current || *c == 0) + return NULL; + + current += strspn(current, WHITESPACE); + *l = strcspn(current, WHITESPACE); + *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) { + char *current; + + current = *state ? *state : (char*) c; + + if (!*current || *c == 0) + return NULL; + + current += strspn(current, WHITESPACE); + + if (*current == '\'') { + current ++; + *l = strcspn(current, "'"); + *state = current+*l; + + if (**state == '\'') + (*state)++; + } else if (*current == '\"') { + current ++; + *l = strcspn(current, "\""); + *state = current+*l; + + if (**state == '\"') + (*state)++; + } else { + *l = strcspn(current, WHITESPACE); + *state = current+*l; + } + + /* FIXME: Cannot deal with strings that have spaces AND ticks + * in them */ + + return (char*) current; +} + +const char *sigchld_code(int code) { + + if (code == CLD_EXITED) + return "exited"; + else if (code == CLD_KILLED) + return "killed"; + else if (code == CLD_DUMPED) + return "dumped"; + else if (code == CLD_TRAPPED) + return "trapped"; + else if (code == CLD_STOPPED) + return "stopped"; + else if (code == CLD_CONTINUED) + return "continued"; + + return "unknown"; +} + +int get_parent_of_pid(pid_t pid, pid_t *_ppid) { + int r; + FILE *f; + char fn[132], line[256], *p; + long long unsigned ppid; + + assert(pid >= 0); + assert(_ppid); + + assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1)); + fn[sizeof(fn)-1] = 0; + + if (!(f = fopen(fn, "r"))) + return -errno; + + if (!(fgets(line, sizeof(line), f))) { + r = -errno; + fclose(f); + return r; + } + + fclose(f); + + /* Let's skip the pid and comm fields. The latter is enclosed + * in () but does not escape any () in its value, so let's + * skip over it manually */ + + if (!(p = strrchr(line, ')'))) + return -EIO; + + p++; + + if (sscanf(p, " " + "%*c " /* state */ + "%llu ", /* ppid */ + &ppid) != 1) + return -EIO; + + if ((long long unsigned) (pid_t) ppid != ppid) + return -ERANGE; + + *_ppid = (pid_t) ppid; + + return 0; +} + +int write_one_line_file(const char *fn, const char *line) { + FILE *f; + int r; + + assert(fn); + assert(line); + + if (!(f = fopen(fn, "we"))) + return -errno; + + if (fputs(line, f) < 0) { + r = -errno; + goto finish; + } + + r = 0; +finish: + fclose(f); + return r; +} + +int read_one_line_file(const char *fn, char **line) { + FILE *f; + int r; + char t[64], *c; + + assert(fn); + assert(line); + + if (!(f = fopen(fn, "re"))) + return -errno; + + if (!(fgets(t, sizeof(t), f))) { + r = -errno; + goto finish; + } + + if (!(c = strdup(t))) { + r = -ENOMEM; + goto finish; + } + + *line = c; + r = 0; + +finish: + fclose(f); + return r; +} + +char *strappend(const char *s, const char *suffix) { + size_t a, b; + char *r; + + assert(s); + assert(suffix); + + a = strlen(s); + b = strlen(suffix); + + if (!(r = new(char, a+b+1))) + return NULL; + + memcpy(r, s, a); + memcpy(r+a, suffix, b); + r[a+b] = 0; + + return r; +} + +int readlink_malloc(const char *p, char **r) { + size_t l = 100; + + assert(p); + assert(r); + + for (;;) { + char *c; + ssize_t n; + + if (!(c = new(char, l))) + return -ENOMEM; + + if ((n = readlink(p, c, l-1)) < 0) { + int ret = -errno; + free(c); + return ret; + } + + if ((size_t) n < l-1) { + c[n] = 0; + *r = c; + return 0; + } + + free(c); + l *= 2; + } +} + +char *file_name_from_path(const char *p) { + char *r; + + assert(p); + + if ((r = strrchr(p, '/'))) + return r + 1; + + return (char*) p; +} + +bool path_is_absolute(const char *p) { + assert(p); + + return p[0] == '/'; +} + +bool is_path(const char *p) { + + return !!strchr(p, '/'); +} + +char *path_make_absolute(const char *p, const char *prefix) { + char *r; + + assert(p); + + if (path_is_absolute(p) || !prefix) + return strdup(p); + + if (asprintf(&r, "%s/%s", prefix, p) < 0) + return NULL; + + return r; +}