X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=de5feeb8d03eb4a2db31f929d167a5b99c29a63b;hp=8a6c3bb5e7b524d70a7c971dbdd545c1822fdc41;hb=51122dc9e36cdafe76a07d1ddf1a3a7e4726bb7b;hpb=df50185b43916926a72246ab3a80875eda7ad2a3 diff --git a/src/util.c b/src/util.c index 8a6c3bb5e..de5feeb8d 100644 --- a/src/util.c +++ b/src/util.c @@ -1119,6 +1119,57 @@ int get_process_exe(pid_t pid, char **name) { return r; } +int get_process_uid(pid_t pid, uid_t *uid) { + char *p; + FILE *f; + int r; + + assert(uid); + + if (pid == 0) + return getuid(); + + if (asprintf(&p, "/proc/%lu/status", (unsigned long) pid) < 0) + return -ENOMEM; + + f = fopen(p, "re"); + free(p); + + if (!f) + return -errno; + + while (!feof(f)) { + char line[LINE_MAX], *l; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + break; + + r = -errno; + goto finish; + } + + l = strstrip(line); + + if (startswith(l, "Uid:")) { + l += 4; + l += strspn(l, WHITESPACE); + + l[strcspn(l, WHITESPACE)] = 0; + + r = parse_uid(l, uid); + goto finish; + } + } + + r = -EIO; + +finish: + fclose(f); + + return r; +} + char *strnappend(const char *s, const char *suffix, size_t b) { size_t a; char *r; @@ -2416,14 +2467,14 @@ int ask(char *ret, const char *replies, const char *text, ...) { bool need_nl = true; if (on_tty) - fputs("\x1B[1m", stdout); + fputs(ANSI_HIGHLIGHT_ON, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); if (on_tty) - fputs("\x1B[0m", stdout); + fputs(ANSI_HIGHLIGHT_OFF, stdout); fflush(stdout); @@ -2453,7 +2504,6 @@ int ask(char *ret, const char *replies, const char *text, ...) { int reset_terminal_fd(int fd) { struct termios termios; int r = 0; - long arg; /* Set terminal to some sane defaults */ @@ -2466,9 +2516,11 @@ int reset_terminal_fd(int fd) { /* Disable exclusive mode, just in case */ ioctl(fd, TIOCNXCL); + /* Switch to text mode */ + ioctl(fd, KDSETMODE, KD_TEXT); + /* Enable console unicode mode */ - arg = K_UNICODE; - ioctl(fd, KDSKBMODE, &arg); + ioctl(fd, KDSKBMODE, K_UNICODE); if (tcgetattr(fd, &termios) < 0) { r = -errno; @@ -3025,6 +3077,8 @@ int parse_bytes(const char *t, off_t *bytes) { { "M", 1024ULL*1024ULL }, { "G", 1024ULL*1024ULL*1024ULL }, { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, { "", 1 }, }; @@ -3429,7 +3483,9 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) { } if (honour_sticky) - keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX); + keep_around = + (st.st_uid == 0 || st.st_uid == getuid()) && + (st.st_mode & S_ISVTX); is_dir = S_ISDIR(st.st_mode); @@ -3443,7 +3499,9 @@ static int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) { continue; } - keep_around = st.st_uid == 0 && (st.st_mode & S_ISVTX); + keep_around = + (st.st_uid == 0 || st.st_uid == getuid()) && + (st.st_mode & S_ISVTX); } is_dir = de->d_type == DT_DIR; @@ -3505,7 +3563,7 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky if (delete_root) { - if (honour_sticky && file_is_sticky(path) > 0) + if (honour_sticky && file_is_priv_sticky(path) > 0) return r; if (rmdir(path) < 0 && errno != ENOENT) { @@ -3524,11 +3582,13 @@ int chmod_and_chown(const char *path, 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 (chmod(path, mode) < 0) - return -errno; + if (mode != (mode_t) -1) + if (chmod(path, mode) < 0) + return -errno; - if (chown(path, uid, gid) < 0) - return -errno; + if (uid != (uid_t) -1 || gid != (gid_t) -1) + if (chown(path, uid, gid) < 0) + return -errno; return 0; } @@ -3577,9 +3637,12 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) { } } -void status_vprintf(const char *format, va_list ap) { - char *s = NULL; - int fd = -1; +void status_vprintf(const char *status, bool ellipse, const char *format, va_list ap) { + char *s = NULL, *spaces = NULL, *e; + int fd = -1, c; + size_t emax, sl, left; + struct iovec iovec[5]; + int n = 0; assert(format); @@ -3589,25 +3652,69 @@ void status_vprintf(const char *format, va_list ap) { if (vasprintf(&s, format, ap) < 0) goto finish; - if ((fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC)) < 0) + fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) goto finish; - write(fd, s, strlen(s)); + if (ellipse) { + c = fd_columns(fd); + if (c <= 0) + c = 80; + + if (status) { + sl = 2 + 6 + 1; /* " [" status "]" */ + emax = (size_t) c > sl ? c - sl - 1 : 0; + } else + emax = c - 1; + + e = ellipsize(s, emax, 75); + if (e) { + free(s); + s = e; + } + } + + zero(iovec); + IOVEC_SET_STRING(iovec[n++], s); + + if (ellipse) { + sl = strlen(s); + left = emax > sl ? emax - sl : 0; + if (left > 0) { + spaces = malloc(left); + if (spaces) { + memset(spaces, ' ', left); + iovec[n].iov_base = spaces; + iovec[n].iov_len = left; + n++; + } + } + } + + if (status) { + IOVEC_SET_STRING(iovec[n++], " ["); + IOVEC_SET_STRING(iovec[n++], status); + IOVEC_SET_STRING(iovec[n++], "]\n"); + } else + IOVEC_SET_STRING(iovec[n++], "\n"); + + writev(fd, iovec, n); finish: free(s); + free(spaces); if (fd >= 0) close_nointr_nofail(fd); } -void status_printf(const char *format, ...) { +void status_printf(const char *status, bool ellipse, const char *format, ...) { va_list ap; assert(format); va_start(ap, format); - status_vprintf(format, ap); + status_vprintf(status, ellipse, format, ap); va_end(ap); } @@ -3764,7 +3871,9 @@ void status_welcome(void) { if (!ansi_color && !const_color) const_color = "1"; - status_printf("\nWelcome to \x1B[%sm%s\x1B[0m!\n\n", + status_printf(NULL, + false, + "\nWelcome to \x1B[%sm%s\x1B[0m!\n", const_color ? const_color : ansi_color, const_pretty ? const_pretty : pretty_name); @@ -3906,6 +4015,19 @@ char **replace_env_argv(char **argv, char **env) { return r; } +int fd_columns(int fd) { + struct winsize ws; + zero(ws); + + if (ioctl(fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_col <= 0) + return -EIO; + + return ws.ws_col; +} + unsigned columns(void) { static __thread int parsed_columns = 0; const char *e; @@ -3913,16 +4035,12 @@ unsigned columns(void) { if (_likely_(parsed_columns > 0)) return parsed_columns; - if ((e = getenv("COLUMNS"))) + e = getenv("COLUMNS"); + if (e) parsed_columns = atoi(e); - if (parsed_columns <= 0) { - struct winsize ws; - zero(ws); - - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) - parsed_columns = ws.ws_col; - } + if (parsed_columns <= 0) + parsed_columns = fd_columns(STDOUT_FILENO); if (parsed_columns <= 0) parsed_columns = 80; @@ -4000,7 +4118,8 @@ char *unquote(const char *s, const char* quotes) { size_t l; assert(s); - if ((l = strlen(s)) < 2) + l = strlen(s); + if (l < 2) return strdup(s); if (strchr(quotes, s[0]) && s[l-1] == s[0]) @@ -4292,31 +4411,37 @@ int vtnr_from_tty(const char *tty) { return i; } -const char *default_term_for_tty(const char *tty) { +bool tty_is_vc_resolve(const char *tty) { char *active = NULL; - const char *term; + bool b; assert(tty); if (startswith(tty, "/dev/")) tty += 5; - /* Resolve where /dev/console is pointing when determining - * TERM */ + /* Resolve where /dev/console is pointing to */ if (streq(tty, "console")) 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 */ - if ((tty = strrchr(active, ' '))) + tty = strrchr(active, ' '); + if (tty) tty++; else tty = active; } - term = tty_is_vc(tty) ? "TERM=linux" : "TERM=vt100"; + b = tty_is_vc(tty); free(active); - return term; + return b; +} + +const char *default_term_for_tty(const char *tty) { + assert(tty); + + return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt100"; } bool dirent_is_file(const struct dirent *de) { @@ -5030,13 +5155,78 @@ int hwclock_reset_localtime_delta(void) { return 0; } +int rtc_open(int flags) { + int fd; + DIR *d; + + /* We open the first RTC which has hctosys=1 set. If we don't + * find any we just take the first one */ + + d = opendir("/sys/class/rtc"); + if (!d) + goto fallback; + + for (;;) { + char *p, *v; + struct dirent buf, *de; + int r; + + r = readdir_r(d, &buf, &de); + if (r != 0) + goto fallback; + + if (!de) + goto fallback; + + if (ignore_file(de->d_name)) + continue; + + p = join("/sys/class/rtc/", de->d_name, "/hctosys", NULL); + if (!p) { + closedir(d); + return -ENOMEM; + } + + r = read_one_line_file(p, &v); + free(p); + + if (r < 0) + continue; + + r = parse_boolean(v); + free(v); + + if (r <= 0) + continue; + + p = strappend("/dev/", de->d_name); + fd = open(p, flags); + free(p); + + if (fd >= 0) { + closedir(d); + return fd; + } + } + +fallback: + if (d) + closedir(d); + + fd = open("/dev/rtc0", flags); + if (fd < 0) + return -errno; + + return fd; +} + int hwclock_get_time(struct tm *tm) { int fd; int err = 0; assert(tm); - fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC); + fd = rtc_open(O_RDONLY|O_CLOEXEC); if (fd < 0) return -errno; @@ -5060,7 +5250,7 @@ int hwclock_set_time(const struct tm *tm) { assert(tm); - fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC); + fd = rtc_open(O_RDONLY|O_CLOEXEC); if (fd < 0) return -errno; @@ -5692,7 +5882,7 @@ int block_get_whole_disk(dev_t d, dev_t *ret) { return -ENOENT; } -int file_is_sticky(const char *p) { +int file_is_priv_sticky(const char *p) { struct stat st; assert(p); @@ -5701,7 +5891,7 @@ int file_is_sticky(const char *p) { return -errno; return - st.st_uid == 0 && + (st.st_uid == 0 || st.st_uid == getuid()) && (st.st_mode & S_ISVTX); } @@ -5966,6 +6156,8 @@ char *format_bytes(char *buf, size_t l, off_t t) { const char *suffix; off_t factor; } table[] = { + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, { "G", 1024ULL*1024ULL*1024ULL }, { "M", 1024ULL*1024ULL }, @@ -5992,3 +6184,16 @@ finish: return buf; } + +void* memdup(const void *p, size_t l) { + void *r; + + assert(p); + + r = malloc(l); + if (!r) + return NULL; + + memcpy(r, p, l); + return r; +}