]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
add an additionnal abstract socket to prepare for more commands
authorMichel Normand <normand@fr.ibm.com>
Wed, 7 Oct 2009 14:06:08 +0000 (16:06 +0200)
committerDaniel Lezcano <dlezcano@fr.ibm.com>
Wed, 7 Oct 2009 14:06:08 +0000 (16:06 +0200)
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 <dlezcano@fr.ibm.com>
Signed-off-by: Michel Normand <normand@fr.ibm.com>
src/lxc/Makefile.am
src/lxc/commands.h [new file with mode: 0644]
src/lxc/console.c
src/lxc/start.c

index d63eb4f666fde91ee9da64188106994be411aa11..269c618d95520d30f1533258adcd1290cd74d28f 100644 (file)
@@ -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 (file)
index 0000000..66dd699
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+#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
index a9d54248cb8e6871e2a1bc5854b20a04a4061c71..18946e1fb0b7011d7daa0902aaa9ce3fd022bcfa 100644 (file)
 #include "error.h"
 
 #include <lxc/log.h>
+#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;
+}
index 05020e0c88184bd50f195df30ed75b61057c8e4a..c96dfb3afbbd0406ad472ce8d9b53dab892f9d75 100644 (file)
@@ -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 <lxc/lxc.h>
 #include <lxc/log.h>
@@ -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);