You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by nk...@apache.org on 2019/12/11 15:05:39 UTC

[zookeeper] branch master updated: ZOOKEEPER-3599: cli.c: Resuscitate "old-style" argument parsing

This is an automated email from the ASF dual-hosted git repository.

nkalmar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 1f33a71  ZOOKEEPER-3599: cli.c: Resuscitate "old-style" argument parsing
1f33a71 is described below

commit 1f33a71457882f9bf3b481b29d4dac2ca0b5d350
Author: Damien Diederen <dd...@crosstwine.com>
AuthorDate: Wed Dec 11 16:05:32 2019 +0100

    ZOOKEEPER-3599: cli.c: Resuscitate "old-style" argument parsing
    
    ZOOKEEPER-2122 added SSL support to the C client and to the `cli_st`/`mt` tools.  It introduced (much-welcome!) GNU-style `getopt_long` argument parsing, but did not try to preserve backwards compatibility.
    
    An earlier version of this https://github.com/apache/zookeeper/pull/1131 introduced (optional) POSIX-style `getopt` argument parsing, and was consequently largely obsoleted by the SSL update.  It did, however, support "old-style" arguments to avoid [breaking workflows](https://xkcd.com/1172/).
    
    This patch salvages that feature while preserving the `getopt_long` goodness.  It is "legacy-only"; adding new positional arguments is not supported—as discussed in this thread: https://github.com/apache/zookeeper/pull/1131#pullrequestreview-320870245.
    
    Author: Damien Diederen <dd...@crosstwine.com>
    
    Reviewers: Enrico Olivelli <eo...@apache.org>, Norbert Kalmar <nk...@apache.org>
    
    Closes #1131 from ztzg/ZOOKEEPER-3599-use-getopt-in-cli-c
---
 zookeeper-client/zookeeper-client-c/src/cli.c | 81 +++++++++++++++++----------
 1 file changed, 50 insertions(+), 31 deletions(-)

diff --git a/zookeeper-client/zookeeper-client-c/src/cli.c b/zookeeper-client/zookeeper-client-c/src/cli.c
index 4a9c76f..64b328c 100644
--- a/zookeeper-client/zookeeper-client-c/src/cli.c
+++ b/zookeeper-client/zookeeper-client-c/src/cli.c
@@ -58,8 +58,8 @@ static zhandle_t *zh;
 static clientid_t myid;
 static const char *clientIdFile = 0;
 struct timeval startTime;
-static char *cmd;
-static char *cert;
+static const char *cmd;
+static const char *cert;
 static int batchMode=0;
 
 static int to_send=0;
