chiark / gitweb /
util: detect CLONE_NEWPID namespaces, and cache results
[elogind.git] / src / util.c
index c9366c4a393fe9239fd038e00f19f074eb020d20..38d630e6a0f7061c76ca277ab20d6cc3ba331bc7 100644 (file)
@@ -2865,7 +2865,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;
@@ -2907,7 +2907,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;
@@ -2925,6 +2925,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. */
@@ -2933,6 +2945,9 @@ int get_ctty(char **r) {
                         return -ENOMEM;
 
                 *r = b;
+                if (_devnr)
+                        *_devnr = devnr;
+
                 return 0;
         }
 
@@ -2950,6 +2965,9 @@ int get_ctty(char **r) {
                 return -ENOMEM;
 
         *r = b;
+        if (_devnr)
+                *_devnr = devnr;
+
         return 0;
 }
 
@@ -3598,7 +3616,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);
@@ -3930,6 +3948,20 @@ int detect_vm(const char **id) {
 /* Returns a short identifier for the various VM/container implementations */
 int detect_virtualization(const char **id) {
         int r;
+        static __thread const char *cached_id = NULL;
+        const char *_id;
+        FILE *f;
+
+        if (cached_id) {
+
+                if (cached_id == (const char*) -1)
+                        return 0;
+
+                if (id)
+                        *id = cached_id;
+
+                return 1;
+        }
 
         /* Unfortunately most of these operations require root access
          * in one way or another */
@@ -3937,24 +3969,60 @@ int detect_virtualization(const char **id) {
                 return -EPERM;
 
         if ((r = running_in_chroot()) > 0) {
-                if (id)
-                        *id = "chroot";
+                _id = "chroot";
+                r = 1;
+                goto finish;
+        }
 
-                return r;
+        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);
+
+                                r = 1;
+                                _id = "ns";
+                                goto finish;
+                        }
+                }
+
+                fclose(f);
         }
 
         /* /proc/vz exists in container and outside of the container,
          * /proc/bc only outside of the container. */
         if (access("/proc/vz", F_OK) >= 0 &&
             access("/proc/bc", F_OK) < 0) {
+                _id = "openvz";
+                r = 1;
+                goto finish;
+        }
 
-                if (id)
-                        *id = "openvz";
+        r = detect_vm(&_id);
 
-                return 1;
-        }
+finish:
+        if (r < 0)
+                return r;
+        else if (r > 0)
+                cached_id = _id;
+        else
+                cached_id = (const char*) -1;
 
-        return detect_vm(id);
+        if (id)
+                *id = _id;
+
+        return r;
 }
 
 void execute_directory(const char *directory, DIR *d, char *argv[]) {