Exemple #1
0
/* TODO: if possible drop sndfile and roll own wav loading function */
unsigned int wav_load(const char *path) {
	int err;

	unsigned int	sample, source;

	SF_INFO		snd_info;
	SNDFILE		*snd_input;

	short		*input_buffer;
	size_t		buffer_size;

	unsigned int	channels, frames, sample_rate, samples;

	char *full_path;

	full_path = malloc(strlen(path) + strlen(SOUND_DATA_PATH) + strlen(DATA_PATH) + 3);
	sprintf(full_path, "%s/%s/%s", DATA_PATH, SOUND_DATA_PATH, path);

	alGenBuffers(1, &sample);

	snd_input = sf_open(full_path, SFM_READ, &snd_info);
	if (snd_input == NULL) fail_printf("%s", sf_strerror(snd_input));

	channels	= snd_info.channels;
	frames		= snd_info.frames;
	sample_rate	= snd_info.samplerate;
	samples		= frames * channels;

	buffer_size	= samples * sizeof(short);

	input_buffer = malloc(buffer_size);
	if (input_buffer == NULL) fail_printf("Out of memory");

	err = sf_read_short(snd_input, input_buffer, frames);
	if (err != frames) fail_printf("%s", sf_strerror(snd_input));

	sf_close(snd_input);

	alBufferData(
		sample,
		(channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16),
		input_buffer, buffer_size, sample_rate
	);

	alGenSources(1, &source);

	alSourcef(source, AL_PITCH, 1);
	alSourcef(source, AL_GAIN, 1);
	alSource3f(source, AL_POSITION, 0, 0, 0);
	alSource3f(source, AL_VELOCITY, 0, 0, 0);
	alSourcei(source, AL_LOOPING, AL_FALSE);

	alSourcei(source, AL_BUFFER, sample);

	free(input_buffer);

	ok_printf("Loaded '%s'", full_path);

	return source;
}
Exemple #2
0
void make_symlinks(const char *dest) {
	int rc;

	const char *src[] = {
		"/proc/kcore",
		"/proc/self/fd",
		"/proc/self/fd/0",
		"/proc/self/fd/1",
		"/proc/self/fd/2"
	};

	const char *dst[] = {
		"/dev/core",
		"/dev/fd",
		"/dev/stdin",
		"/dev/stdout",
		"/dev/stderr"
	};

	for (size_t i = 0; i <  sizeof(src) / sizeof(*src); i++) {
		_free_ char *link = NULL;

		rc = asprintf(&link, "%s/%s", dest, dst[i]);
		if (rc < 0) fail_printf("OOM");

		rc = symlink(src[i], link);
		if (rc < 0) sysf_printf("symlink()");
	}
}
Exemple #3
0
void netif_add_from_spec(struct netif **ifs, const char *spec) {
    _free_ char *tmp = NULL;
    _free_ char **opts = NULL;

    if (!spec) return;

    tmp = strdup(spec);
    fail_if(!tmp, "OOM");

    size_t c = split_str(tmp, &opts, ":");
    fail_if(!c, "Invalid netif spec '%s': not enough args", spec);

    if (if_nametoindex(opts[0])) {
        fail_if(c < 2, "Invalid netif spec '%s': not enough args",spec);

        netif_add(ifs, MOVE, opts[0], opts[1]);
    } else if (!strncmp(opts[0], "macvlan", 8)) {
        fail_if(c < 3, "Invalid netif spec '%s': not enough args",spec);

        netif_add(ifs, MACVLAN, opts[1], opts[2]);
    } else if (!strncmp(opts[0], "ipvlan", 8)) {
        fail_if(c < 3, "Invalid netif spec '%s': not enough args",spec);

        netif_add(ifs, IPVLAN, opts[1], opts[2]);
    } else if (!strncmp(opts[0], "veth", 5)) {
        fail_if(c < 3, "Invalid netif spec '%s': not enough args",spec);

        netif_add(ifs, VETH, opts[1], opts[2]);
    } else {
        fail_printf("Invalid netif spec '%s'", spec);
    }
}
Exemple #4
0
void copy_nodes(const char *dest) {
	int rc;

	mode_t u = umask(0000);

	const char *nodes[] = {
		"/dev/tty",
		"/dev/full",
		"/dev/null",
		"/dev/zero",
		"/dev/random",
		"/dev/urandom"
	};

	for (size_t i = 0; i <  sizeof(nodes) / sizeof(*nodes); i++) {
		struct stat sb;
		_free_ char *target = NULL;

		rc = asprintf(&target, "%s%s", dest, nodes[i]);
		if (rc < 0) fail_printf("OOM");

		rc = stat(nodes[i], &sb);
		if (rc < 0) sysf_printf("stat()");

		rc = mknod(target, sb.st_mode, sb.st_rdev);
		if (rc < 0) sysf_printf("mknod()");
	}

	umask(u);
}
Exemple #5
0
static void add_mount_inside(char *base, char *src, char *dst,
                             char *type, unsigned long f, void *d) {
	int rc;

	_free_ char *target = NULL;

	rc = asprintf(&target, "%s%s", base, dst);
	if (rc < 0) fail_printf("OOM");

	add_mount(src, target, type, f, d);
}
Exemple #6
0
void make_ptmx(const char *dest) {
	int rc;

	_free_ char *target = NULL;

	rc = asprintf(&target, "%s/dev/ptmx", dest);
	if (rc < 0) fail_printf("OOM");

	rc = symlink("/dev/pts/ptmx", target);
	if (rc < 0) sysf_printf("symlink()");
}
Exemple #7
0
static void do_log(const char *pre, const char *fmt, va_list args) {
	int rc;
	static char format[LINE_MAX];

	rc = snprintf(format, LINE_MAX, "%s%s\n", use_syslog ? "" : pre, fmt);
	if (rc < 0) fail_printf("EIO");

	if (use_syslog == 1)
		vsyslog(LOG_CRIT, format, args);
	else
		vfprintf(stderr, format, args);
}
Exemple #8
0
void sysf_printf(const char *fmt, ...) {
	int rc;
	va_list args;

	_free_ char *format = NULL;

	rc = asprintf(&format, "%s: %s", fmt, strerror(errno));
	if (rc < 0) fail_printf("OOM");

	va_start(args, fmt);
	do_log("[" COLOR_RED "✘" COLOR_OFF "] ", format, args);
	va_end(args);

	_exit(EXIT_FAILURE);
}
Exemple #9
0
static int sync_wait(int fd, int seq) {
    int rc;
    int sync = -1;

    rc = read(fd, &sync, sizeof(sync));
    sys_fail_if(rc < 0, "Error reading from socket");

    if (!rc)
        return 0;

    if (sync != seq)
        fail_printf("Invalid sync sequence: %d != %d", seq, sync);

    return 0;
}
Exemple #10
0
static void do_log(const char *pre, const char *fmt, va_list args, bool cursor) {
	int rc;
	static char format[LINE_MAX];

	if (use_syslog || !isatty(STDERR_FILENO))
		rc = snprintf(format, LINE_MAX, "%s\n", fmt);
	else
		rc = snprintf(format, LINE_MAX, "\r" LINE_CLEAR "%s%s%s\n",
			      cursor ? CURSOR_SHOW  : "", pre, fmt);

	if (rc < 0) fail_printf("EIO");

	if (use_syslog == 1)
		vsyslog(LOG_CRIT, format, args);
	else
		vfprintf(stderr, format, args);
}
Exemple #11
0
static void add_mount(char *src, char *dst, char *type,
                      unsigned long f, void *d) {
	mount_list *mnt = malloc(sizeof(mount_list));
	if (mnt == NULL) fail_printf("OOM");

	mnt->src   = src  ? strdup(src)  : NULL;
	mnt->dst   = dst  ? strdup(dst)  : NULL;
	mnt->type  = type ? strdup(type) : NULL;
	mnt->flags = f;
	mnt->data  = d    ? strdup(d)    : NULL;

	mnt->next  = NULL;

	if (mounts)
		mnt->next = mounts;

	mounts = mnt;
}
Exemple #12
0
static size_t validate_optlist(const char *name, const char *opts) {
    size_t i, c;
    _free_ char **vars = NULL;

    _free_ char *tmp = NULL;

    if (!opts || !*opts)
        return 0;

    tmp = strdup(opts);
    fail_if(!tmp, "OOM");

    c = split_str(tmp, &vars, ":");
    fail_if(!c, "Invalid value '%s' for %s", opts, name);

    for (i = 0; i < c; i++) {
        if (*vars[i] == '\0')
            fail_printf("Invalid value '%s' for %s", opts, name);
    }

    return c;
}
Exemple #13
0
void make_console(const char *dest, const char *console) {
	int rc;

	struct stat sb;
	_free_ char *target = NULL;

	rc = chmod(console, 0600);
	if (rc < 0) sysf_printf("chmod()");

	rc = chown(console, 0, 0);
	if (rc < 0) sysf_printf("chown()");

	rc = stat(console, &sb);
	if (rc < 0) sysf_printf("stat()");

	rc = asprintf(&target, "%s/dev/console", dest);
	if (rc < 0) fail_printf("OOM");

	rc = mknod(target, sb.st_mode, sb.st_rdev);
	if (rc < 0) sysf_printf("mknod()");

	rc = mount(console, target, NULL, MS_BIND, NULL);
	if (rc < 0) sysf_printf("mount()");
}
Exemple #14
0
void add_mount_from_spec(char *spec) {
	int rc;

	size_t c;

	_free_ char **opts = NULL;

	_free_ char *tmp = strdup(spec);
	if (tmp == NULL) fail_printf("OOM");

	c = split_str(tmp, &opts, ",");
	if (c == 0) fail_printf("Invalid mount spec '%s'", spec);

	if (strncmp(opts[0], "bind", 4) == 0) {
		_free_ char *src = NULL;
		_free_ char *dst = NULL;

		if (c < 3) fail_printf("Invalid mount spec '%s'", spec);

		src = realpath(opts[1], NULL);
		if (src == NULL) sysf_printf("realpath()");

		dst = realpath(opts[2], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		add_mount(src, dst, NULL, MS_BIND, NULL);

		if (strncmp(opts[0], "bind-ro", 8) == 0)
			add_mount(src, dst, NULL, MS_REMOUNT | MS_BIND | MS_RDONLY, NULL);
	} else if (strncmp(opts[0], "aufs", 5) == 0) {
		_free_ char *dst = NULL;
		_free_ char *overlay = NULL;
		_free_ char *aufs_opts = NULL;

		if (c < 3) fail_printf("Invalid mount spec '%s'", spec);

		overlay = realpath(opts[1], NULL);
		if (overlay == NULL) sysf_printf("realpath()");

		dst = realpath(opts[2], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		rc = asprintf(&aufs_opts, "br:%s=rw:%s=ro", overlay, dst);
		if (rc < 0) fail_printf("OOM");

		add_mount(NULL, dst, "aufs", 0, aufs_opts);
	} else if (strncmp(opts[0], "overlay", 8) == 0) {
		_free_ char *dst = NULL;
		_free_ char *overlay = NULL;
		_free_ char *workdir = NULL;
		_free_ char *overlayfs_opts = NULL;

		if (c < 4) fail_printf("Invalid mount spec '%s'", spec);

		overlay = realpath(opts[1], NULL);
		if (overlay == NULL) sysf_printf("realpath()");

		dst = realpath(opts[2], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		workdir = realpath(opts[3], NULL);
		if (workdir == NULL) sysf_printf("realpath()");

#ifdef HAVE_AUFS
		rc = asprintf(&overlayfs_opts, "br:%s=rw:%s=ro", overlay, dst);
		if (rc < 0) fail_printf("OOM");

		add_mount(NULL, dst, "aufs", 0, overlayfs_opts);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
		rc = asprintf(&overlayfs_opts,
		              "upperdir=%s,lowerdir=%s,workdir=%s",
		              overlay, dst, workdir);
		if (rc < 0) fail_printf("OOM");

		add_mount(NULL, dst, "overlay", 0, overlayfs_opts);
#else
		fail_printf("The 'overlay' mount type is not supported");
#endif
	} else if (strncmp(opts[0], "tmp", 4) == 0) {
		_free_ char *dst = NULL;

		if (c < 2) fail_printf("Invalid mount spec '%s'", spec);

		dst = realpath(opts[1], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		add_mount("tmpfs", dst, "tmpfs", 0, NULL);
	} else {
		fail_printf("Invalid mount type '%s'", opts[0]);
	}
}
Exemple #15
0
int main(int argc, char *argv[]) {
	int rc, i;

	pid_t pid  = -1;
	pid_t ppid = getpid();

	uid_t uid = -1;
	gid_t gid = -1;

	_free_ char *user   = NULL;
	_free_ char *dest   = NULL;
	_free_ char *change = NULL;
	_free_ char *env    = NULL;
	_free_ char *cgroup = NULL;

	_close_ int master_fd = -1;

	char *master_name;

	int detach  = 0;
	int keepenv = 0;

	siginfo_t status;

	while ((rc = getopt_long(argc, argv, short_opts, long_opts, &i)) !=-1) {
		switch (rc) {
			case 'm':
				validate_optlist("--mount", optarg);

				add_mount_from_spec(optarg);
				break;

			case 'n':
				clone_flags |= CLONE_NEWNET;

				if (optarg != NULL) {
					validate_optlist("--netif", optarg);

					add_netif_from_spec(optarg);
				}
				break;

			case 'u':
				clone_flags |= CLONE_NEWUSER;

				freep(&user);

				user = strdup(optarg);
				break;

			case 'r':
				freep(&dest);

				dest = realpath(optarg, NULL);
				if (dest == NULL) sysf_printf("realpath()");
				break;

			case 'c':
				freep(&change);

				change = strdup(optarg);
				break;

			case 'g':
				validate_optlist("--cgroup", optarg);
				validate_cgroup_spec(optarg);

				freep(&change);

				cgroup = strdup(optarg);
				break;

			case 'd':
				detach = 1;
				break;

			case 'a': {
				char *end = NULL;
				pid = strtol(optarg, &end, 10);
				if (*end != '\0')
					fail_printf("Invalid value '%s' for --attach", optarg);
				break;
			}

			case 's': {
				validate_optlist("--setenv", optarg);

				if (env != NULL) {
					char *tmp = env;

					rc = asprintf(&env, "%s,%s", env, optarg);
					if (rc < 0) fail_printf("OOM");

					freep(&tmp);
				} else {
					env = strdup(optarg);
				}

				break;
			}

			case 'k':
				keepenv = 1;
				break;

			case 'U':
				clone_flags &= ~(CLONE_NEWUSER);
				break;

			case 'M':
				clone_flags &= ~(CLONE_NEWNS);
				break;

			case 'N':
				clone_flags &= ~(CLONE_NEWNET);
				break;

			case 'I':
				clone_flags &= ~(CLONE_NEWIPC);
				break;

			case 'H':
				clone_flags &= ~(CLONE_NEWUTS);
				break;

			case 'P':
				clone_flags &= ~(CLONE_NEWPID);
				break;

			case '?':
			case 'h':
				help();
				return 0;
		}
	}

	if (pid != -1) {
		master_fd = recv_pty(pid);
		if (master_fd < 0) fail_printf("Invalid PID '%u'", pid);

		pid = -1;
		goto process_fd;
	}

	if (user == NULL) {
		user = strdup("root");
		if (user == NULL) fail_printf("OOM");
	}

	open_master_pty(&master_fd, &master_name);

	uid = getuid();
	gid = getgid();

	if (detach == 1)
		do_daemonize();

	pid = do_clone();

	if (pid == 0) {
		closep(&master_fd);

		open_slave_pty(master_name);

		rc = setsid();
		if (rc < 0) sysf_printf("setsid()");

		rc = prctl(PR_SET_PDEATHSIG, SIGKILL);
		if (rc < 0) sysf_printf("prctl(PR_SET_PDEATHSIG)");

		if (clone_flags & CLONE_NEWUSER)
			map_user_to_user(uid, gid, user);

		do_cgroup(cgroup, ppid);

		do_mount(dest);

		if (dest != NULL) {
			copy_nodes(dest);

			make_ptmx(dest);

			make_symlinks(dest);

			make_console(dest, master_name);

			do_chroot(dest);
		}

		if (clone_flags & CLONE_NEWNET)
			setup_loopback();

		umask(0022);

		/* TODO: drop capabilities */

		do_user(user);

		if (change != NULL) {
			rc = chdir(change);
			if (rc < 0) sysf_printf("chdir()");
		}

		if (dest != NULL) {
			char *term = getenv("TERM");

			if (keepenv == 0)
				clearenv();

			setenv("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
			setenv("USER", user, 1);
			setenv("LOGNAME", user, 1);
			setenv("TERM", term, 1);
		}

		if (env != NULL) {
			size_t i, c;

			_free_ char **vars = NULL;

			_free_ char *tmp = strdup(env);
			if (tmp == NULL) fail_printf("OOM");

			c = split_str(tmp, &vars, ",");

			for (i = 0; i < c; i++) {
				rc = putenv(strdup(vars[i]));
				if (rc != 0) sysf_printf("putenv()");
			}
		}

		setenv("container", "pflask", 1);

		if (argc > optind)
			rc = execvpe(argv[optind], argv + optind, environ);
		else
			rc = execle("/bin/bash", "-bash", NULL, environ);

		if (rc < 0) sysf_printf("exec()");
	}

	do_netif(pid);

process_fd:
	if (detach == 1)
		serve_pty(master_fd);
	else
		process_pty(master_fd);

	if (pid == -1)
		return 0;

	kill(pid, SIGKILL);

	rc = waitid(P_PID, pid, &status, WEXITED);
	if (rc < 0) sysf_printf("waitid()");

	switch (status.si_code) {
		case CLD_EXITED:
			if (status.si_status != 0)
				err_printf("Child failed with code '%d'",
				           status.si_status);
			else
				ok_printf("Child exited");
			break;

		case CLD_KILLED:
			err_printf("Child was terminated");
			break;

		default:
			err_printf("Child failed");
			break;
	}

	undo_cgroup(cgroup, ppid);

	return status.si_status;
}
Exemple #16
0
void add_mount_from_spec(const char *spec) {
	int rc;

	size_t c;

	_free_ char **opts = NULL;

	_free_ char *tmp = strdup(spec);
	if (tmp == NULL) fail_printf("OOM");

	c = split_str(tmp, &opts, ",");
	if (c == 0) fail_printf("Invalid mount spec '%s'", spec);

	if (strncmp(opts[0], "bind", 4) == 0) {
		_free_ char *src = NULL;
		_free_ char *dst = NULL;

		if (c < 3) fail_printf("Invalid mount spec '%s'", spec);

		src = realpath(opts[1], NULL);
		if (src == NULL) sysf_printf("realpath()");

		dst = realpath(opts[2], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		add_mount(&mounts, src, dst, "bind", MS_BIND, NULL);

		if (strncmp(opts[0], "bind-ro", 8) == 0)
			add_mount(&mounts, src, dst, "bind-ro",
			          MS_REMOUNT | MS_BIND | MS_RDONLY, NULL);
	} else if (strncmp(opts[0], "aufs", 5) == 0) {
		_free_ char *dst = NULL;
		_free_ char *overlay = NULL;
		_free_ char *aufs_opts = NULL;

		if (c < 3) fail_printf("Invalid mount spec '%s'", spec);

		overlay = realpath(opts[1], NULL);
		if (overlay == NULL) sysf_printf("realpath()");

		dst = realpath(opts[2], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		rc = asprintf(&aufs_opts, "br:%s=rw:%s=ro", overlay, dst);
		if (rc < 0) fail_printf("OOM");

		add_mount(&mounts, NULL, dst, "aufs", 0, aufs_opts);
	} else if (strncmp(opts[0], "overlay", 8) == 0) {
		_free_ char *dst = NULL;
		_free_ char *overlay = NULL;
		_free_ char *workdir = NULL;

		if (c < 4) fail_printf("Invalid mount spec '%s'", spec);

		overlay = realpath(opts[1], NULL);
		if (overlay == NULL) sysf_printf("realpath()");

		dst = realpath(opts[2], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		workdir = realpath(opts[3], NULL);
		if (workdir == NULL) sysf_printf("realpath()");

		add_overlay_mount(&mounts, overlay, dst, workdir);
	} else if (strncmp(opts[0], "tmp", 4) == 0) {
		_free_ char *dst = NULL;

		if (c < 2) fail_printf("Invalid mount spec '%s'", spec);

		dst = realpath(opts[1], NULL);
		if (dst == NULL) sysf_printf("realpath()");

		add_mount(&mounts, "tmpfs", dst, "tmpfs", 0, NULL);
	} else {
		fail_printf("Invalid mount type '%s'", opts[0]);
	}
}
Exemple #17
0
int main(int argc, char *argv[]) {
    int rc, sync[2];

    pid_t pid = -1;

    siginfo_t status;

    struct mount *mounts = NULL;
    struct netif *netifs = NULL;
    struct cgroup *cgroups = NULL;
    struct user *users = NULL;
#if HAVE_LIBCAP_NG
    struct capability *caps = NULL;
#endif

    char *master;
    _close_ int master_fd = -1;

    char ephemeral_dir[] = "/tmp/pflask-ephemeral-XXXXXX";

    int clone_flags = CLONE_NEWNS  |
                          CLONE_NEWIPC |
                          CLONE_NEWPID |
#ifdef CLONE_NEWCGROUP
                          CLONE_NEWCGROUP |
#endif
                          CLONE_NEWUTS;

    struct gengetopt_args_info args;

    if (cmdline_parser(argc, argv, &args) != 0)
        return 1;

    for (unsigned int i = 0; i < args.mount_given; i++) {
        validate_optlist("--mount", args.mount_arg[i]);
        mount_add_from_spec(&mounts, args.mount_arg[i]);
    }

    for (unsigned int i = 0; i < args.netif_given; i++) {
        clone_flags |= CLONE_NEWNET;

        if (args.netif_arg != NULL) {
            validate_optlist("--netif", args.netif_arg[i]);
            netif_add_from_spec(&netifs, args.netif_arg[i]);
        }
    }

    if (args.user_given && !args.user_map_given) {
        uid_t uid;
        gid_t gid;

        clone_flags |= CLONE_NEWUSER;

        if (user_get_uid_gid(args.user_arg, &uid, &gid)) {
            user_add_map(&users, 'u', uid, uid, 1);
            user_add_map(&users, 'g', gid, gid, 1);
        }
    }

    for (unsigned int i = 0; i < args.user_map_given; i++) {
        size_t count;
        uid_t id, host_id;

        char *start = args.user_map_arg[i], *end = NULL;

        validate_optlist("--user-map", args.user_map_arg[i]);

        clone_flags |= CLONE_NEWUSER;

        id = strtoul(start, &end, 10);
        if (*end != ':')
            fail_printf("Invalid value '%s' for --user-map",
                        args.user_map_arg[i]);

        start = end + 1;

        host_id = strtoul(start, &end, 10);
        if (*end != ':')
            fail_printf("Invalid value '%s' for --user-map",
                        args.user_map_arg[i]);

        start = end + 1;

        count = strtoul(start, &end, 10);
        if (*end != '\0')
            fail_printf("Invalid value '%s' for --user-map",
                        args.user_map_arg[i]);

        user_add_map(&users, 'u', id, host_id, count);
        user_add_map(&users, 'g', id, host_id, count);
    }

    for (unsigned int i = 0; i < args.cgroup_given; i++)
        cgroup_add(&cgroups, args.cgroup_arg[i]);

#if HAVE_LIBCAP_NG
    for (unsigned int i = 0; i < args.caps_given; i++)
        capability_add(&caps, args.caps_arg[i]);
#endif

    if (args.no_userns_flag)
        clone_flags &= ~(CLONE_NEWUSER);

    if (args.no_mountns_flag)
        clone_flags &= ~(CLONE_NEWNS);

    if (args.no_netns_flag)
        clone_flags &= ~(CLONE_NEWNET);

    if (args.no_ipcns_flag)
        clone_flags &= ~(CLONE_NEWIPC);

    if (args.no_utsns_flag)
        clone_flags &= ~(CLONE_NEWUTS);

    if (args.no_pidns_flag)
        clone_flags &= ~(CLONE_NEWPID);

    if (args.attach_given) {
        master_fd = recv_pty(args.attach_arg);
        fail_if(master_fd < 0, "Invalid PID '%u'", args.attach_arg);

        process_pty(master_fd);
        return 0;
    }

    open_master_pty(&master_fd, &master);

    if (args.detach_flag)
        do_daemonize();

    sync_init(sync);

    if (args.ephemeral_flag) {
        if (!mkdtemp(ephemeral_dir))
            sysf_printf("mkdtemp()");
    }

    pid = do_clone(&clone_flags);

    if (!pid) {
        closep(&master_fd);

        rc = prctl(PR_SET_PDEATHSIG, SIGKILL);
        sys_fail_if(rc < 0, "prctl(PR_SET_PDEATHSIG)");

        rc = setsid();
        sys_fail_if(rc < 0, "setsid()");

        sync_barrier_parent(sync, SYNC_START);

        sync_close(sync);

        open_slave_pty(master);

        setup_user(args.user_arg);

        if (args.hostname_given) {
            rc = sethostname(args.hostname_arg,
                             strlen(args.hostname_arg));
            sys_fail_if(rc < 0, "Error setting hostname");
        }

        setup_mount(mounts, args.chroot_arg, args.ephemeral_flag ?
                                               ephemeral_dir : NULL);

        if (args.chroot_given) {
            setup_nodes(args.chroot_arg);

            setup_ptmx(args.chroot_arg);

            setup_symlinks(args.chroot_arg);

            setup_console(args.chroot_arg, master);

            do_chroot(args.chroot_arg);
        }

        if (clone_flags & CLONE_NEWNET)
            config_netif();

        umask(0022);

#if HAVE_LIBCAP_NG
        setup_capabilities(caps);
#endif

        if (args.chdir_given) {
            rc = chdir(args.chdir_arg);
            sys_fail_if(rc < 0, "Error changing cwd");
        }

        if (args.chroot_given) {
            char *term = getenv("TERM");

            if (!args.keepenv_flag)
                clearenv();

            setenv("PATH", "/usr/sbin:/usr/bin:/sbin:/bin", 1);
            setenv("USER", args.user_arg, 1);
            setenv("LOGNAME", args.user_arg, 1);
            if (term)
                setenv("TERM", term, 1);
        }

        for (unsigned int i = 0; i < args.setenv_given; i++) {
            rc = putenv(strdup(args.setenv_arg[i]));
            sys_fail_if(rc != 0, "Error setting environment");
        }

        setenv("container", "pflask", 1);

        if (argc > optind)
            rc = execvpe(argv[optind], argv + optind, environ);
        else
            rc = execle("/bin/bash", "-bash", NULL, environ);

        sys_fail_if(rc < 0, "Error executing command");
    }

    sync_wait_child(sync, SYNC_START);

    if (args.chroot_given && (clone_flags & CLONE_NEWUSER))
        setup_console_owner(master, users);

    setup_cgroup(cgroups, pid);

    setup_netif(netifs, pid);

#ifdef HAVE_DBUS
    register_machine(pid, args.chroot_given ? args.chroot_arg : "");
#endif

    if (clone_flags & CLONE_NEWUSER)
        setup_user_map(users, pid);

    sync_wake_child(sync, SYNC_DONE);

    sync_close(sync);

    if (args.detach_flag)
        serve_pty(master_fd);
    else
        process_pty(master_fd);

    kill(pid, SIGKILL);

    rc = waitid(P_PID, pid, &status, WEXITED);
    sys_fail_if(rc < 0, "Error waiting for child");

    switch (status.si_code) {
    case CLD_EXITED:
        if (status.si_status != 0)
            err_printf("Child failed with code '%d'",
                       status.si_status);
        else
            ok_printf("Child exited");
        break;

    case CLD_KILLED:
        err_printf("Child was terminated by signal '%d'",
                   status.si_status);
        break;

    default:
        err_printf("Child failed");
        break;
    }

    sync_close(sync);

    clean_cgroup(cgroups);

    if (args.ephemeral_flag) {
        rc = rmdir(ephemeral_dir);
        sys_fail_if(rc != 0, "Error deleting ephemeral directory: %s",
                             ephemeral_dir);
    }

    cmdline_parser_free(&args);

    return status.si_status;
}
Exemple #18
0
void register_machine(pid_t pid, const char *dest) {
	int rc;

	DBusError err;
	DBusConnection *conn;

	DBusMessageIter args;
	DBusMessage *req, *rep;

	DBusMessageIter uuid_iter, scope_iter;

	_free_ char *name = NULL;

	char *app = "pflask";
	unsigned char uuid[16];
	char *type = "container";

	dbus_error_init(&err);

	rc = asprintf(&name, "pflask-%d", pid);
	if (rc < 0) fail_printf("OOM");

	conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
	if (dbus_error_is_set(&err))
		return;

	req = dbus_message_new_method_call(
		"org.freedesktop.machine1",
		"/org/freedesktop/machine1",
		"org.freedesktop.machine1.Manager",
		"CreateMachine"
	);

	dbus_message_iter_init_append(req, &args);

	/* name */
	if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &name))
		fail_printf("OOM");

	/* id */
	if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "y",
	                                      &uuid_iter))
		fail_printf("OOM");

	if (!dbus_message_iter_append_fixed_array(&uuid_iter, DBUS_TYPE_BYTE,
	                                          uuid, 0))
		fail_printf("OOM");

	if (!dbus_message_iter_close_container(&args, &uuid_iter))
		fail_printf("OOM");

	/* service */
	if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &app))
		fail_printf("OOM");

	/* type */
	if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &type))
		fail_printf("OOM");

	/* leader */
	if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid))
		fail_printf("OOM");

	/* root */
	if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &dest))
		fail_printf("OOM");

	/* scope properties */
	if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "(sv)",
	                                      &scope_iter))
		fail_printf("OOM");

	if (!dbus_message_iter_close_container(&args, &scope_iter))
		fail_printf("OOM");

	rep = dbus_connection_send_with_reply_and_block(conn, req, -1, &err);
	if (dbus_error_is_set(&err))
		goto done;

	dbus_message_unref(rep);

