chiark / gitweb /
include <poll.h> instead of <sys/poll.h>
[elogind.git] / src / shared / util.c
index 884e782c4ff79a2c5e1528a8bf491edb996dcfd6..3a633512473d7d7c93d0574ed9b27064490f7a3f 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/tiocl.h>
 #include <termios.h>
 #include <stdarg.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <ctype.h>
 #include <sys/prctl.h>
 #include <sys/utsname.h>
 #include <locale.h>
 #include <sys/personality.h>
 #include <sys/xattr.h>
-#include <libgen.h>
 #include <sys/statvfs.h>
 #include <sys/file.h>
 #include <linux/fs.h>
+
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the XDG
+ * version which is really broken. */
+#include <libgen.h>
 #undef basename
 
 #ifdef HAVE_SYS_AUXV_H
@@ -507,18 +511,24 @@ int safe_atolli(const char *s, long long int *ret_lli) {
 int safe_atod(const char *s, double *ret_d) {
         char *x = NULL;
         double d = 0;
+        locale_t loc;
 
         assert(s);
         assert(ret_d);
 
-        RUN_WITH_LOCALE(LC_NUMERIC_MASK, "C") {
-                errno = 0;
-                d = strtod(s, &x);
-        }
+        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
+        if (loc == (locale_t) 0)
+                return -errno;
 
-        if (!x || x == s || *x || errno)
+        errno = 0;
+        d = strtod_l(s, &x, loc);
+
+        if (!x || x == s || *x || errno) {
+                freelocale(loc);
                 return errno ? -errno : -EINVAL;
+        }
 
+        freelocale(loc);
         *ret_d = (double) d;
         return 0;
 }
@@ -1533,6 +1543,10 @@ _pure_ static bool hidden_file_allow_backup(const char *filename) {
                 endswith(filename, ".dpkg-old") ||
                 endswith(filename, ".dpkg-new") ||
                 endswith(filename, ".dpkg-tmp") ||
+                endswith(filename, ".dpkg-dist") ||
+                endswith(filename, ".dpkg-bak") ||
+                endswith(filename, ".dpkg-backup") ||
+                endswith(filename, ".dpkg-remove") ||
                 endswith(filename, ".swp");
 }
 
@@ -4238,6 +4252,11 @@ bool hostname_is_valid(const char *s) {
         if (isempty(s))
                 return false;
 
+        /* Doesn't accept empty hostnames, hostnames with trailing or
+         * leading dots, and hostnames with multiple dots in a
+         * sequence. Also ensures that the length stays below
+         * HOST_NAME_MAX. */
+
         for (p = s, dot = true; *p; p++) {
                 if (*p == '.') {
                         if (dot)
@@ -5452,25 +5471,56 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
         return r;
 }
 
-bool is_valid_documentation_url(const char *url) {
-        assert(url);
+bool http_etag_is_valid(const char *etag) {
+        if (isempty(etag))
+                return false;
+
+        if (!endswith(etag, "\""))
+                return false;
 
-        if (startswith(url, "http://") && url[7])
-                return true;
+        if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
+                return false;
 
-        if (startswith(url, "https://") && url[8])
-                return true;
+        return true;
+}
 
-        if (startswith(url, "file:") && url[5])
-                return true;
+bool http_url_is_valid(const char *url) {
+        const char *p;
 
-        if (startswith(url, "info:") && url[5])
-                return true;
+        if (isempty(url))
+                return false;
+
+        p = startswith(url, "http://");
+        if (!p)
+                p = startswith(url, "https://");
+        if (!p)
+                return false;
+
+        if (isempty(p))
+                return false;
+
+        return ascii_is_valid(p);
+}
+
+bool documentation_url_is_valid(const char *url) {
+        const char *p;
+
+        if (isempty(url))
+                return false;
 
-        if (startswith(url, "man:") && url[4])
+        if (http_url_is_valid(url))
                 return true;
 
-        return false;
+        p = startswith(url, "file:/");
+        if (!p)
+                p = startswith(url, "info:");
+        if (!p)
+                p = startswith(url, "man:");
+
+        if (isempty(p))
+                return false;
+
+        return ascii_is_valid(p);
 }
 
 bool in_initrd(void) {
@@ -6406,7 +6456,7 @@ int container_get_leader(const char *machine, pid_t *pid) {
         assert(machine);
         assert(pid);
 
-        p = strappenda("/run/systemd/machines/", machine);
+        p = strjoina("/run/systemd/machines/", machine);
         r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
         if (r == -ENOENT)
                 return -EHOSTDOWN;
@@ -6645,7 +6695,7 @@ int open_tmpfile(const char *path, int flags) {
 #endif
 
         /* Fall back to unguessable name + unlinking */
-        p = strappenda(path, "/systemd-tmp-XXXXXX");
+        p = strjoina(path, "/systemd-tmp-XXXXXX");
 
         fd = mkostemp_safe(p, flags);
         if (fd < 0)
@@ -7174,7 +7224,7 @@ int take_password_lock(const char *root) {
          * awfully racy, and thus we just won't do them. */
 
         if (root)
-                path = strappenda(root, "/etc/.pwd.lock");
+                path = strjoina(root, "/etc/.pwd.lock");
         else
                 path = "/etc/.pwd.lock";
 
@@ -7925,3 +7975,117 @@ void release_lock_file(LockFile *f) {
         f->fd = safe_close(f->fd);
         f->operation = 0;
 }
+
+static size_t nul_length(const uint8_t *p, size_t sz) {
+        size_t n = 0;
+
+        while (sz > 0) {
+                if (*p != 0)
+                        break;
+
+                n++;
+                p++;
+                sz--;
+        }
+
+        return n;
+}
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
+        const uint8_t *q, *w, *e;
+        ssize_t l;
+
+        q = w = p;
+        e = q + sz;
+        while (q < e) {
+                size_t n;
+
+                n = nul_length(q, e - q);
+
+                /* If there are more than the specified run length of
+                 * NUL bytes, or if this is the beginning or the end
+                 * of the buffer, then seek instead of write */
+                if ((n > run_length) ||
+                    (n > 0 && q == p) ||
+                    (n > 0 && q + n >= e)) {
+                        if (q > w) {
+                                l = write(fd, w, q - w);
+                                if (l < 0)
+                                        return -errno;
+                                if (l != q -w)
+                                        return -EIO;
+                        }
+
+                        if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
+                                return -errno;
+
+                        q += n;
+                        w = q;
+                } else if (n > 0)
+                        q += n;
+                else
+                        q ++;
+        }
+
+        if (q > w) {
+                l = write(fd, w, q - w);
+                if (l < 0)
+                        return -errno;
+                if (l != q - w)
+                        return -EIO;
+        }
+
+        return q - (const uint8_t*) p;
+}
+
+void sigkill_wait(pid_t *pid) {
+        if (!pid)
+                return;
+        if (*pid <= 1)
+                return;
+
+        if (kill(*pid, SIGKILL) > 0)
+                (void) wait_for_terminate(*pid, NULL);
+}
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
+        int a = 0, b = 0, c = 0;
+        int k;
+
+        assert(p);
+        assert(*p);
+        assert(priority);
+
+        if ((*p)[0] != '<')
+                return 0;
+
+        if (!strchr(*p, '>'))
+                return 0;
+
+        if ((*p)[2] == '>') {
+                c = undecchar((*p)[1]);
+                k = 3;
+        } else if ((*p)[3] == '>') {
+                b = undecchar((*p)[1]);
+                c = undecchar((*p)[2]);
+                k = 4;
+        } else if ((*p)[4] == '>') {
+                a = undecchar((*p)[1]);
+                b = undecchar((*p)[2]);
+                c = undecchar((*p)[3]);
+                k = 5;
+        } else
+                return 0;
+
+        if (a < 0 || b < 0 || c < 0 ||
+            (!with_facility && (a || b || c > 7)))
+                return 0;
+
+        if (with_facility)
+                *priority = a*100 + b*10 + c;
+        else
+                *priority = (*priority & LOG_FACMASK) | c;
+
+        *p += k;
+        return 1;
+}