123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
- //%% (c) Copyright 1993, 1994 International Business Machines Corp.
- //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
- //%% (c) Copyright 1993, 1994 Novell, Inc.
- //%% $XConsortium: ttdbck.C /main/3 1995/10/20 16:34:00 rswiston $
- /*
- *
- * ttdbck.cc
- * @(#)ttdbck.C 1.31 93/09/07
- *
- * ToolTalk 1.0 spec data base inspect and repair tool
- *
- * Copyright (c) 1990 by Sun Microsystems, Inc.
- */
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <isam.h>
- #include <locale.h>
- #include <memory.h>
- #include "util/tt_port.h"
- #include "util/tt_gettext.h"
- #include "util/tt_global_env.h"
- #include "ttdbck.h"
- #include "dbck.h"
- #include "options_tt.h"
- #include "binkey.h"
- #include "spec.h"
- #include "util/copyright.h"
- #include "dm/dm_recfmts.h"
- #include "mp/mp_mp.h"
- #include "mp_s_mp.h"
- #include "tt_db_server_consts.h"
- #include "tt_isstrerror.h"
- TT_INSERT_COPYRIGHT
- #ifdef OPT_PATCH
- static char PatchID[] = "Patch Id: 100626_03.";
- static int Patch_ID100626_03;
- #endif
- char *progname; // from argv[0]
- Dbck_specoptions *opts;
- _Tt_typedb_ptr *tdb_ptr;
- FILE *tstream; // for calling print() methods in dbx
- // Global variables controlling state of main merge loop.
- Table_oid_prop oid_prop_record;
- Table_oid_access oid_access_record;
- Table_oid_container oid_container_record;
- Table_docoid_path docoid_path_record;
- struct keydesc docoid_path_keydesc;
- int oid_prop_fd, oid_access_fd, oid_container_fd, docoid_path_fd;
- Binkey this_min_key;
- Binkey oid_prop_key;
- Binkey oid_access_key;
- Binkey oid_container_key;
- Binkey last_min_key;
- int oid_access_inspected;
- int oid_container_inspected;
- _Tt_string oid_prop_value;
- _Tt_string oid_prop_name;
- _Tt_string oid_prop_rootname;
- _Tt_string oid_access_rootname;
- _Tt_string oid_container_rootname;
- _Tt_string docoid_path_rootname;
- Spec_list_ptr specs_to_repair;
- // TOC
- int main(int argc, char **argv);
- int process_directory(_Tt_string dirname);
- void process_spec(Spec_ptr s);
- void advance_oid_prop();
- void advance_oid_container();
- void advance_oid_access();
- void closeall();
- Binkey compute_min_key(Binkey a, Binkey b, Binkey c);
- void inspect_docoid_path(Spec_ptr p);
- void pisamerr(const char *func, const char *name);
- void check_if_file(Spec_ptr p);
- // isam.h does not include function headers at all!!
- extern "C" {
- int isaddindex(int, struct keydesc*);
- int isbuild(char*, int, struct keydesc*, int);
- int isclose(int);
- int iscntl(int, int, char*);
- int isdelrec(int, long);
- int iserase(char*);
- int isopen(char*, int);
- int isread(int, char*, int);
- int isrepair(const char *, int);
- int isrewrec(int, int, char*);
- int isstart(int, struct keydesc*, int, char*, int);
- int iswrite(int, char*);
- }
- int
- main(int argc, char **argv)
- {
- int status;
-
- tstream = stderr;
- opts = new Dbck_specoptions;
- progname = argv[0];
- setlocale( LC_ALL, "" );
- if (!opts->set_opts(argc, argv))
- {
- fprintf(stderr, "%s", catgets(_ttcatd, 6, 2,
- "Usage:\n"
- "ttdbck [-f file] [-k objkey] [-t type] [-bx] \n"
- "[-impa] [-IZ] [-F newfilename] [-T newtype] [mountpoints]\n"));
- exit (1);
- }
- if (DBCK_DEBUG(1)) {
- opts->print(stderr);
- }
- if (opts->repairing_p() &&
- !opts->selecting_p() &&
- !opts->diagnosing_p()) {
- fprintf(stderr, "%s",
- catgets(_ttcatd, 6, 3,
- "ttdbck: you must specify a selection "
- "[-fkt] option or a diagnosis [-bx] option\n"
- "if a repair [-FTZ] option is specified\n"));
- exit (1);
- }
- if (opts->diag_badform_p()) {
- // We have to initialize just enough of the ttsession
- // server state to make the _Tt_typedb class work.
- // XXX: really the _Tt_typedb class should be independent
- // of the server.
- _tt_global = new _Tt_global;
- _tt_s_mp = new _Tt_s_mp;
- _tt_mp = (_Tt_mp *)new _Tt_s_mp;
- tdb_ptr = new _Tt_typedb_ptr;
- (*tdb_ptr) = new _Tt_typedb;
- Tt_status err;
- // Load the xdr types database
- err = (*tdb_ptr)->init_xdr();
- if (err == TT_ERR_NO_MATCH) {
- fprintf(stderr, "ttdbck: %s\n",
- catgets(_ttcatd, 6, 4,
- "Version mismatch in compiled types"));
- exit (1);
- } else if (err != TT_OK) {
- fprintf(stderr, "ttdbck: %s\n",
- catgets(_ttcatd, 6, 5,
- "Cannot read types in database"));
- exit (1);
- }
- }
-
- status = do_directories(opts->dbdirectories(),process_directory);
- // Normally UNIX programs don't make noise if nothing is wrong, but
- // in the case of ttdbck it's unlikely the admin running it is
- // familiar with it, and it's only being run if the database is
- // suspected of damage already. So we print a reassuring message
- // if there are no errors. If there are errors, there has
- // already been output.
- if (status==0) {
- fprintf(stderr, "%s",
- catgets(_ttcatd, 6, 25,
- "ttdbck: no errors found.\n"));
- }
- exit(status);
- return status;
- }
- /*
- * Main guts of ttdbck. Called once for each directory named on the
- * command line. Returns 1 if the directory was processed without
- * detecting any errors, else 0.
- */
- int
- process_directory(_Tt_string dirname)
- {
- struct keydesc oid_prop_keydesc;
- struct keydesc oid_access_keydesc;
- struct keydesc oid_container_keydesc;
- Spec_ptr this_spec;
- // Initialize for main loop.
- specs_to_repair = new Spec_list;
- oid_prop_rootname = dirname.cat(TT_DB_PROPERTY_TABLE_FILE);
- oid_prop_keydesc.k_flags = ISDUPS;
- oid_prop_keydesc.k_nparts = 2;
- oid_prop_keydesc.k_part[0].kp_start =
- offsetof(Table_oid_prop,objkey);
- oid_prop_keydesc.k_part[0].kp_leng =
- sizeof(oid_prop_record.objkey);
- oid_prop_keydesc.k_part[0].kp_type = BINTYPE;
- oid_prop_keydesc.k_part[1].kp_start =
- offsetof(Table_oid_prop,propname);
- oid_prop_keydesc.k_part[1].kp_leng =
- sizeof(oid_prop_record.propname);
- oid_prop_keydesc.k_part[1].kp_type = CHARTYPE;
-
- oid_access_rootname = dirname.cat(TT_DB_ACCESS_TABLE_FILE);
- oid_access_keydesc.k_flags = ISNODUPS;
- oid_access_keydesc.k_nparts = 1;
- oid_access_keydesc.k_part[0].kp_start =
- offsetof(Table_oid_access,objkey);
- oid_access_keydesc.k_part[0].kp_leng =
- sizeof(oid_access_record.objkey);
- oid_access_keydesc.k_part[0].kp_type = BINTYPE;
- oid_container_rootname = dirname.cat(TT_DB_FILE_OBJECT_MAP_FILE);
- oid_container_keydesc.k_flags = ISNODUPS;
- oid_container_keydesc.k_nparts = 1;
- oid_container_keydesc.k_part[0].kp_start =
- offsetof(Table_oid_container,objkey);
- oid_container_keydesc.k_part[0].kp_leng =
- sizeof(oid_container_record.objkey);
- oid_container_keydesc.k_part[0].kp_type = BINTYPE;
- docoid_path_rootname = dirname.cat(TT_DB_FILE_TABLE_FILE);
- docoid_path_keydesc.k_flags = ISNODUPS;
- docoid_path_keydesc.k_nparts = 1;
- docoid_path_keydesc.k_part[0].kp_start =
- offsetof(Table_docoid_path, dockey);
- docoid_path_keydesc.k_part[0].kp_leng =
- sizeof(docoid_path_record.dockey);
- docoid_path_keydesc.k_part[0].kp_type = BINTYPE;
- last_min_key = Binkey::smallest;
- oid_prop_fd = -1;
- oid_access_fd = -1;
- oid_container_fd = -1;
- docoid_path_fd = -1;
- if (opts->repair_netisam_p()) {
- if (-1==isrepair(oid_prop_rootname, 1)) {
- pisamerr("isrepair", oid_prop_rootname);
- return 0;
- }
- if (-1==isrepair(oid_access_rootname, 1)) {
- pisamerr("isrepair", oid_access_rootname);
- return 0;
- }
- if (-1==isrepair(oid_container_rootname, 1)) {
- pisamerr("isrepair", oid_container_rootname);
- return 0;
- }
- if (-1==isrepair(docoid_path_rootname, 1)) {
- pisamerr("isrepair", docoid_path_rootname);
- return 0;
- }
- }
- oid_prop_fd = isopen(oid_prop_rootname, ISVARLEN+ISINPUT+ISMANULOCK);
- if (oid_prop_fd==-1) {
- pisamerr("isopen",oid_prop_rootname);
- closeall();
- return 0;
- }
- oid_access_fd = isopen(oid_access_rootname,
- ISVARLEN+ISINPUT+ISMANULOCK);
- if (oid_access_fd==-1) {
- pisamerr("isopen",oid_access_rootname);
- closeall();
- return 0;
- }
- oid_container_fd = isopen(oid_container_rootname,
- ISVARLEN+ISINPUT+ISMANULOCK);
- if (oid_container_fd==-1) {
- pisamerr("isopen",oid_container_rootname);
- closeall();
- return 0;
- }
- docoid_path_fd = isopen(docoid_path_rootname,
- ISVARLEN+ISINPUT+ISMANULOCK);
- if (docoid_path_fd==-1) {
- pisamerr("isopen",docoid_path_rootname);
- closeall();
- return 0;
- }
- if (-1==isstart(oid_prop_fd, &oid_prop_keydesc,
- 0,
- (char *)&oid_prop_record,
- ISFIRST)) {
- pisamerr("isstart",oid_prop_rootname);
- closeall();
- return 0;
- }
- if (-1==isstart(oid_access_fd, &oid_access_keydesc,
- 0,
- (char *)&oid_access_record,
- ISFIRST)) {
- pisamerr("isstart", oid_access_rootname);
- closeall();
- return 0;
- }
- if (-1==isstart(oid_container_fd, &oid_container_keydesc,
- 0,
- (char *)&oid_container_record,
- ISFIRST)){
- pisamerr("isstart", oid_container_rootname);
- closeall();
- return 0;
- }
- if (-1==isstart(docoid_path_fd, &docoid_path_keydesc,
- 0,
- (char *)&docoid_path_record,
- ISFIRST)){
- pisamerr("isstart", docoid_path_rootname);
- closeall();
- return 0;
- }
- advance_oid_prop();
- advance_oid_access();
- advance_oid_container();
- this_min_key = compute_min_key(oid_prop_key,
- oid_access_key,
- oid_container_key);
- while (this_min_key<Binkey::largest) {
- if (last_min_key<this_min_key) {
- // At this point, we have read all
- // information about the previous spec.
- // Analyze it, list it if called for,
- // queue it for later repair if called
- // for.
- process_spec(this_spec);
-
- // Complain about any missing required props
- // in previous spec, and reset the required property
- // list.
- // start accumulating a new spec
- this_spec = new Spec;
- this_spec->key =
- new Binkey((unsigned char *)(char *)this_min_key);
- check_if_file(this_spec);
- if (oid_access_key>this_min_key) {
- // mark spec as no access rec
- }
- if (oid_container_key>this_min_key) {
- // mark spec as no container rec
- }
- }
-
- if (!oid_container_inspected &&
- oid_container_key==this_min_key) {
- oid_container_inspected = 1;
- inspect_docoid_path(this_spec);
- }
- if (oid_prop_key==this_min_key) {
- // Accumulate property
- this_spec->add_prop_and_value(oid_prop_name,
- oid_prop_value);
- }
- // Advance to next records.
- if (oid_prop_key==this_min_key) {
- advance_oid_prop();
- } else {
- if (oid_container_key==this_min_key) {
- advance_oid_container();
- }
- if (oid_access_key==this_min_key) {
- advance_oid_access();
- }
- }
- last_min_key = this_min_key;
- this_min_key = compute_min_key(oid_prop_key,
- oid_access_key,
- oid_container_key);
- }
- // And remember to process the last spec.
- process_spec(this_spec);
- closeall();
- if (opts->repairing_p()) {
- Spec_list_cursor c(specs_to_repair);
- while(c.next()) {
- c->repair_spec();
- }
- }
- return 1;
- }
-
- // the advance_*() routines try to read the next record in the table;
- // when eof is hit, they set the record key to the largest possible
- // key. This makes all the merge comparisons work right.
- void
- advance_oid_prop()
- {
- if (-1==isread(oid_prop_fd, (char *)&oid_prop_record, ISNEXT)) {
- switch (iserrno) {
- case EENDFILE:
- break;
- default:
- pisamerr("isread", oid_prop_rootname);
- break;
- }
- oid_prop_key = Binkey::largest;
- } else {
- int l;
- oid_prop_key = oid_prop_record.objkey;
- l = sizeof(oid_prop_record.propname);
- if (oid_prop_record.propname[l-1]==NULL_CHAR) {
- // strip nulls
- l = strlen(oid_prop_record.propname);
- }
- oid_prop_name.set((unsigned char *)oid_prop_record.propname,l);
- oid_prop_value.set((unsigned char *)oid_prop_record.propval,
- isreclen-offsetof(Table_oid_prop,propval));
- }
- }
- void
- advance_oid_access()
- {
- if (-1==isread(oid_access_fd, (char *)&oid_access_record, ISNEXT)) {
- switch (iserrno) {
- case EENDFILE:
- break;
- default:
- pisamerr("isread", oid_access_rootname);
- break;
- }
- oid_access_key = Binkey::largest;
- } else {
- oid_access_key = oid_access_record.objkey;
- }
- oid_access_inspected = 0;
- }
- void
- advance_oid_container()
- {
- if (-1==isread(oid_container_fd,
- (char *)&oid_container_record, ISNEXT)) {
- switch (iserrno) {
- case EENDFILE:
- break;
- default:
- pisamerr("isread", oid_container_rootname);
- break;
- }
- oid_container_key = Binkey::largest;
- } else {
- oid_container_key = oid_container_record.objkey;
- }
- oid_container_inspected = 0;
- }
- void
- closeall()
- {
- if (oid_container_fd!=-1) isclose(oid_container_fd);
- if (oid_access_fd!=-1) isclose(oid_access_fd);
- if (oid_prop_fd!=-1) isclose(oid_prop_fd);
- if (docoid_path_fd!=-1) isclose(docoid_path_fd);
- }
- // compute_min_key finds the least key
- Binkey
- compute_min_key(Binkey a, Binkey b, Binkey c)
- {
- Binkey result = a;
- if (b<result) result = b;
- if (c<result) result = c;
- return result;
- }
- // process spec is called when the next key is encountered, or at
- // end of file. The spec data accumulated in spec s is inspected,
- // printed, and/or queued for later repair.
- void
- process_spec(Spec_ptr s)
- {
- // The first time through the loop there is no accumulated spec
- // so s will be null.
-
- if (!s.is_null()) {
- s->process_spec();
- }
- }
- // inspect_docoid_path retrieves the docoid_path record for the current
- // spec and fills the file name into this_spec.
- void
- inspect_docoid_path(Spec_ptr this_spec)
- {
- memset((char *)&docoid_path_record, 0, sizeof(docoid_path_record));
- memcpy(docoid_path_record.dockey, oid_container_record.dockey,
- sizeof(docoid_path_record.dockey));
-
- if (-1==isread(docoid_path_fd, (char *)&docoid_path_record, ISEQUAL)) {
- switch (iserrno) {
- case ENOREC:
- // oid doesn't have a file!
- this_spec->filename = "";
- return;
- default:
- pisamerr("isread", oid_container_rootname);
- break;
- }
- }
- if (docoid_path_record.filepath[MAX_KEY_LEN-1] == '\0') {
- // strip padding.
- this_spec->filename = (char *)docoid_path_record.filepath;
- } else {
- this_spec->filename.set((unsigned char *)
- docoid_path_record.filepath,
- isreclen-offsetof(Table_docoid_path,
- filepath));
- }
- }
- /*
- * Print ISAM error message. Some error codes (well, one)
- * are special cased to give more "helpful" messages.
- */
- void
- pisamerr(const char *func, const char *name)
- {
- const char *msg = _tt_isstrerror(iserrno);
- if (msg) {
- fprintf(stderr,"ttdbck: %s(\"%s\"): %s\n", func, name,
- msg);
- } else {
- fprintf(stderr,"ttdbck: %s(\"%s\"): %d\n", func, name,
- iserrno);
- }
- switch (iserrno) {
- case EBADFILE:
- fprintf(stderr, "%s",
- catgets(_ttcatd, 6, 6,
- "ttdbck: try 'ttdbck -I'.\n"));
- break;
- default:
- break;
- }
- }
- void
- check_if_file(Spec_ptr this_spec)
- {
- memset((char *)&docoid_path_record, '\0', sizeof(docoid_path_record));
- memcpy((char *)docoid_path_record.dockey,
- (char *)(*this_spec->key), OID_KEY_LENGTH);
- if (-1==isread(docoid_path_fd, (char *)&docoid_path_record, ISEQUAL)) {
- switch (iserrno) {
- case ENOREC:
- break;
- default:
- pisamerr("isread", oid_container_rootname);
- break;
- }
- this_spec->is_filespec = 0;
- return;
- }
- // This is the docoid for a file. Set the filename in the spec
- // so the -f option will select the docoid for the file as well.
- this_spec->is_filespec = 1;
- if (docoid_path_record.filepath[MAX_KEY_LEN-1] == '\0') {
- // strip padding.
- this_spec->filename = (char *)docoid_path_record.filepath;
- } else {
- this_spec->filename.set((unsigned char *)
- docoid_path_record.filepath,
- isreclen-offsetof(Table_docoid_path,
- filepath));
- }
- }
|