diff options
author | 2009-10-07 16:06:08 +0200 | |
---|---|---|
committer | 2009-10-07 16:06:08 +0200 | |
commit | 724e753cb0055b84f896522e8c5ec45ad996c195 (patch) | |
tree | a9486a526ff28a5bf431fb916985fc482637396d /src/lxc/commands.c | |
parent | add an additionnal abstract socket to prepare for more commands (diff) | |
download | lxc-724e753cb0055b84f896522e8c5ec45ad996c195.tar.gz lxc-724e753cb0055b84f896522e8c5ec45ad996c195.tar.bz2 lxc-724e753cb0055b84f896522e8c5ec45ad996c195.zip |
repackage previous code to new commands.c
move some code of start.c to new commands.c and to console.c
Signed-off-by: Michel Normand <normand@fr.ibm.com>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Diffstat (limited to 'src/lxc/commands.c')
-rw-r--r-- | src/lxc/commands.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/lxc/commands.c b/src/lxc/commands.c new file mode 100644 index 0000000..98e6121 --- /dev/null +++ b/src/lxc/commands.c @@ -0,0 +1,214 @@ +/* + * 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; +} |