]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
commands: abstract cmd socket handling + logging
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 3 Jul 2017 21:43:56 +0000 (23:43 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sat, 8 Jul 2017 22:14:46 +0000 (00:14 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/commands.c
src/lxc/commands_utils.c
src/lxc/commands_utils.h

index 645ea43bfcd700efa8cf4f9fc2e7a9b9f468e5fa..4540658c6b6b42ddf0ed52eaa3bccade44353136 100644 (file)
@@ -206,6 +206,60 @@ static int lxc_cmd_rsp_send(int fd, struct lxc_cmd_rsp *rsp)
        return 0;
 }
 
+static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
+                const char *lxcpath, const char *hashed_sock_name)
+{
+       int client_fd;
+       int ret = -1;
+
+       /* -2 here because this is an abstract unix socket so it needs a
+        * leading \0, and we null terminate, so it needs a trailing \0.
+        * Although null termination isn't required by the API, we do it anyway
+        * because we print the sockname out sometimes.
+        */
+       client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name);
+       if (client_fd < 0 && client_fd == -ECONNREFUSED)
+               return -ECONNREFUSED;
+       else if (client_fd < 0)
+               return -1;
+
+       TRACE("Command \"%s\" connected to command socket",
+             lxc_cmd_str(cmd->req.cmd));
+
+       ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req, sizeof(cmd->req));
+       if (ret != sizeof(cmd->req)) {
+               close(client_fd);
+
+               if (errno == EPIPE)
+                       return -EPIPE;
+
+               if (ret >= 0)
+                       return -EMSGSIZE;
+
+               return -1;
+       }
+
+       TRACE("Command \"%s\" requested data of length %d",
+             lxc_cmd_str(cmd->req.cmd), cmd->req.datalen);
+
+       if (cmd->req.datalen > 0) {
+               ret = send(client_fd, cmd->req.data, cmd->req.datalen, MSG_NOSIGNAL);
+               if (ret != cmd->req.datalen) {
+                       close(client_fd);
+
+                       if (errno == EPIPE)
+                               return -EPIPE;
+
+                       if (ret >= 0)
+                               return -EMSGSIZE;
+
+                       return -1;
+               }
+       }
+
+       return client_fd;
+}
+
 /*
  * lxc_cmd: Connect to the specified running container, send it a command
  * request and collect the response
@@ -228,10 +282,7 @@ static int lxc_cmd_rsp_send(int fd, struct lxc_cmd_rsp *rsp)
 static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
                   const char *lxcpath, const char *hashed_sock_name)
 {
-       int sock, ret = -1;
-       char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
-       char *offset = &path[1];
-       size_t len;
+       int client_fd, ret = -1;
        bool stay_connected = false;
 
        if (cmd->req.cmd == LXC_CMD_CONSOLE ||
@@ -245,64 +296,34 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
         * Although null termination isn't required by the API, we do it anyway
         * because we print the sockname out sometimes.
         */
-       len = sizeof(path)-2;
-       if (lxc_make_abstract_socket_name(offset, len, name, lxcpath,
-                                         hashed_sock_name, "command"))
-               return -1;
+       TRACE("command %s tries to connect command socket",
+             lxc_cmd_str(cmd->req.cmd));
 
-       sock = lxc_abstract_unix_connect(path);
-       TRACE("command %s tries to connect to \"@%s\"",
-             lxc_cmd_str(cmd->req.cmd), offset);
-       if (sock < 0) {
-               if (errno == ECONNREFUSED) {
-                       TRACE("command %s failed to connect to \"@%s\": %s",
-                             lxc_cmd_str(cmd->req.cmd), offset,
-                             strerror(errno));
+       client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name);
+       if (client_fd < 0) {
+               TRACE("command %s failed to connect command socket: %s",
+                     lxc_cmd_str(cmd->req.cmd), strerror(errno));
+               if (client_fd == -ECONNREFUSED) {
                        *stopped = 1;
-               } else {
-                       SYSERROR("command %s failed to connect to \"@%s\": %s",
-                                lxc_cmd_str(cmd->req.cmd), offset,
-                                strerror(errno));
+                       return -1;
                }
 
-               return -1;
-       }
-
-       ret = lxc_abstract_unix_send_credential(sock, &cmd->req, sizeof(cmd->req));
-       if (ret != sizeof(cmd->req)) {
-               if (errno == EPIPE)
+               if (client_fd == -EPIPE)
                        goto epipe;
-               SYSERROR("Command %s failed to send req to \"@%s\" %d.",
-                        lxc_cmd_str(cmd->req.cmd), offset, ret);
-               if (ret >=0)
-                       ret = -1;
-               goto out;
-       }
 
-       if (cmd->req.datalen > 0) {
-               ret = send(sock, cmd->req.data, cmd->req.datalen, MSG_NOSIGNAL);
-               if (ret != cmd->req.datalen) {
-                       if (errno == EPIPE)
-                               goto epipe;
-                       SYSERROR("Command %s failed to send request data to \"@%s\" %d.",
-                                lxc_cmd_str(cmd->req.cmd), offset, ret);
-                       if (ret >=0)
-                               ret = -1;
-                       goto out;
-               }
+               goto out;
        }
 
-       ret = lxc_cmd_rsp_recv(sock, cmd);
+       ret = lxc_cmd_rsp_recv(client_fd, cmd);
 out:
        if (!stay_connected || ret <= 0)
-               close(sock);
+               close(client_fd);
        if (stay_connected && ret > 0)
-               cmd->rsp.ret = sock;
+               cmd->rsp.ret = client_fd;
 
        return ret;
 
 epipe:
-       close(sock);
        *stopped = 1;
        return 0;
 }
