From 96fa1ff0d1aa3e1f3ab96297bfbf3a3613b5fe3b Mon Sep 17 00:00:00 2001 From: Michel Normand Date: Wed, 7 Oct 2009 16:06:08 +0200 Subject: [PATCH] add an additionnal abstract socket to prepare for more commands Replace the current tty service socket by a general command service socket and plug for the moment only the existing tty service. Signed-off-by: Daniel Lezcano Signed-off-by: Michel Normand --- src/lxc/Makefile.am | 1 + src/lxc/commands.h | 46 ++++++++++++++ src/lxc/console.c | 65 +++++++++++++++----- src/lxc/start.c | 146 +++++++++++++++++++++++++++++--------------- 4 files changed, 193 insertions(+), 65 deletions(-) create mode 100644 src/lxc/commands.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index d63eb4f66..269c618d9 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -19,6 +19,7 @@ pkginclude_HEADERS = \ liblxc_la_SOURCES = \ arguments.c arguments.h \ + commands.h \ create.c \ destroy.c \ start.c \ diff --git a/src/lxc/commands.h b/src/lxc/commands.h new file mode 100644 index 000000000..66dd6998f --- /dev/null +++ b/src/lxc/commands.h @@ -0,0 +1,46 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2009 + * + * Authors: + * Daniel Lezcano + * + * 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 + */ +#ifndef __commands_h +#define __commands_h + +enum { + LXC_COMMAND_TTY, + LXC_COMMAND_MAX, +}; + +struct lxc_request { + int type; + int data; +}; + +struct lxc_answer { + int fd; + int ret; /* 0 on success, -errno on failure */ +}; + +struct lxc_command { + struct lxc_request request; + struct lxc_answer answer; +}; + +#endif diff --git a/src/lxc/console.c b/src/lxc/console.c index a9d54248c..18946e1fb 100644 --- a/src/lxc/console.c +++ b/src/lxc/console.c @@ -31,47 +31,82 @@ #include "error.h" #include +#include "commands.h" lxc_log_define(lxc_console, lxc); -extern int lxc_console(const char *name, int ttynum, int *fd) +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) { - ERROR("failed to connect to the tty service"); - goto out; + WARN("failed to connect to '@%s': %s", offset, strerror(errno)); + return -1; } - ret = lxc_af_unix_send_credential(sock, &ttynum, sizeof(ttynum)); + ret = lxc_af_unix_send_credential(sock, &command->request, + sizeof(command->request)); if (ret < 0) { SYSERROR("failed to send credentials"); goto out_close; } - ret = lxc_af_unix_recv_fd(sock, fd, &ttynum, sizeof(ttynum)); - if (ret < 0) { - ERROR("failed to connect to the tty"); + if (ret != sizeof(command->request)) { + SYSERROR("message only partially sent to '@%s'", offset); goto out_close; } - INFO("tty %d allocated", ttynum); - - if (!ret) { - ERROR("console denied by '%s'", name); + ret = receive_answer(sock, &command->answer); + if (ret < 0) goto out_close; - } - - ret = 0; - out: return ret; out_close: close(sock); goto out; } + +extern int lxc_console(const char *name, int ttynum, int *fd) +{ + int ret; + struct lxc_command command = { + .request = { .type = LXC_COMMAND_TTY, .data = ttynum }, + }; + + ret = send_command(name, &command); + if (ret < 0) { + ERROR("failed to send command"); + return -1; + } + + if (!ret) { + ERROR("console denied by '%s'", name); + return -1; + } + + *fd = command.answer.fd; + if (*fd <0) { + ERROR("unable to allocate fd for tty %d", ttynum); + return -1; + } + + INFO("tty %d allocated", ttynum); + return 0; +} diff --git a/src/lxc/start.c b/src/lxc/start.c index 05020e0c8..c96dfb3af 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -91,6 +91,7 @@ int signalfd(int fd, const sigset_t *mask, int flags) #include "error.h" #include "af_unix.h" #include "mainloop.h" +#include "commands.h" #include #include @@ -132,10 +133,10 @@ static int setup_sigchld_fd(sigset_t *oldmask) return fd; } -static int ttyservice_handler(int fd, void *data, +static int incoming_command_handler(int fd, void *data, struct lxc_epoll_descr *descr); -static int tty_mainloop_add(const char *name, 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; @@ -147,7 +148,7 @@ static int tty_mainloop_add(const char *name, struct lxc_epoll_descr *descr, fd = lxc_af_unix_open(addr.sun_path, SOCK_STREAM, 0); if (fd < 0) { - ERROR("failed to create the tty service point"); + ERROR("failed to create the command service point"); return -1; } @@ -157,7 +158,7 @@ static int tty_mainloop_add(const char *name, struct lxc_epoll_descr *descr, return -1; } - ret = lxc_mainloop_add_handler(descr, fd, ttyservice_handler, + ret = lxc_mainloop_add_handler(descr, fd, incoming_command_handler, handler); if (ret) { ERROR("failed to add handler for command socket"); @@ -175,6 +176,41 @@ static int sigchld_handler(int fd, void *data, 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; @@ -190,43 +226,24 @@ static void ttyinfo_remove_fd(int fd, struct lxc_tty_info *tty_info) return; } -static void command_fd_cleanup(int fd, struct lxc_tty_info *tty_info, +static void command_fd_cleanup(int fd, struct lxc_handler *handler, struct lxc_epoll_descr *descr) { - ttyinfo_remove_fd(fd, tty_info); + ttyinfo_remove_fd(fd, &handler->tty_info); lxc_mainloop_del_handler(descr, fd); close(fd); } -static int ttyclient_handler(int fd, void *data, - struct lxc_epoll_descr *descr) -{ - struct lxc_tty_info *tty_info = data; - - command_fd_cleanup(fd, tty_info, descr); -} - -static int ttyservice_handler(int fd, void *data, +static int command_handler(int fd, void *data, struct lxc_epoll_descr *descr) { - int conn, ttynum, val = 1, ret = -1; + int ret; + struct lxc_request request; struct lxc_handler *handler = data; - struct lxc_tty_info *tty_info = &handler->tty_info; - - conn = accept(fd, NULL, 0); - if (conn < 0) { - SYSERROR("failed to accept tty client"); - return -1; - } - - if (setsockopt(conn, SOL_SOCKET, SO_PASSCRED, &val, sizeof(val))) { - SYSERROR("failed to enable credential on socket"); - goto out_close; - } - ret = lxc_af_unix_rcv_credential(conn, &ttynum, sizeof(ttynum)); + ret = lxc_af_unix_rcv_credential(fd, &request, sizeof(request)); if (ret < 0) { - SYSERROR("failed to receive data on tty socket"); + SYSERROR("failed to receive data on command socket"); goto out_close; } @@ -235,11 +252,32 @@ static int ttyservice_handler(int fd, void *data, goto out_close; } - if (ret != sizeof(ttynum)) { + 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; @@ -260,26 +298,37 @@ static int ttyservice_handler(int fd, void *data, goto out_close; out_send: - if (lxc_af_unix_send_fd(conn, tty_info->pty_info[ttynum - 1].master, + 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; } - if (lxc_mainloop_add_handler(descr, conn, - ttyclient_handler, tty_info)) { - ERROR("failed to add tty client handler"); - goto out_close; - } + tty_info->pty_info[ttynum - 1].busy = fd; - tty_info->pty_info[ttynum - 1].busy = conn; + return 0; - ret = 0; -out: - return ret; out_close: - close(conn); - goto out; + /* 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) @@ -291,9 +340,8 @@ int lxc_poll(const char *name, struct lxc_handler *handler) int nfds, ret = -1; struct lxc_epoll_descr descr; - /* sigfd + nb tty + tty service - * if tty is enabled */ - nfds = tty_info->nbtty + 1 + tty_info->nbtty ? 1 : 0; + /* nb tty + sigfd + command service */ + nfds = tty_info->nbtty + 2; if (lxc_mainloop_open(nfds, &descr)) { ERROR("failed to create mainloop"); @@ -305,10 +353,8 @@ int lxc_poll(const char *name, struct lxc_handler *handler) goto out_mainloop_open; } - if (tty_info->nbtty) { - if (tty_mainloop_add(name, &descr, handler)) - goto out_mainloop_open; - } + if (command_mainloop_add(name, &descr, handler)) + goto out_mainloop_open; ret = lxc_mainloop(&descr); -- 2.39.5