corosync-objctl.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. * Copyright (c) 2008 Allied Telesis Labs NZ
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Angus Salkeld <angus.salkeld@alliedtelesis.co.nz>
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <errno.h>
  37. #include <signal.h>
  38. #include <unistd.h>
  39. #include <string.h>
  40. #include <sys/types.h>
  41. #include <sys/un.h>
  42. #include <corosync/saAis.h>
  43. #include <corosync/confdb.h>
  44. #define SEPERATOR '.'
  45. #define SEPERATOR_STR "."
  46. #define OBJ_NAME_SIZE 512
  47. typedef enum {
  48. ACTION_READ,
  49. ACTION_WRITE,
  50. ACTION_CREATE,
  51. ACTION_DELETE,
  52. ACTION_PRINT_ALL,
  53. ACTION_PRINT_DEFAULT,
  54. ACTION_TRACK,
  55. } action_types_t;
  56. typedef enum {
  57. FIND_OBJECT_ONLY,
  58. FIND_OBJECT_OR_KEY,
  59. FIND_KEY_ONLY
  60. } find_object_of_type_t;
  61. static void tail_key_changed(confdb_handle_t handle,
  62. confdb_change_type_t change_type,
  63. unsigned int parent_object_handle,
  64. unsigned int object_handle,
  65. void *object_name,
  66. int object_name_len,
  67. void *key_name,
  68. int key_name_len,
  69. void *key_value,
  70. int key_value_len);
  71. static void tail_object_created(confdb_handle_t handle,
  72. unsigned int parent_object_handle,
  73. unsigned int object_handle,
  74. uint8_t *name_pt,
  75. int name_len);
  76. static void tail_object_deleted(confdb_handle_t handle,
  77. unsigned int parent_object_handle,
  78. uint8_t *name_pt,
  79. int name_len);
  80. confdb_callbacks_t callbacks = {
  81. .confdb_key_change_notify_fn = tail_key_changed,
  82. .confdb_object_create_change_notify_fn = tail_object_created,
  83. .confdb_object_delete_change_notify_fn = tail_object_deleted,
  84. };
  85. static int action;
  86. /* Recursively dump the object tree */
  87. static void print_config_tree(confdb_handle_t handle, unsigned int parent_object_handle, char * parent_name)
  88. {
  89. unsigned int object_handle;
  90. char object_name[OBJ_NAME_SIZE];
  91. int object_name_len;
  92. char key_name[OBJ_NAME_SIZE];
  93. int key_name_len;
  94. char key_value[OBJ_NAME_SIZE];
  95. int key_value_len;
  96. confdb_error_t res;
  97. int children_printed;
  98. /* Show the keys */
  99. res = confdb_key_iter_start(handle, parent_object_handle);
  100. if (res != CONFDB_OK) {
  101. fprintf(stderr, "error resetting key iterator for object %d: %d\n", parent_object_handle, res);
  102. exit(EXIT_FAILURE);
  103. }
  104. children_printed = 0;
  105. while ( (res = confdb_key_iter(handle,
  106. parent_object_handle,
  107. key_name,
  108. &key_name_len,
  109. key_value,
  110. &key_value_len)) == CONFDB_OK) {
  111. key_name[key_name_len] = '\0';
  112. key_value[key_value_len] = '\0';
  113. if (parent_name != NULL)
  114. printf("%s%c%s=%s\n", parent_name, SEPERATOR,key_name, key_value);
  115. else
  116. printf("%s=%s\n", key_name, key_value);
  117. children_printed++;
  118. }
  119. /* Show sub-objects */
  120. res = confdb_object_iter_start(handle, parent_object_handle);
  121. if (res != CONFDB_OK) {
  122. fprintf(stderr, "error resetting object iterator for object %d: %d\n", parent_object_handle, res);
  123. exit(EXIT_FAILURE);
  124. }
  125. while ( (res = confdb_object_iter(handle,
  126. parent_object_handle,
  127. &object_handle,
  128. object_name,
  129. &object_name_len)) == CONFDB_OK) {
  130. object_name[object_name_len] = '\0';
  131. if (parent_name != NULL) {
  132. snprintf(key_value, OBJ_NAME_SIZE, "%s%c%s", parent_name, SEPERATOR, object_name);
  133. } else {
  134. if ((action == ACTION_PRINT_DEFAULT) && strcmp(object_name, "internal_configuration") == 0) continue;
  135. snprintf(key_value, OBJ_NAME_SIZE, "%s", object_name);
  136. }
  137. print_config_tree(handle, object_handle, key_value);
  138. children_printed++;
  139. }
  140. if (children_printed == 0 && parent_name != NULL) {
  141. printf("%s\n", parent_name);
  142. }
  143. }
  144. static int print_all(void)
  145. {
  146. confdb_handle_t handle;
  147. int result;
  148. result = confdb_initialize (&handle, &callbacks);
  149. if (result != CONFDB_OK) {
  150. fprintf (stderr, "Could not initialize objdb library. Error %d\n", result);
  151. return 1;
  152. }
  153. print_config_tree(handle, OBJECT_PARENT_HANDLE, NULL);
  154. result = confdb_finalize (handle);
  155. return 0;
  156. }
  157. static int print_help(void)
  158. {
  159. printf("\n");
  160. printf ("usage: corosync-objctl object%ckey ...\n", SEPERATOR);
  161. printf (" corosync-objctl -c object%cchild_obj ...\n", SEPERATOR);
  162. printf (" corosync-objctl -d object%cchild_obj ...\n", SEPERATOR);
  163. printf (" corosync-objctl -w object%cchild_obj.key=value ...\n", SEPERATOR);
  164. printf (" corosync-objctl -a (print all objects)\n");
  165. printf("\n");
  166. return 0;
  167. }
  168. static confdb_error_t validate_name(char * obj_name_pt)
  169. {
  170. if ((strchr (obj_name_pt, SEPERATOR) == NULL) &&
  171. (strchr (obj_name_pt, '=') == NULL))
  172. return CONFDB_OK;
  173. else
  174. return CONFDB_ERR_INVALID_PARAM;
  175. }
  176. void get_child_name(char * name_pt, char * child_name)
  177. {
  178. char * tmp;
  179. char str_copy[OBJ_NAME_SIZE];
  180. strcpy(str_copy, name_pt);
  181. /* first remove the value (it could be a file path */
  182. tmp = strchr(str_copy, '=');
  183. if (tmp != NULL) *tmp = '\0';
  184. /* truncate the */
  185. tmp = strrchr(str_copy, SEPERATOR);
  186. if (tmp == NULL) tmp = str_copy;
  187. strcpy(child_name, tmp+1);
  188. }
  189. void get_parent_name(char * name_pt, char * parent_name)
  190. {
  191. char * tmp;
  192. strcpy(parent_name, name_pt);
  193. /* first remove the value (it could be a file path */
  194. tmp = strchr(parent_name, '=');
  195. if (tmp != NULL) *tmp = '\0';
  196. /* then truncate the child name */
  197. tmp = strrchr(parent_name, SEPERATOR);
  198. if (tmp != NULL) *tmp = '\0';
  199. }
  200. void get_key(char * name_pt, char * key_name, char * key_value)
  201. {
  202. char * tmp;
  203. char str_copy[OBJ_NAME_SIZE];
  204. strcpy(str_copy, name_pt);
  205. /* first remove the value (it could have a SEPERATOR in it */
  206. tmp = strchr(str_copy, '=');
  207. if (tmp != NULL && strlen(tmp) > 0) {
  208. strcpy(key_value, tmp+1);
  209. *tmp = '\0';
  210. } else {
  211. key_value[0] = '\0';
  212. }
  213. /* then remove the name */
  214. tmp = strrchr(str_copy, SEPERATOR);
  215. if (tmp == NULL) tmp = str_copy;
  216. strcpy(key_name, tmp+1);
  217. }
  218. static confdb_error_t find_object (confdb_handle_t handle,
  219. char * name_pt,
  220. find_object_of_type_t type,
  221. uint32_t * out_handle)
  222. {
  223. char * obj_name_pt;
  224. char * save_pt;
  225. uint32_t obj_handle;
  226. confdb_handle_t parent_object_handle = OBJECT_PARENT_HANDLE;
  227. char tmp_name[OBJ_NAME_SIZE];
  228. confdb_error_t res;
  229. strncpy (tmp_name, name_pt, OBJ_NAME_SIZE);
  230. obj_name_pt = strtok_r(tmp_name, SEPERATOR_STR, &save_pt);
  231. while (obj_name_pt != NULL) {
  232. res = confdb_object_find_start(handle, parent_object_handle);
  233. if (res != CONFDB_OK) {
  234. fprintf (stderr, "Could not start object_find %d\n", res);
  235. exit (EXIT_FAILURE);
  236. }
  237. res = confdb_object_find(handle, parent_object_handle,
  238. obj_name_pt, strlen (obj_name_pt), &obj_handle);
  239. if (res != CONFDB_OK) {
  240. return res;
  241. }
  242. parent_object_handle = obj_handle;
  243. obj_name_pt = strtok_r (NULL, SEPERATOR_STR, &save_pt);
  244. }
  245. *out_handle = parent_object_handle;
  246. return res;
  247. }
  248. static void read_object(confdb_handle_t handle, char * name_pt)
  249. {
  250. char parent_name[OBJ_NAME_SIZE];
  251. uint32_t obj_handle;
  252. confdb_error_t res;
  253. get_parent_name(name_pt, parent_name);
  254. res = find_object (handle, name_pt, FIND_OBJECT_OR_KEY, &obj_handle);
  255. if (res == CONFDB_OK) {
  256. print_config_tree(handle, obj_handle, parent_name);
  257. }
  258. }
  259. static void write_key(confdb_handle_t handle, char * path_pt)
  260. {
  261. uint32_t obj_handle;
  262. char parent_name[OBJ_NAME_SIZE];
  263. char key_name[OBJ_NAME_SIZE];
  264. char key_value[OBJ_NAME_SIZE];
  265. char old_key_value[OBJ_NAME_SIZE];
  266. int old_key_value_len;
  267. confdb_error_t res;
  268. /* find the parent object */
  269. get_parent_name(path_pt, parent_name);
  270. get_key(path_pt, key_name, key_value);
  271. if (validate_name(key_name) != CONFDB_OK) {
  272. fprintf(stderr, "Incorrect key name, can not have \"=\" or \"%c\"\n", SEPERATOR);
  273. exit(EXIT_FAILURE);
  274. }
  275. res = find_object (handle, parent_name, FIND_OBJECT_ONLY, &obj_handle);
  276. if (res != CONFDB_OK) {
  277. fprintf(stderr, "Can't find parent object of \"%s\"\n", path_pt);
  278. exit(EXIT_FAILURE);
  279. }
  280. /* get the current key */
  281. res = confdb_key_get (handle,
  282. obj_handle,
  283. key_name,
  284. strlen(key_name),
  285. old_key_value,
  286. &old_key_value_len);
  287. if (res == CONFDB_OK) {
  288. /* replace the current value */
  289. res = confdb_key_replace (handle,
  290. obj_handle,
  291. key_name,
  292. strlen(key_name),
  293. old_key_value,
  294. old_key_value_len,
  295. key_value,
  296. strlen(key_value));
  297. if (res != CONFDB_OK)
  298. fprintf(stderr, "Failed to replace the key %s=%s. Error %d\n", key_name, key_value, res);
  299. } else {
  300. /* not there, create a new key */
  301. res = confdb_key_create (handle,
  302. obj_handle,
  303. key_name,
  304. strlen(key_name),
  305. key_value,
  306. strlen(key_value));
  307. if (res != CONFDB_OK)
  308. fprintf(stderr, "Failed to create the key %s=%s. Error %d\n", key_name, key_value, res);
  309. }
  310. }
  311. static void create_object(confdb_handle_t handle, char * name_pt)
  312. {
  313. char * obj_name_pt;
  314. char * save_pt;
  315. uint32_t obj_handle;
  316. uint32_t parent_object_handle = OBJECT_PARENT_HANDLE;
  317. char tmp_name[OBJ_NAME_SIZE];
  318. confdb_error_t res;
  319. strncpy (tmp_name, name_pt, OBJ_NAME_SIZE);
  320. obj_name_pt = strtok_r(tmp_name, SEPERATOR_STR, &save_pt);
  321. while (obj_name_pt != NULL) {
  322. res = confdb_object_find_start(handle, parent_object_handle);
  323. if (res != CONFDB_OK) {
  324. fprintf (stderr, "Could not start object_find %d\n", res);
  325. exit (EXIT_FAILURE);
  326. }
  327. res = confdb_object_find(handle, parent_object_handle,
  328. obj_name_pt, strlen (obj_name_pt), &obj_handle);
  329. if (res != CONFDB_OK) {
  330. if (validate_name(obj_name_pt) != CONFDB_OK) {
  331. fprintf(stderr, "Incorrect object name \"%s\", \"=\" not allowed.\n",
  332. obj_name_pt);
  333. exit(EXIT_FAILURE);
  334. }
  335. res = confdb_object_create (handle,
  336. parent_object_handle,
  337. obj_name_pt,
  338. strlen (obj_name_pt),
  339. &obj_handle);
  340. if (res != CONFDB_OK)
  341. fprintf(stderr, "Failed to create object \"%s\". Error %d.\n",
  342. obj_name_pt, res);
  343. }
  344. parent_object_handle = obj_handle;
  345. obj_name_pt = strtok_r (NULL, SEPERATOR_STR, &save_pt);
  346. }
  347. }
  348. static void tail_key_changed(confdb_handle_t handle,
  349. confdb_change_type_t change_type,
  350. unsigned int parent_object_handle,
  351. unsigned int object_handle,
  352. void *object_name_pt,
  353. int object_name_len,
  354. void *key_name_pt,
  355. int key_name_len,
  356. void *key_value_pt,
  357. int key_value_len)
  358. {
  359. char * on = (char*)object_name_pt;
  360. char * kn = (char*)key_name_pt;
  361. char * kv = (char*)key_value_pt;
  362. on[object_name_len] = '\0';
  363. kv[key_value_len] = '\0';
  364. kn[key_name_len] = '\0';
  365. printf("key_changed> %s.%s=%s\n", on, kn, kv);
  366. }
  367. static void tail_object_created(confdb_handle_t handle,
  368. unsigned int parent_object_handle,
  369. unsigned int object_handle,
  370. uint8_t *name_pt,
  371. int name_len)
  372. {
  373. name_pt[name_len] = '\0';
  374. printf("object_created> %s\n", name_pt);
  375. }
  376. static void tail_object_deleted(confdb_handle_t handle,
  377. unsigned int parent_object_handle,
  378. uint8_t *name_pt,
  379. int name_len)
  380. {
  381. name_pt[name_len] = '\0';
  382. printf("object_deleted> %s\n", name_pt);
  383. }
  384. static void listen_for_object_changes(confdb_handle_t handle)
  385. {
  386. int result;
  387. fd_set read_fds;
  388. int select_fd;
  389. SaBoolT quit = SA_FALSE;
  390. FD_ZERO (&read_fds);
  391. confdb_fd_get(handle, &select_fd);
  392. printf ("Type \"q\" to finish\n");
  393. do {
  394. FD_SET (select_fd, &read_fds);
  395. FD_SET (STDIN_FILENO, &read_fds);
  396. result = select (select_fd + 1, &read_fds, 0, 0, 0);
  397. if (result == -1) {
  398. perror ("select\n");
  399. }
  400. if (FD_ISSET (STDIN_FILENO, &read_fds)) {
  401. char inbuf[3];
  402. fgets(inbuf, sizeof(inbuf), stdin);
  403. if (strncmp(inbuf, "q", 1) == 0)
  404. quit = SA_TRUE;
  405. }
  406. if (FD_ISSET (select_fd, &read_fds)) {
  407. if (confdb_dispatch (handle, CONFDB_DISPATCH_ALL) != CONFDB_OK)
  408. exit(1);
  409. }
  410. } while (result && quit == SA_FALSE);
  411. confdb_stop_track_changes(handle);
  412. }
  413. static void track_object(confdb_handle_t handle, char * name_pt)
  414. {
  415. confdb_error_t res;
  416. uint32_t obj_handle;
  417. res = find_object (handle, name_pt, FIND_OBJECT_ONLY, &obj_handle);
  418. if (res != CONFDB_OK) {
  419. fprintf (stderr, "Could not find object \"%s\". Error %d\n",
  420. name_pt, res);
  421. return;
  422. }
  423. res = confdb_track_changes (handle, obj_handle, CONFDB_TRACK_DEPTH_RECURSIVE);
  424. if (res != CONFDB_OK) {
  425. fprintf (stderr, "Could not enable tracking on object \"%s\". Error %d\n",
  426. name_pt, res);
  427. return;
  428. }
  429. }
  430. static void stop_tracking(confdb_handle_t handle)
  431. {
  432. confdb_error_t res;
  433. res = confdb_stop_track_changes (handle);
  434. if (res != CONFDB_OK) {
  435. fprintf (stderr, "Could not stop tracking. Error %d\n", res);
  436. return;
  437. }
  438. }
  439. static void delete_object(confdb_handle_t handle, char * name_pt)
  440. {
  441. confdb_error_t res;
  442. uint32_t obj_handle;
  443. res = find_object (handle, name_pt, FIND_OBJECT_ONLY, &obj_handle);
  444. if (res == CONFDB_OK) {
  445. res = confdb_object_destroy (handle, obj_handle);
  446. if (res != CONFDB_OK)
  447. fprintf(stderr, "Failed to find object \"%s\" to delete. Error %d\n", name_pt, res);
  448. } else {
  449. char parent_name[OBJ_NAME_SIZE];
  450. char key_name[OBJ_NAME_SIZE];
  451. char key_value[OBJ_NAME_SIZE];
  452. /* find the parent object */
  453. get_parent_name(name_pt, parent_name);
  454. get_key(name_pt, key_name, key_value);
  455. res = find_object (handle, parent_name, FIND_OBJECT_ONLY, &obj_handle);
  456. if (res != CONFDB_OK) {
  457. fprintf(stderr, "Failed to find the key's parent object \"%s\". Error %d\n", parent_name, res);
  458. exit (EXIT_FAILURE);
  459. }
  460. res = confdb_key_delete (handle,
  461. obj_handle,
  462. key_name,
  463. strlen(key_name),
  464. key_value,
  465. strlen(key_value));
  466. if (res != CONFDB_OK)
  467. fprintf(stderr, "Failed to delete key \"%s=%s\" from object \"%s\". Error %d\n",
  468. key_name, key_value, parent_name, res);
  469. }
  470. }
  471. int main (int argc, char *argv[]) {
  472. confdb_handle_t handle;
  473. confdb_error_t result;
  474. char c;
  475. action = ACTION_READ;
  476. for (;;){
  477. c = getopt (argc,argv,"hawcdtp:");
  478. if (c==-1) {
  479. break;
  480. }
  481. switch (c) {
  482. case 'h':
  483. return print_help();
  484. break;
  485. case 'a':
  486. action = ACTION_PRINT_ALL;
  487. break;
  488. case 'p':
  489. printf("%s:%d NOT Implemented yet.\n", __FUNCTION__, __LINE__);
  490. return -1;
  491. //return read_in_config_file();
  492. break;
  493. case 'c':
  494. action = ACTION_CREATE;
  495. break;
  496. case 'd':
  497. action = ACTION_DELETE;
  498. break;
  499. case 'w':
  500. action = ACTION_WRITE;
  501. break;
  502. case 't':
  503. action = ACTION_TRACK;
  504. break;
  505. default :
  506. action = ACTION_READ;
  507. break;
  508. }
  509. }
  510. if (argc == 1) {
  511. action = ACTION_PRINT_DEFAULT;
  512. return print_all();
  513. } else if (action == ACTION_PRINT_ALL) {
  514. return print_all();
  515. } else if (optind >= argc) {
  516. fprintf(stderr, "Expected an object path after options\n");
  517. exit(EXIT_FAILURE);
  518. }
  519. result = confdb_initialize (&handle, &callbacks);
  520. if (result != CONFDB_OK) {
  521. fprintf (stderr, "Failed to initialize the objdb API. Error %d\n", result);
  522. exit (EXIT_FAILURE);
  523. }
  524. while (optind < argc) {
  525. switch (action) {
  526. case ACTION_READ:
  527. read_object(handle, argv[optind++]);
  528. break;
  529. case ACTION_WRITE:
  530. write_key(handle, argv[optind++]);
  531. break;
  532. case ACTION_CREATE:
  533. create_object(handle, argv[optind++]);
  534. break;
  535. case ACTION_DELETE:
  536. delete_object(handle, argv[optind++]);
  537. break;
  538. case ACTION_TRACK:
  539. track_object(handle, argv[optind++]);
  540. break;
  541. }
  542. }
  543. if (action == ACTION_TRACK) {
  544. listen_for_object_changes(handle);
  545. stop_tracking(handle);
  546. }
  547. result = confdb_finalize (handle);
  548. if (result != CONFDB_OK) {
  549. fprintf (stderr, "Error finalizing objdb API. Error %d\n", result);
  550. exit(EXIT_FAILURE);
  551. }
  552. return 0;
  553. }