Start reworking rpcclient to use popt rather than next_token to parse
authorMartin Pool <mbp@samba.org>
Mon, 17 Feb 2003 05:42:36 +0000 (05:42 +0000)
committerMartin Pool <mbp@samba.org>
Mon, 17 Feb 2003 05:42:36 +0000 (05:42 +0000)
command lines.  This makes the code much simpler and also stops
trivial syntax errors from causing a crash.

Also fix support for semicolon-separated commands in -c, which is
promised by the manual but apparently never working due to an
off-by-one error.
(This used to be commit d85a25e733fe970ae96a02a5cbc892f2b8dca1b7)

source3/rpcclient/rpcclient.c

index 2609519dc487d7da91818632b1e62245f625d77f..f38ef64eb2aa24904cb878d987c21f9be8e741f8 100644 (file)
@@ -3,6 +3,7 @@
    RPC pipe client
 
    Copyright (C) Tim Potter 2000-2001
+   Copyright (C) Martin Pool 2003
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 DOM_SID domain_sid;
 
-/* List to hold groups of commands */
+
+/* List to hold groups of commands.
+ *
+ * Commands are defined in a list of arrays: arrays are easy to
+ * statically declare, and lists are easier to dynamically extend.
+ */
 
 static struct cmd_list {
        struct cmd_list *prev, *next;
@@ -164,7 +170,7 @@ static char* next_command (char** cmdstr)
        if (p)
                *p = '\0';
        pstrcpy(command, *cmdstr);
-       *cmdstr = p;
+       *cmdstr = p + 1;
        
        return command;
 }
@@ -371,7 +377,7 @@ static NTSTATUS cmd_quit(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK; /* NOTREACHED */
 }
 
-/* Build in rpcclient commands */
+/* Built in rpcclient commands */
 
 static struct cmd_set rpcclient_commands[] = {
 
@@ -432,145 +438,105 @@ static void add_command_set(struct cmd_set *cmd_set)
        DLIST_ADD(cmd_list, entry);
 }
 
