From: 2xsec Date: Fri, 20 Jul 2018 14:41:10 +0000 (+0900) Subject: lxccontainer: coding rules X-Git-Tag: lxc-3.1.0~200^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a73846d8935ca471939cc38f92f232806594608f;p=thirdparty%2Flxc.git lxccontainer: coding rules Signed-off-by: 2xsec --- diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index ce01f13e9..cd4891ab0 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -167,11 +167,12 @@ static int ongoing_create(struct lxc_container *c) ret = fcntl(fd, F_OFD_GETLK, &lk); if (ret < 0 && errno == EINVAL) ret = flock(fd, LOCK_EX | LOCK_NB); + close(fd); - if (ret == 0 && lk.l_pid != -1) { + + if (ret == 0 && lk.l_pid != -1) /* create is still ongoing */ return 1; - } /* Create completed but partial is still there. */ return 2; @@ -221,6 +222,7 @@ static void remove_partial(struct lxc_container *c, int fd) char *path; close(fd); + /* $lxcpath + '/' + $name + '/partial' + \0 */ len = strlen(c->config_path) + strlen(c->name) + 10; path = alloca(len); @@ -254,7 +256,6 @@ static void remove_partial(struct lxc_container *c, int fd) * decrement numthreads under privlock, then if it hits 0 you can delete. * Do not ever use a lxccontainer whose numthreads you did not bump. */ - static void lxc_container_free(struct lxc_container *c) { if (!c) @@ -358,7 +359,6 @@ int lxc_container_put(struct lxc_container *c) } container_mem_unlock(c); - return 0; } @@ -385,7 +385,6 @@ static bool do_lxcapi_is_defined(struct lxc_container *c) on_error: container_mem_unlock(c); - return ret; } @@ -596,7 +595,6 @@ static bool load_config_locked(struct lxc_container *c, const char *fname) return false; c->lxc_conf->name = c->name; - return true; } @@ -610,8 +608,10 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) return false; fname = c->configfile; + if (alt_file) fname = alt_file; + if (!fname) return false; @@ -746,9 +746,8 @@ static char **split_init_cmd(const char *incmd) len = strlen(incmd) + 1; copy = alloca(len); retlen = strlcpy(copy, incmd, len); - if (retlen >= len) { + if (retlen >= len) return NULL; - } do { argv = malloc(sizeof(char *)); @@ -781,62 +780,62 @@ static void free_init_cmd(char **argv) static int lxc_rcv_status(int state_socket) { - int ret; - int state = -1; + int ret; + int state = -1; again: - /* Receive container state. */ - ret = lxc_abstract_unix_rcv_credential(state_socket, &state, - sizeof(int)); - if (ret <= 0) { + /* Receive container state. */ + ret = lxc_abstract_unix_rcv_credential(state_socket, &state, sizeof(int)); + if (ret <= 0) { if (errno != EINTR) return -1; + TRACE("Caught EINTR; retrying"); goto again; } - return state; + return state; } static bool wait_on_daemonized_start(struct lxc_handler *handler, int pid) { - int ret, state; + int ret, state; - /* Close write end of the socket pair. */ - close(handler->state_socket_pair[1]); - handler->state_socket_pair[1] = -1; + /* Close write end of the socket pair. */ + close(handler->state_socket_pair[1]); + handler->state_socket_pair[1] = -1; - state = lxc_rcv_status(handler->state_socket_pair[0]); + state = lxc_rcv_status(handler->state_socket_pair[0]); - /* Close read end of the socket pair. */ - close(handler->state_socket_pair[0]); - handler->state_socket_pair[0] = -1; + /* Close read end of the socket pair. */ + close(handler->state_socket_pair[0]); + handler->state_socket_pair[0] = -1; - /* The first child is going to fork() again and then exits. So we reap - * the first child here. - */ + /* The first child is going to fork() again and then exits. So we reap + * the first child here. + */ ret = wait_for_pid(pid); if (ret < 0) - DEBUG("Failed waiting on first child %d", pid); + DEBUG("Failed waiting on first child %d", pid); else - DEBUG("First child %d exited", pid); + DEBUG("First child %d exited", pid); - if (state < 0) { - SYSERROR("Failed to receive the container state"); - return false; - } + if (state < 0) { + SYSERROR("Failed to receive the container state"); + return false; + } - /* If we receive anything else then running we know that the container - * failed to start. - */ - if (state != RUNNING) { - ERROR("Received container state \"%s\" instead of \"RUNNING\"", - lxc_state2str(state)); - return false; - } + /* If we receive anything else then running we know that the container + * failed to start. + */ + if (state != RUNNING) { + ERROR("Received container state \"%s\" instead of \"RUNNING\"", + lxc_state2str(state)); + return false; + } - TRACE("Container is in \"RUNNING\" state"); - return true; + TRACE("Container is in \"RUNNING\" state"); + return true; } static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) @@ -1147,6 +1146,7 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) on_error: if (inargs) { char **arg; + for (arg = inargs; *arg; arg++) free(*arg); free(inargs); @@ -1405,9 +1405,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, * args. */ if (argv) - for (nargs = 0; argv[nargs]; nargs++) { + for (nargs = 0; argv[nargs]; nargs++) ; - } + /* template, path, rootfs and name args */ nargs += 4; @@ -1421,6 +1421,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, patharg = malloc(len); if (!patharg) _exit(EXIT_FAILURE); + ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name); if (ret < 0 || ret >= len) _exit(EXIT_FAILURE); @@ -1431,6 +1432,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, namearg = malloc(len); if (!namearg) _exit(EXIT_FAILURE); + ret = snprintf(namearg, len, "--name=%s", c->name); if (ret < 0 || ret >= len) _exit(EXIT_FAILURE); @@ -1441,6 +1443,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, rootfsarg = malloc(len); if (!rootfsarg) _exit(EXIT_FAILURE); + ret = snprintf(rootfsarg, len, "--rootfs=%s", bdev->dest); if (ret < 0 || ret >= len) _exit(EXIT_FAILURE); @@ -1478,6 +1481,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, newargv[0] = tpath; tpath = "lxc-usernsexec"; n2[0] = "lxc-usernsexec"; + lxc_list_for_each(it, &conf->id_map) { map = it->elem; n2args += 2; @@ -1499,6 +1503,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, hostuid_mapped = mapped_hostid(geteuid(), conf, ID_TYPE_UID); extraargs = hostuid_mapped >= 0 ? 1 : 3; + n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *)); if (!n2) _exit(EXIT_FAILURE); @@ -1516,6 +1521,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, SYSERROR("out of memory"); _exit(EXIT_FAILURE); } + ret = snprintf(n2[n2args - 1], 200, "u:%d:%d:1", hostuid_mapped, geteuid()); if (ret < 0 || ret >= 200) @@ -1524,6 +1530,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, hostgid_mapped = mapped_hostid(getegid(), conf, ID_TYPE_GID); extraargs = hostgid_mapped >= 0 ? 1 : 3; + n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *)); if (!n2) _exit(EXIT_FAILURE); @@ -1547,7 +1554,9 @@ static bool create_run_template(struct lxc_container *c, char *tpath, if (ret < 0 || ret >= 200) _exit(EXIT_FAILURE); } + n2[n2args++] = "--"; + for (i = 0; i < nargs; i++) n2[i + n2args] = newargv[i]; n2args += nargs; @@ -1644,6 +1653,7 @@ static bool prepend_lxc_header(char *path, const char *t, char *const argv[]) goto out_free_contents; contents[flen] = '\0'; + ret = fclose(f); f = NULL; if (ret < 0) @@ -1681,6 +1691,7 @@ static bool prepend_lxc_header(char *path, const char *t, char *const argv[]) } fprintf(f, "\n"); } + #if HAVE_LIBGNUTLS fprintf(f, "# Template script checksum (SHA-1): "); for (i=0; ilxc_conf && c->lxc_conf->rootfs.path && - access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) { + access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) { ERROR("Container \"%s\" already exists in \"%s\"", c->name, c->config_path); goto free_tpath; @@ -1811,6 +1822,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, */ if (!c->save_config(c, NULL)) ERROR("Failed to save initial config for \"%s\"", c->name); + ret = true; goto out; } @@ -1856,14 +1868,17 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, bdev->ops->destroy(bdev); _exit(EXIT_FAILURE); } + _exit(EXIT_SUCCESS); } + if (wait_for_pid(pid) != 0) goto out_unlock; /* Reload config to get the rootfs. */ lxc_conf_free(c->lxc_conf); c->lxc_conf = NULL; + if (!load_config_locked(c, c->configfile)) goto out_unlock; @@ -1881,15 +1896,18 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, goto out_unlock; } } + ret = load_config_locked(c, c->configfile); out_unlock: umask(mask); if (partial_fd >= 0) remove_partial(c, partial_fd); + out: if (!ret) container_destroy(c, NULL); + free_tpath: free(tpath); return ret; @@ -1900,7 +1918,9 @@ static bool lxcapi_create(struct lxc_container *c, const char *t, int flags, char *const argv[]) { bool ret; + current_config = c ? c->lxc_conf : NULL; + ret = do_lxcapi_create(c, t, bdevtype, specs, flags, argv); current_config = NULL; return ret; @@ -1981,6 +2001,7 @@ static bool do_lxcapi_reboot2(struct lxc_container *c, int timeout) if (killret < 0) { if (state_client_fd >= 0) close(state_client_fd); + WARN("Failed to send signal %d to pid %d", rebootsignal, pid); return false; } @@ -2051,6 +2072,7 @@ static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) if (killret < 0) { if (state_client_fd >= 0) close(state_client_fd); + WARN("Failed to send signal %d to pid %d", haltsignal, pid); return false; } @@ -2151,6 +2173,7 @@ static bool do_lxcapi_clear_config_item(struct lxc_container *c, */ if (config && config->clr) ret = config->clr(key, c->lxc_conf, NULL); + if (!ret) do_clear_unexp_config_line(c->lxc_conf, key); @@ -2164,10 +2187,11 @@ static inline bool enter_net_ns(struct lxc_container *c) { pid_t pid = do_lxcapi_init_pid(c); - if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) && access("/proc/self/ns/user", F_OK) == 0) { + if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) && + (access("/proc/self/ns/user", F_OK) == 0)) if (!switch_to_ns(pid, "user")) return false; - } + return switch_to_ns(pid, "net"); } @@ -2229,10 +2253,11 @@ static char** get_from_array(char ***names, char *cname, int size) return (char **)bsearch(&cname, *names, size, sizeof(char *), (int (*)(const void *, const void *))string_cmp); } - -static bool array_contains(char ***names, char *cname, int size) { +static bool array_contains(char ***names, char *cname, int size) +{ if(get_from_array(names, cname, size) != NULL) return true; + return false; } @@ -2243,6 +2268,7 @@ static bool remove_from_array(char ***names, char *cname, int size) free(result); return true; } + return false; } @@ -2293,6 +2319,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c) } count++; } + ret = 0; out: @@ -2322,6 +2349,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c) if (wait_for_pid(pid) != 0) { for(i=0;ilxc_conf) return NULL; + if (container_mem_lock(c)) return NULL; + ret = lxc_cmd_get_config_item(c->name, key, do_lxcapi_get_config_path(c)); container_mem_unlock(c); return ret; @@ -2542,6 +2574,7 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file) if (!alt_file) alt_file = c->configfile; + if (!alt_file) return false; @@ -2615,6 +2648,7 @@ static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name); if (ret < 0 || ret > MAXPATHLEN) goto out; + ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name); if (ret < 0 || ret > MAXPATHLEN) goto out; @@ -2702,6 +2736,7 @@ static bool mod_rdep(struct lxc_container *c0, struct lxc_container *c, bool inc goto out; } } + close(fd); } @@ -2737,9 +2772,11 @@ void mod_all_rdeps(struct lxc_container *c, bool inc) ERROR("Path name too long"); return; } + f = fopen(path, "r"); if (f == NULL) return; + while (getline(&lxcpath, &pathlen, f) != -1) { if (getline(&lxcname, &namelen, f) == -1) { ERROR("badly formatted file %s", path); @@ -2754,11 +2791,14 @@ void mod_all_rdeps(struct lxc_container *c, bool inc) lxcpath, lxcname); continue; } + if (!mod_rdep(p, c, inc)) ERROR("Failed to update snapshots file for %s:%s", lxcpath, lxcname); + lxc_container_put(p); } + out: free(lxcpath); free(lxcname); @@ -2777,20 +2817,24 @@ static bool has_fs_snapshots(struct lxc_container *c) c->name); if (ret < 0 || ret > MAXPATHLEN) goto out; + /* If the file doesn't exist there are no snapshots. */ if (stat(path, &fbuf) < 0) goto out; + v = fbuf.st_size; if (v != 0) { f = fopen(path, "r"); if (!f) goto out; + ret = fscanf(f, "%d", &v); fclose(f); /* TODO: Figure out what to do with the return value of fscanf. */ if (ret != 1) INFO("Container uses new lxc-snapshots format %s", path); } + bret = v != 0; out: @@ -2806,9 +2850,11 @@ static bool has_snapshots(struct lxc_container *c) if (!get_snappath_dir(c, path)) return false; + dir = opendir(path); if (!dir) return false; + while ((direntp = readdir(dir))) { if (!strcmp(direntp->d_name, ".")) continue; @@ -2818,6 +2864,7 @@ static bool has_snapshots(struct lxc_container *c) count++; break; } + closedir(dir); return count > 0; } @@ -2901,6 +2948,7 @@ static bool container_destroy(struct lxc_container *c, if (current_config && conf == current_config) { current_config = NULL; + if (conf->logfd != -1) { close(conf->logfd); conf->logfd = -1; @@ -2966,6 +3014,7 @@ static bool container_destroy(struct lxc_container *c, ret = snprintf(path, len, "%s/%s", p1, c->name); if (ret < 0 || (size_t)ret >= len) goto out; + if (am_guest_unpriv()) ret = userns_exec_full(conf, lxc_rmdir_onedev_wrapper, path, "lxc_rmdir_onedev_wrapper"); @@ -2983,6 +3032,7 @@ static bool container_destroy(struct lxc_container *c, out: if (path) free(path); + container_disk_unlock(c); return bret; } @@ -3011,10 +3061,12 @@ static bool do_lxcapi_destroy_with_snapshots(struct lxc_container *c) { if (!c || !lxcapi_is_defined(c)) return false; + if (!lxcapi_snapshot_destroy_all(c)) { ERROR("Error deleting all snapshots"); return false; } + return lxcapi_destroy(c); } @@ -3085,6 +3137,7 @@ static char *lxcapi_config_file_name(struct lxc_container *c) { if (!c || !c->configfile) return NULL; + return strdup(c->configfile); } @@ -3092,6 +3145,7 @@ static const char *lxcapi_get_config_path(struct lxc_container *c) { if (!c || !c->config_path) return NULL; + return (const char *)(c->config_path); } @@ -3160,6 +3214,7 @@ static bool do_lxcapi_set_config_path(struct lxc_container *c, const char *path) c->config_path = oldpath; oldpath = NULL; } + err: free(oldpath); container_mem_unlock(c); @@ -3248,6 +3303,7 @@ static int copy_file(const char *old, const char *new) ERROR("copy destination %s exists", new); return -1; } + ret = stat(old, &sbuf); if (ret < 0) { INFO("Error stat'ing %s", old); @@ -3259,6 +3315,7 @@ static int copy_file(const char *old, const char *new) SYSERROR("Error opening original file %s", old); return -1; } + out = open(new, O_CREAT | O_EXCL | O_WRONLY, 0644); if (out < 0) { SYSERROR("Error opening new file %s", new); @@ -3272,14 +3329,17 @@ static int copy_file(const char *old, const char *new) SYSERROR("Error reading old file %s", old); goto err; } + if (len == 0) break; + ret = write(out, buf, len); if (ret < len) { /* should we retry? */ SYSERROR("Error: write to new file %s was interrupted", new); goto err; } } + close(in); close(out); @@ -3317,19 +3377,24 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c) char tmppath[MAXPATHLEN]; if (!fname) /* relative path - we don't support, but maybe we should */ return 0; + if (strncmp(hookname, cpath, len - 1) != 0) { /* this hook is public - ignore */ continue; } + /* copy the script, and change the entry in confile */ ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s", c->config_path, c->name, fname+1); if (ret < 0 || ret >= MAXPATHLEN) return -1; + ret = copy_file(it->elem, tmppath); if (ret < 0) return -1; + free(it->elem); + it->elem = strdup(tmppath); if (!it->elem) { ERROR("out of memory copying hook path"); @@ -3343,6 +3408,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c) ERROR("Error saving new hooks in clone"); return -1; } + do_lxcapi_save_config(c, NULL); return 0; } @@ -3362,12 +3428,14 @@ static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c) char *p = strrchr(oldpath, '/'); if (!p) return -1; + ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s", c->config_path, c->name, p); if (ret < 0 || ret >= MAXPATHLEN) { ERROR("error printing new path for %s", oldpath); return -1; } + if (file_exists(newpath)) { ERROR("error: fstab file %s exists", newpath); return -1; @@ -3377,12 +3445,15 @@ static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c) ERROR("error: copying %s to %s", oldpath, newpath); return -1; } + free(c->lxc_conf->fstab); + c->lxc_conf->fstab = strdup(newpath); if (!c->lxc_conf->fstab) { ERROR("error: allocating pathname"); return -1; } + if (!do_append_unexp_config_line(c->lxc_conf, "lxc.mount.fstab", newpath)) { ERROR("error saving new lxctab"); return -1; @@ -3402,12 +3473,14 @@ static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0) WARN("Error copying reverse dependencies"); return; } + ret = snprintf(path1, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path, c->name); if (ret < 0 || ret >= MAXPATHLEN) { WARN("Error copying reverse dependencies"); return; } + if (copy_file(path0, path1) < 0) { INFO("Error copying reverse dependencies"); return; @@ -3425,15 +3498,20 @@ static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0) c->name); if (ret < 0 || ret >= MAXPATHLEN) return false; + f = fopen(path, "a"); if (!f) return false; + bret = true; + /* If anything goes wrong, just return an error. */ if (fprintf(f, "%s\n%s\n", c0->config_path, c0->name) < 0) bret = false; + if (fclose(f) != 0) bret = false; + return bret; } @@ -3506,6 +3584,7 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c, if (flags & LXC_CLONE_SNAPSHOT) copy_rdepends(c, c0); + if (need_rdep) { if (!add_rdepends(c, c0)) WARN("Error adding reverse dependency from %s to %s", @@ -3543,30 +3622,36 @@ static int clone_update_rootfs(struct clone_update_data *data) ERROR("Failed to setgid to 0"); return -1; } + if (setuid(0) < 0) { ERROR("Failed to setuid to 0"); return -1; } + if (setgroups(0, NULL) < 0) WARN("Failed to clear groups"); if (unshare(CLONE_NEWNS) < 0) return -1; + bdev = storage_init(c->lxc_conf); if (!bdev) return -1; + if (strcmp(bdev->type, "dir") != 0) { if (unshare(CLONE_NEWNS) < 0) { ERROR("error unsharing mounts"); storage_put(bdev); return -1; } + if (detect_shared_rootfs()) { if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { SYSERROR("Failed to make / rslave"); ERROR("Continuing..."); } } + if (bdev->ops->mount(bdev) < 0) { storage_put(bdev); return -1; @@ -3578,21 +3663,20 @@ static int clone_update_rootfs(struct clone_update_data *data) if (!lxc_list_empty(&conf->hooks[LXCHOOK_CLONE])) { /* Start of environment variable setup for hooks */ - if (c0->name && setenv("LXC_SRC_NAME", c0->name, 1)) { + if (c0->name && setenv("LXC_SRC_NAME", c0->name, 1)) SYSERROR("failed to set environment variable for source container name"); - } - if (setenv("LXC_NAME", c->name, 1)) { + + if (setenv("LXC_NAME", c->name, 1)) SYSERROR("failed to set environment variable for container name"); - } - if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) { + + if (conf->rcfile && setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) SYSERROR("failed to set environment variable for config path"); - } - if (bdev->dest && setenv("LXC_ROOTFS_MOUNT", bdev->dest, 1)) { + + if (bdev->dest && setenv("LXC_ROOTFS_MOUNT", bdev->dest, 1)) SYSERROR("failed to set environment variable for rootfs mount"); - } - if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) { + + if (conf->rootfs.path && setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) SYSERROR("failed to set environment variable for rootfs mount"); - } if (run_lxc_hooks(c->name, "clone", conf, hookargs)) { ERROR("Error executing clone hook for %s", c->name); @@ -3607,16 +3691,20 @@ static int clone_update_rootfs(struct clone_update_data *data) if (ret < 0 || ret >= MAXPATHLEN) return -1; + if (!file_exists(path)) return 0; + if (!(fout = fopen(path, "w"))) { SYSERROR("unable to open %s: ignoring", path); return 0; } + if (fprintf(fout, "%s", c->name) < 0) { fclose(fout); return -1; } + if (fclose(fout) < 0) return -1; } else { @@ -3650,9 +3738,11 @@ static int create_file_dirname(char *path, struct lxc_conf *conf) if (!p) return -1; + *p = '\0'; ret = do_create_container_dir(path, conf); *p = '/'; + return ret; } @@ -3684,8 +3774,10 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char /* Make sure the container doesn't yet exist. */ if (!newname) newname = c->name; + if (!lxcpath) lxcpath = do_lxcapi_get_config_path(c); + ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname); if (ret < 0 || ret >= MAXPATHLEN) { SYSERROR("clone: failed making config pathname"); @@ -3727,7 +3819,9 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", false); write_config(fd, c->lxc_conf); close(fd); + c->lxc_conf->rootfs.path = origroot; + free(c->lxc_conf->unexpanded_config); c->lxc_conf->unexpanded_config = saved_unexp_conf; saved_unexp_conf = NULL; @@ -3771,7 +3865,6 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char if (ret < 0) goto out; - /* update utsname */ if (!(flags & LXC_CLONE_KEEPNAME)) { clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false); @@ -3819,17 +3912,21 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char SYSERROR("fork"); goto out; } + if (pid > 0) { ret = wait_for_pid(pid); if (ret) goto out; + container_mem_unlock(c); return c2; } + data.c0 = c; data.c1 = c2; data.flags = flags; data.hookargs = hookargs; + if (am_guest_unpriv()) ret = userns_exec_full(c->lxc_conf, clone_update_rootfs_wrapper, &data, "clone_update_rootfs_wrapper"); @@ -3846,6 +3943,7 @@ out: if (c2) { if (!storage_copied) c2->lxc_conf->rootfs.path = NULL; + c2->destroy(c2); lxc_container_put(c2); } @@ -3859,9 +3957,11 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n char **hookargs) { struct lxc_container * ret; + current_config = c ? c->lxc_conf : NULL; ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs); current_config = NULL; + return ret; } @@ -3877,6 +3977,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname) ERROR("Renaming a container with snapshots is not supported"); return false; } + bdev = storage_init(c->lxc_conf); if (!bdev) { ERROR("Failed to find original backing store type"); @@ -3897,6 +3998,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname) ERROR("Could not destroy existing container %s", c->name); return false; } + return true; } @@ -3927,20 +4029,24 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options command.program = (char*)program; command.argv = (char**)argv; + r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid); if (r < 0) { ERROR("ups"); return r; } + return lxc_wait_for_pid_status(pid); } static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[]) { int ret; + current_config = c ? c->lxc_conf : NULL; ret = do_lxcapi_attach_run_wait(c, options, program, argv); current_config = NULL; + return ret; } @@ -3951,11 +4057,14 @@ static int get_next_index(const char *lxcpath, char *cname) int i = 0, ret; fname = alloca(strlen(lxcpath) + 20); + while (1) { sprintf(fname, "%s/snap%d", lxcpath, i); + ret = stat(fname, &sb); if (ret != 0) return i; + i++; } } @@ -3963,6 +4072,7 @@ static int get_next_index(const char *lxcpath, char *cname) static bool get_snappath_dir(struct lxc_container *c, char *snappath) { int ret; + /* * If the old style snapshot path exists, use it * /var/lib/lxc -> /var/lib/lxcsnaps @@ -3970,10 +4080,12 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath) ret = snprintf(snappath, MAXPATHLEN, "%ssnaps", c->config_path); if (ret < 0 || ret >= MAXPATHLEN) return false; + if (dir_exists(snappath)) { ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name); if (ret < 0 || ret >= MAXPATHLEN) return false; + return true; } @@ -3984,6 +4096,7 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath) ret = snprintf(snappath, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name); if (ret < 0 || ret >= MAXPATHLEN) return false; + return true; } @@ -4029,6 +4142,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) ERROR("and keep the original container pristine."); flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT; } + c2 = do_lxcapi_clone(c, newname, snappath, flags, NULL, NULL, 0, NULL); if (!c2) { ERROR("clone of %s:%s failed", c->config_path, c->name); @@ -4055,11 +4169,13 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) ERROR("Failed to open %s", dfnam); return -1; } + if (fprintf(f, "%s", buffer) < 0) { SYSERROR("Writing timestamp"); fclose(f); return -1; } + ret = fclose(f); if (ret != 0) { SYSERROR("Writing timestamp"); @@ -4070,6 +4186,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) /* $p / $name / comment \0 */ int len = strlen(snappath) + strlen(newname) + 10; char *path = alloca(len); + sprintf(path, "%s/%s/comment", snappath, newname); return copy_file(commentfile, path) < 0 ? -1 : i; } @@ -4100,6 +4217,7 @@ static char *get_snapcomment_path(char* snappath, char *name) s = NULL; } } + return s; } @@ -4112,9 +4230,11 @@ static char *get_timestamp(char* snappath, char *name) ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name); if (ret < 0 || ret >= MAXPATHLEN) return NULL; + fin = fopen(path, "r"); if (!fin) return NULL; + (void) fseek(fin, 0, SEEK_END); len = ftell(fin); (void) fseek(fin, 0, SEEK_SET); @@ -4129,6 +4249,7 @@ static char *get_timestamp(char* snappath, char *name) } } } + fclose(fin); return s; } @@ -4148,9 +4269,10 @@ static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot ERROR("path name too long"); return -1; } + dir = opendir(snappath); if (!dir) { - INFO("failed to open %s - assuming no snapshots", snappath); + INFO("Failed to open %s - assuming no snapshots", snappath); return 0; } @@ -4166,30 +4288,35 @@ static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot ERROR("pathname too long"); goto out_free; } + if (!file_exists(path2)) continue; + nsnaps = realloc(snaps, (count + 1)*sizeof(*snaps)); if (!nsnaps) { SYSERROR("Out of memory"); goto out_free; } + snaps = nsnaps; snaps[count].free = lxcsnap_free; snaps[count].name = strdup(direntp->d_name); if (!snaps[count].name) goto out_free; + snaps[count].lxcpath = strdup(snappath); if (!snaps[count].lxcpath) { free(snaps[count].name); goto out_free; } + snaps[count].comment_pathname = get_snapcomment_path(snappath, direntp->d_name); snaps[count].timestamp = get_timestamp(snappath, direntp->d_name); count++; } if (closedir(dir)) - WARN("failed to close directory"); + WARN("Failed to close directory"); *ret_snaps = snaps; return count; @@ -4197,12 +4324,16 @@ static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot out_free: if (snaps) { int i; + for (i=0; itype, "overlay") || !strcmp(bdev->type, "overlayfs")) flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE; + rest = lxcapi_clone(snap, newname, c->config_path, flags, bdev->type, NULL, 0, NULL); storage_put(bdev); if (rest && lxcapi_is_defined(rest)) b = true; + if (rest) lxc_container_put(rest); @@ -4299,11 +4434,13 @@ static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath) ERROR("Could not destroy snapshot %s", snapname); goto err; } + bret = true; err: if (snap) lxc_container_put(snap); + return bret; } @@ -4318,11 +4455,14 @@ static bool remove_all_snapshots(const char *path) SYSERROR("opendir on snapshot path %s", path); return false; } + while ((direntp = readdir(dir))) { if (!strcmp(direntp->d_name, ".")) continue; + if (!strcmp(direntp->d_name, "..")) continue; + if (!do_snapshot_destroy(direntp->d_name, path)) { bret = false; continue; @@ -4507,6 +4647,7 @@ static bool do_lxcapi_add_device_node(struct lxc_container *c, const char *src_p ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__); return false; } + return add_remove_device_node(c, src_path, dest_path, true); } @@ -4518,6 +4659,7 @@ static bool do_lxcapi_remove_device_node(struct lxc_container *c, const char *sr ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__); return false; } + return add_remove_device_node(c, src_path, dest_path, false); } @@ -4621,6 +4763,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, ERROR("Network device \"%s\" not found", ifname); else ERROR("Failed to remove network device \"%s\"", ifname); + _exit(EXIT_FAILURE); } @@ -4654,11 +4797,10 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd, addr = (void *)opts + sizeof(*opts); end = (void *)opts + size; - for (; addr < end; addr++) { - if (*addr) { + + for (; addr < end; addr++) + if (*addr) return -E2BIG; - } - } } /* If the caller has a smaller struct, let's zero out the end for them @@ -4680,6 +4822,7 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd, ERROR("container is not running"); goto on_error; } + ret = !__criu_pre_dump(c, valid_opts); break; case MIGRATE_DUMP: @@ -4687,6 +4830,7 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd, ERROR("container is not running"); goto on_error; } + ret = !__criu_dump(c, valid_opts); break; case MIGRATE_RESTORE: @@ -4694,6 +4838,7 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd, ERROR("container is already running"); goto on_error; } + ret = !__criu_restore(c, valid_opts); break; case MIGRATE_FEATURE_CHECK: @@ -4772,6 +4917,7 @@ static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv); free((void*)argv); + out: current_config = NULL; return ret; @@ -4796,7 +4942,6 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->config_path = strdup(configpath); else c->config_path = strdup(lxc_global_config_value("lxc.lxcpath")); - if (!c->config_path) { fprintf(stderr, "Failed to allocate memory for %s\n", name); goto err; @@ -4840,6 +4985,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath container_destroy(c, NULL); lxcapi_clear_config(c); } + c->daemonize = true; c->pidfile = NULL; @@ -4914,6 +5060,7 @@ int lxc_get_wait_states(const char **states) if (states) for (i=0; id_name)) continue; - if (names) { + if (names) if (!add_to_array(names, direntp->d_name, cfound)) goto free_bad; - } + cfound++; if (!cret) { @@ -4965,17 +5113,22 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta if (!c) { INFO("Container %s:%s has a config but could not be loaded", lxcpath, direntp->d_name); + if (names) if(!remove_from_array(names, direntp->d_name, cfound--)) goto free_bad; + continue; } + if (!do_lxcapi_is_defined(c)) { INFO("Container %s:%s has a config but is not defined", lxcpath, direntp->d_name); + if (names) if(!remove_from_array(names, direntp->d_name, cfound--)) goto free_bad; + lxc_container_put(c); continue; } @@ -4984,6 +5137,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta lxc_container_put(c); goto free_bad; } + nfound++; } @@ -4996,11 +5150,13 @@ free_bad: free((*names)[i]); free(*names); } + if (cret && *cret) { for (i=0; i