Ejemplo n.º 1
0
int vz_env_create(vps_handler *h, envid_t veid, vps_res *res,
		int wait_p[2], int old_wait_p[2], int err_p[2],
				env_create_FN fn, void *data)
{
	int ret, pid, errcode;
	int old_wait_fd;
	int status_p[2];
	struct sigaction act, actold;

	if (check_var(res->fs.root, "VE_ROOT is not set"))
		return VZ_VE_ROOT_NOTSET;
	if (pipe(status_p) < 0) {
		logger(-1, errno, "Can not create pipe");
		return VZ_RESOURCE_ERROR;
	}
	sigaction(SIGCHLD, NULL, &actold);
	sigemptyset(&act.sa_mask);
	act.sa_handler = SIG_IGN;
	act.sa_flags = SA_NOCLDSTOP;
	sigaction(SIGCHLD, &act, NULL);

	get_osrelease(res);

	if ((pid = fork()) < 0) {
		logger(-1, errno, "Can not fork");
		ret =  VZ_RESOURCE_ERROR;
		goto err;
	} else if (pid == 0) {
		dup2(status_p[1], STDIN_FILENO);
		close(status_p[0]);
		close(status_p[1]);
		fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC);
		fcntl(err_p[1], F_SETFD, FD_CLOEXEC);
		close(err_p[0]);
		fcntl(wait_p[0], F_SETFD, FD_CLOEXEC);
		close(wait_p[1]);
		if (old_wait_p) {
			fcntl(old_wait_p[0], F_SETFD, FD_CLOEXEC);
			close(old_wait_p[1]);
			old_wait_fd = old_wait_p[0];
		} else
			old_wait_fd = -1;

		ret = vz_real_env_create(h, veid, res, wait_p[0],
					old_wait_fd, err_p[1], fn, data);
		if (ret)
			write(STDIN_FILENO, &ret, sizeof(ret));
		exit(ret);
	}
	/* Wait for environment created */
	close(status_p[1]);
	close(wait_p[0]);
	if (old_wait_p)
		close(old_wait_p[0]);
	close(err_p[1]);
	ret = read(status_p[0], &errcode, sizeof(errcode));
	if (ret > 0) {
		ret = errcode;
		switch(ret) {
		case VZ_NO_ACCES:
			logger(-1, 0, "Permission denied");
			break;
		case VZ_BAD_KERNEL:
			logger(-1, 0, "Invalid kernel, or some kernel"
				" modules are not loaded");
			break;
		case VZ_SET_CAP:
			logger(-1, 0, "Unable to set capability");
			break;
		case VZ_RESOURCE_ERROR:
			logger(-1, 0, "Not enough resources"
				" to start environment");
			break;
		case VZ_WAIT_FAILED:
			logger(0, 0, "Unable to set"
				" wait functionality");
			break;
		case VZ_SET_OSRELEASE:
			logger(-1, 0, "Unable to set osrelease to %s",
					res->env.osrelease);
			break;
		}
	}
