X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=ef37d05751bc4236834e3905e100338bd3af1c61;hp=cf3cf292a0a6149a817410ee36a4ce2fa87e61e8;hb=0b1724894fb85aa1c07b2619e9269cfafd736956;hpb=8a0867d6c5b47c8697d1ddd815116a548433c718 diff --git a/src/util.c b/src/util.c index cf3cf292a..ef37d0575 100644 --- a/src/util.c +++ b/src/util.c @@ -250,7 +250,7 @@ int parse_boolean(const char *v) { } int parse_pid(const char *s, pid_t* ret_pid) { - unsigned long ul; + unsigned long ul = 0; pid_t pid; int r; @@ -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,31 +2608,13 @@ int make_stdio(int fd) { return 0; } -bool is_clean_exit(int code, int status) { - - if (code == CLD_EXITED) - return status == 0; - - /* If a daemon does not implement handlers for some of the - * signals that's not considered an unclean shutdown */ - if (code == CLD_KILLED) - return - status == SIGHUP || - status == SIGINT || - status == SIGTERM || - status == SIGPIPE; +int make_null_stdio(void) { + int null_fd; - return false; -} - -bool is_clean_exit_lsb(int code, int status) { - - if (is_clean_exit(code, status)) - return true; + if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0) + return -errno; - return - code == CLD_EXITED && - (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED); + return make_stdio(null_fd); } bool is_device_path(const char *path) { @@ -2970,66 +2955,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)); + } + +#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; + if (!pretty_name) { + if ((r = read_one_line_file("/etc/gentoo-release", &pretty_name)) < 0) { - truncate_nl(r); + if (r != -ENOENT) + log_warning("Failed to read /etc/gentoo-release: %s", strerror(-r)); + } else + truncate_nl(pretty_name); + } - status_printf("Welcome to \x1B[1;34m%s\x1B[0m!\n", r); /* Light Blue for Gentoo */ - - 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; - truncate_nl(r); + if ((r = read_one_line_file("/etc/debian_version", &version)) < 0) { - status_printf("Welcome to Debian \x1B[1;31m%s\x1B[0m!\n", r); /* Light Red for Debian */ + 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); + + if (!pretty_name) + log_warning("Failed to allocate Debian version string."); + } + } + + if (!ansi_color) + const_color = "1;31"; /* 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." #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); + + free(ansi_color); + free(pretty_name); } char *replace_env(const char *format, char **env) { @@ -3266,6 +3302,44 @@ char *unquote(const char *s, const char* quotes) { return strdup(s); } +char *normalize_env_assignment(const char *s) { + char *name, *value, *p, *r; + + p = strchr(s, '='); + + if (!p) { + if (!(r = strdup(s))) + return NULL; + + return strstrip(r); + } + + if (!(name = strndup(s, p - s))) + return NULL; + + if (!(p = strdup(p+1))) { + free(name); + return NULL; + } + + value = unquote(strstrip(p), QUOTES); + free(p); + + if (!value) { + free(p); + free(name); + return NULL; + } + + if (asprintf(&r, "%s=%s", name, value) < 0) + r = NULL; + + free(value); + free(name); + + return r; +} + int wait_for_terminate(pid_t pid, siginfo_t *status) { assert(pid >= 1); assert(status); @@ -3319,6 +3393,8 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) { } void freeze(void) { + sync(); + for (;;) pause(); } @@ -3335,8 +3411,19 @@ bool null_or_empty(struct stat *st) { return false; } -DIR *xopendirat(int fd, const char *name) { - return fdopendir(openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)); +DIR *xopendirat(int fd, const char *name, int flags) { + int nfd; + DIR *d; + + if ((nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags)) < 0) + return NULL; + + if (!(d = fdopendir(nfd))) { + close_nointr_nofail(nfd); + return NULL; + } + + return d; } int signal_from_string_try_harder(const char *s) { @@ -3350,6 +3437,118 @@ int signal_from_string_try_harder(const char *s) { return signo; } +void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { + + assert(f); + assert(name); + assert(t); + + if (!dual_timestamp_is_set(t)) + return; + + fprintf(f, "%s=%llu %llu\n", + name, + (unsigned long long) t->realtime, + (unsigned long long) t->monotonic); +} + +void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { + unsigned long long a, b; + + assert(value); + assert(t); + + 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; + } +} + +char *fstab_node_to_udev_node(const char *p) { + char *dn, *t, *u; + int r; + + /* FIXME: to follow udev's logic 100% we need to leave valid + * UTF8 chars unescaped */ + + if (startswith(p, "LABEL=")) { + + if (!(u = unquote(p+6, "\"\'"))) + return NULL; + + t = xescape(u, "/ "); + free(u); + + if (!t) + return NULL; + + r = asprintf(&dn, "/dev/disk/by-label/%s", t); + free(t); + + if (r < 0) + return NULL; + + return dn; + } + + if (startswith(p, "UUID=")) { + + if (!(u = unquote(p+5, "\"\'"))) + return NULL; + + t = xescape(u, "/ "); + free(u); + + if (!t) + return NULL; + + r = asprintf(&dn, "/dev/disk/by-uuid/%s", t); + free(t); + + if (r < 0) + return NULL; + + return dn; + } + + return strdup(p); +} + +void filter_environ(const char *prefix) { + int i, j; + assert(prefix); + + if (!environ) + return; + + for (i = 0, j = 0; environ[i]; i++) { + + if (startswith(environ[i], prefix)) + continue; + + environ[j++] = environ[i]; + } + + environ[j] = NULL; +} + +const char *default_term_for_tty(const char *tty) { + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + if (startswith(tty, "tty") && + tty[3] >= '0' && tty[3] <= '9') + return "TERM=linux"; + + /* FIXME: Proper handling of /dev/console would be cool */ + + return "TERM=vt100"; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime",