+#include "log.h"
+
+static int close_fds(int except[], unsigned n_except) {
+ DIR *d;
+ struct dirent *de;
+ int r = 0;
+
+ /* Modifies the fds array! (sorts it) */
+
+ if (!(d = opendir("/proc/self/fd")))
+ return -errno;
+
+ while ((de = readdir(d))) {
+ int fd;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if ((r = safe_atoi(de->d_name, &fd)) < 0)
+ goto finish;
+
+ if (fd < 3)
+ continue;
+
+ if (fd == dirfd(d))
+ continue;
+
+ if (except) {
+ bool found;
+ unsigned i;
+
+ found = false;
+ for (i = 0; i < n_except; i++)
+ if (except[i] == fd) {
+ found = true;
+ break;
+ }
+
+ if (found)
+ continue;
+ }
+
+ if ((r = close_nointr(fd)) < 0)
+ goto finish;
+ }
+
+finish:
+ closedir(d);
+ return r;
+}
+
+static int shift_fds(int fds[], unsigned n_fds) {
+ int start, restart_from;
+
+ if (n_fds <= 0)
+ return 0;
+
+ assert(fds);
+
+ start = 0;
+ for (;;) {
+ int i;
+
+ restart_from = -1;
+
+ for (i = start; i < (int) n_fds; i++) {
+ int nfd;
+
+ /* Already at right index? */
+ if (fds[i] == i+3)
+ continue;
+
+ if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
+ return -errno;
+
+ assert_se(close_nointr(fds[i]) == 0);
+ fds[i] = nfd;
+
+ /* Hmm, the fd we wanted isn't free? Then
+ * let's remember that and try again from here*/
+ if (nfd != i+3 && restart_from < 0)
+ restart_from = i;
+ }
+
+ if (restart_from < 0)
+ break;
+
+ start = restart_from;
+ }
+
+ return 0;
+}
+
+static int flags_fds(int fds[], unsigned n_fds) {
+ unsigned i;
+
+ if (n_fds <= 0)
+ return 0;
+
+ assert(fds);
+
+ /* Drops O_NONBLOCK and FD_CLOEXEC from the file flags */
+
+ for (i = 0; i < n_fds; i++) {
+ int flags;
+
+ if ((flags = fcntl(fds[i], F_GETFL, 0)) < 0)
+ return -errno;
+
+ /* Since we are at it, let's make sure that nobody
+ * forgot setting O_NONBLOCK for all our fds */
+
+ if (fcntl(fds[i], F_SETFL, flags &~O_NONBLOCK) < 0)
+ return -errno;
+
+ if ((flags = fcntl(fds[i], F_GETFD, 0)) < 0)
+ return -errno;
+
+ /* Also make sure nobody forgot O_CLOEXEC for all our
+ * fds */
+ if (fcntl(fds[i], F_SETFD, flags &~FD_CLOEXEC) < 0)
+ return -errno;
+ }
+
+ return 0;
+}
+
+int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, unsigned n_fds, pid_t *ret) {
+ pid_t pid;