X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=97ff320bc8320c82b3d2f44b72f08dfe31eea4f7;hp=ee95a4b6f71c67bb7ff3f5c3e8ce736bfaa98113;hb=5f8cc96a0301c1177b11dd2e89370ef0b2ef577b;hpb=c4e34a612c81266773cf8358cb38a43d2e43474e diff --git a/src/shared/util.c b/src/shared/util.c index ee95a4b6f..97ff320bc 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -521,7 +521,7 @@ int safe_atod(const char *s, double *ret_d) { static size_t strcspn_escaped(const char *s, const char *reject) { bool escaped = false; - size_t n; + int n; for (n=0; s[n]; n++) { if (escaped) @@ -531,6 +531,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) { else if (strchr(reject, s[n])) break; } + /* if s ends in \, return index of previous char */ return n - escaped; } @@ -566,6 +567,11 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo *state = current++ + *l + 2; } else if (quoted) { *l = strcspn_escaped(current, separator); + if (current[*l] && !strchr(separator, current[*l])) { + /* unfinished escape */ + *state = current; + return NULL; + } *state = current + *l; } else { *l = strcspn(current, separator); @@ -1504,7 +1510,7 @@ char *ascii_strlower(char *t) { return t; } -_pure_ static bool ignore_file_allow_backup(const char *filename) { +_pure_ static bool hidden_file_allow_backup(const char *filename) { assert(filename); return @@ -1521,13 +1527,13 @@ _pure_ static bool ignore_file_allow_backup(const char *filename) { endswith(filename, ".swp"); } -bool ignore_file(const char *filename) { +bool hidden_file(const char *filename) { assert(filename); if (endswith(filename, "~")) return true; - return ignore_file_allow_backup(filename); + return hidden_file_allow_backup(filename); } int fd_nonblock(int fd, bool nonblock) { @@ -1621,7 +1627,7 @@ int close_all_fds(const int except[], unsigned n_except) { while ((de = readdir(d))) { int fd = -1; - if (ignore_file(de->d_name)) + if (hidden_file(de->d_name)) continue; if (safe_atoi(de->d_name, &fd) < 0) @@ -2468,9 +2474,9 @@ int make_stdio(int fd) { assert(fd >= 0); - r = dup3(fd, STDIN_FILENO, 0); - s = dup3(fd, STDOUT_FILENO, 0); - t = dup3(fd, STDERR_FILENO, 0); + r = dup2(fd, STDIN_FILENO); + s = dup2(fd, STDOUT_FILENO); + t = dup2(fd, STDERR_FILENO); if (fd >= 3) safe_close(fd); @@ -2478,7 +2484,11 @@ int make_stdio(int fd) { if (r < 0 || s < 0 || t < 0) return -errno; - /* We rely here that the new fd has O_CLOEXEC not set */ + /* Explicitly unset O_CLOEXEC, since if fd was < 3, then + * dup2() was a NOP and the bit hence possibly set. */ + fd_cloexec(STDIN_FILENO, false); + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); return 0; } @@ -2521,7 +2531,7 @@ int dir_is_empty(const char *path) { if (!de) return 1; - if (!ignore_file(de->d_name)) + if (!hidden_file(de->d_name)) return 0; } } @@ -2775,23 +2785,36 @@ char *getusername_malloc(void) { return lookup_uid(getuid()); } -int getttyname_malloc(int fd, char **r) { - char path[PATH_MAX], *c; - int k; +int getttyname_malloc(int fd, char **ret) { + size_t l = 100; + int r; - assert(r); + assert(fd >= 0); + assert(ret); - k = ttyname_r(fd, path, sizeof(path)); - if (k > 0) - return -k; + for (;;) { + char path[l]; - char_array_0(path); + r = ttyname_r(fd, path, sizeof(path)); + if (r == 0) { + const char *p; + char *c; - c = strdup(startswith(path, "/dev/") ? path + 5 : path); - if (!c) - return -ENOMEM; + p = startswith(path, "/dev/"); + c = strdup(p ?: path); + if (!c) + return -ENOMEM; + + *ret = c; + return 0; + } + + if (r != ERANGE) + return -r; + + l *= 2; + } - *r = c; return 0; } @@ -3059,7 +3082,7 @@ static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bo fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); if (fd < 0) { - if (errno != ENOTDIR) + if (errno != ENOTDIR && errno != ELOOP) return -errno; if (!dangerous) { @@ -3986,7 +4009,7 @@ const char *default_term_for_tty(const char *tty) { bool dirent_is_file(const struct dirent *de) { assert(de); - if (ignore_file(de->d_name)) + if (hidden_file(de->d_name)) return false; if (de->d_type != DT_REG && @@ -4005,7 +4028,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { de->d_type != DT_UNKNOWN) return false; - if (ignore_file_allow_backup(de->d_name)) + if (hidden_file_allow_backup(de->d_name)) return false; return endswith(de->d_name, suffix); @@ -4247,6 +4270,23 @@ bool machine_name_is_valid(const char *s) { return true; } +bool image_name_is_valid(const char *s) { + if (!filename_is_valid(s)) + return false; + + if (string_has_cc(s, NULL)) + return false; + + if (!utf8_is_valid(s)) + return false; + + /* Temporary files for atomically creating new files */ + if (startswith(s, ".#")) + return false; + + return true; +} + int pipe_eof(int fd) { struct pollfd pollfd = { .fd = fd, @@ -5899,7 +5939,7 @@ int on_ac_power(void) { if (!de) break; - if (ignore_file(de->d_name)) + if (hidden_file(de->d_name)) continue; device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); @@ -6982,18 +7022,18 @@ int tempfn_xxxxxx(const char *p, char **ret) { * /foo/bar/waldo * * Into this: - * /foo/bar/.waldoXXXXXX + * /foo/bar/.#waldoXXXXXX */ fn = basename(p); if (!filename_is_valid(fn)) return -EINVAL; - t = new(char, strlen(p) + 1 + 6 + 1); + t = new(char, strlen(p) + 2 + 6 + 1); if (!t) return -ENOMEM; - strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), "."), fn), "XXXXXX"); + strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX"); *ret = path_kill_slashes(t); return 0; @@ -7013,18 +7053,18 @@ int tempfn_random(const char *p, char **ret) { * /foo/bar/waldo * * Into this: - * /foo/bar/.waldobaa2a261115984a9 + * /foo/bar/.#waldobaa2a261115984a9 */ fn = basename(p); if (!filename_is_valid(fn)) return -EINVAL; - t = new(char, strlen(p) + 1 + 16 + 1); + t = new(char, strlen(p) + 2 + 16 + 1); if (!t) return -ENOMEM; - x = stpcpy(stpcpy(mempcpy(t, p, fn - p), "."), fn); + x = stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn); u = random_u64(); for (i = 0; i < 16; i++) { @@ -7049,14 +7089,14 @@ int tempfn_random_child(const char *p, char **ret) { /* Turns this: * /foo/bar/waldo * Into this: - * /foo/bar/waldo/.3c2b6219aa75d7d0 + * /foo/bar/waldo/.#3c2b6219aa75d7d0 */ - t = new(char, strlen(p) + 2 + 16 + 1); + t = new(char, strlen(p) + 3 + 16 + 1); if (!t) return -ENOMEM; - x = stpcpy(stpcpy(t, p), "/."); + x = stpcpy(stpcpy(t, p), "/.#"); u = random_u64(); for (i = 0; i < 16; i++) { @@ -7406,3 +7446,116 @@ int sethostname_idempotent(const char *s) { return 1; } + +int ptsname_malloc(int fd, char **ret) { + size_t l = 100; + + assert(fd >= 0); + assert(ret); + + for (;;) { + char *c; + + c = new(char, l); + if (!c) + return -ENOMEM; + + if (ptsname_r(fd, c, l) == 0) { + *ret = c; + return 0; + } + if (errno != ERANGE) { + free(c); + return -errno; + } + + free(c); + l *= 2; + } +} + +int openpt_in_namespace(pid_t pid, int flags) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + siginfo_t si; + pid_t child; + int r; + + assert(pid > 0); + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = posix_openpt(flags); + if (master < 0) + _exit(EXIT_FAILURE); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &master, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) + return -errno; + + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + int *fds; + unsigned n_fds; + + fds = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (n_fds != 1) { + close_many(fds, n_fds); + return -EIO; + } + + return fds[0]; + } + + return -EIO; +}