]>
Commit | Line | Data |
---|---|---|
5e97c3fc | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
9afe19d6 | 7 | * Daniel Lezcano <daniel.lezcano at free.fr> |
5e97c3fc | 8 | * |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
250b1eec | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
5e97c3fc | 22 | */ |
23 | #include <stdio.h> | |
24 | #include <libgen.h> | |
25 | #include <unistd.h> | |
26 | #include <sys/types.h> | |
27 | ||
b113348e | 28 | #include <lxc/lxc.h> |
00b3c2e2 CLG |
29 | #include <lxc/log.h> |
30 | ||
3e625e2d | 31 | #include <lxc/lxccontainer.h> |
4237c6ca | 32 | #include "arguments.h" |
ef6e34ee | 33 | #include "commands.h" |
67e571de | 34 | #include "utils.h" |
5e97c3fc | 35 | |
3e625e2d SH |
36 | static int my_parser(struct lxc_arguments* args, int c, char* arg) |
37 | { | |
38 | switch (c) { | |
39 | case 'r': args->reboot = 1; break; | |
40 | case 'W': args->nowait = 1; break; | |
41 | case 't': args->timeout = atoi(arg); break; | |
42 | case 'k': args->hardstop = 1; break; | |
43 | case 's': args->shutdown = 1; break; | |
44 | } | |
45 | return 0; | |
46 | } | |
47 | ||
4237c6ca | 48 | static const struct option my_longopts[] = { |
3e625e2d SH |
49 | {"reboot", no_argument, 0, 'r'}, |
50 | {"nowait", no_argument, 0, 'W'}, | |
51 | {"timeout", required_argument, 0, 't'}, | |
52 | {"kill", no_argument, 0, 'k'}, | |
53 | {"shutdown", no_argument, 0, 's'}, | |
4237c6ca MN |
54 | LXC_COMMON_OPTIONS |
55 | }; | |
56 | ||
57 | static struct lxc_arguments my_args = { | |
58 | .progname = "lxc-stop", | |
59 | .help = "\ | |
60 | --name=NAME\n\ | |
61 | \n\ | |
62 | lxc-stop stops a container with the identifier NAME\n\ | |
63 | \n\ | |
64 | Options :\n\ | |
3e625e2d SH |
65 | -n, --name=NAME NAME for name of the container\n\ |
66 | -r, --reboot reboot the container\n\ | |
67 | -W, --nowait don't wait for shutdown or reboot to complete\n\ | |
68 | -t, --timeout=T wait T seconds before hard-stopping\n\ | |
69 | -k, --kill kill container rather than request clean shutdown\n\ | |
70 | -s, --shutdown Only request clean shutdown, don't later force kill\n", | |
4237c6ca | 71 | .options = my_longopts, |
3e625e2d | 72 | .parser = my_parser, |
4237c6ca | 73 | .checker = NULL, |
3e625e2d | 74 | .timeout = 60, |
4237c6ca | 75 | }; |
5e97c3fc | 76 | |
3e625e2d SH |
77 | /* returns -1 on failure, 0 on success */ |
78 | int do_reboot_and_check(struct lxc_arguments *a, struct lxc_container *c) | |
79 | { | |
80 | int ret; | |
81 | pid_t pid; | |
82 | pid_t newpid; | |
83 | int timeout = a->timeout; | |
84 | ||
85 | pid = c->init_pid(c); | |
86 | if (pid == -1) | |
87 | return -1; | |
88 | if (!c->reboot(c)) | |
89 | return -1; | |
90 | if (a->nowait) | |
91 | return 0; | |
92 | if (timeout <= 0) | |
93 | goto out; | |
94 | ||
95 | for (;;) { | |
96 | /* can we use c-> wait for this, assuming it will | |
97 | * re-enter RUNNING? For now just sleep */ | |
98 | int elapsed_time, curtime = 0; | |
99 | struct timeval tv; | |
100 | ||
101 | newpid = c->init_pid(c); | |
102 | if (newpid != -1 && newpid != pid) | |
103 | return 0; | |
104 | ||
105 | ret = gettimeofday(&tv, NULL); | |
106 | if (ret) | |
107 | break; | |
108 | curtime = tv.tv_sec; | |
109 | ||
110 | sleep(1); | |
111 | ret = gettimeofday(&tv, NULL); | |
112 | if (ret) | |
113 | break; | |
114 | elapsed_time = tv.tv_sec - curtime; | |
115 | if (timeout - elapsed_time <= 0) | |
116 | break; | |
117 | timeout -= elapsed_time; | |
118 | } | |
119 | ||
120 | out: | |
121 | newpid = c->init_pid(c); | |
122 | if (newpid == -1 || newpid == pid) { | |
123 | printf("Reboot did not complete before timeout\n"); | |
124 | return -1; | |
125 | } | |
126 | return 0; | |
127 | } | |
128 | ||
5e97c3fc | 129 | int main(int argc, char *argv[]) |
130 | { | |
3e625e2d SH |
131 | struct lxc_container *c; |
132 | bool s; | |
b93aac46 | 133 | int ret = 1; |
3e625e2d | 134 | |
23075e69 | 135 | if (lxc_arguments_parse(&my_args, argc, argv)) |
b93aac46 | 136 | return 1; |
5e97c3fc | 137 | |
5e1e7aaf | 138 | if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority, |
8d06bd13 | 139 | my_args.progname, my_args.quiet, my_args.lxcpath[0])) |
b93aac46 | 140 | return 1; |
5e97c3fc | 141 | |
3e625e2d SH |
142 | c = lxc_container_new(my_args.name, my_args.lxcpath[0]); |
143 | if (!c) { | |
144 | fprintf(stderr, "Error opening container\n"); | |
145 | goto out; | |
146 | } | |
147 | ||
148 | if (!c->is_running(c)) { | |
149 | fprintf(stderr, "%s is not running\n", c->name); | |
b93aac46 | 150 | ret = 2; |
3e625e2d SH |
151 | goto out; |
152 | } | |
153 | ||
154 | if (my_args.hardstop) { | |
b93aac46 | 155 | ret = c->stop(c) ? 0 : 1; |
3e625e2d SH |
156 | goto out; |
157 | } | |
158 | if (my_args.reboot) { | |
159 | ret = do_reboot_and_check(&my_args, c); | |
160 | goto out; | |
161 | } | |
162 | ||
163 | s = c->shutdown(c, my_args.timeout); | |
164 | if (!s) { | |
165 | if (!my_args.shutdown) | |
b93aac46 | 166 | ret = c->wait(c, "STOPPED", -1) ? 0 : 1; |
3e625e2d | 167 | else |
b93aac46 | 168 | ret = 1; // fail |
54b79829 SH |
169 | } else |
170 | ret = 0; | |
3e625e2d SH |
171 | |
172 | out: | |
173 | lxc_container_put(c); | |
174 | return ret; | |
5e97c3fc | 175 | } |