Exemplo n.º 1
0
int run_as_daemon() 
{
  switch (fork())
    {
    case 0: break;
    case -1: return -1;
    default: _exit(0); /* exit the original process */
    }

  if (setsid() < 0)    /* shouldn't fail */
    return -1;

  switch (fork()) 
    {
    case 0: break;
    case -1: return -1;
    default: _exit(0);
    }

  /* change to root dir to ensure no directory is blocked */
  chdir("/");

  /* close all fds */
  close_all_fds(0);
  dup(0); dup(0);

  return 0;
}
Exemplo n.º 2
0
static pid_t
start_child(struct stService *p, int fd)
{
	pid_t	pid;

	pid = vfork();

	if (pid == 0) {
		if (fd != 0)
			dup2(fd, 0);
		if (fd != 1)
			dup2(fd, 1);
		if (fd != 2)
			dup2(fd, 2);
		if (fd > 2)
			close(fd);
		close_all_fds(2);
		execlp(p->args[0],
				p->args[0],
				p->args[1],
				p->args[2],
				p->args[3],
				p->args[4],
				p->args[5],
				NULL
				);
		_exit(0);
	}
	return(pid);
}
Exemplo n.º 3
0
/* The exec core used right after the fork. This will never return. */
static void
do_exec (const char *pgmname, const char *argv[],
         int fd_in, int fd_out, int fd_err,
         void (*preexec)(void) )
{
    char **arg_list;
    int i, j;
    int fds[3];

    fds[0] = fd_in;
    fds[1] = fd_out;
    fds[2] = fd_err;

    /* Create the command line argument array.  */
    i = 0;
    if (argv)
        while (argv[i])
            i++;
    arg_list = xcalloc (i+2, sizeof *arg_list);
    arg_list[0] = strrchr (pgmname, '/');
    if (arg_list[0])
        arg_list[0]++;
    else
        arg_list[0] = xstrdup (pgmname);
    if (argv)
        for (i=0,j=1; argv[i]; i++, j++)
            arg_list[j] = (char*)argv[i];

    /* Assign /dev/null to unused FDs. */
    for (i=0; i <= 2; i++)
    {
        if (fds[i] == -1 )
        {
            fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
            if (fds[i] == -1)
                log_fatal ("failed to open '%s': %s\n",
                           "/dev/null", strerror (errno));
        }
    }

    /* Connect the standard files.  */
    for (i=0; i <= 2; i++)
    {
        if (fds[i] != i && dup2 (fds[i], i) == -1)
            log_fatal ("dup2 std%s failed: %s\n",
                       i==0?"in":i==1?"out":"err", strerror (errno));
    }

    /* Close all other files. */
    close_all_fds (3, NULL);

    if (preexec)
        preexec ();
    execv (pgmname, arg_list);
    /* No way to print anything, as we have closed all streams. */
    _exit (127);
}
Exemplo n.º 4
0
static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
        int pipe_fds[2];
        pid_t pid;

        assert(database);
        assert(key);
        assert(rpid);

        if (pipe2(pipe_fds, O_CLOEXEC) < 0)
                return log_error_errno(errno, "Failed to allocate pipe: %m");

        pid = fork();
        if (pid < 0)
                return log_error_errno(errno, "Failed to fork getent child: %m");
        else if (pid == 0) {
                int nullfd;
                char *empty_env = NULL;

                if (dup3(pipe_fds[1], STDOUT_FILENO, 0) < 0)
                        _exit(EXIT_FAILURE);

                if (pipe_fds[0] > 2)
                        safe_close(pipe_fds[0]);
                if (pipe_fds[1] > 2)
                        safe_close(pipe_fds[1]);

                nullfd = open("/dev/null", O_RDWR);
                if (nullfd < 0)
                        _exit(EXIT_FAILURE);

                if (dup3(nullfd, STDIN_FILENO, 0) < 0)
                        _exit(EXIT_FAILURE);

                if (dup3(nullfd, STDERR_FILENO, 0) < 0)
                        _exit(EXIT_FAILURE);

                if (nullfd > 2)
                        safe_close(nullfd);

                (void) reset_all_signal_handlers();
                (void) reset_signal_mask();
                close_all_fds(NULL, 0);

                execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
                execle("/bin/getent", "getent", database, key, NULL, &empty_env);
                _exit(EXIT_FAILURE);
        }

        pipe_fds[1] = safe_close(pipe_fds[1]);

        *rpid = pid;

        return pipe_fds[0];
}
Exemplo n.º 5
0
static int open_sockets(int *epoll_fd, bool accept) {
        char **address;
        int n, fd, r;
        int count = 0;

        n = sd_listen_fds(true);
        if (n < 0) {
                log_error("Failed to read listening file descriptors from environment: %s",
                          strerror(-n));
                return n;
        }
        if (n > 0) {
                log_info("Received %i descriptors via the environment.", n);

                for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
                        r = fd_cloexec(fd, arg_accept);
                        if (r < 0)
                                return r;

                        count ++;
                }
        }

        /* Close logging and all other descriptors */
        if (arg_listen) {
                int except[3 + n];

                for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++)
                        except[fd] = fd;

                log_close();
                close_all_fds(except, 3 + n);
        }

        /** Note: we leak some fd's on error here. I doesn't matter
         *  much, since the program will exit immediately anyway, but
         *  would be a pain to fix.
         */

        STRV_FOREACH(address, arg_listen) {

                fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
                if (fd < 0) {
                        log_open();
                        log_error("Failed to open '%s': %s", *address, strerror(-fd));
                        return fd;
                }

                assert(fd == SD_LISTEN_FDS_START + count);
                count ++;
        }
