#include "exit-status.h"
#include "hashmap.h"
#include "env-util.h"
+#include "fileio.h"
int saved_argc = 0;
char **saved_argv = NULL;
}
int close_nointr(int fd) {
- assert(fd >= 0);
-
- for (;;) {
- int r;
+ int r;
- r = close(fd);
- if (r >= 0)
- return r;
+ assert(fd >= 0);
+ r = close(fd);
- if (errno != EINTR)
- return -errno;
- }
+ /* Just ignore EINTR; a retry loop is the wrong
+ * thing to do on Linux.
+ *
+ * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+ * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+ * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+ * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+ */
+ if (_unlikely_(r < 0 && errno == EINTR))
+ return 0;
+ else if (r >= 0)
+ return r;
+ else
+ return -errno;
}
void close_nointr_nofail(int fd) {
return 0;
}
+int safe_atod(const char *s, double *ret_d) {
+ char *x = NULL;
+ double d;
+
+ assert(s);
+ assert(ret_d);
+
+ errno = 0;
+ d = strtod(s, &x);
+
+ if (!x || x == s || *x || errno)
+ return errno ? -errno : -EINVAL;
+
+ *ret_d = (double) d;
+ return 0;
+}
+
/* Split a string into words. */
char *split(const char *c, size_t *l, const char *separator, char **state) {
char *current;
return 0;
}
-int write_one_line_file(const char *fn, const char *line) {
- _cleanup_fclose_ FILE *f = NULL;
-
- assert(fn);
- assert(line);
-
- f = fopen(fn, "we");
- if (!f)
- return -errno;
-
- errno = 0;
- if (fputs(line, f) < 0)
- return errno ? -errno : -EIO;
-
- if (!endswith(line, "\n"))
- fputc('\n', f);
-
- fflush(f);
-
- if (ferror(f))
- return errno ? -errno : -EIO;
-
- return 0;
-}
-
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
return r;
}
-int write_one_line_file_atomic(const char *fn, const char *line) {
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *p = NULL;
- int r;
-
- assert(fn);
- assert(line);
-
- r = fopen_temporary(fn, &f, &p);
- if (r < 0)
- return r;
-
- fchmod_umask(fileno(f), 0644);
-
- errno = 0;
- if (fputs(line, f) < 0) {
- r = -errno;
- goto finish;
- }
-
- if (!endswith(line, "\n"))
- fputc('\n', f);
-
- fflush(f);
-
- if (ferror(f))
- r = errno ? -errno : -EIO;
- else {
- if (rename(p, fn) < 0)
- r = -errno;
- else
- r = 0;
- }
-
-finish:
- if (r < 0)
- unlink(p);
-
- return r;
-}
-
-int read_one_line_file(const char *fn, char **line) {
- _cleanup_fclose_ FILE *f = NULL;
- char t[LINE_MAX], *c;
-
- assert(fn);
- assert(line);
-
- f = fopen(fn, "re");
- if (!f)
- return -errno;
-
- if (!fgets(t, sizeof(t), f)) {
-
- if (ferror(f))
- return errno ? -errno : -EIO;
-
- t[0] = 0;
- }
-
- c = strdup(t);
- if (!c)
- return -ENOMEM;
- truncate_nl(c);
-
- *line = c;
- return 0;
-}
-
-int read_full_file(const char *fn, char **contents, size_t *size) {
- _cleanup_fclose_ FILE *f = NULL;
- size_t n, l;
- _cleanup_free_ char *buf = NULL;
- struct stat st;
-
- assert(fn);
- assert(contents);
-
- f = fopen(fn, "re");
- if (!f)
- return -errno;
-
- if (fstat(fileno(f), &st) < 0)
- return -errno;
-
- /* Safety check */
- if (st.st_size > 4*1024*1024)
- return -E2BIG;
-
- n = st.st_size > 0 ? st.st_size : LINE_MAX;
- l = 0;
-
- for (;;) {
- char *t;
- size_t k;
-
- t = realloc(buf, n+1);
- if (!t)
- return -ENOMEM;
-
- buf = t;
- k = fread(buf + l, 1, n - l, f);
-
- if (k <= 0) {
- if (ferror(f))
- return -errno;
-
- break;
- }
-
- l += k;
- n *= 2;
-
- /* Safety check */
- if (n > 4*1024*1024)
- return -E2BIG;
- }
-
- buf[l] = 0;
- *contents = buf;
- buf = NULL;
-
- if (size)
- *size = l;
-
- return 0;
-}
-
-int parse_env_file(
- const char *fname,
- const char *separator, ...) {
-
- int r = 0;
- char *contents = NULL, *p;
-
- assert(fname);
- assert(separator);
-
- if ((r = read_full_file(fname, &contents, NULL)) < 0)
- return r;
-
- p = contents;
- for (;;) {
- const char *key = NULL;
-
- p += strspn(p, separator);
- p += strspn(p, WHITESPACE);
-
- if (!*p)
- break;
-
- if (!strchr(COMMENTS, *p)) {
- va_list ap;
- char **value;
-
- va_start(ap, separator);
- while ((key = va_arg(ap, char *))) {
- size_t n;
- char *v;
-
- value = va_arg(ap, char **);
-
- n = strlen(key);
- if (!strneq(p, key, n) ||
- p[n] != '=')
- continue;
-
- p += n + 1;
- n = strcspn(p, separator);
-
- if (n >= 2 &&
- strchr(QUOTES, p[0]) &&
- p[n-1] == p[0])
- v = strndup(p+1, n-2);
- else
- v = strndup(p, n);
-
- if (!v) {
- r = -ENOMEM;
- va_end(ap);
- 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, separator);
- }
-
-fail:
- free(contents);
- return r;
-}
-
-int load_env_file(const char *fname, char ***rl) {
-
- _cleanup_fclose_ FILE *f;
- _cleanup_strv_free_ char **m = NULL;
- _cleanup_free_ char *c = NULL;
-
- assert(fname);
- assert(rl);
-
- /* This reads an environment file, but will not complain about
- * any invalid assignments, that needs to be done by the
- * caller */
-
- f = fopen(fname, "re");
- if (!f)
- return -errno;
-
- while (!feof(f)) {
- char l[LINE_MAX], *p, *cs, *b;
-
- if (!fgets(l, sizeof(l), f)) {
- if (ferror(f))
- return -errno;
-
- /* The previous line was a continuation line?
- * Let's process it now, before we leave the
- * loop */
- if (c)
- goto process;
-
- break;
- }
-
- /* Is this a continuation line? If so, just append
- * this to c, and go to next line right-away */
- cs = endswith(l, "\\\n");
- if (cs) {
- *cs = '\0';
- b = strappend(c, l);
- if (!b)
- return -ENOMEM;
-
- free(c);
- c = b;
- continue;
- }
-
- /* If the previous line was a continuation line,
- * append the current line to it */
- if (c) {
- b = strappend(c, l);
- if (!b)
- return -ENOMEM;
-
- free(c);
- c = b;
- }
-
- process:
- p = strstrip(c ? c : l);
-
- if (*p && !strchr(COMMENTS, *p)) {
- _cleanup_free_ char *u;
- int k;
-
- u = normalize_env_assignment(p);
- if (!u)
- return -ENOMEM;
-
- k = strv_extend(&m, u);
- if (k < 0)
- return -ENOMEM;
- }
-
- free(c);
- c = NULL;
- }
-
- *rl = m;
- m = NULL;
-
- return 0;
-}
-
-int write_env_file(const char *fname, char **l) {
- char **i, *p;
- FILE *f;
- int r;
-
- r = fopen_temporary(fname, &f, &p);
- if (r < 0)
- return r;
-
- fchmod_umask(fileno(f), 0644);
-
- errno = 0;
- STRV_FOREACH(i, l) {
- fputs(*i, f);
- fputc('\n', f);
- }
-
- fflush(f);
-
- if (ferror(f)) {
- if (errno != 0)
- r = -errno;
- else
- r = -EIO;
- } else {
- if (rename(p, fname) < 0)
- r = -errno;
- else
- r = 0;
- }
-
- if (r < 0)
- unlink(p);
-
- fclose(f);
- free(p);
-
- return r;
-}
-
char *truncate_nl(char *s) {
assert(s);
static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
+ char line[LINE_MAX];
assert(field);
assert(uid);
if (!f)
return -errno;
- FOREACH_LINE(f, line, return -errno) {
+ FOREACH_LINE(line, f, return -errno) {
char *l;
l = strstrip(line);
}
}
-int status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) {
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
static const char status_indent[] = " "; /* "[" STATUS "] " */
_cleanup_free_ char *s = NULL;
_cleanup_close_ int fd = -1;
- struct iovec iovec[5];
+ struct iovec iovec[6];
int n = 0;
+ static bool prev_ephemeral;
assert(format);
zero(iovec);
+ if (prev_ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+ prev_ephemeral = ephemeral;
+
if (status) {
if (!isempty(status)) {
IOVEC_SET_STRING(iovec[n++], "[");
}
IOVEC_SET_STRING(iovec[n++], s);
- IOVEC_SET_STRING(iovec[n++], "\n");
+ if (!ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\n");
if (writev(fd, iovec, n) < 0)
return -errno;
return 0;
}
-int status_printf(const char *status, bool ellipse, const char *format, ...) {
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
va_list ap;
int r;
assert(format);
va_start(ap, format);
- r = status_vprintf(status, ellipse, format, ap);
+ r = status_vprintf(status, ellipse, ephemeral, format, ap);
va_end(ap);
return r;
return i;
}
+char *resolve_dev_console(char **active) {
+ char *tty;
+
+ /* Resolve where /dev/console is pointing to, if /sys is actually ours
+ * (i.e. not read-only-mounted which is a sign for container setups) */
+
+ if (path_is_read_only_fs("/sys") > 0)
+ return NULL;
+
+ if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
+ return NULL;
+
+ /* If multiple log outputs are configured the last one is what
+ * /dev/console points to */
+ tty = strrchr(*active, ' ');
+ if (tty)
+ tty++;
+ else
+ tty = *active;
+
+ return tty;
+}
+
bool tty_is_vc_resolve(const char *tty) {
char *active = NULL;
bool b;
if (startswith(tty, "/dev/"))
tty += 5;
- /* Resolve where /dev/console is pointing to, if /sys is
- * actually ours (i.e. not read-only-mounted which is a sign
- * for container setups) */
- if (streq(tty, "console") && path_is_read_only_fs("/sys") <= 0)
- if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
- /* If multiple log outputs are configured the
- * last one is what /dev/console points to */
- tty = strrchr(active, ' ');
- if (tty)
- tty++;
- else
- tty = active;
- }
+ if (streq(tty, "console")) {
+ tty = resolve_dev_console(&active);
+ if (!tty)
+ return false;
+ }
b = tty_is_vc(tty);
free(active);