X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=d12b5e772da601b9379e0c0efde09481564d7a56;hp=98422b236d263cd9f0f7e1580e5b5696361c1ed7;hb=22927a3654915670c6d2c7f2e60ea5f54cd2503d;hpb=ec863ba65a41e58680a3ab15841243088284e808 diff --git a/src/util.c b/src/util.c index 98422b236..d12b5e772 100644 --- a/src/util.c +++ b/src/util.c @@ -495,6 +495,9 @@ int write_one_line_file(const char *fn, const char *line) { goto finish; } + if (!endswith(line, "\n")) + fputc('\n', f); + r = 0; finish: fclose(f); @@ -2605,6 +2608,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 +2982,117 @@ 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)); + } - truncate_nl(r); +#if defined(TARGET_FEDORA) + if (!pretty_name) { + if ((r = read_one_line_file("/etc/system-release", &pretty_name)) < 0) { - /* This tries to mimic the color magic the old Red Hat sysinit - * script did. */ + if (r != -ENOENT) + log_warning("Failed to read /etc/system-release: %s", strerror(-r)); + } else + truncate_nl(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); + if (!ansi_color && pretty_name) { - free(r); + /* This tries to mimic the color magic the old Red Hat sysinit + * script did. */ + + 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) { + char *version; + if ((r = read_one_line_file("/etc/debian_version", &version)) < 0) { + + if (r != -ENOENT) + log_warning("Failed to read /etc/debian_version: %s", strerror(-r)); + } else { + truncate_nl(version); + pretty_name = strappend("Debian ", version); + free(version); + } + } - 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 +3413,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); +void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { - 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; - } - } - - 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); +char *fstab_node_to_udev_node(const char *p) { + char *dn, *t, *u; + int r; - pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO; - pollfd[POLL_TTY].events = POLLIN; - pollfd[POLL_INOTIFY].fd = notify; - pollfd[POLL_INOTIFY].events = POLLIN; + /* FIXME: to follow udev's logic 100% we need to leave valid + * UTF8 chars unescaped */ - for (;;) { - char c; - int sleep_for = -1, k; - ssize_t n; + if (startswith(p, "LABEL=")) { - if (until > 0) { - usec_t y; + if (!(u = unquote(p+6, "\"\'"))) + return NULL; - y = now(CLOCK_MONOTONIC); + t = xescape(u, "/ "); + free(u); - if (y > until) { - r = -ETIMEDOUT; - goto finish; - } - - 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[] = {