+int detect_container(const char **id) {
+ FILE *f;
+
+ /* Unfortunately many of these operations require root access
+ * in one way or another */
+
+ if (geteuid() != 0)
+ return -EPERM;
+
+ if (running_in_chroot() > 0) {
+
+ if (id)
+ *id = "chroot";
+
+ return 1;
+ }
+
+ /* /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) {
+
+ if (id)
+ *id = "openvz";
+
+ return 1;
+ }
+
+ 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;