chiark / gitweb /
util: when releasing terminal, temporarily disable SIGHUP
[elogind.git] / util.c
diff --git a/util.c b/util.c
index 5f36819fa31f432181989130822d6f047c013da7..8556ea12cd153d6899f3b98a8cc803e80b61f401 100644 (file)
--- a/util.c
+++ b/util.c
@@ -41,6 +41,7 @@
 #include <stdarg.h>
 #include <sys/inotify.h>
 #include <sys/poll.h>
+#include <libgen.h>
 
 #include "macro.h"
 #include "util.h"
@@ -113,6 +114,9 @@ bool endswith(const char *s, const char *postfix) {
         sl = strlen(s);
         pl = strlen(postfix);
 
+        if (pl == 0)
+                return true;
+
         if (sl < pl)
                 return false;
 
@@ -128,6 +132,9 @@ bool startswith(const char *s, const char *prefix) {
         sl = strlen(s);
         pl = strlen(prefix);
 
+        if (pl == 0)
+                return true;
+
         if (sl < pl)
                 return false;
 
@@ -146,11 +153,14 @@ bool first_word(const char *s, const char *word) {
         if (sl < wl)
                 return false;
 
+        if (wl == 0)
+                return true;
+
         if (memcmp(s, word, wl) != 0)
                 return false;
 
-        return (s[wl] == 0 ||
-                strchr(WHITESPACE, s[wl]));
+        return s[wl] == 0 ||
+                strchr(WHITESPACE, s[wl]);
 }
 
 int close_nointr(int fd) {
@@ -1139,6 +1149,39 @@ bool path_startswith(const char *path, const char *prefix) {
         }
 }
 
+bool path_equal(const char *a, const char *b) {
+        assert(a);
+        assert(b);
+
+        if ((a[0] == '/') != (b[0] == '/'))
+                return false;
+
+        for (;;) {
+                size_t j, k;
+
+                a += strspn(a, "/");
+                b += strspn(b, "/");
+
+                if (*a == 0 && *b == 0)
+                        return true;
+
+                if (*a == 0 || *b == 0)
+                        return false;
+
+                j = strcspn(a, "/");
+                k = strcspn(b, "/");
+
+                if (j != k)
+                        return false;
+
+                if (memcmp(a, b, j) != 0)
+                        return false;
+
+                a += j;
+                b += k;
+        }
+}
+
 char *ascii_strlower(char *t) {
         char *p;
 
@@ -1214,7 +1257,7 @@ int close_all_fds(const int except[], unsigned n_except) {
         while ((de = readdir(d))) {
                 int fd = -1;
 
-                if (de->d_name[0] == '.')
+                if (ignore_file(de->d_name))
                         continue;
 
                 if ((r = safe_atoi(de->d_name, &fd)) < 0)
@@ -1323,7 +1366,7 @@ int chvt(int vt) {
         if (ioctl(fd, VT_ACTIVATE, vt) < 0)
                 r = -errno;
 
-        close_nointr(r);
+        close_nointr_nofail(r);
         return r;
 }
 
@@ -1386,10 +1429,14 @@ int ask(char *ret, const char *replies, const char *text, ...) {
                 int r;
                 bool need_nl = true;
 
+                fputs("\x1B[1m", stdout);
+
                 va_start(ap, text);
                 vprintf(text, ap);
                 va_end(ap);
 
+                fputs("\x1B[0m", stdout);
+
                 fflush(stdout);
 
                 if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
@@ -1611,7 +1658,7 @@ int acquire_terminal(const char *name, bool fail, bool force) {
         }
 
         if (notify >= 0)
-                close_nointr(notify);
+                close_nointr_nofail(notify);
 
         if ((r = reset_terminal(fd)) < 0)
                 log_warning("Failed to reset terminal: %s", strerror(-r));
@@ -1620,23 +1667,34 @@ int acquire_terminal(const char *name, bool fail, bool force) {
 
 fail:
         if (fd >= 0)
-                close_nointr(fd);
+                close_nointr_nofail(fd);
 
         if (notify >= 0)
-                close_nointr(notify);
+                close_nointr_nofail(notify);
 
         return r;
 }
 
 int release_terminal(void) {
         int r = 0, fd;
+        struct sigaction sa_old, sa_new;
 
-        if ((fd = open("/dev/tty", O_RDWR)) < 0)
+        if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY)) < 0)
                 return -errno;
 
+        /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
+         * by our own TIOCNOTTY */
+
+        zero(sa_new);
+        sa_new.sa_handler = SIG_IGN;
+        sa_new.sa_flags = SA_RESTART;
+        assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
+
         if (ioctl(fd, TIOCNOTTY) < 0)
                 r = -errno;
 
+        assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
+
         close_nointr_nofail(fd);
         return r;
 }
@@ -1651,6 +1709,160 @@ int ignore_signal(int sig) {
         return sigaction(sig, &sa, NULL);
 }
 
+int close_pipe(int p[]) {
+        int a = 0, b = 0;
+
+        assert(p);
+
+        if (p[0] >= 0) {
+                a = close_nointr(p[0]);
+                p[0] = -1;
+        }
+
+        if (p[1] >= 0) {
+                b = close_nointr(p[1]);
+                p[1] = -1;
+        }
+
+        return a < 0 ? a : b;
+}
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes) {
+        uint8_t *p;
+        ssize_t n = 0;
+
+        assert(fd >= 0);
+        assert(buf);
+
+        p = buf;
+
+        while (nbytes > 0) {
+                ssize_t k;
+
+                if ((k = read(fd, p, nbytes)) <= 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        if (errno == EAGAIN) {
+                                struct pollfd pollfd;
+
+                                zero(pollfd);
+                                pollfd.fd = fd;
+                                pollfd.events = POLLIN;
+
+                                if (poll(&pollfd, 1, -1) < 0) {
+                                        if (errno == EINTR)
+                                                continue;
+
+                                        return n > 0 ? n : -errno;
+                                }
+
+                                if (pollfd.revents != POLLIN)
+                                        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;
+
+        if (lstat(t, &a) < 0) {
+
+                if (errno == ENOENT)
+                        return 0;
+
+                return -errno;
+        }
+
+        if (!(copy = strdup(t)))
+                return -ENOMEM;
+
+        if (lstat(dirname(copy), &b) < 0) {
+                free(copy);
+                return -errno;
+        }
+
+        free(copy);
+
+        return a.st_dev != b.st_dev;
+}
+
+int parse_usec(const char *t, usec_t *usec) {
+        static const struct {
+                const char *suffix;
+                usec_t usec;
+        } table[] = {
+                { "sec", USEC_PER_SEC },
+                { "s", USEC_PER_SEC },
+                { "min", USEC_PER_MINUTE },
+                { "hr", USEC_PER_HOUR },
+                { "h", USEC_PER_HOUR },
+                { "d", USEC_PER_DAY },
+                { "w", USEC_PER_WEEK },
+                { "msec", USEC_PER_MSEC },
+                { "ms", USEC_PER_MSEC },
+                { "m", USEC_PER_MINUTE },
+                { "usec", 1ULL },
+                { "us", 1ULL },
+                { "", USEC_PER_SEC },
+        };
+
+        const char *p;
+        usec_t r = 0;
+
+        assert(t);
+        assert(usec);
+
+        p = t;
+        do {
+                long long l;
+                char *e;
+                unsigned i;
+
+                errno = 0;
+                l = strtoll(p, &e, 10);
+
+                if (errno != 0)
+                        return -errno;
+
+                if (l < 0)
+                        return -ERANGE;
+
+                if (e == p)
+                        return -EINVAL;
+
+                e += strspn(e, WHITESPACE);
+
+                for (i = 0; i < ELEMENTSOF(table); i++)
+                        if (startswith(e, table[i].suffix)) {
+                                r += (usec_t) l * table[i].usec;
+                                p = e + strlen(table[i].suffix);
+                                break;
+                        }
+
+                if (i >= ELEMENTSOF(table))
+                        return -EINVAL;
+
+        } while (*p != 0);
+
+        *usec = r;
+
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",