Exemplo n.º 6
0
int fdset_close_others(FDSet *fds) {
        void *e;
        Iterator i;
        int *a;
        unsigned j, m;

        j = 0, m = fdset_size(fds);
        a = alloca(sizeof(int) * m);
        SET_FOREACH(e, MAKE_SET(fds), i)
                a[j++] = PTR_TO_FD(e);

        assert(j == m);

        return close_all_fds(a, j);
}
Exemplo n.º 7
0
void emancipate(int sig) {
  signal(sig, SIG_DFL);
  noitL(noit_error, "emancipate: process %d, monitored %d, signal %d\n", getpid(), noit_monitored_child_pid, sig);
  if(getpid() == watcher) {
    run_glider(noit_monitored_child_pid);
    kill(noit_monitored_child_pid, sig);
  }
  else if (getpid() == noit_monitored_child_pid){
    it_ticks_crash(); /* slow notification path */
    kill(noit_monitored_child_pid, SIGSTOP); /* stop and wait for a glide */

    if(allow_async_dumps) { 
      stop_other_threads(); /* suspend all peer threads... to safely */
      close_all_fds(); /* close all our FDs */
      it_ticks_crash_release(); /* notify parent that it can fork a new one */
      /* the subsequent dump may take a while on big processes and slow disks */
    }
    kill(noit_monitored_child_pid, sig);
  }
}
Exemplo n.º 8
0
int main(int argc, char *argv[]) {
        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
        _cleanup_bus_close_unref_ sd_bus *bus = NULL;
        int r;

        log_parse_environment();
        log_open();

        r = parse_argv(argc, argv);
        if (r < 0)
                return EXIT_FAILURE;
        if (r == 0)
                return EXIT_SUCCESS;

        r = sd_bus_default_system(&bus);
        if (r < 0) {
                log_error("Failed to connect to bus: %s", strerror(-r));
                return EXIT_FAILURE;
        }

        if (arg_action == ACTION_LIST) {

                r = print_inhibitors(bus, &error);
                if (r < 0) {
                        log_error("Failed to list inhibitors: %s", bus_error_message(&error, -r));
                        return EXIT_FAILURE;
                }

        } else {
                _cleanup_close_ int fd = -1;
                _cleanup_free_ char *w = NULL;
                pid_t pid;

                if (!arg_who)
                        arg_who = w = strv_join(argv + optind, " ");

                fd = inhibit(bus, &error);
                if (fd < 0) {
                        log_error("Failed to inhibit: %s", bus_error_message(&error, -r));
                        return EXIT_FAILURE;
                }

                pid = fork();
                if (pid < 0) {
                        log_error("Failed to fork: %m");
                        return EXIT_FAILURE;
                }

                if (pid == 0) {
                        /* Child */

                        close_all_fds(NULL, 0);

                        execvp(argv[optind], argv + optind);
                        log_error("Failed to execute %s: %m", argv[optind]);
                        _exit(EXIT_FAILURE);
                }

                r = wait_for_terminate_and_warn(argv[optind], pid);
                return r < 0 ? EXIT_FAILURE : r;
        }

        return 0;
}
Exemplo n.º 9
0
static pid_t
start_child(struct stService *p, int fd, int tcp, int ipv6, int local_port, union sa *remote)
{
  pid_t pid;
  const char *proto = tcp ? "TCP" : "UDP";
#ifdef CONFIG_IPV6
  char buf[INET6_ADDRSTRLEN];
#endif

  init_env();
  add_env("PROTO=%s", proto);
  if (tcp) {
    union sa local;
    socklen_t local_size = sizeof(local);

#ifdef CONFIG_IPV6
    if (ipv6) {
      if (getsockname(fd, &local.sa, &local_size) == 0) {
        add_env("TCPLOCALIP=%s", inet_ntop(AF_INET6, &local.sin6.sin6_addr, buf, sizeof(buf)));
      }
      else {
        add_env("TCPLOCALIP=::");
      }
      add_env("TCPREMOTEIP=%s", inet_ntop(AF_INET6, &remote->sin6.sin6_addr, buf, sizeof(buf)));
      add_env("%sREMOTEPORT=%d", proto, ntohs(remote->sin6.sin6_port));
    } else
#endif
    {
      if (getsockname(fd, &local.sa, &local_size) == 0) {
        add_env("TCPLOCALIP=%s", inet_ntoa(local.sin.sin_addr));
      }
      else {
        add_env("TCPLOCALIP=0.0.0.0");
      }
      add_env("TCPREMOTEIP=%s", inet_ntoa(remote->sin.sin_addr));
      add_env("%sREMOTEPORT=%d", proto, ntohs(remote->sin.sin_port));
    }
  }
  add_env("%sLOCALPORT=%d", proto, local_port);
  add_env("PATH=%s", getenv("PATH") ?: "/bin:/usr/bin:/sbin:/usr/sbin");
  env_pointers[env_count] = 0;

#ifdef DEBUG
  fprintf(stderr, "start_child(%s port %d from %s)\n", proto, local_port, 
#ifdef CONFIG_IPV6
        ipv6 ? inet_ntop(AF_INET6, &remote->sin6.sin6_addr, buf, sizeof(buf)) :
#endif
        inet_ntoa(remote->sin.sin_addr));

  {
    int i;

    for (i = 0; env_pointers[i]; i++) {
      fprintf(stderr, "ENV[%d]: %s\n", i, env_pointers[i]);
    }
  }
#endif

  pid = vfork();

  if (pid == 0) {
    if (fd != 0)
      dup2(fd, 0);
    if (fd != 1)
      dup2(fd, 1);
#if 1
    /* Don't redirect stderr to stdout */
    if (fd != 2)
      dup2(fd, 2);
#endif
    if (fd > 2)
      close(fd);
    close_all_fds(2);

    /* There is no execvpe, so we kludge it */
    environ = env_pointers;
    execvp(p->args[0], p->args);
    fprintf(stderr, "execve failed!\n");
    _exit(0);
  }
  return(pid);
}
Exemplo n.º 10
0
/* That is a very crude test.  To do a proper test we would need to
   fork a test process and best return information by some other means
   than file descriptors. */
