X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=9fd2d89556819500d9c602cce6f99a60cf45c02c;hb=45030287af1e8e76b0feb1cfc3011a0ef2b37d0d;hp=64059065d86537e97dd93ab7ffec953d22497df1;hpb=f7ad54a301e4ae8dceab54d3ab3934e56c1134ea;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index 64059065d..9fd2d8955 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -62,6 +62,7 @@ #include #include #include +#include #undef basename #ifdef HAVE_SYS_AUXV_H @@ -1351,12 +1352,19 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre memcpy(r, prefix, pl); for (f = s, t = r + pl; f < s + length; f++) { + size_t remaining = s + length - f; + assert(remaining > 0); - if (*f != '\\') { + if (*f != '\\') { /* a literal literal */ *(t++) = *f; continue; } + if (--remaining == 0) { /* copy trailing backslash verbatim */ + *(t++) = *f; + break; + } + f++; switch (*f) { @@ -1399,10 +1407,12 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre case 'x': { /* hexadecimal encoding */ - int a, b; + int a = -1, b = -1; - a = unhexchar(f[1]); - b = unhexchar(f[2]); + if (remaining >= 2) { + a = unhexchar(f[1]); + b = unhexchar(f[2]); + } if (a < 0 || b < 0 || (a == 0 && b == 0)) { /* Invalid escape code, let's take it literal then */ @@ -1425,11 +1435,13 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre case '6': case '7': { /* octal encoding */ - int a, b, c; + int a = -1, b = -1, c = -1; - a = unoctchar(f[0]); - b = unoctchar(f[1]); - c = unoctchar(f[2]); + if (remaining >= 3) { + a = unoctchar(f[0]); + b = unoctchar(f[1]); + c = unoctchar(f[2]); + } if (a < 0 || b < 0 || c < 0 || (a == 0 && b == 0 && c == 0)) { /* Invalid escape code, let's take it literal then */ @@ -1443,11 +1455,6 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre break; } - case 0: - /* premature end of string. */ - *(t++) = '\\'; - goto finish; - default: /* Invalid escape code, let's take it literal then */ *(t++) = '\\'; @@ -1456,7 +1463,6 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre } } -finish: *t = 0; return r; } @@ -4005,7 +4011,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=vt102"; + return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220"; } bool dirent_is_file(const struct dirent *de) { @@ -4036,64 +4042,66 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { return endswith(de->d_name, suffix); } -void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[]) { - pid_t executor_pid; - int r; - - assert(directory); +static int do_execute(char **directories, usec_t timeout, char *argv[]) { + _cleanup_hashmap_free_free_ Hashmap *pids = NULL; + _cleanup_set_free_free_ Set *seen = NULL; + char **directory; - /* Executes all binaries in a directory in parallel and waits - * for them to finish. Optionally a timeout is applied. */ + /* We fork this all off from a child process so that we can + * somewhat cleanly make use of SIGALRM to set a time limit */ - executor_pid = fork(); - if (executor_pid < 0) { - log_error_errno(errno, "Failed to fork: %m"); - return; + reset_all_signal_handlers(); + reset_signal_mask(); - } else if (executor_pid == 0) { - _cleanup_hashmap_free_free_ Hashmap *pids = NULL; - _cleanup_closedir_ DIR *_d = NULL; - struct dirent *de; + assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); - /* We fork this all off from a child process so that - * we can somewhat cleanly make use of SIGALRM to set - * a time limit */ + pids = hashmap_new(NULL); + if (!pids) + return log_oom(); - reset_all_signal_handlers(); - reset_signal_mask(); + seen = set_new(&string_hash_ops); + if (!seen) + return log_oom(); - assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + STRV_FOREACH(directory, directories) { + _cleanup_closedir_ DIR *d; + struct dirent *de; + d = opendir(*directory); if (!d) { - d = _d = opendir(directory); - if (!d) { - if (errno == ENOENT) - _exit(EXIT_SUCCESS); - - log_error_errno(errno, "Failed to enumerate directory %s: %m", directory); - _exit(EXIT_FAILURE); - } - } + if (errno == ENOENT) + continue; - pids = hashmap_new(NULL); - if (!pids) { - log_oom(); - _exit(EXIT_FAILURE); + return log_error_errno(errno, "Failed to open directory %s: %m", *directory); } FOREACH_DIRENT(de, d, break) { _cleanup_free_ char *path = NULL; pid_t pid; + int r; if (!dirent_is_file(de)) continue; - path = strjoin(directory, "/", de->d_name, NULL); - if (!path) { - log_oom(); - _exit(EXIT_FAILURE); + if (set_contains(seen, de->d_name)) { + log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name); + continue; } + r = set_put_strdup(seen, de->d_name); + if (r < 0) + return log_oom(); + + path = strjoin(*directory, "/", de->d_name, NULL); + if (!path) + return log_oom(); + + if (null_or_empty_path(path)) { + log_debug("%s is empty (a mask).", path); + continue; + } else + log_debug("%s will be executed.", path); + pid = fork(); if (pid < 0) { log_error_errno(errno, "Failed to fork: %m"); @@ -4111,45 +4119,68 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv argv[0] = path; execv(path, argv); - log_error_errno(errno, "Failed to execute %s: %m", path); - _exit(EXIT_FAILURE); + return log_error_errno(errno, "Failed to execute %s: %m", path); } log_debug("Spawned %s as " PID_FMT ".", path, pid); r = hashmap_put(pids, UINT_TO_PTR(pid), path); - if (r < 0) { - log_oom(); - _exit(EXIT_FAILURE); - } - + if (r < 0) + return log_oom(); path = NULL; } + } - /* Abort execution of this process after the - * timout. We simply rely on SIGALRM as default action - * terminating the process, and turn on alarm(). */ + /* Abort execution of this process after the timout. We simply + * rely on SIGALRM as default action terminating the process, + * and turn on alarm(). */ - if (timeout != USEC_INFINITY) - alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); + if (timeout != USEC_INFINITY) + alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); - while (!hashmap_isempty(pids)) { - _cleanup_free_ char *path = NULL; - pid_t pid; + while (!hashmap_isempty(pids)) { + _cleanup_free_ char *path = NULL; + pid_t pid; - pid = PTR_TO_UINT(hashmap_first_key(pids)); - assert(pid > 0); + pid = PTR_TO_UINT(hashmap_first_key(pids)); + assert(pid > 0); - path = hashmap_remove(pids, UINT_TO_PTR(pid)); - assert(path); + path = hashmap_remove(pids, UINT_TO_PTR(pid)); + assert(path); - wait_for_terminate_and_warn(path, pid, true); - } + wait_for_terminate_and_warn(path, pid, true); + } - _exit(EXIT_SUCCESS); + return 0; +} + +void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) { + pid_t executor_pid; + int r; + char *name; + char **dirs = (char**) directories; + + assert(!strv_isempty(dirs)); + + name = basename(dirs[0]); + assert(!isempty(name)); + + /* Executes all binaries in the directories in parallel and waits + * for them to finish. Optionally a timeout is applied. If a file + * with the same name exists in more than one directory, the + * earliest one wins. */ + + executor_pid = fork(); + if (executor_pid < 0) { + log_error_errno(errno, "Failed to fork: %m"); + return; + + } else if (executor_pid == 0) { + r = do_execute(dirs, timeout, argv); + _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); } - wait_for_terminate_and_warn(directory, executor_pid, true); + wait_for_terminate_and_warn(name, executor_pid, true); } int kill_and_sigcont(pid_t pid, int sig) { @@ -6718,23 +6749,6 @@ uint64_t physical_memory(void) { return (uint64_t) mem * (uint64_t) page_size(); } -char* mount_test_option(const char *haystack, const char *needle) { - - struct mntent me = { - .mnt_opts = (char*) haystack - }; - - assert(needle); - - /* Like glibc's hasmntopt(), but works on a string, not a - * struct mntent */ - - if (!haystack) - return NULL; - - return hasmntopt(&me, needle); -} - void hexdump(FILE *f, const void *p, size_t s) { const uint8_t *b = p; unsigned n = 0; @@ -7669,6 +7683,9 @@ int fd_setcrtime(int fd, usec_t usec) { assert(fd >= 0); + if (usec <= 0) + usec = now(CLOCK_REALTIME); + le = htole64((uint64_t) usec); if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0) return -errno; @@ -7740,3 +7757,43 @@ int same_fd(int a, int b) { return fa == fb; } + +int chattr_fd(int fd, bool b, unsigned mask) { + unsigned old_attr, new_attr; + + assert(fd >= 0); + + if (mask == 0) + return 0; + + if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) + return -errno; + + if (b) + new_attr = old_attr | mask; + else + new_attr = old_attr & ~mask; + + if (new_attr == old_attr) + return 0; + + if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) + return -errno; + + return 0; +} + +int chattr_path(const char *p, bool b, unsigned mask) { + _cleanup_close_ int fd = -1; + + assert(p); + + if (mask == 0) + return 0; + + fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return chattr_fd(fd, b, mask); +}