]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/commands.c
restart the container at reboot
[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
d97b36f8 72extern int lxc_command(const char *name, struct lxc_command *command,
ded1d23f 73 int *stopped)
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];
724e753c 78
ded1d23f 79 sprintf(offset, abstractname, name);
724e753c 80
46968ea3 81 sock = lxc_af_unix_connect(path);
d97b36f8
DL
82 if (sock < 0 && errno == ECONNREFUSED) {
83 *stopped = 1;
84 return -1;
85 }
86
724e753c 87 if (sock < 0) {
d97b36f8 88 SYSERROR("failed to connect to '@%s'", offset);
724e753c
MN
89 return -1;
90 }
91
92 ret = lxc_af_unix_send_credential(sock, &command->request,
93 sizeof(command->request));
94 if (ret < 0) {
d97b36f8 95 SYSERROR("failed to send request to '@%s'", offset);
724e753c
MN
96 goto out_close;
97 }
98
99 if (ret != sizeof(command->request)) {
d97b36f8 100 SYSERROR("message partially sent to '@%s'", offset);
724e753c
MN
101 goto out_close;
102 }
103
104 ret = receive_answer(sock, &command->answer);
105 if (ret < 0)
106 goto out_close;
107out:
108 return ret;
109out_close:
110 close(sock);
111 goto out;
112}
113
ded1d23f
DL
114extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
115extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
116extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
117extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
81c75799 118extern int lxc_pid_callback(int, struct lxc_request *, struct lxc_handler *);
724e753c
MN
119
120static int trigger_command(int fd, struct lxc_request *request,
ded1d23f 121 struct lxc_handler *handler)
724e753c 122{
ded1d23f 123 typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
724e753c
MN
124
125 callback cb[LXC_COMMAND_MAX] = {
ded1d23f
DL
126 [LXC_COMMAND_TTY] = lxc_console_callback,
127 [LXC_COMMAND_STOP] = lxc_stop_callback,
e98fe68b 128 [LXC_COMMAND_STATE] = lxc_state_callback,
81c75799 129 [LXC_COMMAND_PID] = lxc_pid_callback,
724e753c
MN
130 };
131
132 if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
133 return -1;
134
135 return cb[request->type](fd, request, handler);
136}
137
138static void command_fd_cleanup(int fd, struct lxc_handler *handler,
ded1d23f 139 struct lxc_epoll_descr *descr)
724e753c 140{
fae349da 141 lxc_console_remove_fd(fd, &handler->conf->tty_info);
724e753c
MN
142 lxc_mainloop_del_handler(descr, fd);
143 close(fd);
144}
145
ded1d23f 146static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
724e753c
MN
147{
148 int ret;
149 struct lxc_request request;
150 struct lxc_handler *handler = data;
151
152 ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
0a3ec350 153 if (ret == -EACCES) {
3cc5de36
MN
154 /* we don't care for the peer, just send and close */
155 struct lxc_answer answer = { .ret = ret };
156 send(fd, &answer, sizeof(answer), 0);
157 goto out_close;
ded1d23f
DL
158 }
159
160 if (ret < 0) {
724e753c
MN
161 SYSERROR("failed to receive data on command socket");
162 goto out_close;
163 }
164
165 if (!ret) {
166 DEBUG("peer has disconnected");
167 goto out_close;
168 }
169
170 if (ret != sizeof(request)) {
171 WARN("partial request, ignored");
172 goto out_close;
173 }
174
175 ret = trigger_command(fd, &request, handler);
176 if (ret) {
177 /* this is not an error, but only a request to close fd */
178 ret = 0;
179 goto out_close;
180 }
181
182out:
183 return ret;
184out_close:
185 command_fd_cleanup(fd, handler, descr);
186 goto out;
187}
188
189static int incoming_command_handler(int fd, void *data,
190 struct lxc_epoll_descr *descr)
191{
ded1d23f 192 int opt = 1, ret = -1, connection;
724e753c
MN
193
194 connection = accept(fd, NULL, 0);
195 if (connection < 0) {
196 SYSERROR("failed to accept connection");
197 return -1;
198 }
199
0a3ec350
DL
200 if (setsockopt(connection, SOL_SOCKET,
201 SO_PASSCRED, &opt, sizeof(opt))) {
724e753c
MN
202 SYSERROR("failed to enable credential on socket");
203 goto out_close;
204 }
205
206 ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
207 if (ret) {
208 ERROR("failed to add handler");
209 goto out_close;
210 }
211
212out:
213 return ret;
214
215out_close:
216 close(connection);
217 goto out;
218}
219
0a3ec350
DL
220extern int lxc_command_mainloop_add(const char *name,
221 struct lxc_epoll_descr *descr,
724e753c
MN
222 struct lxc_handler *handler)
223{
224 int ret, fd;
46968ea3
DL
225 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
226 char *offset = &path[1];
724e753c 227
ded1d23f 228 sprintf(offset, abstractname, name);
724e753c 229
46968ea3 230 fd = lxc_af_unix_open(path, SOCK_STREAM, 0);
724e753c
MN
231 if (fd < 0) {
232 ERROR("failed to create the command service point");
233 return -1;
234 }
235
91480a0f
DL
236 if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
237 SYSERROR("failed to set sigfd to close-on-exec");
238 close(fd);
239 return -1;
240 }
241
0a3ec350
DL
242 ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
243 handler);
724e753c
MN
244 if (ret) {
245 ERROR("failed to add handler for command socket");
246 close(fd);
247 }
248
249 return ret;
250}