]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/commands.c
handle the stop command
[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 <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
33 #include <lxc/lxc.h>
34
35 #include "commands.h"
36 #include "mainloop.h"
37 #include "af_unix.h"
38
39 lxc_log_define(lxc_commands, lxc);
40
41 /*----------------------------------------------------------------------------
42 * functions used by processes requesting command to lxc-start
43 *--------------------------------------------------------------------------*/
44 static int receive_answer(int sock, struct lxc_answer *answer)
45 {
46 int ret;
47
48 ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
49 if (ret < 0)
50 ERROR("failed to receive answer for the command");
51
52 return ret;
53 }
54
55 extern int lxc_command(const char *name, struct lxc_command *command)
56 {
57 struct sockaddr_un addr = { 0 };
58 int sock, ret = -1;
59 char *offset = &addr.sun_path[1];
60
61 snprintf(addr.sun_path, sizeof(addr.sun_path), "@%s", name);
62 addr.sun_path[0] = '\0';
63
64 sock = lxc_af_unix_connect(addr.sun_path);
65 if (sock < 0) {
66 WARN("failed to connect to '@%s': %s", offset, strerror(errno));
67 return -1;
68 }
69
70 ret = lxc_af_unix_send_credential(sock, &command->request,
71 sizeof(command->request));
72 if (ret < 0) {
73 SYSERROR("failed to send credentials");
74 goto out_close;
75 }
76
77 if (ret != sizeof(command->request)) {
78 SYSERROR("message only partially sent to '@%s'", offset);
79 goto out_close;
80 }
81
82 ret = receive_answer(sock, &command->answer);
83 if (ret < 0)
84 goto out_close;
85 out:
86 return ret;
87 out_close:
88 close(sock);
89 goto out;
90 }
91
92 /*----------------------------------------------------------------------------
93 * functions used by lxc-start process
94 *--------------------------------------------------------------------------*/
95 extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info);
96 extern int lxc_console_callback(int fd, struct lxc_request *request,
97 struct lxc_handler *handler);
98 extern int lxc_stop_callback(int fd, struct lxc_request *request,
99 struct lxc_handler *handler);
100
101 static int trigger_command(int fd, struct lxc_request *request,
102 struct lxc_handler *handler)
103 {
104 typedef int (*callback)(int, struct lxc_request *,
105 struct lxc_handler *);
106
107 callback cb[LXC_COMMAND_MAX] = {
108 [LXC_COMMAND_TTY] = lxc_console_callback,
109 [LXC_COMMAND_STOP] = lxc_stop_callback,
110 };
111
112 if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
113 return -1;
114
115 return cb[request->type](fd, request, handler);
116 }
117
118 static void command_fd_cleanup(int fd, struct lxc_handler *handler,
119 struct lxc_epoll_descr *descr)
120 {
121 lxc_console_remove_fd(fd, &handler->tty_info);
122 lxc_mainloop_del_handler(descr, fd);
123 close(fd);
124 }
125
126 static int command_handler(int fd, void *data,
127 struct lxc_epoll_descr *descr)
128 {
129 int ret;
130 struct lxc_request request;
131 struct lxc_handler *handler = data;
132
133 ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
134 if (ret < 0 && ret == -EACCES) {
135 /* we don't care for the peer, just send and close */
136 struct lxc_answer answer = { .ret = ret };
137 send(fd, &answer, sizeof(answer), 0);
138 goto out_close;
139 } else if (ret < 0) {
140 SYSERROR("failed to receive data on command socket");
141 goto out_close;
142 }
143
144 if (!ret) {
145 DEBUG("peer has disconnected");
146 goto out_close;
147 }
148
149 if (ret != sizeof(request)) {
150 WARN("partial request, ignored");
151 goto out_close;
152 }
153
154 ret = trigger_command(fd, &request, handler);
155 if (ret) {
156 /* this is not an error, but only a request to close fd */
157 ret = 0;
158 goto out_close;
159 }
160
161 out:
162 return ret;
163 out_close:
164 command_fd_cleanup(fd, handler, descr);
165 goto out;
166 }
167
168 static int incoming_command_handler(int fd, void *data,
169 struct lxc_epoll_descr *descr)
170 {
171 int ret = 1, connection;
172
173 connection = accept(fd, NULL, 0);
174 if (connection < 0) {
175 SYSERROR("failed to accept connection");
176 return -1;
177 }
178
179 if (setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &ret, sizeof(ret))) {
180 SYSERROR("failed to enable credential on socket");
181 goto out_close;
182 }
183
184 ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
185 if (ret) {
186 ERROR("failed to add handler");
187 goto out_close;
188 }
189
190 out:
191 return ret;
192
193 out_close:
194 close(connection);
195 goto out;
196 }
197
198 extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
199 struct lxc_handler *handler)
200 {
201 int ret, fd;
202 struct sockaddr_un addr = { 0 };
203 char *offset = &addr.sun_path[1];
204
205 strcpy(offset, name);
206 addr.sun_path[0] = '\0';
207
208 fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0);
209 if (fd < 0) {
210 ERROR("failed to create the command service point");
211 return -1;
212 }
213
214 ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
215 handler);
216 if (ret) {
217 ERROR("failed to add handler for command socket");
218 close(fd);
219 }
220
221 return ret;
222 }