cli.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. /**
  19. * cli.c is a example/sample C client shell for ZooKeeper. It contains
  20. * basic shell functionality which exercises some of the features of
  21. * the ZooKeeper C client API. It is not a full fledged client and is
  22. * not meant for production usage - see the Java client shell for a
  23. * fully featured shell.
  24. */
  25. #include <zookeeper.h>
  26. #include <proto.h>
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #ifndef WIN32
  31. #include <sys/time.h>
  32. #include <unistd.h>
  33. #include <sys/select.h>
  34. #include <getopt.h>
  35. #else
  36. #include "winport.h"
  37. //#include <io.h> <-- can't include, conflicting definitions of close()
  38. int read(int _FileHandle, void * _DstBuf, unsigned int _MaxCharCount);
  39. int write(int _Filehandle, const void * _Buf, unsigned int _MaxCharCount);
  40. #define ctime_r(tctime, buffer) ctime_s (buffer, 40, tctime)
  41. #include "win_getopt.h" // VisualStudio doesn't contain 'getopt'
  42. #endif
  43. #include <time.h>
  44. #include <errno.h>
  45. #include <assert.h>
  46. #ifdef YCA
  47. #include <yca/yca.h>
  48. #endif
  49. #define _LL_CAST_ (long long)
  50. static zhandle_t *zh;
  51. static clientid_t myid;
  52. static const char *clientIdFile = 0;
  53. struct timeval startTime;
  54. static const char *cmd;
  55. static const char *cert;
  56. static int batchMode=0;
  57. static int to_send=0;
  58. static int sent=0;
  59. static int recvd=0;
  60. static int shutdownThisThing=0;
  61. static __attribute__ ((unused)) void
  62. printProfileInfo(struct timeval start, struct timeval end, int thres,
  63. const char* msg)
  64. {
  65. int delay=(end.tv_sec*1000+end.tv_usec/1000)-
  66. (start.tv_sec*1000+start.tv_usec/1000);
  67. if(delay>thres)
  68. fprintf(stderr,"%s: execution time=%dms\n",msg,delay);
  69. }
  70. static const char* state2String(int state){
  71. if (state == 0)
  72. return "CLOSED_STATE";
  73. if (state == ZOO_CONNECTING_STATE)
  74. return "CONNECTING_STATE";
  75. if (state == ZOO_ASSOCIATING_STATE)
  76. return "ASSOCIATING_STATE";
  77. if (state == ZOO_CONNECTED_STATE)
  78. return "CONNECTED_STATE";
  79. if (state == ZOO_READONLY_STATE)
  80. return "READONLY_STATE";
  81. if (state == ZOO_EXPIRED_SESSION_STATE)
  82. return "EXPIRED_SESSION_STATE";
  83. if (state == ZOO_AUTH_FAILED_STATE)
  84. return "AUTH_FAILED_STATE";
  85. return "INVALID_STATE";
  86. }
  87. static const char* type2String(int state){
  88. if (state == ZOO_CREATED_EVENT)
  89. return "CREATED_EVENT";
  90. if (state == ZOO_DELETED_EVENT)
  91. return "DELETED_EVENT";
  92. if (state == ZOO_CHANGED_EVENT)
  93. return "CHANGED_EVENT";
  94. if (state == ZOO_CHILD_EVENT)
  95. return "CHILD_EVENT";
  96. if (state == ZOO_SESSION_EVENT)
  97. return "SESSION_EVENT";
  98. if (state == ZOO_NOTWATCHING_EVENT)
  99. return "NOTWATCHING_EVENT";
  100. return "UNKNOWN_EVENT_TYPE";
  101. }
  102. void watcher(zhandle_t *zzh, int type, int state, const char *path,
  103. void* context)
  104. {
  105. /* Be careful using zh here rather than zzh - as this may be mt code
  106. * the client lib may call the watcher before zookeeper_init returns */
  107. fprintf(stderr, "Watcher %s state = %s", type2String(type), state2String(state));
  108. if (path && strlen(path) > 0) {
  109. fprintf(stderr, " for path %s", path);
  110. }
  111. fprintf(stderr, "\n");
  112. if (type == ZOO_SESSION_EVENT) {
  113. if (state == ZOO_CONNECTED_STATE) {
  114. const clientid_t *id = zoo_client_id(zzh);
  115. if (myid.client_id == 0 || myid.client_id != id->client_id) {
  116. myid = *id;
  117. fprintf(stderr, "Got a new session id: 0x%llx\n",
  118. _LL_CAST_ myid.client_id);
  119. if (clientIdFile) {
  120. FILE *fh = fopen(clientIdFile, "w");
  121. if (!fh) {
  122. perror(clientIdFile);
  123. } else {
  124. int rc = fwrite(&myid, sizeof(myid), 1, fh);
  125. if (rc != sizeof(myid)) {
  126. perror("writing client id");
  127. }
  128. fclose(fh);
  129. }
  130. }
  131. }
  132. } else if (state == ZOO_AUTH_FAILED_STATE) {
  133. fprintf(stderr, "Authentication failure. Shutting down...\n");
  134. zookeeper_close(zzh);
  135. shutdownThisThing=1;
  136. zh=0;
  137. } else if (state == ZOO_EXPIRED_SESSION_STATE) {
  138. fprintf(stderr, "Session expired. Shutting down...\n");
  139. zookeeper_close(zzh);
  140. shutdownThisThing=1;
  141. zh=0;
  142. }
  143. }
  144. }
  145. void dumpStat(const struct Stat *stat) {
  146. char tctimes[40];
  147. char tmtimes[40];
  148. time_t tctime;
  149. time_t tmtime;
  150. if (!stat) {
  151. fprintf(stderr,"null\n");
  152. return;
  153. }
  154. tctime = stat->ctime/1000;
  155. tmtime = stat->mtime/1000;
  156. ctime_r(&tmtime, tmtimes);
  157. ctime_r(&tctime, tctimes);
  158. fprintf(stderr, "\tctime = %s\tczxid=%llx\n"
  159. "\tmtime=%s\tmzxid=%llx\n"
  160. "\tversion=%x\taversion=%x\n"
  161. "\tephemeralOwner = %llx\n",
  162. tctimes, _LL_CAST_ stat->czxid, tmtimes,
  163. _LL_CAST_ stat->mzxid,
  164. (unsigned int)stat->version, (unsigned int)stat->aversion,
  165. _LL_CAST_ stat->ephemeralOwner);
  166. }
  167. void my_string_completion(int rc, const char *name, const void *data) {
  168. fprintf(stderr, "[%s]: rc = %d\n", (char*)(data==0?"null":data), rc);
  169. if (!rc) {
  170. fprintf(stderr, "\tname = %s\n", name);
  171. }
  172. if(batchMode)
  173. shutdownThisThing=1;
  174. }
  175. void my_string_completion_free_data(int rc, const char *name, const void *data) {
  176. my_string_completion(rc, name, data);
  177. free((void*)data);
  178. }
  179. void my_string_stat_completion(int rc, const char *name, const struct Stat *stat,
  180. const void *data) {
  181. my_string_completion(rc, name, data);
  182. dumpStat(stat);
  183. }
  184. void my_string_stat_completion_free_data(int rc, const char *name,
  185. const struct Stat *stat, const void *data) {
  186. my_string_stat_completion(rc, name, stat, data);
  187. free((void*)data);
  188. }
  189. void my_data_completion(int rc, const char *value, int value_len,
  190. const struct Stat *stat, const void *data) {
  191. struct timeval tv;
  192. int sec;
  193. int usec;
  194. gettimeofday(&tv, 0);
  195. sec = tv.tv_sec - startTime.tv_sec;
  196. usec = tv.tv_usec - startTime.tv_usec;
  197. fprintf(stderr, "time = %d msec\n", sec*1000 + usec/1000);
  198. fprintf(stderr, "%s: rc = %d\n", (char*)data, rc);
  199. if (value) {
  200. fprintf(stderr, " value_len = %d\n", value_len);
  201. assert(write(2, value, value_len) == value_len);
  202. }
  203. fprintf(stderr, "\nStat:\n");
  204. dumpStat(stat);
  205. free((void*)data);
  206. if(batchMode)
  207. shutdownThisThing=1;
  208. }
  209. void my_silent_data_completion(int rc, const char *value, int value_len,
  210. const struct Stat *stat, const void *data) {
  211. recvd++;
  212. fprintf(stderr, "Data completion %s rc = %d\n",(char*)data,rc);
  213. free((void*)data);
  214. if (recvd==to_send) {
  215. fprintf(stderr,"Recvd %d responses for %d requests sent\n",recvd,to_send);
  216. if(batchMode)
  217. shutdownThisThing=1;
  218. }
  219. }
  220. void my_strings_completion(int rc, const struct String_vector *strings,
  221. const void *data) {
  222. struct timeval tv;
  223. int sec;
  224. int usec;
  225. int i;
  226. gettimeofday(&tv, 0);
  227. sec = tv.tv_sec - startTime.tv_sec;
  228. usec = tv.tv_usec - startTime.tv_usec;
  229. fprintf(stderr, "time = %d msec\n", sec*1000 + usec/1000);
  230. fprintf(stderr, "%s: rc = %d\n", (char*)data, rc);
  231. if (strings)
  232. for (i=0; i < strings->count; i++) {
  233. fprintf(stderr, "\t%s\n", strings->data[i]);
  234. }
  235. free((void*)data);
  236. gettimeofday(&tv, 0);
  237. sec = tv.tv_sec - startTime.tv_sec;
  238. usec = tv.tv_usec - startTime.tv_usec;
  239. fprintf(stderr, "time = %d msec\n", sec*1000 + usec/1000);
  240. if(batchMode)
  241. shutdownThisThing=1;
  242. }
  243. void my_strings_stat_completion(int rc, const struct String_vector *strings,
  244. const struct Stat *stat, const void *data) {
  245. my_strings_completion(rc, strings, data);
  246. dumpStat(stat);
  247. if(batchMode)
  248. shutdownThisThing=1;
  249. }
  250. void my_void_completion(int rc, const void *data) {
  251. fprintf(stderr, "%s: rc = %d\n", (char*)data, rc);
  252. free((void*)data);
  253. if(batchMode)
  254. shutdownThisThing=1;
  255. }
  256. void my_stat_completion(int rc, const struct Stat *stat, const void *data) {
  257. fprintf(stderr, "%s: rc = %d Stat:\n", (char*)data, rc);
  258. dumpStat(stat);
  259. free((void*)data);
  260. if(batchMode)
  261. shutdownThisThing=1;
  262. }
  263. void my_silent_stat_completion(int rc, const struct Stat *stat,
  264. const void *data) {
  265. // fprintf(stderr, "State completion: [%s] rc = %d\n", (char*)data, rc);
  266. sent++;
  267. free((void*)data);
  268. }
  269. static void sendRequest(const char* data) {
  270. zoo_aset(zh, "/od", data, strlen(data), -1, my_silent_stat_completion,
  271. strdup("/od"));
  272. zoo_aget(zh, "/od", 1, my_silent_data_completion, strdup("/od"));
  273. }
  274. void od_completion(int rc, const struct Stat *stat, const void *data) {
  275. int i;
  276. fprintf(stderr, "od command response: rc = %d Stat:\n", rc);
  277. dumpStat(stat);
  278. // send a whole bunch of requests
  279. recvd=0;
  280. sent=0;
  281. to_send=200;
  282. for (i=0; i<to_send; i++) {
  283. char buf[4096*16];
  284. memset(buf, -1, sizeof(buf)-1);
  285. buf[sizeof(buf)-1]=0;
  286. sendRequest(buf);
  287. }
  288. }
  289. int startsWith(const char *line, const char *prefix) {
  290. int len = strlen(prefix);
  291. return strncmp(line, prefix, len) == 0;
  292. }
  293. static const char *hostPort;
  294. static int verbose = 0;
  295. void processline(const char *line) {
  296. int rc;
  297. int async = ((line[0] == 'a') && !(startsWith(line, "addauth ")));
  298. if (async) {
  299. line++;
  300. }
  301. if (startsWith(line, "help")) {
  302. fprintf(stderr, " create [+[e|s|c|t=ttl]] <path>\n");
  303. fprintf(stderr, " create2 [+[e|s|c|t=ttl]] <path>\n");
  304. fprintf(stderr, " delete <path>\n");
  305. fprintf(stderr, " set <path> <data>\n");
  306. fprintf(stderr, " get <path>\n");
  307. fprintf(stderr, " ls <path>\n");
  308. fprintf(stderr, " ls2 <path>\n");
  309. fprintf(stderr, " sync <path>\n");
  310. fprintf(stderr, " exists <path>\n");
  311. fprintf(stderr, " wexists <path>\n");
  312. fprintf(stderr, " myid\n");
  313. fprintf(stderr, " verbose\n");
  314. fprintf(stderr, " addauth <id> <scheme>\n");
  315. fprintf(stderr, " config\n");
  316. fprintf(stderr, " reconfig [-file <path> | -members <serverId=host:port1:port2;port3>,... | "
  317. " -add <serverId=host:port1:port2;port3>,... | -remove <serverId>,...] [-version <version>]\n");
  318. fprintf(stderr, " quit\n");
  319. fprintf(stderr, "\n");
  320. fprintf(stderr, " prefix the command with the character 'a' to run the command asynchronously.\n");
  321. fprintf(stderr, " run the 'verbose' command to toggle verbose logging.\n");
  322. fprintf(stderr, " i.e. 'aget /foo' to get /foo asynchronously\n");
  323. } else if (startsWith(line, "verbose")) {
  324. if (verbose) {
  325. verbose = 0;
  326. zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
  327. fprintf(stderr, "logging level set to WARN\n");
  328. } else {
  329. verbose = 1;
  330. zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);
  331. fprintf(stderr, "logging level set to DEBUG\n");
  332. }
  333. } else if (startsWith(line, "get ")) {
  334. line += 4;
  335. if (line[0] != '/') {
  336. fprintf(stderr, "Path must start with /, found: %s\n", line);
  337. return;
  338. }
  339. rc = zoo_aget(zh, line, 1, my_data_completion, strdup(line));
  340. if (rc) {
  341. fprintf(stderr, "Error %d for %s\n", rc, line);
  342. }
  343. } else if (strcmp(line, "config") == 0) {
  344. gettimeofday(&startTime, 0);
  345. rc = zoo_agetconfig(zh, 1, my_data_completion, strdup(ZOO_CONFIG_NODE));
  346. if (rc) {
  347. fprintf(stderr, "Error %d for %s\n", rc, line);
  348. }
  349. } else if (startsWith(line, "reconfig ")) {
  350. int syntaxError = 0;
  351. char* p = NULL;
  352. char* joining = NULL;
  353. char* leaving = NULL;
  354. char* members = NULL;
  355. size_t members_size = 0;
  356. int mode = 0; // 0 = not set, 1 = incremental, 2 = non-incremental
  357. int64_t version = -1;
  358. line += 9;
  359. p = strtok (strdup(line)," ");
  360. while (p != NULL) {
  361. if (strcmp(p, "-add")==0) {
  362. p = strtok (NULL," ");
  363. if (mode == 2 || p == NULL) {
  364. syntaxError = 1;
  365. break;
  366. }
  367. mode = 1;
  368. joining = strdup(p);
  369. } else if (strcmp(p, "-remove")==0){
  370. p = strtok (NULL," ");
  371. if (mode == 2 || p == NULL) {
  372. syntaxError = 1;
  373. break;
  374. }
  375. mode = 1;
  376. leaving = strdup(p);
  377. } else if (strcmp(p, "-members")==0) {
  378. p = strtok (NULL," ");
  379. if (mode == 1 || p == NULL) {
  380. syntaxError = 1;
  381. break;
  382. }
  383. mode = 2;
  384. members = strdup(p);
  385. } else if (strcmp(p, "-file")==0){
  386. FILE *fp = NULL;
  387. p = strtok (NULL," ");
  388. if (mode == 1 || p == NULL) {
  389. syntaxError = 1;
  390. break;
  391. }
  392. mode = 2;
  393. fp = fopen(p, "r");
  394. if (fp == NULL) {
  395. fprintf(stderr, "Error reading file: %s\n", p);
  396. syntaxError = 1;
  397. break;
  398. }
  399. fseek(fp, 0L, SEEK_END); /* Position to end of file */
  400. members_size = ftell(fp); /* Get file length */
  401. rewind(fp); /* Back to start of file */
  402. members = calloc(members_size + 1, sizeof(char));
  403. if(members == NULL )
  404. {
  405. fprintf(stderr, "\nInsufficient memory to read file: %s\n", p);
  406. syntaxError = 1;
  407. fclose(fp);
  408. break;
  409. }
  410. /* Read the entire file into members
  411. * NOTE: -- fread returns number of items successfully read
  412. * not the number of bytes. We're requesting one item of
  413. * members_size bytes. So we expect the return value here
  414. * to be 1.
  415. */
  416. if (fread(members, members_size, 1, fp) != 1){
  417. fprintf(stderr, "Error reading file: %s\n", p);
  418. syntaxError = 1;
  419. fclose(fp);
  420. break;
  421. }
  422. fclose(fp);
  423. } else if (strcmp(p, "-version")==0){
  424. p = strtok (NULL," ");
  425. if (version != -1 || p == NULL){
  426. syntaxError = 1;
  427. break;
  428. }
  429. #ifdef WIN32
  430. version = _strtoui64(p, NULL, 16);
  431. #else
  432. version = strtoull(p, NULL, 16);
  433. #endif
  434. if (version < 0) {
  435. syntaxError = 1;
  436. break;
  437. }
  438. } else {
  439. syntaxError = 1;
  440. break;
  441. }
  442. p = strtok (NULL," ");
  443. }
  444. if (syntaxError) return;
  445. rc = zoo_areconfig(zh, joining, leaving, members, version, my_data_completion, strdup(line));
  446. free(joining);
  447. free(leaving);
  448. free(members);
  449. if (rc) {
  450. fprintf(stderr, "Error %d for %s\n", rc, line);
  451. }
  452. } else if (startsWith(line, "set ")) {
  453. char *ptr;
  454. line += 4;
  455. if (line[0] != '/') {
  456. fprintf(stderr, "Path must start with /, found: %s\n", line);
  457. return;
  458. }
  459. ptr = strchr(line, ' ');
  460. if (!ptr) {
  461. fprintf(stderr, "No data found after path\n");
  462. return;
  463. }
  464. *ptr = '\0';
  465. ptr++;
  466. rc = zoo_aset(zh, line, ptr, strlen(ptr), -1, my_stat_completion,
  467. strdup(line));
  468. if (rc) {
  469. fprintf(stderr, "Error %d for %s\n", rc, line);
  470. }
  471. } else if (startsWith(line, "ls ")) {
  472. line += 3;
  473. if (line[0] != '/') {
  474. fprintf(stderr, "Path must start with /, found: %s\n", line);
  475. return;
  476. }
  477. gettimeofday(&startTime, 0);
  478. rc= zoo_aget_children(zh, line, 1, my_strings_completion, strdup(line));
  479. if (rc) {
  480. fprintf(stderr, "Error %d for %s\n", rc, line);
  481. }
  482. } else if (startsWith(line, "ls2 ")) {
  483. line += 4;
  484. if (line[0] != '/') {
  485. fprintf(stderr, "Path must start with /, found: %s\n", line);
  486. return;
  487. }
  488. gettimeofday(&startTime, 0);
  489. rc= zoo_aget_children2(zh, line, 1, my_strings_stat_completion, strdup(line));
  490. if (rc) {
  491. fprintf(stderr, "Error %d for %s\n", rc, line);
  492. }
  493. } else if (startsWith(line, "create ") || startsWith(line, "create2 ")) {
  494. int mode = 0;
  495. int64_t ttl_value = -1;
  496. int is_create2 = startsWith(line, "create2 ");
  497. line += is_create2 ? 8 : 7;
  498. if (line[0] == '+') {
  499. int ephemeral = 0;
  500. int sequential = 0;
  501. int container = 0;
  502. int ttl = 0;
  503. char *p = NULL;
  504. line++;
  505. while (*line != ' ' && *line != '\0') {
  506. switch (*line) {
  507. case 'e':
  508. ephemeral = 1;
  509. break;
  510. case 's':
  511. sequential = 1;
  512. break;
  513. case 'c':
  514. container = 1;
  515. break;
  516. case 't':
  517. ttl = 1;
  518. line++;
  519. if (*line != '=') {
  520. fprintf(stderr, "Missing ttl value after +t\n");
  521. return;
  522. }
  523. line++;
  524. ttl_value = strtol(line, &p, 10);
  525. if (ttl_value <= 0) {
  526. fprintf(stderr, "ttl value must be a positive integer\n");
  527. return;
  528. }
  529. // move back line pointer to the last digit
  530. line = p - 1;
  531. break;
  532. default:
  533. fprintf(stderr, "Unknown option: %c\n", *line);
  534. return;
  535. }
  536. line++;
  537. }
  538. if (ephemeral != 0 && sequential == 0 && container == 0 && ttl == 0) {
  539. mode = ZOO_EPHEMERAL;
  540. } else if (ephemeral == 0 && sequential != 0 && container == 0 && ttl == 0) {
  541. mode = ZOO_PERSISTENT_SEQUENTIAL;
  542. } else if (ephemeral != 0 && sequential != 0 && container == 0 && ttl == 0) {
  543. mode = ZOO_EPHEMERAL_SEQUENTIAL;
  544. } else if (ephemeral == 0 && sequential == 0 && container != 0 && ttl == 0) {
  545. mode = ZOO_CONTAINER;
  546. } else if (ephemeral == 0 && sequential == 0 && container == 0 && ttl != 0) {
  547. mode = ZOO_PERSISTENT_WITH_TTL;
  548. } else if (ephemeral == 0 && sequential != 0 && container == 0 && ttl != 0) {
  549. mode = ZOO_PERSISTENT_SEQUENTIAL_WITH_TTL;
  550. } else {
  551. fprintf(stderr, "Invalid mode.\n");
  552. return;
  553. }
  554. if (*line == ' ') {
  555. line++;
  556. }
  557. }
  558. if (line[0] != '/') {
  559. fprintf(stderr, "Path must start with /, found: %s\n", line);
  560. return;
  561. }
  562. fprintf(stderr, "Creating [%s] node (mode: %d)\n", line, mode);
  563. // {
  564. // struct ACL _CREATE_ONLY_ACL_ACL[] = {{ZOO_PERM_CREATE, ZOO_ANYONE_ID_UNSAFE}};
  565. // struct ACL_vector CREATE_ONLY_ACL = {1,_CREATE_ONLY_ACL_ACL};
  566. // rc = zoo_acreate(zh, line, "new", 3, &CREATE_ONLY_ACL, flags,
  567. // my_string_completion, strdup(line));
  568. // }
  569. if (is_create2) {
  570. rc = zoo_acreate2_ttl(zh, line, "new", 3, &ZOO_OPEN_ACL_UNSAFE, mode, ttl_value,
  571. my_string_stat_completion_free_data, strdup(line));
  572. } else {
  573. rc = zoo_acreate_ttl(zh, line, "new", 3, &ZOO_OPEN_ACL_UNSAFE, mode, ttl_value,
  574. my_string_completion_free_data, strdup(line));
  575. }
  576. if (rc) {
  577. fprintf(stderr, "Error %d for %s\n", rc, line);
  578. }
  579. } else if (startsWith(line, "delete ")) {
  580. line += 7;
  581. if (line[0] != '/') {
  582. fprintf(stderr, "Path must start with /, found: %s\n", line);
  583. return;
  584. }
  585. rc = zoo_adelete(zh, line, -1, my_void_completion, strdup(line));
  586. if (rc) {
  587. fprintf(stderr, "Error %d for %s\n", rc, line);
  588. }
  589. } else if (startsWith(line, "sync ")) {
  590. line += 5;
  591. if (line[0] != '/') {
  592. fprintf(stderr, "Path must start with /, found: %s\n", line);
  593. return;
  594. }
  595. rc = zoo_async(zh, line, my_string_completion_free_data, strdup(line));
  596. if (rc) {
  597. fprintf(stderr, "Error %d for %s\n", rc, line);
  598. }
  599. } else if (startsWith(line, "wexists ")) {
  600. #ifdef THREADED
  601. struct Stat stat;
  602. #endif
  603. line += 8;
  604. if (line[0] != '/') {
  605. fprintf(stderr, "Path must start with /, found: %s\n", line);
  606. return;
  607. }
  608. #ifndef THREADED
  609. rc = zoo_awexists(zh, line, watcher, (void*) 0, my_stat_completion, strdup(line));
  610. #else
  611. rc = zoo_wexists(zh, line, watcher, (void*) 0, &stat);
  612. #endif
  613. if (rc) {
  614. fprintf(stderr, "Error %d for %s\n", rc, line);
  615. }
  616. } else if (startsWith(line, "exists ")) {
  617. #ifdef THREADED
  618. struct Stat stat;
  619. #endif
  620. line += 7;
  621. if (line[0] != '/') {
  622. fprintf(stderr, "Path must start with /, found: %s\n", line);
  623. return;
  624. }
  625. #ifndef THREADED
  626. rc = zoo_aexists(zh, line, 1, my_stat_completion, strdup(line));
  627. #else
  628. rc = zoo_exists(zh, line, 1, &stat);
  629. #endif
  630. if (rc) {
  631. fprintf(stderr, "Error %d for %s\n", rc, line);
  632. }
  633. } else if (strcmp(line, "myid") == 0) {
  634. printf("session Id = %llx\n", _LL_CAST_ zoo_client_id(zh)->client_id);
  635. } else if (strcmp(line, "reinit") == 0) {
  636. zookeeper_close(zh);
  637. // we can't send myid to the server here -- zookeeper_close() removes
  638. // the session on the server. We must start anew.
  639. zh = zookeeper_init(hostPort, watcher, 30000, 0, 0, 0);
  640. } else if (startsWith(line, "quit")) {
  641. fprintf(stderr, "Quitting...\n");
  642. shutdownThisThing=1;
  643. } else if (startsWith(line, "od")) {
  644. const char val[]="fire off";
  645. fprintf(stderr, "Overdosing...\n");
  646. rc = zoo_aset(zh, "/od", val, sizeof(val)-1, -1, od_completion, 0);
  647. if (rc)
  648. fprintf(stderr, "od command failed: %d\n", rc);
  649. } else if (startsWith(line, "addauth ")) {
  650. char *ptr;
  651. line += 8;
  652. ptr = strchr(line, ' ');
  653. if (ptr) {
  654. *ptr = '\0';
  655. ptr++;
  656. }
  657. zoo_add_auth(zh, line, ptr, ptr ? strlen(ptr) : 0, NULL, NULL);
  658. }
  659. }
  660. /*
  661. * Look for a command in the form 'cmd:command', and store a pointer
  662. * to the command (without its prefix) into *buf if found.
  663. *
  664. * Returns 0 if the argument does not start with the prefix.
  665. * Returns 1 in case of success.
  666. */
  667. int handleBatchMode(const char* arg, const char** buf) {
  668. size_t cmdlen = strlen(arg);
  669. if (cmdlen < 4) {
  670. // too short
  671. return 0;
  672. }
  673. cmdlen -= 4;
  674. if(strncmp("cmd:", arg, 4) != 0){
  675. return 0;
  676. }
  677. *buf = arg + 4;
  678. return 1;
  679. }
  680. int main(int argc, char **argv) {
  681. static struct option long_options[] = {
  682. {"host", required_argument, NULL, 'h'}, //hostPort
  683. {"ssl", required_argument, NULL, 's'}, //certificate files
  684. {"myid", required_argument, NULL, 'm'}, //myId file
  685. {"cmd", required_argument, NULL, 'c'}, //cmd
  686. {"readonly", no_argument, NULL, 'r'}, //read-only
  687. {"debug", no_argument, NULL, 'd'}, //set log level to DEBUG from the beginning
  688. {NULL, 0, NULL, 0},
  689. };
  690. #ifndef THREADED
  691. fd_set rfds, wfds, efds;
  692. int processed=0;
  693. #endif
  694. char buffer[4096];
  695. char p[2048];
  696. #ifdef YCA
  697. char *cert=0;
  698. char appId[64];
  699. #endif
  700. int bufoff = 0;
  701. int flags;
  702. FILE *fh;
  703. int opt;
  704. int option_index = 0;
  705. verbose = 0;
  706. zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
  707. flags = 0;
  708. while ((opt = getopt_long(argc, argv, "h:s:m:c:rd", long_options, &option_index)) != -1) {
  709. switch (opt) {
  710. case 'h':
  711. hostPort = optarg;
  712. break;
  713. case 'm':
  714. clientIdFile = optarg;
  715. break;
  716. case 'r':
  717. flags = ZOO_READONLY;
  718. break;
  719. case 'c':
  720. cmd = optarg;
  721. batchMode = 1;
  722. fprintf(stderr,"Batch mode: %s\n",cmd);
  723. break;
  724. case 's':
  725. cert = optarg;
  726. break;
  727. case 'd':
  728. verbose = 1;
  729. zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);
  730. fprintf(stderr, "logging level set to DEBUG\n");
  731. break;
  732. case '?':
  733. if (optopt == 'h') {
  734. fprintf (stderr, "Option -%c requires host list.\n", optopt);
  735. } else if (isprint (optopt)) {
  736. fprintf (stderr, "Unknown option `-%c'.\n", optopt);
  737. } else {
  738. fprintf (stderr,
  739. "Unknown option character `\\x%x'.\n",
  740. optopt);
  741. return 1;
  742. }
  743. }
  744. }
  745. if (!hostPort && optind < argc) {
  746. /*
  747. * getopt_long did not find a '-h <connect-string>' option.
  748. *
  749. * The invoker may be using using the "old-style" command
  750. * syntax, with positional parameters and "magical" prefixes
  751. * such as 'cmd:'; let's see if we can make sense of it.
  752. */
  753. hostPort = argv[optind++];
  754. if (optind < argc && !cmd && !clientIdFile) {
  755. int batchModeRes = handleBatchMode(argv[optind], &cmd);
  756. if (batchModeRes == 1) {
  757. batchMode=1;
  758. fprintf(stderr, "Batch mode: '%s'\n", cmd);
  759. } else {
  760. clientIdFile = argv[optind];
  761. }
  762. optind++;
  763. }
  764. }
  765. if (!hostPort || optind < argc) {
  766. fprintf(stderr,
  767. "\nUSAGE: %s -h zk_host_1:port_1,zk_host_2:port_2,... [OPTIONAL ARGS]\n\n"
  768. "MANDATORY ARGS:\n"
  769. "-h, --host <host:port pairs> Comma separated list of ZooKeeper host:port pairs\n\n"
  770. "OPTIONAL ARGS:\n"
  771. "-m, --myid <clientid file> Path to the file contains the client ID\n"
  772. "-c, --cmd <command> Command to execute, e.g. ls|ls2|create|create2|od|...\n"
  773. #ifdef HAVE_OPENSSL_H
  774. "-s, --ssl <ssl params> Comma separated parameters to initiate SSL connection\n"
  775. " e.g.: server_cert.crt,client_cert.crt,client_priv_key.pem,passwd\n"
  776. #endif
  777. "-r, --readonly Connect in read-only mode\n"
  778. "-d, --debug Activate debug logs right from the beginning (you can also use the \n"
  779. " command 'verbose' later to activate debug logs in the cli shell)\n\n",
  780. argv[0]);
  781. fprintf(stderr,
  782. "Version: ZooKeeper cli (c client) version %s\n",
  783. ZOO_VERSION);
  784. return 2;
  785. }
  786. if (clientIdFile) {
  787. fh = fopen(clientIdFile, "r");
  788. if (fh) {
  789. if (fread(&myid, sizeof(myid), 1, fh) != sizeof(myid)) {
  790. memset(&myid, 0, sizeof(myid));
  791. }
  792. fclose(fh);
  793. }
  794. }
  795. #ifdef YCA
  796. strcpy(appId,"yahoo.example.yca_test");
  797. cert = yca_get_cert_once(appId);
  798. if(cert!=0) {
  799. fprintf(stderr,"Certificate for appid [%s] is [%s]\n",appId,cert);
  800. strncpy(p,cert,sizeof(p)-1);
  801. free(cert);
  802. } else {
  803. fprintf(stderr,"Certificate for appid [%s] not found\n",appId);
  804. strcpy(p,"dummy");
  805. }
  806. #else
  807. strcpy(p, "dummy");
  808. #endif
  809. zoo_deterministic_conn_order(1); // enable deterministic order
  810. #ifdef HAVE_OPENSSL_H
  811. if (!cert) {
  812. zh = zookeeper_init(hostPort, watcher, 30000, &myid, NULL, flags);
  813. } else {
  814. zh = zookeeper_init_ssl(hostPort, cert, watcher, 30000, &myid, NULL, flags);
  815. }
  816. #else
  817. zh = zookeeper_init(hostPort, watcher, 30000, &myid, NULL, flags);
  818. #endif
  819. if (!zh) {
  820. return errno;
  821. }
  822. #ifdef YCA
  823. if(zoo_add_auth(zh,"yca",p,strlen(p),0,0)!=ZOK)
  824. return 2;
  825. #endif
  826. #ifdef THREADED
  827. while(!shutdownThisThing) {
  828. int rc;
  829. int len = sizeof(buffer) - bufoff -1;
  830. if (len <= 0) {
  831. fprintf(stderr, "Can't handle lines that long!\n");
  832. exit(2);
  833. }
  834. rc = read(0, buffer+bufoff, len);
  835. if (rc <= 0) {
  836. fprintf(stderr, "bye\n");
  837. shutdownThisThing=1;
  838. break;
  839. }
  840. bufoff += rc;
  841. buffer[bufoff] = '\0';
  842. while (strchr(buffer, '\n')) {
  843. char *ptr = strchr(buffer, '\n');
  844. *ptr = '\0';
  845. processline(buffer);
  846. ptr++;
  847. memmove(buffer, ptr, strlen(ptr)+1);
  848. bufoff = 0;
  849. }
  850. }
  851. #else
  852. FD_ZERO(&rfds);
  853. FD_ZERO(&wfds);
  854. FD_ZERO(&efds);
  855. while (!shutdownThisThing) {
  856. int fd;
  857. int interest;
  858. int events;
  859. struct timeval tv;
  860. int rc;
  861. zookeeper_interest(zh, &fd, &interest, &tv);
  862. if (fd != -1) {
  863. if (interest&ZOOKEEPER_READ) {
  864. FD_SET(fd, &rfds);
  865. } else {
  866. FD_CLR(fd, &rfds);
  867. }
  868. if (interest&ZOOKEEPER_WRITE) {
  869. FD_SET(fd, &wfds);
  870. } else {
  871. FD_CLR(fd, &wfds);
  872. }
  873. } else {
  874. fd = 0;
  875. }
  876. FD_SET(0, &rfds);
  877. rc = select(fd+1, &rfds, &wfds, &efds, &tv);
  878. events = 0;
  879. if (rc > 0) {
  880. if (FD_ISSET(fd, &rfds)) {
  881. events |= ZOOKEEPER_READ;
  882. }
  883. if (FD_ISSET(fd, &wfds)) {
  884. events |= ZOOKEEPER_WRITE;
  885. }
  886. }
  887. if(batchMode && processed==0){
  888. //batch mode
  889. processline(cmd);
  890. processed=1;
  891. }
  892. if (!processed && FD_ISSET(0, &rfds)) {
  893. int rc;
  894. int len = sizeof(buffer) - bufoff -1;
  895. if (len <= 0) {
  896. fprintf(stderr, "Can't handle lines that long!\n");
  897. exit(2);
  898. }
  899. rc = read(0, buffer+bufoff, len);
  900. if (rc <= 0) {
  901. fprintf(stderr, "bye\n");
  902. break;
  903. }
  904. bufoff += rc;
  905. buffer[bufoff] = '\0';
  906. while (strchr(buffer, '\n')) {
  907. char *ptr = strchr(buffer, '\n');
  908. *ptr = '\0';
  909. processline(buffer);
  910. ptr++;
  911. memmove(buffer, ptr, strlen(ptr)+1);
  912. bufoff = 0;
  913. }
  914. }
  915. zookeeper_process(zh, events);
  916. }
  917. #endif
  918. if (to_send!=0)
  919. fprintf(stderr,"Recvd %d responses for %d requests sent\n",recvd,sent);
  920. zookeeper_close(zh);
  921. return 0;
  922. }