~ubuntu-branches/ubuntu/quantal/lxc/quantal-201208301614

« back to all changes in this revision

Viewing changes to src/lxc/commands.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Trotter, Stéphane Graber, Guido Trotter
  • Date: 2010-01-10 10:40:21 UTC
  • mfrom: (1.2.2 upstream)
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20100110104021-25cm8w09ccmw5w2z
[ Stéphane Graber ]
* Upgrade standards-version to 3.8.3
* Drop the copy of etc/* from rules as "etc" is no longer in the tarball

[ Guido Trotter ]
* New Upstream Version
* Update libcap2-dev dependency to libcap-dev
* Install upstream-built man pages via debian/lxc.manpages
* Drop unneeded docbook-utils build dependency

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/log.h>
 
34
#include <lxc/conf.h>
 
35
#include <lxc/start.h>  /* for struct lxc_handler */
 
36
 
 
37
#include "commands.h"
 
38
#include "mainloop.h"
 
39
#include "af_unix.h"
 
40
#include "config.h"
 
41
 
 
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
 
 
56
lxc_log_define(lxc_commands, lxc);
 
57
 
 
58
#define abstractname LXCPATH "/%s/command"
 
59
 
 
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
 
 
71
extern int lxc_command(const char *name, struct lxc_command *command,
 
72
                       int *stopped)
 
73
{
 
74
        int sock, ret = -1;
 
75
        char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
 
76
        char *offset = &path[1];
 
77
 
 
78
        sprintf(offset, abstractname, name);
 
79
 
 
80
        sock = lxc_af_unix_connect(path);
 
81
        if (sock < 0 && errno == ECONNREFUSED) {
 
82
                *stopped = 1;
 
83
                return -1;
 
84
        }
 
85
 
 
86
        if (sock < 0) {
 
87
                SYSERROR("failed to connect to '@%s'", offset);
 
88
                return -1;
 
89
        }
 
90
 
 
91
        ret = lxc_af_unix_send_credential(sock, &command->request,
 
92
                                        sizeof(command->request));
 
93
        if (ret < 0) {
 
94
                SYSERROR("failed to send request to '@%s'", offset);
 
95
                goto out_close;
 
96
        }
 
97
 
 
98
        if (ret != sizeof(command->request)) {
 
99
                SYSERROR("message partially sent to '@%s'", offset);
 
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
 
 
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 *);
 
117
 
 
118
static int trigger_command(int fd, struct lxc_request *request,
 
119
                           struct lxc_handler *handler)
 
120
{
 
121
        typedef int (*callback)(int, struct lxc_request *, struct lxc_handler *);
 
122
 
 
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,
 
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,
 
136
                               struct lxc_epoll_descr *descr)
 
137
{
 
138
        lxc_console_remove_fd(fd, &handler->conf.tty_info);
 
139
        lxc_mainloop_del_handler(descr, fd);
 
140
        close(fd);
 
141
}
 
142
 
 
143
static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
 
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));
 
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;
 
155
        }
 
156
 
 
157
        if (ret < 0) {
 
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
{
 
189
        int opt = 1, ret = -1, connection;
 
190
 
 
191
        connection = accept(fd, NULL, 0);
 
192
        if (connection < 0) {
 
193
                SYSERROR("failed to accept connection");
 
194
                return -1;
 
195
        }
 
196
 
 
197
        if (setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt))) {
 
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;
 
220
        char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
 
221
        char *offset = &path[1];
 
222
 
 
223
        sprintf(offset, abstractname, name);
 
224
 
 
225
        fd = lxc_af_unix_open(path, SOCK_STREAM, 0);
 
226
        if (fd < 0) {
 
227
                ERROR("failed to create the command service point");
 
228
                return -1;
 
229
        }
 
230
 
 
231
        ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler, handler);
 
232
        if (ret) {
 
233
                ERROR("failed to add handler for command socket");
 
234
                close(fd);
 
235
        }
 
236
 
 
237
        return ret;
 
238
}