if (state < 0) {
TRACE("%s - Failed to retrieve state of container", strerror(errno));
return -1;
- } else if (states[state]) {
- TRACE("Container is %s state", lxc_state2str(state));
+ } else if (states[state] == 1) {
+ TRACE("Container is in %s state", lxc_state2str(state));
return state;
}
struct lxc_epoll_descr *descr,
const lxc_cmd_t cmd)
{
- struct state_client *client;
+ struct lxc_state_client *client;
struct lxc_list *cur, *next;
lxc_console_free(handler->conf, fd);
}
process_lock();
- lxc_list_for_each_safe(cur, &handler->state_clients, next) {
+ lxc_list_for_each_safe(cur, &handler->conf->state_clients, next) {
client = cur->elem;
if (client->clientfd != fd)
continue;
int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
lxc_state_t states[MAX_STATE])
{
- struct state_client *newclient;
+ struct lxc_state_client *newclient;
struct lxc_list *tmplist;
newclient = malloc(sizeof(*newclient));
process_lock();
lxc_list_add_elem(tmplist, newclient);
- lxc_list_add_tail(&handler->state_clients, tmplist);
+ lxc_list_add_tail(&handler->conf->state_clients, tmplist);
process_unlock();
TRACE("added state client %d to state client list", state_client_fd);
for (i = 0; i < NUM_LXC_HOOKS; i++)
lxc_list_init(&new->hooks[i]);
lxc_list_init(&new->groups);
+ lxc_list_init(&new->state_clients);
new->lsm_aa_profile = NULL;
new->lsm_se_context = NULL;
new->tmp_umount_proc = 0;
extern char *lxchook_names[NUM_LXC_HOOKS];
+struct lxc_state_client {
+ int clientfd;
+ lxc_state_t states[MAX_STATE];
+};
+
struct lxc_conf {
int is_execute;
char *fstab;
/* init working directory */
char* init_cwd;
+ /* A list of clients registered to be informed about a container state. */
+ struct lxc_list state_clients;
};
int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
WRAP_API(bool, lxcapi_reboot)
+static bool do_lxcapi_reboot2(struct lxc_container *c, int timeout)
+{
+ int killret, ret;
+ pid_t pid;
+ int rebootsignal = SIGINT, state_client_fd = -1;
+ lxc_state_t states[MAX_STATE] = {0};
+
+ if (!c)
+ return false;
+
+ if (!do_lxcapi_is_running(c))
+ return true;
+
+ pid = do_lxcapi_init_pid(c);
+ if (pid <= 0)
+ return true;
+
+ if (c->lxc_conf && c->lxc_conf->rebootsignal)
+ rebootsignal = c->lxc_conf->rebootsignal;
+
+ /* Add a new state client before sending the shutdown signal so that we
+ * don't miss a state.
+ */
+ if (timeout != 0) {
+ states[RUNNING] = 2;
+ ret = lxc_cmd_add_state_client(c->name, c->config_path, states,
+ &state_client_fd);
+ if (ret < 0)
+ return false;
+
+ if (state_client_fd < 0)
+ return false;
+
+ if (ret == RUNNING)
+ return true;
+
+ if (ret < MAX_STATE)
+ return false;
+ }
+
+ /* Send reboot signal to container. */
+ killret = kill(pid, rebootsignal);
+ if (killret < 0) {
+ WARN("Could not send signal %d to pid %d", rebootsignal, pid);
+ if (state_client_fd >= 0)
+ close(state_client_fd);
+ return false;
+ }
+ TRACE("Sent signal %d to pid %d", rebootsignal, pid);
+
+ if (timeout == 0)
+ return true;
+
+ ret = lxc_cmd_sock_rcv_state(state_client_fd, timeout);
+ close(state_client_fd);
+ if (ret < 0)
+ return false;
+
+ TRACE("Received state \"%s\"", lxc_state2str(ret));
+ if (ret != RUNNING)
+ return false;
+
+ return true;
+}
+
+WRAP_API_1(bool, lxcapi_reboot2, int)
+
static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
{
int ret, state_client_fd = -1;
c->createl = lxcapi_createl;
c->shutdown = lxcapi_shutdown;
c->reboot = lxcapi_reboot;
+ c->reboot2 = lxcapi_reboot2;
c->clear_config = lxcapi_clear_config;
c->clear_config_item = lxcapi_clear_config_item;
c->get_config_item = lxcapi_get_config_item;
* \return \c 0 on success, nonzero on failure.
*/
int (*console_log)(struct lxc_container *c, struct lxc_console_log *log);
+
+ /*!
+ * \brief Request the container reboot by sending it \c SIGINT.
+ *
+ * \param c Container.
+ * \param timeout Seconds to wait before returning false.
+ * (-1 to wait forever, 0 to avoid waiting).
+ *
+ * \return \c true if the container was rebooted successfully, else \c false.
+ */
+ bool (*reboot2)(struct lxc_container *c, int timeout);
};
/*!
fddir = dirfd(dir);
while ((direntp = readdir(dir))) {
+ struct lxc_list *cur;
+ bool matched = false;
+
if (!direntp)
break;
(i < len_fds && fd == fds_to_ignore[i]))
continue;
+ /* Keep state clients that wait on reboots. */
+ lxc_list_for_each(cur, &conf->state_clients) {
+ struct lxc_state_client *client = cur->elem;
+
+ if (client->clientfd != fd)
+ continue;
+
+ matched = true;
+ break;
+ }
+
+ if (matched)
+ continue;
+
if (current_config && fd == current_config->logfd)
continue;
{
ssize_t ret;
struct lxc_list *cur, *next;
- struct state_client *client;
+ struct lxc_state_client *client;
struct lxc_msg msg = {.type = lxc_msg_state, .value = state};
handler->state = state;
TRACE("Set container state to %s", lxc_state2str(state));
process_lock();
- if (lxc_list_empty(&handler->state_clients)) {
+ if (lxc_list_empty(&handler->conf->state_clients)) {
TRACE("No state clients registered");
process_unlock();
lxc_monitor_send_state(name, state, handler->lxcpath);
strncpy(msg.name, name, sizeof(msg.name));
msg.name[sizeof(msg.name) - 1] = 0;
- lxc_list_for_each_safe(cur, &handler->state_clients, next) {
+ lxc_list_for_each_safe(cur, &handler->conf->state_clients, next) {
client = cur->elem;
- if (!client->states[state]) {
+ if (client->states[state] == 0) {
TRACE("State %s not registered for state client %d",
lxc_state2str(state), client->clientfd);
continue;
handler->lxcpath = lxcpath;
handler->pinfd = -1;
handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1;
- lxc_list_init(&handler->state_clients);
+ if (handler->conf->reboot == 0)
+ lxc_list_init(&handler->conf->state_clients);
for (i = 0; i < LXC_NS_MAX; i++)
handler->nsfd[i] = -1;
handler->state_socket_pair[1]);
}
- handler->conf->maincmd_fd = lxc_cmd_init(name, lxcpath, "command");
- if (handler->conf->maincmd_fd < 0) {
- ERROR("Failed to set up command socket");
- goto on_error;
+ if (handler->conf->reboot == 0) {
+ handler->conf->maincmd_fd = lxc_cmd_init(name, lxcpath, "command");
+ if (handler->conf->maincmd_fd < 0) {
+ ERROR("Failed to set up command socket");
+ goto on_error;
+ }
}
TRACE("Unix domain socket %d for command server is ready",
handler->conf->maincmd_fd);
lxc_set_state(name, handler, STOPPED);
- /* close command socket */
- close(handler->conf->maincmd_fd);
- handler->conf->maincmd_fd = -1;
+ if (handler->conf->reboot == 0) {
+ /* close command socket */
+ close(handler->conf->maincmd_fd);
+ handler->conf->maincmd_fd = -1;
+ }
if (run_lxc_hooks(name, "post-stop", handler->conf, handler->lxcpath, NULL)) {
ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", name);
/* The command socket is now closed, no more state clients can register
* themselves from now on. So free the list of state clients.
*/
- lxc_list_for_each_safe(cur, &handler->state_clients, next) {
- struct state_client *client = cur->elem;
+ lxc_list_for_each_safe(cur, &handler->conf->state_clients, next) {
+ struct lxc_state_client *client = cur->elem;
+
+ /* Keep state clients that want to be notified about reboots. */
+ if ((handler->conf->reboot > 0) && (client->states[RUNNING] == 2))
+ continue;
+
/* close state client socket */
close(client->clientfd);
lxc_list_del(cur);
lxc_sync_fini_parent(handler);
/* Don't leak the pinfd to the container. */
- if (handler->pinfd >= 0) {
+ if (handler->pinfd >= 0)
close(handler->pinfd);
- }
if (lxc_sync_wait_parent(handler, LXC_SYNC_STARTUP))
return -1;
/* The container's in-memory configuration. */
struct lxc_conf *conf;
- /* A list of clients registered to be informed about a container state. */
- struct lxc_list state_clients;
-
/* A set of operations to be performed at various stages of the
* container's life.
*/
int (*post_start)(struct lxc_handler *, void *);
};
-struct state_client {
- int clientfd;
- lxc_state_t states[MAX_STATE];
-};
-
extern int lxc_poll(const char *name, struct lxc_handler *handler);
extern int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state);
extern void lxc_abort(const char *name, struct lxc_handler *handler);
lxc_log_define(lxc_state, lxc);
-static const char * const strstate[] = {
- "STOPPED", "STARTING", "RUNNING", "STOPPING",
- "ABORTING", "FREEZING", "FROZEN", "THAWED",
+static const char *const strstate[] = {
+ "STOPPED", "STARTING", "RUNNING", "STOPPING",
+ "ABORTING", "FREEZING", "FROZEN", "THAWED",
};
const char *lxc_state2str(lxc_state_t state)
.timeout = -2,
};
-/* returns -1 on failure, 0 on success */
-static int do_reboot_and_check(struct lxc_arguments *a, struct lxc_container *c)
-{
- int ret;
- pid_t pid;
- pid_t newpid;
- int timeout = a->timeout;
-
- pid = c->init_pid(c);
- if (pid == -1)
- return -1;
- if (!c->reboot(c))
- return -1;
- if (a->nowait)
- return 0;
- if (timeout == 0)
- goto out;
-
- for (;;) {
- /* can we use c-> wait for this, assuming it will
- * re-enter RUNNING? For now just sleep */
- int elapsed_time, curtime = 0;
- struct timeval tv;
-
- newpid = c->init_pid(c);
- if (newpid != -1 && newpid != pid)
- return 0;
-
- if (timeout != -1) {
- ret = gettimeofday(&tv, NULL);
- if (ret)
- break;
- curtime = tv.tv_sec;
- }
-
- sleep(1);
- if (timeout != -1) {
- ret = gettimeofday(&tv, NULL);
- if (ret)
- break;
- elapsed_time = tv.tv_sec - curtime;
- if (timeout - elapsed_time <= 0)
- break;
- timeout -= elapsed_time;
- }
- }
-
-out:
- newpid = c->init_pid(c);
- if (newpid == -1 || newpid == pid) {
- printf("Reboot did not complete before timeout\n");
- return -1;
- }
- return 0;
-}
-
int main(int argc, char *argv[])
{
struct lxc_container *c;
/* reboot */
if (my_args.reboot) {
- ret = do_reboot_and_check(&my_args, c) < 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ ret = c->reboot2(c, my_args.timeout);
+ if (ret < 0)
+ ret = EXIT_FAILURE;
+ else
+ ret = EXIT_SUCCESS;
goto out;
}