chiark / gitweb /
gcc: make gcc shut up
[elogind.git] / src / util.c
index bdc194e80c9ce45bde0975d7ef9c5ab4b4482bfd..ef37d05751bc4236834e3905e100338bd3af1c61 100644 (file)
@@ -250,7 +250,7 @@ int parse_boolean(const char *v) {
 }
 
 int parse_pid(const char *s, pid_t* ret_pid) {
-        unsigned long ul;
+        unsigned long ul = 0;
         pid_t pid;
         int r;
 
@@ -495,6 +495,9 @@ int write_one_line_file(const char *fn, const char *line) {
                 goto finish;
         }
 
+        if (!endswith(line, "\n"))
+                fputc('\n', f);
+
         r = 0;
 finish:
         fclose(f);
@@ -600,13 +603,13 @@ finish:
 
 int parse_env_file(
                 const char *fname,
-                const char *seperator, ...) {
+                const char *separator, ...) {
 
-        int r;
+        int r = 0;
         char *contents, *p;
 
         assert(fname);
-        assert(seperator);
+        assert(separator);
 
         if ((r = read_full_file(fname, &contents)) < 0)
                 return r;
@@ -615,7 +618,7 @@ int parse_env_file(
         for (;;) {
                 const char *key = NULL;
 
-                p += strspn(p, seperator);
+                p += strspn(p, separator);
                 p += strspn(p, WHITESPACE);
 
                 if (!*p)
@@ -625,7 +628,7 @@ int parse_env_file(
                         va_list ap;
                         char **value;
 
-                        va_start(ap, seperator);
+                        va_start(ap, separator);
                         while ((key = va_arg(ap, char *))) {
                                 size_t n;
                                 char *v;
@@ -638,7 +641,7 @@ int parse_env_file(
                                         continue;
 
                                 p += n + 1;
-                                n = strcspn(p, seperator);
+                                n = strcspn(p, separator);
 
                                 if (n >= 2 &&
                                     strchr(QUOTES, p[0]) &&
@@ -653,21 +656,27 @@ int parse_env_file(
                                         goto fail;
                                 }
 
+                                if (v[0] == '\0') {
+                                        /* return empty value strings as NULL */
+                                        free(v);
+                                        v = NULL;
+                                }
+
                                 free(*value);
                                 *value = v;
 
                                 p += n;
+
+                                r ++;
                                 break;
                         }
                         va_end(ap);
                 }
 
                 if (!key)
-                        p += strcspn(p, seperator);
+                        p += strcspn(p, separator);
         }
 
-        r = 0;
-
 fail:
         free(contents);
         return r;
@@ -1675,6 +1684,8 @@ bool ignore_file(const char *filename) {
         return
                 filename[0] == '.' ||
                 streq(filename, "lost+found") ||
+                streq(filename, "aquota.user") ||
+                streq(filename, "aquota.group") ||
                 endswith(filename, "~") ||
                 endswith(filename, ".rpmnew") ||
                 endswith(filename, ".rpmsave") ||
@@ -2241,26 +2252,34 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst
                 assert(notify >= 0);
 
                 for (;;) {
-                        struct inotify_event e;
+                        uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
                         ssize_t l;
+                        struct inotify_event *e;
 
-                        if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) {
+                        if ((l = read(notify, &inotify_buffer, sizeof(inotify_buffer))) < 0) {
 
-                                if (l < 0) {
+                                if (errno == EINTR)
+                                        continue;
 
-                                        if (errno == EINTR)
-                                                continue;
+                                r = -errno;
+                                goto fail;
+                        }
+
+                        e = (struct inotify_event*) inotify_buffer;
 
-                                        r = -errno;
-                                } else
+                        while (l > 0) {
+                                size_t step;
+
+                                if (e->wd != wd || !(e->mask & IN_CLOSE)) {
                                         r = -EIO;
+                                        goto fail;
+                                }
 
-                                goto fail;
-                        }
+                                step = sizeof(struct inotify_event) + e->len;
+                                assert(step <= (size_t) l);
 
-                        if (e.wd != wd || !(e.mask & IN_CLOSE)) {
-                                r = -EIO;
-                                goto fail;
+                                e = (struct inotify_event*) ((uint8_t*) e + step);
+                                l -= step;
                         }
 
                         break;
@@ -2589,31 +2608,13 @@ int make_stdio(int fd) {
         return 0;
 }
 
-bool is_clean_exit(int code, int status) {
-
-        if (code == CLD_EXITED)
-                return status == 0;
-
-        /* If a daemon does not implement handlers for some of the
-         * signals that's not considered an unclean shutdown */
-        if (code == CLD_KILLED)
-                return
-                        status == SIGHUP ||
-                        status == SIGINT ||
-                        status == SIGTERM ||
-                        status == SIGPIPE;
+int make_null_stdio(void) {
+        int null_fd;
 
-        return false;
-}
-
-bool is_clean_exit_lsb(int code, int status) {
-
-        if (is_clean_exit(code, status))
-                return true;
+        if ((null_fd = open("/dev/null", O_RDWR|O_NOCTTY)) < 0)
+                return -errno;
 
-        return
-                code == CLD_EXITED &&
-                (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED);
+        return make_stdio(null_fd);
 }
 
 bool is_device_path(const char *path) {
@@ -2954,66 +2955,117 @@ void status_printf(const char *format, ...) {
 }
 
 void status_welcome(void) {
+        char *pretty_name = NULL, *ansi_color = NULL;
+        const char *const_pretty = NULL, *const_color = NULL;
+        int r;
 
-#if defined(TARGET_FEDORA)
-        char *r;
+        if ((r = parse_env_file("/etc/os-release", NEWLINE,
+                                "PRETTY_NAME", &pretty_name,
+                                "ANSI_COLOR", &ansi_color,
+                                NULL)) < 0) {
 
-        if (read_one_line_file("/etc/system-release", &r) < 0)
-                return;
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/os-release: %s", strerror(-r));
+        }
 
-        truncate_nl(r);
+#if defined(TARGET_FEDORA)
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/system-release", &pretty_name)) < 0) {
 
-        /* This tries to mimic the color magic the old Red Hat sysinit
-         * script did. */
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/system-release: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        if (startswith(r, "Red Hat"))
-                status_printf("Welcome to \x1B[0;31m%s\x1B[0m!\n", r); /* Red for RHEL */
-        else if (startswith(r, "Fedora"))
-                status_printf("Welcome to \x1B[0;34m%s\x1B[0m!\n", r); /* Blue for Fedora */
-        else
-                status_printf("Welcome to %s!\n", r);
+        if (!ansi_color && pretty_name) {
 
-        free(r);
+                /* This tries to mimic the color magic the old Red Hat sysinit
+                 * script did. */
+
+                if (startswith(pretty_name, "Red Hat"))
+                        const_color = "0;31"; /* Red for RHEL */
+                else if (startswith(pretty_name, "Fedora"))
+                        const_color = "0;34"; /* Blue for Fedora */
+        }
 
 #elif defined(TARGET_SUSE)
-        char *r;
 
-        if (read_one_line_file("/etc/SuSE-release", &r) < 0)
-                return;
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/SuSE-release", &pretty_name)) < 0) {
 
-        truncate_nl(r);
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/SuSE-release: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        status_printf("Welcome to \x1B[0;32m%s\x1B[0m!\n", r); /* Green for SUSE */
-        free(r);
+        if (!ansi_color)
+                const_color = "0;32"; /* Green for openSUSE */
 
 #elif defined(TARGET_GENTOO)
-        char *r;
 
-        if (read_one_line_file("/etc/gentoo-release", &r) < 0)
-                return;
-
-        truncate_nl(r);
+        if (!pretty_name) {
+                if ((r = read_one_line_file("/etc/gentoo-release", &pretty_name)) < 0) {
 
-        status_printf("Welcome to \x1B[1;34m%s\x1B[0m!\n", r); /* Light Blue for Gentoo */
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/gentoo-release: %s", strerror(-r));
+                } else
+                        truncate_nl(pretty_name);
+        }
 
-        free(r);
+        if (!ansi_color)
+                const_color = "1;34"; /* Light Blue for Gentoo */
 
 #elif defined(TARGET_DEBIAN)
-        char *r;
 
-        if (read_one_line_file("/etc/debian_version", &r) < 0)
-                return;
+        if (!pretty_name) {
+                char *version;
 
-        truncate_nl(r);
+                if ((r = read_one_line_file("/etc/debian_version", &version)) < 0) {
 
-        status_printf("Welcome to Debian \x1B[1;31m%s\x1B[0m!\n", r); /* Light Red for Debian */
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/debian_version: %s", strerror(-r));
+                } else {
+                        truncate_nl(version);
+                        pretty_name = strappend("Debian ", version);
+                        free(version);
+
+                        if (!pretty_name)
+                                log_warning("Failed to allocate Debian version string.");
+                }
+        }
+
+        if (!ansi_color)
+                const_color = "1;31"; /* Light Red for Debian */
+
+#elif defined(TARGET_UBUNTU)
+
+        if ((r = parse_env_file("/etc/lsb-release", NEWLINE,
+                                "DISTRIB_DESCRIPTION", &pretty_name,
+                                NULL)) < 0) {
+
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/lsb-release: %s", strerror(-r));
+        }
+
+        if (!ansi_color)
+                const_color = "0;33"; /* Orange/Brown for Ubuntu */
 
-        free(r);
-#elif defined(TARGET_ARCH)
-        status_printf("Welcome to \x1B[1;36mArch Linux\x1B[0m!\n"); /* Cyan for Arch */
-#else
-#warning "You probably should add a welcome text logic here."
 #endif
+
+        if (!pretty_name && !const_pretty)
+                const_pretty = "Linux";
+
+        if (!ansi_color && !const_color)
+                const_color = "1";
+
+        status_printf("Welcome to \x1B[%sm%s\x1B[0m!\n",
+                      const_color ? const_color : ansi_color,
+                      const_pretty ? const_pretty : pretty_name);
+
+        free(ansi_color);
+        free(pretty_name);
 }
 
 char *replace_env(const char *format, char **env) {
@@ -3250,6 +3302,44 @@ char *unquote(const char *s, const char* quotes) {
         return strdup(s);
 }
 
+char *normalize_env_assignment(const char *s) {
+        char *name, *value, *p, *r;
+
+        p = strchr(s, '=');
+
+        if (!p) {
+                if (!(r = strdup(s)))
+                        return NULL;
+
+                return strstrip(r);
+        }
+
+        if (!(name = strndup(s, p - s)))
+                return NULL;
+
+        if (!(p = strdup(p+1))) {
+                free(name);
+                return NULL;
+        }
+
+        value = unquote(strstrip(p), QUOTES);
+        free(p);
+
+        if (!value) {
+                free(p);
+                free(name);
+                return NULL;
+        }
+
+        if (asprintf(&r, "%s=%s", name, value) < 0)
+                r = NULL;
+
+        free(value);
+        free(name);
+
+        return r;
+}
+
 int wait_for_terminate(pid_t pid, siginfo_t *status) {
         assert(pid >= 1);
         assert(status);
@@ -3302,6 +3392,163 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
 
 }
 
+void freeze(void) {
+        sync();
+
+        for (;;)
+                pause();
+}
+
+bool null_or_empty(struct stat *st) {
+        assert(st);
+
+        if (S_ISREG(st->st_mode) && st->st_size <= 0)
+                return true;
+
+        if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
+                return true;
+
+        return false;
+}
+
+DIR *xopendirat(int fd, const char *name, int flags) {
+        int nfd;
+        DIR *d;
+
+        if ((nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags)) < 0)
+                return NULL;
+
+        if (!(d = fdopendir(nfd))) {
+                close_nointr_nofail(nfd);
+                return NULL;
+        }
+
+        return d;
+}
+
+int signal_from_string_try_harder(const char *s) {
+        int signo;
+        assert(s);
+
+        if ((signo = signal_from_string(s)) <= 0)
+                if (startswith(s, "SIG"))
+                        return signal_from_string(s+3);
+
+        return signo;
+}
+
+void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
+
+        assert(f);
+        assert(name);
+        assert(t);
+
+        if (!dual_timestamp_is_set(t))
+                return;
+
+        fprintf(f, "%s=%llu %llu\n",
+                name,
+                (unsigned long long) t->realtime,
+                (unsigned long long) t->monotonic);
+}
+
+void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
+        unsigned long long a, b;
+
+        assert(value);
+        assert(t);
+
+        if (sscanf(value, "%lli %llu", &a, &b) != 2)
+                log_debug("Failed to parse finish timestamp value %s", value);
+        else {
+                t->realtime = a;
+                t->monotonic = b;
+        }
+}
+
+char *fstab_node_to_udev_node(const char *p) {
+        char *dn, *t, *u;
+        int r;
+
+        /* FIXME: to follow udev's logic 100% we need to leave valid
+         * UTF8 chars unescaped */
+
+        if (startswith(p, "LABEL=")) {
+
+                if (!(u = unquote(p+6, "\"\'")))
+                        return NULL;
+
+                t = xescape(u, "/ ");
+                free(u);
+
+                if (!t)
+                        return NULL;
+
+                r = asprintf(&dn, "/dev/disk/by-label/%s", t);
+                free(t);
+
+                if (r < 0)
+                        return NULL;
+
+                return dn;
+        }
+
+        if (startswith(p, "UUID=")) {
+
+                if (!(u = unquote(p+5, "\"\'")))
+                        return NULL;
+
+                t = xescape(u, "/ ");
+                free(u);
+
+                if (!t)
+                        return NULL;
+
+                r = asprintf(&dn, "/dev/disk/by-uuid/%s", t);
+                free(t);
+
+                if (r < 0)
+                        return NULL;
+
+                return dn;
+        }
+
+        return strdup(p);
+}
+
+void filter_environ(const char *prefix) {
+        int i, j;
+        assert(prefix);
+
+        if (!environ)
+                return;
+
+        for (i = 0, j = 0; environ[i]; i++) {
+
+                if (startswith(environ[i], prefix))
+                        continue;
+
+                environ[j++] = environ[i];
+        }
+
+        environ[j] = NULL;
+}
+
+const char *default_term_for_tty(const char *tty) {
+        assert(tty);
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        if (startswith(tty, "tty") &&
+            tty[3] >= '0' && tty[3] <= '9')
+                return "TERM=linux";
+
+        /* FIXME: Proper handling of /dev/console would be cool */
+
+        return "TERM=vt100";
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",