]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_autostart.c
lxc-autostart: Add a new --ignore-auto/-A flag
[mirror_lxc.git] / src / lxc / lxc_autostart.c
CommitLineData
a6adab20
SG
1/* lxc_autostart
2 *
3 * Copyright © 2013 Stéphane Graber <stgraber@ubuntu.com>
4 * Copyright © 2013 Canonical Ltd.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <string.h>
22#include <unistd.h>
23
24#include <lxc/lxccontainer.h>
25
26#include "arguments.h"
27#include "list.h"
28#include "log.h"
29
6ea518f6
SG
30lxc_log_define(lxc_autostart_ui, lxc);
31
a6adab20
SG
32static int my_parser(struct lxc_arguments* args, int c, char* arg)
33{
34 switch (c) {
35 case 'k': args->hardstop = 1; break;
36 case 'L': args->list = 1; break;
37 case 'r': args->reboot = 1; break;
38 case 's': args->shutdown = 1; break;
39 case 'a': args->all = 1; break;
e582991f 40 case 'A': args->ignore_auto = 1; break;
a6adab20
SG
41 case 'g': args->groups = arg; break;
42 case 't': args->timeout = atoi(arg); break;
43 }
44 return 0;
45}
46
47static const struct option my_longopts[] = {
48 {"kill", no_argument, 0, 'k'},
49 {"list", no_argument, 0, 'L'},
50 {"reboot", no_argument, 0, 'r'},
51 {"shutdown", no_argument, 0, 's'},
52 {"all", no_argument, 0, 'a'},
e582991f 53 {"ignore-auto", no_argument, 0, 'A'},
a6adab20
SG
54 {"groups", required_argument, 0, 'g'},
55 {"timeout", required_argument, 0, 't'},
56 {"help", no_argument, 0, 'h'},
57 LXC_COMMON_OPTIONS
58};
59
60static struct lxc_arguments my_args = {
61 .progname = "lxc-autostart",
62 .help = "\
63\n\
64lxc-autostart managed auto-started containers\n\
65\n\
66Options:\n\
67 -k, --kill kill the containers instead of starting them\n\
68 -L, --list list all affected containers and wait delay\n\
69 -r, --reboot reboot the containers instead of starting them\n\
70 -s, --shutdown shutdown the containers instead of starting them\n\
71\n\
72 -a, --all list all auto-started containers (ignore groups)\n\
e582991f 73 -A, --ignore-auto ignore lxc.start.auto and select all matching containers\n\
a6adab20
SG
74 -g, --groups list of groups (comma separated) to select\n\
75 -t, --timeout=T wait T seconds before hard-stopping\n",
76 .options = my_longopts,
77 .parser = my_parser,
78 .checker = NULL,
a771fe18 79 .timeout = 60,
a6adab20
SG
80};
81
82int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
83 struct lxc_list *it1;
84 struct lxc_list *it2;
85
86 if (!p1 && !p2)
87 return 1;
88
89 if (!p1)
90 return 0;
91
92 if (!p2)
93 return 0;
94
95 lxc_list_for_each(it1, p1) {
96 lxc_list_for_each(it2, p2) {
97 if (strcmp(it1->elem, it2->elem) == 0)
98 return 1;
99 }
100 }
101
102 return 0;
103}
104
74a3920a 105static struct lxc_list *get_list(char *input, char *delimiter) {
a6adab20
SG
106 char *workstr = NULL;
107 char *workptr = NULL;
108 char *sptr = NULL;
109 char *token = NULL;
110 struct lxc_list *worklist;
111 struct lxc_list *workstr_list;
112
113 workstr_list = malloc(sizeof(*workstr_list));
114 lxc_list_init(workstr_list);
115
116 workstr = strdup(input);
f75b4de0
SG
117 if (!workstr) {
118 free(workstr_list);
a6adab20 119 return NULL;
f75b4de0 120 }
a6adab20
SG
121
122 for (workptr = workstr;;workptr = NULL) {
123 token = strtok_r(workptr, delimiter, &sptr);
124 if (!token) {
125 break;
126 }
127
128 worklist = malloc(sizeof(*worklist));
129 if (!worklist)
130 break;
131
132 worklist->elem = strdup(token);
133 if (!worklist->elem) {
134 free(worklist);
135 break;
136 }
137
138 lxc_list_add_tail(workstr_list, worklist);
139 }
140
141 free(workstr);
142
143 return workstr_list;
144}
145
74a3920a 146static struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
a6adab20
SG
147 int len = 0;
148 char* value = NULL;
149 struct lxc_list *config_list = NULL;
150
151 len = c->get_config_item(c, key, NULL, 0);
152 if (len < 0)
153 return NULL;
154
155 value = (char*) malloc(sizeof(char)*len + 1);
156 if (value == NULL)
157 return NULL;
158
159 if (c->get_config_item(c, key, value, len + 1) != len) {
160 free(value);
161 return NULL;
162 }
163
164 if (strlen(value) == 0) {
165 free(value);
166 return NULL;
167 }
168
169 config_list = get_list(value, "\n");
170 free(value);
171
172 return config_list;
173}
174
74a3920a 175static int get_config_integer(struct lxc_container *c, char *key) {
a6adab20
SG
176 int len = 0;
177 int ret = 0;
178 char* value = NULL;
179
180 len = c->get_config_item(c, key, NULL, 0);
181 if (len < 0)
182 return 0;
183
184 value = (char*) malloc(sizeof(char)*len + 1);
185 if (value == NULL)
186 return 0;
187
188 if (c->get_config_item(c, key, value, len + 1) != len) {
189 free(value);
190 return 0;
191 }
192
193 ret = atoi(value);
194 free(value);
195
196 return ret;
197}
198
199static int cmporder(const void *p1, const void *p2) {
200 struct lxc_container *c1 = *(struct lxc_container **)p1;
201 struct lxc_container *c2 = *(struct lxc_container **)p2;
202
203 int c1_order = get_config_integer(c1, "lxc.start.order");
204 int c2_order = get_config_integer(c2, "lxc.start.order");
205
206 if (c1_order == c2_order)
207 return strcmp(c1->name, c2->name);
208 else
209 return (c1_order - c2_order) * -1;
210}
211
212int main(int argc, char *argv[])
213{
214 int count = 0;
215 int i = 0;
216 int ret = 0;
217 struct lxc_container **containers = NULL;
218 struct lxc_list *cmd_groups_list = NULL;
219 struct lxc_list *c_groups_list = NULL;
220 struct lxc_list *it, *next;
221 char *const default_start_args[] = {
222 "/sbin/init",
223 '\0',
224 };
225
226 if (lxc_arguments_parse(&my_args, argc, argv))
227 return 1;
228
6ea518f6
SG
229 if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
230 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
231 return 1;
232 lxc_log_options_no_override();
233
a6adab20
SG
234 count = list_defined_containers(NULL, NULL, &containers);
235
236 if (count < 0)
237 return 1;
238
239 qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
240
241 if (my_args.groups && !my_args.all)
242 cmd_groups_list = get_list((char*)my_args.groups, ",");
243
244 for (i = 0; i < count; i++) {
245 struct lxc_container *c = containers[i];
246
247 if (!c->may_control(c)) {
248 lxc_container_put(c);
249 continue;
250 }
251
e582991f
SG
252 if (!my_args.ignore_auto &&
253 get_config_integer(c, "lxc.start.auto") != 1) {
a6adab20
SG
254 lxc_container_put(c);
255 continue;
256 }
257
258 if (!my_args.all) {
259 /* Filter by group */
260 c_groups_list = get_config_list(c, "lxc.group");
261
262 ret = lists_contain_common_entry(cmd_groups_list, c_groups_list);
263
264 if (c_groups_list) {
265 lxc_list_for_each_safe(it, c_groups_list, next) {
266 lxc_list_del(it);
267 free(it->elem);
268 free(it);
269 }
270 free(c_groups_list);
271 }
272
273 if (ret == 0) {
274 lxc_container_put(c);
275 continue;
276 }
277 }
278
279 c->want_daemonize(c, 1);
280
281 if (my_args.shutdown) {
282 /* Shutdown the container */
283 if (c->is_running(c)) {
284 if (my_args.list)
285 printf("%s\n", c->name);
286 else {
b8ac2750
SG
287 if (!c->shutdown(c, my_args.timeout)) {
288 if (!c->stop(c)) {
289 fprintf(stderr, "Error shutting down container: %s\n", c->name);
290 }
291 }
a6adab20
SG
292 }
293 }
294 }
295 else if (my_args.hardstop) {
296 /* Kill the container */
297 if (c->is_running(c)) {
298 if (my_args.list)
299 printf("%s\n", c->name);
300 else {
301 if (!c->stop(c))
302 fprintf(stderr, "Error killing container: %s\n", c->name);
303 }
304 }
305 }
306 else if (my_args.reboot) {
307 /* Reboot the container */
308 if (c->is_running(c)) {
309 if (my_args.list)
310 printf("%s %d\n", c->name,
311 get_config_integer(c, "lxc.start.delay"));
312 else {
313 if (!c->reboot(c))
314 fprintf(stderr, "Error rebooting container: %s\n", c->name);
315 else
316 sleep(get_config_integer(c, "lxc.start.delay"));
317 }
318 }
319 }
320 else {
321 /* Start the container */
322 if (!c->is_running(c)) {
323 if (my_args.list)
324 printf("%s %d\n", c->name,
325 get_config_integer(c, "lxc.start.delay"));
326 else {
327 if (!c->start(c, 0, default_start_args))
328 fprintf(stderr, "Error starting container: %s\n", c->name);
329 else
330 sleep(get_config_integer(c, "lxc.start.delay"));
331 }
332 }
333 }
334
335
336 lxc_container_put(c);
337 }
338
339 if (cmd_groups_list) {
340 lxc_list_for_each_safe(it, cmd_groups_list, next) {
341 lxc_list_del(it);
342 free(it->elem);
343 free(it);
344 }
345 free(cmd_groups_list);
346 }
347
348 free(containers);
349
350 return 0;
351}