static void
test_close_all_fds (void)
{
  int max_fd = get_max_fds ();
  int *array;
  int fd;
  int initial_count, count, n;
#if 0
  char buffer[100];

  snprintf (buffer, sizeof buffer, "/bin/ls -l /proc/%d/fd", (int)getpid ());
  system (buffer);
#endif

  printf ("max. file descriptors: %d\n", max_fd);
  array = xget_all_open_fds ();
  print_open_fds (array);
  for (initial_count=n=0; array[n] != -1; n++)
    initial_count++;
  free (array);

  /* Some dups to get more file descriptors and close one. */
  dup (1);
  dup (1);
  fd = dup (1);
  dup (1);
  close (fd);

  array = xget_all_open_fds ();
  if (verbose)
    print_open_fds (array);
  for (count=n=0; array[n] != -1; n++)
    count++;
  if (count != initial_count+3)
    {
      fprintf (stderr, "%s:%d: dup or close failed\n",
               __FILE__, __LINE__);
      exit (1);
    }
  free (array);

  /* Close the non standard ones.  */
  close_all_fds (3, NULL);

  /* Get a list to check whether they are all closed.  */
  array = xget_all_open_fds ();
  if (verbose)
    print_open_fds (array);
  for (count=n=0; array[n] != -1; n++)
    count++;
  if (count > initial_count)
    {
      fprintf (stderr, "%s:%d: not all files were closed\n",
               __FILE__, __LINE__);
      exit (1);
    }
  initial_count = count;
  free (array);

  /* Now let's check the realloc we use.  We do this and the next
     tests only if we are allowed to open enought descriptors.  */
  if (get_max_fds () > 32)
    {
      int except[] = { 20, 23, 24, -1 };

      for (n=initial_count; n < 31; n++)
        dup (1);
      array = xget_all_open_fds ();
      if (verbose)
        print_open_fds (array);
      free (array);
      for (n=0; n < 5; n++)
        {
          dup (1);
          array = xget_all_open_fds ();
          if (verbose)
            print_open_fds (array);
          free (array);
        }
      
      /* Check whether the except list works.  */
      close_all_fds (3, except);
      array = xget_all_open_fds ();
      if (verbose)
        print_open_fds (array);
      for (count=n=0; array[n] != -1; n++)
        count++;
      free (array);

      if (count != initial_count + DIM(except)-1)
        {
          fprintf (stderr, "%s:%d: close_all_fds failed\n",
                   __FILE__, __LINE__);
          exit (1);
        }
    }

}
Exemplo n.º 11
0
int main(int argc, char *argv[]) {
        int r, exit_code = 0;
        DBusConnection *bus = NULL;
        DBusError error;
        _cleanup_close_ int fd = -1;

        dbus_error_init(&error);

        log_parse_environment();
        log_open();

        r = parse_argv(argc, argv);
        if (r <= 0)
                goto finish;

        bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
        if (!bus) {
                log_error("Failed to connect to bus: %s", bus_error_message(&error));
                r = -EIO;
                goto finish;
        }

        if (arg_action == ACTION_LIST) {

                r = print_inhibitors(bus, &error);
                if (r < 0) {
                        log_error("Failed to list inhibitors: %s", bus_error(&error, r));
                        goto finish;
                }

        } else {
                char *w = NULL;
                pid_t pid;

                if (!arg_who)
                        arg_who = w = strv_join(argv + optind, " ");

                fd = inhibit(bus, &error);
                free(w);

                if (fd < 0) {
                        log_error("Failed to inhibit: %s", bus_error(&error, r));
                        r = fd;
                        goto finish;
                }

                pid = fork();
                if (pid < 0) {
                        log_error("Failed to fork: %m");
                        r = -errno;
                        goto finish;
                }

                if (pid == 0) {
                        /* Child */

                        safe_close(fd);
                        close_all_fds(NULL, 0);

                        execvp(argv[optind], argv + optind);
                        log_error("Failed to execute %s: %m", argv[optind]);
                        _exit(EXIT_FAILURE);
                }

                r = wait_for_terminate_and_warn(argv[optind], pid);
                if (r >= 0)
                        exit_code = r;
        }

finish:
        if (bus) {
                dbus_connection_close(bus);
                dbus_connection_unref(bus);
        }

        dbus_error_free(&error);

        return r < 0 ? EXIT_FAILURE : exit_code;
}
Exemplo n.º 12
0
int stub_pid1(sd_id128_t uuid) {
        enum {
                STATE_RUNNING,
                STATE_REBOOT,
                STATE_POWEROFF,
        } state = STATE_RUNNING;

        sigset_t fullmask, oldmask, waitmask;
        usec_t quit_usec = USEC_INFINITY;
        pid_t pid;
        int r;

        /* The new environment we set up, on the stack. */
        char new_environment[] =
                "container=systemd-nspawn\0"
                "container_uuid=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        /* Implements a stub PID 1, that reaps all processes and processes a couple of standard signals. This is useful
         * for allowing arbitrary processes run in a container, and still have all zombies reaped. */

        assert_se(sigfillset(&fullmask) >= 0);
        assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);

        pid = fork();
        if (pid < 0)
                return log_error_errno(errno, "Failed to fork child pid: %m");

        if (pid == 0) {
                /* Return in the child */
                assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0);
                setsid();
                return 0;
        }

        reset_all_signal_handlers();

        log_close();
        close_all_fds(NULL, 0);
        log_open();

        /* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also,
         * set $container= and $container_uuid= so that clients in the container that query it from /proc/1/environ
         * find them set set. */
        sd_id128_to_string(uuid, new_environment + sizeof(new_environment) - SD_ID128_STRING_MAX);
        reset_environ(new_environment, sizeof(new_environment));

        rename_process("STUBINIT");

        assert_se(sigemptyset(&waitmask) >= 0);
        assert_se(sigset_add_many(&waitmask,
                                  SIGCHLD,          /* posix: process died */
                                  SIGINT,           /* sysv: ctrl-alt-del */
                                  SIGRTMIN+3,       /* systemd: halt */
                                  SIGRTMIN+4,       /* systemd: poweroff */
                                  SIGRTMIN+5,       /* systemd: reboot */
                                  SIGRTMIN+6,       /* systemd: kexec */
                                  SIGRTMIN+13,      /* systemd: halt */
                                  SIGRTMIN+14,      /* systemd: poweroff */
                                  SIGRTMIN+15,      /* systemd: reboot */
                                  SIGRTMIN+16,      /* systemd: kexec */
                                  -1) >= 0);

        /* Note that we ignore SIGTERM (sysv's reexec), SIGHUP (reload), and all other signals here, since we don't
         * support reexec/reloading in this stub process. */

        for (;;) {
                siginfo_t si;
                usec_t current_usec;

                si.si_pid = 0;
                r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG);
                if (r < 0) {
                        r = log_error_errno(errno, "Failed to reap children: %m");
                        goto finish;
                }

                current_usec = now(CLOCK_MONOTONIC);

                if (si.si_pid == pid || current_usec >= quit_usec) {

                        /* The child we started ourselves died or we reached a timeout. */

                        if (state == STATE_REBOOT) { /* dispatch a queued reboot */
                                (void) reboot(RB_AUTOBOOT);
                                r = log_error_errno(errno, "Failed to reboot: %m");
                                goto finish;

                        } else if (state == STATE_POWEROFF)
                                (void) reboot(RB_POWER_OFF); /* if this fails, fall back to normal exit. */

                        if (si.si_pid == pid && si.si_code == CLD_EXITED)
                                r = si.si_status; /* pass on exit code */
                        else
                                r = 255; /* signal, coredump, timeout, … */

                        goto finish;
                }
                if (si.si_pid != 0)
                        /* We reaped something. Retry until there's nothing more to reap. */
                        continue;

                if (quit_usec == USEC_INFINITY)
                        r = sigwaitinfo(&waitmask, &si);
                else {
                        struct timespec ts;
                        r = sigtimedwait(&waitmask, &si, timespec_store(&ts, quit_usec - current_usec));
                }
                if (r < 0) {
                        if (errno == EINTR) /* strace -p attach can result in EINTR, let's handle this nicely. */
                                continue;
                        if (errno == EAGAIN) /* timeout reached */
                                continue;

                        r = log_error_errno(errno, "Failed to wait for signal: %m");
                        goto finish;
                }

                if (si.si_signo == SIGCHLD)
                        continue; /* Let's reap this */

                if (state != STATE_RUNNING)
                        continue;

                /* Would love to use a switch() statement here, but SIGRTMIN is actually a function call, not a
                 * constant… */

                if (si.si_signo == SIGRTMIN+3 ||
                    si.si_signo == SIGRTMIN+4 ||
                    si.si_signo == SIGRTMIN+13 ||
                    si.si_signo == SIGRTMIN+14)

                        state = STATE_POWEROFF;

                else if (si.si_signo == SIGINT ||
                         si.si_signo == SIGRTMIN+5 ||
                         si.si_signo == SIGRTMIN+6 ||
                         si.si_signo == SIGRTMIN+15 ||
                         si.si_signo == SIGRTMIN+16)

                        state = STATE_REBOOT;
                else
                        assert_not_reached("Got unexpected signal");

                /* (void) kill_and_sigcont(pid, SIGTERM); */
                quit_usec = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC;
        }

