]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/commands.c
use pivot_root instead of chroot
[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>
28#include <sys/socket.h>
29#include <sys/un.h>
30#include <sys/poll.h>
31#include <sys/param.h>
32
00b3c2e2
CLG
33#include <lxc/log.h>
34#include <lxc/conf.h>
35#include <lxc/start.h> /* for struct lxc_handler */
724e753c
MN
36
37#include "commands.h"
38#include "mainloop.h"
39#include "af_unix.h"
adaeaa99 40#include "config.h"
724e753c 41
ded1d23f
DL
42/*
43 * This file provides the different functions to have the client
44 * and the server to communicate
45 *
46 * Each command is transactional, the client send a request to
47 * the server and the server answer the request with a message
48 * giving the request's status (zero or a negative errno value).
49 *
50 * Each command is wrapped in a ancillary message in order to pass
51 * a credential making possible to the server to check if the client
52 * is allowed to ask for this command or not.
53 *
54 */
55
724e753c
MN
56lxc_log_define(lxc_commands, lxc);
57
adaeaa99 58#define abstractname LXCPATH "/%s/command"
ded1d23f 59
724e753c
MN
60static int receive_answer(int sock, struct lxc_answer *answer)
61{
62 int ret;
63
64 ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
65 if (ret < 0)
66 ERROR("failed to receive answer for the command");
67
68 return ret;
69}
70
d97b36f8 71extern int lxc_command(const char *name, struct lxc_command *command,
ded1d23f 72 int *stopped)
724e753c 73{
724e753c 74 int sock, ret = -1;
46968ea3
DL
75 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
76 char *offset = &path[1];
724e753c 77
ded1d23f 78 sprintf(offset, abstractname, name);
724e753c 79
46968ea3 80 sock = lxc_af_unix_connect(path);
d97b36f8
DL
81 if (sock < 0 && errno == ECONNREFUSED) {
82 *stopped = 1;
83 return -1;
84 }
85
724e753c 86 if (sock < 0) {
d97b36f8 87 SYSERROR("failed to connect to '@%s'", offset);
724e753c
MN
88 return -1;
89 }
90
91 ret = lxc_af_unix_send_credential(sock, &command->request,
92 sizeof(command->request));
93 if (ret < 0) {
d97b36f8 94 SYSERROR("failed to send request to '@%s'", offset);
724e753c
MN
95 goto out_close;
96 }
97
98 if (ret != sizeof(command->request)) {
d97b36f8 99 SYSERROR("message partially sent to '@%s'", offset);
724e753c
MN
100 goto out_close;
101 }
102
103 ret = receive_answer(sock, &command->answer);
104 if (ret < 0)
105 goto out_close;
106out:
107 return ret;
108out_close:
109 close(sock);
110 goto out;
111}
112
ded1d23f
DL
113extern void lxc_console_remove_fd(int, struct lxc_tty_info *);
114extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *);
115extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *);
116extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *);
724e753c
MN
117
118static int trigger_command(int fd, struct lxc_request *request,
ded1d23f 119 struct lxc_handler *handler)
724e753c 120{
ded1d23f 121 typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
724e753c
MN
122
123 callback cb[LXC_COMMAND_MAX] = {
ded1d23f
DL
124 [LXC_COMMAND_TTY] = lxc_console_callback,
125 [LXC_COMMAND_STOP] = lxc_stop_callback,
e98fe68b 126 [LXC_COMMAND_STATE] = lxc_state_callback,
724e753c
MN
127 };
128
129 if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
130 return -1;
131
132 return cb[request->type](fd, request, handler);
133}
134
135static void command_fd_cleanup(int fd, struct lxc_handler *handler,
ded1d23f 136 struct lxc_epoll_descr *descr)
724e753c 137{
fae349da 138 lxc_console_remove_fd(fd, &handler->conf->tty_info);
724e753c
MN
139 lxc_mainloop_del_handler(descr, fd);
140 close(fd);
141}
142
ded1d23f 143static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
724e753c
MN
144{
145 int ret;
146 struct lxc_request request;
147 struct lxc_handler *handler = data;
148
149 ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
3cc5de36
MN
150 if (ret < 0 && ret == -EACCES) {
151 /* we don't care for the peer, just send and close */
152 struct lxc_answer answer = { .ret = ret };
153 send(fd, &answer, sizeof(answer), 0);
154 goto out_close;
ded1d23f
DL
155 }
156
157 if (ret < 0) {
724e753c
MN
158 SYSERROR("failed to receive data on command socket");
159 goto out_close;
160 }
161
162 if (!ret) {
163 DEBUG("peer has disconnected");
164 goto out_close;
165 }
166
167 if (ret != sizeof(request)) {
168 WARN("partial request, ignored");
169 goto out_close;
170 }
171
172 ret = trigger_command(fd, &request, handler);
173 if (ret) {
174 /* this is not an error, but only a request to close fd */
175 ret = 0;
176 goto out_close;
177 }
178
179out:
180 return ret;
181out_close:
182 command_fd_cleanup(fd, handler, descr);
183 goto out;
184}
185
186static int incoming_command_handler(int fd, void *data,
187 struct lxc_epoll_descr *descr)
188{
ded1d23f 189 int opt = 1, ret = -1, connection;
724e753c
MN
190
191 connection = accept(fd, NULL, 0);
192 if (connection < 0) {
193 SYSERROR("failed to accept connection");
194 return -1;
195 }
196
ded1d23f 197 if (setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt))) {
724e753c
MN
198 SYSERROR("failed to enable credential on socket");
199 goto out_close;
200 }
201
202 ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
203 if (ret) {
204 ERROR("failed to add handler");
205 goto out_close;
206 }
207
208out:
209 return ret;
210
211out_close:
212 close(connection);
213 goto out;
214}
215
216extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
217 struct lxc_handler *handler)
218{
219 int ret, fd;
46968ea3
DL
220 char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
221 char *offset = &path[1];
724e753c 222
ded1d23f 223 sprintf(offset, abstractname, name);
724e753c 224
46968ea3 225 fd = lxc_af_unix_open(path, SOCK_STREAM, 0);
724e753c
MN
226 if (fd < 0) {
227 ERROR("failed to create the command service point");
228 return -1;
229 }
230
ded1d23f 231 ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler, handler);
724e753c
MN
232 if (ret) {
233 ERROR("failed to add handler for command socket");
234 close(fd);
235 }
236
237 return ret;
238}