chiark / gitweb /
systemctl: add /dev/initctl fallback
[elogind.git] / src / util.c
index 2bc90da3d2b20bf92ad239c265d42f924e968e77..2363ea27b2b87766a459aa31522f7a71a968874d 100644 (file)
@@ -43,6 +43,9 @@
 #include <sys/poll.h>
 #include <libgen.h>
 #include <ctype.h>
+#include <sys/prctl.h>
+#include <sys/utsname.h>
+#include <pwd.h>
 
 #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;
@@ -1931,7 +1964,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 +1978,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 +2012,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;
@@ -2141,6 +2222,113 @@ int dir_is_empty(const char *path) {
         return r;
 }
 
+unsigned long long random_ull(void) {
+        int fd;
+        uint64_t ull;
+        ssize_t r;
+
+        if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0)
+                goto fallback;
+
+        r = loop_read(fd, &ull, sizeof(ull), true);
+        close_nointr_nofail(fd);
+
+        if (r != sizeof(ull))
+                goto fallback;
+
+        return ull;
+
+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",