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.
*/
/*
* 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 <sys/types.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <grp.h>
#include <pwd.h>
#include "conf.h"
/*
* 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 */
/*
* 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;
/*
* 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;
/* 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 <sys/fcntl.h>
@
1.7
log
@Now can modify Strings[] like qi, e.g. prog -DATABASE=/tmp/foo .
@
text
@d39 2
a40 5
#ifdef SYSV
# include <sys/fcntl.h>
#else /* !SYSV */
# include <sys/file.h>
#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 <sys/fcntl.h> instead of <sys/file.h>,
define index/rindex replacements using strchr/strrchr, define L_SET, etc
values if not present.
@
text
@d37 1
a37 1
#include <stdio.h>
a48 7
#include "db.h"
#include "bintree.h"
#ifdef __STDC__
#include <stdlib.h>
#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.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();
/* 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<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);
d429 1
a429 1
/************************************************************************
d431 5
a435 5
************************************************************************/
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;
d437 3
a439 2
if (yes) printf(fmt,a,b,c,d,e,f,g,h,i,j,l,m,n,o,p);
fflush(stdout);
d442 1
a442 1
/************************************************************************
d446 1
a446 1
************************************************************************/
d449 122
a570 94
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);
d573 1
a573 1
/************************************************************************
d577 1
a577 1
************************************************************************/
d580 121
a700 94
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);
@