finish:
        _exit(r < 0 ? EXIT_FAILURE : r);
}
Exemplo n.º 13
0
static int add_epoll(int epoll_fd, int fd) {
        struct epoll_event ev = {
                .events = EPOLLIN,
                .data.fd = fd,
        };

        assert(epoll_fd >= 0);
        assert(fd >= 0);

        if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
                return log_error_errno(errno, "Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd, fd);

        return 0;
}

static int open_sockets(int *epoll_fd, bool accept) {
        char **address;
        int n, fd, r;
        int count = 0;

        n = sd_listen_fds(true);
        if (n < 0)
                return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
        if (n > 0) {
                log_info("Received %i descriptors via the environment.", n);

                for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
                        r = fd_cloexec(fd, arg_accept);
                        if (r < 0)
                                return r;

                        count++;
                }
        }

        /* Close logging and all other descriptors */
        if (arg_listen) {
                int except[3 + n];

                for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++)
                        except[fd] = fd;

                log_close();
                close_all_fds(except, 3 + n);
        }

        /** Note: we leak some fd's on error here. I doesn't matter
         *  much, since the program will exit immediately anyway, but
         *  would be a pain to fix.
         */

        STRV_FOREACH(address, arg_listen) {
                fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept*SOCK_CLOEXEC));
                if (fd < 0) {
                        log_open();
                        return log_error_errno(fd, "Failed to open '%s': %m", *address);
                }

                assert(fd == SD_LISTEN_FDS_START + count);
                count++;
        }