X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=519d22902ae2f4e9edba6bf50e245a944db407b1;hp=5103cc6ce24fefb5846c9bcb958cf58148d79378;hb=4445a8755774550cd5f1b41fb6067b07374a4163;hpb=6febfd0d4bdf7519e119149b8d8ec03c210aed1d diff --git a/src/util.c b/src/util.c index 5103cc6ce..519d22902 100644 --- a/src/util.c +++ b/src/util.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "macro.h" #include "util.h" @@ -609,19 +610,44 @@ int get_process_cmdline(pid_t pid, size_t max_length, char **line) { fclose(f); + /* Kernel threads have no argv[] */ + if (r[0] == 0) { + char *t; + int h; + + free(r); + + if ((h = get_process_name(pid, &t)) < 0) + return h; + + h = asprintf(&r, "[%s]", t); + free(t); + + if (h < 0) + return -ENOMEM; + } + *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; @@ -633,6 +659,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; @@ -683,6 +713,48 @@ int readlink_and_make_absolute(const char *p, char **r) { return 0; } +int parent_of_path(const char *path, char **_r) { + const char *e, *a = NULL, *b = NULL, *p; + char *r; + bool slash = false; + + assert(path); + assert(_r); + + if (!*path) + return -EINVAL; + + for (e = path; *e; e++) { + + if (!slash && *e == '/') { + a = b; + b = e; + slash = true; + } else if (slash && *e != '/') + slash = false; + } + + if (*(e-1) == '/') + p = a; + else + p = b; + + if (!p) + return -EINVAL; + + if (p == path) + r = strdup("/"); + else + r = strndup(path, p-path); + + if (!r) + return -ENOMEM; + + *_r = r; + return 0; +} + + char *file_name_from_path(const char *p) { char *r; @@ -941,7 +1013,6 @@ int mkdir_parents(const char *path, mode_t mode) { return -ENOMEM; r = mkdir(t, mode); - free(t); if (r < 0 && errno != EEXIST) @@ -957,7 +1028,7 @@ int mkdir_p(const char *path, mode_t mode) { if ((r = mkdir_parents(path, mode)) < 0) return r; - if (mkdir(path, mode) < 0) + if (mkdir(path, mode) < 0 && errno != EEXIST) return -errno; return 0; @@ -1182,6 +1253,11 @@ char *cunescape_length(const char *s, size_t length) { *(t++) = '\''; break; + case 's': + /* This is an extension of the XDG syntax files */ + *(t++) = ' '; + break; + case 'x': { /* hexadecimal encoding */ int a, b; @@ -1769,10 +1845,22 @@ int ask(char *ret, const char *replies, const char *text, ...) { int reset_terminal(int fd) { struct termios termios; int r = 0; + long arg; + + /* Set terminal to some sane defaults */ assert(fd >= 0); - /* Set terminal to some sane defaults */ + /* First, unlock termios */ + zero(termios); + ioctl(fd, TIOCSLCKTRMIOS, &termios); + + /* Disable exclusive mode, just in case */ + ioctl(fd, TIOCNXCL); + + /* Enable console unicode mode */ + arg = K_UNICODE; + ioctl(fd, KDSKBMODE, &arg); if (tcgetattr(fd, &termios) < 0) { r = -errno; @@ -1955,7 +2043,7 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst } if (e.wd != wd || !(e.mask & IN_CLOSE)) { - r = -errno; + r = -EIO; goto fail; } @@ -2182,25 +2270,24 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { int path_is_mount_point(const char *t) { struct stat a, b; - char *copy; + char *parent; + int r; if (lstat(t, &a) < 0) { - if (errno == ENOENT) return 0; return -errno; } - if (!(copy = strdup(t))) - return -ENOMEM; + if ((r = parent_of_path(t, &parent)) < 0) + return r; - if (lstat(dirname(copy), &b) < 0) { - free(copy); - return -errno; - } + r = lstat(parent, &b); + free(parent); - free(copy); + if (r < 0) + return -errno; return a.st_dev != b.st_dev; } @@ -2478,7 +2565,8 @@ static int rm_rf_children(int fd, bool only_dirs) { if (!(d = fdopendir(fd))) { close_nointr_nofail(fd); - return -errno; + + return errno == ENOENT ? 0 : -errno; } for (;;) { @@ -2502,7 +2590,7 @@ static int rm_rf_children(int fd, bool only_dirs) { struct stat st; if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { - if (ret == 0) + if (ret == 0 && errno != ENOENT) ret = -errno; continue; } @@ -2515,7 +2603,7 @@ static int rm_rf_children(int fd, bool only_dirs) { int subdir_fd; if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) { - if (ret == 0) + if (ret == 0 && errno != ENOENT) ret = -errno; continue; } @@ -2526,13 +2614,13 @@ static int rm_rf_children(int fd, bool only_dirs) { } if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { - if (ret == 0) + if (ret == 0 && errno != ENOENT) ret = -errno; } } else if (!only_dirs) { if (unlinkat(fd, de->d_name, 0) < 0) { - if (ret == 0) + if (ret == 0 && errno != ENOENT) ret = -errno; } } @@ -2687,6 +2775,143 @@ void status_welcome(void) { #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", @@ -2784,3 +3009,39 @@ static const char* const ip_tos_table[] = { }; DEFINE_STRING_TABLE_LOOKUP(ip_tos, int); + +static const char *const signal_table[] = { + [SIGHUP] = "HUP", + [SIGINT] = "INT", + [SIGQUIT] = "QUIT", + [SIGILL] = "ILL", + [SIGTRAP] = "TRAP", + [SIGABRT] = "ABRT", + [SIGBUS] = "BUS", + [SIGFPE] = "FPE", + [SIGKILL] = "KILL", + [SIGUSR1] = "USR1", + [SIGSEGV] = "SEGV", + [SIGUSR2] = "USR2", + [SIGPIPE] = "PIPE", + [SIGALRM] = "ALRM", + [SIGTERM] = "TERM", + [SIGSTKFLT] = "STKFLT", + [SIGCHLD] = "CHLD", + [SIGCONT] = "CONT", + [SIGSTOP] = "STOP", + [SIGTSTP] = "TSTP", + [SIGTTIN] = "TTIN", + [SIGTTOU] = "TTOU", + [SIGURG] = "URG", + [SIGXCPU] = "XCPU", + [SIGXFSZ] = "XFSZ", + [SIGVTALRM] = "VTALRM", + [SIGPROF] = "PROF", + [SIGWINCH] = "WINCH", + [SIGIO] = "IO", + [SIGPWR] = "PWR", + [SIGSYS] = "SYS" +}; + +DEFINE_STRING_TABLE_LOOKUP(signal, int);