-static NTSTATUS do_cmd(struct cli_state *cli, struct cmd_set *cmd_entry, 
-                       char *cmd)
-{
-       char **argv = NULL;
-       const char *p = cmd;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       pstring buf;
-       int argc = 0, i;
-
-       /* Count number of arguments first time through the loop then
-          allocate memory and strdup them. */
-
- again:
-       while(next_token(&p, buf, " ", sizeof(buf))) {
-               if (argv) {
-                       argv[argc] = strdup(buf);
-               }
-               
-               argc++;
-       }
-                               
-       if (!argv) {
 
-               /* Create argument list */
+/**
+ * Call an rpcclient function, passing an argv array.
+ *
+ * @param cmd Command to run, as a single string.
+ **/
+static NTSTATUS do_cmd(struct cli_state *cli,
+                      struct cmd_set *cmd_entry,
+                      int argc, char **argv)
+{
+       NTSTATUS result;
+       
+       TALLOC_CTX *mem_ctx;
 
-               argv = (char **)malloc(sizeof(char *) * argc);
-                memset(argv, 0, sizeof(char *) * argc);
+       /* Create mem_ctx */
 
-               if (!argv) {
-                       fprintf(stderr, "out of memory\n");
-                       result = NT_STATUS_NO_MEMORY;
-                        goto done;
-               }
-                                       
-               p = cmd;
-               argc = 0;
-                                       
-               goto again;
+       if (!(mem_ctx = talloc_init("do_cmd"))) {
+               DEBUG(0, ("talloc_init() failed\n"));
+               return NT_STATUS_UNSUCCESSFUL;
        }
 
-       /* Call the function */
-
-       if (cmd_entry->fn) {
-                TALLOC_CTX *mem_ctx;
-
-                /* Create mem_ctx */
-
-                if (!(mem_ctx = talloc_init("do_cmd"))) {
-                        DEBUG(0, ("talloc_init() failed\n"));
-                        goto done;
-                }
-
-                /* Open pipe */
-
-                if (cmd_entry->pipe_idx != -1)
-                        if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
-                                DEBUG(0, ("Could not initialise pipe\n"));
-                                goto done;
-                        }
-
-                /* Run command */
+       /* Open pipe */
 
-                result = cmd_entry->fn(cli, mem_ctx, argc, argv);
+       if (cmd_entry->pipe_idx != -1)
+               if (!cli_nt_session_open(cli, cmd_entry->pipe_idx)) {
+                       DEBUG(0, ("Could not initialize pipe\n"));
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
 
-                /* Cleanup */
+       /* Run command */
 
-                if (cmd_entry->pipe_idx != -1)
-                        cli_nt_session_close(cli);
+       result = cmd_entry->fn(cli, mem_ctx, argc, (char **) argv);
 
-                talloc_destroy(mem_ctx);
+       /* Cleanup */
 
-       } else {
-               fprintf (stderr, "Invalid command\n");
-                goto done;
-        }
+       if (cmd_entry->pipe_idx != -1)
+               cli_nt_session_close(cli);
 
- done:
-                                               
-       /* Cleanup */
+       talloc_destroy(mem_ctx);
 
-        if (argv) {
-                for (i = 0; i < argc; i++)
-                        SAFE_FREE(argv[i]);
-       
-                SAFE_FREE(argv);
-        }
-       
        return result;
 }
 
-/* Process a command entered at the prompt or as part of -c */
 
+/**
+ * Process a command entered at the prompt or as part of -c
+ *
+ * @returns The NTSTATUS from running the command.
+ **/
 static NTSTATUS process_cmd(struct cli_state *cli, char *cmd)
 {
        struct cmd_list *temp_list;
-       BOOL found = False;
-       pstring buf;
-       const char *p = cmd;
        NTSTATUS result = NT_STATUS_OK;
-       int len = 0;
-
-       if (cmd[strlen(cmd) - 1] == '\n')
-               cmd[strlen(cmd) - 1] = '\0';
+       int ret;
+       int argc;
+       char **argv = NULL;
 
-       if (!next_token(&p, buf, " ", sizeof(buf))) {
-               return NT_STATUS_OK;
+       if ((ret = poptParseArgvString(cmd, &argc, (const char ***) &argv)) != 0) {
+               fprintf(stderr, "rpcclient: %s\n", poptStrerror(ret));
+               return NT_STATUS_UNSUCCESSFUL;
        }
 
-        /* strip the trainly \n if it exsists */
-       len = strlen(buf);
-       if (buf[len-1] == '\n')
-               buf[len-1] = '\0';
-
-       /* Search for matching commands */
 
+       /* Walk through a dlist of arrays of commands. */
        for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
                struct cmd_set *temp_set = temp_list->cmd_set;
 
-               while(temp_set->name) {
-                       if (strequal(buf, temp_set->name)) {
-                                found = True;
-                               result = do_cmd(cli, temp_set, cmd);
+               while (temp_set->name) {
+                       if (strequal(argv[0], temp_set->name)) {
+                               if (!temp_set->fn) {
+                                       fprintf (stderr, "Invalid command\n");
+                                       goto out_free;
+                               }
 
-                               goto done;
+                               result = do_cmd(cli, temp_set, argc, argv);
+
+                               goto out_free;
                        }
                        temp_set++;
                }
        }
 
- done:
-       if (!found && buf[0]) {
-               printf("command not found: %s\n", buf);
-               return NT_STATUS_OK;
+       if (argv[0]) {
+               printf("command not found: %s\n", argv[0]);
        }
 
+out_free:
        if (!NT_STATUS_IS_OK(result)) {
                printf("result was %s\n", nt_errstr(result));
        }
 
+       if (argv) {
+               /* NOTE: popt allocates the whole argv, including the
+                * strings, as a single block.  So a single free is
+                * enough to release it -- we don't free the
+                * individual strings.  rtfm. */
+               free(argv);
+       }
+       
        return result;
 }