mrclean.c 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * COMPONENT_NAME: austext
  25. *
  26. * FUNCTIONS: TERMINATE_LINE
  27. * copy_new_d99
  28. * copy_old_d2x_to_new
  29. * end_of_job
  30. * main
  31. * open_all_files
  32. * print_progress
  33. * print_usage
  34. * read_d2x
  35. * signal_shutdown
  36. * user_args_processor
  37. * validation_error
  38. * write_d2x
  39. *
  40. * ORIGINS: 27
  41. *
  42. * IBM CONFIDENTIAL -- (IBM Confidential Restricted when
  43. * combined with the aggregated modules for this product)
  44. * OBJECT CODE ONLY SOURCE MATERIALS
  45. *
  46. * (C) COPYRIGHT International Business Machines Corp. 1995
  47. * All Rights Reserved
  48. * US Government Users Restricted Rights - Use, duplication or
  49. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  50. */
  51. /*************************** MRCLEAN.C ****************************
  52. * $TOG: mrclean.c /main/7 1998/04/17 11:25:42 mgreess $
  53. * Does garbage collection (ie compression) of .d99 file.
  54. * Optionally verifies all database addresses in d99.
  55. * Modification of clndtbs.c and checkd99.c.
  56. * Does NOT use austext engine so this must be modified if schema changes.
  57. *
  58. * INPUT FORMAT:
  59. * All command input is on command line. Reads existing d2x and d99 files.
  60. *
  61. * OUTPUT FORMAT:
  62. * New .d2x and .d99 files are placed into the directory specified by user.
  63. *
  64. * EXIT CODE STANDARDS:
  65. * 0 = normal.
  66. * 1 = warnings, but output should be ok.
  67. * 2 = failure in cmd line parse or other initialization; job never started.
  68. * 3 - 49 = fatal error, but output may be acceptable.
  69. * 50 - 99 = fatal error and output files are probably unusable.
  70. * (In this program, even input may be corrupted).
  71. * 100+ = aborting due to asynchronous interrupt signal.
  72. * Output files may or may not be unusable.
  73. *
  74. * $Log$
  75. * Revision 1.11 1995/09/05 18:16:46 miker
  76. * Name, msg, and other minor changes for DtSearch..
  77. * Print messages if austext_dopen() fails.
  78. *
  79. * Revision 1.10 1995/06/02 15:52:42 miker
  80. * Cleaned up -m and bit vector overflow msgs.
  81. *
  82. * Revision 1.9 1995/05/30 19:15:58 miker
  83. * Print beta char in startup banner msg.
  84. * Remove -m option and max_totrecs; select bit vector
  85. * size from maxdba, not reccount.
  86. */
  87. #include "SearchP.h"
  88. #include <stdlib.h>
  89. #include <ctype.h>
  90. #include <string.h>
  91. #include <errno.h>
  92. #include <signal.h>
  93. #include <sys/stat.h>
  94. #include "vista.h"
  95. #define XOS_USE_NO_LOCKING
  96. #define X_INCLUDE_TIME_H
  97. #include <X11/Xos_r.h>
  98. #define MS_misc 1 /* msg catalog set number */
  99. #define DISCARD_FORMAT "%s\t\"%s\"\t%s\t%s\n" /* copied from oe.h */
  100. #define RECS_PER_DOT 1000L
  101. #define DOTS_PER_MSG 50L
  102. #define DISK_BLKSIZE 512
  103. #define MAX_CORRUPTION 100L
  104. #define MAX_REC_READ (DISK_BLKSIZE / sizeof(DB_ADDR))
  105. /* Max number of addresses to be read from
  106. * database addresses file, ie the size
  107. * of one block read from hard disk.
  108. */
  109. #define PROGNAME "MRCLEAN"
  110. #define READBUFSIZE (1024 + 32)
  111. #define SHOW_NOTHING 0 /* bit arguments for end_of_job() */
  112. #define SHOW_USAGE 1
  113. #define SHOW_EXITCODE 2
  114. #define SHOW_PROGRESS 4
  115. #define TERMINATE_LINE() if(need_linefeed){fputc('\n',aa_stderr);need_linefeed=FALSE;}
  116. /*-------------------------- GLOBALS ----------------------------*/
  117. static char *arg_dbname = NULL;
  118. static char *arg_newpath = NULL;
  119. long batch_size = 0; /* (to fileman.c) */
  120. int beta =
  121. #ifdef BETA
  122. BETA;
  123. #else
  124. 0;
  125. #endif
  126. char betabuf[8];
  127. unsigned char *bit_vector = NULL;
  128. static size_t bytes_in = 0L;
  129. static size_t corruption_count = 0L;
  130. static struct or_swordrec
  131. d21new, d21old;
  132. static struct or_lwordrec
  133. d22new, d22old;
  134. static struct or_hwordrec
  135. d23new, d23old;
  136. static char datestr [32] = ""; /* "1946/04/17 13:03" */
  137. static int debug_mode = FALSE;
  138. static size_t dot_count = 0L;
  139. char fname_d99_new [1024];
  140. char fname_d99_old [1024];
  141. FILE *fp_d99_new = NULL;
  142. FILE *fp_d99_old = NULL;
  143. static FILE *frecids = NULL;
  144. static int is_valid_dba;
  145. static size_t max_corruption = MAX_CORRUPTION;
  146. /***static long max_totrecs = 0L;****/
  147. static int normal_exitcode = 0;
  148. static int need_linefeed = FALSE;
  149. static int overlay_no = FALSE;
  150. static int overlay_yes = FALSE;
  151. static size_t reccount = 0L;
  152. static short recslots;
  153. static int dba_offset;
  154. static size_t recs_per_dot = RECS_PER_DOT;
  155. static int rewrite_reccount = FALSE;
  156. static int shutdown_now = 0; /* = FALSE */
  157. static size_t size_d21_old = 0L;
  158. static size_t size_d22_old = 0L;
  159. static size_t size_d23_old = 0L;
  160. static size_t size_d99_old = 0L;
  161. static time_t timestart = 0L;
  162. static long total_num_addrs = 0L;
  163. static int validation_mode = FALSE;
  164. /*****************************************************************************
  165. structure words: from opera.h file (just FYI...)
  166. char word[DtSrMAXWIDTH_WORD] - unique word.
  167. long word_offset - offset in a database addresses file for
  168. a given word. the first address starts
  169. at this position.
  170. int num_free_slots - number of free slots in a database
  171. addresses file for a given word.
  172. long number_of_addrs - total number of addresses for a given
  173. word.
  174. *****************************************************************************/
  175. /********************************************************/
  176. /* */
  177. /* signal_shutdown */
  178. /* */
  179. /********************************************************/
  180. /* interrupt handler for SIGINT */
  181. static void signal_shutdown (int sig)
  182. {
  183. shutdown_now = 100 + sig;
  184. return;
  185. } /* signal_shutdown() */
  186. /************************************************/
  187. /* */
  188. /* print_usage */
  189. /* */
  190. /************************************************/
  191. /* Prints usage statement to stderr. */
  192. static void print_usage (void)
  193. {
  194. fprintf (aa_stderr,
  195. "\nUSAGE: %s [options] dbname newpath\n"
  196. " Compresses unused d99 space and validates d00-d99 links.\n"
  197. " dbname: 1 - 8 char database name = the old d99/d2x files to be updated.\n"
  198. " Files found in local directory or DBFPATH environment variable.\n"
  199. " newpath: Specifies where the new d99/d2x files will be placed.\n"
  200. " If first char is not slash, path is relative to local directory.\n"
  201. "OPTIONS:\n"
  202. " -pN: Progress dots printed every N records (default %lu).\n"
  203. " Complete progress message printed every %d dots.\n"
  204. " -oy: Authorizes overlaying preexisting d99/d2x files in newpath.\n"
  205. " -on: Forces exit if preexisting d99/d2x files in newpath.\n"
  206. " -v: Validates d99 and d00 links, uncorrupts d99 file, and ensures\n"
  207. " accurate record count. Also use -c0 to uncorrupt entire database.\n"
  208. " -v<fname>: Same as -v but also writes all d00 recs unreferenced by d99\n"
  209. " to fname in format suitable for albeniz to extract into fzk format.\n"
  210. /********
  211. " -mN: Changes max # database documents from curr count in database to N.\n"
  212. *********/
  213. " -cN: Exits if more than N corrupted/incomplete links (default %d).\n"
  214. " Corruption limit turned off by -c0.\n"
  215. "EXIT CODES:\n"
  216. " 0: Complete success. 1: Warning. 2: Job never started.\n"
  217. " 3-49: Job ended prematurely, old files ok, new files unusable.\n"
  218. " 50-99: Fatal Error, even old database may be corrupted.\n"
  219. " 100+: Ctrl-C, kill, and all other signal interrupts cause premature\n"
  220. " end, new files may be unusable. Signal = exit code - 100.\n"
  221. , aa_argv0, RECS_PER_DOT, DOTS_PER_MSG, MAX_CORRUPTION);
  222. return;
  223. } /* print_usage() */
  224. /************************************************/
  225. /* */
  226. /* print_progress */
  227. /* */
  228. /************************************************/
  229. /* Prints progress msg after dots or at end of job.
  230. * Label is "Final" or "Progress".
  231. */
  232. static void print_progress (char *label)
  233. {
  234. long seconds;
  235. int compression;
  236. seconds = time(NULL) - timestart; /* total seconds elapsed */
  237. if (seconds < 0L)
  238. seconds = 0L;
  239. if ((float) bytes_in / (float) size_d99_old >= 99.5)
  240. compression = 100;
  241. else
  242. {
  243. compression = (int) (100. * (float) bytes_in / (float) size_d99_old);
  244. if (compression < 0 || compression > 100)
  245. compression = 0;
  246. }
  247. TERMINATE_LINE();
  248. fprintf (aa_stderr,
  249. "%s: %s Compression %d%% (about %lu KB) in %ld:%02ld min:sec.\n",
  250. aa_argv0, label, compression, bytes_in / 1000L,
  251. seconds / 60UL, seconds % 60UL);
  252. if (*label == 'F')
  253. fprintf (aa_stderr, "%s: Counted %ld WORDS in %s.d99.\n",
  254. aa_argv0, reccount, arg_dbname);
  255. return;
  256. } /* print_progress() */
  257. /************************************************/
  258. /* */
  259. /* end_of_job */
  260. /* */
  261. /************************************************/
  262. /* Exits program. Prints status messages before going down.
  263. * Should be called on even record boundaries whenever possible,
  264. * ie after record writes complete and shutdown_now > 0 (TRUE).
  265. */
  266. static void end_of_job (int exitcode, int show_flags)
  267. {
  268. TERMINATE_LINE();
  269. if (exitcode >= 100)
  270. {
  271. fprintf (aa_stderr, PROGNAME"66 Aborting after interrupt signal %d.\n",
  272. exitcode - 100);
  273. }
  274. if (validation_mode && corruption_count == 0L)
  275. fprintf (aa_stderr, "%s: No corrupted links detected.\n", aa_argv0);
  276. if (corruption_count > 0L)
  277. {
  278. if (max_corruption > 0L && corruption_count >= max_corruption)
  279. fprintf (aa_stderr, PROGNAME"193 Aborting at %ld corrupted links.\n",
  280. corruption_count);
  281. else
  282. fprintf (aa_stderr, PROGNAME"194 "
  283. "Detected%s %ld corrupted/incomplete link(s).\n",
  284. (validation_mode)? " and corrected" : "",
  285. corruption_count);
  286. }
  287. if (show_flags & SHOW_PROGRESS)
  288. {
  289. print_progress ("Final");
  290. }
  291. if (show_flags & SHOW_USAGE)
  292. print_usage();
  293. if (show_flags & SHOW_EXITCODE)
  294. fprintf (aa_stderr, "%s: Exit code = %d.\n", aa_argv0, exitcode);
  295. DtSearchExit (exitcode);
  296. } /* end_of_job() */
  297. /************************************************/
  298. /* */
  299. /* user_args_processor() */
  300. /* */
  301. /************************************************/
  302. /* Reads and verifies users command line arguments and
  303. * converts them into internal switches and variables.
  304. * Some attempt is made to read as many errors as possible
  305. * before ending job for bad arguments.
  306. */
  307. static void user_args_processor (int argc, char **argv)
  308. {
  309. char *argptr;
  310. int oops = FALSE;
  311. int i;
  312. time_t stamp;
  313. size_t tempsize;
  314. if (argc < 3) end_of_job (2, SHOW_USAGE);
  315. /* parse all args that begin with a dash (-) */
  316. while (--argc > 0)
  317. {
  318. argv++;
  319. argptr = argv[0];
  320. if (argptr[0] != '-') break;
  321. switch (tolower(argptr[1]))
  322. {
  323. case 'r':
  324. if (strcmp(argptr, "-russell") == 0) /* backdoor debug */
  325. debug_mode = TRUE;
  326. else goto UNKNOWN_ARG;
  327. case 'm':
  328. fprintf (aa_stderr,
  329. PROGNAME"301 The -m argument is no longer necessary.\n");
  330. break;
  331. case 'o':
  332. i = tolower (argptr[2]);
  333. if (i == 'n') overlay_no = TRUE;
  334. else if (i == 'y') overlay_yes = TRUE;
  335. else
  336. {
  337. INVALID_ARG:
  338. fprintf (aa_stderr,
  339. PROGNAME"177 Invalid %.2s argument.\n", argptr);
  340. oops = TRUE;
  341. }
  342. break;
  343. case 'v':
  344. validation_mode = TRUE;
  345. if (argptr[2] != '\0')
  346. {
  347. _Xltimeparams localtime_buf;
  348. struct tm *time_ptr;
  349. if ((frecids = fopen (argptr+2, "w")) == NULL)
  350. {
  351. fprintf (aa_stderr, PROGNAME"802 Unable to open '%s' "
  352. "to output unreferenced d00 records: %s\n",
  353. argptr, strerror(errno));
  354. oops = TRUE;
  355. }
  356. time (&stamp);
  357. time_ptr = _XLocaltime(&stamp, localtime_buf);
  358. strftime (datestr, sizeof(datestr),
  359. "%Y/%m/%d %H:%M", time_ptr);
  360. }
  361. break;
  362. case 'p':
  363. recs_per_dot = atol (argptr + 2);
  364. if (recs_per_dot <= 0L) goto INVALID_ARG;
  365. break;
  366. case 'c':
  367. tempsize = atol (argptr + 2);
  368. if (tempsize < 0L) goto INVALID_ARG;
  369. max_corruption = tempsize;
  370. break;
  371. UNKNOWN_ARG:
  372. default:
  373. fprintf (aa_stderr, PROGNAME"159 Unknown argument: '%s'.\n", argptr);
  374. oops = TRUE;
  375. break;
  376. } /* end switch */
  377. } /* end parse of cmd line args */
  378. /* Test how we broke loop.
  379. * There should still be 2 args past the ones
  380. * beginning with a dash: dbname and newpath.
  381. */
  382. if (argc != 2)
  383. {
  384. if (argc <= 0)
  385. fputs (PROGNAME"210 Missing required dbname argument.\n", aa_stderr);
  386. if (argc <= 1)
  387. fputs (PROGNAME"211 Missing required newpath argument.\n", aa_stderr);
  388. if (argc > 2)
  389. fputs (PROGNAME"212 Too many arguments.\n", aa_stderr);
  390. oops = TRUE;
  391. }
  392. if (oops) end_of_job (2, SHOW_USAGE);
  393. /* DBNAME */
  394. arg_dbname = argv[0];
  395. if (strlen(arg_dbname) > 8)
  396. {
  397. fprintf (aa_stderr,
  398. PROGNAME"229 Invalid database name '%s'.\n", arg_dbname);
  399. end_of_job (2, SHOW_USAGE);
  400. }
  401. /* NEWPATH:
  402. * Oldpath and newpath are validated when the files
  403. * are copied and the database is opened.
  404. */
  405. arg_newpath = argv[1];
  406. return;
  407. } /* user_args_processor() */
  408. /************************************************/
  409. /* */
  410. /* validation_error() */
  411. /* */
  412. /************************************************/
  413. /* Subroutine of validation_mode in main().
  414. * Prints d2x and d99 data at location of error.
  415. * Adjusts d2x counts for number of good addrs and free slots.
  416. */
  417. static void validation_error (DB_ADDR dbaorig)
  418. {
  419. DB_ADDR slot;
  420. is_valid_dba = FALSE;
  421. slot = dbaorig >> 8;
  422. /* now retranslate back to real dba */
  423. if (dbaorig != -1)
  424. slot = ((slot + 1) * recslots - dba_offset)
  425. | (OR_D00 << 24);
  426. fprintf (aa_stderr,
  427. " DBA = %d:%ld (x%02x:%06lx), orig addr val = x%08lx\n"
  428. " Word='%c%s' offset=%ld addrs=%ld free=%d\n",
  429. OR_D00, slot, OR_D00, slot, dbaorig,
  430. (!isgraph(d23old.or_hwordkey[0]))? '^' : d23old.or_hwordkey[0],
  431. d23old.or_hwordkey+1, d23old.or_hwoffset,
  432. d23old.or_hwaddrs, d23old.or_hwfree);
  433. if (--d23new.or_hwaddrs < 0L) d23new.or_hwaddrs = 0L;
  434. /* (should never occur) */
  435. d23new.or_hwfree++;
  436. return;
  437. } /* validation_error() */
  438. /************************************************/
  439. /* */
  440. /* open_all_files */
  441. /* */
  442. /************************************************/
  443. static void open_all_files
  444. (FILE **fp, char *fname, char *mode, size_t *size, int *oops)
  445. {
  446. struct stat fstatbuf;
  447. if ((*fp = fopen (fname, mode)) == NULL)
  448. {
  449. fprintf (aa_stderr, PROGNAME"439 Can't open %s: %s\n",
  450. fname, strerror(errno));
  451. *oops = TRUE;
  452. return;
  453. }
  454. if (fstat (fileno(*fp), &fstatbuf) == -1)
  455. {
  456. fprintf (aa_stderr, PROGNAME"440 Can't access status of %s: %s\n",
  457. fname, strerror(errno));
  458. *oops = TRUE;
  459. return;
  460. }
  461. if (size)
  462. if ((*size = fstatbuf.st_size) <= 0L)
  463. {
  464. fprintf (aa_stderr, PROGNAME"499 %s is empty.\n", fname);
  465. *oops = TRUE;
  466. }
  467. return;
  468. } /* open_all_files() */
  469. /************************************************/
  470. /* */
  471. /* copy_old_d2x_to_new */
  472. /* */
  473. /************************************************/
  474. static void copy_old_d2x_to_new
  475. (char *fname_old, char *fname_new, FILE *fp_old, FILE *fp_new)
  476. {
  477. char readbuf [READBUFSIZE];
  478. int i, j;
  479. fprintf (aa_stderr, "%s: Copying from old d2x files to %s...\n",
  480. aa_argv0, fname_new );
  481. for (;;) /* loop ends when eof set on input stream */
  482. {
  483. errno = 0;
  484. i = fread (readbuf, 1, sizeof(readbuf), fp_old);
  485. if (errno)
  486. {
  487. fprintf (aa_stderr, PROGNAME"517 Read error on %s: %s.\n",
  488. fname_old, strerror(errno));
  489. end_of_job (3, SHOW_EXITCODE);
  490. }
  491. j = fwrite (readbuf, 1, i, fp_new);
  492. if (i != j)
  493. {
  494. fprintf (aa_stderr, PROGNAME"489 Write error on %s: %s.\n",
  495. fname_new, strerror(errno));
  496. end_of_job (3, SHOW_EXITCODE);
  497. }
  498. if (shutdown_now)
  499. end_of_job (shutdown_now, SHOW_EXITCODE);
  500. if (feof(fp_old))
  501. break;
  502. }
  503. TERMINATE_LINE();
  504. fclose (fp_old);
  505. fclose (fp_new);
  506. return;
  507. } /* copy_old_d2x_to_new() */
  508. /********************************/
  509. /* */
  510. /* read_d2x */
  511. /* */
  512. /********************************/
  513. /* Performs vista RECREAD on curr word record.
  514. * CALLER SHOULD CHECK DB_STATUS.
  515. */
  516. void read_d2x (struct or_hwordrec *glob_word, long field)
  517. {
  518. if (field == OR_SWORDKEY)
  519. {
  520. RECREAD (PROGNAME"61", &d21old, 0);
  521. if (db_status != S_OKAY)
  522. return;
  523. strncpy (glob_word->or_hwordkey, d21old.or_swordkey,
  524. DtSrMAXWIDTH_HWORD);
  525. glob_word->or_hwordkey [DtSrMAXWIDTH_HWORD-1] = 0;
  526. glob_word->or_hwoffset = d21old.or_swoffset;
  527. glob_word->or_hwfree = d21old.or_swfree;
  528. glob_word->or_hwaddrs = d21old.or_swaddrs;
  529. }
  530. else if (field == OR_LWORDKEY) {
  531. RECREAD (PROGNAME"69", &d22old, 0);
  532. if (db_status != S_OKAY)
  533. return;
  534. strncpy (glob_word->or_hwordkey, d22old.or_lwordkey,
  535. DtSrMAXWIDTH_HWORD);
  536. glob_word->or_hwordkey [DtSrMAXWIDTH_HWORD-1] = 0;
  537. glob_word->or_hwoffset = d22old.or_lwoffset;
  538. glob_word->or_hwfree = d22old.or_lwfree;
  539. glob_word->or_hwaddrs = d22old.or_lwaddrs;
  540. }
  541. else {
  542. RECREAD (PROGNAME"78", glob_word, 0);
  543. glob_word->or_hwordkey [DtSrMAXWIDTH_HWORD-1] = 0;
  544. }
  545. return;
  546. } /* read_d2x() */
  547. /********************************/
  548. /* */
  549. /* write_d2x */
  550. /* */
  551. /********************************/
  552. /* performs vista RECWRITE on curr word record.
  553. * CALLER MUST CHECK DB_STATUS.
  554. */
  555. static void write_d2x (struct or_hwordrec *glob_word, long field)
  556. {
  557. if (field == OR_SWORDKEY) {
  558. strcpy (d21new.or_swordkey, glob_word->or_hwordkey);
  559. d21new.or_swoffset = glob_word->or_hwoffset;
  560. d21new.or_swfree = glob_word->or_hwfree;
  561. d21new.or_swaddrs = glob_word->or_hwaddrs;
  562. RECWRITE (PROGNAME"102", &d21new, 0);
  563. }
  564. else if (field == OR_LWORDKEY) {
  565. strcpy (d22new.or_lwordkey, glob_word->or_hwordkey);
  566. d22new.or_lwoffset = glob_word->or_hwoffset;
  567. d22new.or_lwfree = glob_word->or_hwfree;
  568. d22new.or_lwaddrs = glob_word->or_hwaddrs;
  569. RECWRITE (PROGNAME"111", &d22new, 0);
  570. }
  571. else {
  572. RECWRITE (PROGNAME"115", glob_word, 0);
  573. }
  574. return;
  575. } /* write_d2x() */
  576. /************************************************/
  577. /* */
  578. /* copy_new_d99() */
  579. /* */
  580. /************************************************/
  581. /* The garbage collection/compression process itself.
  582. * For very large databases, there will be appx 3 million word records,
  583. * so the loop should be coded for ***EFFICIENCY***.
  584. */
  585. /* fool the read_wordstr() function by using a phony word
  586. * whose length tells the function which read to do.
  587. * This code really sucks but I don't have time to fix it.
  588. */
  589. static void copy_new_d99 (long keyfield)
  590. {
  591. int is_odd_nibble;
  592. long num_holes;
  593. long slots_left;
  594. long good_addrs_this_block;
  595. unsigned char *bvptr;
  596. int a;
  597. DB_ADDR dba, dbaorig;
  598. long x;
  599. int done;
  600. long good_addrs_left;
  601. int num_reads, num_writes;
  602. DB_ADDR word_addrs [MAX_REC_READ + 64]; /* d99 read buf */
  603. DB_ADDR word_addrs_out [MAX_REC_READ + 64]; /* d99 write buf */
  604. KEYFRST (PROGNAME"179", keyfield, 0);
  605. while (db_status == S_OKAY)
  606. {
  607. /********RECREAD (PROGNAME"182", &d02new, 0);********/
  608. read_d2x (&d23new, keyfield);
  609. if (validation_mode) /* save for validation err msgs */
  610. memcpy (&d23old, &d23new, sizeof(d23old));
  611. /****************
  612. @@@@@ START HERE NEXT
  613. @@@@@ USE OR_D2x instead of keyfiled OR_SWROD etc so we can
  614. @@@@@ correctly call validation_error()
  615. ****************/
  616. /* Read old d99 file at specified offset to get total num "holes".
  617. * In the first portion of record holes are filled with
  618. * representations of valid database addresses + statistical weights.
  619. * In the second portion the holes are "free slots" for future
  620. * expansion which are conventionally initialized with a -1.
  621. */
  622. /* force number of free slots to 0(ZERO) */
  623. d23new.or_hwfree = 0L;
  624. fseek (fp_d99_old, d23new.or_hwoffset, SEEK_SET);
  625. num_holes = d23new.or_hwaddrs + (long )d23new.or_hwfree;
  626. good_addrs_left = d23new.or_hwaddrs;
  627. bytes_in += sizeof(DB_ADDR) * num_holes;
  628. /* Update the offset in the d2x record buffer */
  629. d23new.or_hwoffset = ftell (fp_d99_new);
  630. /* Copy the array of holes in each disk block,
  631. * reading the old and writing to the new. Loop ends
  632. * when the number of holes left will fit into one last block.
  633. */
  634. done = FALSE;
  635. while (!done) /* loop on each block in this word */
  636. {
  637. if (num_holes > MAX_REC_READ)
  638. {
  639. num_reads = MAX_REC_READ;
  640. num_holes -= MAX_REC_READ;
  641. }
  642. else
  643. {
  644. done = TRUE;
  645. num_reads = num_holes;
  646. }
  647. errno = 0;
  648. fread (word_addrs, sizeof(DB_ADDR), num_reads, fp_d99_old);
  649. if (errno)
  650. {
  651. TERMINATE_LINE();
  652. fprintf (aa_stderr, PROGNAME"657 Read error on %s: %s.\n",
  653. fname_d99_old, strerror(errno));
  654. end_of_job (4, SHOW_PROGRESS + SHOW_EXITCODE);
  655. }
  656. /* Addrs on d99 are now 'record numbers' not dbas.
  657. * A rec# is what the dba/slot# would be if records
  658. * took up just one slot and there were no dbrec at
  659. * start of file. D99 rec#s start at #1, not #0.
  660. */
  661. /* If user requested validation_mode, validate each 'good' rec#
  662. * (not free slots) in word_addrs buffer. If any d99 links
  663. * are corrupt, skip them when copying to the new d99 file.
  664. * Rewrite -1's to all free slots.
  665. * ----> NOTE UNUSUAL FORMAT OF DBA HOLES IN D99! <----
  666. * Record number is shifted to the high order 3 bytes.
  667. * The statistical weight is in the low order byte.
  668. * The vista file number is known from the #define constant OR_D00,
  669. * and the vista dba/slot# is mapped from rec# by mult/div
  670. * number of slots per rec, plus/minus dbrec offset.
  671. */
  672. if (validation_mode)
  673. {
  674. /* set x to number of good addrs in this block */
  675. if (good_addrs_left > num_reads)
  676. {
  677. x = num_reads;
  678. good_addrs_left -= num_reads;
  679. }
  680. else
  681. {
  682. x = good_addrs_left;
  683. good_addrs_left = 0;
  684. }
  685. /* Validate the rec#'s in this block. Note that the loop
  686. * is skipped if the entire block is free slots.
  687. */
  688. good_addrs_this_block = 0;
  689. for (a=0; a<x; a++) /* a = index to curr dba */
  690. {
  691. /* Get rec#. Save original rec# for err msgs, then shift
  692. * slot number to lower 3 bytes, discarding weight.
  693. */
  694. dbaorig = word_addrs[a]; /* rec#,rec#,rec#:wt */
  695. dba = dbaorig >> 8; /* 0,rec#,rec#,rec# */
  696. is_valid_dba = TRUE; /* default */
  697. /* If original rec# == -1 we've overrun the good
  698. * rec#'s into the expansion area, which is filled
  699. * with -1's. This is real bad news because if
  700. * the counts in d02 are bad, the online programs
  701. * will quickly crash, and we can't continue this program.
  702. * Advance to next rec# because we can't mark the bit vector.
  703. */
  704. if (dbaorig == -1L)
  705. {
  706. TERMINATE_LINE();
  707. fprintf (aa_stderr, "*** "PROGNAME "111 DBA in d99 = -1. "
  708. "Probable overrun into expansion area\n"
  709. " due to incorrect count values in d2x file.\n");
  710. validation_error (dbaorig);
  711. corruption_count++;
  712. if (max_corruption > 0L &&
  713. corruption_count >= max_corruption)
  714. end_of_job (91, SHOW_PROGRESS + SHOW_EXITCODE);
  715. continue; /* skip the bit vector check */
  716. }
  717. /* If slot number > max totrecs, we have a
  718. * corrupted d99-d00 link because we've
  719. * already validated the d00 file and we know that
  720. * it has no slots > max. Also we have to advance
  721. * to next slot because we can't mark the bit vector.
  722. */
  723. /****** if (dba >= max_totrecs)*******/
  724. if (dba >= total_num_addrs)
  725. {
  726. TERMINATE_LINE();
  727. fprintf (aa_stderr, "*** "PROGNAME"222 "
  728. "DBA in d99 not in d00, slot > max num docs.\n");
  729. validation_error (dbaorig);
  730. corruption_count++;
  731. if (max_corruption > 0L &&
  732. corruption_count >= max_corruption)
  733. end_of_job (92, SHOW_PROGRESS + SHOW_EXITCODE);
  734. continue; /* skip the bit vector check */
  735. }
  736. /* Verify that dba exists in d00 file (test bit #1).
  737. * If not, mark bit #3 (3rd lowest) in nibble and
  738. * print error msg unless bit #3 previously marked.
  739. */
  740. bvptr = bit_vector + (dba >> 1);
  741. is_odd_nibble = (dba & 1L);
  742. if (!(*bvptr & ((is_odd_nibble)? 0x01 : 0x10))) /* bit #1 */
  743. {
  744. if (!(*bvptr & ((is_odd_nibble)? 0x04 : 0x40)))/* bit #3 */
  745. {
  746. *bvptr |= (is_odd_nibble)? 0x04 : 0x40;
  747. TERMINATE_LINE();
  748. fprintf (aa_stderr, "*** "PROGNAME"333 "
  749. "DBA in d99 does not exist in d00.\n");
  750. validation_error (dbaorig);
  751. corruption_count++;
  752. if (max_corruption > 0L &&
  753. corruption_count >= max_corruption)
  754. end_of_job (93, SHOW_PROGRESS + SHOW_EXITCODE);
  755. } /* endif where corrupt link detected */
  756. }
  757. /* Mark bit #2 in bit vector indicating a d99 reference. */
  758. *bvptr |= (is_odd_nibble)? 0x02 : 0x20; /* bit #2 */
  759. /* move good dba to curr output block, incr counter */
  760. if (is_valid_dba)
  761. word_addrs_out [good_addrs_this_block++] = dbaorig;
  762. } /* end validation loop for each good dba in the block */
  763. /* Write out only validated addrs in current block.
  764. * If this was the last block, fill out all the free slots,
  765. * if any, with -1 values, and exit the dba loop for this word.
  766. */
  767. if (good_addrs_this_block > 0L)
  768. {
  769. num_writes = fwrite (word_addrs_out, sizeof(DB_ADDR),
  770. good_addrs_this_block, fp_d99_new);
  771. if (num_writes != good_addrs_this_block) goto WRITE_ERROR;
  772. }
  773. if (good_addrs_left <= 0L)
  774. {
  775. /* Write blocks of -1s until new d2x free slot count
  776. * is exhausted. The last block may be < MAX_REC_READ.
  777. */
  778. slots_left = d23new.or_hwfree;
  779. while (slots_left > 0L)
  780. {
  781. /* set x to number of -1's to write for this block */
  782. if (slots_left > MAX_REC_READ)
  783. {
  784. x = MAX_REC_READ;
  785. slots_left -= MAX_REC_READ;
  786. }
  787. else
  788. {
  789. x = slots_left;
  790. slots_left = 0L;
  791. }
  792. for (a=0; a<x; a++) word_addrs_out[a] = -1L;
  793. num_writes = fwrite
  794. (word_addrs_out, sizeof(DB_ADDR), x, fp_d99_new);
  795. if (num_writes != x) goto WRITE_ERROR;
  796. } /* end while loop to write out all -1's */
  797. done = TRUE;
  798. }
  799. } /* endif for validation_mode for this block */
  800. /* If NOT in validation mode, just write out the new d99 block
  801. * as an exact copy of the input block.
  802. */
  803. else
  804. {
  805. num_writes =
  806. fwrite (word_addrs, sizeof(DB_ADDR), num_reads, fp_d99_new);
  807. if (num_writes != num_reads)
  808. {
  809. WRITE_ERROR:
  810. fprintf (aa_stderr, PROGNAME"665 Write error on %s: %s.\n",
  811. fname_d99_new, strerror(errno));
  812. end_of_job (4, SHOW_PROGRESS + SHOW_EXITCODE);
  813. }
  814. } /* endelse for NOT validation_mode for this block */
  815. } /* end loop for all blocks for this entire word (done = TRUE) */
  816. /* write the updated d2x record */
  817. /*****RECWRITE (PROGNAME"184", &d23new, 0);******/
  818. write_d2x (&d23new, keyfield);
  819. reccount++;
  820. /* Every now and then print a dot.
  821. * Print complete progress msg after DOTS_PER_MSG dots.
  822. */
  823. if (!(reccount % recs_per_dot))
  824. {
  825. if (++dot_count > DOTS_PER_MSG)
  826. {
  827. dot_count = 0;
  828. print_progress ("Progress");
  829. }
  830. else
  831. {
  832. fputc ('.', aa_stderr);
  833. need_linefeed = TRUE;
  834. if (!(dot_count % 10L)) fputc (' ', aa_stderr);
  835. }
  836. fflush (aa_stderr);
  837. } /* end of print-a-dot */
  838. if (shutdown_now)
  839. end_of_job (shutdown_now, SHOW_PROGRESS + SHOW_EXITCODE);
  840. KEYNEXT (PROGNAME"196", keyfield, 0);
  841. } /* end of main loop on each word in database */
  842. return;
  843. } /* copy_new_d99() */
  844. /************************************************/
  845. /* */
  846. /* main() */
  847. /* */
  848. /************************************************/
  849. int main (int argc, char *argv[])
  850. {
  851. FILE_HEADER fl_hdr;
  852. int a, i, j;
  853. unsigned char *bvptr;
  854. DB_ADDR dba, dba1, dbaorig;
  855. char dbfpath [1024];
  856. char fname_d21_new [1024];
  857. char fname_d21_old [1024];
  858. char fname_d22_new [1024];
  859. char fname_d22_old [1024];
  860. char fname_d23_new [1024];
  861. char fname_d23_old [1024];
  862. FILE *fp_d21_new = NULL;
  863. FILE *fp_d21_old = NULL;
  864. FILE *fp_d22_new = NULL;
  865. FILE *fp_d22_old = NULL;
  866. FILE *fp_d23_new = NULL;
  867. FILE *fp_d23_old = NULL;
  868. char full_dbname_old [1024];
  869. char full_dbname_new [1024];
  870. long max_bitvec = 0L;
  871. int oops;
  872. char *ptr;
  873. char readbuf [READBUFSIZE];
  874. unsigned long reads_per_dot;
  875. char recidbuf [DtSrMAX_DB_KEYSIZE + 4];
  876. time_t starttime;
  877. long x;
  878. struct or_dbrec dbrec;
  879. struct tm *time_ptr;
  880. _Xltimeparams localtime_buf;
  881. if (beta > 1)
  882. sprintf (betabuf, "%c", beta);
  883. else
  884. betabuf[0] = 0;
  885. aa_argv0 = argv[0];
  886. time (&starttime);
  887. time_ptr = _XLocaltime(&starttime, localtime_buf);
  888. strftime (dbfpath, sizeof (dbfpath), /* just use any ol' buffer */
  889. CATGETS(dtsearch_catd, MS_misc, 22, "%A, %b %d %Y, %I:%M %p"),
  890. time_ptr);
  891. printf (CATGETS(dtsearch_catd, MS_misc, 23,
  892. "%s: Version %s%s. Run %s.\n"),
  893. aa_argv0, AUSAPI_VERSION, betabuf, dbfpath);
  894. signal (SIGHUP, signal_shutdown);
  895. signal (SIGINT, signal_shutdown);
  896. signal (SIGQUIT, signal_shutdown);
  897. signal (SIGTRAP, signal_shutdown);
  898. signal (SIGABRT, signal_shutdown); /* ordinarily this causes core dump */
  899. signal (SIGKILL, signal_shutdown); /* this cannot be trapped */
  900. signal (SIGALRM, signal_shutdown);
  901. signal (SIGTERM, signal_shutdown);
  902. signal (SIGPWR, signal_shutdown);
  903. signal (SIGUSR1, signal_shutdown); /* ordinarily this "pings" OE */
  904. #ifdef _AIX
  905. signal (SIGXCPU, signal_shutdown);
  906. signal (SIGDANGER, signal_shutdown);
  907. #endif
  908. user_args_processor (argc, argv);
  909. /* In order to find old files, we have to check if
  910. * DBFPATH environment variable has been set.
  911. * Load the fully constructed DBFPATH-dbname into its own buffer.
  912. */
  913. full_dbname_old[0] = '\0';
  914. dbfpath[0] = 0;
  915. if ((ptr = getenv ("DBFPATH")) != NULL)
  916. {
  917. if (*ptr == 0)
  918. fprintf (aa_stderr,
  919. "%s: Ignoring empty DBFPATH environment variable.\n",
  920. aa_argv0);
  921. else
  922. {
  923. fprintf (aa_stderr, "%s: Using DBFPATH = '%s'.\n",
  924. aa_argv0, ptr);
  925. strcpy (full_dbname_old, ptr);
  926. /* Ensure that DBFPATH ends in a slash. */
  927. ptr = strchr (full_dbname_old, '\0');
  928. if (*(ptr-1) != LOCAL_SLASH)
  929. {
  930. *ptr++ = LOCAL_SLASH;
  931. *ptr = '\0';
  932. }
  933. strcpy (dbfpath, full_dbname_old);
  934. }
  935. }
  936. /* Currently full_dbname_old contains just the path.
  937. * Similarly, build just path name for the 2 new files
  938. * using full_dbname_new as a buffer.
  939. * Verify they don't both refer to the same directory.
  940. */
  941. strcpy (full_dbname_new, arg_newpath);
  942. ptr = strchr (full_dbname_new, '\0');
  943. if (*(ptr-1) != LOCAL_SLASH)
  944. {
  945. *ptr++ = LOCAL_SLASH;
  946. *ptr = '\0';
  947. }
  948. if (strcmp (full_dbname_old, full_dbname_new) == 0)
  949. {
  950. fprintf (aa_stderr,
  951. PROGNAME"393 Old and new directories are identical: '%s'\n.",
  952. full_dbname_old);
  953. end_of_job (2, SHOW_USAGE);
  954. }
  955. /* Complete full_dbname_old by appending dbname to the path prefix.
  956. * Then build full path/file names for all 4 files.
  957. */
  958. strcat (full_dbname_old, arg_dbname);
  959. strcat (full_dbname_new, arg_dbname);
  960. fprintf (aa_stderr, "%s: Old files: '%s.d2x, .d99'.\n",
  961. aa_argv0, full_dbname_old);
  962. fprintf (aa_stderr, "%s: New files: '%s.d2x, .d99'.\n",
  963. aa_argv0, full_dbname_new);
  964. strcat (fname_d99_old, full_dbname_old);
  965. strcat (fname_d99_old, ".d99");
  966. strcpy (fname_d21_old, full_dbname_old);
  967. strcat (fname_d21_old, ".d21");
  968. strcpy (fname_d22_old, full_dbname_old);
  969. strcat (fname_d22_old, ".d22");
  970. strcpy (fname_d23_old, full_dbname_old);
  971. strcat (fname_d23_old, ".d23");
  972. strcat (fname_d99_new, full_dbname_new);
  973. strcat (fname_d99_new, ".d99");
  974. strcpy (fname_d21_new, full_dbname_new);
  975. strcat (fname_d21_new, ".d21");
  976. strcpy (fname_d22_new, full_dbname_new);
  977. strcat (fname_d22_new, ".d22");
  978. strcpy (fname_d23_new, full_dbname_new);
  979. strcat (fname_d23_new, ".d23");
  980. /* If the user hasn't already authorized overwriting preexisting files,
  981. * check new directory and if new files already exist,
  982. * ask permission to overwrite.
  983. */
  984. if (!overlay_yes)
  985. {
  986. oops = FALSE; /* TRUE forces a user prompt */
  987. if ((fp_d99_new = fopen(fname_d99_new, "r")) != NULL)
  988. {
  989. fclose (fp_d99_new);
  990. oops = TRUE;
  991. }
  992. if ((fp_d21_new = fopen(fname_d21_new, "r")) != NULL)
  993. {
  994. fclose (fp_d21_new);
  995. oops = TRUE;
  996. }
  997. if ((fp_d22_new = fopen(fname_d22_new, "r")) != NULL)
  998. {
  999. fclose (fp_d22_new);
  1000. oops = TRUE;
  1001. }
  1002. if ((fp_d23_new = fopen(fname_d23_new, "r")) != NULL)
  1003. {
  1004. fclose (fp_d23_new);
  1005. oops = TRUE;
  1006. }
  1007. if (oops)
  1008. {
  1009. fprintf (aa_stderr, "%s: One or more new files already exist.\n",
  1010. aa_argv0);
  1011. if (overlay_no)
  1012. {
  1013. fputs (PROGNAME"463 "
  1014. "Command line argument disallows file overlay.\n",
  1015. aa_stderr);
  1016. end_of_job (2, SHOW_EXITCODE);
  1017. }
  1018. fputs (" Is it ok to overlay files in new directory? [y/n] ",
  1019. aa_stderr);
  1020. *readbuf = '\0';
  1021. fgets (readbuf, sizeof(readbuf), stdin);
  1022. if (strlen(readbuf) && readbuf[strlen(readbuf)-1] == '\n')
  1023. readbuf[strlen(readbuf)-1] = '\0';
  1024. if (tolower (*readbuf) != 'y') end_of_job (2, SHOW_NOTHING);
  1025. }
  1026. } /* end of check for overlaying new files */
  1027. /* Open all files. The d2x's are opened so that the old ones
  1028. * can be copied into the new directory before starting
  1029. * the garbage collection process proper.
  1030. * The d99's are opened now just to verify permissions.
  1031. */
  1032. oops = FALSE; /* TRUE ends job, but only after trying all 4 files */
  1033. open_all_files (&fp_d21_old, fname_d21_old, "rb", &size_d21_old, &oops);
  1034. open_all_files (&fp_d22_old, fname_d22_old, "rb", &size_d22_old, &oops);
  1035. open_all_files (&fp_d23_old, fname_d23_old, "rb", &size_d23_old, &oops);
  1036. open_all_files (&fp_d99_old, fname_d99_old, "rb", &size_d99_old, &oops);
  1037. open_all_files (&fp_d21_new, fname_d21_new, "wb", NULL, &oops);
  1038. open_all_files (&fp_d22_new, fname_d22_new, "wb", NULL, &oops);
  1039. open_all_files (&fp_d23_new, fname_d23_new, "wb", NULL, &oops);
  1040. open_all_files (&fp_d99_new, fname_d99_new, "wb", NULL, &oops);
  1041. if (shutdown_now)
  1042. end_of_job (shutdown_now, SHOW_EXITCODE);
  1043. if (oops)
  1044. end_of_job (2, SHOW_EXITCODE);
  1045. /* Copy old d2x files to new directory.
  1046. * Database will open using new files so only they will be changed.
  1047. */
  1048. copy_old_d2x_to_new (fname_d21_old, fname_d21_new, fp_d21_old, fp_d21_new);
  1049. copy_old_d2x_to_new (fname_d22_old, fname_d22_new, fp_d22_old, fp_d22_new);
  1050. copy_old_d2x_to_new (fname_d23_old, fname_d23_new, fp_d23_old, fp_d23_new);
  1051. /* Open database, but use new d02 file for updates. */
  1052. if (!austext_dopen (arg_dbname, (dbfpath[0] == 0)? NULL : dbfpath,
  1053. arg_newpath, 0, &dbrec))
  1054. {
  1055. puts (DtSearchGetMessages());
  1056. end_of_job (3, SHOW_EXITCODE);
  1057. }
  1058. /* Use the number of records in the dbrec, unless
  1059. * user specified a larger number on command line.
  1060. * Get other constants from dbrec.
  1061. */
  1062. /********************
  1063. if (max_totrecs == 0)
  1064. {
  1065. max_totrecs = dbrec.or_reccount + 24;
  1066. fprintf (aa_stderr,
  1067. "%s: %ld records in database. Using this as default for -m.\n",
  1068. aa_argv0, dbrec.or_reccount);
  1069. }
  1070. **********************/
  1071. /* this is where real dba was changed to record number (still called dba) */
  1072. RECFRST (PROGNAME"1067", OR_OBJREC, 0);
  1073. CRGET (PROGNAME"1068", &dba, 0); /* dba of first real obj record */
  1074. recslots = dbrec.or_recslots; /* vista slots per obj record */
  1075. dba_offset = recslots - (dba & 0xffffff); /* accounts for dbrec */
  1076. /* total_num_addrs = what reccount would be if
  1077. * all holes were filled with good records.
  1078. */
  1079. total_num_addrs = (dbrec.or_maxdba - (dba & 0xffffff) + 1) / recslots + 1;
  1080. fprintf (aa_stderr,
  1081. "%s: curr reccnt=%ld, mxdba=%ld, sl/rec=%ld, tot#adr=%ld.\n",
  1082. aa_argv0, dbrec.or_reccount, dbrec.or_maxdba,
  1083. dbrec.or_recslots, total_num_addrs);
  1084. /* Initialize validation_mode (checkd99) */
  1085. if (validation_mode)
  1086. {
  1087. /* Allocate and initialize a bit vector:
  1088. * 4 bits for every possible d00 database address.
  1089. */
  1090. max_bitvec = (total_num_addrs >> 1) + 2;
  1091. if ((bit_vector = malloc (max_bitvec + 64L)) == NULL)
  1092. {
  1093. fprintf (aa_stderr, PROGNAME"465 WARNING: "
  1094. "Can't allocate memory for bit vector. "
  1095. "'Validate' mode switched off.\n");
  1096. validation_mode = FALSE;
  1097. normal_exitcode = 1; /* warning */
  1098. goto EXIT_INIT_VALIDATION;
  1099. }
  1100. memset (bit_vector, 0, max_bitvec);
  1101. /* Read every d00 rec sequentially. 1 in bit #1 (lowest order)
  1102. * in bit vector means record (dba) exists in d00 file.
  1103. * While we're at it, count the total number of records.
  1104. */
  1105. x = dbrec.or_reccount / 50L + 1; /* x = recs per dot */
  1106. fprintf (aa_stderr,
  1107. "%s: Reading d00 file. Each dot appx %ld database documents...\n",
  1108. aa_argv0, x);
  1109. reccount = 0L;
  1110. dot_count = 0L;
  1111. RECFRST (PROGNAME"534", OR_OBJREC, 0);
  1112. while (db_status == S_OKAY)
  1113. {
  1114. CRREAD (PROGNAME"617", OR_OBJKEY, recidbuf, 0);
  1115. /* print periodic progress dots */
  1116. if (!(++reccount % x))
  1117. {
  1118. fputc ('.', aa_stderr);
  1119. need_linefeed = TRUE;
  1120. if (!(++dot_count % 10L)) fputc (' ', aa_stderr);
  1121. fflush (aa_stderr);
  1122. }
  1123. /* Get dba and record number and confirm
  1124. * it will not overflow bit vector.
  1125. */
  1126. CRGET (PROGNAME"537", &dba, 0);
  1127. dba &= 0x00ffffff; /* mask out file number in high order byte */
  1128. dba1 = (dba + dba_offset) / recslots; /* = "rec number", base 1 */
  1129. /***** if (dba1 >= max_totrecs)*****/
  1130. if (dba1 >= total_num_addrs)
  1131. {
  1132. TERMINATE_LINE();
  1133. fprintf (aa_stderr, PROGNAME"561 "
  1134. "DBA '%d:%ld' (rec #%ld) in d00 exceeds total num addrs %ld;\n"
  1135. " Bit vector overflow because maxdba %ld"
  1136. " in dbrec is incorrect.\n",
  1137. /****** OR_D00, dba, dba1, max_totrecs);******/
  1138. OR_D00, dba, dba1, total_num_addrs, dbrec.or_maxdba);
  1139. end_of_job (7, SHOW_EXITCODE);
  1140. }
  1141. if (shutdown_now)
  1142. end_of_job (shutdown_now, SHOW_EXITCODE);
  1143. /* Set bit #1 of even or odd nibble to indicate that
  1144. * this record *number* actually exists in d00 file.
  1145. */
  1146. bit_vector[dba1>>1] |= (dba1 & 1L)? 0x01 : 0x10;
  1147. RECNEXT (PROGNAME"541", 0);
  1148. } /* end of sequential read thru d00 file */
  1149. TERMINATE_LINE(); /* end the dots... */
  1150. /* confirm that RECCOUNT record holds the correct number */
  1151. if (dbrec.or_reccount == reccount)
  1152. {
  1153. fprintf (aa_stderr,
  1154. "%s: Confirmed %ld DOCUMENTS in %s.d00.\n",
  1155. aa_argv0, dbrec.or_reccount, arg_dbname);
  1156. }
  1157. else
  1158. {
  1159. fprintf (aa_stderr,
  1160. "%s: %ld DOCUMENTS actually in %s.d00 not ="
  1161. " %ld count stored there.\n"
  1162. " Count will be corrected in new d00 file.\n",
  1163. aa_argv0, reccount, arg_dbname, dbrec.or_reccount);
  1164. dbrec.or_reccount = reccount;
  1165. rewrite_reccount = TRUE;
  1166. }
  1167. EXIT_INIT_VALIDATION: ;
  1168. } /* end of validation_mode initialization */
  1169. /* initialize main loop */
  1170. time (&timestart);
  1171. reccount = 0L;
  1172. bytes_in = 0L;
  1173. dot_count = DOTS_PER_MSG; /* force initial msg after first blk of recs */
  1174. TERMINATE_LINE();
  1175. fprintf (aa_stderr, "%s: Compressing into %s. Each dot appx %lu words...\n",
  1176. aa_argv0, arg_newpath, recs_per_dot);
  1177. /* write New Header Information to a new d99 file */
  1178. init_header(fp_d99_new, &fl_hdr);
  1179. /* Sequentially read each word key file in big loop.
  1180. * For each word, read the d99.
  1181. * In validation mode check the dbas.
  1182. * If not validating, just blindly rewrite the old d99 to the new one.
  1183. * If validating only write good dba's and mark the bit vector.
  1184. */
  1185. copy_new_d99 (OR_SWORDKEY);
  1186. copy_new_d99 (OR_LWORDKEY);
  1187. copy_new_d99 (OR_HWORDKEY);
  1188. if (reccount == 0L)
  1189. end_of_job (50, SHOW_PROGRESS + SHOW_EXITCODE);
  1190. else
  1191. print_progress ("Final");
  1192. /* If validation_mode requested, traverse bit vector and print out
  1193. * table of each d00 record which cannot be accessed from any d99 word.
  1194. * If a validation file name was provided, write out a line for each
  1195. * bad reecord in alebeniz-compatible format.
  1196. */
  1197. if (validation_mode)
  1198. {
  1199. for (x=0L, bvptr = bit_vector; x<max_bitvec; x++, bvptr++)
  1200. {
  1201. for (j=0; j<8; j+=4) /* j = 0 or 4, amount of bit shift */
  1202. {
  1203. /* a = bits #1 and #2 of current nibble */
  1204. a = 0x30 & (*bvptr << j);
  1205. /* if dba is in d00 but not in d99... */
  1206. if (a & 0x10 && !(a & 0x20))
  1207. {
  1208. /* ...construct valid vista dba */
  1209. dbaorig = x << 1;
  1210. if (j) dbaorig++; /* slot number */
  1211. /*** dba = dbaorig | (OR_D00 << 24); ***/ /* real dba */
  1212. /* now retranslate back to real dba */
  1213. dba = ((dbaorig + 1) * recslots - dba_offset)
  1214. | (OR_D00 << 24);
  1215. /* ...print out err msg */
  1216. /***printf("DBAORIG = %ld DBA = %ld\n", dbaorig, dba);***/
  1217. CRSET (PROGNAME"734", &dba, 0);
  1218. CRREAD (PROGNAME"735", OR_OBJKEY, readbuf, 0);
  1219. fprintf (aa_stderr, "*** "PROGNAME"444 "
  1220. "d00 record '%s' is not referenced in d99.\n"
  1221. " DBA = %d:%ld (x%02x:%06lx).\n",
  1222. readbuf, OR_D00, dba, OR_D00, dba);
  1223. /***readbuf, OR_D00, dbaorig, OR_D00, dbaorig);****/
  1224. /* ...if albeniz compatible output requested, do it */
  1225. if (frecids)
  1226. {
  1227. fprintf (frecids, DISCARD_FORMAT, arg_dbname,
  1228. readbuf, "MrClean", datestr);
  1229. }
  1230. corruption_count++;
  1231. if (max_corruption > 0L && corruption_count >= max_corruption)
  1232. end_of_job (94, SHOW_EXITCODE);
  1233. } /* endif where d00 is not referenced by d99 */
  1234. } /* end forloop: every 2 bits in a bitvector byte */
  1235. } /* end forloop: every byte in bitvector */
  1236. }
  1237. /* Normal_exitcode currently will contain either a 0 or a 1.
  1238. * If we were uncorrupting the d99 and found any corrupt links,
  1239. * make sure it's 1 (warning). If there were corrupt links and
  1240. * we weren't trying to uncorrupt it, change it to a hard error.
  1241. */
  1242. /***@@@@ by the way, corruption_count can be > 0 only if in validation_mode */
  1243. if (corruption_count > 0L)
  1244. {
  1245. if (validation_mode)
  1246. normal_exitcode = 1;
  1247. else
  1248. normal_exitcode = 90;
  1249. }
  1250. end_of_job (normal_exitcode, SHOW_EXITCODE);
  1251. } /* main() */
  1252. /*************************** MRCLEAN.C ****************************/