chiark / gitweb /
util: add Arch welcome message
[elogind.git] / src / util.c
index 2279efac493f1d9c7ebda2f6f60eb3217cc77a5b..93f982e8bcabd07436ec5a3306cef12f311d2466 100644 (file)
@@ -1,4 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
 /***
   This file is part of systemd.
@@ -48,6 +48,7 @@
 #include <pwd.h>
 #include <netinet/ip.h>
 #include <linux/kd.h>
+#include <dlfcn.h>
 
 #include "macro.h"
 #include "util.h"
 #include "missing.h"
 #include "log.h"
 #include "strv.h"
-
-#if HAVE_SELINUX
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-
-static struct selabel_handle *label_hnd = NULL;
-
-static inline int use_selinux(void) {
-        static int use_selinux_ind = -1;
-
-        if (use_selinux_ind == -1)
-                use_selinux_ind = (is_selinux_enabled() == 1);
-
-        return use_selinux_ind;
-}
-
-static int label_get_file_label_from_path(
-                const char *label,
-                const char *path,
-                const char *class,
-                security_context_t *fcon) {
-
-        security_context_t dir_con = NULL;
-        security_class_t sclass;
-        int r = 0;
-
-        r = getfilecon(path, &dir_con);
-        if (r >= 0) {
-                r = -1;
-                if ((sclass = string_to_security_class(class)) != 0)
-                        r = security_compute_create((security_context_t) label, dir_con, sclass, fcon);
-        }
-        if (r < 0)
-                r = -errno;
-
-        freecon(dir_con);
-        return r;
-}
-
-#endif
-
-int label_init(void) {
-        int r = 0;
-
-#if HAVE_SELINUX
-        if (use_selinux()) {
-                label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
-                if (!label_hnd) {
-                        log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, "Failed to initialize SELinux context: %m");
-                        r = (security_getenforce() == 1) ? -errno : 0;
-                }
-        }
-#endif
-
-        return r;
-}
-
-int label_fix(const char *path) {
-        int r = 0;
-#if HAVE_SELINUX
-        struct stat st;
-        security_context_t fcon;
-        if (use_selinux()) {
-                r = lstat(path, &st);
-
-                if (r == 0) {
-                        r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
-
-                        if (r == 0) {
-                                r = setfilecon(path, fcon);
-                                freecon(fcon);
-                        }
-                }
-                if (r < 0) {
-                        log_error("Unable to fix label of %s: %m", path);
-                        r = (security_getenforce() == 1) ? -errno : 0;
-                }
-        }
-#endif
-        return r;
-}
-
-void label_finish(void) {
-
-#if HAVE_SELINUX
-        if (use_selinux())
-                selabel_close(label_hnd);
-#endif
-
-}
-
-int label_get_socket_label_from_exe(
-        const char *exe,
-        char **label) {
-        int r = 0;
-
-#if HAVE_SELINUX
-        security_context_t mycon = NULL, fcon = NULL;
-        security_class_t sclass;
-
-        r = getcon(&mycon);
-        if (r < 0)
-                goto fail;
-
-        r = getfilecon(exe, &fcon);
-        if (r < 0)
-                goto fail;
-
-        sclass = string_to_security_class("process");
-        r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
-        if (r == 0)
-                log_debug("SELinux Socket context for %s will be set to %s", exe, *label);
-
-fail:
-        if (r< 0 && security_getenforce() == 1)
-                r = -errno;
-
-        freecon(mycon);
-        freecon(fcon);
-#endif
-
-        return r;
-}
-
-int label_fifofile_set(const char *label, const char *path) {
-        int r = 0;
-
-#if HAVE_SELINUX
-        security_context_t filecon = NULL;
-        if (use_selinux() && label) {
-                if (((r = label_get_file_label_from_path(label, path, "fifo_file", &filecon)) == 0)) {
-                        if ((r = setfscreatecon(filecon)) < 0) {
-                                log_error("Failed to set SELinux file context (%s) on %s: %m", label, path);
-                                r = -errno;
-                        }
-
-                        freecon(filecon);
-                }
-
-                if (r < 0  && security_getenforce() == 0)
-                        r = 0;
-        }
-#endif
-
-        return r;
-}
-
-int label_socket_set(const char *label) {
-
-#if HAVE_SELINUX
-        if (use_selinux() && setsockcreatecon((security_context_t) label) < 0) {
-                log_error("Failed to set SELinux context (%s) on socket: %m", label);
-                if (security_getenforce() == 1)
-                        return -errno;
-        }
-#endif
-
-        return 0;
-}
-
-void label_file_clear(void) {
-
-#if HAVE_SELINUX
-        if (use_selinux())
-                setfscreatecon(NULL);
-#endif
-
-        return;
-}
-
-void label_free(const char *label) {
-
-#if HAVE_SELINUX
-        if (use_selinux())
-                freecon((security_context_t) label);
-#endif
-
-        return;
-}
-
-void label_socket_clear(void) {
-
-#if HAVE_SELINUX
-        if (use_selinux())
-                setsockcreatecon(NULL);
-#endif
-
-        return;
-}
-
-static int label_mkdir(
-        const char *path,
-        mode_t mode) {
-
-#if HAVE_SELINUX
-        int r;
-        security_context_t fcon = NULL;
-
-        if (use_selinux()) {
-                if (path[0] == '/') {
-                        r = selabel_lookup_raw(label_hnd, &fcon, path, mode);
-                }
-                else {
-                        char *cwd = NULL;
-                        char *newpath = NULL;
-                        cwd = getcwd(NULL,0);
-                        if ((! cwd) || (asprintf(&newpath, "%s/%s",cwd,path) < 0)) {
-                                free(cwd);
-                                return -errno;
-                        }
-                        r = selabel_lookup_raw(label_hnd, &fcon, newpath, mode);
-                        free(cwd);
-                        free(newpath);
-                }
-
-                if (r == 0)
-                        r = setfscreatecon(fcon);
-
-                if ((r < 0) && (errno != ENOENT)) {
-                        log_error("Failed to set security context %s for %s", fcon, path);
-
-                        if (security_getenforce() == 1)
-                                goto finish;
-                }
-        }
-        r = mkdir(path, mode);
-
-finish:
-        if (use_selinux()) {
-                setfscreatecon(NULL);
-                freecon(fcon);
-        }
-
-        return r;
-#else
-        return mkdir(path, mode);
-#endif
-}
+#include "label.h"
+#include "exit-status.h"
 
 bool streq_ptr(const char *a, const char *b) {
 
@@ -1894,6 +1659,63 @@ char *format_timestamp(char *buf, size_t l, usec_t t) {
         return buf;
 }
 
+char *format_timestamp_pretty(char *buf, size_t l, usec_t t) {
+        usec_t n, d;
+
+        n = now(CLOCK_REALTIME);
+
+        if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
+                return NULL;
+
+        d = n - t;
+
+        if (d >= USEC_PER_YEAR)
+                snprintf(buf, l, "%llu years and %llu months ago",
+                         (unsigned long long) (d / USEC_PER_YEAR),
+                         (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
+        else if (d >= USEC_PER_MONTH)
+                snprintf(buf, l, "%llu months and %llu days ago",
+                         (unsigned long long) (d / USEC_PER_MONTH),
+                         (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
+        else if (d >= USEC_PER_WEEK)
+                snprintf(buf, l, "%llu weeks and %llu days ago",
+                         (unsigned long long) (d / USEC_PER_WEEK),
+                         (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
+        else if (d >= 2*USEC_PER_DAY)
+                snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
+        else if (d >= 25*USEC_PER_HOUR)
+                snprintf(buf, l, "1 day and %lluh ago",
+                         (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
+        else if (d >= 6*USEC_PER_HOUR)
+                snprintf(buf, l, "%lluh ago",
+                         (unsigned long long) (d / USEC_PER_HOUR));
+        else if (d >= USEC_PER_HOUR)
+                snprintf(buf, l, "%lluh %llumin ago",
+                         (unsigned long long) (d / USEC_PER_HOUR),
+                         (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
+        else if (d >= 5*USEC_PER_MINUTE)
+                snprintf(buf, l, "%llumin ago",
+                         (unsigned long long) (d / USEC_PER_MINUTE));
+        else if (d >= USEC_PER_MINUTE)
+                snprintf(buf, l, "%llumin %llus ago",
+                         (unsigned long long) (d / USEC_PER_MINUTE),
+                         (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
+        else if (d >= USEC_PER_SEC)
+                snprintf(buf, l, "%llus ago",
+                         (unsigned long long) (d / USEC_PER_SEC));
+        else if (d >= USEC_PER_MSEC)
+                snprintf(buf, l, "%llums ago",
+                         (unsigned long long) (d / USEC_PER_MSEC));
+        else if (d > 0)
+                snprintf(buf, l, "%lluus ago",
+                         (unsigned long long) d);
+        else
+                snprintf(buf, l, "now");
+
+        buf[l-1] = 0;
+        return buf;
+}
+
 char *format_timespan(char *buf, size_t l, usec_t t) {
         static const struct {
                 const char *suffix;
@@ -1917,6 +1739,12 @@ char *format_timespan(char *buf, size_t l, usec_t t) {
         if (t == (usec_t) -1)
                 return NULL;
 
+        if (t == 0) {
+                snprintf(p, l, "0");
+                p[l-1] = 0;
+                return p;
+        }
+
         /* The result of this function can be parsed with parse_usec */
 
         for (i = 0; i < ELEMENTSOF(table); i++) {
@@ -2089,9 +1917,9 @@ int reset_terminal(int fd) {
 
         assert(fd >= 0);
 
-        /* First, unlock termios */
-        zero(termios);
-        ioctl(fd, TIOCSLCKTRMIOS, &termios);
+        /* We leave locked terminal attributes untouched, so that
+         * Plymouth may set whatever it wants to set, and we don't
+         * interfere with that. */
 
         /* Disable exclusive mode, just in case */
         ioctl(fd, TIOCNXCL);
@@ -2628,6 +2456,16 @@ bool is_clean_exit(int code, int status) {
         return false;
 }
 
+bool is_clean_exit_lsb(int code, int status) {
+
+        if (is_clean_exit(code, status))
+                return true;
+
+        return
+                code == CLD_EXITED &&
+                (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED);
+}
+
 bool is_device_path(const char *path) {
 
         /* Returns true on paths that refer to a device, either in
@@ -2723,18 +2561,6 @@ char* gethostname_malloc(void) {
         return strdup(u.sysname);
 }
 
-int getmachineid_malloc(char **b) {
-        int r;
-
-        assert(b);
-
-        if ((r = read_one_line_file("/var/lib/dbus/machine-id", b)) < 0)
-                return r;
-
-        strstrip(*b);
-        return 0;
-}
-
 char* getlogname_malloc(void) {
         uid_t uid;
         long bufsize;
@@ -2773,11 +2599,12 @@ char* getlogname_malloc(void) {
 
 int getttyname_malloc(char **r) {
         char path[PATH_MAX], *p, *c;
+        int k;
 
         assert(r);
 
-        if (ttyname_r(STDIN_FILENO, path, sizeof(path)) < 0)
-                return -errno;
+        if ((k = ttyname_r(STDIN_FILENO, path, sizeof(path))) != 0)
+                return -k;
 
         char_array_0(path);
 
@@ -3008,6 +2835,32 @@ void status_welcome(void) {
 
         status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */
         free(r);
+
+#elif defined(TARGET_GENTOO)
+        char *r;
+
+        if (read_one_line_file("/etc/gentoo-release", &r) < 0)
+                return;
+
+        truncate_nl(r);
+
+        status_printf("Welcome to \x1B[1;34m%s\x1B[0m!\n", r); /* Light Blue for Gentoo */
+
+        free(r);
+
+#elif defined(TARGET_DEBIAN)
+       char *r;
+
+       if (read_one_line_file("/etc/debian_version", &r) < 0)
+               return;
+
+       truncate_nl(r);
+
+       status_printf("Welcome to Debian \x1B[1;31m%s\x1B[0m!\n", r); /* Light Red for Debian */
+
+       free(r);
+#elif defined(TARGET_ARCH)
+       status_printf("Welcome to \x1B[1;36mArch Linux\x1B[0m!\n"); /* Cyan for Arch */
 #else
 #warning "You probably should add a welcome text logic here."
 #endif
@@ -3060,18 +2913,18 @@ char *replace_env(const char *format, char **env) {
 
                 case VARIABLE:
                         if (*e == '}') {
-                                char *t;
+                                const char *t;
 
-                                if ((t = strv_env_get_with_length(env, word+2, e-word-2))) {
-                                        if (!(k = strappend(r, t)))
-                                                goto fail;
+                                if (!(t = strv_env_get_with_length(env, word+2, e-word-2)))
+                                        t = "";
 
-                                        free(r);
-                                        r = k;
+                                if (!(k = strappend(r, t)))
+                                        goto fail;
 
-                                        word = e+1;
-                                }
+                                free(r);
+                                r = k;
 
+                                word = e+1;
                                 state = WORD;
                         }
                         break;
@@ -3101,36 +2954,39 @@ char **replace_env_argv(char **argv, char **env) {
         STRV_FOREACH(i, argv) {
 
                 /* If $FOO appears as single word, replace it by the split up variable */
-                if ((*i)[0] == '$') {
-                        char *e = strv_env_get(env, *i+1);
+                if ((*i)[0] == '$' && (*i)[1] != '{') {
+                        char *e;
+                        char **w, **m;
+                        unsigned q;
 
-                        if (e) {
-                                char **w, **m;
-                                unsigned q;
+                        if ((e = strv_env_get(env, *i+1))) {
 
                                 if (!(m = strv_split_quoted(e))) {
                                         r[k] = NULL;
                                         strv_free(r);
                                         return NULL;
                                 }
+                        } else
+                                m = NULL;
 
-                                q = strv_length(m);
-                                l = l + q - 1;
+                        q = strv_length(m);
+                        l = l + q - 1;
 
-                                if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
-                                        r[k] = NULL;
-                                        strv_free(r);
-                                        strv_free(m);
-                                        return NULL;
-                                }
+                        if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
+                                r[k] = NULL;
+                                strv_free(r);
+                                strv_free(m);
+                                return NULL;
+                        }
 
-                                r = w;
+                        r = w;
+                        if (m) {
                                 memcpy(r + k, m, q * sizeof(char*));
                                 free(m);
-
-                                k += q;
-                                continue;
                         }
+
+                        k += q;
+                        continue;
                 }
 
                 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
@@ -3158,7 +3014,7 @@ int columns(void) {
                 struct winsize ws;
                 zero(ws);
 
-                if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
+                if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
                         parsed_columns = ws.ws_col;
         }
 
@@ -3219,6 +3075,31 @@ char *ellipsize(const char *s, unsigned length, unsigned percent) {
         return r;
 }
 
+int touch(const char *path) {
+        int fd;
+
+        assert(path);
+
+        if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0)
+                return -errno;
+
+        close_nointr_nofail(fd);
+        return 0;
+}
+
+char *unquote(const char *s, const char quote) {
+        size_t l;
+        assert(s);
+
+        if ((l = strlen(s)) < 2)
+                return strdup(s);
+
+        if (s[0] == quote && s[l-1] == quote)
+                return strndup(s+1, l-2);
+
+        return strdup(s);
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",