Pass command via sideband.
authorAndre Noll <maan@systemlinux.org>
Thu, 5 Jan 2012 16:19:49 +0000 (17:19 +0100)
committerAndre Noll <maan@systemlinux.org>
Sat, 5 May 2012 10:54:54 +0000 (12:54 +0200)
This makes para_cclient pass the paraslash command and its arguments
as a sideband packet to para_server if possible.

For sideband connections the command and its arguments are stored as
NULL-terminated strings. This is better than separating by newlines
(as we do for non-sideband connections) because it allows for arguments
containing newlines.

Suitable helpers for creating and parsing a buffer of NULL-terminated
strings, are provided in client_common.c and command.c, respectively.

No change for non-sideband connections.

client_common.c
command.c

index 53f7b5a..ff351e8 100644 (file)
@@ -245,6 +245,26 @@ static bool has_feature(const char *feature, struct client_task *ct)
        return find_arg(feature, ct->features) >= 0? true : false;
 }
 
+static int send_sb_command(struct client_task *ct)
+{
+       int i;
+       char *command, *p;
+       size_t len = 0;
+
+       if (ct->sbc)
+               return send_sb(ct, NULL, 0, 0, false);
+
+       for (i = 0; i < ct->conf.inputs_num; i++)
+               len += strlen(ct->conf.inputs[i]) + 1;
+       p = command = para_malloc(len);
+       for (i = 0; i < ct->conf.inputs_num; i++) {
+               strcpy(p, ct->conf.inputs[i]);
+               p += strlen(ct->conf.inputs[i]) + 1;
+       }
+       PARA_DEBUG_LOG("--> %s\n", command);
+       return send_sb(ct, command, len, SBD_COMMAND, false);
+}
+
 /**
  * The post select hook for client commands.
  *
@@ -385,6 +405,13 @@ static void client_post_select(struct sched *s, struct task *t)
                char *command = NULL;
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
                        return;
+               if (ct->use_sideband) {
+                       ret = send_sb_command(ct);
+                       if (ret <= 0)
+                               goto out;
+                       ct->status = CL_SENT_COMMAND;
+                       return;
+               }
                for (i = 0; i < ct->conf.inputs_num; i++) {
                        char *tmp = command;
                        command = make_message("%s\n%s", command?
index 8deb69c..c18cd4d 100644 (file)
--- a/command.c
+++ b/command.c
@@ -856,6 +856,38 @@ out:
 
 #define HANDSHAKE_BUFSIZE 4096
 
+static int parse_sb_command(struct command_context *cc, struct iovec *iov)
+{
+       int ret, i;
+       char *p, *end;
+
+       ret = -E_BAD_CMD;
+       if (iov->iov_base == NULL || iov->iov_len == 0)
+               goto out;
+       p = iov->iov_base;
+       p[iov->iov_len - 1] = '\0'; /* just to be sure */
+       cc->cmd = get_cmd_ptr(p, NULL);
+       if (!cc->cmd)
+               goto out;
+       ret = check_perms(cc->u->perms, cc->cmd);
+       if (ret < 0)
+               goto out;
+       end = iov->iov_base + iov->iov_len;
+       for (i = 0, p = iov->iov_base; p < end; i++)
+               p += strlen(p) + 1;
+       cc->argc = i;
+       cc->argv = para_malloc((cc->argc + 1) * sizeof(char *));
+       for (i = 0, p = iov->iov_base; p < end; i++) {
+               cc->argv[i] = para_strdup(p);
+               p += strlen(p) + 1;
+       }
+       cc->argv[cc->argc] = NULL;
+       ret = cc->argc;
+out:
+       free(iov->iov_base);
+       return ret;
+}
+
 /**
  * Perform user authentication and execute a command.
  *
@@ -981,24 +1013,35 @@ __noreturn void handle_connect(int fd, const char *peername)
                ret = sc_send_buffer(&cc->scc, PROCEED_MSG);
        if (ret < 0)
                goto net_err;
-       ret = read_command(&cc->scc, &command);
-       if (ret == -E_COMMAND_SYNTAX)
-               goto err_out;
-       if (ret < 0)
-               goto net_err;
-       ret = -E_BAD_CMD;
-       cc->cmd = parse_cmd(command);
-       if (!cc->cmd)
-               goto err_out;
-       /* valid command, check permissions */
-       ret = check_perms(cc->u->perms, cc->cmd);
-       if (ret < 0)
-               goto err_out;
-       /* valid command and sufficient perms */
-       ret = create_argv(command, "\n", &cc->argv);
-       if (ret < 0)
-               goto err_out;
-       cc->argc = ret;
+       if (cc->use_sideband) {
+               struct iovec iov;
+               ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov);
+               if (ret < 0)
+                       goto net_err;
+               ret = parse_sb_command(cc, &iov);
+               if (ret < 0)
+                       goto err_out;
+               cc->argc = ret;
+       } else {
+               ret = read_command(&cc->scc, &command);
+               if (ret == -E_COMMAND_SYNTAX)
+                       goto err_out;
+               if (ret < 0)
+                       goto net_err;
+               ret = -E_BAD_CMD;
+               cc->cmd = parse_cmd(command);
+               if (!cc->cmd)
+                       goto err_out;
+               /* valid command, check permissions */
+               ret = check_perms(cc->u->perms, cc->cmd);
+               if (ret < 0)
+                       goto err_out;
+               /* valid command and sufficient perms */
+               ret = create_argv(command, "\n", &cc->argv);
+               if (ret < 0)
+                       goto err_out;
+               cc->argc = ret;
+       }
        PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name,
                cc->u->name, peername);
        ret = cc->cmd->handler(cc);