chiark / gitweb /
install: various improvements
[elogind.git] / src / util.c
index 5103cc6ce24fefb5846c9bcb958cf58148d79378..7f5fa05dca4d1beb15da5b82db6a6792198dec9b 100644 (file)
@@ -609,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;
@@ -633,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;
 
@@ -1182,6 +1197,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;
@@ -2687,6 +2707,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",