diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-10-25 13:14:12 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-10-25 13:19:18 +0100 |
commit | 3ffd4af22052963e7a29431721ee204e634bea75 (patch) | |
tree | fe60142dfddd37cfc02b7a135542107e772b36c3 /src/basic | |
parent | 04c0136989b7eb896bfb0fb176e11233d69e1453 (diff) |
util-lib: split out fd-related operations into fd-util.[ch]
There are more than enough to deserve their own .c file, hence move them
over.
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/async.c | 1 | ||||
-rw-r--r-- | src/basic/audit.c | 7 | ||||
-rw-r--r-- | src/basic/barrier.c | 1 | ||||
-rw-r--r-- | src/basic/btrfs-util.c | 3 | ||||
-rw-r--r-- | src/basic/capability.c | 10 | ||||
-rw-r--r-- | src/basic/cgroup-util.c | 3 | ||||
-rw-r--r-- | src/basic/clock-util.c | 3 | ||||
-rw-r--r-- | src/basic/clock-util.h | 1 | ||||
-rw-r--r-- | src/basic/conf-files.c | 3 | ||||
-rw-r--r-- | src/basic/copy.c | 3 | ||||
-rw-r--r-- | src/basic/extract-word.c | 1 | ||||
-rw-r--r-- | src/basic/fd-util.c | 321 | ||||
-rw-r--r-- | src/basic/fd-util.h | 69 | ||||
-rw-r--r-- | src/basic/fdset.c | 5 | ||||
-rw-r--r-- | src/basic/fileio.c | 3 | ||||
-rw-r--r-- | src/basic/hostname-util.c | 3 | ||||
-rw-r--r-- | src/basic/locale-util.c | 3 | ||||
-rw-r--r-- | src/basic/lockfile-util.c | 5 | ||||
-rw-r--r-- | src/basic/log.c | 3 | ||||
-rw-r--r-- | src/basic/memfd-util.c | 3 | ||||
-rw-r--r-- | src/basic/memfd-util.h | 3 | ||||
-rw-r--r-- | src/basic/path-util.c | 3 | ||||
-rw-r--r-- | src/basic/process-util.c | 3 | ||||
-rw-r--r-- | src/basic/random-util.c | 13 | ||||
-rw-r--r-- | src/basic/rm-rf.c | 3 | ||||
-rw-r--r-- | src/basic/socket-label.c | 11 | ||||
-rw-r--r-- | src/basic/terminal-util.c | 3 | ||||
-rw-r--r-- | src/basic/time-util.c | 3 | ||||
-rw-r--r-- | src/basic/util.c | 301 | ||||
-rw-r--r-- | src/basic/util.h | 38 |
30 files changed, 455 insertions, 377 deletions
diff --git a/src/basic/async.c b/src/basic/async.c index 7725e6d7d3..c3135f0efe 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -23,6 +23,7 @@ #include <unistd.h> #include "async.h" +#include "fd-util.h" #include "log.h" #include "util.h" diff --git a/src/basic/audit.c b/src/basic/audit.c index 1f593aa813..af43ec8097 100644 --- a/src/basic/audit.c +++ b/src/basic/audit.c @@ -22,11 +22,12 @@ #include <errno.h> #include <stdio.h> -#include "macro.h" #include "audit.h" -#include "util.h" -#include "process-util.h" +#include "fd-util.h" #include "fileio.h" +#include "macro.h" +#include "process-util.h" +#include "util.h" int audit_session_from_pid(pid_t pid, uint32_t *id) { _cleanup_free_ char *s = NULL; diff --git a/src/basic/barrier.c b/src/basic/barrier.c index 436ba95989..2d55bab4ab 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -30,6 +30,7 @@ #include <unistd.h> #include "barrier.h" +#include "fd-util.h" #include "macro.h" #include "util.h" diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index df7b959c12..f799f8dcc2 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -27,7 +27,9 @@ #endif #include "btrfs-ctree.h" +#include "btrfs-util.h" #include "copy.h" +#include "fd-util.h" #include "fileio.h" #include "macro.h" #include "missing.h" @@ -36,7 +38,6 @@ #include "smack-util.h" #include "string-util.h" #include "util.h" -#include "btrfs-util.h" /* WARNING: Be careful with file system ioctls! When we get an fd, we * need to make sure it either refers to only a regular file or diff --git a/src/basic/capability.c b/src/basic/capability.c index 8dbe4da5bb..6f25b5dee9 100644 --- a/src/basic/capability.c +++ b/src/basic/capability.c @@ -19,18 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <grp.h> #include <stdio.h> #include <sys/capability.h> #include <sys/prctl.h> -#include "grp.h" +#include <unistd.h> +#include "capability.h" +#include "fileio.h" +#include "log.h" #include "macro.h" #include "util.h" -#include "log.h" -#include "fileio.h" -#include "capability.h" int have_effective_cap(int value) { _cleanup_cap_free_ cap_t cap; diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index ce21ef73eb..958497543a 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -29,7 +29,9 @@ #include <sys/types.h> #include <unistd.h> +#include "cgroup-util.h" #include "extract-word.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "login-util.h" @@ -42,7 +44,6 @@ #include "string-util.h" #include "unit-name.h" #include "util.h" -#include "cgroup-util.h" int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { _cleanup_free_ char *fs = NULL; diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 03ec5725ae..00ee4c2796 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -26,10 +26,11 @@ #include <sys/ioctl.h> #include <sys/time.h> +#include "clock-util.h" +#include "fd-util.h" #include "macro.h" #include "string-util.h" #include "util.h" -#include "clock-util.h" int clock_get_hwclock(struct tm *tm) { _cleanup_close_ int fd = -1; diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index 8c2d235430..fef2d471a6 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -21,6 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <time.h> int clock_is_localtime(void); int clock_set_timezone(int *min); diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 0e44d1bbad..3af3fe392c 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -25,6 +25,8 @@ #include <stdlib.h> #include <string.h> +#include "conf-files.h" +#include "fd-util.h" #include "hashmap.h" #include "log.h" #include "macro.h" @@ -33,7 +35,6 @@ #include "string-util.h" #include "strv.h" #include "util.h" -#include "conf-files.h" static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { _cleanup_closedir_ DIR *dir = NULL; diff --git a/src/basic/copy.c b/src/basic/copy.c index 7702d906c7..c15527df22 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -23,10 +23,11 @@ #include <sys/xattr.h> #include "btrfs-util.h" +#include "copy.h" +#include "fd-util.h" #include "string-util.h" #include "strv.h" #include "util.h" -#include "copy.h" #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 52d2672390..f2b74802fa 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -22,7 +22,6 @@ #include "escape.h" #include "utf8.h" #include "util.h" - #include "extract-word.h" int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c new file mode 100644 index 0000000000..e54c104597 --- /dev/null +++ b/src/basic/fd-util.c @@ -0,0 +1,321 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "fd-util.h" +#include "util.h" + +int close_nointr(int fd) { + assert(fd >= 0); + + if (close(fd) >= 0) + return 0; + + /* + * Just ignore EINTR; a retry loop is the wrong thing to do on + * Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (errno == EINTR) + return 0; + + return -errno; +} + +int safe_close(int fd) { + + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ + + if (fd >= 0) { + PROTECT_ERRNO; + + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ + + assert_se(close_nointr(fd) != -EBADF); + } + + return -1; +} + +void safe_close_pair(int p[]) { + assert(p); + + if (p[0] == p[1]) { + /* Special case pairs which use the same fd in both + * directions... */ + p[0] = p[1] = safe_close(p[0]); + return; + } + + p[0] = safe_close(p[0]); + p[1] = safe_close(p[1]); +} + +void close_many(const int fds[], unsigned n_fd) { + unsigned i; + + assert(fds || n_fd <= 0); + + for (i = 0; i < n_fd; i++) + safe_close(fds[i]); +} + +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + +DIR* safe_closedir(DIR *d) { + + if (d) { + PROTECT_ERRNO; + + assert_se(closedir(d) >= 0 || errno != EBADF); + } + + return NULL; +} + +int fd_nonblock(int fd, bool nonblock) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + return -errno; + + if (nonblock) + nflags = flags | O_NONBLOCK; + else + nflags = flags & ~O_NONBLOCK; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFL, nflags) < 0) + return -errno; + + return 0; +} + +int fd_cloexec(int fd, bool cloexec) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) + return -errno; + + if (cloexec) + nflags = flags | FD_CLOEXEC; + else + nflags = flags & ~FD_CLOEXEC; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFD, nflags) < 0) + return -errno; + + return 0; +} + +_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { + unsigned i; + + assert(n_fdset == 0 || fdset); + + for (i = 0; i < n_fdset; i++) + if (fdset[i] == fd) + return true; + + return false; +} + +int close_all_fds(const int except[], unsigned n_except) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(n_except == 0 || except); + + d = opendir("/proc/self/fd"); + if (!d) { + int fd; + struct rlimit rl; + + /* When /proc isn't available (for example in chroots) + * the fallback is brute forcing through the fd + * table */ + + assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); + for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) + if (errno != EBADF && r == 0) + r = -errno; + } + + return r; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (hidden_file(de->d_name)) + continue; + + if (safe_atoi(de->d_name, &fd) < 0) + /* Let's better ignore this, just in case */ + continue; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) { + /* Valgrind has its own FD and doesn't want to have it closed */ + if (errno != EBADF && r == 0) + r = -errno; + } + } + + return r; +} + +int same_fd(int a, int b) { + struct stat sta, stb; + pid_t pid; + int r, fa, fb; + + assert(a >= 0); + assert(b >= 0); + + /* Compares two file descriptors. Note that semantics are + * quite different depending on whether we have kcmp() or we + * don't. If we have kcmp() this will only return true for + * dup()ed file descriptors, but not otherwise. If we don't + * have kcmp() this will also return true for two fds of the same + * file, created by separate open() calls. Since we use this + * call mostly for filtering out duplicates in the fd store + * this difference hopefully doesn't matter too much. */ + + if (a == b) + return true; + + /* Try to use kcmp() if we have it. */ + pid = getpid(); + r = kcmp(pid, pid, KCMP_FILE, a, b); + if (r == 0) + return true; + if (r > 0) + return false; + if (errno != ENOSYS) + return -errno; + + /* We don't have kcmp(), use fstat() instead. */ + if (fstat(a, &sta) < 0) + return -errno; + + if (fstat(b, &stb) < 0) + return -errno; + + if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) + return false; + + /* We consider all device fds different, since two device fds + * might refer to quite different device contexts even though + * they share the same inode and backing dev_t. */ + + if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) + return false; + + if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) + return false; + + /* The fds refer to the same inode on disk, let's also check + * if they have the same fd flags. This is useful to + * distinguish the read and write side of a pipe created with + * pipe(). */ + fa = fcntl(a, F_GETFL); + if (fa < 0) + return -errno; + + fb = fcntl(b, F_GETFL); + if (fb < 0) + return -errno; + + return fa == fb; +} + +void cmsg_close_all(struct msghdr *mh) { + struct cmsghdr *cmsg; + + assert(mh); + + CMSG_FOREACH(cmsg, mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) + close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h new file mode 100644 index 0000000000..be00d881c3 --- /dev/null +++ b/src/basic/fd-util.h @@ -0,0 +1,69 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdio.h> +#include <dirent.h> +#include <stdbool.h> +#include <sys/socket.h> + +#include "macro.h" + +int close_nointr(int fd); +int safe_close(int fd); +void safe_close_pair(int p[]); + +void close_many(const int fds[], unsigned n_fd); + +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); +DIR* safe_closedir(DIR *f); + +static inline void closep(int *fd) { + safe_close(*fd); +} + +static inline void close_pairp(int (*p)[2]) { + safe_close_pair(*p); +} + +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); + +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_pclose_ _cleanup_(pclosep) +#define _cleanup_closedir_ _cleanup_(closedirp) +#define _cleanup_close_pair_ _cleanup_(close_pairp) + +int fd_nonblock(int fd, bool nonblock); +int fd_cloexec(int fd, bool cloexec); + +int close_all_fds(const int except[], unsigned n_except); + +int same_fd(int a, int b); + +void cmsg_close_all(struct msghdr *mh); diff --git a/src/basic/fdset.c b/src/basic/fdset.c index 2882f515b5..9669110828 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -25,10 +25,11 @@ #include "sd-daemon.h" +#include "fd-util.h" +#include "fdset.h" +#include "macro.h" #include "set.h" #include "util.h" -#include "macro.h" -#include "fdset.h" #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index f8ccf79221..5d33309ab2 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -23,11 +23,12 @@ #include "ctype.h" #include "escape.h" +#include "fd-util.h" +#include "fileio.h" #include "string-util.h" #include "strv.h" #include "utf8.h" #include "util.h" -#include "fileio.h" int write_string_stream(FILE *f, const char *line, bool enforce_newline) { diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 8d10615682..7d058416e5 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -22,9 +22,10 @@ #include <ctype.h> #include <sys/utsname.h> +#include "fd-util.h" +#include "hostname-util.h" #include "string-util.h" #include "util.h" -#include "hostname-util.h" bool hostname_is_set(void) { struct utsname u; diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index a44daf8f5e..44e1628664 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -21,12 +21,13 @@ #include <sys/mman.h> +#include "fd-util.h" +#include "locale-util.h" #include "set.h" #include "string-util.h" #include "strv.h" #include "utf8.h" #include "util.h" -#include "locale-util.h" static int add_locales_from_archive(Set *locales) { /* Stolen from glibc... */ diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index f3ec6a3e52..e573dcb56f 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -27,9 +27,10 @@ #include <limits.h> #include <sys/file.h> -#include "util.h" -#include "lockfile-util.h" +#include "fd-util.h" #include "fileio.h" +#include "lockfile-util.h" +#include "util.h" int make_lock_file(const char *p, int operation, LockFile *ret) { _cleanup_close_ int fd = -1; diff --git a/src/basic/log.c b/src/basic/log.c index acc390b8d3..99dccb1f10 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -31,7 +31,9 @@ #include "sd-messages.h" +#include "fd-util.h" #include "formats-util.h" +#include "log.h" #include "macro.h" #include "missing.h" #include "process-util.h" @@ -40,7 +42,6 @@ #include "string-util.h" #include "terminal-util.h" #include "util.h" -#include "log.h" #define SNDBUF_SIZE (8*1024*1024) diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 4dafd69daf..9d638b27f0 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -27,11 +27,12 @@ #include <sys/mman.h> #include <sys/prctl.h> +#include "fd-util.h" +#include "memfd-util.h" #include "missing.h" #include "string-util.h" #include "utf8.h" #include "util.h" -#include "memfd-util.h" int memfd_new(const char *name) { _cleanup_free_ char *g = NULL; diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 3ed551fb37..2cb404ea81 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -21,7 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include <sys/types.h> +#include <inttypes.h> int memfd_new(const char *name); int memfd_new_and_map(const char *name, size_t sz, void **p); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 31328807f4..7b01633f5f 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -27,14 +27,15 @@ #include <sys/statvfs.h> #include <unistd.h> +#include "fd-util.h" #include "fileio.h" #include "log.h" #include "macro.h" #include "missing.h" +#include "path-util.h" #include "string-util.h" #include "strv.h" #include "util.h" -#include "path-util.h" bool path_is_absolute(const char *p) { return p[0] == '/'; diff --git a/src/basic/process-util.c b/src/basic/process-util.c index bfde17a956..949bd1f64d 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -29,12 +29,13 @@ #include <unistd.h> #include "escape.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" +#include "process-util.h" #include "signal-util.h" #include "string-util.h" #include "util.h" -#include "process-util.h" int get_process_state(pid_t pid) { const char *p; diff --git a/src/basic/random-util.c b/src/basic/random-util.c index b230044f50..e183165b9f 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -17,20 +17,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> #include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> -#include <time.h> +#include <linux/random.h> +#include <stdint.h> #ifdef HAVE_SYS_AUXV_H #include <sys/auxv.h> #endif -#include <linux/random.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include "fd-util.h" +#include "missing.h" #include "random-util.h" #include "time-util.h" -#include "missing.h" #include "util.h" int dev_urandom(void *p, size_t n) { diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index 5a75090a6d..a5daa23f86 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -20,10 +20,11 @@ ***/ #include "btrfs-util.h" +#include "fd-util.h" #include "path-util.h" +#include "rm-rf.h" #include "string-util.h" #include "util.h" -#include "rm-rf.h" int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { _cleanup_closedir_ DIR *d = NULL; diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 937124cc02..4099ea6f9f 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -19,18 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> #include <errno.h> -#include <sys/stat.h> #include <stddef.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include "fd-util.h" #include "macro.h" -#include "util.h" -#include "mkdir.h" #include "missing.h" +#include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" +#include "util.h" int socket_address_listen( const SocketAddress *a, diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 4723653566..5949b99c95 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -31,13 +31,14 @@ #include <time.h> #include <unistd.h> +#include "fd-util.h" #include "fileio.h" #include "path-util.h" #include "process-util.h" #include "string-util.h" +#include "terminal-util.h" #include "time-util.h" #include "util.h" -#include "terminal-util.h" static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; diff --git a/src/basic/time-util.c b/src/basic/time-util.c index a516d2807b..d117380d52 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -23,11 +23,12 @@ #include <sys/timerfd.h> #include <sys/timex.h> +#include "fd-util.h" #include "path-util.h" #include "string-util.h" #include "strv.h" -#include "util.h" #include "time-util.h" +#include "util.h" usec_t now(clockid_t clock_id) { struct timespec ts; diff --git a/src/basic/util.c b/src/basic/util.c index 233a6c2e35..05f34ea52c 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -79,6 +79,7 @@ #include "env-util.h" #include "escape.h" #include "exit-status.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "gunicode.h" @@ -98,8 +99,8 @@ #include "strv.h" #include "terminal-util.h" #include "utf8.h" -#include "virt.h" #include "util.h" +#include "virt.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -121,98 +122,6 @@ size_t page_size(void) { return pgsz; } -int close_nointr(int fd) { - assert(fd >= 0); - - if (close(fd) >= 0) - return 0; - - /* - * Just ignore EINTR; a retry loop is the wrong thing to do on - * Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (errno == EINTR) - return 0; - - return -errno; -} - -int safe_close(int fd) { - - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ - - if (fd >= 0) { - PROTECT_ERRNO; - - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ - - assert_se(close_nointr(fd) != -EBADF); - } - - return -1; -} - -void close_many(const int fds[], unsigned n_fd) { - unsigned i; - - assert(fds || n_fd <= 0); - - for (i = 0; i < n_fd; i++) - safe_close(fds[i]); -} - -int fclose_nointr(FILE *f) { - assert(f); - - /* Same as close_nointr(), but for fclose() */ - - if (fclose(f) == 0) - return 0; - - if (errno == EINTR) - return 0; - - return -errno; -} - -FILE* safe_fclose(FILE *f) { - - /* Same as safe_close(), but for fclose() */ - - if (f) { - PROTECT_ERRNO; - - assert_se(fclose_nointr(f) != EBADF); - } - - return NULL; -} - -DIR* safe_closedir(DIR *d) { - - if (d) { - PROTECT_ERRNO; - - assert_se(closedir(d) >= 0 || errno != EBADF); - } - - return NULL; -} - int unlink_noerrno(const char *path) { PROTECT_ERRNO; int r; @@ -1304,123 +1213,6 @@ bool hidden_file(const char *filename) { return hidden_file_allow_backup(filename); } -int fd_nonblock(int fd, bool nonblock) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) - return -errno; - - if (nonblock) - nflags = flags | O_NONBLOCK; - else - nflags = flags & ~O_NONBLOCK; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFL, nflags) < 0) - return -errno; - - return 0; -} - -int fd_cloexec(int fd, bool cloexec) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) - return -errno; - - if (cloexec) - nflags = flags | FD_CLOEXEC; - else - nflags = flags & ~FD_CLOEXEC; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFD, nflags) < 0) - return -errno; - - return 0; -} - -_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; - - assert(n_fdset == 0 || fdset); - - for (i = 0; i < n_fdset; i++) - if (fdset[i] == fd) - return true; - - return false; -} - -int close_all_fds(const int except[], unsigned n_except) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - - assert(n_except == 0 || except); - - d = opendir("/proc/self/fd"); - if (!d) { - int fd; - struct rlimit rl; - - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd - * table */ - - assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) - if (errno != EBADF && r == 0) - r = -errno; - } - - return r; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (hidden_file(de->d_name)) - continue; - - if (safe_atoi(de->d_name, &fd) < 0) - /* Let's better ignore this, just in case */ - continue; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) { - /* Valgrind has its own FD and doesn't want to have it closed */ - if (errno != EBADF && r == 0) - r = -errno; - } - } - - return r; -} - bool fstype_is_network(const char *fstype) { static const char table[] = "afs\0" @@ -1480,20 +1272,6 @@ int flush_fd(int fd) { } } -void safe_close_pair(int p[]) { - assert(p); - - if (p[0] == p[1]) { - /* Special case pairs which use the same fd in both - * directions... */ - p[0] = p[1] = safe_close(p[0]); - return; - } - - p[0] = safe_close(p[0]); - p[1] = safe_close(p[1]); -} - ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { uint8_t *p = buf; ssize_t n = 0; @@ -4804,71 +4582,6 @@ int fd_setcrtime(int fd, usec_t usec) { return 0; } -int same_fd(int a, int b) { - struct stat sta, stb; - pid_t pid; - int r, fa, fb; - - assert(a >= 0); - assert(b >= 0); - - /* Compares two file descriptors. Note that semantics are - * quite different depending on whether we have kcmp() or we - * don't. If we have kcmp() this will only return true for - * dup()ed file descriptors, but not otherwise. If we don't - * have kcmp() this will also return true for two fds of the same - * file, created by separate open() calls. Since we use this - * call mostly for filtering out duplicates in the fd store - * this difference hopefully doesn't matter too much. */ - - if (a == b) - return true; - - /* Try to use kcmp() if we have it. */ - pid = getpid(); - r = kcmp(pid, pid, KCMP_FILE, a, b); - if (r == 0) - return true; - if (r > 0) - return false; - if (errno != ENOSYS) - return -errno; - - /* We don't have kcmp(), use fstat() instead. */ - if (fstat(a, &sta) < 0) - return -errno; - - if (fstat(b, &stb) < 0) - return -errno; - - if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) - return false; - - /* We consider all device fds different, since two device fds - * might refer to quite different device contexts even though - * they share the same inode and backing dev_t. */ - - if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) - return false; - - if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) - return false; - - /* The fds refer to the same inode on disk, let's also check - * if they have the same fd flags. This is useful to - * distinguish the read and write side of a pipe created with - * pipe(). */ - fa = fcntl(a, F_GETFL); - if (fa < 0) - return -errno; - - fb = fcntl(b, F_GETFL); - if (fb < 0) - return -errno; - - return fa == fb; -} - int chattr_fd(int fd, unsigned value, unsigned mask) { unsigned old_attr, new_attr; struct stat st; @@ -5075,16 +4788,6 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return -1; } -void cmsg_close_all(struct msghdr *mh) { - struct cmsghdr *cmsg; - - assert(mh); - - CMSG_FOREACH(cmsg, mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) - close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); -} - int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { struct stat buf; int ret; diff --git a/src/basic/util.h b/src/basic/util.h index d1da9ce106..e50fd69664 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -87,16 +87,6 @@ static inline const char* one_zero(bool b) { return b ? "1" : "0"; } -int close_nointr(int fd); -int safe_close(int fd); -void safe_close_pair(int p[]); - -void close_many(const int fds[], unsigned n_fd); - -int fclose_nointr(FILE *f); -FILE* safe_fclose(FILE *f); -DIR* safe_closedir(DIR *f); - int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_boolean(const char *v) _pure_; @@ -245,11 +235,6 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k } \ struct __useless_struct_to_allow_trailing_semicolon__ -int fd_nonblock(int fd, bool nonblock); -int fd_cloexec(int fd, bool cloexec); - -int close_all_fds(const int except[], unsigned n_except); - bool fstype_is_network(const char *fstype); int flush_fd(int fd); @@ -410,35 +395,16 @@ static inline void freep(void *p) { free(*(void**) p); } -static inline void closep(int *fd) { - safe_close(*fd); -} - static inline void umaskp(mode_t *u) { umask(*u); } -static inline void close_pairp(int (*p)[2]) { - safe_close_pair(*p); -} - -static inline void fclosep(FILE **f) { - safe_fclose(*f); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); #define _cleanup_free_ _cleanup_(freep) -#define _cleanup_close_ _cleanup_(closep) #define _cleanup_umask_ _cleanup_(umaskp) #define _cleanup_globfree_ _cleanup_(globfree) -#define _cleanup_fclose_ _cleanup_(fclosep) -#define _cleanup_pclose_ _cleanup_(pclosep) -#define _cleanup_closedir_ _cleanup_(closedirp) #define _cleanup_endmntent_ _cleanup_(endmntentp) -#define _cleanup_close_pair_ _cleanup_(close_pairp) _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) @@ -747,8 +713,6 @@ int fd_getcrtime(int fd, usec_t *usec); int path_getcrtime(const char *p, usec_t *usec); int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags); -int same_fd(int a, int b); - int chattr_fd(int fd, unsigned value, unsigned mask); int chattr_path(const char *p, unsigned value, unsigned mask); @@ -764,8 +728,6 @@ void sigkill_wait(pid_t *pid); int syslog_parse_priority(const char **p, int *priority, bool with_facility); -void cmsg_close_all(struct msghdr *mh); - int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); int parse_mode(const char *s, mode_t *ret); |