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);
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;
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;
}
if (streq(s, "tty")) {
free(s);
- return get_ctty(r);
+ return get_ctty(r, NULL);
}
*r = s;
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;
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. */
return -ENOMEM;
*r = b;
+ if (_devnr)
+ *_devnr = devnr;
+
return 0;
}
return -ENOMEM;
*r = b;
+ if (_devnr)
+ *_devnr = devnr;
+
return 0;
}
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)
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);
}
void freeze(void) {
+
+ /* Make sure nobody waits for us on a socket anymore */
+ close_all_fds(NULL, 0);
+
sync();
for (;;)
return term;
}
-bool running_in_vm(void) {
+/* Returns a short identifier for the various VM implementations */
+int detect_vm(const char **id) {
#if defined(__i386__) || defined(__x86_64__)
/* Both CPUID and DMI are x86 specific interfaces... */
- const char *const dmi_vendors[] = {
+ static const char *const dmi_vendors[] = {
"/sys/class/dmi/id/sys_vendor",
"/sys/class/dmi/id/board_vendor",
"/sys/class/dmi/id/bios_vendor"
};
- uint32_t eax = 0x40000000;
+ static const char dmi_vendor_table[] =
+ "QEMU\0" "qemu\0"
+ /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+ "VMware\0" "vmware\0"
+ "VMW\0" "vmware\0"
+ "Microsoft Corporation\0" "microsoft\0"
+ "innotek GmbH\0" "oracle\0"
+ "Xen\0" "xen\0"
+ "Bochs\0" "bochs\0";
+
+ static const char cpuid_vendor_table[] =
+ "XenVMMXenVMM\0" "xen\0"
+ "KVMKVMKVM\0" "kvm\0"
+ /* 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";
+
+ uint32_t eax, ecx;
union {
uint32_t sig32[3];
char text[13];
} sig;
-
unsigned i;
-
- for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
- char *s;
- bool b;
-
- if (read_one_line_file(dmi_vendors[i], &s) < 0)
- continue;
-
- b = startswith(s, "QEMU") ||
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- startswith(s, "VMware") ||
- startswith(s, "VMW") ||
- startswith(s, "Microsoft Corporation") ||
- startswith(s, "innotek GmbH") ||
- startswith(s, "Xen");
-
- free(s);
-
- if (b)
- return true;
- }
+ const char *j, *k;
+ bool hypervisor;
/* http://lwn.net/Articles/301888/ */
zero(sig);
-
#if defined (__i386__)
#define REG_a "eax"
#define REG_b "ebx"
#define REG_b "rbx"
#endif
+ /* First detect whether there is a hypervisor */
+ eax = 1;
__asm__ __volatile__ (
/* ebx/rbx is being used for PIC! */
" push %%"REG_b" \n\t"
" cpuid \n\t"
- " mov %%ebx, %1 \n\t"
" pop %%"REG_b" \n\t"
- : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+ : "=a" (eax), "=c" (ecx)
: "0" (eax)
);
- if (streq(sig.text, "XenVMMXenVMM") ||
- streq(sig.text, "KVMKVMKVM") ||
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- streq(sig.text, "VMwareVMware") ||
- /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */
- streq(sig.text, "Microsoft Hv"))
- return true;
+ hypervisor = !!(ecx & ecx & 0x80000000U);
+
+ if (hypervisor) {
+
+ /* There is a hypervisor, see what it is */
+ eax = 0x40000000U;
+ __asm__ __volatile__ (
+ /* ebx/rbx is being used for PIC! */
+ " push %%"REG_b" \n\t"
+ " cpuid \n\t"
+ " mov %%ebx, %1 \n\t"
+ " pop %%"REG_b" \n\t"
+
+ : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+ : "0" (eax)
+ );
+
+ NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table)
+ if (streq(sig.text, j)) {
+
+ if (id)
+ *id = k;
+
+ return 1;
+ }
+ }
+
+ for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
+ char *s;
+ int r;
+ const char *found = NULL;
+
+ if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) {
+ if (r != -ENOENT)
+ return r;
+
+ continue;
+ }
+
+ NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table)
+ if (startswith(s, j))
+ found = k;
+ free(s);
+
+ if (found) {
+ if (id)
+ *id = found;
+
+ return 1;
+ }
+ }
+
+ if (hypervisor) {
+ if (id)
+ *id = "other";
+
+ return 1;
+ }
+
#endif
+ return 0;
+}
- return false;
+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 = "ns";
+
+ 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[]) {
hashmap_free_free(pids);
}
+int kill_and_sigcont(pid_t pid, int sig) {
+ int r;
+
+ r = kill(pid, sig) < 0 ? -errno : 0;
+
+ if (r >= 0)
+ kill(pid, SIGCONT);
+
+ 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",