err:
	close(status_p[1]);
	close(status_p[0]);
	sigaction(SIGCHLD, &actold, NULL);

	return ret;
}
Ejemplo n.º 2
0
Archivo: env.c Proyecto: funtoo/vzctl
static int _env_create(vps_handler *h, envid_t veid, int wait_p, int err_p,
                       void *data)
{
    struct vzctl_env_create_data env_create_data;
    struct env_create_param3 create_param;
    int fd, ret;
    vps_res *res;
    char *argv[] = {"init", "-z", "      ", NULL};
    char *envp[] = {"HOME=/", "TERM=linux", NULL};

    res = (vps_res *) data;
    memset(&create_param, 0, sizeof(create_param));
    create_param.iptables_mask = get_ipt_mask(res->env.ipt_mask);
    logger(3, 0, "Set iptables mask %#10.8llx",
           (unsigned long long) create_param.iptables_mask);
    clean_hardlink_dir("/");
    if (res->cpu.vcpus != NULL)
        create_param.total_vcpus = *res->cpu.vcpus;
    env_create_data.veid = veid;
    env_create_data.class_id = 0;
    env_create_data.flags = VE_CREATE | VE_EXCLUSIVE;
    env_create_data.data = &create_param;
    env_create_data.datalen = sizeof(create_param);

    create_param.feature_mask = res->env.features_mask;
    create_param.known_features = res->env.features_known;
    /* sysfs enabled by default, unless explicitly disabled */
    if (! (res->env.features_known & VE_FEATURE_SYSFS)) {
        create_param.feature_mask |= VE_FEATURE_SYSFS;
        create_param.known_features |= VE_FEATURE_SYSFS;
    }
    logger(3, 0, "Set features mask %016llx/%016llx",
           create_param.feature_mask,
           create_param.known_features);

    /* Close all fds except stdin. stdin is status pipe */
    close(STDERR_FILENO);
    close(STDOUT_FILENO);
    close_fds(0, wait_p, err_p, h->vzfd, -1);
try:
        ret = vz_env_create_data_ioctl(h, &env_create_data);
    if (ret < 0) {
        switch(errno) {
        case EINVAL:
            ret = VZ_ENVCREATE_ERROR;
            /* Run-time kernel did not understand the
             * latest create_param -- so retry with
             * the old env_create_param structs.
             */
            switch (env_create_data.datalen) {
            case sizeof(struct env_create_param3):
                env_create_data.datalen =
                    sizeof(struct env_create_param2);
                goto try;
            case sizeof(struct env_create_param2):
                env_create_data.datalen =
                    sizeof(struct env_create_param);
                goto try;
            }
            break;
        case EACCES:
            /* License is not loaded */
            ret = VZ_NO_ACCES;
            break;
        case ENOTTY:
            /* Some vz modules are not present */
            ret = VZ_BAD_KERNEL;
            break;
        default:
            logger(-1, errno, "env_create error");
            ret = VZ_ENVCREATE_ERROR;
            break;
        }
        goto env_err;
    }
    if (res->env.osrelease != NULL) {
        ret = vz_env_configure(h->vzfd, veid,
                               res->env.osrelease);
        if (ret != 0)
            goto env_err;
    }

    close(h->vzfd);
    /* Create /fastboot to skip run fsck */
    fd = open("/fastboot", O_CREAT | O_RDONLY, 0644);
    close(fd);

    if (res->misc.wait == YES) {
        if (add_reach_runlevel_mark()) {
            ret = VZ_WAIT_FAILED;
            goto env_err;
        }
    }

    mount("proc", "/proc", "proc", 0, 0);
    if (stat_file("/sys"))
        mount("sysfs", "/sys", "sysfs", 0, 0);

    if (create_param.feature_mask & VE_FEATURE_NFSD) {
        mount("nfsd", "/proc/fs/nfsd", "nfsd", 0, 0);
        make_dir("/var/lib/nfs/rpc_pipefs", 1);
        mount("sunrpc", "/var/lib/nfs/rpc_pipefs", "rpc_pipefs", 0, 0);
    }
    configure_sysctl();
    if (res->dq.ugidlimit != NULL)
        mk_quota_link();

    /* Close status descriptor to report that
     * environment is created.
    */
    close(STDIN_FILENO);
    /* Now we wait until CT setup will be done
       If no error, then start init, otherwise exit.
    */
    if (read(wait_p, &ret, sizeof(ret)) == 0)
        return 0;
    if ((fd = open("/dev/null", O_RDWR)) != -1) {
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);
    }
    logger(10, 0, "Starting init");
    execve("/sbin/init", argv, envp);
    execve("/etc/init", argv, envp);
    execve("/bin/init", argv, envp);

    ret = VZ_FS_BAD_TMPL;
    write(err_p, &ret, sizeof(ret));
env_err:
    return ret;
}

