]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_autostart.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
12 #include "arguments.h"
17 lxc_log_define(lxc_autostart
, lxc
);
19 static struct lxc_list
*accumulate_list(char *input
, char *delimiter
, struct lxc_list
*str_list
);
21 struct lxc_list
*cmd_groups_list
= NULL
;
23 static int my_parser(struct lxc_arguments
*args
, int c
, char *arg
)
42 args
->ignore_auto
= 1;
45 cmd_groups_list
= accumulate_list(arg
, ",", cmd_groups_list
);
48 if (lxc_safe_long(arg
, &args
->timeout
) < 0)
55 static const struct option my_longopts
[] = {
56 {"kill", no_argument
, 0, 'k'},
57 {"list", no_argument
, 0, 'L'},
58 {"reboot", no_argument
, 0, 'r'},
59 {"shutdown", no_argument
, 0, 's'},
60 {"all", no_argument
, 0, 'a'},
61 {"ignore-auto", no_argument
, 0, 'A'},
62 {"groups", required_argument
, 0, 'g'},
63 {"timeout", required_argument
, 0, 't'},
64 {"help", no_argument
, 0, 'h'},
68 static struct lxc_arguments my_args
= {
69 .progname
= "lxc-autostart",
72 lxc-autostart managed auto-started containers\n\
75 -k, --kill kill the containers instead of starting them\n\
76 -L, --list list all affected containers and wait delay\n\
77 -r, --reboot reboot the containers instead of starting them\n\
78 -s, --shutdown shutdown the containers instead of starting them\n\
80 -a, --all list all auto-started containers (ignore groups)\n\
81 -A, --ignore-auto ignore lxc.start.auto and select all matching containers\n\
82 -g, --groups list of groups (comma separated) to select\n\
83 -t, --timeout=T wait T seconds before hard-stopping\n",
84 .options
= my_longopts
,
90 static int list_contains_entry(char *str_ptr
, struct lxc_list
*p1
) {
94 * If the entry is NULL or the empty string and the list
95 * is NULL, we have a match
97 if (!p1
&& (!str_ptr
|| !*str_ptr
))
103 lxc_list_for_each(it1
, p1
) {
104 if (strncmp(it1
->elem
, str_ptr
, strlen(it1
->elem
)) == 0)
111 /* This is a variation of get_list below it. This version allows two additional
112 * features. If a list is passed to it, it adds to it. It allows for empty
113 * entries (i.e. "group1,,group2") generating and empty list entry.
115 static struct lxc_list
*accumulate_list(char *input
, char *delimiter
,
116 struct lxc_list
*str_list
)
118 char *workstr
= NULL
;
119 char *workptr
= NULL
;
120 char *next_ptr
= NULL
;
121 struct lxc_list
*worklist
;
122 struct lxc_list
*workstr_list
;
124 workstr
= strdup(input
);
128 workstr_list
= str_list
;
130 workstr_list
= malloc(sizeof(*workstr_list
));
136 lxc_list_init(workstr_list
);
139 for (workptr
= workstr
; workptr
; workptr
= next_ptr
) {
140 /* We can't use strtok_r here because it collapses multiple
141 * delimiters into 1 making empty fields impossible...
143 next_ptr
= strchr(workptr
, *delimiter
);
147 /* At this point, we'd like to check to see if this group is
148 * already contained in the list and ignore it if it is... This
149 * also helps us with any corner cases where a string begins or
150 * ends with a delimiter.
152 if (list_contains_entry(workptr
, workstr_list
)) {
154 ERROR("Duplicate group \"%s\" in list - ignoring", workptr
);
156 ERROR("Duplicate NULL group in list - ignoring");
158 worklist
= malloc(sizeof(*worklist
));
162 worklist
->elem
= strdup(workptr
);
163 if (!worklist
->elem
) {
168 lxc_list_add_tail(workstr_list
, worklist
);
177 static struct lxc_list
*get_list(char *input
, char *delimiter
)
179 char *workstr
= NULL
;
181 struct lxc_list
*worklist
;
182 struct lxc_list
*workstr_list
;
184 workstr_list
= malloc(sizeof(*workstr_list
));
188 lxc_list_init(workstr_list
);
190 workstr
= strdup(input
);
196 lxc_iterate_parts(token
, workstr
, delimiter
) {
197 worklist
= malloc(sizeof(*worklist
));
201 worklist
->elem
= strdup(token
);
202 if (!worklist
->elem
) {
207 lxc_list_add_tail(workstr_list
, worklist
);
215 static struct lxc_list
*get_config_list(struct lxc_container
*c
, char *key
)
219 struct lxc_list
*config_list
= NULL
;
221 len
= c
->get_config_item(c
, key
, NULL
, 0);
225 value
= (char *)malloc(sizeof(char) * len
+ 1);
229 if (c
->get_config_item(c
, key
, value
, len
+ 1) != len
) {
234 if (strlen(value
) == 0) {
239 config_list
= get_list(value
, "\n");
245 static int get_config_integer(struct lxc_container
*c
, char *key
)
247 int len
= 0, ret
= 0;
250 len
= c
->get_config_item(c
, key
, NULL
, 0);
254 value
= (char *)malloc(sizeof(char) * len
+ 1);
258 if (c
->get_config_item(c
, key
, value
, len
+ 1) != len
) {
263 if (lxc_safe_int(value
, &ret
) < 0)
264 printf("Could not parse config item.\n");
271 static int cmporder(const void *p1
, const void *p2
)
273 struct lxc_container
*c1
= *(struct lxc_container
**)p1
;
274 struct lxc_container
*c2
= *(struct lxc_container
**)p2
;
276 int c1_order
= get_config_integer(c1
, "lxc.start.order");
277 int c2_order
= get_config_integer(c2
, "lxc.start.order");
279 if (c1_order
== c2_order
)
280 return strncmp(c1
->name
, c2
->name
, strlen(c1
->name
));
282 return (c1_order
- c2_order
);
285 static int toss_list(struct lxc_list
*c_groups_list
)
287 struct lxc_list
*it
, *next
;
292 lxc_list_for_each_safe(it
, c_groups_list
, next
) {
302 int main(int argc
, char *argv
[])
304 int count
= 0, failed
= 0, i
= 0, ret
= 0;
305 struct lxc_list
*cmd_group
;
306 struct lxc_container
**containers
= NULL
;
307 struct lxc_list
**c_groups_lists
= NULL
;
310 if (lxc_arguments_parse(&my_args
, argc
, argv
))
313 /* Only create log if explicitly instructed */
314 if (my_args
.log_file
|| my_args
.log_priority
) {
315 log
.name
= my_args
.name
;
316 log
.file
= my_args
.log_file
;
317 log
.level
= my_args
.log_priority
;
318 log
.prefix
= my_args
.progname
;
319 log
.quiet
= my_args
.quiet
;
320 log
.lxcpath
= my_args
.lxcpath
[0];
322 if (lxc_log_init(&log
))
326 count
= list_defined_containers(my_args
.lxcpath
[0], NULL
, &containers
);
331 /* Allocate an array for our container group lists */
333 c_groups_lists
= calloc( count
, sizeof( struct lxc_list
* ) );
335 qsort(&containers
[0], count
, sizeof(struct lxc_container
*), cmporder
);
337 if (cmd_groups_list
&& my_args
.all
)
338 ERROR("Specifying -a (all) with -g (groups) doesn't make sense. All option overrides");
340 /* We need a default cmd_groups_list even for the -a
341 * case in order to force a pass through the loop for
342 * the NULL group. This, someday, could be taken from
343 * a config file somewhere...
345 if (!cmd_groups_list
)
346 cmd_groups_list
= accumulate_list( "" , ",", NULL
);
349 lxc_list_for_each(cmd_group
, cmd_groups_list
) {
350 /* Because we may take several passes through the container list
351 * We'll switch on if the container pointer is NULL and if we
352 * process a container (run it or decide to ignore it) and call
353 * lxc_container_put then we'll NULL it out and not check it
356 for (i
= 0; i
< count
; i
++) {
357 struct lxc_container
*c
= containers
[i
];
360 /* Skip - must have been already processed */
363 /* We haven't loaded the container groups yet so these
364 * next two checks don't need to free them if they fail.
365 * They'll fail on the first pass.
367 if (!c
->may_control(c
)) {
368 /* We're done with this container */
369 if (lxc_container_put(c
) > 0)
370 containers
[i
] = NULL
;
375 if (!my_args
.ignore_auto
&&
376 get_config_integer(c
, "lxc.start.auto") != 1) {
377 /* We're done with this container */
378 if (lxc_container_put(c
) > 0)
379 containers
[i
] = NULL
;
385 /* Filter by group */
386 if (!c_groups_lists
[i
]) {
387 /* Now we're loading up a container's groups */
388 c_groups_lists
[i
] = get_config_list(c
, "lxc.group");
391 ret
= list_contains_entry(cmd_group
->elem
, c_groups_lists
[i
]);
393 /* Not in the target group this pass so
394 * leave in the list for subsequent
401 /* We have a candidate container to process */
402 c
->want_daemonize(c
, 1);
404 if (my_args
.shutdown
) {
405 /* Shutdown the container */
406 if (c
->is_running(c
)) {
408 printf("%s\n", c
->name
);
412 if (!c
->shutdown(c
, my_args
.timeout
)) {
415 ERROR("Error shutting down container: %s", c
->name
);
420 } else if (my_args
.hardstop
) {
421 /* Kill the container */
422 if (c
->is_running(c
)) {
424 printf("%s\n", c
->name
);
430 ERROR("Error killing container: %s", c
->name
);
434 } else if (my_args
.reboot
) {
435 /* Reboot the container */
436 if (c
->is_running(c
)) {
438 printf("%s %d\n", c
->name
,
439 get_config_integer(c
, "lxc.start.delay"));
445 ERROR("Error rebooting container: %s", c
->name
);
447 sleep(get_config_integer(c
, "lxc.start.delay"));
452 /* Start the container */
453 if (!c
->is_running(c
)) {
455 printf("%s %d\n", c
->name
,
456 get_config_integer(c
, "lxc.start.delay"));
460 if (!c
->start(c
, 0, NULL
)) {
462 ERROR("Error starting container: %s", c
->name
);
464 sleep(get_config_integer(c
, "lxc.start.delay"));
471 * If we get this far and we haven't hit any skip "continue"
472 * then we're done with this container... We can dump any
473 * c_groups_list and the container itself.
475 if (lxc_container_put(c
) > 0)
476 containers
[i
] = NULL
;
478 if (c_groups_lists
) {
479 toss_list(c_groups_lists
[i
]);
480 c_groups_lists
[i
] = NULL
;
486 /* clean up any lingering detritus, if container exists here
487 * then it must have failed to start.
489 for (i
= 0; i
< count
; i
++) {
491 lxc_container_put(containers
[i
]);
492 if (c_groups_lists
&& c_groups_lists
[i
])
493 toss_list(c_groups_lists
[i
]);
496 free(c_groups_lists
);
497 toss_list(cmd_groups_list
);
501 exit(EXIT_FAILURE
); /* Total failure */
503 exit(2); /* Partial failure */