#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;
+}
#include "error.h"
#include "af_unix.h"
#include "mainloop.h"
+#include "commands.h"
#include <lxc/lxc.h>
#include <lxc/log.h>
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;
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;
}
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");
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;
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;
}
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;
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)
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");
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);