]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_autostart.c
lxc-autostart: don't set timeout if user requested -s
[mirror_lxc.git] / src / lxc / lxc_autostart.c
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
30 static int my_parser(struct lxc_arguments* args, int c, char* arg)
31 {
32 switch (c) {
33 case 'k': args->hardstop = 1; break;
34 case 'L': args->list = 1; break;
35 case 'r': args->reboot = 1; break;
36 case 's': args->shutdown = 1; break;
37 case 'a': args->all = 1; break;
38 case 'g': args->groups = arg; break;
39 case 't': args->timeout = atoi(arg); break;
40 }
41 return 0;
42 }
43
44 static const struct option my_longopts[] = {
45 {"kill", no_argument, 0, 'k'},
46 {"list", no_argument, 0, 'L'},
47 {"reboot", no_argument, 0, 'r'},
48 {"shutdown", no_argument, 0, 's'},
49 {"all", no_argument, 0, 'a'},
50 {"groups", required_argument, 0, 'g'},
51 {"timeout", required_argument, 0, 't'},
52 {"help", no_argument, 0, 'h'},
53 LXC_COMMON_OPTIONS
54 };
55
56 static struct lxc_arguments my_args = {
57 .progname = "lxc-autostart",
58 .help = "\
59 \n\
60 lxc-autostart managed auto-started containers\n\
61 \n\
62 Options:\n\
63 -k, --kill kill the containers instead of starting them\n\
64 -L, --list list all affected containers and wait delay\n\
65 -r, --reboot reboot the containers instead of starting them\n\
66 -s, --shutdown shutdown the containers instead of starting them\n\
67 \n\
68 -a, --all list all auto-started containers (ignore groups)\n\
69 -g, --groups list of groups (comma separated) to select\n\
70 -t, --timeout=T wait T seconds before hard-stopping\n",
71 .options = my_longopts,
72 .parser = my_parser,
73 .checker = NULL,
74 .timeout = 30,
75 };
76
77 int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
78 struct lxc_list *it1;
79 struct lxc_list *it2;
80
81 if (!p1 && !p2)
82 return 1;
83
84 if (!p1)
85 return 0;
86
87 if (!p2)
88 return 0;
89
90 lxc_list_for_each(it1, p1) {
91 lxc_list_for_each(it2, p2) {
92 if (strcmp(it1->elem, it2->elem) == 0)
93 return 1;
94 }
95 }
96
97 return 0;
98 }
99
100 struct lxc_list *get_list(char *input, char *delimiter) {
101 char *workstr = NULL;
102 char *workptr = NULL;
103 char *sptr = NULL;
104 char *token = NULL;
105 struct lxc_list *worklist;
106 struct lxc_list *workstr_list;
107
108 workstr_list = malloc(sizeof(*workstr_list));
109 lxc_list_init(workstr_list);
110
111 workstr = strdup(input);
112 if (!workstr) {
113 free(workstr_list);
114 return NULL;
115 }
116
117 for (workptr = workstr;;workptr = NULL) {
118 token = strtok_r(workptr, delimiter, &sptr);
119 if (!token) {
120 break;
121 }
122
123 worklist = malloc(sizeof(*worklist));
124 if (!worklist)
125 break;
126
127 worklist->elem = strdup(token);
128 if (!worklist->elem) {
129 free(worklist);
130 break;
131 }
132
133 lxc_list_add_tail(workstr_list, worklist);
134 }
135
136 free(workstr);
137
138 return workstr_list;
139 }
140
141 struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
142 int len = 0;
143 char* value = NULL;
144 struct lxc_list *config_list = NULL;
145
146 len = c->get_config_item(c, key, NULL, 0);
147 if (len < 0)
148 return NULL;
149
150 value = (char*) malloc(sizeof(char)*len + 1);
151 if (value == NULL)
152 return NULL;
153
154 if (c->get_config_item(c, key, value, len + 1) != len) {
155 free(value);
156 return NULL;
157 }
158
159 if (strlen(value) == 0) {
160 free(value);
161 return NULL;
162 }
163
164 config_list = get_list(value, "\n");
165 free(value);
166
167 return config_list;
168 }
169
170 int get_config_integer(struct lxc_container *c, char *key) {
171 int len = 0;
172 int ret = 0;
173 char* value = NULL;
174
175 len = c->get_config_item(c, key, NULL, 0);
176 if (len < 0)
177 return 0;
178
179 value = (char*) malloc(sizeof(char)*len + 1);
180 if (value == NULL)
181 return 0;
182
183 if (c->get_config_item(c, key, value, len + 1) != len) {
184 free(value);
185 return 0;
186 }
187
188 ret = atoi(value);
189 free(value);
190
191 return ret;
192 }
193
194 static int cmporder(const void *p1, const void *p2) {
195 struct lxc_container *c1 = *(struct lxc_container **)p1;
196 struct lxc_container *c2 = *(struct lxc_container **)p2;
197
198 int c1_order = get_config_integer(c1, "lxc.start.order");
199 int c2_order = get_config_integer(c2, "lxc.start.order");
200
201 if (c1_order == c2_order)
202 return strcmp(c1->name, c2->name);
203 else
204 return (c1_order - c2_order) * -1;
205 }
206
207 int main(int argc, char *argv[])
208 {
209 int count = 0;
210 int i = 0;
211 int ret = 0;
212 struct lxc_container **containers = NULL;
213 struct lxc_list *cmd_groups_list = NULL;
214 struct lxc_list *c_groups_list = NULL;
215 struct lxc_list *it, *next;
216 char *const default_start_args[] = {
217 "/sbin/init",
218 '\0',
219 };
220
221 if (lxc_arguments_parse(&my_args, argc, argv))
222 return 1;
223
224 count = list_defined_containers(NULL, NULL, &containers);
225
226 if (count < 0)
227 return 1;
228
229 qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
230
231 if (my_args.groups && !my_args.all)
232 cmd_groups_list = get_list((char*)my_args.groups, ",");
233
234 for (i = 0; i < count; i++) {
235 struct lxc_container *c = containers[i];
236
237 if (!c->may_control(c)) {
238 lxc_container_put(c);
239 continue;
240 }
241
242 if (get_config_integer(c, "lxc.start.auto") != 1) {
243 lxc_container_put(c);
244 continue;
245 }
246
247 if (!my_args.all) {
248 /* Filter by group */
249 c_groups_list = get_config_list(c, "lxc.group");
250
251 ret = lists_contain_common_entry(cmd_groups_list, c_groups_list);
252
253 if (c_groups_list) {
254 lxc_list_for_each_safe(it, c_groups_list, next) {
255 lxc_list_del(it);
256 free(it->elem);
257 free(it);
258 }
259 free(c_groups_list);
260 }
261
262 if (ret == 0) {
263 lxc_container_put(c);
264 continue;
265 }
266 }
267
268 c->want_daemonize(c, 1);
269
270 if (my_args.shutdown) {
271 /* Shutdown the container */
272 if (c->is_running(c)) {
273 if (my_args.list)
274 printf("%s\n", c->name);
275 else {
276 my_args.timeout = 0;
277 if (!c->shutdown(c, my_args.timeout))
278 fprintf(stderr, "Error shutting down container: %s\n", c->name);
279 }
280 }
281 }
282 else if (my_args.hardstop) {
283 /* Kill the container */
284 if (c->is_running(c)) {
285 if (my_args.list)
286 printf("%s\n", c->name);
287 else {
288 if (!c->stop(c))
289 fprintf(stderr, "Error killing container: %s\n", c->name);
290 }
291 }
292 }
293 else if (my_args.reboot) {
294 /* Reboot the container */
295 if (c->is_running(c)) {
296 if (my_args.list)
297 printf("%s %d\n", c->name,
298 get_config_integer(c, "lxc.start.delay"));
299 else {
300 if (!c->reboot(c))
301 fprintf(stderr, "Error rebooting container: %s\n", c->name);
302 else
303 sleep(get_config_integer(c, "lxc.start.delay"));
304 }
305 }
306 }
307 else {
308 /* Start the container */
309 if (!c->is_running(c)) {
310 if (my_args.list)
311 printf("%s %d\n", c->name,
312 get_config_integer(c, "lxc.start.delay"));
313 else {
314 if (!c->start(c, 0, default_start_args))
315 fprintf(stderr, "Error starting container: %s\n", c->name);
316 else
317 sleep(get_config_integer(c, "lxc.start.delay"));
318 }
319 }
320 }
321
322
323 lxc_container_put(c);
324 }
325
326 if (cmd_groups_list) {
327 lxc_list_for_each_safe(it, cmd_groups_list, next) {
328 lxc_list_del(it);
329 free(it->elem);
330 free(it);
331 }
332 free(cmd_groups_list);
333 }
334
335 free(containers);
336
337 return 0;
338 }