chiark / gitweb /
util: introduce /etc/os-release so that distros don't need to patch systemd to get...
[elogind.git] / src / util.c
index 98422b236d263cd9f0f7e1580e5b5696361c1ed7..861f9eaa437ba8c5fbe7f768979473cabfc8ee82 100644 (file)
@@ -2605,6 +2605,15 @@ int make_stdio(int fd) {
         return 0;
 }
 
+int make_null_stdio(void) {
+        int null_fd;
+
+        if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0)
+                return -errno;
+
+        return make_stdio(null_fd);
+}
+
 bool is_clean_exit(int code, int status) {
 
         if (code == CLD_EXITED)
@@ -2970,66 +2979,113 @@ void status_printf(const char *format, ...) {
 }
 
 void status_welcome(void) {
+        char *pretty_name = NULL, *ansi_color = NULL;
+        const char *const_pretty = NULL, *const_color = NULL;
+        int r;
 
-#if defined(TARGET_FEDORA)
-        char *r;
+        if ((r = parse_env_file("/etc/os-release", NEWLINE,
+                                "PRETTY_NAME", &pretty_name,
+                                "ANSI_COLOR", &ansi_color,
+                                NULL)) < 0) {
 
-        if (read_one_line_file("/etc/system-release", &r) < 0)
-                return;
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/os-release: %s", strerror(-r));
+        }
+
+#if defined(TARGET_FEDORA)
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/system-release", &pretty_name)) < 0) {
 
-        truncate_nl(r);
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/system-release: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        /* This tries to mimic the color magic the old Red Hat sysinit
-         * script did. */
+        if (!ansi_color && pretty_name) {
 
-        if (startswith(r, "Red Hat"))
-                status_printf("Welcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */
-        else if (startswith(r, "Fedora"))
-                status_printf("Welcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */
-        else
-                status_printf("Welcome to %s!\n", r);
+                /* This tries to mimic the color magic the old Red Hat sysinit
+                 * script did. */
 
-        free(r);
+                if (startswith(pretty_name, "Red Hat"))
+                        const_color = "0;31"; /* Red for RHEL */
+                else if (startswith(pretty_name, "Fedora"))
+                        const_color = "0;34"; /* Blue for Fedora */
+        }
 
 #elif defined(TARGET_SUSE)
-        char *r;
 
-        if (read_one_line_file("/etc/SuSE-release", &r) < 0)
-                return;
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/SuSE-release", &pretty_name)) < 0) {
 
-        truncate_nl(r);
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/SuSE-release: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */
-        free(r);
+        if (!ansi_color)
+                const_color = "0;32"; /* Green for openSUSE */
 
 #elif defined(TARGET_GENTOO)
-        char *r;
-
-        if (read_one_line_file("/etc/gentoo-release", &r) < 0)
-                return;
 
-        truncate_nl(r);
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/gentoo-release", &pretty_name)) < 0) {
 
-        status_printf("Welcome to \x1B[1;34m%s\x1B[0m!\n", r); /* Light Blue for Gentoo */
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/gentoo-release: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        free(r);
+        if (!ansi_color)
+                const_color = "1;34"; /* Light Blue for Gentoo */
 
 #elif defined(TARGET_DEBIAN)
-        char *r;
 
-        if (read_one_line_file("/etc/debian_version", &r) < 0)
-                return;
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/debian_version", &pretty_name)) < 0) {
+
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/debian_version: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        truncate_nl(r);
+        if (!ansi_color)
+                const_color = "1;31"; /* Light Red for Debian */
 
-        status_printf("Welcome to Debian \x1B[1;31m%s\x1B[0m!\n", r); /* Light Red for Debian */
+#elif defined(TARGET_UBUNTU)
+
+        if ((r = parse_env_file("/etc/lsb-release", NEWLINE,
+                                "DISTRIB_DESCRIPTION", &pretty_name,
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/lsb-release: %s", strerror(-r));
+        }
+
+        if (!ansi_color)
+                const_color = "0;33"; /* Orange/Brown for Ubuntu */
 
-        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."
+
+        if (!pretty_name)
+                const_pretty = "Arch Linux";
+
+        if (!ansi_color)
+                const_color = "1;36"; /* Cyan for Arch */
 #endif
+
+        if (!pretty_name && !const_pretty)
+                const_pretty = "Linux";
+
+        if (!ansi_color && !const_color)
+                const_color = "1";
+
+        status_printf("Welcome to \x1B[%sm%s\x1B[0m!\n",
+                      const_color ? const_color : ansi_color,
+                      const_pretty ? const_pretty : pretty_name);
 }
 
 char *replace_env(const char *format, char **env) {
@@ -3350,168 +3406,116 @@ int signal_from_string_try_harder(const char *s) {
         return signo;
 }
 
-int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase) {
-        struct termios old_termios, new_termios;
-        char passphrase[LINE_MAX];
-        size_t p = 0;
-        int r, ttyfd = -1, notify = -1;
-        struct pollfd pollfd[2];
-        bool reset_tty = false;
-        enum {
-                POLL_TTY,
-                POLL_INOTIFY
-        };
-
-        assert(message);
-        assert(_passphrase);
-
-        if (flag_file) {
-                if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-        }
+void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
 
-        if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) {
+        assert(f);
+        assert(name);
+        assert(t);
 
-                if (tcgetattr(ttyfd, &old_termios) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
+        if (!dual_timestamp_is_set(t))
+                return;
 
-                loop_write(ttyfd, "\x1B[1m", 4, false);
-                loop_write(ttyfd, message, strlen(message), false);
-                loop_write(ttyfd, ": ", 2, false);
-                loop_write(ttyfd, "\x1B[0m", 4, false);
+        fprintf(f, "%s=%llu %llu\n",
+                name,
+                (unsigned long long) t->realtime,
+                (unsigned long long) t->monotonic);
+}
 
-                new_termios = old_termios;
-                new_termios.c_lflag &= ~(ICANON|ECHO);
-                new_termios.c_cc[VMIN] = 1;
-                new_termios.c_cc[VTIME] = 0;
+void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
+        unsigned long long a, b;
 
-                if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
+        assert(value);
+        assert(t);
 
-                reset_tty = true;
+        if (sscanf(value, "%lli %llu", &a, &b) != 2)
+                log_debug("Failed to parse finish timestamp value %s", value);
+        else {
+                t->realtime = a;
+                t->monotonic = b;
         }
+}
 
-        zero(pollfd);
-
-        pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO;
-        pollfd[POLL_TTY].events = POLLIN;
-        pollfd[POLL_INOTIFY].fd = notify;
-        pollfd[POLL_INOTIFY].events = POLLIN;
+char *fstab_node_to_udev_node(const char *p) {
+        char *dn, *t, *u;
+        int r;
 
-        for (;;) {
-                char c;
-                int sleep_for = -1, k;
-                ssize_t n;
+        /* FIXME: to follow udev's logic 100% we need to leave valid
+         * UTF8 chars unescaped */
 
-                if (until > 0) {
-                        usec_t y;
+        if (startswith(p, "LABEL=")) {
 
-                        y = now(CLOCK_MONOTONIC);
+                if (!(u = unquote(p+6, "\"\'")))
+                        return NULL;
 
-                        if (y > until) {
-                                r = -ETIMEDOUT;
-                                goto finish;
-                        }
+                t = xescape(u, "/ ");
+                free(u);
 
-                        sleep_for = (int) ((until - y) / USEC_PER_MSEC);
-                }
+                if (!t)
+                        return NULL;
 
-                if (flag_file)
-                        if (access(flag_file, F_OK) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
+                r = asprintf(&dn, "/dev/disk/by-label/%s", t);
+                free(t);
 
-                if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) {
+                if (r < 0)
+                        return NULL;
 
-                        if (errno == EINTR)
-                                continue;
+                return dn;
+        }
 
-                        r = -errno;
-                        goto finish;
-                } else if (k == 0) {
-                        r = -ETIMEDOUT;
-                        goto finish;
-                }
+        if (startswith(p, "UUID=")) {
 
-                if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
-                        flush_fd(notify);
+                if (!(u = unquote(p+5, "\"\'")))
+                        return NULL;
 
-                if (pollfd[POLL_TTY].revents == 0)
-                        continue;
+                t = xescape(u, "/ ");
+                free(u);
 
-                if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) {
+                if (!t)
+                        return NULL;
 
-                        if (errno == EINTR || errno == EAGAIN)
-                                continue;
+                r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t));
+                free(t);
 
-                        r = -errno;
-                        goto finish;
+                if (r < 0)
+                        return NULL;
 
-                } else if (n == 0)
-                        break;
+                return dn;
+        }
 
-                if (c == '\n')
-                        break;
-                else if (c == 21) {
+        return strdup(p);
+}
 
-                        while (p > 0) {
-                                p--;
+void filter_environ(const char *prefix) {
+        int i, j;
+        assert(prefix);
 
-                                if (ttyfd >= 0)
-                                        loop_write(ttyfd, "\b \b", 3, false);
-                        }
+        if (!environ)
+                return;
 
-                } else if (c == '\b' || c == 127) {
-                        if (p > 0) {
-                                p--;
+        for (i = 0, j = 0; environ[i]; i++) {
 
-                                if (ttyfd >= 0)
-                                        loop_write(ttyfd, "\b \b", 3, false);
-                        }
-                } else {
-                        passphrase[p++] = c;
+                if (startswith(environ[i], prefix))
+                        continue;
 
-                        if (ttyfd >= 0)
-                                loop_write(ttyfd, "*", 1, false);
-                }
+                environ[j++] = environ[i];
         }
 
-        if (ttyfd >= 0)
-                loop_write(ttyfd, "\n", 1, false);
-
-        passphrase[p] = 0;
-
-        if (!(*_passphrase = strdup(passphrase))) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        environ[j] = NULL;
+}
 
-        r = 0;
+const char *default_term_for_tty(const char *tty) {
+        assert(tty);
 
-finish:
-        if (notify >= 0)
-                close_nointr_nofail(notify);
+        if (startswith(tty, "/dev/"))
+                tty += 5;
 
-        if (ttyfd >= 0) {
-                if (reset_tty)
-                        tcsetattr(ttyfd, TCSADRAIN, &old_termios);
+        if (startswith(tty, "tty") &&
+            tty[3] >= '0' && tty[3] <= '9')
+                return "TERM=linux";
 
-                close_nointr_nofail(ttyfd);
-        }
+        /* FIXME: Proper handling of /dev/console would be cool */
 
-        return r;
+        return "TERM=vt100-nav";
 }
 
 static const char *const ioprio_class_table[] = {