@@ -330,7 +330,7 @@ int startsWith(const char *line, const char *prefix) {
 static const char *hostPort;
 static int verbose = 0;
 
-void processline(char *line) {
+void processline(const char *line) {
     int rc;
     int async = ((line[0] == 'a') && !(startsWith(line, "addauth ")));
     if (async) {
@@ -545,6 +545,7 @@ void processline(char *line) {
             int sequential = 0;
             int container = 0;
             int ttl = 0;
+            char *p = NULL;
 
             line++;
 
@@ -571,7 +572,7 @@ void processline(char *line) {
 
                     line++;
 
-                    ttl_value = strtol(line, &line, 10);
+                    ttl_value = strtol(line, &p, 10);
 
                     if (ttl_value <= 0) {
                         fprintf(stderr, "ttl value must be a positive integer\n");
@@ -579,7 +580,7 @@ void processline(char *line) {
                     }
 
                     // move back line pointer to the last digit
-                    line--;
+                    line = p - 1;
 
                     break;
                 default:
@@ -713,15 +714,15 @@ void processline(char *line) {
       zoo_add_auth(zh, line, ptr, ptr ? strlen(ptr) : 0, NULL, NULL);
     }
 }
+
 /*
- * Look for a command in the form 'cmd:command'.
- * Strips the prefix and copies the command in buf.
+ * Look for a command in the form 'cmd:command', and store a pointer
+ * to the command (without its prefix) into *buf if found.
+ *
  * Returns 0 if the argument does not start with the prefix.
- * Returns -1 in case of error (command too long).
  * Returns 1 in case of success.
- * 
  */
-int handleBatchMode(char* arg, char* buf, size_t maxlen) {    
+int handleBatchMode(const char* arg, const char** buf) {
     size_t cmdlen = strlen(arg);
     if (cmdlen < 4) {
         // too short
@@ -731,15 +732,7 @@ int handleBatchMode(char* arg, char* buf, size_t maxlen) {
     if(strncmp("cmd:", arg, 4) != 0){
         return 0;        
     }
-    // we must leave space for the NULL terminator
-    if (cmdlen >= maxlen) {
-          fprintf(stderr,
-                  "Command length %zu exceeds max length of %zu\n",
-                  cmdlen,
-                  maxlen);
-          return -1;
-    }
-    memcpy(cmd, arg + 4, cmdlen);
+    *buf = arg + 4;
     return 1;
 }
 
@@ -777,28 +770,21 @@ int main(int argc, char **argv) {
     while ((opt = getopt_long(argc, argv, "h:s:m:c:rd", long_options, &option_index)) != -1) {
         switch (opt) {
             case 'h':
-                hostPort = strdup(optarg);
+                hostPort = optarg;
                 break;
             case 'm':
-                clientIdFile = strdup(optarg);
-                fh = fopen(clientIdFile, "r");
-                if (fh) {
-                    if (fread(&myid, sizeof(myid), 1, fh) != sizeof(myid)) {
-                        memset(&myid, 0, sizeof(myid));
-                    }
-                    fclose(fh);
-                }
+                clientIdFile = optarg;
                 break;
             case 'r':
                 flags = ZOO_READONLY;
                 break;
             case 'c':
-                cmd = strdup(optarg);
+                cmd = optarg;
                 batchMode = 1;
                 fprintf(stderr,"Batch mode: %s\n",cmd);
                 break;
             case 's':
-                cert = strdup(optarg);
+                cert = optarg;
                 break;
             case 'd':
                 verbose = 1;
@@ -819,7 +805,30 @@ int main(int argc, char **argv) {
         }
     }
 
-    if (!hostPort) {
+    if (!hostPort && optind < argc) {
+        /*
+         * getopt_long did not find a '-h <connect-string>' option.
+         *
+         * The invoker may be using using the "old-style" command
+         * syntax, with positional parameters and "magical" prefixes
+         * such as 'cmd:'; let's see if we can make sense of it.
+         */
+        hostPort = argv[optind++];
+
+        if (optind < argc && !cmd && !clientIdFile) {
+            int batchModeRes = handleBatchMode(argv[optind], &cmd);
+            if (batchModeRes == 1) {
+                batchMode=1;
+                fprintf(stderr, "Batch mode: '%s'\n", cmd);
+            } else {
+                clientIdFile = argv[optind];
+            }
+
+            optind++;
+        }
+    }
+
+    if (!hostPort || optind < argc) {
         fprintf(stderr,
                 "\nUSAGE:    %s -h zk_host_1:port_1,zk_host_2:port_2,... [OPTIONAL ARGS]\n\n"
                 "MANDATORY ARGS:\n"
@@ -839,6 +848,16 @@ int main(int argc, char **argv) {
         return 2;
     }
 
+    if (clientIdFile) {
+        fh = fopen(clientIdFile, "r");
+        if (fh) {
+            if (fread(&myid, sizeof(myid), 1, fh) != sizeof(myid)) {
+                memset(&myid, 0, sizeof(myid));
+            }
+            fclose(fh);
+        }
+    }
+
 #ifdef YCA
     strcpy(appId,"yahoo.example.yca_test");
     cert = yca_get_cert_once(appId);