2
* lxc: linux Container library
4
* (C) Copyright IBM Corp. 2007, 2009
7
* Daniel Lezcano <dlezcano at fr.ibm.com>
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.
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.
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
28
#include <sys/socket.h>
31
#include <sys/param.h>
35
#include <lxc/start.h> /* for struct lxc_handler */
43
* This file provides the different functions to have the client
44
* and the server to communicate
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).
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.
56
lxc_log_define(lxc_commands, lxc);
58
#define abstractname LXCPATH "/%s/command"
60
static int receive_answer(int sock, struct lxc_answer *answer)
64
ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
66
ERROR("failed to receive answer for the command");
71
extern int lxc_command(const char *name, struct lxc_command *command,
75
char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
76
char *offset = &path[1];
78
sprintf(offset, abstractname, name);
80
sock = lxc_af_unix_connect(path);
81
if (sock < 0 && errno == ECONNREFUSED) {
87
SYSERROR("failed to connect to '@%s'", offset);
91
ret = lxc_af_unix_send_credential(sock, &command->request,
92
sizeof(command->request));
94
SYSERROR("failed to send request to '@%s'", offset);
98
if (ret != sizeof(command->request)) {
99
SYSERROR("message partially sent to '@%s'", offset);
103
ret = receive_answer(sock, &command->answer);
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 *);
118
static int trigger_command(int fd, struct lxc_request *request,
119
struct lxc_handler *handler)
121
typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
123
callback cb[LXC_COMMAND_MAX] = {
124
[LXC_COMMAND_TTY] = lxc_console_callback,
125
[LXC_COMMAND_STOP] = lxc_stop_callback,
126
[LXC_COMMAND_STATE] = lxc_state_callback,
129
if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
132
return cb[request->type](fd, request, handler);
135
static void command_fd_cleanup(int fd, struct lxc_handler *handler,
136
struct lxc_epoll_descr *descr)
138
lxc_console_remove_fd(fd, &handler->conf.tty_info);
139
lxc_mainloop_del_handler(descr, fd);
143
static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
146
struct lxc_request request;
147
struct lxc_handler *handler = data;
149
ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
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);
158
SYSERROR("failed to receive data on command socket");
163
DEBUG("peer has disconnected");
167
if (ret != sizeof(request)) {
168
WARN("partial request, ignored");
172
ret = trigger_command(fd, &request, handler);
174
/* this is not an error, but only a request to close fd */
182
command_fd_cleanup(fd, handler, descr);
186
static int incoming_command_handler(int fd, void *data,
187
struct lxc_epoll_descr *descr)
189
int opt = 1, ret = -1, connection;
191
connection = accept(fd, NULL, 0);
192
if (connection < 0) {
193
SYSERROR("failed to accept connection");
197
if (setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt))) {
198
SYSERROR("failed to enable credential on socket");
202
ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
204
ERROR("failed to add handler");
216
extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
217
struct lxc_handler *handler)
220
char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
221
char *offset = &path[1];
223
sprintf(offset, abstractname, name);
225
fd = lxc_af_unix_open(path, SOCK_STREAM, 0);
227
ERROR("failed to create the command service point");
231
ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler, handler);
233
ERROR("failed to add handler for command socket");