static int vz_real_env_create(vps_handler *h, envid_t veid, vps_res *res,
                              int wait_p, int old_wait_p, int err_p, env_create_FN fn, void *data)
{
    int ret, pid;

    if ((ret = vz_chroot(res->fs.root)))
        return ret;
    if ((ret = vz_setluid(veid)))
        return ret;
    if ((ret = setup_resource_management(h, veid, res)))
        return ret;
    /* Create another process for proper resource accounting */
    if ((pid = fork()) < 0) {
        logger(-1, errno, "Unable to fork");
        return VZ_RESOURCE_ERROR;
    } else if (pid == 0) {
        if ((ret = vps_set_cap(veid, &res->env, &res->cap)))
            goto env_err;
        if (fn == NULL) {
            ret = _env_create(h, veid, wait_p, err_p, (void *)res);
        } else {
            ret = fn(h, veid, wait_p, old_wait_p, err_p, data);
        }
env_err:
        if (ret)
            write(STDIN_FILENO, &ret, sizeof(ret));
        exit(ret);
    }
    return 0;
}

int vz_env_create(vps_handler *h, envid_t veid, vps_res *res,
                  int wait_p[2], int old_wait_p[2], int err_p[2],
                  env_create_FN fn, void *data)
{
    int ret, pid, errcode;
    int old_wait_fd;
    int status_p[2];
    struct sigaction act, actold;

    if (check_var(res->fs.root, "VE_ROOT is not set"))
        return VZ_VE_ROOT_NOTSET;
    if (pipe(status_p) < 0) {
        logger(-1, errno, "Can not create pipe");
        return VZ_RESOURCE_ERROR;
    }
    sigaction(SIGCHLD, NULL, &actold);
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_IGN;
    act.sa_flags = SA_NOCLDSTOP;
    sigaction(SIGCHLD, &act, NULL);

    get_osrelease(res);

    if ((pid = fork()) < 0) {
        logger(-1, errno, "Can not fork");
        ret =  VZ_RESOURCE_ERROR;
        goto err;
    } else if (pid == 0) {
        dup2(status_p[1], STDIN_FILENO);
        close(status_p[0]);
        close(status_p[1]);
        fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC);
        fcntl(err_p[1], F_SETFD, FD_CLOEXEC);
        close(err_p[0]);
        fcntl(wait_p[0], F_SETFD, FD_CLOEXEC);
        close(wait_p[1]);
        if (old_wait_p) {
            fcntl(old_wait_p[0], F_SETFD, FD_CLOEXEC);
            close(old_wait_p[1]);
            old_wait_fd = old_wait_p[0];
        } else
            old_wait_fd = -1;

        ret = vz_real_env_create(h, veid, res, wait_p[0],
                                 old_wait_fd, err_p[1], fn, data);
        if (ret)
            write(STDIN_FILENO, &ret, sizeof(ret));
        exit(ret);
    }
    /* Wait for environment created */
    close(status_p[1]);
    close(wait_p[0]);
    if (old_wait_p)
        close(old_wait_p[0]);
    close(err_p[1]);
    ret = read(status_p[0], &errcode, sizeof(errcode));
    if (ret > 0) {
        ret = errcode;
        switch(ret) {
        case VZ_NO_ACCES:
            logger(-1, 0, "Permission denied");
            break;
        case VZ_BAD_KERNEL:
            logger(-1, 0, "Invalid kernel, or some kernel"
                   " modules are not loaded");
            break;
        case VZ_SET_CAP:
            logger(-1, 0, "Unable to set capability");
            break;
        case VZ_RESOURCE_ERROR:
            logger(-1, 0, "Not enough resources"
                   " to start environment");
            break;
        case VZ_WAIT_FAILED:
            logger(0, 0, "Unable to set"
                   " wait functionality");
            break;
        case VZ_SET_OSRELEASE:
            logger(-1, 0, "Unable to set osrelease to %s",
                   res->env.osrelease);
            break;
        }
    }
err:
    close(status_p[1]);
    close(status_p[0]);
    sigaction(SIGCHLD, &actold, NULL);

    return ret;
}