goto finish;
}
+ if (!endswith(line, "\n"))
+ fputc('\n', f);
+
r = 0;
finish:
fclose(f);
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)
}
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) {
+ if ((r = read_one_line_file("/etc/debian_version", &pretty_name)) < 0) {
- truncate_nl(r);
+ if (r != -ENOENT)
+ log_warning("Failed to read /etc/debian_version: %s", strerror(-r));
+ } else
+ truncate_nl(pretty_name);
+ }
- status_printf("Welcome to Debian \x1B[1;31m%s\x1B[0m!\n", r); /* Light Red for Debian */
+ if (!ansi_color)
+ const_color = "1;31"; /* 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);
+ 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 */
+
#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) {
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[] = {