X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=b77d010d2d5801a60da5e1492c5acadf6b2ae00b;hp=200955376e3ebcc539a790b11cbf1ca7b536a92d;hb=8aa5429a4a59abbcf567938fa6ef60bb2c8ae2f1;hpb=8f6ce71fe79d897b67157d92869db87ee2042af6 diff --git a/src/shared/util.c b/src/shared/util.c index 200955376..b77d010d2 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -74,6 +74,10 @@ #include "env-util.h" #include "fileio.h" #include "device-nodes.h" +#include "utf8.h" +#include "gunicode.h" +#include "virt.h" +#include "def.h" int saved_argc = 0; char **saved_argv = NULL; @@ -641,7 +645,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * /* Kernel threads have no argv[] */ if (r == NULL || r[0] == 0) { - char *t; + _cleanup_free_ char *t = NULL; int h; free(r); @@ -654,8 +658,6 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return h; r = strjoin("[", t, "]", NULL); - free(t); - if (!r) return -ENOMEM; } @@ -1362,7 +1364,7 @@ char *bus_path_escape(const char *s) { assert(s); /* Escapes all chars that D-Bus' object path cannot deal - * with. Can be reverse with bus_path_unescape(). We special + * with. Can be reversed with bus_path_unescape(). We special * case the empty string. */ if (*s == 0) @@ -2186,8 +2188,10 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { return n > 0 ? n : -errno; } - if (pollfd.revents != POLLIN) - return n > 0 ? n : -EIO; + /* We knowingly ignore the revents value here, + * and expect that any error/EOF is reported + * via read()/write() + */ continue; } @@ -2234,8 +2238,10 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return n > 0 ? n : -errno; } - if (pollfd.revents != POLLOUT) - return n > 0 ? n : -EIO; + /* We knowingly ignore the revents value here, + * and expect that any error/EOF is reported + * via read()/write() + */ continue; } @@ -2420,6 +2426,25 @@ fallback: return random() * RAND_MAX + random(); } +unsigned random_u(void) { + _cleanup_close_ int fd; + unsigned u; + ssize_t r; + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + goto fallback; + + r = loop_read(fd, &u, sizeof(u), true); + if (r != sizeof(u)) + goto fallback; + + return u; + +fallback: + return random() * RAND_MAX + random(); +} + void rename_process(const char name[8]) { assert(name); @@ -2900,11 +2925,13 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { * first change the access mode and only then hand out * ownership to avoid a window where access is too open. */ - if (fchmod(fd, mode) < 0) - return -errno; + if (mode != (mode_t) -1) + if (fchmod(fd, mode) < 0) + return -errno; - if (fchown(fd, uid, gid) < 0) - return -errno; + if (uid != (uid_t) -1 || gid != (gid_t) -1) + if (fchown(fd, uid, gid) < 0) + return -errno; return 0; } @@ -3016,13 +3043,14 @@ int status_printf(const char *status, bool ellipse, bool ephemeral, const char * } int status_welcome(void) { - int r; _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; + int r; r = parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &pretty_name, "ANSI_COLOR", &ansi_color, NULL); + if (r < 0 && r != -ENOENT) log_warning("Failed to read /etc/os-release: %s", strerror(-r)); @@ -3265,7 +3293,7 @@ int running_in_chroot(void) { a.st_ino != b.st_ino; } -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { +static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { size_t x; char *r; @@ -3296,6 +3324,80 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne return r; } +char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *e; + const char *i, *j; + unsigned k, len, len2; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + /* if no multibyte characters use ascii_ellipsize_mem for speed */ + if (ascii_is_valid(s)) + return ascii_ellipsize_mem(s, old_length, new_length, percent); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + k = 0; + for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + int c; + + c = utf8_encoded_to_unichar(i); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + + if (k > x) /* last character was wide and went over quota */ + x ++; + + for (j = s + old_length; k < new_length && j > i; ) { + int c; + + j = utf8_prev_char(j); + c = utf8_encoded_to_unichar(j); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + assert(i <= j); + + /* we don't actually need to ellipsize */ + if (i == j) + return memdup(s, old_length + 1); + + /* make space for ellipsis */ + j = utf8_next_char(j); + + len = i - s; + len2 = s + old_length - j; + e = new(char, len + 3 + len2 + 1); + if (!e) + return NULL; + + /* + printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", + old_length, new_length, x, len, len2, k); + */ + + memcpy(e, s, len); + e[len] = 0xe2; /* tri-dot ellipsis: … */ + e[len + 1] = 0x80; + e[len + 2] = 0xa6; + + memcpy(e + len + 3, j, len2 + 1); + + return e; +} + char *ellipsize(const char *s, size_t length, unsigned percent) { return ellipsize_mem(s, strlen(s), length, percent); } @@ -3504,7 +3606,7 @@ static char *tag_to_udev_node(const char *tagvalue, const char *by) { if (u == NULL) return NULL; - enc_len = strlen(u) * 4; + enc_len = strlen(u) * 4 + 1; t = new(char, enc_len); if (t == NULL) return NULL; @@ -3598,12 +3700,21 @@ char *resolve_dev_console(char **active) { else tty = *active; + if (streq(tty, "tty0")) { + char *tmp; + + /* Get the active VC (e.g. tty1) */ + if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) { + free(*active); + tty = *active = tmp; + } + } + return tty; } bool tty_is_vc_resolve(const char *tty) { - char *active = NULL; - bool b; + _cleanup_free_ char *active = NULL; assert(tty); @@ -3616,10 +3727,7 @@ bool tty_is_vc_resolve(const char *tty) { return false; } - b = tty_is_vc(tty); - free(active); - - return b; + return tty_is_vc(tty); } const char *default_term_for_tty(const char *tty) { @@ -4033,8 +4141,9 @@ int vt_disallocate(const char *name) { return 0; } -int copy_file(const char *from, const char *to) { - int r, fdf, fdt; +int copy_file(const char *from, const char *to, int flags) { + _cleanup_close_ int fdf = -1; + int r, fdt; assert(from); assert(to); @@ -4043,11 +4152,9 @@ int copy_file(const char *from, const char *to) { if (fdf < 0) return -errno; - fdt = open(to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY, 0644); - if (fdt < 0) { - close_nointr_nofail(fdf); + fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644); + if (fdt < 0) return -errno; - } for (;;) { char buf[PIPE_BUF]; @@ -4057,7 +4164,6 @@ int copy_file(const char *from, const char *to) { if (n < 0) { r = -errno; - close_nointr_nofail(fdf); close_nointr(fdt); unlink(to); @@ -4072,15 +4178,13 @@ int copy_file(const char *from, const char *to) { if (n != k) { r = k < 0 ? k : (errno ? -errno : -EIO); - close_nointr_nofail(fdf); close_nointr(fdt); - unlink(to); + return r; } } - close_nointr_nofail(fdf); r = close_nointr(fdt); if (r < 0) { @@ -4368,7 +4472,7 @@ int glob_extend(char ***strv, const char *path) { char **p; errno = 0; - k = glob(optarg, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); if (k == GLOB_NOMATCH) return -ENOENT; @@ -4412,38 +4516,31 @@ int dirent_ensure_type(DIR *d, struct dirent *de) { } int in_search_path(const char *path, char **search) { - char **i, *parent; + char **i; + _cleanup_free_ char *parent = NULL; int r; r = path_get_parent(path, &parent); if (r < 0) return r; - r = 0; - - STRV_FOREACH(i, search) { - if (path_equal(parent, *i)) { - r = 1; - break; - } - } - - free(parent); + STRV_FOREACH(i, search) + if (path_equal(parent, *i)) + return 1; - return r; + return 0; } int get_files_in_directory(const char *path, char ***list) { - DIR *d; - int r = 0; - unsigned n = 0; - char **l = NULL; + _cleanup_closedir_ DIR *d = NULL; + size_t bufsize = 0, n = 0; + _cleanup_strv_free_ char **l = NULL; assert(path); /* Returns all files in a directory in *list, and the number * of files as return value. If list is NULL returns only the - * number */ + * number. */ d = opendir(path); if (!d) @@ -4455,11 +4552,9 @@ int get_files_in_directory(const char *path, char ***list) { int k; k = readdir_r(d, &buf.de, &de); - if (k != 0) { - r = -k; - goto finish; - } - + assert(k >= 0); + if (k > 0) + return -k; if (!de) break; @@ -4469,43 +4564,25 @@ int get_files_in_directory(const char *path, char ***list) { continue; if (list) { - if ((unsigned) r >= n) { - char **t; - - n = MAX(16, 2*r); - t = realloc(l, sizeof(char*) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } - - l = t; - } - - assert((unsigned) r < n); + /* one extra slot is needed for the terminating NULL */ + if (!GREEDY_REALLOC(l, bufsize, n + 2)) + return -ENOMEM; - l[r] = strdup(de->d_name); - if (!l[r]) { - r = -ENOMEM; - goto finish; - } + l[n] = strdup(de->d_name); + if (!l[n]) + return -ENOMEM; - l[++r] = NULL; + l[++n] = NULL; } else - r++; + n++; } -finish: - if (d) - closedir(d); - - if (r >= 0) { - if (list) - *list = l; - } else - strv_free(l); + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } - return r; + return n; } char *strjoin(const char *x, ...) { @@ -5399,6 +5476,7 @@ const char *draw_special_char(DrawSpecialChar ch) { [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ [DRAW_TREE_SPACE] = " ", /* */ [DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */ + [DRAW_BLACK_CIRCLE] = "\342\227\217 ", /* ● */ }, /* ASCII fallback */ { [DRAW_TREE_VERT] = "| ", @@ -5406,6 +5484,7 @@ const char *draw_special_char(DrawSpecialChar ch) { [DRAW_TREE_RIGHT] = "`-", [DRAW_TREE_SPACE] = " ", [DRAW_TRIANGULAR_BULLET] = "> ", + [DRAW_BLACK_CIRCLE] = "* ", } }; @@ -5924,3 +6003,37 @@ int split_pair(const char *s, const char *sep, char **l, char **r) { return 0; } + +int shall_restore_state(void) { + _cleanup_free_ char *line; + char *w, *state; + size_t l; + int r; + + r = proc_cmdline(&line); + if (r < 0) + return r; + if (r == 0) /* Container ... */ + return 1; + + FOREACH_WORD_QUOTED(w, l, line, state) + if (l == 23 && memcmp(w, "systemd.restore_state=0", 23)) + return 0; + + return 1; +} + +int proc_cmdline(char **ret) { + int r; + + if (detect_container(NULL) > 0) { + *ret = NULL; + return 0; + } + + r = read_one_line_file("/proc/cmdline", ret); + if (r < 0) + return r; + + return 1; +}