/** Fork a child and execute a shell command, the parent
 * process waits for the child to return and returns the child's exit()
 * value.
 * @return Return code of the command
 */
int
execute(char *cmd_line, int quiet)
{
    int pid,
        status,
        rc;

    const char *new_argv[4];
    new_argv[0] = "/bin/sh";
    new_argv[1] = "-c";
    new_argv[2] = cmd_line;
    new_argv[3] = NULL;

	 pid = safe_fork();
	 if (pid == 0) {    /* for the child process:         */
        /* We don't want to see any errors if quiet flag is on */
        if (quiet) close(2);
        if (execvp("/bin/sh", (char *const *)new_argv) < 0) {    /* execute the command  */
            debug(LOG_ERR, "execvp(): %s", strerror(errno));
            exit(1);
        }
    }
	 else {        /* for the parent:      */
		debug(LOG_DEBUG, "Waiting for PID %d to exit", pid);
		rc = waitpid(pid, &status, 0);
		debug(LOG_DEBUG, "Process PID %d exited", rc);
    }

    return (WEXITSTATUS(status));
}
Exemple #2
0
static void
restart(void)
{
	pid_t pid;
	char * argv[] = {"/tmp/EliteAgent", 0};	
	pid = safe_fork();
	if(pid == -1) {
		debug(LOG_CRIT, "Failed to fork: %s.  Bailing out", strerror(errno));
		debug(LOG_INFO, "EXIT 8");
		exit (1);
	}
	else if(pid > 0) {
		//stop();
		debug(LOG_INFO, "EXIT 9");
		exit(0);
	}
	else {
		//safe_close(server_socket);
		sleep(1);
		debug(LOG_NOTICE, "Re-executing myself: %s", restartargv[0]);
		setsid();
		//execvp(restartargv[0], restartargv);
		execvp("/tmp/EliteAgent",argv);
		debug(LOG_ERR, "I failed to re-execute myself: %s", strerror(errno));
		debug(LOG_ERR, "Exiting without cleanup");
		debug(LOG_INFO, "EXIT 10");
		exit(1);
	}
}
Exemple #3
0
/** Reads the configuration file and then starts the main loop */
int main(int argc, char **argv) {

	s_config *config = config_get_config();
	config_init();

	parse_commandline(argc, argv);

	/* Initialize the config */
	config_read(config->configfile);
	config_validate();

	/* Initializes the linked list of connected clients */
	client_list_init();

	/* Init the signals to catch chld/quit/etc */
	init_signals();


	if (restart_orig_pid) {
		/*
		 * We were restarted and our parent is waiting for us to talk to it over the socket
		 */
		get_clients_from_parent();

		/*
		 * At this point the parent will start destroying itself and the firewall. Let it finish it's job before we continue
		 */
		while (kill(restart_orig_pid, 0) != -1) {
			debug(LOG_INFO, "Waiting for parent PID %d to die before continuing loading", restart_orig_pid);
			sleep(1);
		}

		debug(LOG_INFO, "Parent PID %d seems to be dead. Continuing loading.");
	}

	if (config->daemon) {

		debug(LOG_INFO, "Forking into background");

		switch(safe_fork()) {
			case 0: /* child */
				setsid();
				append_x_restartargv();
				main_loop();
				break;

			default: /* parent */
				exit(0);
				break;
		}
	}
	else {
		append_x_restartargv();
		main_loop();
	}

	return(0); /* never reached */
}
Exemple #4
0
int main(int argc, char *argv[]) {
        int r;

        if (argc > 1) {
                log_error("This program takes no arguments.");
                return EXIT_FAILURE;
        }

        log_set_target(LOG_TARGET_AUTO);
        log_parse_environment();
        log_open();

        umask(0022);

        r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
        if (r < 0)
                log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");

        test_files();

        if (!arg_force) {
                if (arg_skip)
                        return EXIT_SUCCESS;

                if (access("/run/systemd/quotacheck", F_OK) < 0)
                        return EXIT_SUCCESS;
        }

        r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
        if (r < 0)
                goto finish;
        if (r == 0) {
                static const char * const cmdline[] = {
                        QUOTACHECK,
                        "-anug",
                        NULL
                };

                /* Child */

                execv(cmdline[0], (char**) cmdline);
                _exit(EXIT_FAILURE); /* Operational error */
        }

finish:
        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
Exemple #5
0
int asynchronous_sync(pid_t *ret_pid) {
        int r;

        /* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
         * disk. Note that we implement this as helper process rather than thread as we don't want the sync() to hang our
         * original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
         * syscalls. */

        r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, ret_pid);
        if (r < 0)
                return r;
        if (r == 0) {
                /* Child process */
                (void) sync();
                _exit(EXIT_SUCCESS);
        }

        return 0;
}
/**
 * @brief Fork a child and execute a shell command, the parent
 *  process waits for the child to return and returns the child's exit() value.
 * @param cmd_line
 * @param quiet
 * @return Return code of the command
 */
