dbscan.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2005 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. /*
  38. * small program to scan a Directory Server db file and dump the contents
  39. *
  40. * TODO: indirect indexes
  41. */
  42. #include <stdio.h>
  43. #include <stdarg.h>
  44. #include <stdlib.h>
  45. #include <sys/types.h>
  46. #include <time.h>
  47. #include <string.h>
  48. #include <ctype.h>
  49. #include "db.h"
  50. #ifdef _WIN32
  51. #include <windows.h>
  52. #include <winsock.h>
  53. extern int getopt();
  54. extern char *optarg;
  55. typedef unsigned char uint8_t;
  56. #else
  57. #include <netinet/in.h>
  58. #include <inttypes.h>
  59. #endif
  60. /* file type */
  61. #define ENTRYTYPE 0x1
  62. #define INDEXTYPE 0x2
  63. #define VLVINDEXTYPE 0x4
  64. #define CHANGELOGTYPE 0x8
  65. /* display mode */
  66. #define RAWDATA 0x1
  67. #define SHOWCOUNT 0x2
  68. #define SHOWDATA 0x4
  69. #define SHOWSUMMARY 0x8
  70. /* stolen from slapi-plugin.h */
  71. #define SLAPI_OPERATION_BIND 0x00000001UL
  72. #define SLAPI_OPERATION_UNBIND 0x00000002UL
  73. #define SLAPI_OPERATION_SEARCH 0x00000004UL
  74. #define SLAPI_OPERATION_MODIFY 0x00000008UL
  75. #define SLAPI_OPERATION_ADD 0x00000010UL
  76. #define SLAPI_OPERATION_DELETE 0x00000020UL
  77. #define SLAPI_OPERATION_MODDN 0x00000040UL
  78. #define SLAPI_OPERATION_MODRDN SLAPI_OPERATION_MODDN
  79. #define SLAPI_OPERATION_COMPARE 0x00000080UL
  80. #define SLAPI_OPERATION_ABANDON 0x00000100UL
  81. #define SLAPI_OPERATION_EXTENDED 0x00000200UL
  82. #define SLAPI_OPERATION_ANY 0xFFFFFFFFUL
  83. #define SLAPI_OPERATION_NONE 0x00000000UL
  84. #define ONEMEG (1024*1024)
  85. #if defined(linux)
  86. #include <getopt.h>
  87. #endif
  88. typedef u_int32_t ID;
  89. typedef unsigned int uint32;
  90. typedef struct {
  91. uint32 max;
  92. uint32 used;
  93. uint32 id[1];
  94. } IDL;
  95. /** db_printf - functioning same as printf but a place for manipluating output.
  96. */
  97. void db_printf(char *fmt, ...)
  98. {
  99. va_list ap;
  100. va_start(ap, fmt);
  101. vfprintf(stdout, fmt, ap);
  102. }
  103. void db_printfln(char *fmt, ...)
  104. {
  105. va_list ap;
  106. va_start(ap, fmt);
  107. vfprintf(stdout, fmt, ap);
  108. vfprintf(stdout, "\n", NULL);
  109. }
  110. int MAX_BUFFER = 4096;
  111. int MIN_BUFFER = 20;
  112. static IDL *idl_make(DBT *data)
  113. {
  114. IDL *idl = NULL, *xidl;
  115. if (data->size < 2*sizeof(uint32)) {
  116. idl = (IDL *)malloc(sizeof(IDL) + 64*sizeof(uint32));
  117. if (! idl)
  118. return NULL;
  119. idl->max = 64;
  120. idl->used = 1;
  121. idl->id[0] = *(uint32 *)(data->data);
  122. return idl;
  123. }
  124. xidl = (IDL *)(data->data);
  125. idl = (IDL *)malloc(data->size);
  126. if (! idl)
  127. return NULL;
  128. memcpy(idl, xidl, data->size);
  129. return idl;
  130. }
  131. static void idl_free(IDL *idl)
  132. {
  133. idl->max = 0;
  134. idl->used = 0;
  135. free(idl);
  136. }
  137. static IDL *idl_append(IDL *idl, uint32 id)
  138. {
  139. if (idl->used >= idl->max) {
  140. /* must grow */
  141. idl->max *= 2;
  142. idl = realloc(idl, sizeof(IDL) + idl->max * sizeof(uint32));
  143. if (! idl)
  144. return NULL;
  145. }
  146. idl->id[idl->used++] = id;
  147. return idl;
  148. }
  149. /* format a string for easy printing */
  150. #define FMT_LF_OK 1
  151. #define FMT_SP_OK 2
  152. static char *format_raw(unsigned char *s, int len, int flags)
  153. {
  154. static unsigned char buf[BUFSIZ]; /* not intended to be threadsafe */
  155. static char hex[] = "0123456789ABCDEF";
  156. unsigned char *p, *o;
  157. int i;
  158. for (p = s, o = buf, i = 0; i < len; p++, i++) {
  159. if ((*p == '%') || (*p <= ' ') || (*p >= 126)) {
  160. /* index keys are stored with their trailing NUL */
  161. if ((*p == 0) && (i == len-1))
  162. continue;
  163. if ((flags & FMT_LF_OK) && (*p == '\n')) {
  164. *o++ = '\n';
  165. *o++ = '\t';
  166. } else if ((flags && FMT_SP_OK) && (*p == ' ')) {
  167. *o++ = ' ';
  168. } else {
  169. *o++ = '%';
  170. *o++ = hex[*p / 16];
  171. *o++ = hex[*p % 16];
  172. }
  173. } else {
  174. *o++ = *p;
  175. }
  176. if (o-buf > BUFSIZ-5) {
  177. /* out of space */
  178. strcpy(o, " ...");
  179. i = len;
  180. }
  181. }
  182. *o = 0;
  183. return (char *)buf;
  184. }
  185. static char *format(unsigned char *s, int len)
  186. {
  187. return format_raw(s, len, 0);
  188. }
  189. static char *format_entry(unsigned char *s, int len)
  190. {
  191. return format_raw(s, len, FMT_LF_OK | FMT_SP_OK);
  192. }
  193. static char *idl_format(IDL *idl, int isfirsttime, int *done)
  194. {
  195. static char *buf = NULL;
  196. static uint32 i = 0;
  197. if (buf == NULL) {
  198. buf = (char *)malloc(MAX_BUFFER);
  199. if (buf == NULL)
  200. return "?";
  201. }
  202. buf[0] = 0;
  203. if (0 != isfirsttime) {
  204. i = 0;
  205. }
  206. for (; i < idl->used; i++) {
  207. sprintf((char *)buf + strlen(buf), "%d ", idl->id[i]);
  208. if (strlen(buf) > (size_t)MAX_BUFFER-MIN_BUFFER) {
  209. i++;
  210. done = 0;
  211. return (char *)buf;
  212. }
  213. }
  214. *done = 1;
  215. return (char *)buf;
  216. }
  217. /*** Copied from cl5_api.c: _cl5ReadString ***/
  218. void _cl5ReadString (char **str, char **buff)
  219. {
  220. if (str)
  221. {
  222. int len = strlen (*buff);
  223. if (len)
  224. {
  225. *str = strdup(*buff);
  226. (*buff) += len + 1;
  227. }
  228. else /* just null char - skip it */
  229. {
  230. *str = NULL;
  231. (*buff) ++;
  232. }
  233. }
  234. else /* just skip this string */
  235. {
  236. (*buff) += strlen (*buff) + 1;
  237. }
  238. }
  239. /** print_attr - print attribute name followed by one value.
  240. assume the value stored as null terminated string.
  241. */
  242. void print_attr(char *attrname, char **buff)
  243. {
  244. char *val = NULL;
  245. _cl5ReadString(&val, buff);
  246. if(attrname != NULL || val != NULL) {
  247. db_printf("\t");
  248. }
  249. if(attrname) {
  250. db_printf("%s: ", attrname);
  251. }
  252. if(val != NULL) {
  253. db_printf("%s\n", val);
  254. free(val);
  255. }
  256. }
  257. /*** Copied from cl5_api.c: _cl5ReadMods ***/
  258. /* mods format:
  259. -----------
  260. <4 byte mods count><mod1><mod2>...
  261. mod format:
  262. -----------
  263. <1 byte modop><null terminated attr name><4 byte count>
  264. {<4 byte size><value1><4 byte size><value2>... ||
  265. <null terminated str1> <null terminated str2>...}
  266. */
  267. void _cl5ReadMod(char **buff);
  268. void _cl5ReadMods(char **buff)
  269. {
  270. char *pos = *buff;
  271. uint32 i;
  272. uint32 mod_count;
  273. /* need to copy first, to skirt around alignment problems on certain
  274. architectures */
  275. memcpy((char *)&mod_count, *buff, sizeof(mod_count));
  276. mod_count = ntohl(mod_count);
  277. pos += sizeof (mod_count);
  278. for (i = 0; i < mod_count; i++)
  279. {
  280. _cl5ReadMod (&pos);
  281. }
  282. *buff = pos;
  283. }
  284. /** print_ber_attr - print one line of attribute, the value was stored
  285. in ber format, length followed by string.
  286. */
  287. void print_ber_attr(char* attrname, char** buff)
  288. {
  289. char *val = NULL;
  290. uint32 bv_len;
  291. memcpy((char *)&bv_len, *buff, sizeof(bv_len));
  292. bv_len = ntohl(bv_len);
  293. *buff += sizeof (uint32);
  294. if (bv_len > 0) {
  295. db_printf("\t\t");
  296. if(attrname != NULL) {
  297. db_printf("%s: ", attrname);
  298. }
  299. val = malloc(bv_len + 1);
  300. memcpy (val, *buff, bv_len);
  301. val[bv_len] = 0;
  302. *buff += bv_len;
  303. db_printf("%s\n", val);
  304. free(val);
  305. }
  306. }
  307. /*
  308. * Conversion routines between host byte order and
  309. * big-endian (which is how we store data in the db).
  310. */
  311. static ID id_stored_to_internal(char* b)
  312. {
  313. ID i;
  314. i = (ID)b[3] & 0x000000ff;
  315. i |= (((ID)b[2]) << 8) & 0x0000ff00;
  316. i |= (((ID)b[1]) << 16) & 0x00ff0000;
  317. i |= ((ID)b[0]) << 24;
  318. return i;
  319. }
  320. static void id_internal_to_stored(ID i,char *b)
  321. {
  322. if ( sizeof(ID) > 4 ) {
  323. memset (b+4, 0, sizeof(ID)-4);
  324. }
  325. b[0] = (char)(i >> 24);
  326. b[1] = (char)(i >> 16);
  327. b[2] = (char)(i >> 8);
  328. b[3] = (char)i;
  329. }
  330. void _cl5ReadMod(char **buff)
  331. {
  332. char *pos = *buff;
  333. uint32 i;
  334. uint32 val_count;
  335. char *type = NULL;
  336. int op;
  337. op = (*pos) & 0x000000FF;
  338. pos ++;
  339. _cl5ReadString (&type, &pos);
  340. /* need to do the copy first, to skirt around alignment problems on
  341. certain architectures */
  342. memcpy((char *)&val_count, pos, sizeof(val_count));
  343. val_count = ntohl(val_count);
  344. pos += sizeof (uint32);
  345. for (i = 0; i < val_count; i++)
  346. {
  347. print_ber_attr(type, &pos);
  348. }
  349. (*buff) = pos;
  350. free(type);
  351. }
  352. /*
  353. *** Copied from cl5_api:cl5DBData2Entry ***
  354. Data in db format:
  355. ------------------
  356. <1 byte version><1 byte change_type><sizeof uint32 time><null terminated dbid>
  357. <null terminated csn><null terminated uniqueid><null terminated targetdn>
  358. [<null terminated newrdn><1 byte deleteoldrdn>][<4 byte mod count><mod1><mod2>....]
  359. Note: the length of time is set uint32 instead of time_t. Regardless of the
  360. width of long (32-bit or 64-bit), it's stored using 4bytes by the server [153306].
  361. mod format:
  362. -----------
  363. <1 byte modop><null terminated attr name><4 byte value count>
  364. <4 byte value size><value1><4 byte value size><value2>
  365. */
  366. void print_changelog(unsigned char *data, int len)
  367. {
  368. uint8_t version;
  369. unsigned long operation_type;
  370. char *pos = (char *)data;
  371. uint32 thetime32;
  372. time_t thetime;
  373. uint32 replgen;
  374. /* read byte of version */
  375. version = *((uint8_t *)pos);
  376. if (version != 5)
  377. {
  378. db_printf("Invalid changelog db version %i\nWorks for version 5 only.\n", version);
  379. exit(1);
  380. }
  381. pos += sizeof(version);
  382. /* read change type */
  383. operation_type = (unsigned long)(*(uint8_t *)pos);
  384. pos ++;
  385. /* need to do the copy first, to skirt around alignment problems on
  386. certain architectures */
  387. memcpy((char *)&thetime32, pos, sizeof(thetime32));
  388. replgen = ntohl(thetime32);
  389. pos += sizeof(uint32);
  390. thetime = (time_t)replgen;
  391. db_printf("\treplgen: %ld %s", replgen, ctime((time_t *)&thetime));
  392. /* read csn */
  393. print_attr("csn", &pos);
  394. /* read UniqueID */
  395. print_attr("uniqueid", &pos);
  396. /* figure out what else we need to read depending on the operation type */
  397. switch (operation_type)
  398. {
  399. case SLAPI_OPERATION_ADD:
  400. print_attr("parentuniqueid", &pos);
  401. print_attr("dn", &pos);
  402. /* convert mods to entry */
  403. db_printf("\toperation: add\n");
  404. _cl5ReadMods(&pos);
  405. break;
  406. case SLAPI_OPERATION_MODIFY:
  407. print_attr("dn", &pos);
  408. db_printf("\toperation: modify\n");
  409. _cl5ReadMods(&pos);
  410. break;
  411. case SLAPI_OPERATION_MODRDN:
  412. print_attr("dn", &pos);
  413. print_attr("newrdn", &pos);
  414. pos ++;
  415. print_attr("dn", &pos);
  416. print_attr("uniqueid", &pos);
  417. db_printf("\toperation: modrdn\n");
  418. _cl5ReadMods(&pos);
  419. break;
  420. case SLAPI_OPERATION_DELETE:
  421. print_attr("dn", &pos);
  422. db_printf("\toperation: delete\n");
  423. break;
  424. default:
  425. db_printf("Failed to format entry\n");
  426. break;
  427. }
  428. }
  429. uint32 file_type = 0;
  430. uint32 min_display = 0;
  431. uint32 display_mode = 0;
  432. int verbose = 0;
  433. long pres_cnt = 0;
  434. long eq_cnt = 0;
  435. long app_cnt = 0;
  436. long sub_cnt = 0;
  437. long match_cnt = 0;
  438. long ind_cnt = 0;
  439. long allids_cnt = 0;
  440. long other_cnt = 0;
  441. static void display_index_item(DBC *cursor, DBT *key, DBT *data)
  442. {
  443. IDL *idl = NULL;
  444. int ret = 0;
  445. idl = idl_make(data);
  446. if (idl == NULL) {
  447. printf("\t(illegal idl)\n");
  448. return;
  449. }
  450. if (file_type & VLVINDEXTYPE) { /* vlv index file */
  451. if (1 > min_display) { /* recno is always 1 */
  452. if (display_mode & SHOWCOUNT) { /* key size=1 */
  453. printf("%-40s 1\n", format(key->data, key->size));
  454. } else {
  455. printf("%-40s\n", format(key->data, key->size));
  456. }
  457. if (display_mode & SHOWDATA) {
  458. cursor->c_get(cursor, key, data, DB_GET_RECNO);
  459. printf("\t%5d\n", *(db_recno_t *)(data->data));
  460. }
  461. }
  462. goto index_done;
  463. }
  464. /* ordinary index file */
  465. /* fetch all other id's too */
  466. while (ret == 0) {
  467. ret = cursor->c_get(cursor, key, data, DB_NEXT_DUP);
  468. if (ret == 0)
  469. idl = idl_append(idl, *(uint32 *)(data->data));
  470. }
  471. if (ret == DB_NOTFOUND)
  472. ret = 0;
  473. if (ret != 0) {
  474. printf("Failure while looping dupes: %s\n", db_strerror(ret));
  475. exit(1);
  476. }
  477. if (idl && idl->max == 0) {
  478. /* allids; should not exist in the new idl world */
  479. if ( allids_cnt == 0 && (display_mode & SHOWSUMMARY)) {
  480. printf("The following index keys reached allids:\n");
  481. }
  482. printf("%-40s(allids)\n", format(key->data, key->size));
  483. allids_cnt++;
  484. } else {
  485. if (idl->used < min_display) {
  486. goto index_done; /* less than minimum display count */
  487. } else if (display_mode & SHOWCOUNT) { /* key size */
  488. printf("%-40s%d\n", format(key->data, key->size), idl->used);
  489. } else if (!(display_mode & SHOWSUMMARY) || (display_mode & SHOWDATA)) {
  490. /* show keys only if show summary is not set or
  491. * even if it's set, but with show data */
  492. printf("%-40s\n", format(key->data, key->size));
  493. }
  494. if (display_mode & SHOWDATA) {
  495. char *formatted_idl = NULL;
  496. int done = 0;
  497. int isfirsttime = 1;
  498. while (0 == done) {
  499. formatted_idl = idl_format(idl, isfirsttime, &done);
  500. if (NULL == formatted_idl) {
  501. done = 1; /* no more idl */
  502. } else {
  503. if (1 == isfirsttime) {
  504. printf("\t%s", formatted_idl);
  505. isfirsttime = 0;
  506. } else {
  507. printf("%s", formatted_idl);
  508. }
  509. }
  510. }
  511. printf("\n");
  512. }
  513. }
  514. index_done:
  515. if ( display_mode & SHOWSUMMARY ) {
  516. char firstchar;
  517. firstchar = ((char*)key->data)[0];
  518. switch ( firstchar ) {
  519. case '+':
  520. pres_cnt += idl->used;
  521. break;
  522. case '=':
  523. eq_cnt += idl->used;
  524. break;
  525. case '~':
  526. app_cnt += idl->used;
  527. break;
  528. case '*':
  529. sub_cnt += idl->used;
  530. break;
  531. case ':':
  532. match_cnt += idl->used;
  533. break;
  534. case '\\':
  535. ind_cnt += idl->used;
  536. break;
  537. default:
  538. other_cnt += idl->used;
  539. break;
  540. }
  541. }
  542. idl_free(idl);
  543. return;
  544. }
  545. static void display_item(DBC *cursor, DBT *key, DBT *data)
  546. {
  547. if (display_mode & RAWDATA) {
  548. printf("%s\n", format(key->data, key->size));
  549. printf("\t%s\n", format(data->data, data->size));
  550. } else {
  551. if (file_type & INDEXTYPE) {
  552. display_index_item(cursor, key, data);
  553. } else if (file_type & CHANGELOGTYPE) {
  554. /* changelog db file */
  555. printf("\ndbid: %s\n", format(key->data, key->size));
  556. print_changelog(data->data, data->size);
  557. return;
  558. } else if (file_type & ENTRYTYPE) {
  559. /* id2entry file */
  560. ID entry_id = id_stored_to_internal(key->data);
  561. printf("id %d\n", entry_id);
  562. printf("\t%s\n", format_entry(data->data, data->size));
  563. } else {
  564. /* user didn't tell us what kind of file, dump it raw */
  565. printf("%s\n", format(key->data, key->size));
  566. printf("\t%s\n", format(data->data, data->size));
  567. }
  568. }
  569. return;
  570. }
  571. static int
  572. is_changelog(char *filename)
  573. {
  574. char *ptr = NULL;
  575. int dashes = 0;
  576. int underscore = 0;
  577. if (NULL == (ptr = strrchr(filename, '/'))) {
  578. if (NULL == (ptr = strrchr(filename, '\\'))) {
  579. ptr = filename;
  580. } else {
  581. ptr++;
  582. }
  583. } else {
  584. ptr++;
  585. }
  586. for (; ptr && *ptr; ptr++) {
  587. if ('.' == *ptr) {
  588. if (0 == strncmp(ptr, ".db", 3)) {
  589. if (3 == dashes && 1 == underscore) {
  590. return 1;
  591. } else {
  592. return 0;
  593. }
  594. }
  595. } else if ('-' == *ptr) {
  596. if (underscore > 0) {
  597. return 0;
  598. }
  599. dashes++;
  600. } else if ('_' == *ptr) {
  601. if (dashes < 3) {
  602. return 0;
  603. }
  604. underscore++;
  605. } else if (!isxdigit(*ptr)) {
  606. return 0;
  607. }
  608. }
  609. return 0;
  610. }
  611. static void usage(char *argv0)
  612. {
  613. printf("\n%s - scan a db file and dump the contents\n", argv0);
  614. printf(" common options:\n");
  615. printf(" -f <filename> specify db file\n");
  616. printf(" -R dump as raw data\n");
  617. printf(" entry file options:\n");
  618. printf(" -K <entry_id> lookup only a specific entry id\n");
  619. printf(" index file options:\n");
  620. printf(" -k <key> lookup only a specific key\n");
  621. printf(" -l <size> max length of dumped id list\n");
  622. printf(" (default %d; 40 bytes <= size <= 1048576 bytes)\n",
  623. MAX_BUFFER);
  624. printf(" -G <n> only display index entries with more than <n> ids\n");
  625. printf(" -n display idl lengths\n");
  626. printf(" -r display the conents of idl\n");
  627. printf(" -s Summary of index counts\n");
  628. printf(" sample usages:\n");
  629. printf(" # set <serverroot>/bin/slapd/server:<serverroot>/shared/lib in the library path\n");
  630. printf(" # dump the entry file\n");
  631. printf(" %s -f id2entry.db\n", argv0);
  632. printf(" # display index keys in cn.db4\n");
  633. printf(" %s -f cn.db4\n", argv0);
  634. printf(" # display index keys and the count of entries having the key in mail.db4\n");
  635. printf(" %s -r -f mail.db4\n", argv0);
  636. printf(" # display index keys and the IDs having more than 20 IDs in sn.db4\n");
  637. printf(" %s -r -G 20 -f sn.db4\n", argv0);
  638. printf(" # display summary of objectclass.db4\n");
  639. printf(" %s -f objectclass.db4\n", argv0);
  640. printf("\n");
  641. exit(1);
  642. }
  643. int main(int argc, char **argv)
  644. {
  645. DB_ENV *env = NULL;
  646. DB *db = NULL;
  647. DBC *cursor = NULL;
  648. char *filename = NULL;
  649. DBT key = {0}, data = {0};
  650. int ret;
  651. char *find_key = NULL;
  652. uint32 entry_id = 0xffffffff;
  653. int c;
  654. while ((c = getopt(argc, argv, "f:Rl:nG:srk:K:hv")) != EOF) {
  655. switch (c) {
  656. case 'f':
  657. filename = optarg;
  658. break;
  659. case 'R':
  660. display_mode |= RAWDATA;
  661. break;
  662. case 'l':
  663. {
  664. uint32 tmpmaxbufsz = atoi(optarg);
  665. if (tmpmaxbufsz > ONEMEG) {
  666. tmpmaxbufsz = ONEMEG;
  667. printf("WARNING: max length of dumped id list too long, "
  668. "reduced to %d\n", tmpmaxbufsz);
  669. } else if (tmpmaxbufsz < MIN_BUFFER * 2) {
  670. tmpmaxbufsz = MIN_BUFFER * 2;
  671. printf("WARNING: max length of dumped id list too short, "
  672. "increased to %d\n", tmpmaxbufsz);
  673. }
  674. MAX_BUFFER = tmpmaxbufsz;
  675. break;
  676. }
  677. case 'n':
  678. display_mode |= SHOWCOUNT;
  679. break;
  680. case 'G':
  681. min_display = atoi(optarg)+1;
  682. break;
  683. case 'r':
  684. display_mode |= SHOWDATA;
  685. break;
  686. case 's':
  687. display_mode |= SHOWSUMMARY;
  688. break;
  689. case 'k':
  690. find_key = optarg;
  691. break;
  692. case 'K':
  693. id_internal_to_stored((ID)atoi(optarg), (char *)&entry_id);
  694. break;
  695. case 'h':
  696. default:
  697. usage(argv[0]);
  698. }
  699. }
  700. if(filename == NULL) {
  701. usage(argv[0]);
  702. }
  703. if (NULL != strstr(filename, "id2entry.db")) {
  704. file_type |= ENTRYTYPE;
  705. } else if (is_changelog(filename)) {
  706. file_type |= CHANGELOGTYPE;
  707. } else {
  708. file_type |= INDEXTYPE;
  709. if (0 == strncmp(filename, "vlv#", 4)) {
  710. file_type |= VLVINDEXTYPE;
  711. }
  712. }
  713. ret = db_env_create(&env, 0);
  714. if (ret != 0) {
  715. printf("Can't create dbenv: %s\n", db_strerror(ret));
  716. exit(1);
  717. }
  718. ret = env->open(env, NULL, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0);
  719. if (ret != 0) {
  720. printf("Can't open dbenv: %s\n", db_strerror(ret));
  721. exit(1);
  722. }
  723. ret = db_create(&db, env, 0);
  724. if (ret != 0) {
  725. printf("Can't create db handle: %d\n", ret);
  726. exit(1);
  727. }
  728. ret = db->open(db, NULL, filename, NULL, DB_UNKNOWN, DB_RDONLY, 0);
  729. if (ret != 0) {
  730. printf("Can't open db file '%s': %s\n", filename, db_strerror(ret));
  731. exit(1);
  732. }
  733. /* cursor through the db */
  734. ret = db->cursor(db, NULL, &cursor, 0);
  735. if (ret != 0) {
  736. printf("Can't create db cursor: %s\n", db_strerror(ret));
  737. exit(1);
  738. }
  739. ret = cursor->c_get(cursor, &key, &data, DB_FIRST);
  740. if (ret == DB_NOTFOUND) {
  741. printf("Empty database!\n");
  742. exit(0);
  743. }
  744. if (ret != 0) {
  745. printf("Can't get first cursor: %s\n", db_strerror(ret));
  746. exit(1);
  747. }
  748. if (find_key) {
  749. key.size = strlen(find_key)+1;
  750. key.data = find_key;
  751. ret = db->get(db, NULL, &key, &data, 0);
  752. if (ret != 0) {
  753. /* could be a key that doesn't have the trailing null? */
  754. key.size--;
  755. ret = db->get(db, NULL, &key, &data, 0);
  756. if (ret != 0) {
  757. printf("Can't find key '%s'\n", find_key);
  758. exit(1);
  759. }
  760. }
  761. ret = cursor->c_get(cursor, &key, &data, DB_SET);
  762. if (ret != 0) {
  763. printf("Can't set cursor to returned item: %s\n",
  764. db_strerror(ret));
  765. exit(1);
  766. }
  767. do {
  768. display_item(cursor, &key, &data);
  769. ret = cursor->c_get(cursor, &key, &data, DB_NEXT_DUP);
  770. } while (0 == ret);
  771. key.size = 0;
  772. key.data = NULL;
  773. } else if (entry_id != -1) {
  774. key.size = sizeof(entry_id);
  775. key.data = &entry_id;
  776. ret = db->get(db, NULL, &key, &data, 0);
  777. if (ret != 0) {
  778. printf("Can't set cursor to returned item: %s\n",
  779. db_strerror(ret));
  780. exit(1);
  781. }
  782. display_item(cursor, &key, &data);
  783. key.size = 0;
  784. key.data = NULL;
  785. } else {
  786. while (ret == 0) {
  787. /* display */
  788. display_item(cursor, &key, &data);
  789. ret = cursor->c_get(cursor, &key, &data, DB_NEXT);
  790. if ((ret != 0) && (ret != DB_NOTFOUND)) {
  791. printf("Bizarre error: %s\n", db_strerror(ret));
  792. exit(1);
  793. }
  794. }
  795. }
  796. ret = cursor->c_close(cursor);
  797. if (ret != 0) {
  798. printf("Can't close the cursor (?!): %s\n", db_strerror(ret));
  799. exit(1);
  800. }
  801. ret = db->close(db, 0);
  802. if (ret != 0) {
  803. printf("Unable to close db file: %s\n", db_strerror(ret));
  804. exit(1);
  805. }
  806. if ( display_mode & SHOWSUMMARY) {
  807. if ( allids_cnt > 0 ) {
  808. printf("Index keys that reached ALLIDs threshold: %ld\n", allids_cnt);
  809. }
  810. if ( pres_cnt > 0 ) {
  811. printf("Presence index keys: %ld\n", pres_cnt);
  812. }
  813. if ( eq_cnt > 0 ) {
  814. printf("Equality index keys: %ld\n", eq_cnt);
  815. }
  816. if ( app_cnt > 0 ) {
  817. printf("Approximate index keys: %ld\n", app_cnt);
  818. }
  819. if ( sub_cnt > 0 ) {
  820. printf("Substring index keys: %ld\n", sub_cnt);
  821. }
  822. if ( match_cnt > 0 ) {
  823. printf("Match index keys: %ld\n", match_cnt);
  824. }
  825. if ( ind_cnt > 0 ) {
  826. printf("Indirect index keys: %ld\n", ind_cnt);
  827. }
  828. if ( other_cnt > 0 ) {
  829. printf("This file contains %ld number of unknown type ( possible corruption)\n",other_cnt);
  830. }
  831. }
  832. ret = env->close(env, 0);
  833. if (ret != 0) {
  834. printf("Unable to shutdown libdb: %s\n", db_strerror(ret));
  835. exit(1);
  836. }
  837. return 0;
  838. }