to monitor all the containers, several of them or just one.
</para>
+ <para>
+ The <option>-P, --lxcpath</option>=PATH option may be specified multiple
+ times to monitor more than one container path. Note however that
+ containers with the same name in multiple paths will be
+ indistinguishable in the output.
+ </para>
+
</refsect1>
&commonoptions;
exit(code);
}
+static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
+ const char *lxcpath)
+{
+ if (args->lxcpath_additional != -1 &&
+ args->lxcpath_cnt > args->lxcpath_additional) {
+ fprintf(stderr, "This command only accepts %d -P,--lxcpath arguments\n",
+ args->lxcpath_additional + 1);
+ exit(EXIT_FAILURE);
+ }
+
+ args->lxcpath = realloc(args->lxcpath, (args->lxcpath_cnt + 1) *
+ sizeof(args->lxcpath[0]));
+ if (args->lxcpath == NULL) {
+ lxc_error(args, "no memory");
+ return ENOMEM;
+ }
+ args->lxcpath[args->lxcpath_cnt++] = lxcpath;
+ return 0;
+}
+
extern int lxc_arguments_parse(struct lxc_arguments *args,
int argc, char * const argv[])
{
char shortopts[256];
int ret = 0;
- args->lxcpath = default_lxc_path();
ret = build_shortopts(args->options, shortopts, sizeof(shortopts));
if (ret < 0) {
lxc_error(args, "build_shortopts() failed : %s",
case 'l': args->log_priority = optarg; break;
case 'c': args->console = optarg; break;
case 'q': args->quiet = 1; break;
- case 'P': args->lxcpath = optarg; break;
+ case 'P':
+ ret = lxc_arguments_lxcpath_add(args, optarg);
+ if (ret < 0)
+ return ret;
+ break;
case OPT_USAGE: print_usage(args->options, args);
case '?': print_help(args, 1);
case 'h': print_help(args, 0);
args->argv = &argv[optind];
args->argc = argc - optind;
+ /* If no lxcpaths were given, use default */
+ if (!args->lxcpath_cnt) {
+ ret = lxc_arguments_lxcpath_add(args, default_lxc_path());
+ if (ret < 0)
+ return ret;
+ }
+
/* Check the command options */
if (!args->name) {
const char *console;
const char *console_log;
const char *pidfile;
- const char *lxcpath;
+ const char **lxcpath;
+ int lxcpath_cnt;
+ /* set to 0 to accept only 1 lxcpath, -1 for unlimited */
+ int lxcpath_additional;
/* for lxc-checkpoint/restart */
const char *statefile;
#endif
#include <stddef.h>
+#include <sys/types.h>
#include <lxc/state.h>
struct lxc_msg;
extern int lxc_monitor_open(const char *lxcpath);
/*
- * Read the state of the container if this one has changed
- * The function will block until there is an event available
- * @fd : the file descriptor provided by lxc_monitor_open
- * @state : the variable which will be filled with the state
+ * Blocking read for the next container state change
+ * @fd : the file descriptor provided by lxc_monitor_open
+ * @msg : the variable which will be filled with the state
* Returns 0 if the monitored container has exited, > 0 if
- * data was readen, < 0 otherwise
+ * data was read, < 0 otherwise
*/
extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
+
+/*
+ * Blocking read for the next container state change with timeout
+ * @fd : the file descriptor provided by lxc_monitor_open
+ * @msg : the variable which will be filled with the state
+ * @timeout : the timeout in seconds to wait for a state change
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
+/*
+ * Blocking read from multiple monitors for the next container state
+ * change with timeout
+ * @rfds : an fd_set of file descriptors provided by lxc_monitor_open
+ * @nfds : the maximum fd number in rfds + 1
+ * @msg : the variable which will be filled with the state
+ * @timeout : the timeout in seconds to wait for a state change
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg, int timeout);
+
/*
* Close the fd associated with the monitoring
* @fd : the file descriptor provided by lxc_monitor_open
return ret;
ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath);
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]);
if (ret)
return ret;
- init_pid = get_init_pid(my_args.name, my_args.lxcpath);
+ init_pid = get_init_pid(my_args.name, my_args.lxcpath[0]);
if (init_pid < 0) {
ERROR("failed to get the init pid");
return -1;
* by asking lxc-start
*/
if (namespace_flags == -1) {
- namespace_flags = lxc_get_clone_flags(my_args.name, my_args.lxcpath);
+ namespace_flags = lxc_get_clone_flags(my_args.name, my_args.lxcpath[0]);
/* call failed */
if (namespace_flags == -1) {
ERROR("failed to automatically determine the "
}
if (!elevated_privileges) {
- ret = lxc_cgroup_attach(grandchild, my_args.name, my_args.lxcpath);
+ ret = lxc_cgroup_attach(grandchild, my_args.name, my_args.lxcpath[0]);
if (ret < 0) {
ERROR("failed to attach process to cgroup");
return -1;
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
state_object = my_args.argv[0];
value = my_args.argv[1];
if (value) {
- if (lxc_cgroup_set(my_args.name, state_object, value, my_args.lxcpath)) {
+ if (lxc_cgroup_set(my_args.name, state_object, value, my_args.lxcpath[0])) {
ERROR("failed to assign '%s' value to '%s' for '%s'",
value, state_object, my_args.name);
return -1;
int ret;
char buffer[len];
- ret = lxc_cgroup_get(my_args.name, state_object, buffer, len, my_args.lxcpath);
+ ret = lxc_cgroup_get(my_args.name, state_object, buffer, len, my_args.lxcpath[0]);
if (ret < 0) {
ERROR("failed to retrieve value of '%s' for '%s'",
state_object, my_args.name);
return ret;
ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath);
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]);
if (ret)
return ret;
return -1;
err = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath);
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]);
if (err)
return -1;
return -1;
}
- err = lxc_console(my_args.name, my_args.ttynum, &master, my_args.lxcpath);
+ err = lxc_console(my_args.name, my_args.ttynum, &master, my_args.lxcpath[0]);
if (err)
goto out;
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
/* rcfile is specified in the cli option */
else {
int rc;
- rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath, my_args.name);
+ rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath[0], my_args.name);
if (rc == -1) {
SYSERROR("failed to allocate memory");
return -1;
if (lxc_config_define_load(&defines, conf))
return -1;
- return lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath);
+ return lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0]);
}
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
- return lxc_freeze(my_args.name, my_args.lxcpath);
+ return lxc_freeze(my_args.name, my_args.lxcpath[0]);
}
return 1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return 1;
if (!state && !pid)
state = pid = true;
if (state || test_state) {
- ret = lxc_getstate(my_args.name, my_args.lxcpath);
+ ret = lxc_getstate(my_args.name, my_args.lxcpath[0]);
if (ret < 0)
return 1;
if (test_state)
}
if (pid)
- printf("pid:%10d\n", get_init_pid(my_args.name, my_args.lxcpath));
+ printf("pid:%10d\n", get_init_pid(my_args.name, my_args.lxcpath[0]));
return 0;
}
return ret;
ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath);
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]);
if (ret)
return ret;
} else
sig=SIGKILL;
- pid = get_init_pid(my_args.name, my_args.lxcpath);
+ pid = get_init_pid(my_args.name, my_args.lxcpath[0]);
if (pid < 0) {
ERROR("failed to get the init pid");
return -1;
.options = my_longopts,
.parser = NULL,
.checker = NULL,
+ .lxcpath_additional = -1,
};
int main(int argc, char *argv[])
char *regexp;
struct lxc_msg msg;
regex_t preg;
- int fd;
- int len, rc;
+ fd_set rfds, rfds_save;
+ int len, rc, i, nfds = -1;
if (lxc_arguments_parse(&my_args, argc, argv))
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
len = strlen(my_args.name) + 3;
return -1;
}
- lxc_monitord_spawn(my_args.lxcpath);
+ if (my_args.lxcpath_cnt > FD_SETSIZE) {
+ ERROR("too many paths requested, only the first %d will be monitored", FD_SETSIZE);
+ my_args.lxcpath_cnt = FD_SETSIZE;
+ }
- fd = lxc_monitor_open(my_args.lxcpath);
- if (fd < 0)
- return -1;
+ FD_ZERO(&rfds);
+ for (i = 0; i < my_args.lxcpath_cnt; i++) {
+ int fd;
+
+ lxc_monitord_spawn(my_args.lxcpath[i]);
+
+ fd = lxc_monitor_open(my_args.lxcpath[i]);
+ if (fd < 0)
+ return -1;
+ FD_SET(fd, &rfds);
+ if (fd > nfds)
+ nfds = fd;
+ }
+ memcpy(&rfds_save, &rfds, sizeof(rfds_save));
+ nfds++;
setlinebuf(stdout);
for (;;) {
- if (lxc_monitor_read(fd, &msg) < 0)
+ memcpy(&rfds, &rfds_save, sizeof(rfds));
+
+ if (lxc_monitor_read_fdset(&rfds, nfds, &msg, -1) < 0)
return -1;
msg.name[sizeof(msg.name)-1] = '\0';
return 0;
}
-
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
/* rcfile is specified in the cli option */
else {
int rc;
- rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath, my_args.name);
+ rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath[0], my_args.name);
if (rc == -1) {
SYSERROR("failed to allocate memory");
return -1;
}
}
- ret = lxc_restart(my_args.name, sfd, conf, my_args.flags, my_args.lxcpath);
+ ret = lxc_restart(my_args.name, sfd, conf, my_args.flags, my_args.lxcpath[0]);
if (my_args.statefile)
close(sfd);
args = my_args.argv;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return err;
/* rcfile is specified in the cli option */
else {
int rc;
- rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath, my_args.name);
+ rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath[0], my_args.name);
if (rc == -1) {
SYSERROR("failed to allocate memory");
return err;
if (my_args.close_all_fds)
conf->close_all_fds = 1;
- err = lxc_start(my_args.name, args, conf, my_args.lxcpath);
+ err = lxc_start(my_args.name, args, conf, my_args.lxcpath[0]);
/*
* exec ourself, that requires to have all opened fd
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
- return lxc_stop(my_args.name, my_args.lxcpath);
+ return lxc_stop(my_args.name, my_args.lxcpath[0]);
}
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
- return lxc_unfreeze(my_args.name, my_args.lxcpath);
+ return lxc_unfreeze(my_args.name, my_args.lxcpath[0]);
}
return -1;
if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
- my_args.progname, my_args.quiet, my_args.lxcpath))
+ my_args.progname, my_args.quiet, my_args.lxcpath[0]))
return -1;
- return lxc_wait(strdup(my_args.name), my_args.states, my_args.timeout, my_args.lxcpath);
+ return lxc_wait(strdup(my_args.name), my_args.states, my_args.timeout,
+ my_args.lxcpath[0]);
}
return ret;
}
-int lxc_monitor_read_timeout(int fd, struct lxc_msg *msglxc, int timeout)
+int lxc_monitor_read_fdset(fd_set *rfds, int nfds, struct lxc_msg *msg,
+ int timeout)
{
- fd_set rfds;
- struct timeval tv;
- int ret;
+ struct timeval tval,*tv = NULL;
+ int ret,i;
if (timeout != -1) {
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
-
- ret = select(fd+1, &rfds, NULL, NULL, &tv);
- if (ret == -1)
- return -1;
- else if (!ret)
- return -2; // timed out
+ tv = &tval;
+ tv->tv_sec = timeout;
+ tv->tv_usec = 0;
}
- ret = recv(fd, msglxc, sizeof(*msglxc), 0);
- if (ret <= 0) {
- SYSERROR("client failed to recv (monitord died?) %s",
- strerror(errno));
+ ret = select(nfds, rfds, NULL, NULL, tv);
+ if (ret == -1)
return -1;
+ else if (ret == 0)
+ return -2; // timed out
+
+ /* only read from the first ready fd, the others will remain ready
+ * for when this routine is called again
+ */
+ for (i = 0; i < nfds; i++) {
+ if (FD_ISSET(i, rfds)) {
+ ret = recv(i, msg, sizeof(*msg), 0);
+ if (ret <= 0) {
+ SYSERROR("client failed to recv (monitord died?) %s",
+ strerror(errno));
+ return -1;
+ }
+ return ret;
+ }
}
- return ret;
+ SYSERROR("no ready fd found?");
+ return -1;
+}
+
+int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
+{
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ return lxc_monitor_read_fdset(&rfds, fd+1, msg, timeout);
}
int lxc_monitor_read(int fd, struct lxc_msg *msg)