mirror of
git://github.com/lxc/lxc
synced 2025-08-31 02:59:36 +00:00
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>
This commit is contained in:
committed by
Daniel Lezcano
parent
96fa1ff0d1
commit
724e753cb0
@@ -19,7 +19,7 @@ pkginclude_HEADERS = \
|
||||
|
||||
liblxc_la_SOURCES = \
|
||||
arguments.c arguments.h \
|
||||
commands.h \
|
||||
commands.c commands.h \
|
||||
create.c \
|
||||
destroy.c \
|
||||
start.c \
|
||||
|
214
src/lxc/commands.c
Normal file
214
src/lxc/commands.c
Normal file
@@ -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;
|
||||
}
|
@@ -43,4 +43,12 @@ struct lxc_command {
|
||||
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
|
||||
|
@@ -27,62 +27,12 @@
|
||||
#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;
|
||||
@@ -90,7 +40,7 @@ extern int lxc_console(const char *name, int ttynum, int *fd)
|
||||
.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;
|
||||
@@ -110,3 +60,64 @@ extern int lxc_console(const char *name, int ttynum, int *fd)
|
||||
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;
|
||||
}
|
||||
|
||||
|
192
src/lxc/start.c
192
src/lxc/start.c
@@ -133,41 +133,6 @@ static int setup_sigchld_fd(sigset_t *oldmask)
|
||||
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)
|
||||
{
|
||||
@@ -176,161 +141,6 @@ 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;
|
||||
|
||||
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;
|
||||
@@ -353,7 +163,7 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
|
||||
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);
|
||||
|
Reference in New Issue
Block a user