X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Futil.c;h=7f5fa05dca4d1beb15da5b82db6a6792198dec9b;hb=4627d39661ffcdd11e814650dfcc9ac3d0d0ec0b;hp=774f061efc5cdbd385b6967db63d6a66106be2e7;hpb=c846ff4798c4c48d229587297e6df8b593c60c54;p=elogind.git diff --git a/src/util.c b/src/util.c index 774f061ef..7f5fa05dc 100644 --- a/src/util.c +++ b/src/util.c @@ -307,40 +307,6 @@ int safe_atoi(const char *s, int *ret_i) { 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; @@ -394,7 +360,8 @@ char *split(const char *c, size_t *l, const char *separator, char **state) { /* 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; + char *current, *e; + bool escaped = false; current = *state ? *state : (char*) c; @@ -405,26 +372,45 @@ char *split_quoted(const char *c, size_t *l, char **state) { if (*current == '\'') { current ++; - *l = strcspn(current, "'"); - *state = current+*l; - if (**state == '\'') - (*state)++; + for (e = current; *e; e++) { + if (escaped) + escaped = false; + else if (*e == '\\') + escaped = true; + else if (*e == '\'') + break; + } + + *l = e-current; + *state = *e == 0 ? e : e+1; } else if (*current == '\"') { current ++; - *l = strcspn(current, "\""); - *state = current+*l; - if (**state == '\"') - (*state)++; + for (e = current; *e; e++) { + if (escaped) + escaped = false; + else if (*e == '\\') + escaped = true; + else if (*e == '\"') + break; + } + + *l = e-current; + *state = *e == 0 ? e : e+1; } else { - *l = strcspn(current, WHITESPACE); - *state = current+*l; + for (e = current; *e; e++) { + if (escaped) + escaped = false; + else if (*e == '\\') + escaped = true; + else if (strchr(WHITESPACE, *e)) + break; + } + *l = e-current; + *state = e; } - /* FIXME: Cannot deal with strings that have spaces AND ticks - * in them */ - return (char*) current; } @@ -623,19 +609,30 @@ int get_process_cmdline(pid_t pid, size_t max_length, char **line) { fclose(f); + if (r[0] == 0) + return get_process_name(pid, line); + *line = r; return 0; } -char *strappend(const char *s, const char *suffix) { - size_t a, b; +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; char *r; + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + assert(s); assert(suffix); a = strlen(s); - b = strlen(suffix); if (!(r = new(char, a+b+1))) return NULL; @@ -647,6 +644,10 @@ char *strappend(const char *s, const char *suffix) { return r; } +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + int readlink_malloc(const char *p, char **r) { size_t l = 100; @@ -1143,7 +1144,7 @@ char *cescape(const char *s) { return r; } -char *cunescape(const char *s) { +char *cunescape_length(const char *s, size_t length) { char *r, *t; const char *f; @@ -1151,10 +1152,10 @@ char *cunescape(const char *s) { /* Undoes C style string escaping */ - if (!(r = new(char, strlen(s)+1))) + if (!(r = new(char, length+1))) return r; - for (f = s, t = r; *f; f++) { + for (f = s, t = r; f < s + length; f++) { if (*f != '\\') { *(t++) = *f; @@ -1196,6 +1197,11 @@ char *cunescape(const char *s) { *(t++) = '\''; break; + case 's': + /* This is an extension of the XDG syntax files */ + *(t++) = ' '; + break; + case 'x': { /* hexadecimal encoding */ int a, b; @@ -1246,7 +1252,7 @@ char *cunescape(const char *s) { default: /* Invalid escape code, let's take it literal then */ *(t++) = '\\'; - *(t++) = 'f'; + *(t++) = *f; break; } } @@ -1256,6 +1262,9 @@ finish: return r; } +char *cunescape(const char *s) { + return cunescape_length(s, strlen(s)); +} char *xescape(const char *s, const char *bad) { char *r, *t; @@ -2675,11 +2684,11 @@ void status_welcome(void) { * script did. */ if (startswith(r, "Red Hat")) - status_printf("\tWelcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */ + status_printf("Welcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */ else if (startswith(r, "Fedora")) - status_printf("\tWelcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */ + status_printf("Welcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */ else - status_printf("\tWelcome to %s!\n", r); + status_printf("Welcome to %s!\n", r); free(r); @@ -2691,13 +2700,150 @@ void status_welcome(void) { truncate_nl(r); - status_printf("\tWelcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */ + status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */ free(r); #else #warning "You probably should add a welcome text logic here." #endif } +char *replace_env(const char *format, char **env) { + enum { + WORD, + DOLLAR, + VARIABLE + } state = WORD; + + const char *e, *word = format; + char *r = NULL, *k; + + assert(format); + + for (e = format; *e; e ++) { + + switch (state) { + + case WORD: + if (*e == '$') + state = DOLLAR; + break; + + case DOLLAR: + if (*e == '(') { + if (!(k = strnappend(r, word, e-word-1))) + goto fail; + + free(r); + r = k; + + word = e-1; + state = VARIABLE; + + } else if (*e == '$') { + if (!(k = strnappend(r, word, e-word))) + goto fail; + + free(r); + r = k; + + word = e+1; + state = WORD; + } else + state = WORD; + break; + + case VARIABLE: + if (*e == ')') { + char *t; + + if ((t = strv_env_get_with_length(env, word+2, e-word-2))) { + if (!(k = strappend(r, t))) + goto fail; + + free(r); + r = k; + + word = e+1; + } + + state = WORD; + } + break; + } + } + + if (!(k = strnappend(r, word, e-word))) + goto fail; + + free(r); + return k; + +fail: + free(r); + return NULL; +} + +char **replace_env_argv(char **argv, char **env) { + char **r, **i; + unsigned k = 0; + + if (!(r = new(char*, strv_length(argv)+1))) + return NULL; + + STRV_FOREACH(i, argv) { + if (!(r[k++] = replace_env(*i, env))) { + strv_free(r); + return NULL; + } + } + + r[k] = NULL; + return r; +} + +int columns(void) { + static __thread int parsed_columns = 0; + const char *e; + + if (parsed_columns > 0) + return parsed_columns; + + if ((e = getenv("COLUMNS"))) + parsed_columns = atoi(e); + + if (parsed_columns <= 0) { + struct winsize ws; + zero(ws); + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) + parsed_columns = ws.ws_col; + } + + if (parsed_columns <= 0) + parsed_columns = 80; + + return parsed_columns; +} + +int running_in_chroot(void) { + struct stat a, b; + + zero(a); + zero(b); + + /* Only works as root */ + + if (stat("/proc/1/root", &a) < 0) + return -errno; + + if (stat("/", &b) < 0) + return -errno; + + return + a.st_dev != b.st_dev || + a.st_ino != b.st_ino; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime",