13e2ea4ccSMatthew Dillon /*
23e2ea4ccSMatthew Dillon * Copyright (c) 2014 The DragonFly Project. All rights reserved.
33e2ea4ccSMatthew Dillon *
43e2ea4ccSMatthew Dillon * This code is derived from software contributed to The DragonFly Project
53e2ea4ccSMatthew Dillon * by Matthew Dillon <dillon@backplane.com>
63e2ea4ccSMatthew Dillon *
73e2ea4ccSMatthew Dillon * Redistribution and use in source and binary forms, with or without
83e2ea4ccSMatthew Dillon * modification, are permitted provided that the following conditions
93e2ea4ccSMatthew Dillon * are met:
103e2ea4ccSMatthew Dillon *
113e2ea4ccSMatthew Dillon * 1. Redistributions of source code must retain the above copyright
123e2ea4ccSMatthew Dillon * notice, this list of conditions and the following disclaimer.
133e2ea4ccSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
143e2ea4ccSMatthew Dillon * notice, this list of conditions and the following disclaimer in
153e2ea4ccSMatthew Dillon * the documentation and/or other materials provided with the
163e2ea4ccSMatthew Dillon * distribution.
173e2ea4ccSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its
183e2ea4ccSMatthew Dillon * contributors may be used to endorse or promote products derived
193e2ea4ccSMatthew Dillon * from this software without specific, prior written permission.
203e2ea4ccSMatthew Dillon *
213e2ea4ccSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
223e2ea4ccSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
233e2ea4ccSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
243e2ea4ccSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
253e2ea4ccSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
263e2ea4ccSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
273e2ea4ccSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
283e2ea4ccSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
293e2ea4ccSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
303e2ea4ccSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
313e2ea4ccSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323e2ea4ccSMatthew Dillon * SUCH DAMAGE.
333e2ea4ccSMatthew Dillon */
343e2ea4ccSMatthew Dillon /*
353e2ea4ccSMatthew Dillon * Handle remote listen/connect and parsing operations.
363e2ea4ccSMatthew Dillon */
373e2ea4ccSMatthew Dillon
383e2ea4ccSMatthew Dillon #include "svc.h"
393e2ea4ccSMatthew Dillon
403e2ea4ccSMatthew Dillon typedef struct SvcConnect {
413e2ea4ccSMatthew Dillon struct SvcConnect *next;
423e2ea4ccSMatthew Dillon command_t *cmd;
433e2ea4ccSMatthew Dillon char *label;
443e2ea4ccSMatthew Dillon pthread_t td;
453e2ea4ccSMatthew Dillon int active;
463e2ea4ccSMatthew Dillon int fd;
473e2ea4ccSMatthew Dillon int rc;
483e2ea4ccSMatthew Dillon FILE *fpr;
493e2ea4ccSMatthew Dillon FILE *fpw;
503e2ea4ccSMatthew Dillon } connect_t;
513e2ea4ccSMatthew Dillon
523e2ea4ccSMatthew Dillon static void *remote_connect_thread(void *arg);
533e2ea4ccSMatthew Dillon static void *remote_listener_thread(void *arg);
543e2ea4ccSMatthew Dillon static void *remote_accepted_thread(void *arg);
553e2ea4ccSMatthew Dillon static void remote_issue(connect_t *conn, command_t *cmd);
563e2ea4ccSMatthew Dillon static int decode_args(connect_t *conn, char ***avp,
573e2ea4ccSMatthew Dillon const char *ptr, size_t len);
583e2ea4ccSMatthew Dillon
593e2ea4ccSMatthew Dillon connect_t *CHead;
603e2ea4ccSMatthew Dillon connect_t **CNextP = &CHead;
613e2ea4ccSMatthew Dillon
623e2ea4ccSMatthew Dillon
633e2ea4ccSMatthew Dillon /*
643e2ea4ccSMatthew Dillon * Execute cmd on the running service by connecting to the service, passing-in
653e2ea4ccSMatthew Dillon * the command, and processing results.
663e2ea4ccSMatthew Dillon *
673e2ea4ccSMatthew Dillon * Called only by master process
683e2ea4ccSMatthew Dillon */
693e2ea4ccSMatthew Dillon void
remote_execute(command_t * cmd,const char * label)703e2ea4ccSMatthew Dillon remote_execute(command_t *cmd, const char *label)
713e2ea4ccSMatthew Dillon {
723e2ea4ccSMatthew Dillon connect_t *conn = calloc(sizeof(*conn), 1);
733e2ea4ccSMatthew Dillon
743e2ea4ccSMatthew Dillon conn->fd = -1;
753e2ea4ccSMatthew Dillon conn->cmd = cmd;
763e2ea4ccSMatthew Dillon conn->label = strdup(label);
773e2ea4ccSMatthew Dillon conn->active = 1;
783e2ea4ccSMatthew Dillon conn->next = *CNextP;
793e2ea4ccSMatthew Dillon *CNextP = conn;
803e2ea4ccSMatthew Dillon
813e2ea4ccSMatthew Dillon pthread_create(&conn->td, NULL, remote_connect_thread, conn);
823e2ea4ccSMatthew Dillon }
833e2ea4ccSMatthew Dillon
843e2ea4ccSMatthew Dillon /*
853e2ea4ccSMatthew Dillon * Threaded connect/execute
863e2ea4ccSMatthew Dillon */
873e2ea4ccSMatthew Dillon static
883e2ea4ccSMatthew Dillon void *
remote_connect_thread(void * arg)893e2ea4ccSMatthew Dillon remote_connect_thread(void *arg)
903e2ea4ccSMatthew Dillon {
913e2ea4ccSMatthew Dillon connect_t *conn;
923e2ea4ccSMatthew Dillon command_t *cmd;
933e2ea4ccSMatthew Dillon struct sockaddr_un sou;
943e2ea4ccSMatthew Dillon size_t len;
953e2ea4ccSMatthew Dillon char *ptr;
963e2ea4ccSMatthew Dillon
973e2ea4ccSMatthew Dillon conn = arg;
983e2ea4ccSMatthew Dillon cmd = conn->cmd;
993e2ea4ccSMatthew Dillon
1003e2ea4ccSMatthew Dillon bzero(&sou, sizeof(sou));
1013e2ea4ccSMatthew Dillon if ((conn->fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
1023e2ea4ccSMatthew Dillon sou.sun_family = AF_UNIX;
1033e2ea4ccSMatthew Dillon snprintf(sou.sun_path, sizeof(sou.sun_path),
1043e2ea4ccSMatthew Dillon "%s/service.%s.sk", cmd->piddir, conn->label);
1053e2ea4ccSMatthew Dillon len = strlen(sou.sun_path);
1063e2ea4ccSMatthew Dillon len = offsetof(struct sockaddr_un, sun_path[len+1]);
1073e2ea4ccSMatthew Dillon
1083e2ea4ccSMatthew Dillon if (connect(conn->fd, (void *)&sou, len) < 0) {
1093e2ea4ccSMatthew Dillon close(conn->fd);
1103e2ea4ccSMatthew Dillon conn->fd = -1;
1113e2ea4ccSMatthew Dillon }
1123e2ea4ccSMatthew Dillon }
1133e2ea4ccSMatthew Dillon if (conn->fd >= 0) {
1143e2ea4ccSMatthew Dillon /*
1153e2ea4ccSMatthew Dillon * Issue command
1163e2ea4ccSMatthew Dillon */
1173e2ea4ccSMatthew Dillon conn->fpr = fdopen(conn->fd, "r");
1183e2ea4ccSMatthew Dillon conn->fpw = fdopen(dup(conn->fd), "w");
1193e2ea4ccSMatthew Dillon conn->fd = -1;
1203e2ea4ccSMatthew Dillon setvbuf(conn->fpr, NULL, _IOFBF, 0);
1213e2ea4ccSMatthew Dillon setvbuf(conn->fpw, NULL, _IOFBF, 0);
1223e2ea4ccSMatthew Dillon remote_issue(conn, cmd);
1233e2ea4ccSMatthew Dillon while ((ptr = fgetln(conn->fpr, &len)) != NULL) {
1243e2ea4ccSMatthew Dillon if (len == 2 && ptr[0] == '.' && ptr[1] == '\n')
1253e2ea4ccSMatthew Dillon break;
126*82f39527SMatthew Dillon
127*82f39527SMatthew Dillon /*
128*82f39527SMatthew Dillon * de-escape ..
129*82f39527SMatthew Dillon */
130*82f39527SMatthew Dillon if (len == 3 && ptr[0] == '.' && ptr[1] == '.' &&
131*82f39527SMatthew Dillon ptr[2] == '\n') {
132*82f39527SMatthew Dillon ++ptr;
133*82f39527SMatthew Dillon --len;
134*82f39527SMatthew Dillon }
1353e2ea4ccSMatthew Dillon fwrite(ptr, 1, len, cmd->fp);
1363e2ea4ccSMatthew Dillon fflush(cmd->fp);
1373e2ea4ccSMatthew Dillon }
1383e2ea4ccSMatthew Dillon conn->rc = 0;
1393e2ea4ccSMatthew Dillon conn->active = 0;
1403e2ea4ccSMatthew Dillon fclose(conn->fpr);
1413e2ea4ccSMatthew Dillon fclose(conn->fpw);
1423e2ea4ccSMatthew Dillon conn->fpr = NULL;
1433e2ea4ccSMatthew Dillon conn->fpw = NULL;
1443e2ea4ccSMatthew Dillon } else {
1453e2ea4ccSMatthew Dillon /*
1463e2ea4ccSMatthew Dillon * Connection failed
1473e2ea4ccSMatthew Dillon */
1483e2ea4ccSMatthew Dillon fprintf(cmd->fp,
1493e2ea4ccSMatthew Dillon "Unable to connect to service %s\n",
1503e2ea4ccSMatthew Dillon conn->label);
1513e2ea4ccSMatthew Dillon conn->rc = 1;
1523e2ea4ccSMatthew Dillon conn->active = 0;
153ee6361d4SMatthew Dillon if (cmd->force_remove_files) {
154ee6361d4SMatthew Dillon fprintf(cmd->fp,
155ee6361d4SMatthew Dillon "Removing pid and socket files for %s\n",
156ee6361d4SMatthew Dillon conn->label);
157ee6361d4SMatthew Dillon remove_pid_and_socket(cmd, conn->label);
158ee6361d4SMatthew Dillon }
1593e2ea4ccSMatthew Dillon }
1603e2ea4ccSMatthew Dillon return NULL;
1613e2ea4ccSMatthew Dillon }
1623e2ea4ccSMatthew Dillon
1633e2ea4ccSMatthew Dillon /*
1643e2ea4ccSMatthew Dillon * Called only by master process
1653e2ea4ccSMatthew Dillon *
1663e2ea4ccSMatthew Dillon * Collect status from all remote commands.
1673e2ea4ccSMatthew Dillon */
1683e2ea4ccSMatthew Dillon int
remote_wait(void)1693e2ea4ccSMatthew Dillon remote_wait(void)
1703e2ea4ccSMatthew Dillon {
1713e2ea4ccSMatthew Dillon connect_t *scan;
1723e2ea4ccSMatthew Dillon int rc = 0;
1733e2ea4ccSMatthew Dillon
1743e2ea4ccSMatthew Dillon while ((scan = CHead) != NULL) {
1753e2ea4ccSMatthew Dillon if (pthread_join(scan->td, NULL) < 0)
1763e2ea4ccSMatthew Dillon continue;
1773e2ea4ccSMatthew Dillon assert(scan->active == 0);
1783e2ea4ccSMatthew Dillon rc += scan->rc;
1793e2ea4ccSMatthew Dillon CHead = scan->next;
1803e2ea4ccSMatthew Dillon
1813e2ea4ccSMatthew Dillon if (scan->fpr) {
1823e2ea4ccSMatthew Dillon fclose(scan->fpr);
1833e2ea4ccSMatthew Dillon scan->fpr = NULL;
1843e2ea4ccSMatthew Dillon }
1853e2ea4ccSMatthew Dillon if (scan->fpw) {
1863e2ea4ccSMatthew Dillon fclose(scan->fpw);
1873e2ea4ccSMatthew Dillon scan->fpw = NULL;
1883e2ea4ccSMatthew Dillon }
1893e2ea4ccSMatthew Dillon if (scan->fd >= 0) {
1903e2ea4ccSMatthew Dillon close(scan->fd);
1913e2ea4ccSMatthew Dillon scan->fd = -1;
1923e2ea4ccSMatthew Dillon }
1933e2ea4ccSMatthew Dillon if (scan->label) {
1943e2ea4ccSMatthew Dillon free(scan->label);
1953e2ea4ccSMatthew Dillon scan->label = NULL;
1963e2ea4ccSMatthew Dillon }
1973e2ea4ccSMatthew Dillon scan->cmd = NULL;
1983e2ea4ccSMatthew Dillon free(scan);
1993e2ea4ccSMatthew Dillon }
2003e2ea4ccSMatthew Dillon return rc;
2013e2ea4ccSMatthew Dillon }
2023e2ea4ccSMatthew Dillon
2033e2ea4ccSMatthew Dillon /*
2043e2ea4ccSMatthew Dillon * Create the unix domain socket and pid file for the service
2053e2ea4ccSMatthew Dillon * and start a thread to accept and process connections.
2063e2ea4ccSMatthew Dillon *
2073e2ea4ccSMatthew Dillon * Return 0 on success, non-zero if the socket could not be created.
2083e2ea4ccSMatthew Dillon */
2093e2ea4ccSMatthew Dillon void
remote_listener(command_t * cmd,int lfd)2103e2ea4ccSMatthew Dillon remote_listener(command_t *cmd, int lfd)
2113e2ea4ccSMatthew Dillon {
2123e2ea4ccSMatthew Dillon connect_t *conn;
2133e2ea4ccSMatthew Dillon
2143e2ea4ccSMatthew Dillon /*
2153e2ea4ccSMatthew Dillon * child, create our unix domain socket listener thread.
2163e2ea4ccSMatthew Dillon */
2173e2ea4ccSMatthew Dillon conn = calloc(sizeof(*conn), 1);
2183e2ea4ccSMatthew Dillon conn->fd = lfd;
2193e2ea4ccSMatthew Dillon conn->cmd = cmd;
2203e2ea4ccSMatthew Dillon conn->label = strdup(cmd->label);
2213e2ea4ccSMatthew Dillon conn->active = 1;
2223e2ea4ccSMatthew Dillon
2233e2ea4ccSMatthew Dillon conn->next = *CNextP;
2243e2ea4ccSMatthew Dillon *CNextP = conn;
2253e2ea4ccSMatthew Dillon pthread_create(&conn->td, NULL, remote_listener_thread, conn);
2263e2ea4ccSMatthew Dillon }
2273e2ea4ccSMatthew Dillon
2283e2ea4ccSMatthew Dillon static void *
remote_listener_thread(void * arg)2293e2ea4ccSMatthew Dillon remote_listener_thread(void *arg)
2303e2ea4ccSMatthew Dillon {
2313e2ea4ccSMatthew Dillon connect_t *lconn = arg;
2323e2ea4ccSMatthew Dillon connect_t *conn;
2333e2ea4ccSMatthew Dillon struct sockaddr_un sou;
2343e2ea4ccSMatthew Dillon socklen_t len;
2353e2ea4ccSMatthew Dillon
2363e2ea4ccSMatthew Dillon conn = calloc(sizeof(*conn), 1);
2373e2ea4ccSMatthew Dillon for (;;) {
2383e2ea4ccSMatthew Dillon len = sizeof(sou);
2393e2ea4ccSMatthew Dillon conn->fd = accept(lconn->fd, (void *)&sou, &len);
2403e2ea4ccSMatthew Dillon conn->label = strdup(lconn->label);
2413e2ea4ccSMatthew Dillon if (conn->fd < 0) {
2423e2ea4ccSMatthew Dillon if (errno == EINTR)
2433e2ea4ccSMatthew Dillon continue;
2443e2ea4ccSMatthew Dillon break;
2453e2ea4ccSMatthew Dillon }
2463e2ea4ccSMatthew Dillon pthread_create(&conn->td, NULL, remote_accepted_thread, conn);
2473e2ea4ccSMatthew Dillon conn = calloc(sizeof(*conn), 1);
2483e2ea4ccSMatthew Dillon }
2493e2ea4ccSMatthew Dillon free(conn);
2503e2ea4ccSMatthew Dillon
2513e2ea4ccSMatthew Dillon return NULL;
2523e2ea4ccSMatthew Dillon }
2533e2ea4ccSMatthew Dillon
2543e2ea4ccSMatthew Dillon static void *
remote_accepted_thread(void * arg)2553e2ea4ccSMatthew Dillon remote_accepted_thread(void *arg)
2563e2ea4ccSMatthew Dillon {
2573e2ea4ccSMatthew Dillon connect_t *conn = arg;
2583e2ea4ccSMatthew Dillon command_t cmd;
2593e2ea4ccSMatthew Dillon char *ptr;
2603e2ea4ccSMatthew Dillon size_t len;
2613e2ea4ccSMatthew Dillon int rc;
2623e2ea4ccSMatthew Dillon int ac;
2633e2ea4ccSMatthew Dillon char **av;
2643e2ea4ccSMatthew Dillon
2653e2ea4ccSMatthew Dillon pthread_detach(conn->td);
2663e2ea4ccSMatthew Dillon conn->fpr = fdopen(conn->fd, "r");
2673e2ea4ccSMatthew Dillon conn->fpw = fdopen(dup(conn->fd), "w");
2683e2ea4ccSMatthew Dillon conn->fd = -1;
2693e2ea4ccSMatthew Dillon setvbuf(conn->fpr, NULL, _IOFBF, 0);
2703e2ea4ccSMatthew Dillon setvbuf(conn->fpw, NULL, _IOFBF, 0);
2713e2ea4ccSMatthew Dillon
2723e2ea4ccSMatthew Dillon while ((ptr = fgetln(conn->fpr, &len)) != NULL) {
2733e2ea4ccSMatthew Dillon ac = decode_args(conn, &av, ptr, len);
2743e2ea4ccSMatthew Dillon rc = process_cmd(&cmd, conn->fpw, ac, av);
2753e2ea4ccSMatthew Dillon cmd.cmdline = 0; /* we are the remote */
2763e2ea4ccSMatthew Dillon cmd.commanded = 1; /* commanded action (vs automatic) */
2773e2ea4ccSMatthew Dillon sreplace(&cmd.label, conn->label);
2783e2ea4ccSMatthew Dillon if (rc == 0) {
2793e2ea4ccSMatthew Dillon pthread_mutex_lock(&serial_mtx);
2803e2ea4ccSMatthew Dillon rc = execute_cmd(&cmd);
2813e2ea4ccSMatthew Dillon pthread_mutex_unlock(&serial_mtx);
2823e2ea4ccSMatthew Dillon }
2833e2ea4ccSMatthew Dillon free_cmd(&cmd);
2843e2ea4ccSMatthew Dillon afree(&av);
2853e2ea4ccSMatthew Dillon fwrite(".\n", 2, 1, conn->fpw);
2863e2ea4ccSMatthew Dillon fflush(conn->fpw);
2873e2ea4ccSMatthew Dillon }
2883e2ea4ccSMatthew Dillon fclose(conn->fpr);
2893e2ea4ccSMatthew Dillon fclose(conn->fpw);
2903e2ea4ccSMatthew Dillon conn->fpr = NULL;
2913e2ea4ccSMatthew Dillon conn->fpw = NULL;
2923e2ea4ccSMatthew Dillon free(conn->label);
2933e2ea4ccSMatthew Dillon free(conn);
2943e2ea4ccSMatthew Dillon
2953e2ea4ccSMatthew Dillon return NULL;
2963e2ea4ccSMatthew Dillon }
2973e2ea4ccSMatthew Dillon
2983e2ea4ccSMatthew Dillon /*
2993e2ea4ccSMatthew Dillon * Issue the command to the remote, encode the arguments.
3003e2ea4ccSMatthew Dillon */
3013e2ea4ccSMatthew Dillon static
3023e2ea4ccSMatthew Dillon void
remote_issue(connect_t * conn,command_t * cmd)3033e2ea4ccSMatthew Dillon remote_issue(connect_t *conn, command_t *cmd)
3043e2ea4ccSMatthew Dillon {
3053e2ea4ccSMatthew Dillon int i;
3063e2ea4ccSMatthew Dillon
3073e2ea4ccSMatthew Dillon for (i = 1; i < cmd->orig_ac; ++i) {
3083e2ea4ccSMatthew Dillon const char *str = cmd->orig_av[i];
3093e2ea4ccSMatthew Dillon
3103e2ea4ccSMatthew Dillon if (i != 1)
3113e2ea4ccSMatthew Dillon putc(' ', conn->fpw);
3123e2ea4ccSMatthew Dillon while (*str) {
3133e2ea4ccSMatthew Dillon if (*str == ' ' || *str == '\\' || *str == '\n')
3143e2ea4ccSMatthew Dillon putc('\\', conn->fpw);
3153e2ea4ccSMatthew Dillon putc(*str, conn->fpw);
3163e2ea4ccSMatthew Dillon ++str;
3173e2ea4ccSMatthew Dillon }
3183e2ea4ccSMatthew Dillon }
3193e2ea4ccSMatthew Dillon putc('\n', conn->fpw);
3203e2ea4ccSMatthew Dillon fflush(conn->fpw);
3213e2ea4ccSMatthew Dillon }
3223e2ea4ccSMatthew Dillon
3233e2ea4ccSMatthew Dillon /*
3243e2ea4ccSMatthew Dillon * Decode arguments
3253e2ea4ccSMatthew Dillon */
3263e2ea4ccSMatthew Dillon static int
decode_args(connect_t * conn __unused,char *** avp,const char * ptr,size_t len)3273e2ea4ccSMatthew Dillon decode_args(connect_t *conn __unused, char ***avp, const char *ptr, size_t len)
3283e2ea4ccSMatthew Dillon {
3293e2ea4ccSMatthew Dillon char **av;
3303e2ea4ccSMatthew Dillon char *arg;
3313e2ea4ccSMatthew Dillon size_t i;
3323e2ea4ccSMatthew Dillon size_t j;
3333e2ea4ccSMatthew Dillon int acmax;
3343e2ea4ccSMatthew Dillon int ac;
3353e2ea4ccSMatthew Dillon
3363e2ea4ccSMatthew Dillon if (len && ptr[len-1] == '\n')
3373e2ea4ccSMatthew Dillon --len;
3383e2ea4ccSMatthew Dillon
3393e2ea4ccSMatthew Dillon acmax = 3; /* av[0], first arg, terminating NULL */
3403e2ea4ccSMatthew Dillon for (i = 0; i < len; ++i) {
3413e2ea4ccSMatthew Dillon if (ptr[i] == ' ')
3423e2ea4ccSMatthew Dillon ++acmax;
3433e2ea4ccSMatthew Dillon }
3443e2ea4ccSMatthew Dillon av = calloc(sizeof(char *), acmax);
3453e2ea4ccSMatthew Dillon av[0] = NULL;
3463e2ea4ccSMatthew Dillon ac = 1;
3473e2ea4ccSMatthew Dillon
3483e2ea4ccSMatthew Dillon i = 0;
3493e2ea4ccSMatthew Dillon while (i < len) {
3503e2ea4ccSMatthew Dillon for (j = i; j < len; ++j) {
3513e2ea4ccSMatthew Dillon if (ptr[j] == ' ')
3523e2ea4ccSMatthew Dillon break;
3533e2ea4ccSMatthew Dillon }
3543e2ea4ccSMatthew Dillon arg = malloc(j - i + 1); /* worst case arg size */
3553e2ea4ccSMatthew Dillon j = 0;
3563e2ea4ccSMatthew Dillon while (i < len) {
3573e2ea4ccSMatthew Dillon if (ptr[i] == ' ')
3583e2ea4ccSMatthew Dillon break;
3593e2ea4ccSMatthew Dillon if (ptr[i] == '\\' && i + 1 < len) {
3603e2ea4ccSMatthew Dillon arg[j++] = ptr[i+1];
3613e2ea4ccSMatthew Dillon i += 2;
3623e2ea4ccSMatthew Dillon } else {
3633e2ea4ccSMatthew Dillon arg[j++] = ptr[i];
3643e2ea4ccSMatthew Dillon i += 1;
3653e2ea4ccSMatthew Dillon }
3663e2ea4ccSMatthew Dillon }
3673e2ea4ccSMatthew Dillon arg[j] = 0;
3683e2ea4ccSMatthew Dillon av[ac++] = arg;
3693e2ea4ccSMatthew Dillon if (i < len && ptr[i] == ' ')
3703e2ea4ccSMatthew Dillon ++i;
3713e2ea4ccSMatthew Dillon }
3723e2ea4ccSMatthew Dillon av[ac] = NULL;
3733e2ea4ccSMatthew Dillon
3743e2ea4ccSMatthew Dillon #if 0
3753e2ea4ccSMatthew Dillon fprintf(conn->fpw, "DECODE ARGS: ");
3763e2ea4ccSMatthew Dillon for (i = 1; i < (size_t)ac; ++i)
3773e2ea4ccSMatthew Dillon fprintf(conn->fpw, " \"%s\"", av[i]);
3783e2ea4ccSMatthew Dillon fprintf(conn->fpw, "\n");
3793e2ea4ccSMatthew Dillon fflush(conn->fpw);
3803e2ea4ccSMatthew Dillon #endif
3813e2ea4ccSMatthew Dillon
3823e2ea4ccSMatthew Dillon *avp = av;
3833e2ea4ccSMatthew Dillon return ac;
3843e2ea4ccSMatthew Dillon }
385