/* * 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 #include #include #include #include #include #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_keykey = 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 (bprocess_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)); } }