head 1.10; access; symbols; locks; strict; comment @ * @; 1.10 date 94.03.12.00.59.25; author paul; state Exp; branches; next 1.9; 1.9 date 93.12.19.18.43.04; author paul; state Exp; branches; next 1.8; 1.8 date 93.07.24.19.06.03; author paul; state Exp; branches; next 1.7; 1.7 date 93.04.01.16.27.58; author paul; state Exp; branches; next 1.6; 1.6 date 93.02.27.21.06.24; author paul; state Exp; branches; next 1.5; 1.5 date 93.01.23.19.38.20; author paul; state Exp; branches; next 1.4; 1.4 date 92.12.12.19.10.18; author paul; state Exp; branches; next 1.3; 1.3 date 92.07.28.05.04.53; author paul; state Exp; branches; next 1.2; 1.2 date 92.07.27.22.20.02; author paul; state Exp; branches; next 1.1; 1.1 date 92.07.27.21.37.00; author paul; state Exp; branches; next ; desc @@ 1.10 log @New copyright statement. @ text @/* * Copyright (c) 1985 Corporation for Research and Educational Networking * Copyright (c) 1988 University of Illinois Board of Trustees, Steven * Dorner, and Paul Pomes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Corporation for * Research and Educational Networking (CREN), the University of * Illinois at Urbana, and their contributors. * 4. Neither the name of CREN, the University nor the names of their * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE TRUSTEES AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char RcsId[] = "@@(#)$Id$"; #endif /* * This program checks the integrity of a CSO nameserver database. It makes * sure almost everything is "on the up-and-up". Specifically, it detects * the following problems: * * + existence and permissions of all database files * - non-unique aliases * - no pointers to null leaves in the .bdx file * - entries in .bdx file in proper order * - no bad pointers into .seq file from .bdx file * - entries in .seq file in proper order * - proper counts in all files * + no bad pointers into .dir file from .idx file * + no pointers to deleted entries in .dir file from .idx file * + no bad pointers into .iov file from .idx file * + no shared pointers into .iov file from .idx and .iov files * + no bad pointers into .dov file from .dir file * + no shared pointers into .dov file from .dir file * + no bad pointers from .dov file into .dov file * + no shared pointers from .dov file into .dov file * - no entries whose data is longer than their entry chain * * Note that it DETECTS only; it does not (yet) correct problems. Note * also that it does NOT check to see that each word the index claims to be * in an entry is in fact in that entry, nor does it check to see that every * word in indexed fields actually appear in the index with the proper * pointers. The reason it does not do so is that such would amount to * doing a full reindex of the database, and would take hours. Perhaps * at some time nsck will be extended to perform some or all of these * functions. * * Note also that this program avoids many of the normal database * operations, since they may give wrong information in the presence * of flaws. That means that changes made in database structure will * require changes in this program. */ #include "protos.h" #include #include #include #include #include #include #include #include "conf.h" #ifndef L_SET # define L_SET 0 #endif /* !L_SET */ #ifndef L_INCR # define L_INCR 1 #endif /* !L_INCR */ /* * important definitions */ #define FATAL 2 /* an error that makes progress impossible */ #define ERROR 1 /* error that does not stop processing */ #define FINE 0 /* clean bill of health */ #define DEAD 1 /* for dead .dir entries */ #define REFERENCED 2 /* .dir entries that are referenced in .idx */ typedef char string[2048]; /* for various strings */ #define T (trouble ? 0 : (trouble=ERROR)),printf #define PERR(msg) printf("%s%d: %s: %s\n",Me,__LINE__,msg,errno > sys_nerr ? "unknown error" : sys_errlist[errno]) #define REP_INT 1000 /* reporting interval for status messages */ #define HASNULL(x) (!(x&0xff && x&0xff00 && x&0xff0000 && x&0xff000000)) /* * some functions that have to be declared... */ /* * some global variables */ static char *Me; /* the name of this program */ int WantInfo = 0; /* do we want info messages? */ int WantStatus = 0; /* do we want status messages? */ extern char *sys_errlist[]; /* system errors */ extern int sys_nerr; /* how many of them there are */ extern int errno; /* the current error */ /* * this structure holds names and functions for all the checks */ typedef struct { char *name; /* name (for humans) of check */ int (*func) (); /* function implementing check */ } CHECK; int Files(), IdxDir(), IdxIov(), DirDov(); CHECK Checks[] = { "Files and Permissions", Files, "IDX/DIR Consistency", IdxDir, "IDX/IOV Consistency", IdxIov, "DIR/DOV Consistency", DirDov, 0, 0 }; /* * here we go... */ main(argc, argv) int argc; char **argv; { int result; /* when you're strange, no one remembers your name */ Me = *argv; /* process options */ for (argc--, argv++; argc && **argv == '-'; argc--, argv++) { char *equal, **opt; (*argv)++; switch (**argv) { case 'i': WantInfo = 1; break; case 's': WantStatus = 1; break; default: if (equal = strchr(*argv, '=')) { *equal++ = '\0'; for (opt = Strings; *opt; opt += 2) if (!strcmp(opt[0], *argv)) { opt[1] = equal; break; } if (*opt == '\0') { fprintf(stderr, "%s: %s: unknown string.\n", Me, *argv); exit(1); } } else { fprintf(stderr, "%s: %s: unknown option.\n", Me, *argv); exit(1); } } } Database = (argc > 0) ? *argv : DATABASE; /* process database(s) */ if (argc == 0) result = Nsck(); /* use configured database */ else for (; argc > 0; argc--, argv++) { Database = *argv; result = (result << 1) | Nsck(); } exit(result); } /* * The real work begins here... */ Nsck() { int trouble = 0; CHECK *ck; printf("\n%s:\n", Database); for (ck = Checks; ck->name; ck++) { printf("%s:\n", ck->name); switch ((*ck->func) ()) { case FATAL: printf("%s: Giving up\n", Database); return (1); break; case ERROR: trouble = 1; break; case FINE: break; } } return (trouble); } /* * Check that all the proper files exist, and that they have all the * proper owner, group, and modes */ #define RIGHT_MODE (0660) Files() { int trouble = 0; static char *extensions[] = {"bdx", "seq", "idx", "iov", "dir", "dov", 0}; string filename; char **x; struct stat s; static int nsuid = -1; static int nsgid = -1; /* figure out proper uid and gid */ if (nsuid < 0) { struct passwd *pwent; struct group *grent; if (!(pwent = getpwnam(OWNER))) { printf("Proper owner \"%s\" does not exist!\n", OWNER); trouble = ERROR; nsuid = 0; } else nsuid = pwent->pw_uid; if (!(grent = getgrnam(GROUP))) { printf("Proper group \"%s\" does not exist!\n", GROUP); trouble = ERROR; nsgid = 0; } else nsgid = grent->gr_gid; } /* now check the files */ for (x = extensions; *x; x++) { sprintf(filename, "%s.%s", Database, *x); if (stat(filename, &s)) { PERR(filename); trouble = FATAL; } else { if (s.st_uid != nsuid) T("%s: owner %d not %d\n", filename, s.st_uid, nsuid); if (s.st_gid != nsgid) T("%s: group %d not %d\n", filename, s.st_gid, nsgid); if (s.st_mode != RIGHT_MODE) T("%s: mode %o not %o\n", filename, s.st_mode, RIGHT_MODE); } } return (trouble); } /* * make sure all the pointers in the .idx file point to non-deleted, * valid entries in the .dir file. */ IdxDir() { int trouble = FINE; int dirCount, idxCount; int i; char *ents = NULL; string dirName, idxName, iovName; string buffer; int dfd = 0, ifd = 0, iod = 0; register int *ptr; struct stat s; int aDir; register char *d; /* * first, we find out how many entries are in the .dir file, * and collect the numbers of all the deleted entries. Along * the way, we test the size of the .dir file */ sprintf(dirName, "%s.%s", Database, "dir"); if ((dfd = open(dirName, O_RDONLY)) == 0) { PERR(dirName); return (FATAL); } if (read(dfd, buffer, sizeof (int)) < 0) { PERR(dirName); trouble = FATAL; goto done; } dirCount = *((int *) buffer); fstat(dfd, &s); i = s.st_size / DRECSIZE; if (s.st_size % DRECSIZE) T("%s: size is not a multiple of %d.\n", dirName, DRECSIZE); if (dirCount != i) { T("%s:number of entries is %d; file size indicates %d.\n", dirCount, i); dirCount = i; } /* now, gather entries */ maybef(WantStatus, "Gathering entry information.\n"); if (dirCount) { ents = malloc(dirCount); if (!ents) { printf("malloc FAILED! Sheesh!\n"); trouble = FATAL; goto done; } for (d = ents; d < ents + dirCount; d++) *d = 0; if (lseek(dfd, 14, L_INCR) < 0) { PERR(dirName); trouble = FATAL; goto done; } for (aDir = 1; aDir < dirCount; aDir++) { if (aDir % REP_INT == REP_INT - 1) maybef(WantStatus, "%-10d\r", aDir); if (lseek(dfd, DRECSIZE - sizeof (short), L_INCR) < 0) { PERR(dirName); trouble = FATAL; goto done; } if (read(dfd, buffer, sizeof (short)) < 0) { PERR(dirName); trouble = FATAL; goto done; } if (buffer[0] || buffer[1]) ents[aDir - 1] = DEAD; } } close(dfd); dfd = 0; /* entries found. now, wade through .idx file, checking each ptr */ maybef(WantStatus, "Checking idx file against .dir list.\n"); sprintf(idxName, "%s.%s", Database, "idx"); sprintf(iovName, "%s.%s", Database, "iov"); if ((ifd = open(idxName, O_RDONLY)) == 0) { PERR(idxName); trouble = FATAL; goto done; } if ((iod = open(iovName, O_RDONLY)) == 0) { PERR(iovName); trouble = FATAL; goto done; } fstat(ifd, &s); if (s.st_size % sizeof (struct iindex)) T("%s: size is not a multiple of %d.\n", idxName, sizeof (struct iindex)); idxCount = s.st_size / sizeof (struct iindex); for (i = 1; i < idxCount; i++) { if (i % REP_INT == REP_INT - 1) maybef(WantStatus, "%-10d\r", i); if (lseek(ifd, i * sizeof (struct iindex), L_SET) < 0) { PERR(idxName); printf("idx %x\n", i); trouble = FATAL; goto done; } if (read(ifd, buffer, sizeof (struct iindex)) < 0) { PERR(idxName); printf("idx %x\n", i); trouble = FATAL; goto done; } if (!*buffer || *buffer == '\377') continue; /* empty... */ for (ptr = (int *) buffer; ptr < (int *) (buffer + sizeof (struct iindex)) - 1; ptr++) if (HASNULL(*ptr)) { for (ptr++; ptr < (int *) (buffer + sizeof (struct iindex)) - 1; ptr++) { if (!*ptr) break; if (ents[*ptr - 1] & DEAD) T("Index entry %x references dead entry %x.\n", i, *ptr); ents[*ptr - 1] |= REFERENCED; } } for (ptr = (int *) (buffer + sizeof (struct iindex)) - 1; *ptr;) { if (lseek(iod, *ptr * NOPTRS * PTRSIZE, L_SET) < 0) { PERR(iovName); T("Bad overflow pointer (%x) in idx chain %x.\n", *ptr, i); break; } if (read(iod, buffer, NOPTRS * PTRSIZE) < 0) { PERR(iovName); printf("idx %x\n", i); trouble = FATAL; goto done; } for (ptr = (int *) buffer; ptr < (int *) (buffer + NOPTRS * PTRSIZE) - 1; ptr++) { if (!*ptr) break; if (ents[*ptr - 1] & DEAD) T("Index chain %x references dead entry %x.\n", i, *ptr); ents[*ptr - 1] |= REFERENCED; } } } /* report on any "funny" dir entries */ for (d = ents; d < &ents[dirCount]; d++) switch (*d) { case REFERENCED: break; case DEAD: maybef(WantInfo, "INFO: entry %x is dead.\n", d - ents + 1); break; case DEAD | REFERENCED: T("Dead entry %x referenced.\n", d - ents + 1); break; case 0: T("Entry %x unreferenced.\n", d - ents + 1); break; default: printf("Internal error, entry %x (%x).\n", d - ents + 1, *d); break; } /* finished. clean up and return */ done: if (ifd) close(ifd); if (iod) close(iod); if (dfd) close(dfd); if (ents) free(ents); return (trouble); } /* * print a message (maybe) */ maybef(yes, fmt, a, b, c, d, e, f, g, h, i, j, l, m, n, o, p) int yes; char *fmt; unsigned a, b, c, d, e, f, g, h, i, j, l, m, n, o, p; { if (yes) printf(fmt, a, b, c, d, e, f, g, h, i, j, l, m, n, o, p); fflush(stdout); } /* * Check the consistency of the Idx and Iov files * - no unreferenced IOV entries * - no doubly-referenced IOV entries */ IdxIov() { int idx = 0, iov = 0; string idxName, iovName; string buffer; int *iovEnts = NULL; int trouble = FINE; int idxCount, iovCount; struct stat s; int i; register int *ent; sprintf(iovName, "%s.iov", Database); sprintf(idxName, "%s.idx", Database); if ((idx = open(idxName, O_RDONLY)) == 0) { PERR(idxName); trouble = FATAL; goto done; } if ((iov = open(iovName, O_RDONLY)) == 0) { PERR(iovName); trouble = FATAL; goto done; } /* set up and array to keep track of iov entries and references */ fstat(iov, &s); if (s.st_size % (PTRSIZE * NOPTRS)) T("%s: size not a multiple of %d.\n", iovName, PTRSIZE * NOPTRS); iovCount = s.st_size / (PTRSIZE * NOPTRS); if (!(iovEnts = (int *) malloc(iovCount * sizeof (int)))) { PERR("malloc iovEnts"); trouble = FATAL; goto done; } for (ent = iovEnts; ent - iovEnts < iovCount; ent++) *ent = 0; /* look through idx file for bad things */ fstat(idx, &s); idxCount = s.st_size / sizeof (struct iindex); /* put a NULL word at end of iindex buffer as a placemarker */ *(int *) (buffer + sizeof (struct iindex)) = 0; *(int *) (buffer + sizeof (struct iindex) + sizeof (int)) = 0; /* read the iindex entries */ maybef(WantStatus, "Checking idx for bad iov pointers.\n"); for (i = 0; i < idxCount; i++) { if (i % REP_INT == REP_INT - 1) maybef(WantStatus, "%-10d\r", i); if (read(idx, buffer, sizeof (struct iindex)) < 0) { PERR(idxName); trouble = ERROR; break; } if (!*buffer || *buffer == '\377') continue; /* empty... */ /* look for a NULL byte */ for (ent = (int *) buffer; !HASNULL(*ent); ent++) ; /* look for a NULL word */ for (ent++; *ent; ent++) ; if (ent - (int *) buffer == sizeof (struct iindex) / sizeof (int)) { ent--; /* we have an overflow pointer */ if (*ent < 0 || *ent >= iovCount) T("idx %x: overflow pointer out of range (%x).\n", i, *ent); else if (iovEnts[*ent]) T("idx %x: shares overflow %x with %x.\n", i, *ent, iovEnts[*ent]); else iovEnts[*ent] = i; } } close(idx); idx = 0; /* now for the iov entries */ maybef(WantStatus, "Checking iov for bad iov pointers.\n"); *(int *) (buffer + PTRSIZE * NOPTRS) = 0; for (i = 0; i < iovCount; i++) { if (i % REP_INT == REP_INT - 1) maybef(WantStatus, "%-10d\r", i); if (read(iov, buffer, PTRSIZE * NOPTRS) < 0) { PERR(iovName); trouble = ERROR; break; } /* look for a NULL word */ for (ent = (int *) buffer; *ent; ent++) ; if (ent - (int *) buffer == PTRSIZE * NOPTRS / sizeof (int)) { ent--; /* we have an overflow pointer */ if (*ent < 0 || *ent >= iovCount) T("iov %x: overflow pointer out of range (%x).\n", i, *ent); else if (iovEnts[*ent]) T("iov %x: shares overflow %x with %x.\n", i, *ent, iovEnts[*ent]); else iovEnts[*ent] = -i; } } /* let's have a look for unused iov entries */ if (WantInfo) for (i = 1; i < iovCount; i++) if (iovEnts[i] == 0) printf("%s: overflow block %x unused.\n", iovName, i); done: if (idx) close(idx); if (iov) close(iov); if (iovEnts) free(iovEnts); return (trouble); } /* * Check the consistency of the dir and dov files * - no unreferenced dov entries * - no doubly-referenced dov entries */ DirDov() { int dir = 0, dov = 0; string dirName, dovName; string buffer; int *dovEnts = NULL; int trouble = FINE; int dirCount, dovCount; struct stat s; int i; register int *ent; sprintf(dovName, "%s.dov", Database); sprintf(dirName, "%s.dir", Database); if ((dir = open(dirName, O_RDONLY)) == 0) { PERR(dirName); trouble = FATAL; goto done; } if ((dov = open(dovName, O_RDONLY)) == 0) { PERR(dovName); trouble = FATAL; goto done; } /* set up and array to keep track of dov entries and references */ fstat(dov, &s); if (s.st_size % DOVRSIZE) T("%s: size not a multiple of %d.\n", dovName, DOVRSIZE); dovCount = s.st_size / (DOVRSIZE); if (!(dovEnts = (int *) malloc(dovCount * sizeof (int)))) { PERR("malloc dovEnts"); trouble = FATAL; goto done; } for (ent = dovEnts; ent - dovEnts < dovCount; ent++) *ent = 0; /* look through dir file for bad things */ fstat(dir, &s); dirCount = s.st_size / DRECSIZE; /* put a NULL word at end of iindex buffer as a placemarker */ *(int *) (buffer + DRECSIZE) = 0; *(int *) (buffer + DRECSIZE + sizeof (int)) = 0; /* read the dir entries */ maybef(WantStatus, "Checking dir for bad dov pointers.\n"); ent = (int *) buffer; for (i = 0; i < dirCount; i++) { if (i % REP_INT == REP_INT - 1) maybef(WantStatus, "%-10d\r", i); if (read(dir, buffer, DRECSIZE) < 0) { PERR(dirName); trouble = ERROR; break; } if (buffer[16] || buffer[17]) continue; /* dead... */ /* look for a NULL byte */ if (*ent) { /* we have an overflow pointer */ if (*ent < 0 || *ent >= dovCount) T("dir %x: overflow pointer out of range (%x).\n", i, *ent); else if (dovEnts[*ent]) T("dir %x: shares overflow %x with %x.\n", i, *ent, dovEnts[*ent]); else dovEnts[*ent] = i; } } close(dir); dir = 0; /* now for the dov entries */ maybef(WantStatus, "Checking dov for bad dov pointers.\n"); ent = ((int *) (buffer + DOVRSIZE)) - 1; for (i = 0; i < dovCount; i++) { if (i % REP_INT == REP_INT - 1) maybef(WantStatus, "%-10d\r", i); if (read(dov, buffer, DOVRSIZE) < 0) { PERR(dovName); trouble = ERROR; break; } /* look for a NULL word */ if (*ent) { /* we have an overflow pointer */ if (*ent < 0 || *ent >= dovCount) T("dov %x: overflow pointer out of range (%x).\n", i, *ent); else if (dovEnts[*ent]) { if (dovEnts[*ent] > 0) T("dov %x: shares overflow %x with %x.\n", i, *ent, dovEnts[*ent]); else T("dov %x: shares overflow %x with dov %x.\n", i, *ent, -dovEnts[*ent]); } else dovEnts[*ent] = -i; } } /* let's have a look for unused dov entries */ if (WantInfo) for (i = 1; i < dovCount; i++) if (dovEnts[i] == 0) printf("%s: overflow block %x unused.\n", dovName, i); done: if (dir) close(dir); if (dov) close(dov); if (dovEnts) free(dovEnts); return (trouble); } @ 1.9 log @fcntl.h is normally in /usr/include . @ text @d2 40 @ 1.8 log @POSIX: index() -> strchr(). Now obtains proper owner/group from configuration files. Suggested by George Pavel. @ text @d39 1 a39 1 #include @ 1.7 log @Now can modify Strings[] like qi, e.g. prog -DATABASE=/tmp/foo . @ text @d39 2 a40 5 #ifdef SYSV # include #else /* !SYSV */ # include #endif /* SYSV */ d131 1 a131 1 if (equal = index(*argv, '=')) d137 1 a137 1 opt[1] = equal + 1; a203 2 #define RIGHT_OWNER "paul" #define RIGHT_GROUP "nameserv" d221 1 a221 1 if (!(pwent = getpwnam(RIGHT_OWNER))) d223 1 a223 1 printf("Proper owner \"%s\" does not exist!\n", RIGHT_OWNER); d229 1 a229 1 if (!(grent = getgrnam(RIGHT_GROUP))) d231 1 a231 1 printf("Proper group \"%s\" does not exist!\n", RIGHT_GROUP); @ 1.6 log @System 5 changes, 1 or more of #include instead of , define index/rindex replacements using strchr/strrchr, define L_SET, etc values if not present. @ text @d37 1 a37 1 #include a48 7 #include "db.h" #include "bintree.h" #ifdef __STDC__ #include #else char *malloc(); #endif a60 1 #define OPTIONS "is" /* the options we accept */ a82 2 extern char *optarg; /* courtesy of getopt */ extern int optind; /* ditto */ a113 1 int option; d120 6 a125 2 while ((option = getopt(argc, argv, OPTIONS)) != EOF) switch (option) d127 1 a127 1 case 'i': d130 1 a130 1 case 's': d133 22 d156 2 d160 2 a161 2 if (optind == argc) result = Nsck(Database); /* use configured database */ d163 1 a163 1 for (; optind < argc; optind++) d165 1 a165 1 (void) strncpy(Database, argv[optind], MAXPATHLEN-1); @ 1.5 log @*** empty log message *** @ text @d39 5 a43 1 #include d56 8 @ 1.4 log @Updated usage of Database. @ text @a130 1 (void) strcpy(Database, DATABASE); @ 1.3 log @Random fixes. @ text @d41 1 d131 1 d133 1 a133 1 result = Nsck(Database); /* use the configured database */ d135 3 a137 1 for (Database = argv[optind]; optind < argc; optind++, Database = argv[optind]) d139 1 @ 1.2 log @Re-formatted for clarity @ text @d46 5 @ 1.1 log @Initial revision @ text @d1 1 a1 1 /************************************************************************ d5 1 a5 1 * d22 1 a22 1 * d31 1 a31 1 * d36 1 a36 1 ************************************************************************/ d47 1 a47 1 /************************************************************************ d49 1 a49 1 ************************************************************************/ d57 1 d63 1 a63 1 /************************************************************************ d65 1 a65 2 ************************************************************************/ char *malloc(), *realloc(); d67 1 a67 1 /************************************************************************ d69 1 a69 1 ************************************************************************/ d71 2 a72 2 int WantInfo=0; /* do we want info messages? */ int WantStatus=0; /* do we want status messages? */ d79 1 a79 1 /************************************************************************ d81 1 a81 1 ************************************************************************/ d84 3 a86 3 char *name; /* name (for humans) of check */ int (*func)(); /* function implementing check */ } Check; d88 1 a88 1 int Files(), IdxDir(), IdxIov(), DirDov(); d90 1 a90 1 Check Checks[]= d92 5 a96 5 "Files and Permissions", Files, "IDX/DIR Consistency", IdxDir, "IDX/IOV Consistency", IdxIov, "DIR/DOV Consistency", DirDov, 0, 0 d99 1 a99 1 /************************************************************************ d101 1 a101 1 ************************************************************************/ d103 2 a104 2 int argc; char **argv; d106 26 a131 22 int option; int result; /* when you're strange, no one remembers your name */ Me = *argv; /* process options */ while ((option = getopt(argc, argv, OPTIONS)) != EOF) switch(option) { case 'i': WantInfo = 1; break; case 's': WantStatus = 1; break; } /* process database(s) */ if (optind==argc) result = Nsck(Database); /* use the configured database */ else for (Database=argv[optind]; optind < argc; optind++,Database=argv[optind]) result = (result << 1) | Nsck(); exit(result); d134 1 a134 1 /************************************************************************ d136 1 a136 1 ************************************************************************/ d139 23 a161 23 int trouble = 0; Check *theCheck; printf("\n%s:\n",Database); for (theCheck=Checks; theCheck->name; theCheck++) { printf("%s:\n",theCheck->name); switch((*theCheck->func)()) { case FATAL: printf("%s: Giving up\n",Database); return(1); break; case ERROR: trouble = 1; break; case FINE: break; } } return(trouble); d164 1 a164 1 /************************************************************************ d167 1 a167 1 ************************************************************************/ d169 1 a169 1 #define RIGHT_OWNER "dorner" d173 51 a223 53 int trouble = 0; static char *extensions[]={"bdx","seq","idx","iov","dir","dov",0}; string filename; char **x; struct stat s; static int nsuid = -1; static int nsgid = -1; /* figure out proper uid and gid */ if (nsuid < 0) { struct passwd *pwent; struct group *grent; if (!(pwent = getpwnam(RIGHT_OWNER))) { printf("Proper owner \"%s\" does not exist!\n",RIGHT_OWNER); trouble = ERROR; nsuid = 0; } else nsuid = pwent->pw_uid; if (!(grent = getgrnam(RIGHT_GROUP))) { printf("Proper group \"%s\" does not exist!\n",RIGHT_GROUP); trouble = ERROR; nsgid = 0; } else nsgid = grent->gr_gid; } /* now check the files */ for (x=extensions; *x; x++) { sprintf(filename,"%s.%s",Database,*x); if (stat(filename,&s)) { PERR(filename); trouble = FATAL; } else { if (s.st_uid != nsuid) T("%s: owner %d not %d\n",filename,s.st_uid,nsuid); if (s.st_gid != nsgid) T("%s: group %d not %d\n",filename,s.st_gid,nsgid); if (s.st_mode != RIGHT_MODE) T("%s: mode %o not %o\n",filename,s.st_mode,RIGHT_MODE); } } return(trouble); d226 1 a226 1 /************************************************************************ d229 1 a229 1 ************************************************************************/ d232 195 a426 142 int trouble = FINE; int dirCount, idxCount; int i; char *ents=NULL; string dirName, idxName, iovName; string buffer; int dfd=0, ifd=0, iod=0; register int *ptr; struct stat s; int aDir; register char *d; /* * first, we find out how many entries are in the .dir file, * and collect the numbers of all the deleted entries. Along * the way, we test the size of the .dir file */ sprintf(dirName,"%s.%s",Database,"dir"); if ((dfd=open(dirName,O_RDONLY))==0) { PERR(dirName); return(FATAL); } if (read(dfd, buffer, sizeof(int))<0) {PERR(dirName); trouble=FATAL; goto done;} dirCount = *((int *)buffer); fstat(dfd,&s); i = s.st_size/DRECSIZE; if (s.st_size % DRECSIZE) T("%s: size is not a multiple of %d.\n",dirName,DRECSIZE); if (dirCount != i) { T("%s:number of entries is %d; file size indicates %d.\n",dirCount,i); dirCount = i; } /* now, gather entries */ maybef(WantStatus,"Gathering entry information.\n"); if (dirCount) { ents = malloc(dirCount); if (!ents) {printf("malloc FAILED! Sheesh!\n"); trouble=FATAL; goto done;} for (d=ents;d= iovCount) T("idx %x: overflow pointer out of range (%x).\n",i,*ent); else if (iovEnts[*ent]) T("idx %x: shares overflow %x with %x.\n",i,*ent,iovEnts[*ent]); else iovEnts[*ent] = i; } } close(idx); idx = 0; /* now for the iov entries */ maybef(WantStatus,"Checking iov for bad iov pointers.\n"); *(int *)(buffer+PTRSIZE*NOPTRS) = 0; for (i=0; i= iovCount) T("iov %x: overflow pointer out of range (%x).\n",i,*ent); else if (iovEnts[*ent]) T("iov %x: shares overflow %x with %x.\n",i,*ent,iovEnts[*ent]); else iovEnts[*ent] = -i; } } /* let's have a look for unused iov entries */ if (WantInfo) for (i=1;i= dovCount) T("dir %x: overflow pointer out of range (%x).\n",i,*ent); else if (dovEnts[*ent]) T("dir %x: shares overflow %x with %x.\n",i,*ent,dovEnts[*ent]); else dovEnts[*ent] = i; } } close(dir); dir = 0; /* now for the dov entries */ maybef(WantStatus,"Checking dov for bad dov pointers.\n"); ent = ((int *)(buffer+DOVRSIZE))-1; for (i=0; i= dovCount) T("dov %x: overflow pointer out of range (%x).\n",i,*ent); else if (dovEnts[*ent]) { if (dovEnts[*ent]>0) T("dov %x: shares overflow %x with %x.\n",i,*ent, dovEnts[*ent]); else T("dov %x: shares overflow %x with dov %x.\n",i,*ent,-dovEnts[*ent]); } else dovEnts[*ent] = -i; } } /* let's have a look for unused dov entries */ if (WantInfo) for (i=1;i