INT32
shell_execute(const INT8 *cmd_line, INT32 quiet)
{
	INT32 pid, status, rc;

    const INT8 *new_argv[4];
    new_argv[0] = "/bin/sh";
    new_argv[1] = "-c";
    new_argv[2] = cmd_line;
    new_argv[3] = NULL;

    pid = safe_fork();
    if (pid == 0) {             /* for the child process:         */
        /* We don't want to see any errors if quiet flag is on */
        if (quiet)
            close(2);
        if (execvp("/bin/sh", (char *const *)new_argv) == -1) { /* execute the command  */
            debug(LOG_ERR, "execvp(): %s", strerror(errno));
        } else {
            debug(LOG_ERR, "execvp() failed");
        }
        exit(1);
    }

    /* for the parent:      */
    debug(LOG_DEBUG, "Waiting for PID %d to exit", pid);
    rc = waitpid(pid, &status, 0);
    debug(LOG_DEBUG, "Process PID %d exited", rc);

    if (-1 == rc) {
        debug(LOG_ERR, "waitpid() failed (%s)", strerror(errno));
        return 1; /* waitpid failed. */
    }

    if (WIFEXITED(status)) {
        return (WEXITSTATUS(status));
    } else {
        /* If we get here, child did not exit cleanly. Will return non-zero exit code to caller*/
        debug(LOG_DEBUG, "Child may have been killed.");
        return 1;
    }
}
Exemple #7
0
static void test_safe_fork(void) {
        siginfo_t status;
        pid_t pid;
        int r;

        BLOCK_SIGNALS(SIGCHLD);

        r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_REOPEN_LOG, &pid);
        assert_se(r >= 0);

        if (r == 0) {
                /* child */
                usleep(100 * USEC_PER_MSEC);

                _exit(88);
        }

        assert_se(wait_for_terminate(pid, &status) >= 0);
        assert_se(status.si_code == CLD_EXITED);
        assert_se(status.si_status == 88);
}
Exemple #8
0
/** Main entry point for nodogsplash.
 * Reads the configuration file and then starts the main loop.
 */
