extern struct s1 *getnode_bynodeid (long nodeid)
{
struct s2 *nlist;
int found;
int h;
h = nodeid % PRIME2;
/* NOT assuming that the lists in a2 are sorted; though it'd be faster */
for (found=0, nlist = a2[h]; !found && nlist != NULL;) {
if (nodeid == nlist->nodeid)
found = 1;
else
nlist = nlist->nextnode;
}
/*
MODIFIED make_link_block code from MIT (it had a bug) --lam
*/
static long * make_link_block (char links[], short *linkcnt, int chknodeids)
{
char *cp;
int numlink;
long *nid_block;
int chadded;
int c, c2;
long nid;
short repeat;
short nodexists;
struct s1 *tempnode;
/* add node to array 1. */
static void a1_add (struct s1 *nd)
{
int h;
h = ghash (nd->gophertitle, nd->gopherserver, nd->gopherport, nd->gopherpath);
nd->nextnode = a1[h];
/* add nd to the beginning of the list */
a1[h] = nd;
return;
}
if (is_reserved_node(nodeid)) {
fprintf (stderr, "load_gopher_node: %d is reserved nodeid\n", nodeid);
return (struct s1 *) NULL;
}
else if (GW_NODE_UNUSED(lastused)) {
fprintf (stderr, "load_gopher_node: Nodeid %d last used %d, too old.\n",
nodeid, lastused);
return (struct s1 *) NULL;
}
else {
parsefields (gophernodestr[2],gofields,&numf,GOPHER_DLM,NUMFIELDS_GOPHER);
if (numf < NUMFIELDS_GOPHER) { /* gopher info not parseable */
fprintf (stderr, "Only %d Gopher fields in %s\n",
numf, gophernodestr[2]);
return (struct s1 *) NULL;
}
else
return(init_gopher_node(gofields, nodeid, lastused, 1));
}
}
void gophernodes_unload ()
{
int i, numunloaded;
struct s1 *temp1, *temp2;
struct s2 *temp3, *temp4;
for (i = 0, numunloaded = 0; i < PRIME1; i++) {
for (temp1 = a1[i]; temp1 != NULL; temp1 = temp2 ) {
temp2 = temp1->nextnode;
/* free the char data as well... */
do_free(temp1->gophertitle);
do_free(temp1->gopherserver);
do_free(temp1->gopherpath);
do_free(temp1->gopherport);
free (temp1);
numunloaded++;
}
}
if (debug)
fprintf (stderr, "Freed %d gopher nodes\n", numunloaded);
for (i = 0; i < PRIME2; i++) {
for (temp3 = a2[i]; temp3 != NULL; ) {
temp4 = temp3->nextnode;
free (temp3); /* there's no other data to worry about here */
temp3 = temp4;
}
}
numgophnodes = 0;
}
int gophernodes_load(int unloadfirst)
{
#define ADAY 86400
int numf;
char *gonodefields[NUMFIELDS_GOPHNODES];
int numlines = 0;
FILE *gophernodesfile;
char line[NLINE_MAXLEN];
/* Two arrays of pointers to nodes. Make them all null to start with */
init_arrays ()
{
long i;
for (i = 0; i < PRIME1; i++)
a1[i] = (struct s1 *) NULL;
for (i = 0; i < PRIME2; i++)
a2[i] = (struct s2 *) NULL;
}
/* Load reserved nodes table, gopher nodes tables */
/* maybe add option to load one or the other & not both from disk */
int datastruct_load (int unloadfirst)
{
int okay;
okay = gophernodes_load(unloadfirst);
/*
get gopher nodes loaded first so that when reserved nodes are loaded,
no unknown gopher nodes will be added to the reserved table
*/
void cleancache(void) /* any files whose mtime is older than cache timeout
should be removed */
{
DIR *cachedir;
struct direct *nextfile;
struct stat stbuf;
char filename[MAXPATHLEN];
long now;
int numrm;
/* fprintf (stderr, "Removing old files from %s...", CACHEDIR); */
cachedir = opendir(CACHEDIR);
if (cachedir == NULL) /* cache directory is not being used */
return;
now = time (0);
numrm = 0;
while ( (nextfile = readdir(cachedir)) != NULL ) {
if (strcmp (".", nextfile->d_name) != 0 &&
strcmp ("..", nextfile->d_name) != 0) {
sprintf (filename, "%s%s", CACHEDIR, nextfile->d_name);
if (stat(filename, &stbuf) >= 0
&& (now - stbuf.st_mtime) > CACHETIMEOUT) {
unlink (filename);
numrm++;
}
}
}
(int) closedir(cachedir);
if (numrm)
fprintf (stderr, "T=%d. Removed %d files from the cache\n", time(0),numrm);
}
/* Safekeeping:
If an unreserved node _is_ a child of a reserved
node, then it is safe, even if it hasn't been used
for a while.
*/
static void get_safekeeping (long **safe, int *numsafe)
{
int r, c;
int maxsafe;
/* first, we figure out the max # of nodes that could be safe */
for (r = 0, maxsafe = 0; r < numresvnodes; r++)
maxsafe += reservednodes[r].numchildren;
for (r = 0, maxsafe = 0; r < numresvnodes; r++) {
for (c = 0; c < reservednodes[r].numchildren; c++) {
if ( ! is_reserved_node(reservednodes[r].children[c] ) ) {
(*safe)[*numsafe] = reservednodes[r].children[c];
(*numsafe)++;
}
}
}
}
/* a2 is the nodeid table.
Using the given nodeid, find the corresponding struct s2
in the nodeid table and remove it from the table
*/
static void removenode_nodeidtab (long nodeid)
{
int h, done;
struct s2 *nd, *b4, *tmp;
h = nodeid % PRIME2;
for (done = 0, b4 = NULL, nd = a2[h]; !done && nd != NULL; ) {
if (nodeid == nd->nodeid) {
done = 1;
if (b4 == NULL)
a2[h] = nd->nextnode; /* nd was the first on the list */
else
b4->nextnode = nd->nextnode;
/* remove unused should be improved so that it checks to see if
todaysdate has changed since the last time nodes were removed
from the tables because the granularity is a day; it's more
efficient to avoid checking thousands of nodes unnecessarily */
static void remove_unused(void)
{
int n;
struct s1 *node, *b4, *temp;
long *safelist;
int numsafe;
int s, is_safe;
sigset_t prev_sigmask;
sigset_t new_sigmask;
sigset_t temp_sigmask;
int numremoved = 0;
/* block Children from interrupting this delicate stuff */
sigprocmask (SIG_SETMASK, (sigset_t *)NULL, &prev_sigmask);
new_sigmask = prev_sigmask | SIGCHLD;
sigprocmask (SIG_SETMASK, &new_sigmask, NULL);
/* sigprocmask (SIG_SETMASK, NULL, &temp_sigmask);
fprintf (stderr, "Signal mask has been set to %d.\n", temp_sigmask); */
get_safekeeping(&safelist, &numsafe);
for (n = 0; n < PRIME1; n++) {
for (node = a1[n], b4=NULL; node != (struct s1 *) NULL; )
{
if ( ! GW_NODE_UNUSED(node->lastused) ) {
b4 = node;
node = node->nextnode;
}
else {
for (s = 0, is_safe = 0; s < numsafe && !is_safe; s++)
if (safelist[s] == node->nodeid) is_safe = 1;
if ( is_safe ) {
b4 = node;
node = node->nextnode;
}
else { /* node should be removed from the tables */
fprintf (stderr, "rm %d (%d)\n",
node->nodeid, node->lastused);
numremoved++;
removenode_nodeidtab (node->nodeid);
if (b4 == NULL) /* node was the first on the list */
a1[n] = node->nextnode;
else
b4->nextnode = node->nextnode;
/* leave b4 as it is... */
temp = node;
node = node->nextnode;
free(temp); /* Get rid of old node */
}
}
}
}
if (safelist)
free (safelist);
tables_changed += numremoved;
/* okay, set the signal mask back to whatever it was */
sigprocmask (SIG_SETMASK, &prev_sigmask, NULL);
if (numremoved)
fprintf (stderr, "Removed %d nodes from tables\n", numremoved);
}
static void save_gwnodes (char *tempfilename)
{
FILE *tempfile;
int n;
int g = 0;
struct s1 *node;
tempfile = fopen (tempfilename, "w");
if (tempfile == NULL) { /* we're in trouble... */
fprintf (stderr, "Unable to write gopher nodes temp file\n");
perror (tempfilename);
}
else {
fprintf (stderr, "%d: Saving gateway nodes to tempfile %s\n",
getpid(), tempfilename);
for (n = 0; n < PRIME1; n++) {
for (node = a1[n]; node != (struct s1 *) NULL; node=node->nextnode)
{/* go down the list writing out the data to temp file */
/* rename() requires the two files to be on the same file system */
rename(GW_NODES_FILE, GW_NODES_BAK_FILE);
rename(tempfilename, GW_NODES_FILE);
chmod(GW_NODES_FILE,0644);
fprintf(stderr, "%d: wrote %d gopher nodes to disk\n", getpid(), g);
}
}
/* write gophernodes arrays out to disk */
void save_datastruct ()
{
char *tempfilename;
int forkstat;
union wait status;
struct rusage rusage;
(void) cleancache(); /* parent cleans the cache */
remove_unused(); /* get rid of useless nodeids in the tables */
/* Because these variables need to be known by the parent,
the child cannot update them */
tables_changed = 0;
addednewnodes = 0;
lastused_changed = 0;
/* generate temporary file name */
tempfilename = tempnam(GW_NODES_DIR, "gwnodes");
forkstat = fork();
if (forkstat != 0)
signal(SIGCHLD, catch_child);