liblxc_la_SOURCES = \
arguments.c arguments.h \
- commands.h \
+ commands.c commands.h \
create.c \
destroy.c \
start.c \
--- /dev/null
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2009
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+
+#include <lxc/lxc.h>
+
+#include "commands.h"
+#include "mainloop.h"
+#include "af_unix.h"
+
+lxc_log_define(lxc_commands, lxc);
+
+/*----------------------------------------------------------------------------
+ * functions used by processes requesting command to lxc-start
+ *--------------------------------------------------------------------------*/
+static int receive_answer(int sock, struct lxc_answer *answer)
+{
+ int ret;
+
+ ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
+ if (ret < 0)
+ ERROR("failed to receive answer for the command");
+
+ return ret;
+}
+
+extern int lxc_command(const char *name, struct lxc_command *command)
+{
+ struct sockaddr_un addr = { 0 };
+ int sock, ret = -1;
+ char *offset = &addr.sun_path[1];
+
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "@%s", name);
+ addr.sun_path[0] = '\0';
+
+ sock = lxc_af_unix_connect(addr.sun_path);
+ if (sock < 0) {
+ WARN("failed to connect to '@%s': %s", offset, strerror(errno));
+ return -1;
+ }
+
+ ret = lxc_af_unix_send_credential(sock, &command->request,
+ sizeof(command->request));
+ if (ret < 0) {
+ SYSERROR("failed to send credentials");
+ goto out_close;
+ }
+
+ if (ret != sizeof(command->request)) {
+ SYSERROR("message only partially sent to '@%s'", offset);
+ goto out_close;
+ }
+
+ ret = receive_answer(sock, &command->answer);
+ if (ret < 0)
+ goto out_close;
+out:
+ return ret;
+out_close:
+ close(sock);
+ goto out;
+}
+
+/*----------------------------------------------------------------------------
+ * functions used by lxc-start process
+ *--------------------------------------------------------------------------*/
+extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info);
+extern int lxc_console_callback(int fd, struct lxc_request *request,
+ struct lxc_handler *handler);
+
+static int trigger_command(int fd, struct lxc_request *request,
+ struct lxc_handler *handler)
+{
+ typedef int (*callback)(int, struct lxc_request *,
+ struct lxc_handler *);
+
+ callback cb[LXC_COMMAND_MAX] = {
+ [LXC_COMMAND_TTY] = lxc_console_callback,
+ };
+
+ if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
+ return -1;
+
+ return cb[request->type](fd, request, handler);
+}
+
+static void command_fd_cleanup(int fd, struct lxc_handler *handler,
+ struct lxc_epoll_descr *descr)
+{
+ lxc_console_remove_fd(fd, &handler->tty_info);
+ lxc_mainloop_del_handler(descr, fd);
+ close(fd);
+}
+
+static int command_handler(int fd, void *data,
+ struct lxc_epoll_descr *descr)
+{
+ int ret;
+ struct lxc_request request;
+ struct lxc_handler *handler = data;
+
+ ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
+ if (ret < 0) {
+ SYSERROR("failed to receive data on command socket");
+ goto out_close;
+ }
+
+ if (!ret) {
+ DEBUG("peer has disconnected");
+ goto out_close;
+ }
+
+ if (ret != sizeof(request)) {
+ WARN("partial request, ignored");
+ goto out_close;
+ }
+
+ ret = trigger_command(fd, &request, handler);
+ if (ret) {
+ /* this is not an error, but only a request to close fd */
+ ret = 0;
+ goto out_close;
+ }
+
+out:
+ return ret;
+out_close:
+ command_fd_cleanup(fd, handler, descr);
+ goto out;
+}
+
+static int incoming_command_handler(int fd, void *data,
+ struct lxc_epoll_descr *descr)
+{
+ int ret = 1, connection;
+
+ connection = accept(fd, NULL, 0);
+ if (connection < 0) {
+ SYSERROR("failed to accept connection");
+ return -1;
+ }
+
+ if (setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &ret, sizeof(ret))) {
+ SYSERROR("failed to enable credential on socket");
+ goto out_close;
+ }
+
+ ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
+ if (ret) {
+ ERROR("failed to add handler");
+ goto out_close;
+ }
+
+out:
+ return ret;
+
+out_close:
+ close(connection);
+ goto out;
+}
+
+extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
+ struct lxc_handler *handler)
+{
+ int ret, fd;
+ struct sockaddr_un addr = { 0 };
+ char *offset = &addr.sun_path[1];
+
+ strcpy(offset, name);
+ addr.sun_path[0] = '\0';
+
+ fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0);
+ if (fd < 0) {
+ ERROR("failed to create the command service point");
+ return -1;
+ }
+
+ ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
+ handler);
+ if (ret) {
+ ERROR("failed to add handler for command socket");
+ close(fd);
+ }
+
+ return ret;
+}
struct lxc_answer answer;
};
+extern int lxc_command(const char *name, struct lxc_command *command);
+
+struct lxc_epoll_descr;
+struct lxc_handler;
+
+extern int lxc_command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
+ struct lxc_handler *handler);
+
#endif
#include <sys/types.h>
#include <sys/un.h>
-#include "af_unix.h"
-#include "error.h"
-
-#include <lxc/log.h>
+#include <lxc/lxc.h>
#include "commands.h"
+#include "af_unix.h"
lxc_log_define(lxc_console, lxc);
-static int receive_answer(int sock, struct lxc_answer *answer)
-{
- int ret;
-
- ret = lxc_af_unix_recv_fd(sock, &answer->fd, answer, sizeof(*answer));
- if (ret < 0)
- ERROR("failed to receive answer for the command");
-
- return ret;
-}
-
-static int send_command(const char *name, struct lxc_command *command)
-{
- struct sockaddr_un addr = { 0 };
- int sock, ret = -1;
- char *offset = &addr.sun_path[1];
-
- snprintf(addr.sun_path, sizeof(addr.sun_path), "@%s", name);
- addr.sun_path[0] = '\0';
-
- sock = lxc_af_unix_connect(addr.sun_path);
- if (sock < 0) {
- WARN("failed to connect to '@%s': %s", offset, strerror(errno));
- return -1;
- }
-
- ret = lxc_af_unix_send_credential(sock, &command->request,
- sizeof(command->request));
- if (ret < 0) {
- SYSERROR("failed to send credentials");
- goto out_close;
- }
-
- if (ret != sizeof(command->request)) {
- SYSERROR("message only partially sent to '@%s'", offset);
- goto out_close;
- }
-
- ret = receive_answer(sock, &command->answer);
- if (ret < 0)
- goto out_close;
-out:
- return ret;
-out_close:
- close(sock);
- goto out;
-}
-
extern int lxc_console(const char *name, int ttynum, int *fd)
{
int ret;
.request = { .type = LXC_COMMAND_TTY, .data = ttynum },
};
- ret = send_command(name, &command);
+ ret = lxc_command(name, &command);
if (ret < 0) {
ERROR("failed to send command");
return -1;
INFO("tty %d allocated", ttynum);
return 0;
}
+
+/*----------------------------------------------------------------------------
+ * functions used by lxc-start mainloop
+ * to handle above command request.
+ *--------------------------------------------------------------------------*/
+extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
+{
+ int i;
+
+ for (i = 0; i < tty_info->nbtty; i++) {
+
+ if (tty_info->pty_info[i].busy != fd)
+ continue;
+
+ tty_info->pty_info[i].busy = 0;
+ }
+
+ return;
+}
+
+extern int lxc_console_callback(int fd, struct lxc_request *request,
+ struct lxc_handler *handler)
+{
+ int ttynum = request->data;
+ struct lxc_tty_info *tty_info = &handler->tty_info;
+
+ if (ttynum > 0) {
+ if (ttynum > tty_info->nbtty)
+ goto out_close;
+
+ if (tty_info->pty_info[ttynum - 1].busy)
+ goto out_close;
+
+ goto out_send;
+ }
+
+ /* fixup index tty1 => [0] */
+ for (ttynum = 1;
+ ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
+ ttynum++);
+
+ /* we didn't find any available slot for tty */
+ if (ttynum > tty_info->nbtty)
+ goto out_close;
+
+out_send:
+ if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
+ &ttynum, sizeof(ttynum)) < 0) {
+ ERROR("failed to send tty to client");
+ goto out_close;
+ }
+
+ tty_info->pty_info[ttynum - 1].busy = fd;
+
+ return 0;
+
+out_close:
+ /* the close fd and related cleanup will be done by caller */
+ return 1;
+}
+
return fd;
}
-static int incoming_command_handler(int fd, void *data,
- struct lxc_epoll_descr *descr);
-
-static int command_mainloop_add(const char *name, struct lxc_epoll_descr *descr,
- struct lxc_handler *handler)
-{
- int ret, fd;
- struct sockaddr_un addr = { 0 };
- char *offset = &addr.sun_path[1];
-
- strcpy(offset, name);
- addr.sun_path[0] = '\0';
-
- fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0);
- if (fd < 0) {
- ERROR("failed to create the command service point");
- return -1;
- }
-
- if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
- SYSERROR("failed to close-on-exec flag");
- close(fd);
- return -1;
- }
-
- ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler,
- handler);
- if (ret) {
- ERROR("failed to add handler for command socket");
- close(fd);
- }
-
- return ret;
-}
-
static int sigchld_handler(int fd, void *data,
struct lxc_epoll_descr *descr)
{
return 1;
}
-static int command_handler(int fd, void *data,
- struct lxc_epoll_descr *descr);
-static int trigger_command(int fd, struct lxc_request *request,
- struct lxc_handler *handler,
- struct lxc_epoll_descr *descr);
-
-static int incoming_command_handler(int fd, void *data, struct lxc_epoll_descr *descr)
-{
- int ret = 1, connection;
-
- connection = accept(fd, NULL, 0);
- if (connection < 0) {
- SYSERROR("failed to accept connection");
- return -1;
- }
-
- if (setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &ret, sizeof(ret))) {
- SYSERROR("failed to enable credential on socket");
- goto out_close;
- }
-
- ret = lxc_mainloop_add_handler(descr, connection, command_handler, data);
- if (ret) {
- ERROR("failed to add handler");
- goto out_close;
- }
-
-out:
- return ret;
-
-out_close:
- close(connection);
- goto out;
-}
-
-static void ttyinfo_remove_fd(int fd, struct lxc_tty_info *tty_info)
-{
- int i;
-
- for (i = 0; i < tty_info->nbtty; i++) {
-
- if (tty_info->pty_info[i].busy != fd)
- continue;
-
- tty_info->pty_info[i].busy = 0;
- }
-
- return;
-}
-
-static void command_fd_cleanup(int fd, struct lxc_handler *handler,
- struct lxc_epoll_descr *descr)
-{
- ttyinfo_remove_fd(fd, &handler->tty_info);
- lxc_mainloop_del_handler(descr, fd);
- close(fd);
-}
-
-static int command_handler(int fd, void *data,
- struct lxc_epoll_descr *descr)
-{
- int ret;
- struct lxc_request request;
- struct lxc_handler *handler = data;
-
- ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request));
- if (ret < 0) {
- SYSERROR("failed to receive data on command socket");
- goto out_close;
- }
-
- if (!ret) {
- DEBUG("peer has disconnected");
- goto out_close;
- }
-
- if (ret != sizeof(request)) {
- WARN("partial request, ignored");
- goto out_close;
- }
-
- ret = trigger_command(fd, &request, handler, descr);
- if (ret) {
- /* this is not an error, but only a request to close fd */
- ret = 0;
- goto out_close;
- }
-
-out:
- return ret;
-out_close:
- command_fd_cleanup(fd, handler, descr);
- goto out;
-}
-
-static int ttyservice_handler(int fd, struct lxc_request *request,
- struct lxc_handler *handler,
- struct lxc_epoll_descr *descr)
-{
- int ttynum = request->data;
- struct lxc_tty_info *tty_info = &handler->tty_info;
-
- if (ttynum > 0) {
- if (ttynum > tty_info->nbtty)
- goto out_close;
-
- if (tty_info->pty_info[ttynum - 1].busy)
- goto out_close;
-
- goto out_send;
- }
-
- /* fixup index tty1 => [0] */
- for (ttynum = 1;
- ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
- ttynum++);
-
- /* we didn't find any available slot for tty */
- if (ttynum > tty_info->nbtty)
- goto out_close;
-
-out_send:
- if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
- &ttynum, sizeof(ttynum)) < 0) {
- ERROR("failed to send tty to client");
- goto out_close;
- }
-
- tty_info->pty_info[ttynum - 1].busy = fd;
-
- return 0;
-
-out_close:
- /* the close fd and related cleanup will be done by caller */
- return 1;
-}
-
-static int trigger_command(int fd, struct lxc_request *request,
- struct lxc_handler *handler,
- struct lxc_epoll_descr *descr)
-{
- typedef int (*callback)(int, struct lxc_request *,
- struct lxc_handler *,
- struct lxc_epoll_descr *descr);
-
- callback cb[LXC_COMMAND_MAX] = {
- [LXC_COMMAND_TTY] = ttyservice_handler,
- };
-
- if (request->type < 0 || request->type >= LXC_COMMAND_MAX)
- return -1;
-
- return cb[request->type](fd, request, handler, descr);
-}
-
int lxc_poll(const char *name, struct lxc_handler *handler)
{
int sigfd = handler->sigfd;
goto out_mainloop_open;
}
- if (command_mainloop_add(name, &descr, handler))
+ if (lxc_command_mainloop_add(name, &descr, handler))
goto out_mainloop_open;
ret = lxc_mainloop(&descr);