]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/commands.c
Fix race/corruption with multiple lxc-start, lxc-execute
[mirror_lxc.git] / src / lxc / commands.c
CommitLineData
724e753c
MN
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2009
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
24#include <stdio.h>
25#include <errno.h>
26#include <unistd.h>
27#include <signal.h>
91480a0f 28#include <fcntl.h>
724e753c
MN
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <sys/poll.h>
32#include <sys/param.h>
33
00b3c2e2
CLG
34#include <lxc/log.h>
35#include <lxc/conf.h>
36#include <lxc/start.h> /* for struct lxc_handler */
724e753c
MN
37
38#include "commands.h"
39#include "mainloop.h"
40#include "af_unix.h"
adaeaa99 41#include "config.h"
724e753c 42
ded1d23f
DL
43/*
44 * This file provides the different functions to have the client
45 * and the server to communicate
46 *
47 * Each command is transactional, the client send a request to
48 * the server and the server answer the request with a message
49 * giving the request's status (zero or a negative errno value).
50 *
51 * Each command is wrapped in a ancillary message in order to pass
52 * a credential making possible to the server to check if the client
53 * is allowed to ask for this command or not.
54 *
55 */
56
724e753c
MN
57lxc_log_define(lxc_commands, lxc);
58
adaeaa99 59#define abstractname LXCPATH "/%s/command"
ded1d23f 60
724e753c
MN
61static int receive_answer(int sock, struct lxc_answer *answer)
62{
63 int ret;
64
65 ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
66 if (ret < 0)
67 ERROR("failed to receive answer for the command");
68
69 return ret;
70}
71
43eb6f29
DL
72static int __lxc_command(const char *name, struct lxc_command *command,
73 int *stopped, int stay_connected)
724e753c 74{
724e753c 75 int sock, ret = -1;
46968ea3
DL
76 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
77 char *offset = &path[1];
9ba8130c 78 int rc, len;
724e753c 79
9ba8130c
SH
80 len = sizeof(path)-1;
81 rc = snprintf(offset, len, abstractname, name);
82 if (rc < 0 || rc >= len) {
83 ERROR("Name too long");
84 return -1;
85 }
724e753c 86
46968ea3 87 sock = lxc_af_unix_connect(path);
d97b36f8
DL
88 if (sock < 0 && errno == ECONNREFUSED) {
89 *stopped = 1;
90 return -1;
91 }
92
724e753c 93 if (sock < 0) {
d97b36f8 94 SYSERROR("failed to connect to '@%s'", offset);
724e753c
MN
95 return -1;
96 }
97
98 ret = lxc_af_unix_send_credential(sock, &command->request,
99 sizeof(command->request));
100 if (ret < 0) {
d97b36f8 101 SYSERROR("failed to send request to '@%s'", offset);
1362f2eb 102 goto out;
724e753c
MN
103 }
104
105 if (ret != sizeof(command->request)) {
d97b36f8 106 SYSERROR("message partially sent to '@%s'", offset);
1362f2eb 107 goto out;
724e753c
MN
108 }
109
110 ret = receive_answer(sock, &command->answer);
724e753c 111out:
43eb6f29
DL
112 if (!stay_connected || ret < 0)
113 close(sock);
114
1362f2eb 115 return ret;
724e753c
MN
116}
117
43eb6f29
DL
118extern int lxc_command(const char *name,
119 struct lxc_command *command, int *stopped)
120{
121 return __lxc_command(name, command, stopped, 0);
122}
123
124extern int lxc_command_connected(const char *name,
125 struct lxc_command *command, int *stopped)
126{
127 return __lxc_command(name, command, stopped, 1);
128}
129
130
26b2d152
MN
131pid_t get_init_pid(const char *name)
132{
133 struct lxc_command command = {
134 .request = { .type = LXC_COMMAND_PID },
135 };
136
137 int ret, stopped = 0;
138
139 ret = lxc_command(name, &command, &stopped);
ebdd307d 140 if (ret < 0 && stopped)
26b2d152 141 return -1;
26b2d152
MN
142
143 if (ret < 0) {
144 ERROR("failed to send command");
145 return -1;
146 }
147
148 if (command.answer.ret) {
149 ERROR("failed to retrieve the init pid: %s",
150 strerror(-command.answer.ret));
151 return -1;
152 }
153
154 return command.answer.pid;
155}
156
d5088cf2
CS
157int lxc_get_clone_flags(const char *name)
158{
159 struct lxc_command command = {
160 .request = { .type = LXC_COMMAND_CLONE_FLAGS },
161 };
162
163 int ret, stopped = 0;
164
165 ret = lxc_command(name, &command, &stopped);
166 if (ret < 0 && stopped)
167 return -1;
168
169 if (ret < 0) {
170 ERROR("failed to send command");
171 return -1;
172 }
173
174 return command.answer.ret;
175}
176
ded1d23f
DL
177extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
178extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
179extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
180extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
81c75799 181extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
d5088cf2 182extern int lxc_clone_flags_callback(int, struct lxc_request *, struct lxc_handler *);
724e753c
MN
183
184static int trigger_command(int fd, struct lxc_request *request,
ded1d23f 185 struct lxc_handler *handler)
724e753c 186{
ded1d23f 187 typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
724e753c
MN
188
189 callback cb[LXC_COMMAND_MAX] = {
d5088cf2
CS
190 [LXC_COMMAND_TTY] = lxc_console_callback,
191 [LXC_COMMAND_STOP] = lxc_stop_callback,
192 [LXC_COMMAND_STATE] = lxc_state_callback,
193 [LXC_COMMAND_PID] = lxc_pid_callback,
194 [LXC_COMMAND_CLONE_FLAGS] = lxc_clone_flags_callback,
724e753c
MN
195 };
196
197 if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
198 return -1;
199
200 return cb[request->type](fd, request, handler);
201}
202
203static void command_fd_cleanup(int fd, struct lxc_handler *handler,
ded1d23f 204 struct lxc_epoll_descr *descr)
724e753c 205{
fae349da 206 lxc_console_remove_fd(fd, &handler->conf->tty_info);
724e753c
MN
207 lxc_mainloop_del_handler(descr, fd);
208 close(fd);
209}
210
ded1d23f 211static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
724e753c
MN
212{
213 int ret;
214 struct lxc_request request;
215 struct lxc_handler *handler = data;
216
217 ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
0a3ec350 218 if (ret == -EACCES) {
3cc5de36
MN
219 /* we don't care for the peer, just send and close */
220 struct lxc_answer answer = { .ret = ret };
221 send(fd, &answer, sizeof(answer), 0);
222 goto out_close;
ded1d23f
DL
223 }
224
225 if (ret < 0) {
724e753c
MN
226 SYSERROR("failed to receive data on command socket");
227 goto out_close;
228 }
229
230 if (!ret) {
231 DEBUG("peer has disconnected");
232 goto out_close;
233 }
234
235 if (ret != sizeof(request)) {
236 WARN("partial request, ignored");
237 goto out_close;
238 }
239
240 ret = trigger_command(fd, &request, handler);
241 if (ret) {
242 /* this is not an error, but only a request to close fd */
243 ret = 0;
244 goto out_close;
245 }
246
247out:
248 return ret;
249out_close:
250 command_fd_cleanup(fd, handler, descr);
251 goto out;
252}
253
254static int incoming_command_handler(int fd, void *data,
255 struct lxc_epoll_descr *descr)
256{
ded1d23f 257 int opt = 1, ret = -1, connection;
724e753c
MN
258
259 connection = accept(fd, NULL, 0);
260 if (connection < 0) {
261 SYSERROR("failed to accept connection");
262 return -1;
263 }
264
9ccb2dbc
DL
265 if (fcntl(connection, F_SETFD, FD_CLOEXEC)) {
266 SYSERROR("failed to set close-on-exec on incoming connection");
267 goto out_close;
268 }
269
0a3ec350
DL
270 if (setsockopt(connection, SOL_SOCKET,
271 SO_PASSCRED, &opt, sizeof(opt))) {
724e753c
MN
272 SYSERROR("failed to enable credential on socket");
273 goto out_close;
274 }
275
276 ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
277 if (ret) {
278 ERROR("failed to add handler");
279 goto out_close;
280 }
281
282out:
283 return ret;
284
285out_close:
286 close(connection);
287 goto out;
288}
289
d2e30e99 290extern int lxc_command_init(const char *name, struct lxc_handler *handler)
724e753c 291{
d2e30e99 292 int fd;
46968ea3
DL
293 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
294 char *offset = &path[1];
9ba8130c 295 int rc, len;
724e753c 296
9ba8130c
SH
297 len = sizeof(path)-1;
298 rc = snprintf(offset, len, abstractname, name);
299 if (rc < 0 || rc >= len) {
300 ERROR("Name too long");
301 return -1;
302 }
724e753c 303
46968ea3 304 fd = lxc_af_unix_open(path, SOCK_STREAM, 0);
724e753c 305 if (fd < 0) {
97d3756c
SH
306 ERROR("failed (%d) to create the command service point %s", errno, offset);
307 if (errno == EADDRINUSE) {
308 ERROR("##");
309 ERROR("# The container appears to be already running!");
310 ERROR("##");
311 }
724e753c
MN
312 return -1;
313 }
314
91480a0f
DL
315 if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
316 SYSERROR("failed to set sigfd to close-on-exec");
317 close(fd);
318 return -1;
319 }
320
d2e30e99
DE
321 handler->conf->maincmd_fd = fd;
322 return 0;
323}
324
325extern int lxc_command_mainloop_add(const char *name,
326 struct lxc_epoll_descr *descr,
327 struct lxc_handler *handler)
328{
329 int ret, fd = handler->conf->maincmd_fd;
330
0a3ec350
DL
331 ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
332 handler);
724e753c
MN
333 if (ret) {
334 ERROR("failed to add handler for command socket");
335 close(fd);
336 }
337
338 return ret;
339}