cli.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  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. #ifdef THREADED
  681. static void millisleep(int ms) {
  682. #ifdef WIN32
  683. Sleep(ms);
  684. #else /* !WIN32 */
  685. struct timespec ts;
  686. ts.tv_sec = ms / 1000;
  687. ts.tv_nsec = (ms % 1000) * 1000000; // to nanoseconds
  688. nanosleep(&ts, NULL);
  689. #endif /* WIN32 */
  690. }
  691. #endif /* THREADED */
  692. int main(int argc, char **argv) {
  693. static struct option long_options[] = {
  694. {"host", required_argument, NULL, 'h'}, //hostPort
  695. {"ssl", required_argument, NULL, 's'}, //certificate files
  696. {"myid", required_argument, NULL, 'm'}, //myId file
  697. {"cmd", required_argument, NULL, 'c'}, //cmd
  698. {"readonly", no_argument, NULL, 'r'}, //read-only
  699. {"debug", no_argument, NULL, 'd'}, //set log level to DEBUG from the beginning
  700. #ifdef HAVE_CYRUS_SASL_H
  701. // Parameters for SASL authentication.
  702. {"service", required_argument, NULL, 'z'},
  703. {"server-fqdn", required_argument, NULL, 'o'}, //Host used for SASL auth
  704. {"mechlist", required_argument, NULL, 'n'}, //SASL mechanism list
  705. {"user", required_argument, NULL, 'u'}, //SASL user
  706. {"realm", required_argument, NULL, 'l'}, //SASL realm
  707. {"password-file", required_argument, NULL, 'p'},
  708. #endif /* HAVE_CYRUS_SASL_H */
  709. {NULL, 0, NULL, 0},
  710. };
  711. #ifndef THREADED
  712. fd_set rfds, wfds, efds;
  713. int processed=0;
  714. #endif
  715. char buffer[4096];
  716. char p[2048];
  717. #ifdef YCA
  718. char *cert=0;
  719. char appId[64];
  720. #endif
  721. int bufoff = 0;
  722. int flags;
  723. FILE *fh;
  724. #ifdef HAVE_CYRUS_SASL_H
  725. char *service = "zookeeper";
  726. char *serverFQDN = NULL;
  727. char *mechlist = NULL;
  728. char *user = NULL;
  729. char *realm = NULL;
  730. char *passwordFile = NULL;
  731. #endif /* HAVE_CYRUS_SASL_H */
  732. int opt;
  733. int option_index = 0;
  734. verbose = 0;
  735. zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
  736. flags = 0;
  737. while ((opt = getopt_long(argc, argv, "h:s:m:c:rdz:o:n:u:l:p:", long_options, &option_index)) != -1) {
  738. switch (opt) {
  739. case 'h':
  740. hostPort = optarg;
  741. break;
  742. case 'm':
  743. clientIdFile = optarg;
  744. break;
  745. case 'r':
  746. flags = ZOO_READONLY;
  747. break;
  748. case 'c':
  749. cmd = optarg;
  750. batchMode = 1;
  751. fprintf(stderr,"Batch mode: %s\n",cmd);
  752. break;
  753. case 's':
  754. cert = optarg;
  755. break;
  756. case 'd':
  757. verbose = 1;
  758. zoo_set_debug_level(ZOO_LOG_LEVEL_DEBUG);
  759. fprintf(stderr, "logging level set to DEBUG\n");
  760. break;
  761. #ifdef HAVE_CYRUS_SASL_H
  762. case 'z':
  763. service = optarg;
  764. break;
  765. case 'o':
  766. serverFQDN = optarg;
  767. break;
  768. case 'n':
  769. mechlist = optarg;
  770. break;
  771. case 'u':
  772. user = optarg;
  773. break;
  774. case 'l':
  775. realm = optarg;
  776. break;
  777. case 'p':
  778. passwordFile = optarg;
  779. break;
  780. #endif /* HAVE_CYRUS_SASL_H */
  781. case '?':
  782. if (optopt == 'h') {
  783. fprintf (stderr, "Option -%c requires host list.\n", optopt);
  784. } else if (isprint (optopt)) {
  785. fprintf (stderr, "Unknown option `-%c'.\n", optopt);
  786. } else {
  787. fprintf (stderr,
  788. "Unknown option character `\\x%x'.\n",
  789. optopt);
  790. return 1;
  791. }
  792. }
  793. }
  794. if (!hostPort && optind < argc) {
  795. /*
  796. * getopt_long did not find a '-h <connect-string>' option.
  797. *
  798. * The invoker may be using using the "old-style" command
  799. * syntax, with positional parameters and "magical" prefixes
  800. * such as 'cmd:'; let's see if we can make sense of it.
  801. */
  802. hostPort = argv[optind++];
  803. if (optind < argc && !cmd && !clientIdFile) {
  804. int batchModeRes = handleBatchMode(argv[optind], &cmd);
  805. if (batchModeRes == 1) {
  806. batchMode=1;
  807. fprintf(stderr, "Batch mode: '%s'\n", cmd);
  808. } else {
  809. clientIdFile = argv[optind];
  810. }
  811. optind++;
  812. }
  813. }
  814. if (!hostPort || optind < argc) {
  815. fprintf(stderr,
  816. "\nUSAGE: %s -h zk_host_1:port_1,zk_host_2:port_2,... [OPTIONAL ARGS]\n\n"
  817. "MANDATORY ARGS:\n"
  818. "-h, --host <host:port pairs> Comma separated list of ZooKeeper host:port pairs\n\n"
  819. "OPTIONAL ARGS:\n"
  820. "-m, --myid <clientid file> Path to the file contains the client ID\n"
  821. "-c, --cmd <command> Command to execute, e.g. ls|ls2|create|create2|od|...\n"
  822. #ifdef HAVE_OPENSSL_H
  823. "-s, --ssl <ssl params> Comma separated parameters to initiate SSL connection\n"
  824. " e.g.: server_cert.crt,client_cert.crt,client_priv_key.pem,passwd\n"
  825. #endif
  826. #ifdef HAVE_CYRUS_SASL_H
  827. "-u, --user <user> SASL user name\n"
  828. "-n, --mechlist <mechlist> Comma separated list of SASL mechanisms (GSSAPI and/or DIGEST-MD5)\n"
  829. "-o, --server-fqdn <fqdn> SASL server name ('zk-sasl-md5' for DIGEST-MD5; default: reverse DNS lookup)\n"
  830. "-p, --password-file <file> File containing the password (recommended for SASL/DIGEST-MD5)\n"
  831. "-l, --realm <realm> Realm (for SASL/GSSAPI)\n"
  832. "-z, --service <service> SASL service parameter (default: 'zookeeper')\n"
  833. #endif /* HAVE_CYRUS_SASL_H */
  834. "-r, --readonly Connect in read-only mode\n"
  835. "-d, --debug Activate debug logs right from the beginning (you can also use the \n"
  836. " command 'verbose' later to activate debug logs in the cli shell)\n\n",
  837. argv[0]);
  838. #ifdef HAVE_CYRUS_SASL_H
  839. fprintf(stderr,
  840. "SASL EXAMPLES:\n"
  841. "$ %s --mechlist DIGEST-MD5 --user bob --password-file bob.secret --server-fqdn zk-sasl-md5 -h ...\n"
  842. "$ %s --mechlist GSSAPI --user bob --realm BOBINC.COM -h ...\n"
  843. "Notes:\n"
  844. " * SASL and SSL support are currently incompatible (ZOOKEEPER-3482);\n"
  845. " * SASL parameters map to Cyrus SASL's _new/_start APIs and callbacks;\n"
  846. " * DIGEST-MD5 requires '--server-fqdn zk-sasl-md5' for historical reasons.\n"
  847. " * Passwords are obtained via the obsolete 'getpass()' if not provided via '--password-file'.\n"
  848. "\n",
  849. argv[0], argv[0]);
  850. #endif /* HAVE_CYRUS_SASL_H */
  851. fprintf(stderr,
  852. "Version: ZooKeeper cli (c client) version %s\n",
  853. ZOO_VERSION);
  854. return 2;
  855. }
  856. if (clientIdFile) {
  857. fh = fopen(clientIdFile, "r");
  858. if (fh) {
  859. if (fread(&myid, sizeof(myid), 1, fh) != 1) {
  860. memset(&myid, 0, sizeof(myid));
  861. }
  862. fclose(fh);
  863. }
  864. }
  865. #ifdef YCA
  866. strcpy(appId,"yahoo.example.yca_test");
  867. cert = yca_get_cert_once(appId);
  868. if(cert!=0) {
  869. fprintf(stderr,"Certificate for appid [%s] is [%s]\n",appId,cert);
  870. strncpy(p,cert,sizeof(p)-1);
  871. free(cert);
  872. } else {
  873. fprintf(stderr,"Certificate for appid [%s] not found\n",appId);
  874. strcpy(p,"dummy");
  875. }
  876. #else
  877. strcpy(p, "dummy");
  878. #endif
  879. zoo_deterministic_conn_order(1); // enable deterministic order
  880. #ifdef HAVE_CYRUS_SASL_H
  881. /*
  882. * We need to disable the deprecation warnings as Apple has
  883. * decided to deprecate all of CyrusSASL's functions with OS 10.11
  884. * (see MESOS-3030, ZOOKEEPER-4201). We are using GCC pragmas also
  885. * for covering clang.
  886. */
  887. #ifdef __APPLE__
  888. #pragma GCC diagnostic push
  889. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  890. #endif
  891. if (mechlist) {
  892. zoo_sasl_params_t sasl_params = { 0 };
  893. int sr;
  894. if (cert) {
  895. fprintf(stderr, "SASL and SSL support are currently incompatible (ZOOKEEPER-3482); exiting.\n");
  896. return 1;
  897. }
  898. sr = sasl_client_init(NULL);
  899. if (sr != SASL_OK) {
  900. fprintf(stderr, "Unable to initialize SASL library: %s\n",
  901. sasl_errstring(sr, NULL, NULL));
  902. return 1;
  903. }
  904. sasl_params.service = service;
  905. sasl_params.host = serverFQDN;
  906. sasl_params.mechlist = mechlist;
  907. sasl_params.callbacks = zoo_sasl_make_basic_callbacks(user, realm,
  908. passwordFile);
  909. zh = zookeeper_init_sasl(hostPort, watcher, 30000, &myid, NULL, flags,
  910. NULL, &sasl_params);
  911. if (!zh) {
  912. return errno;
  913. }
  914. }
  915. #ifdef __APPLE__
  916. #pragma GCC diagnostic pop
  917. #endif
  918. #endif /* HAVE_CYRUS_SASL_H */
  919. if (!zh) {
  920. #ifdef HAVE_OPENSSL_H
  921. if (!cert) {
  922. zh = zookeeper_init(hostPort, watcher, 30000, &myid, NULL, flags);
  923. } else {
  924. zh = zookeeper_init_ssl(hostPort, cert, watcher, 30000, &myid, NULL, flags);
  925. }
  926. #else
  927. zh = zookeeper_init(hostPort, watcher, 30000, &myid, NULL, flags);
  928. #endif
  929. if (!zh) {
  930. return errno;
  931. }
  932. }
  933. #ifdef YCA
  934. if(zoo_add_auth(zh,"yca",p,strlen(p),0,0)!=ZOK)
  935. return 2;
  936. #endif
  937. #ifdef THREADED
  938. if (batchMode) {
  939. processline(cmd);
  940. }
  941. while(!shutdownThisThing) {
  942. int rc, len;
  943. if (batchMode) {
  944. // We are just waiting for the asynchronous command to complete.
  945. millisleep(10);
  946. continue;
  947. }
  948. len = sizeof(buffer) - bufoff -1;
  949. if (len <= 0) {
  950. fprintf(stderr, "Can't handle lines that long!\n");
  951. exit(2);
  952. }
  953. rc = read(0, buffer+bufoff, len);
  954. if (rc <= 0) {
  955. fprintf(stderr, "bye\n");
  956. shutdownThisThing=1;
  957. break;
  958. }
  959. bufoff += rc;
  960. buffer[bufoff] = '\0';
  961. while (strchr(buffer, '\n')) {
  962. char *ptr = strchr(buffer, '\n');
  963. *ptr = '\0';
  964. processline(buffer);
  965. ptr++;
  966. memmove(buffer, ptr, strlen(ptr)+1);
  967. bufoff = 0;
  968. }
  969. }
  970. #else
  971. FD_ZERO(&rfds);
  972. FD_ZERO(&wfds);
  973. FD_ZERO(&efds);
  974. while (!shutdownThisThing) {
  975. int fd;
  976. int interest;
  977. int events;
  978. struct timeval tv;
  979. int rc;
  980. zookeeper_interest(zh, &fd, &interest, &tv);
  981. if (fd != -1) {
  982. if (interest&ZOOKEEPER_READ) {
  983. FD_SET(fd, &rfds);
  984. } else {
  985. FD_CLR(fd, &rfds);
  986. }
  987. if (interest&ZOOKEEPER_WRITE) {
  988. FD_SET(fd, &wfds);
  989. } else {
  990. FD_CLR(fd, &wfds);
  991. }
  992. } else {
  993. fd = 0;
  994. }
  995. FD_SET(0, &rfds);
  996. rc = select(fd+1, &rfds, &wfds, &efds, &tv);
  997. events = 0;
  998. if (rc > 0) {
  999. if (FD_ISSET(fd, &rfds)) {
  1000. events |= ZOOKEEPER_READ;
  1001. }
  1002. if (FD_ISSET(fd, &wfds)) {
  1003. events |= ZOOKEEPER_WRITE;
  1004. }
  1005. }
  1006. if(batchMode && processed==0){
  1007. //batch mode
  1008. processline(cmd);
  1009. processed=1;
  1010. }
  1011. if (!processed && FD_ISSET(0, &rfds)) {
  1012. int rc;
  1013. int len = sizeof(buffer) - bufoff -1;
  1014. if (len <= 0) {
  1015. fprintf(stderr, "Can't handle lines that long!\n");
  1016. exit(2);
  1017. }
  1018. rc = read(0, buffer+bufoff, len);
  1019. if (rc <= 0) {
  1020. fprintf(stderr, "bye\n");
  1021. break;
  1022. }
  1023. bufoff += rc;
  1024. buffer[bufoff] = '\0';
  1025. while (strchr(buffer, '\n')) {
  1026. char *ptr = strchr(buffer, '\n');
  1027. *ptr = '\0';
  1028. processline(buffer);
  1029. ptr++;
  1030. memmove(buffer, ptr, strlen(ptr)+1);
  1031. bufoff = 0;
  1032. }
  1033. }
  1034. zookeeper_process(zh, events);
  1035. }
  1036. #endif
  1037. if (to_send!=0)
  1038. fprintf(stderr,"Recvd %d responses for %d requests sent\n",recvd,sent);
  1039. zookeeper_close(zh);
  1040. return 0;
  1041. }