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; }
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; }