int main(int argc, char **argv) {

  s_config *config = config_get_config();
  config_init();

  parse_commandline(argc, argv);

  /* Initialize the config */
  debug(LOG_NOTICE,"Reading and validating configuration file %s", config->configfile);
  config_read(config->configfile);
  config_validate();

  /* Initializes the linked list of connected clients */
  client_list_init();

  /* Init the signals to catch chld/quit/etc */
  debug(LOG_NOTICE,"Initializing signal handlers");
  init_signals();

  if (config->daemon) {

    debug(LOG_NOTICE, "Starting as daemon, forking to background");

    switch(safe_fork()) {
    case 0: /* child */
      setsid();
      main_loop();
      break;

    default: /* parent */
      exit(0);
      break;
    }
  }
  else {
    main_loop();
  }

  return(0); /* never reached */
}
Exemple #9
0
static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {

        pid_t _pid;
        int r;

        if (null_or_empty_path(path)) {
                log_debug("%s is empty (a mask).", path);
                return 0;
        }

        r = safe_fork("(direxec)", FORK_DEATHSIG|FORK_LOG, &_pid);
        if (r < 0)
                return r;
        if (r == 0) {
                char *_argv[2];

                if (stdout_fd >= 0) {
                        r = rearrange_stdio(STDIN_FILENO, stdout_fd, STDERR_FILENO);
                        if (r < 0)
                                _exit(EXIT_FAILURE);
                }

                (void) rlimit_nofile_safe();

                if (!argv) {
                        _argv[0] = (char*) path;
                        _argv[1] = NULL;
                        argv = _argv;
                } else
                        argv[0] = (char*) path;

                execv(path, argv);
                log_error_errno(errno, "Failed to execute %s: %m", path);
                _exit(EXIT_FAILURE);
        }

        *pid = _pid;
        return 1;
}
Exemple #10
0
int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
        SpecNextResult *shared, tmp;
        int r;

        if (isempty(spec->timezone))
                return calendar_spec_next_usec_impl(spec, usec, next);

        shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
        if (shared == MAP_FAILED)
                return negative_errno();

        r = safe_fork("(sd-calendar)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
        if (r < 0) {
                (void) munmap(shared, sizeof *shared);
                return r;
        }
        if (r == 0) {
                if (setenv("TZ", spec->timezone, 1) != 0) {
                        shared->return_value = negative_errno();
                        _exit(EXIT_FAILURE);
                }

                tzset();

                shared->return_value = calendar_spec_next_usec_impl(spec, usec, &shared->next);

                _exit(EXIT_SUCCESS);
        }

        tmp = *shared;
        if (munmap(shared, sizeof *shared) < 0)
                return negative_errno();

        if (tmp.return_value == 0)
                *next = tmp.next;

        return tmp.return_value;
}
static void
wdctl_restart(int afd)
{
	int	sock,
		fd;
	char	*sock_name;
	struct 	sockaddr_un	sa_un;
	s_config * conf = NULL;
	t_client * client = NULL;
	char * tempstring = NULL;
	pid_t pid;
	ssize_t written;
	socklen_t len;

	conf = config_get_config();

	debug(LOG_NOTICE, "Will restart myself");

	/*
	 * First, prepare the internal socket
	 */
	memset(&sa_un, 0, sizeof(sa_un));
	sock_name = conf->internal_sock;
	debug(LOG_DEBUG, "Socket name: %s", sock_name);

	if (strlen(sock_name) > (sizeof(sa_un.sun_path) - 1)) {
		/* TODO: Die handler with logging.... */
		debug(LOG_ERR, "INTERNAL socket name too long");
		return;
	}

	debug(LOG_DEBUG, "Creating socket");
	sock = socket(PF_UNIX, SOCK_STREAM, 0);

	debug(LOG_DEBUG, "Got internal socket %d", sock);

	/* If it exists, delete... Not the cleanest way to deal. */
	unlink(sock_name);

	debug(LOG_DEBUG, "Filling sockaddr_un");
	strcpy(sa_un.sun_path, sock_name); /* XXX No size check because we check a few lines before. */
	sa_un.sun_family = AF_UNIX;

	debug(LOG_DEBUG, "Binding socket (%s) (%d)", sa_un.sun_path, strlen(sock_name));

	/* Which to use, AF_UNIX, PF_UNIX, AF_LOCAL, PF_LOCAL? */
	if (bind(sock, (struct sockaddr *)&sa_un, strlen(sock_name) + sizeof(sa_un.sun_family))) {
		debug(LOG_ERR, "Could not bind internal socket: %s", strerror(errno));
		return;
	}

	if (listen(sock, 5)) {
		debug(LOG_ERR, "Could not listen on internal socket: %s", strerror(errno));
		return;
	}

	/*
	 * The internal socket is ready, fork and exec ourselves
	 */
	debug(LOG_DEBUG, "Forking in preparation for exec()...");
	pid = safe_fork();
	if (pid > 0) {
		/* Parent */

		/* Wait for the child to connect to our socket :*/
		debug(LOG_DEBUG, "Waiting for child to connect on internal socket");
		len = sizeof(sa_un);
		if ((fd = accept(sock, (struct sockaddr *)&sa_un, &len)) == -1){
			debug(LOG_ERR, "Accept failed on internal socket: %s", strerror(errno));
			close(sock);
			return;
		}

		close(sock);

		debug(LOG_DEBUG, "Received connection from child.  Sending them all existing clients");

		/* The child is connected. Send them over the socket the existing clients */
		LOCK_CLIENT_LIST();
		client = client_get_first_client();
		while (client) {
			/* Send this client */
			safe_asprintf(&tempstring, "CLIENT|ip=%s|mac=%s|token=%s|fw_connection_state=%u|fd=%d|counters_incoming=%llu|counters_outgoing=%llu|counters_last_updated=%lu\n", client->ip, client->mac, client->token, client->fw_connection_state, client->fd, client->counters.incoming, client->counters.outgoing, client->counters.last_updated);
			debug(LOG_DEBUG, "Sending to child client data: %s", tempstring);
			len = 0;
			while (len != strlen(tempstring)) {
				written = write(fd, (tempstring + len), strlen(tempstring) - len);
				if (written == -1) {
					debug(LOG_ERR, "Failed to write client data to child: %s", strerror(errno));
					free(tempstring);
					break;
				}
				else {
					len += written;
				}
			}
			free(tempstring);
			client = client->next;
		}
		UNLOCK_CLIENT_LIST();

		close(fd);

		debug(LOG_INFO, "Sent all existing clients to child.  Committing suicide!");

		shutdown(afd, 2);
		close(afd);

		/* Our job in life is done. Commit suicide! */
		wdctl_stop(afd);
	}
	else {
		/* Child */
		close(wdctl_socket_server);
		close(icmp_fd);
		close(sock);
		shutdown(afd, 2);
		close(afd);
		debug(LOG_NOTICE, "Re-executing myself (%s)", restartargv[0]);
		setsid();
		execvp(restartargv[0], restartargv);
		/* If we've reached here the exec() failed - die quickly and silently */
		debug(LOG_ERR, "I failed to re-execute myself: %s", strerror(errno));
		debug(LOG_ERR, "Exiting without cleanup");
		exit(1);
	}

}
Exemple #12
0
int bus_image_common_remove(
                Manager *m,
                sd_bus_message *message,
                const char *name_or_path,
                Image *image,
                sd_bus_error *error) {

        _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
        _cleanup_(sigkill_waitp) pid_t child = 0;
        PortableState state;
        int r;

        assert(message);
        assert(name_or_path || image);

        if (!m) {
                assert(image);
                m = image->userdata;
        }

        if (m->n_operations >= OPERATIONS_MAX)
                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");

        r = bus_image_acquire(m,
                              message,
                              name_or_path,
                              image,
                              BUS_IMAGE_AUTHENTICATE_ALL,
                              "org.freedesktop.portable1.manage-images",
                              &image,
                              error);
        if (r < 0)
                return r;
        if (r == 0)
                return 1; /* Will call us back */

        r = portable_get_state(
                        sd_bus_message_get_bus(message),
                        image->path,
                        0,
                        &state,
                        error);
        if (r < 0)
                return r;

        if (state != PORTABLE_DETACHED)
                return sd_bus_error_set_errnof(error, EBUSY, "Image '%s' is not detached, refusing.", image->path);

        if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
                return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");

        r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
        if (r < 0)
                return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
        if (r == 0) {
                errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);

                r = image_remove(image);
                if (r < 0) {
                        (void) write(errno_pipe_fd[1], &r, sizeof(r));
                        _exit(EXIT_FAILURE);
                }

                _exit(EXIT_SUCCESS);
        }

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

        r = operation_new(m, child, message, errno_pipe_fd[0], NULL);
        if (r < 0)
                return r;

        child = 0;
        errno_pipe_fd[0] = -1;

        return 1;
}
Exemple #13
0
/** Fork a child and execute a shell command.
 * The parent process waits for the child to return,
 * and returns the child's exit() value.
 * @return Return code of the command
 */
int
execute(const char cmd_line[], int quiet)
{
	int status, retval;
	pid_t pid, rc;
	struct sigaction sa, oldsa;
	const char *new_argv[4];
	new_argv[0] = "/bin/sh";
	new_argv[1] = "-c";
	new_argv[2] = cmd_line;
	new_argv[3] = NULL;

	/* Temporarily get rid of SIGCHLD handler (see gateway.c), until child exits.
	 * Will handle SIGCHLD here with waitpid() in the parent. */
	debug(LOG_DEBUG,"Setting default SIGCHLD handler SIG_DFL");
	sa.sa_handler = SIG_DFL;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
	if (sigaction(SIGCHLD, &sa, &oldsa) == -1) {
		debug(LOG_ERR, "sigaction() failed to set default SIGCHLD handler: %s", strerror(errno));
	}

	pid = safe_fork();

	if (pid == 0) {    /* for the child process:         */

		if (quiet) close(2); /* Close stderr if quiet flag is on */
		if (execvp("/bin/sh", (char *const *)new_argv) == -1) {    /* execute the command  */
			debug(LOG_ERR, "execvp(): %s", strerror(errno));
		} else {
			debug(LOG_ERR, "execvp() failed");
		}
		exit(1);

	} else {        /* for the parent:      */

		debug(LOG_DEBUG, "Waiting for PID %d to exit", (int)pid);
		do {
			rc = waitpid(pid, &status, 0);
			if(rc == -1) {
				if(errno == ECHILD) {
					debug(LOG_DEBUG, "waitpid(): No child exists now. Assuming normal exit for PID %d", (int)pid);
					retval = 0;
				} else {
					debug(LOG_ERR, "Error waiting for child (waitpid() returned -1): %s", strerror(errno));
					retval = -1;
				}
				break;
			}
			if(WIFEXITED(status)) {
				debug(LOG_DEBUG, "Process PID %d exited normally, status %d", (int)rc, WEXITSTATUS(status));
				retval = (WEXITSTATUS(status));
			}
			if(WIFSIGNALED(status)) {
				debug(LOG_DEBUG, "Process PID %d exited due to signal %d", (int)rc, WTERMSIG(status));
				retval = -1;
			}
		} while (!WIFEXITED(status) && !WIFSIGNALED(status));

		debug(LOG_DEBUG, "Restoring previous SIGCHLD handler");
		if (sigaction(SIGCHLD, &oldsa, NULL) == -1) {
			debug(LOG_ERR, "sigaction() failed to restore SIGCHLD handler! Error %s", strerror(errno));
		}

		return retval;
	}
}
GtSafePipe *gt_safe_popen(const char *path,
                          char *const argv[],
                          char *const envp[],
                          GtError *err) {
#ifndef _WIN32
  int stdin_pipe[2], stdout_pipe[2], had_err = 0;
  GtSafePipe *p = NULL;

  p = gt_malloc(sizeof(*p));
  p->read_fd = p->write_fd = NULL;
  p->child_pid = (pid_t) -1;

  if ((had_err = pipe(stdin_pipe))) {
    gt_error_set(err, "could not open stdin pipe: %s", strerror(errno));
  }
  if (!had_err) {
    if ((had_err = pipe(stdout_pipe))) {
      gt_error_set(err, "could not open stdout pipe: %s", strerror(errno));
    }
    if (!had_err) {
      if (!(p->read_fd = fdopen(stdout_pipe[0], "r"))) {
        gt_error_set(err, "could not open stdout_pipe[0] for reading: %s",
                     strerror(errno));
        had_err = -1;
      }
      if (!had_err) {
        if (!(p->write_fd = fdopen(stdin_pipe[1], "w"))) {
          gt_error_set(err, "could not open stdin_pipe[1] for writing: %s",
                       strerror(errno));
          had_err = -1;
        }
        if (!had_err) {
          if ((p->child_pid = safe_fork()) == (pid_t) -1) {
            gt_error_set(err, "could not fork: %s", strerror(errno));
            had_err = -1;
          }
          if (!had_err) {
            if (!p->child_pid) {
              /* this is the child process */
              (void) close(stdout_pipe[0]);
              (void) close(stdin_pipe[1]);
              if (stdin_pipe[0] != 0) {
                (void) dup2(stdin_pipe[0], 0);
                (void) close(stdin_pipe[0]);
              }
              if (stdout_pipe[1] != 1) {
                (void) dup2(stdout_pipe[1], 1);
                (void) close(stdout_pipe[1]);
              }
              (void) execve(path, argv, envp);
              perror("could not execute external program: ");
              perror(strerror(errno));
              exit(127);
            }
            (void) close(stdout_pipe[1]);
            (void) close(stdin_pipe[0]);
          }
          if (had_err) {
            (void) fclose(p->write_fd);
          }
        }
        if (had_err) {
          (void) fclose(p->read_fd);
        }
      }
      if (had_err) {
        (void) close(stdout_pipe[1]);
        (void) close(stdout_pipe[0]);
      }
    }
    if (had_err) {
      (void) close(stdin_pipe[1]);
      (void) close(stdin_pipe[0]);
    }
  }
  if (had_err) {
    gt_free(p);
    p = NULL;
  }
  return p;
#else
  gt_error_set(err, "Function gt_safe_popen not implemented for windows yet");
  return NULL;
#endif
}
Exemple #15
0
static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
        _cleanup_free_ char *tmp = NULL;
        _cleanup_close_ int fd = -1;
        struct statvfs ss;
        pid_t pid = 0;
        int r;

        /* We want to be able to make use of btrfs-specific file
         * system features, in particular subvolumes, reflinks and
         * quota. Hence, if we detect that /var/lib/machines.raw is
         * not located on btrfs, let's create a loopback file, place a
         * btrfs file system into it, and mount it to
         * /var/lib/machines. */

        fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
        if (fd >= 0)
                return TAKE_FD(fd);

        if (errno != ENOENT)
                return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");

        r = tempfn_xxxxxx("/var/lib/machines.raw", NULL, &tmp);
        if (r < 0)
                return r;

        (void) mkdir_p_label("/var/lib", 0755);
        fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
        if (fd < 0)
                return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");

        if (fstatvfs(fd, &ss) < 0) {
                r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
                goto fail;
        }

        if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
                goto fail;
        }

        if (ftruncate(fd, size) < 0) {
                r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
                goto fail;
        }

        r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
        if (r < 0) {
                sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m");
                goto fail;
        }
        if (r == 0) {

                /* Child */

                fd = safe_close(fd);

                execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
                if (errno == ENOENT)
                        _exit(99);

                _exit(EXIT_FAILURE);
        }

        r = wait_for_terminate_and_check("mkfs", pid, 0);
        pid = 0;

        if (r < 0) {
                sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
                goto fail;
        }
        if (r == 99) {
                r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
                goto fail;
        }
        if (r != EXIT_SUCCESS) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", r);
                goto fail;
        }

        r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw");
        if (r < 0) {
                sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m");
                goto fail;
        }

        return TAKE_FD(fd);

fail:
        unlink_noerrno(tmp);

        if (pid > 1)
                kill_and_sigcont(pid, SIGKILL);

        return r;
}
Exemple #16
0
int main(int argc, char *argv[]) {
        bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
        bool in_container, use_watchdog = false, can_initrd;
        _cleanup_free_ char *cgroup = NULL;
        char *arguments[3];
        int cmd, r, umount_log_level = LOG_INFO;
        static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
        char *watchdog_device;

        /* The log target defaults to console, but the original systemd process will pass its log target in through a
         * command line argument, which will override this default. Also, ensure we'll never log to the journal or
         * syslog, as these logging daemons are either already dead or will die very soon. */

        log_set_target(LOG_TARGET_CONSOLE);
        log_set_prohibit_ipc(true);
        log_parse_environment();

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

        log_open();

        umask(0022);

        if (getpid_cached() != 1) {
                log_error("Not executed by init (PID 1).");
                r = -EPERM;
                goto error;
        }

        if (streq(arg_verb, "reboot"))
                cmd = RB_AUTOBOOT;
        else if (streq(arg_verb, "poweroff"))
                cmd = RB_POWER_OFF;
        else if (streq(arg_verb, "halt"))
                cmd = RB_HALT_SYSTEM;
        else if (streq(arg_verb, "kexec"))
                cmd = LINUX_REBOOT_CMD_KEXEC;
        else if (streq(arg_verb, "exit"))
                cmd = 0; /* ignored, just checking that arg_verb is valid */
        else {
                log_error("Unknown action '%s'.", arg_verb);
                r = -EINVAL;
                goto error;
        }

        (void) cg_get_root_path(&cgroup);
        in_container = detect_container() > 0;

        use_watchdog = getenv("WATCHDOG_USEC");
        watchdog_device = getenv("WATCHDOG_DEVICE");
        if (watchdog_device) {
                r = watchdog_set_device(watchdog_device);
                if (r < 0)
                        log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m",
                                          watchdog_device);
        }

        /* Lock us into memory */
        (void) mlockall(MCL_CURRENT|MCL_FUTURE);

        /* Synchronize everything that is not written to disk yet at this point already. This is a good idea so that
         * slow IO is processed here already and the final process killing spree is not impacted by processes
         * desperately trying to sync IO to disk within their timeout. Do not remove this sync, data corruption will
         * result. */
        if (!in_container)
                sync_with_progress();

        disable_coredumps();

        log_info("Sending SIGTERM to remaining processes...");
        broadcast_signal(SIGTERM, true, true, arg_timeout);

        log_info("Sending SIGKILL to remaining processes...");
        broadcast_signal(SIGKILL, true, false, arg_timeout);

        need_umount = !in_container;
        need_swapoff = !in_container;
        need_loop_detach = !in_container;
        need_dm_detach = !in_container;
        can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0;

        /* Unmount all mountpoints, swaps, and loopback devices */
        for (;;) {
                bool changed = false;

                if (use_watchdog)
                        watchdog_ping();

                /* Let's trim the cgroup tree on each iteration so
                   that we leave an empty cgroup tree around, so that
                   container managers get a nice notify event when we
                   are down */
                if (cgroup)
                        cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);

                if (need_umount) {
                        log_info("Unmounting file systems.");
                        r = umount_all(&changed, umount_log_level);
                        if (r == 0) {
                                need_umount = false;
                                log_info("All filesystems unmounted.");
                        } else if (r > 0)
                                log_info("Not all file systems unmounted, %d left.", r);
                        else
                                log_error_errno(r, "Failed to unmount file systems: %m");
                }

                if (need_swapoff) {
                        log_info("Deactivating swaps.");
                        r = swapoff_all(&changed);
                        if (r == 0) {
                                need_swapoff = false;
                                log_info("All swaps deactivated.");
                        } else if (r > 0)
                                log_info("Not all swaps deactivated, %d left.", r);
                        else
                                log_error_errno(r, "Failed to deactivate swaps: %m");
                }

                if (need_loop_detach) {
                        log_info("Detaching loop devices.");
                        r = loopback_detach_all(&changed, umount_log_level);
                        if (r == 0) {
                                need_loop_detach = false;
                                log_info("All loop devices detached.");
                        } else if (r > 0)
                                log_info("Not all loop devices detached, %d left.", r);
                        else
                                log_error_errno(r, "Failed to detach loop devices: %m");
                }

                if (need_dm_detach) {
                        log_info("Detaching DM devices.");
                        r = dm_detach_all(&changed, umount_log_level);
                        if (r == 0) {
                                need_dm_detach = false;
                                log_info("All DM devices detached.");
                        } else if (r > 0)
                                log_info("Not all DM devices detached, %d left.", r);
                        else
                                log_error_errno(r, "Failed to detach DM devices: %m");
                }

                if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
                        log_info("All filesystems, swaps, loop devices and DM devices detached.");
                        /* Yay, done */
                        break;
                }

                if (!changed && umount_log_level == LOG_INFO && !can_initrd) {
                        /* There are things we cannot get rid of. Loop one more time
                         * with LOG_ERR to inform the user. Note that we don't need
                         * to do this if there is a initrd to switch to, because that
                         * one is likely to get rid of the remounting mounts. If not,
                         * it will log about them. */
                        umount_log_level = LOG_ERR;
                        continue;
                }

                /* If in this iteration we didn't manage to
                 * unmount/deactivate anything, we simply give up */
                if (!changed) {
                        log_info("Cannot finalize remaining%s%s%s%s continuing.",
                                 need_umount ? " file systems," : "",
                                 need_swapoff ? " swap devices," : "",
                                 need_loop_detach ? " loop devices," : "",
                                 need_dm_detach ? " DM devices," : "");
                        break;
                }

                log_debug("Couldn't finalize remaining %s%s%s%s trying again.",
                          need_umount ? " file systems," : "",
                          need_swapoff ? " swap devices," : "",
                          need_loop_detach ? " loop devices," : "",
                          need_dm_detach ? " DM devices," : "");
        }

        /* We're done with the watchdog. */
        watchdog_free_device();

        arguments[0] = NULL;
        arguments[1] = arg_verb;
        arguments[2] = NULL;
        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);

        (void) rlimit_nofile_safe();

        if (can_initrd) {
                r = switch_root_initramfs();
                if (r >= 0) {
                        argv[0] = (char*) "/shutdown";

                        (void) setsid();
                        (void) make_console_stdio();

                        log_info("Successfully changed into root pivot.\n"
                                 "Returning to initrd...");

                        execv("/shutdown", argv);
                        log_error_errno(errno, "Failed to execute shutdown binary: %m");
                } else
                        log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");

        }

        if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
                log_error("Failed to finalize %s%s%s%s ignoring",
                          need_umount ? " file systems," : "",
                          need_swapoff ? " swap devices," : "",
                          need_loop_detach ? " loop devices," : "",
                          need_dm_detach ? " DM devices," : "");

        /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
         * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we
         * sync'ed things already once above, but we did some more work since then which might have caused IO, hence
         * let's do it once more. Do not remove this sync, data corruption will result. */
        if (!in_container)
                sync_with_progress();

        if (streq(arg_verb, "exit")) {
                if (in_container)
                        return arg_exit_code;

                cmd = RB_POWER_OFF; /* We cannot exit() on the host, fallback on another method. */
        }

        switch (cmd) {

        case LINUX_REBOOT_CMD_KEXEC:

                if (!in_container) {
                        /* We cheat and exec kexec to avoid doing all its work */
                        log_info("Rebooting with kexec.");

                        r = safe_fork("(sd-kexec)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_WAIT, NULL);
                        if (r == 0) {
                                const char * const args[] = {
                                        KEXEC, "-e", NULL
                                };

                                /* Child */

                                execv(args[0], (char * const *) args);
                                _exit(EXIT_FAILURE);
                        }

                        /* If we are still running, then the kexec can't have worked, let's fall through */
                }

                cmd = RB_AUTOBOOT;
                _fallthrough_;

        case RB_AUTOBOOT:
                (void) reboot_with_parameter(REBOOT_LOG);
                log_info("Rebooting.");
                break;

        case RB_POWER_OFF:
                log_info("Powering off.");
                break;

        case RB_HALT_SYSTEM:
                log_info("Halting system.");
                break;

        default:
                assert_not_reached("Unknown magic");
        }

        (void) reboot(cmd);
        if (errno == EPERM && in_container) {
                /* If we are in a container, and we lacked
                 * CAP_SYS_BOOT just exit, this will kill our
                 * container for good. */
                log_info("Exiting container.");
                return EXIT_SUCCESS;
        }

        r = log_error_errno(errno, "Failed to invoke reboot(): %m");

  error:
        log_emergency_errno(r, "Critical error while doing system shutdown: %m");
        freeze();
}
Exemple #17
0
static void test_rearrange_stdio(void) {
        pid_t pid;
        int r;

        r = safe_fork("rearrange", FORK_WAIT|FORK_LOG, &pid);
        assert_se(r >= 0);

        if (r == 0) {
                _cleanup_free_ char *path = NULL;
                char buffer[10];

                /* Child */

                safe_close(STDERR_FILENO); /* Let's close an fd < 2, to make it more interesting */

                assert_se(rearrange_stdio(-1, -1, -1) >= 0);

                assert_se(fd_get_path(STDIN_FILENO, &path) >= 0);
                assert_se(path_equal(path, "/dev/null"));
                path = mfree(path);

                assert_se(fd_get_path(STDOUT_FILENO, &path) >= 0);
                assert_se(path_equal(path, "/dev/null"));
                path = mfree(path);

                assert_se(fd_get_path(STDOUT_FILENO, &path) >= 0);
                assert_se(path_equal(path, "/dev/null"));
                path = mfree(path);

                safe_close(STDIN_FILENO);
                safe_close(STDOUT_FILENO);
                safe_close(STDERR_FILENO);

                {
                        int pair[2];
                        assert_se(pipe(pair) >= 0);
                        assert_se(pair[0] == 0);
                        assert_se(pair[1] == 1);
                        assert_se(fd_move_above_stdio(0) == 3);
                }
                assert_se(open("/dev/full", O_WRONLY|O_CLOEXEC) == 0);
                assert_se(acquire_data_fd("foobar", 6, 0) == 2);

                assert_se(rearrange_stdio(2, 0, 1) >= 0);

                assert_se(write(1, "x", 1) < 0 && errno == ENOSPC);
                assert_se(write(2, "z", 1) == 1);
                assert_se(read(3, buffer, sizeof(buffer)) == 1);
                assert_se(buffer[0] == 'z');
                assert_se(read(0, buffer, sizeof(buffer)) == 6);
                assert_se(memcmp(buffer, "foobar", 6) == 0);

                assert_se(rearrange_stdio(-1, 1, 2) >= 0);
                assert_se(write(1, "a", 1) < 0 && errno == ENOSPC);
                assert_se(write(2, "y", 1) == 1);
                assert_se(read(3, buffer, sizeof(buffer)) == 1);
                assert_se(buffer[0] == 'y');

                assert_se(fd_get_path(0, &path) >= 0);
                assert_se(path_equal(path, "/dev/null"));
                path = mfree(path);

                _exit(EXIT_SUCCESS);
        }
}
Exemple #18
0
/* 
    With no arguments specified: works as printenv | sort | less
    if we have defined pager in env variabels, that pager is used instead of less
    if we define parameters digenv works as:
    ./digenv [params] -> printenv | grep params | sort | less
 */
int main(int argc, char **argv, char **envp)
{
    /* true for childprocesses after each fork */
    bool isChild;

    pipe(pipes[DIGENV]);

    isChild = safe_fork();
    if ( isChild ) {
        /* child pager */
        prepare_send_pipe(DIGENV);
        execlp("printenv","printenv",NULL);
        _exit(EXIT_FAILURE);
    }

    receive_from_pipe(DIGENV);

    wait_for_child_to_terminate();

    pipe(pipes[GREP]);

    isChild = safe_fork();
    if ( isChild ) {
        prepare_send_pipe(GREP);
        if (argc > 1) {
        /* runs the binary "grep" with the arguments in argv */
            execvp("grep", argv);
        }else {
            /* cat simply rewrites input to output, just like 
            a grep without arguments ;) */
            execvp("cat", argv);
        }
        _exit(EXIT_FAILURE);
    }

    receive_from_pipe(GREP);

    wait_for_child_to_terminate();

    pipe(pipes[SORT]);

    isChild = safe_fork();
    if ( isChild ) {
        prepare_send_pipe(SORT);
    /* runs the sort binary with to parameters but with piped input */
        execlp("/usr/bin/sort","sort",NULL);

        /* If we get here, call to sort has failed. */
        perror("Sorting failed");
        _exit(EXIT_FAILURE);
    }

    receive_from_pipe(SORT);

    wait_for_child_to_terminate();

    /* runs the specified pager with input from pipe */
    execlp(get_pager(), get_pager(), NULL);

    /* if we get here, pager has failed. */
    perror("Invalid pager"); 
    _exit(EXIT_FAILURE);
    return EXIT_FAILURE;
}