993 lines
19 KiB
C
993 lines
19 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Nodelist Compiler
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2002
|
|
*
|
|
* Michiel Broek FIDO: 2:280/2802
|
|
* Beekmansbos 10
|
|
* 1971 BV IJmuiden
|
|
* the Netherlands
|
|
*
|
|
* This file is part of MBSE BBS.
|
|
*
|
|
* This BBS is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* MBSE BBS is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MBSE BBS; see the file COPYING. If not, write to the Free
|
|
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/libs.h"
|
|
#include "../lib/memwatch.h"
|
|
#include "../lib/structs.h"
|
|
#include "../lib/users.h"
|
|
#include "../lib/records.h"
|
|
#include "../lib/common.h"
|
|
#include "../lib/clcomm.h"
|
|
#include "../lib/dbcfg.h"
|
|
#include "../lib/dbftn.h"
|
|
|
|
|
|
#define TMPNAME "TMP."
|
|
#define LCKNAME "LOCKFILE"
|
|
|
|
|
|
typedef struct _nl_list {
|
|
struct _nl_list *next;
|
|
struct _nlidx idx;
|
|
} nl_list;
|
|
|
|
|
|
#include "mbindex.h"
|
|
|
|
|
|
FILE *ifp, *ufp, *ffp;
|
|
long total = 0, entries = 0;
|
|
int filenr = 0;
|
|
unsigned short regio;
|
|
nl_list *nll = NULL;
|
|
static char lockfile[81];
|
|
|
|
|
|
extern int do_quiet; /* Quiet flag */
|
|
extern int show_log; /* Show logging on screen */
|
|
time_t t_start; /* Start time */
|
|
time_t t_end; /* End time */
|
|
|
|
|
|
/*
|
|
* Put a lock on this program.
|
|
*/
|
|
int lockindex(void)
|
|
{
|
|
char Tmpfile[81];
|
|
FILE *fp;
|
|
pid_t oldpid;
|
|
|
|
sprintf(Tmpfile, "%s/", CFG.nodelists);
|
|
strcpy(lockfile, Tmpfile);
|
|
sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid());
|
|
sprintf(lockfile + strlen(lockfile), "%s", LCKNAME);
|
|
|
|
if ((fp = fopen(Tmpfile, "w")) == NULL) {
|
|
WriteError("$Can't create lockfile \"%s\"", Tmpfile);
|
|
return 1;
|
|
}
|
|
fprintf(fp, "%10u\n", getpid());
|
|
fclose(fp);
|
|
|
|
while (TRUE) {
|
|
if (link(Tmpfile, lockfile) == 0) {
|
|
unlink(Tmpfile);
|
|
return 0;
|
|
}
|
|
if ((fp = fopen(lockfile, "r")) == NULL) {
|
|
WriteError("$Can't open lockfile \"%s\"", Tmpfile);
|
|
unlink(Tmpfile);
|
|
return 1;
|
|
}
|
|
if (fscanf(fp, "%u", &oldpid) != 1) {
|
|
WriteError("$Can't read old pid from \"%s\"", Tmpfile);
|
|
fclose(fp);
|
|
unlink(Tmpfile);
|
|
return 1;
|
|
}
|
|
fclose(fp);
|
|
if (kill(oldpid,0) == -1) {
|
|
if (errno == ESRCH) {
|
|
Syslog('+', "Stale lock found for pid %u", oldpid);
|
|
unlink(lockfile);
|
|
/* no return, try lock again */
|
|
} else {
|
|
WriteError("$Kill for %u failed",oldpid);
|
|
unlink(Tmpfile);
|
|
return 1;
|
|
}
|
|
} else {
|
|
Syslog('+', "mbindex already running, pid=%u", oldpid);
|
|
if (!do_quiet)
|
|
printf("Another mbindex is already running.\n");
|
|
unlink(Tmpfile);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ulockindex(void)
|
|
{
|
|
if (lockfile)
|
|
(void)unlink(lockfile);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* If we don't know what to type
|
|
*/
|
|
void Help(void)
|
|
{
|
|
do_quiet = FALSE;
|
|
ProgName();
|
|
|
|
colour(11, 0);
|
|
printf("\nUsage: mbindex <options>\n\n");
|
|
colour(9, 0);
|
|
printf(" Options are:\n\n");
|
|
colour(3, 0);
|
|
printf(" -quiet Quiet mode\n");
|
|
colour(7, 0);
|
|
printf("\n");
|
|
die(0);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Header, only if not quiet.
|
|
*/
|
|
void ProgName(void)
|
|
{
|
|
if (do_quiet)
|
|
return;
|
|
|
|
colour(15, 0);
|
|
printf("\nMBINDEX: MBSE BBS %s Nodelist Index Compiler\n", VERSION);
|
|
colour(14, 0);
|
|
printf(" %s\n", COPYRIGHT);
|
|
colour(3, 0);
|
|
}
|
|
|
|
|
|
|
|
void die(int onsig)
|
|
{
|
|
if (onsig && (onsig < NSIG))
|
|
signal(onsig, SIG_IGN);
|
|
|
|
ulockindex();
|
|
|
|
if (!do_quiet) {
|
|
colour(3, 0);
|
|
show_log = TRUE;
|
|
}
|
|
|
|
if (IsSema((char *)"mbindex"))
|
|
RemoveSema((char *)"mbindex");
|
|
|
|
if (onsig) {
|
|
if (onsig <= NSIG)
|
|
WriteError("Terminated on signal %d (%s)", onsig, SigName[onsig]);
|
|
else
|
|
WriteError("Terminated with error %d", onsig);
|
|
}
|
|
|
|
t_end = time(NULL);
|
|
Syslog(' ', "MBINDEX finished in %s", t_elapsed(t_start, t_end));
|
|
|
|
if (!do_quiet)
|
|
colour(7, 0);
|
|
|
|
ExitClient(onsig);
|
|
}
|
|
|
|
|
|
|
|
int main(int argc,char *argv[])
|
|
{
|
|
int i, rc;
|
|
char *cmd;
|
|
struct passwd *pw;
|
|
|
|
#ifdef MEMWATCH
|
|
mwInit();
|
|
#endif
|
|
InitConfig();
|
|
InitFidonet();
|
|
TermInit(1);
|
|
t_start = time(NULL);
|
|
umask(002);
|
|
|
|
/*
|
|
* Catch all the signals we can, and ignore the rest.
|
|
* Don't listen to SIGTERM.
|
|
*/
|
|
for(i = 0; i < NSIG; i++) {
|
|
|
|
if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV))
|
|
signal(i, (void (*))die);
|
|
else
|
|
signal(i, SIG_IGN);
|
|
}
|
|
|
|
cmd = xstrcpy((char *)"Command line: mbindex");
|
|
|
|
if (argc > 2)
|
|
Help();
|
|
|
|
if (argc == 2) {
|
|
cmd = xstrcat(cmd, (char *)" ");
|
|
cmd = xstrcat(cmd, argv[1]);
|
|
|
|
if (strncasecmp(argv[1], "-q", 2) == 0)
|
|
do_quiet = TRUE;
|
|
else
|
|
Help();
|
|
}
|
|
|
|
ProgName();
|
|
pw = getpwuid(getuid());
|
|
InitClient(pw->pw_name, (char *)"mbindex", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log, CFG.mgrlog);
|
|
|
|
Syslog(' ', " ");
|
|
Syslog(' ', "MBINDEX v%s", VERSION);
|
|
Syslog(' ', cmd);
|
|
free(cmd);
|
|
|
|
if (!diskfree(CFG.freespace))
|
|
die(101);
|
|
|
|
if (lockindex()) {
|
|
if (!do_quiet)
|
|
printf("Can't lock mbindex, abort.\n");
|
|
die(104);
|
|
}
|
|
|
|
rc = nodebld();
|
|
die(rc);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void tidy_nllist(nl_list **fap)
|
|
{
|
|
nl_list *tmp, *old;
|
|
|
|
Syslog('S', "tidy_nllist");
|
|
for (tmp = *fap; tmp; tmp = old) {
|
|
old = tmp->next;
|
|
free(tmp);
|
|
}
|
|
*fap = NULL;
|
|
}
|
|
|
|
|
|
|
|
int in_nllist(struct _nlidx idx, nl_list **fap, int replace)
|
|
{
|
|
nl_list *tmp;
|
|
|
|
Syslog('S', "Seeking nlidx match for %u:%u/%u.%u", idx.zone, idx.net, idx.node, idx.point);
|
|
|
|
for (tmp = *fap; tmp; tmp = tmp->next)
|
|
if ((tmp->idx.zone == idx.zone) && (tmp->idx.net == idx.net) &&
|
|
(tmp->idx.node == idx.node) && (tmp->idx.point == idx.point)) {
|
|
Syslog('S', "Match found");
|
|
if (replace) {
|
|
tmp->idx = idx;
|
|
entries++;
|
|
}
|
|
regio = tmp->idx.region;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
void fill_nllist(struct _nlidx idx, nl_list **fap)
|
|
{
|
|
nl_list *tmp;
|
|
|
|
Syslog('S', "fill_nllist %u:%u/%u.%u", idx.zone, idx.net, idx.node, idx.point);
|
|
tmp = (nl_list *)malloc(sizeof(nl_list));
|
|
tmp->next = *fap;
|
|
tmp->idx = idx;
|
|
*fap = tmp;
|
|
total++;
|
|
entries++;
|
|
}
|
|
|
|
|
|
|
|
char *fullpath(char *fname)
|
|
{
|
|
static char path[128];
|
|
|
|
sprintf(path, "%s/%s", CFG.nodelists, fname);
|
|
return path;
|
|
}
|
|
|
|
|
|
|
|
void sort_nllist(nl_list **fap)
|
|
{
|
|
nl_list *ta, **vector;
|
|
size_t n = 0, i;
|
|
|
|
if (*fap == NULL)
|
|
return;
|
|
|
|
for (ta = *fap; ta; ta = ta->next)
|
|
n++;
|
|
|
|
vector = (nl_list **)malloc(n * sizeof(nl_list *));
|
|
Syslog('s', "Sorting %d nodelist entries", n);
|
|
|
|
i = 0;
|
|
for (ta = *fap; ta; ta = ta->next) {
|
|
vector[i++] = ta;
|
|
Syslog('S', "Before %u:%u/%u.%u", ta->idx.zone, ta->idx.net, ta->idx.node, ta->idx.point);
|
|
}
|
|
|
|
qsort(vector, n, sizeof(nl_list *),
|
|
(int(*)(const void*, const void *))comp_node);
|
|
|
|
(*fap) = vector[0];
|
|
i = 1;
|
|
|
|
for (ta = *fap; ta; ta = ta->next) {
|
|
if (i < n)
|
|
ta->next = vector[i++];
|
|
else
|
|
ta->next = NULL;
|
|
Syslog('S', "After %u:%u/%u.%u", ta->idx.zone, ta->idx.net, ta->idx.node, ta->idx.point);
|
|
}
|
|
|
|
free(vector);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
int comp_node(nl_list **fap1, nl_list **fap2)
|
|
{
|
|
if ((*fap1)->idx.zone != (*fap2)->idx.zone)
|
|
return ((*fap1)->idx.zone - (*fap2)->idx.zone);
|
|
else if ((*fap1)->idx.net != (*fap2)->idx.net)
|
|
return ((*fap1)->idx.net - (*fap2)->idx.net);
|
|
else if ((*fap1)->idx.node != (*fap2)->idx.node)
|
|
return ((*fap1)->idx.node - (*fap2)->idx.node);
|
|
else
|
|
return ((*fap1)->idx.point - (*fap2)->idx.point);
|
|
}
|
|
|
|
|
|
|
|
int compile(char *nlname, unsigned short zo, unsigned short ne, unsigned short no)
|
|
{
|
|
int num, i, rc = 0;
|
|
int lineno, boss = FALSE, bossvalid = FALSE;
|
|
unsigned short upnet, upnode;
|
|
char buf[256], *p, *q;
|
|
faddr *tmpa;
|
|
FILE *nl;
|
|
struct _nlidx ndx;
|
|
struct _nlusr udx;
|
|
|
|
rc = 0;
|
|
if ((nl = fopen(fullpath(nlname), "r")) == NULL) {
|
|
WriteError("$Can't open %s", fullpath(nlname));
|
|
return 102;
|
|
}
|
|
|
|
Syslog('+', "Compiling \"%s\" (%d)", nlname, filenr);
|
|
IsDoing("Compile NL %d", filenr +1);
|
|
|
|
memset(&ndx, 0, sizeof(ndx));
|
|
ndx.type = NL_NODE;
|
|
ndx.fileno = filenr;
|
|
upnet = 0;
|
|
upnode = 0;
|
|
|
|
/*
|
|
* If zone is set, it is a overlay segment
|
|
*/
|
|
if (zo) {
|
|
ndx.zone = zo;
|
|
ndx.net = ne;
|
|
ndx.node = no;
|
|
ndx.point = 0;
|
|
}
|
|
entries = 0;
|
|
lineno = 0;
|
|
|
|
while (!feof(nl)) {
|
|
|
|
Nopper();
|
|
ndx.offset = ftell(nl);
|
|
lineno++;
|
|
if (fgets(buf, sizeof(buf)-1, nl) == NULL)
|
|
continue;
|
|
|
|
/*
|
|
* Next check at <lf> and <eof> characters
|
|
*/
|
|
if ((*(buf+strlen(buf) -1) != '\n') && (*(buf + strlen(buf) -1) != '\012')) {
|
|
while (fgets(buf, sizeof(buf) -1, nl) &&
|
|
(*(buf + strlen(buf) -1) != '\n')) /*void*/;
|
|
if (strlen(buf) > 1) /* Suppress EOF character */
|
|
Syslog('s', "Nodelist: too long line junked (%d)", lineno);
|
|
continue;
|
|
}
|
|
|
|
if (*(p=buf+strlen(buf) -1) == '\n')
|
|
*p-- = '\0';
|
|
if (*p == '\r')
|
|
*p = '\0';
|
|
if ((buf[0] == ';') || (buf[0] == '\032') || (buf[0] == '\0'))
|
|
continue;
|
|
|
|
if (CFG.slow_util && do_quiet) {
|
|
if (zo) {
|
|
usleep(1);
|
|
} else {
|
|
if ((lineno % 40) == 0)
|
|
usleep(1);
|
|
}
|
|
}
|
|
|
|
if ((p = strchr(buf, ',')))
|
|
*p++ = '\0';
|
|
if ((q = strchr(p, ',')))
|
|
*q++ = '\0';
|
|
|
|
ndx.type = NL_NONE;
|
|
ndx.pflag = 0;
|
|
|
|
if (buf[0] == '\0') {
|
|
if (boss)
|
|
ndx.type = NL_POINT;
|
|
else
|
|
ndx.type = NL_NODE;
|
|
} else
|
|
if (strcasecmp(buf,"Boss") == 0) {
|
|
ndx.type = NL_POINT;
|
|
bossvalid = FALSE;
|
|
if ((tmpa=parsefnode(p)) == NULL) {
|
|
WriteError("%s(%u): unparsable Boss addr \"%s\"",
|
|
nlname,lineno,p);
|
|
continue;
|
|
}
|
|
boss = TRUE;
|
|
if (tmpa->zone)
|
|
ndx.zone = tmpa->zone;
|
|
ndx.net = tmpa->net;
|
|
ndx.node = tmpa->node;
|
|
ndx.point = 0;
|
|
tidy_faddr(tmpa);
|
|
Syslog('S', "Boss %u:%u/%u", ndx.zone, ndx.net, ndx.node);
|
|
ndx.type = NL_NONE;
|
|
|
|
if (in_nllist(ndx, &nll, FALSE)) {
|
|
Syslog('S', "Boss exists");
|
|
bossvalid = TRUE;
|
|
}
|
|
else
|
|
Syslog('S', "Boss not found");
|
|
continue; /* no further processing */
|
|
} else {
|
|
boss = FALSE;
|
|
ndx.type = NL_NONE;
|
|
if (!strcasecmp(buf, "Down")) {
|
|
ndx.pflag |= NL_DOWN;
|
|
ndx.type = NL_NODE;
|
|
}
|
|
if (!strcasecmp(buf, "Hold")) {
|
|
ndx.pflag |= NL_HOLD;
|
|
ndx.type = NL_NODE;
|
|
}
|
|
if (!strcasecmp(buf, "Pvt")) {
|
|
ndx.pflag |= NL_PVT;
|
|
ndx.type = NL_NODE;
|
|
}
|
|
|
|
if (!strcasecmp(buf, "Zone"))
|
|
ndx.type = NL_ZONE;
|
|
if (!strcasecmp(buf, "Region"))
|
|
ndx.type = NL_REGION;
|
|
if (!strcasecmp(buf, "Host"))
|
|
ndx.type = NL_HOST;
|
|
if (!strcasecmp(buf, "Hub"))
|
|
ndx.type = NL_HUB;
|
|
if (!strcasecmp(buf, "Point")) {
|
|
ndx.type = NL_POINT;
|
|
bossvalid = TRUE;
|
|
}
|
|
}
|
|
|
|
if (ndx.type == NL_NONE) {
|
|
for (q = buf; *q; q++)
|
|
if (*q < ' ')
|
|
*q='.';
|
|
WriteError("%s(%u): unidentified entry \"%s\"",
|
|
nlname, lineno, buf);
|
|
continue;
|
|
}
|
|
|
|
Syslog('S',"Got \"%s\" as \"%s\" typ %d", buf, p, ndx.type);
|
|
if ((num=atoi(p)) == 0) {
|
|
WriteError("%s(%u): bad numeric \"%s\"",
|
|
nlname,lineno,p);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* now update the current address
|
|
*/
|
|
switch (ndx.type) {
|
|
case NL_REGION: ndx.net = num;
|
|
ndx.node = 0;
|
|
ndx.point = 0;
|
|
ndx.upnet = ndx.zone;
|
|
ndx.upnode= 0;
|
|
ndx.region= num;
|
|
upnet = num;
|
|
upnode = 0;
|
|
break;
|
|
case NL_ZONE: ndx.zone = num;
|
|
ndx.net = num;
|
|
ndx.node = 0;
|
|
ndx.point = 0;
|
|
ndx.upnet = 0;
|
|
ndx.upnode= 0;
|
|
ndx.region= 0;
|
|
upnet = num;
|
|
upnode = 0;
|
|
break;
|
|
case NL_HOST: ndx.net = num;
|
|
ndx.node = 0;
|
|
ndx.point = 0;
|
|
ndx.upnet = ndx.region;
|
|
ndx.upnode= 0;
|
|
upnet = num;
|
|
upnode = 0;
|
|
break;
|
|
case NL_HUB: ndx.node = num;
|
|
ndx.point = 0;
|
|
ndx.upnet = ndx.net;
|
|
ndx.upnode= 0;
|
|
upnet = ndx.net;
|
|
upnode = num;
|
|
break;
|
|
case NL_NODE: ndx.node = num;
|
|
ndx.point = 0;
|
|
ndx.upnet = upnet;
|
|
ndx.upnode= upnode;
|
|
break;
|
|
case NL_POINT: ndx.point = num;
|
|
ndx.upnet = ndx.net;
|
|
ndx.upnode= ndx.node;
|
|
if ((!ndx.region) && bossvalid)
|
|
ndx.region = regio;
|
|
break;
|
|
}
|
|
if (!do_quiet) {
|
|
printf("\rZone %-6uRegion %-6uNet %-6uNode %-6uPoint %-6u",
|
|
ndx.zone, ndx.region, ndx.net, ndx.node, ndx.point);
|
|
fflush(stdout);
|
|
}
|
|
|
|
memset(&udx, 0, sizeof(udx));
|
|
udx.record = total;
|
|
|
|
/*
|
|
* Read nodelist line and extract username.
|
|
*/
|
|
for (i = 0; i < 3; i++) {
|
|
p = q;
|
|
if (p == NULL)
|
|
continue;
|
|
if ((q = strchr(p, ',')))
|
|
*q++ = '\0';
|
|
if (q == NULL)
|
|
q = p;
|
|
}
|
|
if (strlen(p) > 35)
|
|
p[35] = '\0';
|
|
sprintf(udx.user, "%s", p);
|
|
|
|
/*
|
|
* Now search for the baudrate field, 300 means it's
|
|
* and ISDN or TCP/IP only node which is a special case.
|
|
*/
|
|
for (i = 0; i < 2; i++) {
|
|
p = q;
|
|
if (p == NULL)
|
|
continue;
|
|
if ((q = strchr(p, ',')))
|
|
*q++ = '\0';
|
|
if (q == NULL)
|
|
q = p;
|
|
}
|
|
if ((strlen(p) == 3) && (!strcmp(p, "300")) && (q != NULL)) {
|
|
if ((strstr(q, (char *)"X75")) ||
|
|
(strstr(q, (char *)"V110L")) ||
|
|
(strstr(q, (char *)"V110H")) ||
|
|
(strstr(q, (char *)"V120L")) ||
|
|
(strstr(q, (char *)"V120H")) ||
|
|
(strstr(q, (char *)"ISDN")))
|
|
ndx.pflag |= NL_ISDN;
|
|
if ((strstr(q, (char *)"IFC")) ||
|
|
(strstr(q, (char *)"IBN")) ||
|
|
(strstr(q, (char *)"ITN")) ||
|
|
(strstr(q, (char *)"IVM")) ||
|
|
(strstr(q, (char *)"IFT")) ||
|
|
(strstr(q, (char *)"IP")))
|
|
ndx.pflag |= NL_TCPIP;
|
|
}
|
|
|
|
Syslog('S',"put: %u:%u/%u.%u reg %u upl %u/%u typ %u flg %02X as (%u,%lu)",
|
|
ndx.zone,ndx.net,ndx.node,
|
|
ndx.point,ndx.region,ndx.upnet,ndx.upnode,
|
|
ndx.type,ndx.pflag,ndx.fileno,ndx.offset);
|
|
|
|
|
|
/*
|
|
* If zone, net and node given, then this list is an
|
|
* overlay so we will call in_list() to replace the
|
|
* existing records, or append them if they don't exist.
|
|
* Also, only points with a valid boss will be added.
|
|
*/
|
|
if (zo) {
|
|
if (!(in_nllist(ndx, &nll, TRUE))) {
|
|
if (ndx.point && bossvalid) {
|
|
fill_nllist(ndx, &nll);
|
|
Syslog('S', "Add point %u:%u/%u.%u", ndx.zone, ndx.net, ndx.node, ndx.point);
|
|
}
|
|
if (!ndx.point)
|
|
fill_nllist(ndx, &nll);
|
|
}
|
|
} else
|
|
fill_nllist(ndx, &nll);
|
|
}
|
|
|
|
Syslog('+', "%d entries", entries);
|
|
|
|
if (!do_quiet) {
|
|
printf(" %ld entries\n", entries);
|
|
fflush(stdout);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Tidy the filearray
|
|
*/
|
|
void tidy_fdlist(fd_list **fdp)
|
|
{
|
|
fd_list *tmp, *old;
|
|
|
|
for (tmp = *fdp; tmp; tmp = old) {
|
|
old = tmp->next;
|
|
free(tmp);
|
|
}
|
|
*fdp = NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Add a file on the array.
|
|
*/
|
|
void fill_fdlist(fd_list **fdp, char *filename, time_t filedate)
|
|
{
|
|
fd_list *tmp;
|
|
|
|
tmp = (fd_list *)malloc(sizeof(fd_list));
|
|
tmp->next = *fdp;
|
|
sprintf(tmp->fname, "%s", filename);
|
|
tmp->fdate = filedate;
|
|
*fdp = tmp;
|
|
}
|
|
|
|
|
|
|
|
int compfdate(fd_list **, fd_list **);
|
|
|
|
|
|
/*
|
|
* Sort the array of files by filedate
|
|
*/
|
|
void sort_fdlist(fd_list **fdp)
|
|
{
|
|
fd_list *ta, **vector;
|
|
size_t n = 0, i;
|
|
|
|
if (*fdp == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (ta = *fdp; ta; ta = ta->next)
|
|
n++;
|
|
|
|
vector = (fd_list **)malloc(n * sizeof(fd_list *));
|
|
|
|
i = 0;
|
|
for (ta = *fdp; ta; ta = ta->next) {
|
|
vector[i++] = ta;
|
|
}
|
|
|
|
qsort(vector, n, sizeof(fd_list*), (int(*)(const void*, const void*))compfdate);
|
|
|
|
(*fdp) = vector[0];
|
|
i = 1;
|
|
|
|
for (ta = *fdp; ta; ta = ta->next) {
|
|
|
|
if (i < n)
|
|
ta->next = vector[i++];
|
|
else
|
|
ta->next = NULL;
|
|
}
|
|
|
|
free(vector);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
int compfdate(fd_list **fdp1, fd_list **fdp2)
|
|
{
|
|
return ((*fdp1)->fdate - (*fdp2)->fdate);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Return the name of the oldest file in the array
|
|
*/
|
|
char *pull_fdlist(fd_list **fdp)
|
|
{
|
|
static char buf[65];
|
|
fd_list *ta;
|
|
|
|
if (*fdp == NULL)
|
|
return NULL;
|
|
|
|
ta = *fdp;
|
|
memset(&buf, 0, sizeof(buf));
|
|
sprintf(buf, "%s", ta->fname);
|
|
|
|
if (ta->next != NULL)
|
|
*fdp = ta->next;
|
|
else
|
|
*fdp = NULL;
|
|
|
|
free(ta);
|
|
return buf;
|
|
}
|
|
|
|
|
|
|
|
int makelist(char *base, unsigned short zo, unsigned short ne, unsigned short no)
|
|
{
|
|
int rc = 0, files = 0;
|
|
struct dirent *de;
|
|
DIR *dp;
|
|
char *p = NULL, *q;
|
|
struct _nlfil fdx;
|
|
fd_list *fdl = NULL;
|
|
|
|
if (!strlen(base)) {
|
|
WriteError("Error, no nodelist defined for %d:%d/%d", zo, ne, no);
|
|
return 0;
|
|
}
|
|
|
|
if ((dp = opendir(CFG.nodelists)) == NULL) {
|
|
WriteError("$Can't open dir %s", CFG.nodelists);
|
|
rc = 103;
|
|
} else {
|
|
while ((de = readdir(dp)))
|
|
if (strncmp(de->d_name, base, strlen(base)) == 0) {
|
|
/*
|
|
* Extension must be at least 2 digits
|
|
*/
|
|
q = (de->d_name) + strlen(base);
|
|
if ((*q == '.') && (strlen(q) > 2) &&
|
|
(strspn(q+1,"0123456789") == (strlen(q)-1))) {
|
|
/*
|
|
* Add matched filenames to the array
|
|
*/
|
|
fill_fdlist(&fdl, de->d_name, file_time(fullpath(de->d_name)));
|
|
files++;
|
|
}
|
|
}
|
|
closedir(dp);
|
|
|
|
if (files == 0) {
|
|
Syslog('+', "No nodelist found for %s", base);
|
|
return 103;
|
|
}
|
|
|
|
/*
|
|
* Sort found nodelists by age and kill all but the newest 2.
|
|
*/
|
|
sort_fdlist(&fdl);
|
|
while (files) {
|
|
p = pull_fdlist(&fdl);
|
|
if (files > 2) {
|
|
Syslog('+', "Remove old \"%s\"", p);
|
|
unlink(fullpath(p));
|
|
}
|
|
files--;
|
|
}
|
|
tidy_fdlist(&fdl);
|
|
|
|
memset(&fdx, 0, sizeof(fdx));
|
|
sprintf(fdx.filename, "%s", p);
|
|
sprintf(fdx.domain, "%s", fidonet.domain);
|
|
fdx.number = filenr;
|
|
fwrite(&fdx, sizeof(fdx), 1, ffp);
|
|
|
|
rc = compile(p, zo, ne, no);
|
|
filenr++;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
int nodebld(void)
|
|
{
|
|
int rc = 0, i;
|
|
char *im, *fm, *um, *old, *new;
|
|
struct _nlfil fdx;
|
|
FILE *fp;
|
|
nl_list *tmp;
|
|
|
|
memset(&fdx, 0, sizeof(fdx));
|
|
im = xstrcpy(fullpath((char *)"temp.index"));
|
|
fm = xstrcpy(fullpath((char *)"temp.files"));
|
|
um = xstrcpy(fullpath((char *)"temp.users"));
|
|
|
|
if ((ifp = fopen(im, "w+")) == NULL) {
|
|
WriteError("$Can't create %s",MBSE_SS(im));
|
|
return 101;
|
|
}
|
|
if ((ufp = fopen(um, "w+")) == NULL) {
|
|
WriteError("$Can't create %s", MBSE_SS(um));
|
|
fclose(ifp);
|
|
unlink(im);
|
|
return 101;
|
|
}
|
|
if ((ffp = fopen(fm, "w+")) == NULL) {
|
|
WriteError("$Can't create %s", MBSE_SS(fm));
|
|
fclose(ifp);
|
|
unlink(im);
|
|
fclose(ufp);
|
|
unlink(um);
|
|
return 101;
|
|
}
|
|
|
|
if (!do_quiet) {
|
|
colour(3, 0);
|
|
printf("\n");
|
|
}
|
|
|
|
if ((fp = fopen(fidonet_fil, "r")) == 0)
|
|
rc = 102;
|
|
else {
|
|
fread(&fidonethdr, sizeof(fidonethdr), 1, fp);
|
|
|
|
while (fread(&fidonet, fidonethdr.recsize, 1, fp) == 1) {
|
|
if (fidonet.available) {
|
|
rc = makelist(fidonet.nodelist, 0, 0, 0);
|
|
if (rc)
|
|
break;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
if (fidonet.seclist[i].zone) {
|
|
rc = makelist(fidonet.seclist[i].nodelist,
|
|
fidonet.seclist[i].zone,
|
|
fidonet.seclist[i].net,
|
|
fidonet.seclist[i].node);
|
|
if (rc)
|
|
break;
|
|
}
|
|
}
|
|
if (rc)
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
fclose(ufp);
|
|
fclose(ffp);
|
|
|
|
if (rc == 0) {
|
|
IsDoing("Sorting nodes");
|
|
sort_nllist(&nll);
|
|
|
|
IsDoing("Writing files");
|
|
for (tmp = nll; tmp; tmp = tmp->next)
|
|
fwrite(&tmp->idx, sizeof(struct _nlidx), 1, ifp);
|
|
fclose(ifp);
|
|
|
|
Syslog('+', "Compiled %d entries", total);
|
|
|
|
/*
|
|
* Rename existing files to old.*, they stay on disk in
|
|
* case they are open by some program. The temp.* files
|
|
* are then renamed to node.*
|
|
*/
|
|
old = xstrcpy(fullpath((char *)"old.index"));
|
|
new = xstrcpy(fullpath((char *)"node.index"));
|
|
unlink(old);
|
|
rename(new, old);
|
|
rename(im, new);
|
|
free(old);
|
|
free(new);
|
|
old = xstrcpy(fullpath((char *)"old.users"));
|
|
new = xstrcpy(fullpath((char *)"node.users"));
|
|
unlink(old);
|
|
rename(new, old);
|
|
rename(um, new);
|
|
free(old);
|
|
free(new);
|
|
old = xstrcpy(fullpath((char *)"old.files"));
|
|
new = xstrcpy(fullpath((char *)"node.files"));
|
|
unlink(old);
|
|
rename(new, old);
|
|
rename(fm, new);
|
|
free(old);
|
|
free(new);
|
|
} else {
|
|
fclose(ifp);
|
|
Syslog('+', "Compile failed, rc=%d", rc);
|
|
unlink(im);
|
|
unlink(fm);
|
|
unlink(um);
|
|
}
|
|
|
|
free(im);
|
|
free(fm);
|
|
free(um);
|
|
tidy_nllist(&nll);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|