ttdbck.C 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
  24. //%% (c) Copyright 1993, 1994 International Business Machines Corp.
  25. //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  26. //%% (c) Copyright 1993, 1994 Novell, Inc.
  27. //%% $XConsortium: ttdbck.C /main/3 1995/10/20 16:34:00 rswiston $
  28. /*
  29. *
  30. * ttdbck.cc
  31. * @(#)ttdbck.C 1.31 93/09/07
  32. *
  33. * ToolTalk 1.0 spec data base inspect and repair tool
  34. *
  35. * Copyright (c) 1990 by Sun Microsystems, Inc.
  36. */
  37. #include <stddef.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <isam.h>
  41. #include <locale.h>
  42. #include <memory.h>
  43. #include "util/tt_port.h"
  44. #include "util/tt_gettext.h"
  45. #include "util/tt_global_env.h"
  46. #include "ttdbck.h"
  47. #include "dbck.h"
  48. #include "options_tt.h"
  49. #include "binkey.h"
  50. #include "spec.h"
  51. #include "util/copyright.h"
  52. #include "dm/dm_recfmts.h"
  53. #include "mp/mp_mp.h"
  54. #include "mp_s_mp.h"
  55. #include "tt_db_server_consts.h"
  56. #include "tt_isstrerror.h"
  57. TT_INSERT_COPYRIGHT
  58. #ifdef OPT_PATCH
  59. static char PatchID[] = "Patch Id: 100626_03.";
  60. static int Patch_ID100626_03;
  61. #endif
  62. char *progname; // from argv[0]
  63. Dbck_specoptions *opts;
  64. _Tt_typedb_ptr *tdb_ptr;
  65. FILE *tstream; // for calling print() methods in dbx
  66. // Global variables controlling state of main merge loop.
  67. Table_oid_prop oid_prop_record;
  68. Table_oid_access oid_access_record;
  69. Table_oid_container oid_container_record;
  70. Table_docoid_path docoid_path_record;
  71. struct keydesc docoid_path_keydesc;
  72. int oid_prop_fd, oid_access_fd, oid_container_fd, docoid_path_fd;
  73. Binkey this_min_key;
  74. Binkey oid_prop_key;
  75. Binkey oid_access_key;
  76. Binkey oid_container_key;
  77. Binkey last_min_key;
  78. int oid_access_inspected;
  79. int oid_container_inspected;
  80. _Tt_string oid_prop_value;
  81. _Tt_string oid_prop_name;
  82. _Tt_string oid_prop_rootname;
  83. _Tt_string oid_access_rootname;
  84. _Tt_string oid_container_rootname;
  85. _Tt_string docoid_path_rootname;
  86. Spec_list_ptr specs_to_repair;
  87. // TOC
  88. int main(int argc, char **argv);
  89. int process_directory(_Tt_string dirname);
  90. void process_spec(Spec_ptr s);
  91. void advance_oid_prop();
  92. void advance_oid_container();
  93. void advance_oid_access();
  94. void closeall();
  95. Binkey compute_min_key(Binkey a, Binkey b, Binkey c);
  96. void inspect_docoid_path(Spec_ptr p);
  97. void pisamerr(const char *func, const char *name);
  98. void check_if_file(Spec_ptr p);
  99. // isam.h does not include function headers at all!!
  100. extern "C" {
  101. int isaddindex(int, struct keydesc*);
  102. int isbuild(char*, int, struct keydesc*, int);
  103. int isclose(int);
  104. int iscntl(int, int, char*);
  105. int isdelrec(int, long);
  106. int iserase(char*);
  107. int isopen(char*, int);
  108. int isread(int, char*, int);
  109. int isrepair(const char *, int);
  110. int isrewrec(int, int, char*);
  111. int isstart(int, struct keydesc*, int, char*, int);
  112. int iswrite(int, char*);
  113. }
  114. int
  115. main(int argc, char **argv)
  116. {
  117. int status;
  118. tstream = stderr;
  119. opts = new Dbck_specoptions;
  120. progname = argv[0];
  121. setlocale( LC_ALL, "" );
  122. if (!opts->set_opts(argc, argv))
  123. {
  124. fprintf(stderr, "%s", catgets(_ttcatd, 6, 2,
  125. "Usage:\n"
  126. "ttdbck [-f file] [-k objkey] [-t type] [-bx] \n"
  127. "[-impa] [-IZ] [-F newfilename] [-T newtype] [mountpoints]\n"));
  128. exit (1);
  129. }
  130. if (DBCK_DEBUG(1)) {
  131. opts->print(stderr);
  132. }
  133. if (opts->repairing_p() &&
  134. !opts->selecting_p() &&
  135. !opts->diagnosing_p()) {
  136. fprintf(stderr, "%s",
  137. catgets(_ttcatd, 6, 3,
  138. "ttdbck: you must specify a selection "
  139. "[-fkt] option or a diagnosis [-bx] option\n"
  140. "if a repair [-FTZ] option is specified\n"));
  141. exit (1);
  142. }
  143. if (opts->diag_badform_p()) {
  144. // We have to initialize just enough of the ttsession
  145. // server state to make the _Tt_typedb class work.
  146. // XXX: really the _Tt_typedb class should be independent
  147. // of the server.
  148. _tt_global = new _Tt_global;
  149. _tt_s_mp = new _Tt_s_mp;
  150. _tt_mp = (_Tt_mp *)new _Tt_s_mp;
  151. tdb_ptr = new _Tt_typedb_ptr;
  152. (*tdb_ptr) = new _Tt_typedb;
  153. Tt_status err;
  154. // Load the xdr types database
  155. err = (*tdb_ptr)->init_xdr();
  156. if (err == TT_ERR_NO_MATCH) {
  157. fprintf(stderr, "ttdbck: %s\n",
  158. catgets(_ttcatd, 6, 4,
  159. "Version mismatch in compiled types"));
  160. exit (1);
  161. } else if (err != TT_OK) {
  162. fprintf(stderr, "ttdbck: %s\n",
  163. catgets(_ttcatd, 6, 5,
  164. "Cannot read types in database"));
  165. exit (1);
  166. }
  167. }
  168. status = do_directories(opts->dbdirectories(),process_directory);
  169. // Normally UNIX programs don't make noise if nothing is wrong, but
  170. // in the case of ttdbck it's unlikely the admin running it is
  171. // familiar with it, and it's only being run if the database is
  172. // suspected of damage already. So we print a reassuring message
  173. // if there are no errors. If there are errors, there has
  174. // already been output.
  175. if (status==0) {
  176. fprintf(stderr, "%s",
  177. catgets(_ttcatd, 6, 25,
  178. "ttdbck: no errors found.\n"));
  179. }
  180. exit(status);
  181. return status;
  182. }
  183. /*
  184. * Main guts of ttdbck. Called once for each directory named on the
  185. * command line. Returns 1 if the directory was processed without
  186. * detecting any errors, else 0.
  187. */
  188. int
  189. process_directory(_Tt_string dirname)
  190. {
  191. struct keydesc oid_prop_keydesc;
  192. struct keydesc oid_access_keydesc;
  193. struct keydesc oid_container_keydesc;
  194. Spec_ptr this_spec;
  195. // Initialize for main loop.
  196. specs_to_repair = new Spec_list;
  197. oid_prop_rootname = dirname.cat(TT_DB_PROPERTY_TABLE_FILE);
  198. oid_prop_keydesc.k_flags = ISDUPS;
  199. oid_prop_keydesc.k_nparts = 2;
  200. oid_prop_keydesc.k_part[0].kp_start =
  201. offsetof(Table_oid_prop,objkey);
  202. oid_prop_keydesc.k_part[0].kp_leng =
  203. sizeof(oid_prop_record.objkey);
  204. oid_prop_keydesc.k_part[0].kp_type = BINTYPE;
  205. oid_prop_keydesc.k_part[1].kp_start =
  206. offsetof(Table_oid_prop,propname);
  207. oid_prop_keydesc.k_part[1].kp_leng =
  208. sizeof(oid_prop_record.propname);
  209. oid_prop_keydesc.k_part[1].kp_type = CHARTYPE;
  210. oid_access_rootname = dirname.cat(TT_DB_ACCESS_TABLE_FILE);
  211. oid_access_keydesc.k_flags = ISNODUPS;
  212. oid_access_keydesc.k_nparts = 1;
  213. oid_access_keydesc.k_part[0].kp_start =
  214. offsetof(Table_oid_access,objkey);
  215. oid_access_keydesc.k_part[0].kp_leng =
  216. sizeof(oid_access_record.objkey);
  217. oid_access_keydesc.k_part[0].kp_type = BINTYPE;
  218. oid_container_rootname = dirname.cat(TT_DB_FILE_OBJECT_MAP_FILE);
  219. oid_container_keydesc.k_flags = ISNODUPS;
  220. oid_container_keydesc.k_nparts = 1;
  221. oid_container_keydesc.k_part[0].kp_start =
  222. offsetof(Table_oid_container,objkey);
  223. oid_container_keydesc.k_part[0].kp_leng =
  224. sizeof(oid_container_record.objkey);
  225. oid_container_keydesc.k_part[0].kp_type = BINTYPE;
  226. docoid_path_rootname = dirname.cat(TT_DB_FILE_TABLE_FILE);
  227. docoid_path_keydesc.k_flags = ISNODUPS;
  228. docoid_path_keydesc.k_nparts = 1;
  229. docoid_path_keydesc.k_part[0].kp_start =
  230. offsetof(Table_docoid_path, dockey);
  231. docoid_path_keydesc.k_part[0].kp_leng =
  232. sizeof(docoid_path_record.dockey);
  233. docoid_path_keydesc.k_part[0].kp_type = BINTYPE;
  234. last_min_key = Binkey::smallest;
  235. oid_prop_fd = -1;
  236. oid_access_fd = -1;
  237. oid_container_fd = -1;
  238. docoid_path_fd = -1;
  239. if (opts->repair_netisam_p()) {
  240. if (-1==isrepair(oid_prop_rootname, 1)) {
  241. pisamerr("isrepair", oid_prop_rootname);
  242. return 0;
  243. }
  244. if (-1==isrepair(oid_access_rootname, 1)) {
  245. pisamerr("isrepair", oid_access_rootname);
  246. return 0;
  247. }
  248. if (-1==isrepair(oid_container_rootname, 1)) {
  249. pisamerr("isrepair", oid_container_rootname);
  250. return 0;
  251. }
  252. if (-1==isrepair(docoid_path_rootname, 1)) {
  253. pisamerr("isrepair", docoid_path_rootname);
  254. return 0;
  255. }
  256. }
  257. oid_prop_fd = isopen(oid_prop_rootname, ISVARLEN+ISINPUT+ISMANULOCK);
  258. if (oid_prop_fd==-1) {
  259. pisamerr("isopen",oid_prop_rootname);
  260. closeall();
  261. return 0;
  262. }
  263. oid_access_fd = isopen(oid_access_rootname,
  264. ISVARLEN+ISINPUT+ISMANULOCK);
  265. if (oid_access_fd==-1) {
  266. pisamerr("isopen",oid_access_rootname);
  267. closeall();
  268. return 0;
  269. }
  270. oid_container_fd = isopen(oid_container_rootname,
  271. ISVARLEN+ISINPUT+ISMANULOCK);
  272. if (oid_container_fd==-1) {
  273. pisamerr("isopen",oid_container_rootname);
  274. closeall();
  275. return 0;
  276. }
  277. docoid_path_fd = isopen(docoid_path_rootname,
  278. ISVARLEN+ISINPUT+ISMANULOCK);
  279. if (docoid_path_fd==-1) {
  280. pisamerr("isopen",docoid_path_rootname);
  281. closeall();
  282. return 0;
  283. }
  284. if (-1==isstart(oid_prop_fd, &oid_prop_keydesc,
  285. 0,
  286. (char *)&oid_prop_record,
  287. ISFIRST)) {
  288. pisamerr("isstart",oid_prop_rootname);
  289. closeall();
  290. return 0;
  291. }
  292. if (-1==isstart(oid_access_fd, &oid_access_keydesc,
  293. 0,
  294. (char *)&oid_access_record,
  295. ISFIRST)) {
  296. pisamerr("isstart", oid_access_rootname);
  297. closeall();
  298. return 0;
  299. }
  300. if (-1==isstart(oid_container_fd, &oid_container_keydesc,
  301. 0,
  302. (char *)&oid_container_record,
  303. ISFIRST)){
  304. pisamerr("isstart", oid_container_rootname);
  305. closeall();
  306. return 0;
  307. }
  308. if (-1==isstart(docoid_path_fd, &docoid_path_keydesc,
  309. 0,
  310. (char *)&docoid_path_record,
  311. ISFIRST)){
  312. pisamerr("isstart", docoid_path_rootname);
  313. closeall();
  314. return 0;
  315. }
  316. advance_oid_prop();
  317. advance_oid_access();
  318. advance_oid_container();
  319. this_min_key = compute_min_key(oid_prop_key,
  320. oid_access_key,
  321. oid_container_key);
  322. while (this_min_key<Binkey::largest) {
  323. if (last_min_key<this_min_key) {
  324. // At this point, we have read all
  325. // information about the previous spec.
  326. // Analyze it, list it if called for,
  327. // queue it for later repair if called
  328. // for.
  329. process_spec(this_spec);
  330. // Complain about any missing required props
  331. // in previous spec, and reset the required property
  332. // list.
  333. // start accumulating a new spec
  334. this_spec = new Spec;
  335. this_spec->key =
  336. new Binkey((unsigned char *)(char *)this_min_key);
  337. check_if_file(this_spec);
  338. if (oid_access_key>this_min_key) {
  339. // mark spec as no access rec
  340. }
  341. if (oid_container_key>this_min_key) {
  342. // mark spec as no container rec
  343. }
  344. }
  345. if (!oid_container_inspected &&
  346. oid_container_key==this_min_key) {
  347. oid_container_inspected = 1;
  348. inspect_docoid_path(this_spec);
  349. }
  350. if (oid_prop_key==this_min_key) {
  351. // Accumulate property
  352. this_spec->add_prop_and_value(oid_prop_name,
  353. oid_prop_value);
  354. }
  355. // Advance to next records.
  356. if (oid_prop_key==this_min_key) {
  357. advance_oid_prop();
  358. } else {
  359. if (oid_container_key==this_min_key) {
  360. advance_oid_container();
  361. }
  362. if (oid_access_key==this_min_key) {
  363. advance_oid_access();
  364. }
  365. }
  366. last_min_key = this_min_key;
  367. this_min_key = compute_min_key(oid_prop_key,
  368. oid_access_key,
  369. oid_container_key);
  370. }
  371. // And remember to process the last spec.
  372. process_spec(this_spec);
  373. closeall();
  374. if (opts->repairing_p()) {
  375. Spec_list_cursor c(specs_to_repair);
  376. while(c.next()) {
  377. c->repair_spec();
  378. }
  379. }
  380. return 1;
  381. }
  382. // the advance_*() routines try to read the next record in the table;
  383. // when eof is hit, they set the record key to the largest possible
  384. // key. This makes all the merge comparisons work right.
  385. void
  386. advance_oid_prop()
  387. {
  388. if (-1==isread(oid_prop_fd, (char *)&oid_prop_record, ISNEXT)) {
  389. switch (iserrno) {
  390. case EENDFILE:
  391. break;
  392. default:
  393. pisamerr("isread", oid_prop_rootname);
  394. break;
  395. }
  396. oid_prop_key = Binkey::largest;
  397. } else {
  398. int l;
  399. oid_prop_key = oid_prop_record.objkey;
  400. l = sizeof(oid_prop_record.propname);
  401. if (oid_prop_record.propname[l-1]==NULL_CHAR) {
  402. // strip nulls
  403. l = strlen(oid_prop_record.propname);
  404. }
  405. oid_prop_name.set((unsigned char *)oid_prop_record.propname,l);
  406. oid_prop_value.set((unsigned char *)oid_prop_record.propval,
  407. isreclen-offsetof(Table_oid_prop,propval));
  408. }
  409. }
  410. void
  411. advance_oid_access()
  412. {
  413. if (-1==isread(oid_access_fd, (char *)&oid_access_record, ISNEXT)) {
  414. switch (iserrno) {
  415. case EENDFILE:
  416. break;
  417. default:
  418. pisamerr("isread", oid_access_rootname);
  419. break;
  420. }
  421. oid_access_key = Binkey::largest;
  422. } else {
  423. oid_access_key = oid_access_record.objkey;
  424. }
  425. oid_access_inspected = 0;
  426. }
  427. void
  428. advance_oid_container()
  429. {
  430. if (-1==isread(oid_container_fd,
  431. (char *)&oid_container_record, ISNEXT)) {
  432. switch (iserrno) {
  433. case EENDFILE:
  434. break;
  435. default:
  436. pisamerr("isread", oid_container_rootname);
  437. break;
  438. }
  439. oid_container_key = Binkey::largest;
  440. } else {
  441. oid_container_key = oid_container_record.objkey;
  442. }
  443. oid_container_inspected = 0;
  444. }
  445. void
  446. closeall()
  447. {
  448. if (oid_container_fd!=-1) isclose(oid_container_fd);
  449. if (oid_access_fd!=-1) isclose(oid_access_fd);
  450. if (oid_prop_fd!=-1) isclose(oid_prop_fd);
  451. if (docoid_path_fd!=-1) isclose(docoid_path_fd);
  452. }
  453. // compute_min_key finds the least key
  454. Binkey
  455. compute_min_key(Binkey a, Binkey b, Binkey c)
  456. {
  457. Binkey result = a;
  458. if (b<result) result = b;
  459. if (c<result) result = c;
  460. return result;
  461. }
  462. // process spec is called when the next key is encountered, or at
  463. // end of file. The spec data accumulated in spec s is inspected,
  464. // printed, and/or queued for later repair.
  465. void
  466. process_spec(Spec_ptr s)
  467. {
  468. // The first time through the loop there is no accumulated spec
  469. // so s will be null.
  470. if (!s.is_null()) {
  471. s->process_spec();
  472. }
  473. }
  474. // inspect_docoid_path retrieves the docoid_path record for the current
  475. // spec and fills the file name into this_spec.
  476. void
  477. inspect_docoid_path(Spec_ptr this_spec)
  478. {
  479. memset((char *)&docoid_path_record, 0, sizeof(docoid_path_record));
  480. memcpy(docoid_path_record.dockey, oid_container_record.dockey,
  481. sizeof(docoid_path_record.dockey));
  482. if (-1==isread(docoid_path_fd, (char *)&docoid_path_record, ISEQUAL)) {
  483. switch (iserrno) {
  484. case ENOREC:
  485. // oid doesn't have a file!
  486. this_spec->filename = "";
  487. return;
  488. default:
  489. pisamerr("isread", oid_container_rootname);
  490. break;
  491. }
  492. }
  493. if (docoid_path_record.filepath[MAX_KEY_LEN-1] == '\0') {
  494. // strip padding.
  495. this_spec->filename = (char *)docoid_path_record.filepath;
  496. } else {
  497. this_spec->filename.set((unsigned char *)
  498. docoid_path_record.filepath,
  499. isreclen-offsetof(Table_docoid_path,
  500. filepath));
  501. }
  502. }
  503. /*
  504. * Print ISAM error message. Some error codes (well, one)
  505. * are special cased to give more "helpful" messages.
  506. */
  507. void
  508. pisamerr(const char *func, const char *name)
  509. {
  510. const char *msg = _tt_isstrerror(iserrno);
  511. if (msg) {
  512. fprintf(stderr,"ttdbck: %s(\"%s\"): %s\n", func, name,
  513. msg);
  514. } else {
  515. fprintf(stderr,"ttdbck: %s(\"%s\"): %d\n", func, name,
  516. iserrno);
  517. }
  518. switch (iserrno) {
  519. case EBADFILE:
  520. fprintf(stderr, "%s",
  521. catgets(_ttcatd, 6, 6,
  522. "ttdbck: try 'ttdbck -I'.\n"));
  523. break;
  524. default:
  525. break;
  526. }
  527. }
  528. void
  529. check_if_file(Spec_ptr this_spec)
  530. {
  531. memset((char *)&docoid_path_record, '\0', sizeof(docoid_path_record));
  532. memcpy((char *)docoid_path_record.dockey,
  533. (char *)(*this_spec->key), OID_KEY_LENGTH);
  534. if (-1==isread(docoid_path_fd, (char *)&docoid_path_record, ISEQUAL)) {
  535. switch (iserrno) {
  536. case ENOREC:
  537. break;
  538. default:
  539. pisamerr("isread", oid_container_rootname);
  540. break;
  541. }
  542. this_spec->is_filespec = 0;
  543. return;
  544. }
  545. // This is the docoid for a file. Set the filename in the spec
  546. // so the -f option will select the docoid for the file as well.
  547. this_spec->is_filespec = 1;
  548. if (docoid_path_record.filepath[MAX_KEY_LEN-1] == '\0') {
  549. // strip padding.
  550. this_spec->filename = (char *)docoid_path_record.filepath;
  551. } else {
  552. this_spec->filename.set((unsigned char *)
  553. docoid_path_record.filepath,
  554. isreclen-offsetof(Table_docoid_path,
  555. filepath));
  556. }
  557. }