@@ -896,37 +917,27 @@ static int lxc_cmd_add_state_client_callback(int fd, struct lxc_cmd_req *req,
                                             struct lxc_handler *handler)
 {
        struct lxc_cmd_rsp rsp = {0};
-       struct state_client *newclient;
-       struct lxc_list *tmplist;
 
        if (req->datalen < 0) {
-               TRACE("requested datalen was < 0");
+               TRACE("Requested datalen was < 0");
                return -1;
        }
 
-       if (!req->data) {
-               TRACE("no states requested");
+       if (req->datalen > (sizeof(lxc_state_t) * MAX_STATE)) {
+               TRACE("Requested datalen was too large");
                return -1;
        }
 
-       newclient = malloc(sizeof(*newclient));
-       if (!newclient)
-               return -1;
-
-       /* copy requested states */
-       memcpy(newclient->states, req->data, sizeof(newclient->states));
-       newclient->clientfd = fd;
-
-       tmplist = malloc(sizeof(*tmplist));
-       if (!tmplist) {
-               free(newclient);
+       if (!req->data) {
+               TRACE("No states requested");
                return -1;
        }
 
-       lxc_list_add_elem(tmplist, newclient);
-       lxc_list_add_tail(&handler->state_clients, tmplist);
-
-       TRACE("added state client %d to state client list", fd);
+       rsp.ret = lxc_add_state_client(fd, handler, (lxc_state_t *)req->data);
+       if (rsp.ret < 0)
+               ERROR("Failed to add state client %d to state client list", fd);
+       else
+               TRACE("Added state client %d to state client list", fd);
 
        return lxc_cmd_rsp_send(fd, &rsp);
 }
@@ -981,24 +992,30 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
                goto out_close;
        }
 
+       TRACE("Processing \"%s\" command", lxc_cmd_str(req.cmd));
        if (ret < 0) {
-               SYSERROR("Failed to receive data on command socket.");
+               SYSERROR("Failed to receive data on command socket for \"%s\"",
+                        lxc_cmd_str(req.cmd));
                goto out_close;
        }
 
        if (!ret) {
-               DEBUG("Peer has disconnected.");
+               DEBUG("Peer has disconnected for \"%s\"", lxc_cmd_str(req.cmd));
                goto out_close;
        }
 
        if (ret != sizeof(req)) {
-               WARN("Failed to receive full command request. Ignoring request.");
+               WARN("Failed to receive full command request. Ignoring request "
+                    "for \"%s\"",
+                    lxc_cmd_str(req.cmd));
                ret = -1;
                goto out_close;
        }
 
        if (req.datalen > LXC_CMD_DATA_MAX) {
-               ERROR("Received command data length %d is too large.", req.datalen);
+               ERROR("Received command data length %d is too large for "
+                     "command \"%s\"",
+                     req.datalen, lxc_cmd_str(req.cmd));
                ret = -1;
                goto out_close;
        }
@@ -1009,7 +1026,9 @@ static int lxc_cmd_handler(int fd, uint32_t events, void *data,
                reqdata = alloca(req.datalen);
                ret = recv(fd, reqdata, req.datalen, 0);
                if (ret != req.datalen) {
-                       WARN("Failed to receive full command request. Ignoring request.");
+                       WARN("Failed to receive full command request. Ignoring "
+                            "request for \"%s\"",
+                            lxc_cmd_str(req.cmd));
                        ret = -1;
                        goto out_close;
                }
index d82e20ffef5badcdcf2e73a38adb8fb4f9784e82..fde7da9047303862bd8a7224f2c55938ada7adec 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include "af_unix.h"
 #include "commands.h"
 #include "commands_utils.h"
+#include "initutils.h"
 #include "log.h"
 #include "monitor.h"
 #include "state.h"
@@ -153,3 +155,60 @@ int lxc_make_abstract_socket_name(char *path, int len, const char *lxcname,
 
        return 0;
 }
+
+int lxc_cmd_connect(const char *name, const char *lxcpath,
+                   const char *hashed_sock_name)
+{
+       int ret, client_fd;
+       char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = {0};
+       char *offset = &path[1];
+       size_t len = sizeof(path) - 2;
+
+       /* -2 here because this is an abstract unix socket so it needs a
+        * leading \0, and we null terminate, so it needs a trailing \0.
+        * Although null termination isn't required by the API, we do it anyway
+        * because we print the sockname out sometimes.
+        */
+       ret = lxc_make_abstract_socket_name(offset, len, name, lxcpath,
+                                           hashed_sock_name, "command");
+       if (ret < 0)
+               return -1;
+
+       /* Get new client fd. */
+       client_fd = lxc_abstract_unix_connect(path);
+       if (client_fd < 0) {
+               if (errno == ECONNREFUSED)
+                       return -ECONNREFUSED;
+               return -1;
+       }
+
+       return client_fd;
+}
+
+int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler,
+                        lxc_state_t states[MAX_STATE])
+{
+       struct state_client *newclient;
+       struct lxc_list *tmplist;
+
+       newclient = malloc(sizeof(*newclient));
+       if (!newclient)
+               return -ENOMEM;
+
+       /* copy requested states */
+       memcpy(newclient->states, states, sizeof(newclient->states));
+       newclient->clientfd = state_client_fd;
+
+       tmplist = malloc(sizeof(*tmplist));
+       if (!tmplist) {
+               free(newclient);
+               return -ENOMEM;
+       }
+
+       lxc_list_add_elem(tmplist, newclient);
+       lxc_list_add_tail(&handler->state_clients, tmplist);
+
+       TRACE("added state client %d to state client list", state_client_fd);
+
+       return 0;
+}
index 40307b6abe84010c1b50bbeb326bef1ebe47db42..134a0d73a6f054f61a815f0f406cb4f0418dfc4a 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 
 #include "state.h"
+#include "commands.h"
 
 int lxc_make_abstract_socket_name(char *path, int len, const char *lxcname,
                                  const char *lxcpath,
@@ -53,4 +54,31 @@ extern int lxc_cmd_sock_get_state(const char *name, const char *lxcpath,
  */
 extern int lxc_cmd_sock_rcv_state(int state_client_fd, int timeout);
 
+/* lxc_add_state_client        Add a new state client to the container's
+ *                             in-memory handler.
+ *
+ * @param[int] state_client_fd The state client fd to add.
+ * @param[int] handler         The container's in-memory handler.
+ * @param[in] states           The states to wait for.
+ *
+ * @return                     Return  < 0 on error
+ *                                       0 on success
+ */
+extern int lxc_add_state_client(int state_client_fd,
+                               struct lxc_handler *handler,
+                               lxc_state_t states[MAX_STATE]);
+
+/* lxc_cmd_connect             Connect to the container's command socket.
+ *
+ * @param[in] name             Name of container to connect to.
+ * @param[in] lxcpath          The lxcpath in which the container is running.
+ * @param[in] hashed_sock_name The hashed name of the socket (optional). Can be
+ *                             NULL.
+ *
+ * @return                     Return   < 0 on error
+ *                                     >= 0 client fd
+ */
+extern int lxc_cmd_connect(const char *name, const char *lxcpath,
+                          const char *hashed_sock_name);
+
 #endif /* __LXC_COMMANDS_UTILS_H */