X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Futil.c;h=1febd073d2eeef37f9e7ecf99179ae711a7acbdd;hp=7e8246bb61195a0019b6945eb87e7a621b892c41;hb=28cf382a0afd10d0e2a71d152f0df4909e90d159;hpb=07faed4f99d0c798f92de3032b9c20ca31388494 diff --git a/src/util.c b/src/util.c index 7e8246bb6..1febd073d 100644 --- a/src/util.c +++ b/src/util.c @@ -683,6 +683,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 +1815,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 +1840,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 +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; @@ -2842,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; @@ -2860,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. */ @@ -2868,6 +2945,9 @@ int get_ctty(char **r) { return -ENOMEM; *r = b; + if (_devnr) + *_devnr = devnr; + return 0; } @@ -2885,6 +2965,9 @@ int get_ctty(char **r) { return -ENOMEM; *r = b; + if (_devnr) + *_devnr = devnr; + return 0; } @@ -3185,6 +3268,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 +3524,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 +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); @@ -3526,6 +3635,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 (;;) @@ -3713,13 +3826,13 @@ int detect_vm(const char **id) { /* 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" }; - const char dmi_vendor_table[] = + 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" @@ -3727,50 +3840,24 @@ int detect_vm(const char **id) { "Microsoft Corporation\0" "microsoft\0" "innotek GmbH\0" "oracle\0" "Xen\0" "xen\0" - "\0"; + "Bochs\0" "bochs\0"; - const char cpuid_vendor_table[] = + 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" - "\0"; + "Microsoft Hv\0" "microsoft\0"; uint32_t eax, ecx; union { uint32_t sig32[3]; char text[13]; } sig; - unsigned i; const char *j, *k; - - 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; - } - } + bool hypervisor; /* http://lwn.net/Articles/301888/ */ zero(sig); @@ -3795,7 +3882,9 @@ int detect_vm(const char **id) { : "0" (eax) ); - if (ecx & 0x80000000U) { + hypervisor = !!(ecx & ecx & 0x80000000U); + + if (hypervisor) { /* There is a hypervisor, see what it is */ eax = 0x40000000U; @@ -3818,31 +3907,59 @@ int detect_vm(const char **id) { 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 +#endif 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, @@ -3856,7 +3973,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[]) { @@ -3972,6 +4150,30 @@ finish: 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",