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