]>
Commit | Line | Data |
---|---|---|
5e97c3fc | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Daniel Lezcano <dlezcano at fr.ibm.com> | |
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 | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | #include <stdio.h> | |
0ad19a3f | 24 | #include <string.h> |
25 | #include <fcntl.h> | |
26 | #include <errno.h> | |
5e97c3fc | 27 | #include <unistd.h> |
5e97c3fc | 28 | #include <sys/types.h> |
90b59fd0 | 29 | #include <sys/socket.h> |
0ad19a3f | 30 | #include <sys/param.h> |
31 | #include <sys/stat.h> | |
32 | #include <sys/file.h> | |
5e97c3fc | 33 | |
72d0e1cb | 34 | #include <lxc/lxc.h> |
36eb9bde | 35 | #include <lxc/log.h> |
00b3c2e2 | 36 | #include <lxc/start.h> |
108ed092 | 37 | #include <lxc/cgroup.h> |
72d0e1cb | 38 | #include <lxc/monitor.h> |
e98fe68b | 39 | #include "commands.h" |
881450bb | 40 | #include "config.h" |
36eb9bde CLG |
41 | |
42 | lxc_log_define(lxc_state, lxc); | |
0ad19a3f | 43 | |
44 | static char *strstate[] = { | |
45 | "STOPPED", "STARTING", "RUNNING", "STOPPING", | |
fa082227 | 46 | "ABORTING", "FREEZING", "FROZEN", "THAWED", |
0ad19a3f | 47 | }; |
48 | ||
49 | const char *lxc_state2str(lxc_state_t state) | |
50 | { | |
51 | if (state < STOPPED || state > MAX_STATE - 1) | |
52 | return NULL; | |
53 | return strstate[state]; | |
54 | } | |
5e97c3fc | 55 | |
0ad19a3f | 56 | lxc_state_t lxc_str2state(const char *state) |
5e97c3fc | 57 | { |
0ad19a3f | 58 | int i, len; |
59 | len = sizeof(strstate)/sizeof(strstate[0]); | |
60 | for (i = 0; i < len; i++) | |
61 | if (!strcmp(strstate[i], state)) | |
62 | return i; | |
3ab87b66 | 63 | |
439358bf | 64 | ERROR("invalid state '%s'", state); |
0ad19a3f | 65 | return -1; |
5e97c3fc | 66 | } |
67 | ||
0ad19a3f | 68 | static int freezer_state(const char *name) |
69 | { | |
fa082227 | 70 | char *nsgroup; |
0ad19a3f | 71 | char freezer[MAXPATHLEN]; |
72 | char status[MAXPATHLEN]; | |
73 | FILE *file; | |
74 | int err; | |
35d2c3e7 | 75 | |
bcbd102c | 76 | err = lxc_cgroup_path_get(&nsgroup, "freezer", name); |
fa082227 MN |
77 | if (err) |
78 | return -1; | |
79 | ||
9ba8130c SH |
80 | err = snprintf(freezer, MAXPATHLEN, "%s/freezer.state", nsgroup); |
81 | if (err < 0 || err >= MAXPATHLEN) | |
82 | return -1; | |
0ad19a3f | 83 | |
84 | file = fopen(freezer, "r"); | |
85 | if (!file) | |
86 | return -1; | |
87 | ||
88 | err = fscanf(file, "%s", status); | |
89 | fclose(file); | |
90 | ||
91 | if (err == EOF) { | |
36eb9bde | 92 | SYSERROR("failed to read %s", freezer); |
0ad19a3f | 93 | return -1; |
94 | } | |
95 | ||
96 | return lxc_str2state(status); | |
97 | } | |
98 | ||
fa082227 | 99 | static lxc_state_t __lxc_getstate(const char *name) |
e98fe68b DL |
100 | { |
101 | struct lxc_command command = { | |
102 | .request = { .type = LXC_COMMAND_STATE }, | |
103 | }; | |
104 | ||
d97b36f8 DL |
105 | int ret, stopped = 0; |
106 | ||
107 | ret = lxc_command(name, &command, &stopped); | |
108 | if (ret < 0 && stopped) | |
109 | return STOPPED; | |
e98fe68b | 110 | |
e98fe68b DL |
111 | if (ret < 0) { |
112 | ERROR("failed to send command"); | |
113 | return -1; | |
114 | } | |
115 | ||
116 | if (!ret) { | |
117 | WARN("'%s' has stopped before sending its state", name); | |
118 | return -1; | |
119 | } | |
120 | ||
121 | if (command.answer.ret < 0) { | |
122 | ERROR("failed to get state for '%s': %s", | |
123 | name, strerror(-command.answer.ret)); | |
124 | return -1; | |
125 | } | |
126 | ||
127 | DEBUG("'%s' is in '%s' state", name, lxc_state2str(command.answer.ret)); | |
128 | ||
129 | return command.answer.ret; | |
130 | } | |
131 | ||
fa082227 | 132 | lxc_state_t lxc_getstate(const char *name) |
0ad19a3f | 133 | { |
134 | int state = freezer_state(name); | |
135 | if (state != FROZEN && state != FREEZING) | |
fa082227 | 136 | state = __lxc_getstate(name); |
0ad19a3f | 137 | return state; |
138 | } | |
e98fe68b DL |
139 | |
140 | /*---------------------------------------------------------------------------- | |
141 | * functions used by lxc-start mainloop | |
142 | * to handle above command request. | |
143 | *--------------------------------------------------------------------------*/ | |
144 | extern int lxc_state_callback(int fd, struct lxc_request *request, | |
145 | struct lxc_handler *handler) | |
146 | { | |
147 | struct lxc_answer answer; | |
148 | int ret; | |
149 | ||
150 | answer.ret = handler->state; | |
151 | ||
152 | ret = send(fd, &answer, sizeof(answer), 0); | |
153 | if (ret < 0) { | |
154 | WARN("failed to send answer to the peer"); | |
155 | goto out; | |
156 | } | |
157 | ||
158 | if (ret != sizeof(answer)) { | |
159 | ERROR("partial answer sent"); | |
160 | goto out; | |
161 | } | |
162 | ||
163 | out: | |
164 | return ret; | |
165 | } | |
166 | ||
72d0e1cb SG |
167 | static int fillwaitedstates(char *strstates, int *states) |
168 | { | |
169 | char *token, *saveptr = NULL; | |
170 | int state; | |
171 | ||
172 | token = strtok_r(strstates, "|", &saveptr); | |
173 | while (token) { | |
174 | ||
175 | state = lxc_str2state(token); | |
176 | if (state < 0) | |
177 | return -1; | |
178 | ||
179 | states[state] = 1; | |
180 | ||
181 | token = strtok_r(NULL, "|", &saveptr); | |
182 | } | |
183 | return 0; | |
184 | } | |
185 | ||
186 | extern int lxc_wait(char *lxcname, char *states, int timeout) | |
187 | { | |
188 | struct lxc_msg msg; | |
189 | int state, ret; | |
190 | int s[MAX_STATE] = { }, fd; | |
191 | ||
192 | if (fillwaitedstates(states, s)) | |
193 | return -1; | |
194 | ||
195 | fd = lxc_monitor_open(); | |
196 | if (fd < 0) | |
197 | return -1; | |
198 | ||
199 | /* | |
200 | * if container present, | |
201 | * then check if already in requested state | |
202 | */ | |
203 | ret = -1; | |
204 | state = lxc_getstate(lxcname); | |
205 | if (state < 0) { | |
206 | goto out_close; | |
207 | } else if ((state >= 0) && (s[state])) { | |
208 | ret = 0; | |
209 | goto out_close; | |
210 | } | |
211 | ||
212 | for (;;) { | |
213 | int elapsed_time, curtime; | |
214 | struct timeval tv; | |
215 | int stop = 0; | |
216 | int retval; | |
217 | ||
218 | if (timeout != -1) { | |
219 | retval = gettimeofday(&tv, NULL); | |
220 | if (retval) | |
221 | goto out_close; | |
222 | curtime = tv.tv_sec; | |
223 | } | |
224 | if (lxc_monitor_read_timeout(fd, &msg, timeout) < 0) | |
225 | goto out_close; | |
226 | ||
227 | if (timeout != -1) { | |
228 | retval = gettimeofday(&tv, NULL); | |
229 | if (retval) | |
230 | goto out_close; | |
231 | elapsed_time = tv.tv_sec - curtime; | |
232 | if (timeout - elapsed_time <= 0) | |
233 | stop = 1; | |
234 | timeout -= elapsed_time; | |
235 | } | |
236 | ||
237 | if (strcmp(lxcname, msg.name)) { | |
238 | if (stop) { | |
239 | ret = -2; | |
240 | goto out_close; | |
241 | } | |
242 | continue; | |
243 | } | |
244 | ||
245 | switch (msg.type) { | |
246 | case lxc_msg_state: | |
247 | if (msg.value < 0 || msg.value >= MAX_STATE) { | |
248 | ERROR("Receive an invalid state number '%d'", | |
249 | msg.value); | |
250 | goto out_close; | |
251 | } | |
252 | ||
253 | if (s[msg.value]) { | |
254 | ret = 0; | |
255 | goto out_close; | |
256 | } | |
257 | break; | |
258 | default: | |
259 | if (stop) { | |
260 | ret = -2; | |
261 | goto out_close; | |
262 | } | |
263 | /* just ignore garbage */ | |
264 | break; | |
265 | } | |
266 | } | |
267 | ||
268 | out_close: | |
269 | lxc_monitor_close(fd); | |
270 | return ret; | |
271 | } |