done:
	dbus_message_unref(req);

	dbus_connection_close(conn);
	dbus_error_free(&err);
}
Exemple #19
0
void do_mount(char *dest) {
	int rc;

	mount_list *i = NULL;

	rc = mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL);
	if (rc < 0) sysf_printf("mount(MS_SLAVE)");

	if (dest != NULL) {
		/* add_mount(dest, dest, NULL, MS_BIND, "bind"); */

		add_mount_inside(dest, "proc", "/proc", "proc",
			MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL);

		add_mount_inside(dest, "/proc/sys", "/proc/sys", "proc/sys",
			MS_BIND, NULL);

		add_mount_inside(dest, NULL, "/proc/sys", "proc/sys-ro",
			MS_BIND | MS_RDONLY | MS_REMOUNT, NULL);

		add_mount_inside(dest, "sysfs", "/sys", "sysfs",
			MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_RDONLY, NULL);

		add_mount_inside(dest, "tmpfs", "/dev", "tmpfs",
			MS_NOSUID | MS_STRICTATIME, "mode=755");

		add_mount_inside(dest, "devpts", "/dev/pts", "devpts",
			MS_NOSUID | MS_NOEXEC,
			"newinstance,ptmxmode=000,mode=620,gid=5");

		add_mount_inside(dest, "tmpfs", "/dev/shm", "tmpfs",
			MS_NOSUID | MS_STRICTATIME | MS_NODEV, "mode=1777");

		add_mount_inside(dest, "tmpfs", "/run", "tmpfs",
			MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755");

		/* add_mount(dest, "/", NULL, MS_MOVE, "move"); */
	}

	while (mounts) {
		mount_list *next = mounts->next;
		mounts->next = i;
		i = mounts;
		mounts = next;
	}

	while (i != NULL) {
		rc = mkdir(i->dst, 0755);
		if (rc < 0) {
			switch (errno) {
				struct stat sb;

				case EEXIST:
					if (!stat(i->dst, &sb) &&
					    !S_ISDIR(sb.st_mode))
						fail_printf("Not a directory");
					break;

				default:
					sysf_printf("mkdir(%s)", i->dst);
					break;
			}
		}

		rc = mount(i->src, i->dst, i->type, i->flags, i->data);
		if (rc < 0) sysf_printf("mount(%s)", i->type);

		i = i->next;
	}
}