]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_autostart.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 #include <lxc/lxccontainer.h>
13 #include "arguments.h"
19 lxc_log_define(lxc_autostart
, lxc
);
21 static struct lxc_list
*accumulate_list(char *input
, char *delimiter
, struct lxc_list
*str_list
);
23 struct lxc_list
*cmd_groups_list
= NULL
;
25 static int my_parser(struct lxc_arguments
*args
, int c
, char *arg
)
44 args
->ignore_auto
= 1;
47 cmd_groups_list
= accumulate_list(arg
, ",", cmd_groups_list
);
50 if (lxc_safe_long(arg
, &args
->timeout
) < 0)
57 static const struct option my_longopts
[] = {
58 {"kill", no_argument
, 0, 'k'},
59 {"list", no_argument
, 0, 'L'},
60 {"reboot", no_argument
, 0, 'r'},
61 {"shutdown", no_argument
, 0, 's'},
62 {"all", no_argument
, 0, 'a'},
63 {"ignore-auto", no_argument
, 0, 'A'},
64 {"groups", required_argument
, 0, 'g'},
65 {"timeout", required_argument
, 0, 't'},
66 {"help", no_argument
, 0, 'h'},
70 static struct lxc_arguments my_args
= {
71 .progname
= "lxc-autostart",
74 lxc-autostart managed auto-started containers\n\
77 -k, --kill kill the containers instead of starting them\n\
78 -L, --list list all affected containers and wait delay\n\
79 -r, --reboot reboot the containers instead of starting them\n\
80 -s, --shutdown shutdown the containers instead of starting them\n\
82 -a, --all list all auto-started containers (ignore groups)\n\
83 -A, --ignore-auto ignore lxc.start.auto and select all matching containers\n\
84 -g, --groups list of groups (comma separated) to select\n\
85 -t, --timeout=T wait T seconds before hard-stopping\n",
86 .options
= my_longopts
,
92 static int list_contains_entry(char *str_ptr
, struct lxc_list
*p1
) {
96 * If the entry is NULL or the empty string and the list
97 * is NULL, we have a match
99 if (!p1
&& (!str_ptr
|| !*str_ptr
))
105 lxc_list_for_each(it1
, p1
) {
106 if (strncmp(it1
->elem
, str_ptr
, strlen(it1
->elem
)) == 0)
113 /* This is a variation of get_list below it. This version allows two additional
114 * features. If a list is passed to it, it adds to it. It allows for empty
115 * entries (i.e. "group1,,group2") generating and empty list entry.
117 static struct lxc_list
*accumulate_list(char *input
, char *delimiter
,
118 struct lxc_list
*str_list
)
120 char *workstr
= NULL
;
121 char *workptr
= NULL
;
122 char *next_ptr
= NULL
;
123 struct lxc_list
*worklist
;
124 struct lxc_list
*workstr_list
;
126 workstr
= strdup(input
);
130 workstr_list
= str_list
;
132 workstr_list
= malloc(sizeof(*workstr_list
));
138 lxc_list_init(workstr_list
);
141 for (workptr
= workstr
; workptr
; workptr
= next_ptr
) {
142 /* We can't use strtok_r here because it collapses multiple
143 * delimiters into 1 making empty fields impossible...
145 next_ptr
= strchr(workptr
, *delimiter
);
149 /* At this point, we'd like to check to see if this group is
150 * already contained in the list and ignore it if it is... This
151 * also helps us with any corner cases where a string begins or
152 * ends with a delimiter.
154 if (list_contains_entry(workptr
, workstr_list
)) {
156 ERROR("Duplicate group \"%s\" in list - ignoring", workptr
);
158 ERROR("Duplicate NULL group in list - ignoring");
160 worklist
= malloc(sizeof(*worklist
));
164 worklist
->elem
= strdup(workptr
);
165 if (!worklist
->elem
) {
170 lxc_list_add_tail(workstr_list
, worklist
);
179 static struct lxc_list
*get_list(char *input
, char *delimiter
)
181 char *workstr
= NULL
;
183 struct lxc_list
*worklist
;
184 struct lxc_list
*workstr_list
;
186 workstr_list
= malloc(sizeof(*workstr_list
));
190 lxc_list_init(workstr_list
);
192 workstr
= strdup(input
);
198 lxc_iterate_parts(token
, workstr
, delimiter
) {
199 worklist
= malloc(sizeof(*worklist
));
203 worklist
->elem
= strdup(token
);
204 if (!worklist
->elem
) {
209 lxc_list_add_tail(workstr_list
, worklist
);
217 static struct lxc_list
*get_config_list(struct lxc_container
*c
, char *key
)
221 struct lxc_list
*config_list
= NULL
;
223 len
= c
->get_config_item(c
, key
, NULL
, 0);
227 value
= (char *)malloc(sizeof(char) * len
+ 1);
231 if (c
->get_config_item(c
, key
, value
, len
+ 1) != len
) {
236 if (strlen(value
) == 0) {
241 config_list
= get_list(value
, "\n");
247 static int get_config_integer(struct lxc_container
*c
, char *key
)
249 int len
= 0, ret
= 0;
252 len
= c
->get_config_item(c
, key
, NULL
, 0);
256 value
= (char *)malloc(sizeof(char) * len
+ 1);
260 if (c
->get_config_item(c
, key
, value
, len
+ 1) != len
) {
265 if (lxc_safe_int(value
, &ret
) < 0)
266 printf("Could not parse config item.\n");
273 static int cmporder(const void *p1
, const void *p2
)
275 struct lxc_container
*c1
= *(struct lxc_container
**)p1
;
276 struct lxc_container
*c2
= *(struct lxc_container
**)p2
;
278 int c1_order
= get_config_integer(c1
, "lxc.start.order");
279 int c2_order
= get_config_integer(c2
, "lxc.start.order");
281 if (c1_order
== c2_order
)
282 return strncmp(c1
->name
, c2
->name
, strlen(c1
->name
));
284 return (c1_order
- c2_order
);
287 static int toss_list(struct lxc_list
*c_groups_list
)
289 struct lxc_list
*it
, *next
;
294 lxc_list_for_each_safe(it
, c_groups_list
, next
) {
304 int main(int argc
, char *argv
[])
306 int count
= 0, failed
= 0, i
= 0, ret
= 0;
307 struct lxc_list
*cmd_group
;
308 struct lxc_container
**containers
= NULL
;
309 struct lxc_list
**c_groups_lists
= NULL
;
312 if (lxc_arguments_parse(&my_args
, argc
, argv
))
315 /* Only create log if explicitly instructed */
316 if (my_args
.log_file
|| my_args
.log_priority
) {
317 log
.name
= my_args
.name
;
318 log
.file
= my_args
.log_file
;
319 log
.level
= my_args
.log_priority
;
320 log
.prefix
= my_args
.progname
;
321 log
.quiet
= my_args
.quiet
;
322 log
.lxcpath
= my_args
.lxcpath
[0];
324 if (lxc_log_init(&log
))
328 count
= list_defined_containers(my_args
.lxcpath
[0], NULL
, &containers
);
333 /* Allocate an array for our container group lists */
335 c_groups_lists
= calloc( count
, sizeof( struct lxc_list
* ) );
337 qsort(&containers
[0], count
, sizeof(struct lxc_container
*), cmporder
);
339 if (cmd_groups_list
&& my_args
.all
)
340 ERROR("Specifying -a (all) with -g (groups) doesn't make sense. All option overrides");
342 /* We need a default cmd_groups_list even for the -a
343 * case in order to force a pass through the loop for
344 * the NULL group. This, someday, could be taken from
345 * a config file somewhere...
347 if (!cmd_groups_list
)
348 cmd_groups_list
= accumulate_list( "" , ",", NULL
);
350 lxc_list_for_each(cmd_group
, cmd_groups_list
) {
351 /* Because we may take several passes through the container list
352 * We'll switch on if the container pointer is NULL and if we
353 * process a container (run it or decide to ignore it) and call
354 * lxc_container_put then we'll NULL it out and not check it
357 for (i
= 0; i
< count
; i
++) {
358 struct lxc_container
*c
= containers
[i
];
361 /* Skip - must have been already processed */
364 /* We haven't loaded the container groups yet so these
365 * next two checks don't need to free them if they fail.
366 * They'll fail on the first pass.
368 if (!c
->may_control(c
)) {
369 /* We're done with this container */
370 if (lxc_container_put(c
) > 0)
371 containers
[i
] = NULL
;
376 if (!my_args
.ignore_auto
&&
377 get_config_integer(c
, "lxc.start.auto") != 1) {
378 /* We're done with this container */
379 if (lxc_container_put(c
) > 0)
380 containers
[i
] = NULL
;
386 /* Filter by group */
387 if (!c_groups_lists
[i
]) {
388 /* Now we're loading up a container's groups */
389 c_groups_lists
[i
] = get_config_list(c
, "lxc.group");
392 ret
= list_contains_entry(cmd_group
->elem
, c_groups_lists
[i
]);
394 /* Not in the target group this pass so
395 * leave in the list for subsequent
402 /* We have a candidate container to process */
403 c
->want_daemonize(c
, 1);
405 if (my_args
.shutdown
) {
406 /* Shutdown the container */
407 if (c
->is_running(c
)) {
409 printf("%s\n", c
->name
);
413 if (!c
->shutdown(c
, my_args
.timeout
)) {
415 ERROR("Error shutting down container: %s", c
->name
);
419 } else if (my_args
.hardstop
) {
420 /* Kill the container */
421 if (c
->is_running(c
)) {
423 printf("%s\n", c
->name
);
428 ERROR("Error killing container: %s", c
->name
);
431 } else if (my_args
.reboot
) {
432 /* Reboot the container */
433 if (c
->is_running(c
)) {
435 printf("%s %d\n", c
->name
,
436 get_config_integer(c
, "lxc.start.delay"));
441 ERROR("Error rebooting container: %s", c
->name
);
443 sleep(get_config_integer(c
, "lxc.start.delay"));
447 /* Start the container */
448 if (!c
->is_running(c
)) {
450 printf("%s %d\n", c
->name
,
451 get_config_integer(c
, "lxc.start.delay"));
455 if (!c
->start(c
, 0, NULL
))
456 ERROR("Error starting container: %s", c
->name
);
458 sleep(get_config_integer(c
, "lxc.start.delay"));
464 * If we get this far and we haven't hit any skip "continue"
465 * then we're done with this container... We can dump any
466 * c_groups_list and the container itself.
468 if (lxc_container_put(c
) > 0)
469 containers
[i
] = NULL
;
471 if (c_groups_lists
) {
472 toss_list(c_groups_lists
[i
]);
473 c_groups_lists
[i
] = NULL
;
479 /* clean up any lingering detritus, if container exists here
480 * then it must have failed to start.
483 for (i
= 0; i
< count
; i
++) {
486 lxc_container_put(containers
[i
]);
488 if (c_groups_lists
&& c_groups_lists
[i
])
489 toss_list(c_groups_lists
[i
]);
492 free(c_groups_lists
);
493 toss_list(cmd_groups_list
);
497 exit(EXIT_FAILURE
); /* Total failure */
499 exit(2); /* Partial failure */