lxccontainer.c revision f5dd1d532a76a1b57cf341db821eae85ea1118c5
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher * Copyright © 2012 Serge Hallyn <serge.hallyn@ubuntu.com>.
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher * Copyright © 2012 Canonical Ltd.
c252d148fa8ab50aaaa8bbae7beb4d208025171dNikolai Kondrashov * This library is free software; you can redistribute it and/or
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher * modify it under the terms of the GNU Lesser General Public
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher * License as published by the Free Software Foundation; either
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher * version 2.1 of the License, or (at your option) any later version.
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov * This library is distributed in the hope that it will be useful,
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov * but WITHOUT ANY WARRANTY; without even the implied warranty of
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov * Lesser General Public License for more details.
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher * You should have received a copy of the GNU Lesser General Public
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher * License along with this library; if not, write to the Free Software
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher#include <../include/ifaddrs.h>
d921c1eba437662437847279f251a0a5d8f70127Maxim#include <../include/getline.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool file_exists(char *f)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void remove_trailing_slashes(char *p)
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagher while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek p[l] = '\0';
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek * A few functions to help detect when a container creation failed.
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek * If a container creation was killed partway through, then trying
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek * to actually start that container could harm the host. We detect
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek * this by creating a 'partial' file under the container directory,
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek * and keeping an advisory lock. When container creation completes,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * we remove that file. When we load or try to start a container, if
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * we find that file, without a flock, we remove the container.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint ongoing_create(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int len = strlen(c->config_path) + strlen(c->name) + 10;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
558998ce664055a75595371118f818084d8f2b23Jan Cholasta // give benefit of the doubt
f1828234a850dd28465425248a83a993f262918fPavel Březina if (fcntl(fd, F_GETLK, &lk) == 0 && lk.l_pid != -1) {
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guay // create is still ongoing
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // create completed but partial is still there.
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina // $lxcpath + '/' + $name + '/partial' + \0
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina int len = strlen(c->config_path) + strlen(c->name) + 10;
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
19d3aba12c70528708be9440aca66038a291f29eYassir Elley if ((fd=open(path, O_RDWR | O_CREAT | O_EXCL, 0755)) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher SYSERROR("Error locking partial file %s", path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid remove_partial(struct lxc_container *c, int fd)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // $lxcpath + '/' + $name + '/partial' + \0
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int len = strlen(c->config_path) + strlen(c->name) + 10;
fe60346714a73ac3987f786731389320633dd245Pavel Březina ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina SYSERROR("Error unlink partial file %s", path);
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina * 1. container_mem_lock(c) protects the struct lxc_container from multiple threads.
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina * 2. container_disk_lock(c) protects the on-disk container data - in particular the
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina * container configuration file.
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * The container_disk_lock also takes the container_mem_lock.
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * 3. thread_mutex protects process data (ex: fd table) from multiple threads.
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * NOTHING mutexes two independent programs with their own struct
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * lxc_container for the same c->name, between API calls. For instance,
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * c->config_read(); c->start(); Between those calls, data on disk
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * could change (which shouldn't bother the caller unless for instance
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek * the rootfs get moved). c->config_read(); update; c->config_write();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * Two such updaters could race. The callers should therefore check their
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek * results. Trying to prevent that would necessarily expose us to deadlocks
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek * due to hung callers. So I prefer to keep the locks only within our own
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh * functions, not across functions.
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose * If you're going to clone while holding a lxccontainer, increment
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha * c->numthreads (under privlock) before forking. When deleting,
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha * decrement numthreads under privlock, then if it hits 0 you can delete.
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek * Do not ever use a lxccontainer whose numthreads you did not bump.
e046ae03d0f55b1c8b0ec2fa6139bf86a3449adfPavel Březinastatic void lxc_container_free(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * Consider the following case:
f232789430a080384188d5da89b19d874cf17513Jakub Hrozekfreer | racing get()er
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek==================================================================
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherlxc_container_put() | lxc_container_get()
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher\ lxclock(c->privlock) | c->numthreads < 1? (no)
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek\ c->numthreads = 0 | \ lxclock(c->privlock) -> waits
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozek\ lxcunlock() | \
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek\ lxc_container_free() | \ lxclock() returns
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek | \ c->numthreads < 1 -> return 0
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher\ \ (free stuff) |
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher\ \ sem_destroy(privlock) |
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * When the get()er checks numthreads the first time, one of the following
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * 1. freer has set numthreads = 0. get() returns 0
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * 2. freer is between lxclock and setting numthreads to 0. get()er will
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * sem_wait on privlock, get lxclock after freer() drops it, then see
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * numthreads is 0 and exit without touching lxclock again..
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * 3. freer has not yet locked privlock. If get()er runs first, then put()er
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik * will see --numthreads = 1 and not call lxc_container_free().
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagherint lxc_container_get(struct lxc_container *c)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek // if someone else has already started freeing the container, don't
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // try to take the lock, which may be invalid
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // bail without trying to unlock, bc the privlock is now probably
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik // in freed memory
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint lxc_container_put(struct lxc_container *c)
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bosestatic bool lxcapi_is_defined(struct lxc_container *c)
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke bool ret = false;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return false;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikstatic const char *lxcapi_state(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher s = lxc_getstate(c->name, c->config_path);
15b266d9f14dad26da8678a79019749d0f69532eStephen Gallagherstatic bool is_stopped(struct lxc_container *c)
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher s = lxc_getstate(c->name, c->config_path);
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny return (s == STOPPED);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashovstatic bool lxcapi_is_running(struct lxc_container *c)
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov const char *s;
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose return false;
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek return false;
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozekstatic bool lxcapi_freeze(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = lxc_freeze(c->name, c->config_path);
17f08cbd0f909181536b93d6c12c7cd69995f09eSumit Bose return false;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashovstatic bool lxcapi_unfreeze(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = lxc_unfreeze(c->name, c->config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ttyfd = lxc_console_getfd(c, ttynum, masterfd);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic pid_t lxcapi_init_pid(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return lxc_cmd_get_init_pid(c->name, c->config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool load_config_locked(struct lxc_container *c, const char *fname)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (c->lxc_conf && !lxc_config_read(fname, c->lxc_conf))
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose return false;
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozekstatic bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
769347ad4d35d43488eb98f980143495b0db415dStef Walter return false;
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina * If we're reading something other than the container's config,
769347ad4d35d43488eb98f980143495b0db415dStef Walter * we only need to lock the in-memory container. If loading the
769347ad4d35d43488eb98f980143495b0db415dStef Walter * container's config file, take the disk lock.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void lxcapi_want_daemonize(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = lxc_wait(c->name, state, timeout, c->config_path);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool wait_on_daemonized_start(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we'll probably want to make this timeout configurable? */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * our child is going to fork again, then exit. reap the
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose DEBUG("failed waiting for first dual-fork child");
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher return lxcapi_wait(c, "RUNNING", timeout);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * I can't decide if it'd be more convenient for callers if we accept '...',
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * or a null-terminated array (i.e. execl vs execv)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny /* container exists */
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek return false;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* container has been setup */
701f13b5c8e27bcbfc79e77ce7c76d9f768a448cLukas Slebodnik ERROR("Error checking for incomplete creation");
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina return false;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("Error: %s creation was not completed", c->name);
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce return false;
7452f1b637276ce582b120f8f5482ae7f3b6bd47Jakub Hrozek ERROR("Error: creation of %s is ongoing", c->name);
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorce return false;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* is this app meant to be run through lxcinit, as in lxc-execute? */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina return false;
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher ret = lxc_execute(c->name, argv, 1, conf, c->config_path);
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce return ret == 0 ? true : false;
590582be38cdbfde387fcc57df92903d48c5a083Jakub Hrozek * say, I'm not sure - what locks do we want here? Any?
8a1fd0633e85221da1fb63451516a70d66c0af31Pavel Březina * Is liblxc's locking enough here to protect the on disk
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * container? We don't want to exclude things like lxc_info
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * while container is running...
f9961e5f82e0ef474d6492371bfdf9e74e208a99Pavel Březina /* second fork to be reparented by init */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek /* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */
213ce2a78b1abe3921d8dc13c949a28130d00aecJan Zeleny ret = lxc_start(c->name, argv, conf, c->config_path);
a679f0167b646cffdae86546ed77e105576991b0Pavel Březina return (ret == 0 ? true : false);
347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5Jan Cholasta * note there MUST be an ending NULL
50fe3d79ab12b795a687b676761bef265701626aStephen Gallagherstatic bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose bool bret = false;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose /* container exists */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose return false;
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek /* pass NULL if no arguments were supplied */
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek bret = lxcapi_start(c, useinit, *inargs ? inargs : NULL);
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březinastatic bool lxcapi_stop(struct lxc_container *c)
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnik return false;
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek return ret == 0;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher * create the standard expected container dir
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagherstatic bool create_container_dir(struct lxc_container *c)
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt len = strlen(c->config_path) + strlen(c->name) + 2;
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher ret = snprintf(s, len, "%s/%s", c->config_path, c->name);
5a05b6127064c74349f1edae32e5e13032c386feLukas Slebodnik return false;
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik SYSERROR("failed to create container path for %s\n", c->name);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnikstatic const char *lxcapi_get_config_path(struct lxc_container *c);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnikstatic bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik * do_bdev_create: thin wrapper around bdev_create(). Like bdev_create(),
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik * it returns a mounted bdev on success, NULL on error.
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnikstatic struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik const char *lxcpath = lxcapi_get_config_path(c);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik len = strlen(c->name) + strlen(lxcpath) + 9;
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik bdev = bdev_create(dest, type, c->name, specs);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik ERROR("Failed to create backing store type %s\n", type);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher lxcapi_set_config_item(c, "lxc.rootfs", bdev->src);
c2352a73f52f600d95966ebe0b0819649ba923faStephen Gallagher * Given the '-t' template option to lxc-create, figure out what to
4c1bf6607060cea867fccf667063c028dfd51e96Stephen Gallagher * do. If the template is a full executable path, use that. If it
1f1e6cbc59868f06dee3ab4b3df660fcb77ce1c8Jakub Hrozek * is something like 'sshd', then return $templatepath/lxc-sshd. If
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * no template was passed in, return NULL (this is ok).
2ef62c64e7f07c8aced3f72850008ecb72860162Sumit Bose * On error return (char *) -1.
817b1bcafff27cc67630dd0cbd36df708c05fcccStephen Gallagherchar *get_template_path(const char *t)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (t[0] == '/' && access(t, X_OK) == 0) {
42c28b9424b6ef8a0021b124773e171dd5defaddJakub Hrozek return (char *) -1;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter return (char *) -1;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher return (char *) -1;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek return (char *) -1;
022c6b90bb37851c0e8704c0e5388ebc113c6470Lukas Slebodnikstatic bool create_run_template(struct lxc_container *c, char *tpath, bool quiet,
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek char *const argv[])
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek return true;
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek SYSERROR("failed to fork task for container creation template\n");
5a05b6127064c74349f1edae32e5e13032c386feLukas Slebodnik return false;
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek * for an overlayfs create, what the user wants is the template to fill
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek * in what will become the readonly lower layer. So don't mount for
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek * the template
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek bdev = bdev_init(src, c->lxc_conf->rootfs.mount, NULL);
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina * create our new array, pre-pend the template name and
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina nargs += 4; // template, path, rootfs and name args
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2;
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name);
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt len = strlen("--name=") + strlen(c->name) + 1;
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt ret = snprintf(namearg, len, "--name=%s", c->name);
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik len = strlen("--rootfs=") + 1 + strlen(bdev->dest);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek ret = snprintf(rootfsarg, len, "--rootfs=%s", bdev->dest);
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik /* add passed-in args */
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose /* add trailing NULL */
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose newargv = realloc(newargv, nargs * sizeof(*newargv));
0d01e4f6cc21d8ca0e4fafe59c7cbfa1459fa47eSumit Bose /* execute */
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik SYSERROR("failed to execute template %s", tpath);
a9c287bda3fc2a1e12cef2135ade96945f11ad01Sumit Bose ERROR("container creation template for %s failed\n", c->name);
a9c287bda3fc2a1e12cef2135ade96945f11ad01Sumit Bose return false;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose return true;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bosebool prepend_lxc_header(char *path, const char *t, char *const argv[])
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose bool have_tpath = false;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose return false;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose return false;
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose return false;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina return false;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina return false;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina return false;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (fclose(f) < 0) {
706d211b5d6e32d11a1c6ffc8065ca8be4d4d8c5Pavel Březina return false;
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina return false;
769347ad4d35d43488eb98f980143495b0db415dStef Walter return false;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return false;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter fprintf(f, "# Template used to create this container: %s\n", t);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter fprintf(f, "# Parameters passed to the template:");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter fprintf(f, "# Template script checksum (SHA-1): ");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter for (i=0; i<SHA_DIGEST_LENGTH; i++)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (fwrite(contents, 1, flen, f) != flen) {
574a1c20f114851071ae74112b34488c3d1aeeb3Ondrej Kos return false;
769347ad4d35d43488eb98f980143495b0db415dStef Walter if (fclose(f) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher SYSERROR("Closing config file after write");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lxcapi_destroy(struct lxc_container *c);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * lxcapi_create:
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * create a container with the given parameters.
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher * @c: container to be created. It has the lxcpath, name, and a starting
8c3a4809b3420657289b42f028a1c9019b112991Stephen Gallagher * configuration already set
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce * @t: the template to execute to instantiate the root filesystem and
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * adjust the configuration.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * @bdevtype: backing store type to use. If NULL, dir will be used.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * @specs: additional parameters for the backing store, i.e. LVM vg to
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik * @argv: the arguments to pass to the template, terminated by NULL. If no
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher * arguments, you can just pass NULL.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lxcapi_create(struct lxc_container *c, const char *t,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *bdevtype, struct bdev_specs *specs, int flags,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char *const argv[])
bdc2aced1185c4ee36921fa01b8dc01789a63900Jakub Hrozek return false;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina ERROR("failed to save starting configuration for %s\n", c->name);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina /* container is already created if we have a config and rootfs.path is accessible */
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0)
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek /* Mark that this container is being created */
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek /* no need to get disk lock bc we have the partial locked */
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek * Create the backing store
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik * Note we can't do this in the same task as we use to execute the
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek * template because of the way zfs works.
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek * After you 'zfs create', zfs mounts the fs only in the initial
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta * namespace.
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta SYSERROR("failed to fork task for container creation template\n");
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose if (!(bdev = do_bdev_create(c, bdevtype, specs))) {
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose ERROR("Error creating backing store type %s for %s",
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose /* save config file again to store the new rootfs location */
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose ERROR("failed to save starting configuration for %s\n", c->name);
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose // parent task won't see bdev in config so we delete it
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek /* reload config to get the rootfs */
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek if (!create_run_template(c, tpath, !!(flags & LXC_CREATE_QUIET), argv))
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek // now clear out the lxc_conf we have, reload from the created
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek // container
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek if (!prepend_lxc_header(c->configfile, tpath, argv)) {
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek ERROR("Error prepending header to configuration file");
769347ad4d35d43488eb98f980143495b0db415dStef Walterstatic bool lxcapi_reboot(struct lxc_container *c)
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return false;
2db6afe70eee2bbc22aa657a6b6609a9f3eb5d4cSimo Sorce return true;
52e0894fd65bff4715c88330eb62b28e1635228fStephen Gallagherstatic bool lxcapi_shutdown(struct lxc_container *c, int timeout)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher retv = c->wait(c, "STOPPED", 0); // 0 means don't wait
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidekstatic bool lxcapi_createl(struct lxc_container *c, const char *t,
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek const char *bdevtype, struct bdev_specs *specs, int flags, ...)
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return false;
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek * since we're going to wait for create to finish, I don't think we
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek * need to get a copy of the arguments.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bret = c->create(c, t, bdevtype, specs, flags, args);
a9eff330a7fbd231e8cc28a6828a1e5014ddb0d2Michal Zidekstatic bool lxcapi_clear_config_item(struct lxc_container *c, const char *key)
2c0a971010596c122d7a0c0d76c8eb85f16f6d06Jakub Hrozek return false;
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return false;
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt ret = lxc_clear_config_item(c->lxc_conf, key);
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek return ret == 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherchar** lxcapi_get_ips(struct lxc_container *c, char* interface, char* family, int scope)
2c0a971010596c122d7a0c0d76c8eb85f16f6d06Jakub Hrozek struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char addressOutputBuffer[INET6_ADDRSTRLEN];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int old_netns = -1, new_netns = -1, ret = 0;
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* Save reference to old netns */
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik old_netns = open("/proc/self/ns/net", O_RDONLY);
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* Switch to new netns */
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt ret = snprintf(new_netns_path, MAXPATHLEN, "/proc/%d/ns/net", c->init_pid(c));
f1828234a850dd28465425248a83a993f262918fPavel Březina SYSERROR("failed to open %s", new_netns_path);
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* Grab the list of interfaces */
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek /* Iterate through the interfaces */
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek if(tempIfAddr->ifa_addr->sa_family == AF_INET) {
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek tempAddrPtr = &((struct sockaddr_in *)tempIfAddr->ifa_addr)->sin_addr;
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek if (((struct sockaddr_in6 *)tempIfAddr->ifa_addr)->sin6_scope_id != scope)
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina tempAddrPtr = &((struct sockaddr_in6 *)tempIfAddr->ifa_addr)->sin6_addr;
558998ce664055a75595371118f818084d8f2b23Jan Cholasta if (interface && strcmp(interface, tempIfAddr->ifa_name))
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta else if (!interface && strcmp("lo", tempIfAddr->ifa_name) == 0)
558998ce664055a75595371118f818084d8f2b23Jan Cholasta address = (char *)inet_ntop(tempIfAddr->ifa_addr->sa_family,
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta temp = realloc(addresses, count * sizeof(*addresses));
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek /* Switch back to original netns */
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose if (old_netns >= 0 && setns(old_netns, CLONE_NEWNET))
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik /* Append NULL to the array */
221619d8e8d7cf269c55482e5f466f6511ed35adLukas Slebodnik temp = realloc(addresses, count * sizeof(*addresses));
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorcestatic int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen)
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce if (!c || !c->lxc_conf)
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce ret = lxc_get_config_item(c->lxc_conf, key, retv, inlen);
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorcestatic int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen)
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik * Support 'lxc.network.<idx>', i.e. 'lxc.network.0'
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik * This is an intelligent result to show which keys are valid given
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik * the type of nic it is
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik if (!c || !c->lxc_conf)
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce ret = lxc_list_nicconfigs(c->lxc_conf, key, retv, inlen);
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorcestatic bool lxcapi_save_config(struct lxc_container *c, const char *alt_file)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return false; // should we write to stdout if no file is specified?
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // If we haven't yet loaded a config, load the stock config
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!c->load_config(c, LXC_DEFAULT_CONFIG)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("Error loading default configuration file %s while saving %s\n", LXC_DEFAULT_CONFIG, c->name);
16c351625346b3193e1762027e5215ab76042127Sumit Bose return false;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek return false;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek * If we're writing to the container's config file, take the
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek * disk lock. Otherwise just take the memlock to protect the
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik * struct lxc_container while we're traversing it.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool mod_rdep(struct lxc_container *c, bool inc)
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return false;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("Error writing new snapshots value");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (fclose(f) != 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher SYSERROR("Error writing to or closing snapshots file");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void strip_newline(char *p)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void mod_all_rdeps(struct lxc_container *c, bool inc)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char *lxcpath = NULL, *lxcname = NULL, path[MAXPATHLEN];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (getline(&lxcpath, &pathlen, f) != -1) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (getline(&lxcname, &namelen, f) == -1) {
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik if ((p = lxc_container_new(lxcname, lxcpath)) == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("Unable to find dependent container %s:%s",
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher ERROR("Failed to increase numsnapshots for %s:%s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool has_snapshots(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher// do we want the api to support --force, or leave that to the caller?
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lxcapi_destroy(struct lxc_container *c)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool ret = false;
35872dc24058c5e8028cb4082fd405a27835dcd1Jakub Hrozek return false;
fcb8e3f1f49bb34c409d8dbd75889eb72be05517Jakub Hrozek return false;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // we should queue some sort of error - in c->error_string?
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("container %s is not stopped", c->name);
d12c95d840ed5de7f34e21002943c48e711a33f4Lukas Slebodnik ERROR("container %s has dependent snapshots", c->name);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (c->lxc_conf && c->lxc_conf->rootfs.path && c->lxc_conf->rootfs.mount)
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher r = bdev_init(c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ERROR("Error destroying rootfs for %s", c->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *path = alloca(strlen(p1) + strlen(c->name) + 2);
0cf0e2d758d09e9b314ba72ce6638df10b258462Pavel Březina ERROR("Error destroying container directory for %s", c->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v)
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return false;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher return (0 == config->cb(key, v, c->lxc_conf));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool b = false;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter return false;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walterstatic char *lxcapi_config_file_name(struct lxc_container *c)
fe60346714a73ac3987f786731389320633dd245Pavel Březina if (!c || !c->configfile)
fe60346714a73ac3987f786731389320633dd245Pavel Březinastatic const char *lxcapi_get_config_path(struct lxc_container *c)
fe60346714a73ac3987f786731389320633dd245Pavel Březina if (!c || !c->config_path)
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return (const char *)(c->config_path);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * not for export
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * Just recalculate the c->configfile based on the
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * c->config_path, which must be set.
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek * The lxc_container must be locked or not yet public.
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozekstatic bool set_config_filename(struct lxc_container *c)
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek return false;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher /* $lxc_path + "/" + c->name + "/" + "config" + '\0' */
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher len = strlen(c->config_path) + strlen(c->name) + strlen("config") + 3;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher ret = snprintf(newpath, len, "%s/%s/config", c->config_path, c->name);
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher fprintf(stderr, "Error printing out config file name\n");
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose return false;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose return true;
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bosestatic bool lxcapi_set_config_path(struct lxc_container *c, const char *path)
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose bool b = false;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("Out of memory setting new lxc path");
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek /* Since we've changed the config path, we have to change the
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek * config file name too */
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ERROR("Out of memory setting new config filename");
f232789430a080384188d5da89b19d874cf17513Jakub Hrozekstatic bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value)
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik return false;
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek return false;
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter return false;
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter ret = lxc_cgroup_set(c->name, subsys, value, c->config_path);
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter return ret == 0;
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walterstatic int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!c || !c->lxc_conf)
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek ret = lxc_cgroup_get(c->name, subsys, retv, inlen, c->config_path);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozekconst char *lxc_get_version(void)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek SYSERROR("Error opening original file %s", old);
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek out = open(new, O_CREAT | O_EXCL | O_WRONLY, 0644);
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh SYSERROR("Error: write to new file %s was interrupted", new);
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek // we set mode, but not owner/group
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozekstatic int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek for (i=0; i<NUM_LXC_HOOKS; i++) {
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek lxc_list_for_each(it, &c->lxc_conf->hooks[i]) {
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek if (!fname) // relative path - we don't support, but maybe we should
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek // copy the script, and change the entry in confile
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh unsigned int seed;
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jhastatic void network_new_hwaddrs(struct lxc_container *c)
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jhastatic int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s",
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik ERROR("error printing new path for %s", oldpath);
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik ERROR("error: fstab file %s exists", newpath);
04868f1573f4b26ef34610b6d7069172f93bd8abJakub Hrozek ERROR("error: copying %s to %s", oldpath, newpath);
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnikstatic void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek ret = snprintf(path0, MAXPATHLEN, "%s/%s/lxc_rdepends", c0->config_path,
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik ret = snprintf(path1, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
e046ae03d0f55b1c8b0ec2fa6139bf86a3449adfPavel Březinastatic bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
e046ae03d0f55b1c8b0ec2fa6139bf86a3449adfPavel Březina ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose return false;
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose return false;
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose // if anything goes wrong, just return an error
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose if (fprintf(f, "%s\n%s\n", c0->config_path, c0->name) < 0)
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose if (fclose(f) != 0)
f69f3581658351003a6d9245045e41d0efb85022Sumit Bosestatic int copy_storage(struct lxc_container *c0, struct lxc_container *c,
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose const char *newtype, int flags, const char *bdevdata, unsigned long newsize)
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose bdev = bdev_copy(c0->lxc_conf->rootfs.path, c0->name, c->name,
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose c0->config_path, c->config_path, newtype, !!(flags & LXC_CLONE_SNAPSHOT),
022c6b90bb37851c0e8704c0e5388ebc113c6470Lukas Slebodnik c->lxc_conf->rootfs.path = strdup(bdev->src);
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose ERROR("Out of memory while setting storage path");
cebdc563a094d305b91da5b5af4d95d8e3a1bf27Pavel Reichl WARN("Error adding reverse dependency from %s to %s",
cebdc563a094d305b91da5b5af4d95d8e3a1bf27Pavel Reichlstatic int clone_update_rootfs(struct lxc_container *c0,
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek /* update hostname in rootfs */
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek /* we're going to mount, so run in a clean namespace to simplify cleanup */
0352c371e743d8dae996123f658b5d32c677614eYassir Elley bdev = bdev_init(c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
0352c371e743d8dae996123f658b5d32c677614eYassir Elley if (!lxc_list_empty(&conf->hooks[LXCHOOK_CLONE])) {
0352c371e743d8dae996123f658b5d32c677614eYassir Elley /* Start of environment variable setup for hooks */
0352c371e743d8dae996123f658b5d32c677614eYassir Elley SYSERROR("failed to set environment variable for source container name");
0352c371e743d8dae996123f658b5d32c677614eYassir Elley SYSERROR("failed to set environment variable for container name");
0352c371e743d8dae996123f658b5d32c677614eYassir Elley if (setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) {
0352c371e743d8dae996123f658b5d32c677614eYassir Elley SYSERROR("failed to set environment variable for config path");
0352c371e743d8dae996123f658b5d32c677614eYassir Elley if (setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) {
0352c371e743d8dae996123f658b5d32c677614eYassir Elley SYSERROR("failed to set environment variable for rootfs mount");
0352c371e743d8dae996123f658b5d32c677614eYassir Elley if (setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) {
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek SYSERROR("failed to set environment variable for rootfs mount");
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek if (run_lxc_hooks(c->name, "clone", conf, c->get_config_path(c), hookargs)) {
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek ERROR("Error executing clone hook for %s", c->name);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek SYSERROR("unable to open %s: ignoring\n", path);
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek * We want to support:
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozeksudo lxc-clone -o o1 -n n1 -s -L|-fssize fssize -v|--vgname vgname \
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek -p|--lvprefix lvprefix -t|--fstype fstype -B backingstore
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek-s [ implies overlayfs]
5c36e1f8901a4baff2b51d81d87c2b577f84fef6Lukas Slebodnik-s -B overlayfs
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozekonly rootfs gets converted (copied/snapshotted) on clone.
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek SYSERROR("creating container path %s\n", path);
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozekstruct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname,
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek const char *bdevtype, const char *bdevdata, unsigned long newsize,
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek const char *n, *l;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek if (!c || !c->is_defined(c))
3fe339bcba0e211cc666bb3afe34e5c8fce85f4fJakub Hrozek ERROR("error: Original container (%s) is running", c->name);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek // Make sure the container doesn't yet exist.
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", l, n);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek SYSERROR("clone: failed making config pathname");
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina ERROR("Error creating container dir for %s", newpath);
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina // copy the configuration, tweak it as needed,
a524965fbe0551f1b3a68f1e5c7a5689a652998fSumit Bose ERROR("clone: failed to create new container (%s %s)", n, l);
a524965fbe0551f1b3a68f1e5c7a5689a652998fSumit Bose // update utsname
a524965fbe0551f1b3a68f1e5c7a5689a652998fSumit Bose if (!set_config_item_locked(c2, "lxc.utsname", newname)) {
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina // copy hooks if requested
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina // update macaddrs
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose ret = copy_storage(c, c2, bdevtype, flags, bdevdata, newsize);
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose // We've now successfully created c2's storage, so clear it out if we
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose // fail after this
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose if (clone_update_rootfs(c, c2, flags, hookargs) < 0)
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose // TODO: update c's lxc.snapshot = count
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozekstatic int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process)
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek return lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozekstatic int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid);
44703b84feaafa4f0a4f8df11c5a503dcf48616eJakub Hrozek if (r < 0) {
4d9db278db1197ae84fecb8f269e2de368a6be2aLukas Slebodnikint get_next_index(const char *lxcpath, char *cname)
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březinastatic int lxcapi_snapshot(struct lxc_container *c, char *commentfile)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina ERROR("Failed to create snapshot directory %s", snappath);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR | LXC_CLONE_KEEPNAME;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek c2 = c->clone(c, newname, snappath, flags, NULL, NULL, 0, NULL);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek ERROR("clone of %s:%s failed\n", c->config_path, c->name);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek // Now write down the creation time
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek strftime(buffer, 25, "%Y:%m:%d %H:%M:%S", tm_info);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek char *dfnam = alloca(strlen(snappath) + strlen(newname) + 5);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (fclose(f) != 0) {
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher // $p / $name / comment \0
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher int len = strlen(snappath) + strlen(newname) + 10;
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt sprintf(path, "%s/%s/comment", snappath, newname);
6e8238868a4d17030bb4f01494961d0354a953bfJakub Hrozek return copy_file(commentfile, path) < 0 ? -1 : i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void lxcsnap_free(struct lxc_snapshot *s)
1171986bdc3011555c5b62a9d9ee9f7481f48cdcSimo Sorcestatic char *get_snapcomment_path(char* snappath, char *name)
5f216c753dbd2f2b25a011c5f705ee4f8ad924e6Simo Sorce // $snappath/$name/comment
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt int ret, len = strlen(snappath) + strlen(name) + 10;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = snprintf(s, len, "%s/%s/comment", snappath, name);
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzerstatic char *get_timestamp(char* snappath, char *name)
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher char snappath[MAXPATHLEN], path2[MAXPATHLEN];
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek // snappath is ${lxcpath}snaps/${lxcname}/
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek dirlen = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
42870c7ac3608ffc58f2c9524ad3dfc1401bc1aaPavel Březina INFO("failed to open %s - assuming no snapshots", snappath);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek ret = snprintf(path2, MAXPATHLEN, "%s/%s/config", snappath, direntp->d_name);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek nsnaps = realloc(snaps, (count + 1)*sizeof(*snaps));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher snaps[count].comment_pathname = get_snapcomment_path(snappath, direntp->d_name);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher snaps[count].timestamp = get_timestamp(snappath, direntp->d_name);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i=0; i<count; i++)
755aee449c6311518200c2f11c1aae329a19b038Pavel Březinastatic bool lxcapi_snapshot_restore(struct lxc_container *c, char *snapname, char *newname)
796463906a54e259bd5b582ce84af4297a58eafcStephen Gallagher bool b = false;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher bdev = bdev_init(c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
41be4e3976cf66823ad2c6880671ac7fbafdc640Pavel Březina ERROR("Failed to find original backing store type");
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return false;
cc1c033c34b5f816b633d27a21aefbf811a7cf72Lukas Slebodnik ERROR("Could not destroy existing container %s", newname);
7fc27c7a3ccbb6aecb8cf4a4a5f91962028cb897Lukas Slebodnik return false;
cc1c033c34b5f816b633d27a21aefbf811a7cf72Lukas Slebodnik ret = snprintf(clonelxcpath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher // how should we lock this?
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher snap = lxc_container_new(snapname, clonelxcpath);
c407643004a02566e35a864ba0d8b0c0f88d9d67Pavel Březina ERROR("Could not open snapshot %s", snapname);
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher rest = lxcapi_clone(snap, newname, c->config_path, 0, bdev->type, NULL, 0, NULL);
60cab26b12df9a2153823972cde0c38ca86e01b9Yassir Elleystatic int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...)
b1c4a998f8e217b4ba4cd632f5069d479211c22dYassir Elley const char **argv;
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher argv = lxc_va_arg_list_to_argv_const(ap, 1);
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek ret = lxcapi_attach_run_wait(c, options, program, (const char * const *)argv);
6261893e00bd14fdd192ffc9a1379cb9c647d326Lukas Slebodnikstruct lxc_container *lxc_container_new(const char *name, const char *configpath)
6261893e00bd14fdd192ffc9a1379cb9c647d326Lukas Slebodnik c = malloc(sizeof(*c));
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher fprintf(stderr, "failed to malloc lxc_container\n");
92ae9d2b909d0fd4a522a270157926878b5d0862Stephen Gallagher memset(c, 0, sizeof(*c));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher c->config_path = strdup(default_lxc_path());
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher fprintf(stderr, "Error allocating lxc_container name\n");
769347ad4d35d43488eb98f980143495b0db415dStef Walter if (!(c->slock = lxc_newlock(c->config_path, name))) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!(c->privlock = lxc_newlock(NULL, NULL))) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher fprintf(stderr, "failed to alloc privlock\n");
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce fprintf(stderr, "Error allocating config file pathname\n");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ERROR("Error: %s creation was not completed", c->name);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher // assign the member functions
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher c->want_daemonize = lxcapi_want_daemonize;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher c->set_config_item = lxcapi_set_config_item;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher c->get_config_item = lxcapi_get_config_item;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher c->get_cgroup_item = lxcapi_get_cgroup_item;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher c->set_cgroup_item = lxcapi_set_cgroup_item;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher c->set_config_path = lxcapi_set_config_path;
88275cccddf39892e01682b39b02292eb74729bdPavel Březina c->attach_run_waitl = lxcapi_attach_run_waitl;
f8a4a5f6240156809e1b5ef03816f673281e3fa0Jakub Hrozek /* we'll allow the caller to update these later */
f8a4a5f6240156809e1b5ef03816f673281e3fa0Jakub Hrozek if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher for (i=0; i<MAX_STATE; i++)