X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=a055ce197ddf44881182d4e3b4d9da65fa4d6ab5;hb=bbc98d32560cc456531bf254f7b69054921082bd;hp=7778b0a06b9702adaeafcb0810e14a8e9882dea8;hpb=9bdc770ccd3e23419a0d908782a661dd81a36bc8;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index 7778b0a06..a055ce197 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -6,16 +6,16 @@ Copyright 2010 Lennart Poettering systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ @@ -52,10 +52,10 @@ #include #include #include -#include #include #include #include +#include #include "macro.h" #include "util.h" @@ -1690,7 +1690,8 @@ char *cescape(const char *s) { /* Does C style string escaping. */ - if (!(r = new(char, strlen(s)*4 + 1))) + r = new(char, strlen(s)*4 + 1); + if (!r) return NULL; for (f = s, t = r; *f; f++) @@ -4285,6 +4286,15 @@ bool tty_is_vc(const char *tty) { return vtnr_from_tty(tty) >= 0; } +bool tty_is_console(const char *tty) { + assert(tty); + + if (startswith(tty, "/dev/")) + tty += 5; + + return streq(tty, "console"); +} + int vtnr_from_tty(const char *tty) { int i, r; @@ -4318,8 +4328,10 @@ bool tty_is_vc_resolve(const char *tty) { if (startswith(tty, "/dev/")) tty += 5; - /* Resolve where /dev/console is pointing to */ - if (streq(tty, "console")) + /* Resolve where /dev/console is pointing to, if /sys is + * actually ours (i.e. not read-only-mounted which is a sign + * for container setups) */ + if (streq(tty, "console") && path_is_read_only_fs("/sys") <= 0) if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { /* If multiple log outputs are configured the * last one is what /dev/console points to */ @@ -4339,7 +4351,7 @@ bool tty_is_vc_resolve(const char *tty) { const char *default_term_for_tty(const char *tty) { assert(tty); - return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt100"; + return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102"; } bool dirent_is_file(const struct dirent *de) { @@ -4850,306 +4862,6 @@ int vt_disallocate(const char *name) { return 0; } -static int files_add(Hashmap *h, const char *path, const char *suffix) { - DIR *dir; - struct dirent buffer, *de; - int r = 0; - - dir = opendir(path); - if (!dir) { - if (errno == ENOENT) - return 0; - return -errno; - } - - for (;;) { - int k; - char *p, *f; - - k = readdir_r(dir, &buffer, &de); - if (k != 0) { - r = -k; - goto finish; - } - - if (!de) - break; - - if (!dirent_is_file_with_suffix(de, suffix)) - continue; - - if (asprintf(&p, "%s/%s", path, de->d_name) < 0) { - r = -ENOMEM; - goto finish; - } - - f = canonicalize_file_name(p); - if (!f) { - log_error("Failed to canonicalize file name '%s': %m", p); - free(p); - continue; - } - free(p); - - log_debug("found: %s\n", f); - if (hashmap_put(h, file_name_from_path(f), f) <= 0) - free(f); - } - -finish: - closedir(dir); - return r; -} - -static int base_cmp(const void *a, const void *b) { - const char *s1, *s2; - - s1 = *(char * const *)a; - s2 = *(char * const *)b; - return strcmp(file_name_from_path(s1), file_name_from_path(s2)); -} - -int conf_files_list(char ***strv, const char *suffix, const char *dir, ...) { - Hashmap *fh = NULL; - char **dirs = NULL; - char **files = NULL; - char **p; - va_list ap; - int r = 0; - - va_start(ap, dir); - dirs = strv_new_ap(dir, ap); - va_end(ap); - if (!dirs) { - r = -ENOMEM; - goto finish; - } - if (!strv_path_canonicalize(dirs)) { - r = -ENOMEM; - goto finish; - } - if (!strv_uniq(dirs)) { - r = -ENOMEM; - goto finish; - } - - fh = hashmap_new(string_hash_func, string_compare_func); - if (!fh) { - r = -ENOMEM; - goto finish; - } - - STRV_FOREACH(p, dirs) { - if (files_add(fh, *p, suffix) < 0) { - log_error("Failed to search for files."); - r = -EINVAL; - goto finish; - } - } - - files = hashmap_get_strv(fh); - if (files == NULL) { - log_error("Failed to compose list of files."); - r = -ENOMEM; - goto finish; - } - - qsort(files, hashmap_size(fh), sizeof(char *), base_cmp); - -finish: - strv_free(dirs); - hashmap_free(fh); - *strv = files; - return r; -} - -int hwclock_is_localtime(void) { - FILE *f; - bool local = false; - - /* - * The third line of adjtime is "UTC" or "LOCAL" or nothing. - * # /etc/adjtime - * 0.0 0 0 - * 0 - * UTC - */ - f = fopen("/etc/adjtime", "re"); - if (f) { - char line[LINE_MAX]; - bool b; - - b = fgets(line, sizeof(line), f) && - fgets(line, sizeof(line), f) && - fgets(line, sizeof(line), f); - - fclose(f); - - if (!b) - return -EIO; - - - truncate_nl(line); - local = streq(line, "LOCAL"); - - } else if (errno != -ENOENT) - return -errno; - - return local; -} - -int hwclock_apply_localtime_delta(int *min) { - const struct timeval *tv_null = NULL; - struct timespec ts; - struct tm *tm; - int minuteswest; - struct timezone tz; - - assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); - assert_se(tm = localtime(&ts.tv_sec)); - minuteswest = tm->tm_gmtoff / 60; - - tz.tz_minuteswest = -minuteswest; - tz.tz_dsttime = 0; /* DST_NONE*/ - - /* - * If the hardware clock does not run in UTC, but in local time: - * The very first time we set the kernel's timezone, it will warp - * the clock so that it runs in UTC instead of local time. - */ - if (settimeofday(tv_null, &tz) < 0) - return -errno; - if (min) - *min = minuteswest; - return 0; -} - -int hwclock_reset_localtime_delta(void) { - const struct timeval *tv_null = NULL; - struct timezone tz; - - tz.tz_minuteswest = 0; - tz.tz_dsttime = 0; /* DST_NONE*/ - - if (settimeofday(tv_null, &tz) < 0) - return -errno; - - return 0; -} - -int rtc_open(int flags) { - int fd; - DIR *d; - - /* First, we try to make use of the /dev/rtc symlink. If that - * doesn't exist, we open the first RTC which has hctosys=1 - * set. If we don't find any we just take the first RTC that - * exists at all. */ - - fd = open("/dev/rtc", flags); - if (fd >= 0) - return fd; - - d = opendir("/sys/class/rtc"); - if (!d) - goto fallback; - - for (;;) { - char *p, *v; - struct dirent buf, *de; - int r; - - r = readdir_r(d, &buf, &de); - if (r != 0) - goto fallback; - - if (!de) - goto fallback; - - if (ignore_file(de->d_name)) - continue; - - p = join("/sys/class/rtc/", de->d_name, "/hctosys", NULL); - if (!p) { - closedir(d); - return -ENOMEM; - } - - r = read_one_line_file(p, &v); - free(p); - - if (r < 0) - continue; - - r = parse_boolean(v); - free(v); - - if (r <= 0) - continue; - - p = strappend("/dev/", de->d_name); - fd = open(p, flags); - free(p); - - if (fd >= 0) { - closedir(d); - return fd; - } - } - -fallback: - if (d) - closedir(d); - - fd = open("/dev/rtc0", flags); - if (fd < 0) - return -errno; - - return fd; -} - -int hwclock_get_time(struct tm *tm) { - int fd; - int err = 0; - - assert(tm); - - fd = rtc_open(O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - /* This leaves the timezone fields of struct tm - * uninitialized! */ - if (ioctl(fd, RTC_RD_TIME, tm) < 0) - err = -errno; - - /* We don't now daylight saving, so we reset this in order not - * to confused mktime(). */ - tm->tm_isdst = -1; - - close_nointr_nofail(fd); - - return err; -} - -int hwclock_set_time(const struct tm *tm) { - int fd; - int err = 0; - - assert(tm); - - fd = rtc_open(O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - if (ioctl(fd, RTC_SET_TIME, tm) < 0) - err = -errno; - - close_nointr_nofail(fd); - - return err; -} - int copy_file(const char *from, const char *to) { int r, fdf, fdt; @@ -6120,3 +5832,100 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa execv(path, l); _exit(EXIT_FAILURE); } + +int setrlimit_closest(int resource, const struct rlimit *rlim) { + struct rlimit highest, fixed; + + assert(rlim); + + if (setrlimit(resource, rlim) >= 0) + return 0; + + if (errno != EPERM) + return -errno; + + /* So we failed to set the desired setrlimit, then let's try + * to get as close as we can */ + assert_se(getrlimit(resource, &highest) == 0); + + fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); + fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); + + if (setrlimit(resource, &fixed) < 0) + return -errno; + + return 0; +} + +int path_is_read_only_fs(const char *path) { + struct statvfs st; + + assert(path); + + if (statvfs(path, &st) < 0) + return -errno; + + return !!(st.f_flag & ST_RDONLY); +} + +int getenv_for_pid(pid_t pid, const char *field, char **_value) { + char path[sizeof("/proc/")-1+10+sizeof("/environ")], *value = NULL; + int r; + FILE *f; + bool done = false; + size_t l; + + assert(field); + assert(_value); + + if (pid == 0) + pid = getpid(); + + snprintf(path, sizeof(path), "/proc/%lu/environ", (unsigned long) pid); + char_array_0(path); + + f = fopen(path, "re"); + if (!f) + return -errno; + + l = strlen(field); + r = 0; + + do { + char line[LINE_MAX]; + unsigned i; + + for (i = 0; i < sizeof(line)-1; i++) { + int c; + + c = getc(f); + if (_unlikely_(c == EOF)) { + done = true; + break; + } else if (c == 0) + break; + + line[i] = c; + } + line[i] = 0; + + if (memcmp(line, field, l) == 0 && line[l] == '=') { + value = strdup(line + l + 1); + if (!value) { + r = -ENOMEM; + break; + } + + r = 1; + break; + } + + } while (!done); + + fclose(f); + + if (r >= 0) + *_value = value; + + return r; +}