[LXC_CMD_GET_NAME] = "get_name",
[LXC_CMD_GET_LXCPATH] = "get_lxcpath",
[LXC_CMD_ADD_STATE_CLIENT] = "add_state_client",
+ [LXC_CMD_SET_CONFIG_ITEM] = "set_config_item",
};
if (cmd >= LXC_CMD_MAX)
return lxc_cmd_rsp_send(fd, &rsp);
}
+/*
+ * lxc_cmd_set_config_item: Get config item the running container
+ *
+ * @name : name of container to connect to
+ * @item : the configuration item to set (ex: lxc.net.0.veth.pair)
+ * @value : the value to set (ex: "eth0")
+ * @lxcpath : the lxcpath in which the container is running
+ *
+ * Returns 0 on success, negative errno on failure.
+ */
+int lxc_cmd_set_config_item(const char *name, const char *item,
+ const char *value, const char *lxcpath)
+{
+ int ret, stopped;
+ struct lxc_cmd_set_config_item_req_data data;
+ struct lxc_cmd_rr cmd;
+
+ /* pre-validate request
+ Currently we only support live-patching network configurations.
+ */
+ if (strncmp(item, "lxc.net.", 8))
+ return -EINVAL;
+
+ data.item = item;
+ data.value = (void *)value;
+
+ cmd.req.cmd = LXC_CMD_SET_CONFIG_ITEM;
+ cmd.req.data = &data;
+ cmd.req.datalen = sizeof(data);
+
+ ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+ if (ret < 0)
+ return ret;
+
+ return cmd.rsp.ret;
+}
+
+static int lxc_cmd_set_config_item_callback(int fd, struct lxc_cmd_req *req,
+ struct lxc_handler *handler)
+{
+ const char *key, *value;
+ struct lxc_cmd_rsp rsp;
+ const struct lxc_cmd_set_config_item_req_data *data;
+
+ data = req->data;
+ key = data->item;
+ value = data->value;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.ret = lxc_set_config_item_locked(handler->conf, key, value);
+ return lxc_cmd_rsp_send(fd, &rsp);
+}
+
/*
* lxc_cmd_get_state: Get current state of the container
*
[LXC_CMD_GET_NAME] = lxc_cmd_get_name_callback,
[LXC_CMD_GET_LXCPATH] = lxc_cmd_get_lxcpath_callback,
[LXC_CMD_ADD_STATE_CLIENT] = lxc_cmd_add_state_client_callback,
+ [LXC_CMD_SET_CONFIG_ITEM] = lxc_cmd_set_config_item_callback,
};
if (req->cmd >= LXC_CMD_MAX) {
LXC_CMD_GET_NAME,
LXC_CMD_GET_LXCPATH,
LXC_CMD_ADD_STATE_CLIENT,
+ LXC_CMD_SET_CONFIG_ITEM,
LXC_CMD_MAX,
} lxc_cmd_t;
int ttynum;
};
+struct lxc_cmd_set_config_item_req_data {
+ const char *item;
+ void *value;
+};
+
extern int lxc_cmd_console_winch(const char *name, const char *lxcpath);
extern int lxc_cmd_console(const char *name, int *ttynum, int *fd,
const char *lxcpath);
struct lxc_handler *handler);
extern int lxc_try_cmd(const char *name, const char *lxcpath);
+extern int lxc_cmd_set_config_item(const char *name, const char *item,
+ const char *value, const char *lxcpath);
+
#endif /* __commands_h */
*/
extern int add_rdepend(struct lxc_conf *lxc_conf, char *rdepend);
+/*
+ * Set a key/value configuration option. Requires that to take a lock on the
+ * in-memory config of the container.
+ */
+extern int lxc_set_config_item_locked(struct lxc_conf *conf, const char *key,
+ const char *v);
+
#ifdef __cplusplus
}
#endif
WRAP_API(bool, lxcapi_destroy_with_snapshots)
-static bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v)
+int lxc_set_config_item_locked(struct lxc_conf *conf, const char *key,
+ const char *v)
{
+ int ret;
struct lxc_config_t *config;
+ bool bret = true;
+
+ config = lxc_get_config(key);
+ if (!config)
+ return -EINVAL;
+
+ ret = config->set(key, v, conf, NULL);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (lxc_config_value_empty(v))
+ do_clear_unexp_config_line(conf, key);
+ else
+ bret = do_append_unexp_config_line(conf, key, v);
+ if (!bret)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static bool do_set_config_item_locked(struct lxc_container *c, const char *key,
+ const char *v)
+{
+ int ret;
if (!c->lxc_conf)
c->lxc_conf = lxc_conf_init();
if (!c->lxc_conf)
return false;
- config = lxc_get_config(key);
- if (!config)
- return false;
-
- if (config->set(key, v, c->lxc_conf, NULL) != 0)
+ ret = lxc_set_config_item_locked(c->lxc_conf, key, v);
+ if (ret < 0)
return false;
- if (lxc_config_value_empty(v)) {
- do_clear_unexp_config_line(c->lxc_conf, key);
- return true;
- }
-
- return do_append_unexp_config_line(c->lxc_conf, key, v);
+ return true;
}
static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v)
if (container_mem_lock(c))
return false;
- b = set_config_item_locked(c, key, v);
+ b = do_set_config_item_locked(c, key, v);
container_mem_unlock(c);
return b;
WRAP_API_2(bool, lxcapi_set_config_item, const char *, const char *)
+static bool do_lxcapi_set_running_config_item(struct lxc_container *c, const char *key, const char *v)
+{
+ int ret;
+
+ if (!c)
+ return false;
+
+ if (container_mem_lock(c))
+ return false;
+
+ ret = lxc_cmd_set_config_item(c->name, key, v, do_lxcapi_get_config_path(c));
+ if (ret < 0)
+ ERROR("Failed to live patch container");
+
+ container_mem_unlock(c);
+ return ret == 0;
+}
+
+WRAP_API_2(bool, lxcapi_set_running_config_item, const char *, const char *)
+
static char *lxcapi_config_file_name(struct lxc_container *c)
{
if (!c || !c->configfile)
clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false);
clear_unexp_config_line(c2->lxc_conf, "lxc.uts.name", false);
- if (!set_config_item_locked(c2, "lxc.uts.name", newname)) {
+ if (!do_set_config_item_locked(c2, "lxc.uts.name", newname)) {
ERROR("Error setting new hostname");
goto out;
}
c->clear_config_item = lxcapi_clear_config_item;
c->get_config_item = lxcapi_get_config_item;
c->get_running_config_item = lxcapi_get_running_config_item;
+ c->set_running_config_item = lxcapi_set_running_config_item;
c->get_cgroup_item = lxcapi_get_cgroup_item;
c->set_cgroup_item = lxcapi_set_cgroup_item;
c->get_config_path = lxcapi_get_config_path;
*/
bool (*set_config_item)(struct lxc_container *c, const char *key, const char *value);
+ /*!
+ * \brief Set a key/value configuration option on a running container.
+ *
+ * \param c Container.
+ * \param key Name of option to set.
+ * \param value Value of \p name to set.
+ *
+ * \return \c true on success, else \c false.
+ */
+ bool (*set_running_config_item)(struct lxc_container *c, const char *key, const char *value);
+
/*!
* \brief Delete the container.
*