chiark / gitweb /
taint: add missing cgroups taint flag
[elogind.git] / src / util.c
index 23d7e2211d8a94c1642452627b24ff208ead8559..fada69cf1a981893f85998ac2da465865a2d0074 100644 (file)
 #include "exit-status.h"
 #include "hashmap.h"
 
+size_t page_size(void) {
+        static __thread size_t pgsz = 0;
+        long r;
+
+        if (pgsz)
+                return pgsz;
+
+        assert_se((r = sysconf(_SC_PAGESIZE)) > 0);
+
+        pgsz = (size_t) r;
+
+        return pgsz;
+}
+
 bool streq_ptr(const char *a, const char *b) {
 
         /* Like streq(), but tries to make sense of NULL pointers */
@@ -683,6 +697,73 @@ fail:
         return r;
 }
 
+int load_env_file(
+                const char *fname,
+                char ***rl) {
+
+        FILE *f;
+        char **m = 0;
+        int r;
+
+        assert(fname);
+        assert(rl);
+
+        if (!(f = fopen(fname, "re")))
+                return -errno;
+
+        while (!feof(f)) {
+                char l[LINE_MAX], *p, *u;
+                char **t;
+
+                if (!fgets(l, sizeof(l), f)) {
+                        if (feof(f))
+                                break;
+
+                        r = -errno;
+                        goto finish;
+                }
+
+                p = strstrip(l);
+
+                if (!*p)
+                        continue;
+
+                if (strchr(COMMENTS, *p))
+                        continue;
+
+                if (!(u = normalize_env_assignment(p))) {
+                        log_error("Out of memory");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                t = strv_append(m, u);
+                free(u);
+
+                if (!t) {
+                        log_error("Out of memory");
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                strv_free(m);
+                m = t;
+        }
+
+        r = 0;
+
+        *rl = m;
+        m = NULL;
+
+finish:
+        if (f)
+                fclose(f);
+
+        strv_free(m);
+
+        return r;
+}
+
 char *truncate_nl(char *s) {
         assert(s);
 
@@ -1748,8 +1829,9 @@ int close_all_fds(const int except[], unsigned n_except) {
                 if (ignore_file(de->d_name))
                         continue;
 
-                if ((r = safe_atoi(de->d_name, &fd)) < 0)
-                        goto finish;
+                if (safe_atoi(de->d_name, &fd) < 0)
+                        /* Let's better ignore this, just in case */
+                        continue;
 
                 if (fd < 3)
                         continue;
@@ -1772,16 +1854,13 @@ int close_all_fds(const int except[], unsigned n_except) {
                                 continue;
                 }
 
-                if ((r = close_nointr(fd)) < 0) {
+                if (close_nointr(fd) < 0) {
                         /* Valgrind has its own FD and doesn't want to have it closed */
-                        if (errno != EBADF)
-                                goto finish;
+                        if (errno != EBADF && r == 0)
+                                r = -errno;
                 }
         }
 
-        r = 0;
-
-finish:
         closedir(d);
         return r;
 }
@@ -2800,7 +2879,7 @@ int getttyname_harder(int fd, char **r) {
 
         if (streq(s, "tty")) {
                 free(s);
-                return get_ctty(r);
+                return get_ctty(r, NULL);
         }
 
         *r = s;
@@ -2842,7 +2921,7 @@ int get_ctty_devnr(dev_t *d) {
         return 0;
 }
 
-int get_ctty(char **r) {
+int get_ctty(char **r, dev_t *_devnr) {
         int k;
         char fn[128], *s, *b, *p;
         dev_t devnr;
@@ -2860,6 +2939,18 @@ int get_ctty(char **r) {
                 if (k != -ENOENT)
                         return k;
 
+                /* This is an ugly hack */
+                if (major(devnr) == 136) {
+                        if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0)
+                                return -ENOMEM;
+
+                        *r = b;
+                        if (_devnr)
+                                *_devnr = devnr;
+
+                        return 0;
+                }
+
                 /* Probably something like the ptys which have no
                  * symlink in /dev/char. Let's return something
                  * vaguely useful. */
@@ -2868,6 +2959,9 @@ int get_ctty(char **r) {
                         return -ENOMEM;
 
                 *r = b;
+                if (_devnr)
+                        *_devnr = devnr;
+
                 return 0;
         }
 
@@ -2885,6 +2979,9 @@ int get_ctty(char **r) {
                 return -ENOMEM;
 
         *r = b;
+        if (_devnr)
+                *_devnr = devnr;
+
         return 0;
 }
 
@@ -3185,6 +3282,32 @@ void status_welcome(void) {
         if (!ansi_color)
                 const_color = "0;33"; /* Orange/Brown for Ubuntu */
 
+#elif defined(TARGET_MANDRIVA)
+
+        if (!pretty_name) {
+                char *s, *p;
+
+                if ((r = read_one_line_file("/etc/mandriva-release", &s) < 0)) {
+                        if (r != -ENOENT)
+                                log_warning("Failed to read /etc/mandriva-release: %s", strerror(-r));
+                } else {
+                        p = strstr(s, " release ");
+                        if (p) {
+                                *p = '\0';
+                                p += 9;
+                                p[strcspn(p, " ")] = '\0';
+
+                                /* This corresponds to standard rc.sysinit */
+                                if (asprintf(&pretty_name, "%s\x1B[0;39m %s", s, p) > 0)
+                                        const_color = "1;36";
+                                else
+                                        log_warning("Failed to allocate Mandriva version string.");
+                        } else
+                                log_warning("Failed to parse /etc/mandriva-release");
+                        free(s);
+                }
+        }
+
 #endif
 
         if (!pretty_name && !const_pretty)
@@ -3415,7 +3538,7 @@ int touch(const char *path) {
 
         assert(path);
 
-        if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0)
+        if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644)) < 0)
                 return -errno;
 
         close_nointr_nofail(fd);
@@ -3507,7 +3630,7 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
         if (status.si_code == CLD_EXITED) {
                 if (status.si_status != 0) {
                         log_warning("%s failed with error code %i.", name, status.si_status);
-                        return -EPROTO;
+                        return status.si_status;
                 }
 
                 log_debug("%s succeeded.", name);
@@ -3526,6 +3649,10 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
 }
 
 void freeze(void) {
+
+        /* Make sure nobody waits for us on a socket anymore */
+        close_all_fds(NULL, 0);
+
         sync();
 
         for (;;)
@@ -3727,8 +3854,7 @@ int detect_vm(const char **id) {
                 "Microsoft Corporation\0" "microsoft\0"
                 "innotek GmbH\0"          "oracle\0"
                 "Xen\0"                   "xen\0"
-                "Bochs\0"                 "bochs\0"
-                "\0";
+                "Bochs\0"                 "bochs\0";
 
         static const char cpuid_vendor_table[] =
                 "XenVMMXenVMM\0"          "xen\0"
@@ -3736,8 +3862,7 @@ int detect_vm(const char **id) {
                 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
                 "VMwareVMware\0"          "vmware\0"
                 /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */
-                "Microsoft Hv\0"          "microsoft\0"
-                "\0";
+                "Microsoft Hv\0"          "microsoft\0";
 
         uint32_t eax, ecx;
         union {
@@ -3834,20 +3959,21 @@ int detect_vm(const char **id) {
         return 0;
 }
 
-/* Returns a short identifier for the various VM/container implementations */
-int detect_virtualization(const char **id) {
-        int r;
+int detect_container(const char **id) {
+        FILE *f;
 
-        /* Unfortunately most of these operations require root access
+        /* Unfortunately many of these operations require root access
          * in one way or another */
+
         if (geteuid() != 0)
                 return -EPERM;
 
-        if ((r = running_in_chroot()) > 0) {
+        if (running_in_chroot() > 0) {
+
                 if (id)
                         *id = "chroot";
 
-                return r;
+                return 1;
         }
 
         /* /proc/vz exists in container and outside of the container,
@@ -3861,7 +3987,68 @@ int detect_virtualization(const char **id) {
                 return 1;
         }
 
-        return detect_vm(id);
+        if ((f = fopen("/proc/self/cgroup", "r"))) {
+
+                for (;;) {
+                        char line[LINE_MAX], *p;
+
+                        if (!fgets(line, sizeof(line), f))
+                                break;
+
+                        if (!(p = strchr(strstrip(line), ':')))
+                                continue;
+
+                        if (strncmp(p, ":ns:", 4))
+                                continue;
+
+                        if (!streq(p, ":ns:/")) {
+                                fclose(f);
+
+                                if (id)
+                                        *id = "pidns";
+
+                                return 1;
+                        }
+                }
+
+                fclose(f);
+        }
+
+        return 0;
+}
+
+/* Returns a short identifier for the various VM/container implementations */
+int detect_virtualization(const char **id) {
+        static __thread const char *cached_id = NULL;
+        const char *_id;
+        int r;
+
+        if (cached_id) {
+
+                if (cached_id == (const char*) -1)
+                        return 0;
+
+                if (id)
+                        *id = cached_id;
+
+                return 1;
+        }
+
+        if ((r = detect_container(&_id)) != 0)
+                goto finish;
+
+        r = detect_vm(&_id);
+
+finish:
+        if (r > 0) {
+                cached_id = _id;
+
+                if (id)
+                        *id = _id;
+        } else if (r == 0)
+                cached_id = (const char*) -1;
+
+        return r;
 }
 
 void execute_directory(const char *directory, DIR *d, char *argv[]) {
@@ -3988,6 +4175,19 @@ int kill_and_sigcont(pid_t pid, int sig) {
         return r;
 }
 
+bool nulstr_contains(const char*nulstr, const char *needle) {
+        const char *i;
+
+        if (!nulstr)
+                return false;
+
+        NULSTR_FOREACH(i, nulstr)
+                if (streq(i, needle))
+                        return true;
+
+        return false;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",