X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=9a82c71dcb249b1e268f8959385fecbc05782f59;hp=c1ee936aaf97d7166d26bc9dcb863d5243f8abc2;hb=ade509ce73ba1de3bcda8b012961a3045f721df7;hpb=e7db37dd19d540e9ac8b89c689914d44d15433c4 diff --git a/src/util.c b/src/util.c index c1ee936aa..9a82c71dc 100644 --- a/src/util.c +++ b/src/util.c @@ -600,13 +600,13 @@ finish: int parse_env_file( const char *fname, - const char *seperator, ...) { + const char *separator, ...) { - int r; + int r = 0; char *contents, *p; assert(fname); - assert(seperator); + assert(separator); if ((r = read_full_file(fname, &contents)) < 0) return r; @@ -615,7 +615,7 @@ int parse_env_file( for (;;) { const char *key = NULL; - p += strspn(p, seperator); + p += strspn(p, separator); p += strspn(p, WHITESPACE); if (!*p) @@ -625,7 +625,7 @@ int parse_env_file( va_list ap; char **value; - va_start(ap, seperator); + va_start(ap, separator); while ((key = va_arg(ap, char *))) { size_t n; char *v; @@ -638,7 +638,7 @@ int parse_env_file( continue; p += n + 1; - n = strcspn(p, seperator); + n = strcspn(p, separator); if (n >= 2 && strchr(QUOTES, p[0]) && @@ -653,21 +653,27 @@ int parse_env_file( goto fail; } + if (v[0] == '\0') { + /* return empty value strings as NULL */ + free(v); + v = NULL; + } + free(*value); *value = v; p += n; + + r ++; break; } va_end(ap); } if (!key) - p += strcspn(p, seperator); + p += strcspn(p, separator); } - r = 0; - fail: free(contents); return r; @@ -1675,6 +1681,8 @@ bool ignore_file(const char *filename) { return filename[0] == '.' || streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || endswith(filename, "~") || endswith(filename, ".rpmnew") || endswith(filename, ".rpmsave") || @@ -2009,23 +2017,29 @@ int read_one_char(FILE *f, char *ret, bool *need_nl) { } int ask(char *ret, const char *replies, const char *text, ...) { + bool on_tty; + assert(ret); assert(replies); assert(text); + on_tty = isatty(STDOUT_FILENO); + for (;;) { va_list ap; char c; int r; bool need_nl = true; - fputs("\x1B[1m", stdout); + if (on_tty) + fputs("\x1B[1m", stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - fputs("\x1B[0m", stdout); + if (on_tty) + fputs("\x1B[0m", stdout); fflush(stdout); @@ -2235,26 +2249,34 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst assert(notify >= 0); for (;;) { - struct inotify_event e; + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; ssize_t l; + struct inotify_event *e; + + if ((l = read(notify, &inotify_buffer, sizeof(inotify_buffer))) < 0) { - if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) { + if (errno == EINTR) + continue; - if (l < 0) { + r = -errno; + goto fail; + } - if (errno == EINTR) - continue; + e = (struct inotify_event*) inotify_buffer; + + while (l > 0) { + size_t step; - r = -errno; - } else + if (e->wd != wd || !(e->mask & IN_CLOSE)) { r = -EIO; + goto fail; + } - goto fail; - } + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) l); - if (e.wd != wd || !(e.mask & IN_CLOSE)) { - r = -EIO; - goto fail; + e = (struct inotify_event*) ((uint8_t*) e + step); + l -= step; } break; @@ -2583,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) @@ -3003,6 +3034,20 @@ void status_welcome(void) { status_printf("Welcome to Debian \x1B[1;31m%s\x1B[0m!\n", r); /* Light Red for Debian */ free(r); +#elif defined(TARGET_UBUNTU) + char *desc = NULL; + char *codename = NULL; + + if (parse_env_file("/etc/lsb-release", NEWLINE, + "DISTRIB_DESCRIPTION", &desc, + "DISTRIB_CODENAME", &codename, NULL) < 0) + return; + if (desc && codename) + /* Light Red for Ubuntu */ + status_printf("Welcome to \x1B[1;31m%s\x1B[0m (%s)\n", + desc, codename); + free(desc); + free(codename); #elif defined(TARGET_ARCH) status_printf("Welcome to \x1B[1;36mArch Linux\x1B[0m!\n"); /* Cyan for Arch */ #else @@ -3296,6 +3341,232 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) { } +void freeze(void) { + for (;;) + pause(); +} + +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + return true; + + return false; +} + +DIR *xopendirat(int fd, const char *name) { + return fdopendir(openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)); +} + +int signal_from_string_try_harder(const char *s) { + int signo; + assert(s); + + if ((signo = signal_from_string(s)) <= 0) + if (startswith(s, "SIG")) + return signal_from_string(s+3); + + 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|IN_NONBLOCK)) < 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) { + + if (tcgetattr(ttyfd, &old_termios) < 0) { + r = -errno; + goto finish; + } + + 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); + + new_termios = old_termios; + new_termios.c_lflag &= ~(ICANON|ECHO); + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + + if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) { + r = -errno; + goto finish; + } + + reset_tty = true; + } + + 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; + + for (;;) { + char c; + int sleep_for = -1, k; + ssize_t n; + + if (until > 0) { + usec_t y; + + y = now(CLOCK_MONOTONIC); + + if (y > until) { + r = -ETIMEDOUT; + goto finish; + } + + sleep_for = (int) ((until - y) / USEC_PER_MSEC); + } + + if (flag_file) + if (access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } + + if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } else if (k == 0) { + r = -ETIMEDOUT; + goto finish; + } + + if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[POLL_TTY].revents == 0) + continue; + + if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + r = -errno; + goto finish; + + } else if (n == 0) + break; + + if (c == '\n') + break; + else if (c == 21) { + + while (p > 0) { + p--; + + if (ttyfd >= 0) + loop_write(ttyfd, "\b \b", 3, false); + } + + } else if (c == '\b' || c == 127) { + if (p > 0) { + p--; + + if (ttyfd >= 0) + loop_write(ttyfd, "\b \b", 3, false); + } + } else { + passphrase[p++] = c; + + if (ttyfd >= 0) + loop_write(ttyfd, "*", 1, false); + } + } + + if (ttyfd >= 0) + loop_write(ttyfd, "\n", 1, false); + + passphrase[p] = 0; + + if (!(*_passphrase = strdup(passphrase))) { + r = -ENOMEM; + goto finish; + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (ttyfd >= 0) { + if (reset_tty) + tcsetattr(ttyfd, TCSADRAIN, &old_termios); + + close_nointr_nofail(ttyfd); + } + + return r; +} + +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(FILE *f, const char *value, dual_timestamp *t) { + unsigned long long a, b; + + assert(f); + 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; + } +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime",