#include <sys/prctl.h>
#include <sys/capability.h>
#include <getopt.h>
+#include <sys/poll.h>
#include <sys/epoll.h>
#include <termios.h>
#include <sys/signalfd.h>
#include "sd-id128.h"
#include "dev-setup.h"
#include "fdset.h"
+#include "build.h"
+#include "fileio.h"
typedef enum LinkJournal {
LINK_NO,
(1ULL << CAP_SYS_PTRACE) |
(1ULL << CAP_SYS_TTY_CONFIG) |
(1ULL << CAP_SYS_RESOURCE) |
- (1ULL << CAP_SYS_BOOT);
+ (1ULL << CAP_SYS_BOOT) |
+ (1ULL << CAP_AUDIT_WRITE) |
+ (1ULL << CAP_AUDIT_CONTROL);
static int help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
"Spawn a minimal namespace container for debugging, testing and building.\n\n"
" -h --help Show this help\n"
+ " --version Print version string\n"
" -D --directory=NAME Root directory for the container\n"
" -b --boot Boot up full system (i.e. invoke init)\n"
" -u --user=USER Run the command under specified user or uid\n"
static int parse_argv(int argc, char *argv[]) {
enum {
- ARG_PRIVATE_NETWORK = 0x100,
+ ARG_VERSION = 0x100,
+ ARG_PRIVATE_NETWORK,
ARG_UUID,
ARG_READ_ONLY,
ARG_CAPABILITY,
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
{ "directory", required_argument, NULL, 'D' },
{ "user", required_argument, NULL, 'u' },
{ "controllers", required_argument, NULL, 'C' },
help();
return 0;
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0;
+
case 'D':
free(arg_directory);
arg_directory = canonicalize_file_name(optarg);
signal_ev.events = EPOLLIN;
signal_ev.data.fd = signal_fd;
- if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
- epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0) {
+ if (errno != EPERM) {
+ log_error("Failed to register stdout in epoll: %m");
+ r = -errno;
+ goto finish;
+ }
+ /* stdout without epoll support. Likely redirected to regular file. */
+ stdout_writable = true;
+ }
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
log_error("Failed to register fds in epoll: %m");
r = -errno;
for (;;) {
siginfo_t status;
+ int pipefd[2];
- if (saved_attr_valid) {
- if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
- log_error("Failed to set terminal attributes: %m");
- goto finish;
- }
+ if(pipe2(pipefd, O_NONBLOCK|O_CLOEXEC) < 0) {
+ log_error("pipe2(): %m");
+ goto finish;
}
pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_private_network ? CLONE_NEWNET : 0), NULL);
if (pid == 0) {
/* child */
-
const char *home = NULL;
uid_t uid = (uid_t) -1;
gid_t gid = (gid_t) -1;
envp[2] = strv_find_prefix(environ, "TERM=");
n_env = 3;
+ close_nointr_nofail(pipefd[1]);
+ fd_wait_for_event(pipefd[0], POLLHUP, -1);
+ close_nointr_nofail(pipefd[0]);
+
close_nointr_nofail(master);
master = -1;
+ if (saved_attr_valid) {
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
+ log_error("Failed to set terminal attributes: %m");
+ goto child_fail;
+ }
+ }
+
close_nointr(STDIN_FILENO);
close_nointr(STDOUT_FILENO);
close_nointr(STDERR_FILENO);
_exit(EXIT_FAILURE);
}
+ log_info("Init process in the container running as PID %d", pid);
+ close_nointr_nofail(pipefd[0]);
+ close_nointr_nofail(pipefd[1]);
+
fdset_free(fds);
fds = NULL;