X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=766aa02965825651481d6bdf4146372a72f50def;hp=71409034a4e15cb0c35fbbd2994e520cccfbea7c;hb=f872ec33973b2f508d36939e917ffafd47a87b07;hpb=d3782d60cd47f57f48a9229bdd3badbd2f4bae44 diff --git a/src/util.c b/src/util.c index 71409034a..766aa0296 100644 --- a/src/util.c +++ b/src/util.c @@ -43,6 +43,9 @@ #include #include #include +#include +#include +#include #include "macro.h" #include "util.h" @@ -222,6 +225,13 @@ void close_nointr_nofail(int fd) { errno = saved_errno; } +void close_many(const int fds[], unsigned n_fd) { + unsigned i; + + for (i = 0; i < n_fd; i++) + close_nointr_nofail(fds[i]); +} + int parse_boolean(const char *v) { assert(v); @@ -233,6 +243,29 @@ int parse_boolean(const char *v) { return -EINVAL; } +int parse_pid(const char *s, pid_t* ret_pid) { + unsigned long ul; + pid_t pid; + int r; + + assert(s); + assert(ret_pid); + + if ((r = safe_atolu(s, &ul)) < 0) + return r; + + pid = (pid_t) ul; + + if ((unsigned long) pid != ul) + return -ERANGE; + + if (pid <= 0) + return -ERANGE; + + *ret_pid = pid; + return 0; +} + int safe_atou(const char *s, unsigned *ret_u) { char *x = NULL; unsigned long l; @@ -860,6 +893,53 @@ int mkdir_p(const char *path, mode_t mode) { return 0; } +int rmdir_parents(const char *path, const char *stop) { + size_t l; + int r = 0; + + assert(path); + assert(stop); + + l = strlen(path); + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + while (l > 0) { + char *t; + + /* Skip last component */ + while (l > 0 && path[l-1] != '/') + l--; + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + if (l <= 0) + break; + + if (!(t = strndup(path, l))) + return -ENOMEM; + + if (path_startswith(stop, t)) { + free(t); + return 0; + } + + r = rmdir(t); + free(t); + + if (r < 0) + if (errno != ENOENT) + return -errno; + } + + return 0; +} + + char hexchar(int x) { static const char table[16] = "0123456789abcdef"; @@ -1419,7 +1499,7 @@ char *format_timestamp(char *buf, size_t l, usec_t t) { if (t <= 0) return NULL; - sec = (time_t) t / USEC_PER_SEC; + sec = (time_t) (t / USEC_PER_SEC); if (strftime(buf, l, "%a, %d %b %Y %H:%M:%S %z", localtime_r(&sec, &tm)) <= 0) return NULL; @@ -1931,7 +2011,7 @@ int close_pipe(int p[]) { return a < 0 ? a : b; } -ssize_t loop_read(int fd, void *buf, size_t nbytes) { +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { uint8_t *p; ssize_t n = 0; @@ -1945,10 +2025,10 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes) { if ((k = read(fd, p, nbytes)) <= 0) { - if (errno == EINTR) + if (k < 0 && errno == EINTR) continue; - if (errno == EAGAIN) { + if (k < 0 && errno == EAGAIN && do_poll) { struct pollfd pollfd; zero(pollfd); @@ -1979,6 +2059,54 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes) { return n; } +ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { + const uint8_t *p; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + p = buf; + + while (nbytes > 0) { + ssize_t k; + + if ((k = write(fd, p, nbytes)) <= 0) { + + if (k < 0 && errno == EINTR) + continue; + + if (k < 0 && errno == EAGAIN && do_poll) { + struct pollfd pollfd; + + zero(pollfd); + pollfd.fd = fd; + pollfd.events = POLLOUT; + + if (poll(&pollfd, 1, -1) < 0) { + if (errno == EINTR) + continue; + + return n > 0 ? n : -errno; + } + + if (pollfd.revents != POLLOUT) + return n > 0 ? n : -EIO; + + continue; + } + + return n > 0 ? n : (k < 0 ? -errno : 0); + } + + p += k; + nbytes -= k; + n += k; + } + + return n; +} + int path_is_mount_point(const char *t) { struct stat a, b; char *copy; @@ -2149,7 +2277,7 @@ unsigned long long random_ull(void) { if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) goto fallback; - r = loop_read(fd, &ull, sizeof(ull)); + r = loop_read(fd, &ull, sizeof(ull), true); close_nointr_nofail(fd); if (r != sizeof(ull)) @@ -2161,6 +2289,93 @@ fallback: return random() * RAND_MAX + random(); } +void rename_process(const char name[8]) { + assert(name); + + prctl(PR_SET_NAME, name); + + /* This is a like a poor man's setproctitle(). The string + * passed should fit in 7 chars (i.e. the length of + * "systemd") */ + + if (program_invocation_name) + strncpy(program_invocation_name, name, strlen(program_invocation_name)); +} + +void sigset_add_many(sigset_t *ss, ...) { + va_list ap; + int sig; + + assert(ss); + + va_start(ap, ss); + while ((sig = va_arg(ap, int)) > 0) + assert_se(sigaddset(ss, sig) == 0); + va_end(ap); +} + +char* gethostname_malloc(void) { + struct utsname u; + + assert_se(uname(&u) >= 0); + + if (u.nodename[0]) + return strdup(u.nodename); + + return strdup(u.sysname); +} + +char* getlogname_malloc(void) { + uid_t uid; + long bufsize; + char *buf, *name; + struct passwd pwbuf, *pw = NULL; + struct stat st; + + if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) + uid = st.st_uid; + else + uid = getuid(); + + /* Shortcut things to avoid NSS lookups */ + if (uid == 0) + return strdup("root"); + + if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) <= 0) + bufsize = 4096; + + if (!(buf = malloc(bufsize))) + return NULL; + + if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) { + name = strdup(pw->pw_name); + free(buf); + return name; + } + + free(buf); + + if (asprintf(&name, "%lu", (unsigned long) uid) < 0) + return NULL; + + return name; +} + +char *getttyname_malloc(void) { + char path[PATH_MAX], *p; + + if (ttyname_r(STDIN_FILENO, path, sizeof(path)) < 0) + return strdup("unknown"); + + char_array_0(path); + + p = path; + if (startswith(path, "/dev/")) + p += 5; + + return strdup(p); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime",