]>
Commit | Line | Data |
---|---|---|
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 |
56 | lxc_log_define(lxc_commands, lxc); |
57 | ||
adaeaa99 | 58 | #define abstractname LXCPATH "/%s/command" |
ded1d23f | 59 | |
724e753c MN |
60 | static 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 | 71 | extern 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; | |
106 | out: | |
107 | return ret; | |
108 | out_close: | |
109 | close(sock); | |
110 | goto out; | |
111 | } | |
112 | ||
ded1d23f DL |
113 | extern void lxc_console_remove_fd(int, struct lxc_tty_info *); |
114 | extern int lxc_console_callback(int, struct lxc_request *, struct lxc_handler *); | |
115 | extern int lxc_stop_callback(int, struct lxc_request *, struct lxc_handler *); | |
116 | extern int lxc_state_callback(int, struct lxc_request *, struct lxc_handler *); | |
724e753c MN |
117 | |
118 | static 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 | ||
135 | static 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 | 143 | static 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 | ||
179 | out: | |
180 | return ret; | |
181 | out_close: | |
182 | command_fd_cleanup(fd, handler, descr); | |
183 | goto out; | |
184 | } | |
185 | ||
186 | static 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 | ||
208 | out: | |
209 | return ret; | |
210 | ||
211 | out_close: | |
212 | close(connection); | |
213 | goto out; | |
214 | } | |
215 | ||
216 | extern 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 | } |