X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Futil.c;h=14aa1f97280a5a8f700a3cf7d1b2cd044c08bae8;hb=6ea832a20700f5282c08c70f38422c6ab290a0b5;hp=5a076e6e34e7fefc51fdac0355ffbe4e29cfe106;hpb=54e4fdef80693f7fd7893bd048bb4d9a258b03a6;p=elogind.git diff --git a/src/util.c b/src/util.c index 5a076e6e3..14aa1f972 100644 --- a/src/util.c +++ b/src/util.c @@ -1209,6 +1209,26 @@ char **strv_path_canonicalize(char **l) { return l; } +char **strv_path_remove_empty(char **l) { + char **f, **t; + + if (!l) + return NULL; + + for (f = t = l; *f; f++) { + + if (dir_is_empty(*f) > 0) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + int reset_all_signal_handlers(void) { int sig; @@ -2241,7 +2261,7 @@ int ask(char *ret, const char *replies, const char *text, ...) { } } -int reset_terminal(int fd) { +int reset_terminal_fd(int fd) { struct termios termios; int r = 0; long arg; @@ -2303,6 +2323,19 @@ finish: return r; } +int reset_terminal(const char *name) { + int fd, r; + + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + r = reset_terminal_fd(fd); + close_nointr_nofail(fd); + + return r; +} + int open_terminal(const char *name, int mode) { int fd, r; unsigned c = 0; @@ -2423,8 +2456,8 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst /* We pass here O_NOCTTY only so that we can check the return * value TIOCSCTTY and have a reliable way to figure out if we * successfully became the controlling process of the tty */ - if ((fd = open_terminal(name, O_RDWR|O_NOCTTY)) < 0) - return -errno; + if ((fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) + return fd; /* First, try to get the tty */ r = ioctl(fd, TIOCSCTTY, force); @@ -2491,7 +2524,7 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst if (notify >= 0) close_nointr_nofail(notify); - if ((r = reset_terminal(fd)) < 0) + if ((r = reset_terminal_fd(fd)) < 0) log_warning("Failed to reset terminal: %s", strerror(-r)); return fd; @@ -3991,7 +4024,7 @@ int detect_vm(const char **id) { : "0" (eax) ); - hypervisor = !!(ecx & ecx & 0x80000000U); + hypervisor = !!(ecx & 0x80000000U); if (hypervisor) { @@ -4393,6 +4426,123 @@ char* hostname_cleanup(char *s) { return s; } +int terminal_vhangup_fd(int fd) { + if (ioctl(fd, TIOCVHANGUP) < 0) + return -errno; + + return 0; +} + +int terminal_vhangup(const char *name) { + int fd, r; + + fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + r = terminal_vhangup_fd(fd); + close_nointr_nofail(fd); + + return r; +} + +int vt_disallocate(const char *name) { + int fd, r; + unsigned u; + int temporary_vt, temporary_fd; + char tpath[64]; + struct vt_stat vt_stat; + + /* Deallocate the VT if possible. If not possible + * (i.e. because it is the active one), at least clear it + * entirely (including the scrollback buffer) */ + + if (!tty_is_vc(name)) + return -EIO; + + if (!startswith(name, "/dev/tty")) + return -EINVAL; + + r = safe_atou(name+8, &u); + if (r < 0) + return r; + + if (u <= 0) + return -EIO; + + fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + r = ioctl(fd, VT_DISALLOCATE, u); + if (r >= 0) { + close_nointr_nofail(fd); + return 0; + } + + if (errno != EBUSY) { + close_nointr_nofail(fd); + return -errno; + } + + if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (u != vt_stat.v_active) { + close_nointr_nofail(fd); + return -EBUSY; + } + + if (ioctl(fd, VT_OPENQRY, &temporary_vt) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (temporary_vt <= 0) { + close_nointr_nofail(fd); + return -EIO; + } + + /* Switch to temporary VT */ + snprintf(tpath, sizeof(tpath), "/dev/tty%i", temporary_vt); + char_array_0(tpath); + temporary_fd = open_terminal(tpath, O_RDWR|O_NOCTTY|O_CLOEXEC); + ioctl(fd, VT_ACTIVATE, temporary_vt); + if (temporary_fd >= 0) + close_nointr_nofail(temporary_fd); + + /* Reopen /dev/tty0 */ + close_nointr_nofail(fd); + fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + r = -errno; + else { + /* Disallocate the real VT */ + if (ioctl(fd, VT_DISALLOCATE, u) < 0) + r = -errno; + else + r = 0; + } + + /* Recreate original VT */ + temporary_fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); + + if (temporary_fd >= 0) { + loop_write(temporary_fd, "\033[H\033[2J", 7, false); /* clear screen explicitly */ + close_nointr_nofail(temporary_fd); + } + + /* Switch back to original VT */ + if (fd >= 0) { + ioctl(fd, VT_ACTIVATE, vt_stat.v_active); + close_nointr_nofail(fd); + } + + return r; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", @@ -4528,3 +4678,121 @@ static const char *const signal_table[] = { }; DEFINE_STRING_TABLE_LOOKUP(signal, int); + +static int file_is_conf(const struct dirent *d, const char *suffix) { + assert(d); + + if (ignore_file(d->d_name)) + return 0; + + if (d->d_type != DT_REG && + d->d_type != DT_LNK && + d->d_type != DT_UNKNOWN) + return 0; + + return endswith(d->d_name, suffix); +} + +static int files_add(Hashmap *h, const char *path, const char *suffix) { + DIR *dir; + struct dirent *de; + int r = 0; + + dir = opendir(path); + if (!dir) { + if (errno == ENOENT) + return 0; + return -errno; + } + + for (de = readdir(dir); de; de = readdir(dir)) { + char *p, *f; + const char *base; + + if (!file_is_conf(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); + base = f + strlen(path) + 1; + if (hashmap_put(h, base, 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; +}