572 lines
12 KiB
C
572 lines
12 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Nodelist diff processor
|
|
* Original ideas ........: Eugene G. Crosser.
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2004
|
|
*
|
|
* 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/mbselib.h"
|
|
#include "../lib/users.h"
|
|
#include "../lib/mbsedb.h"
|
|
#include "mbdiff.h"
|
|
|
|
|
|
|
|
#ifndef BLKSIZ
|
|
#define BLKSIZ 512
|
|
#endif
|
|
|
|
extern unsigned short crc16xmodemtab[];
|
|
#define updcrc(cp, crc) ( crc16xmodemtab[((crc >> 8) & 255) ^ cp] ^ (crc << 8))
|
|
|
|
extern int show_log;
|
|
extern int e_pid;
|
|
extern int do_quiet; /* Suppress screen output */
|
|
extern int show_log; /* Show logging */
|
|
time_t t_start; /* Start time */
|
|
time_t t_end; /* End time */
|
|
|
|
|
|
|
|
void ProgName(void)
|
|
{
|
|
if (do_quiet)
|
|
return;
|
|
|
|
colour(15, 0);
|
|
printf("\nMBDIFF: MBSE BBS %s Nodelist diff processor\n", VERSION);
|
|
colour(14, 0);
|
|
printf(" %s\n", COPYRIGHT);
|
|
}
|
|
|
|
|
|
|
|
void die(int onsig)
|
|
{
|
|
/*
|
|
* First check if a child is running, if so, kill it.
|
|
*/
|
|
if (e_pid) {
|
|
if ((kill(e_pid, SIGTERM)) == 0)
|
|
Syslog('+', "SIGTERM to pid %d succeeded", e_pid);
|
|
else {
|
|
if ((kill(e_pid, SIGKILL)) == 0)
|
|
Syslog('+', "SIGKILL to pid %d succeded", e_pid);
|
|
else
|
|
WriteError("$Failed to kill pid %d", e_pid);
|
|
}
|
|
|
|
/*
|
|
* In case the child had the tty in raw mode...
|
|
*/
|
|
system("stty sane");
|
|
}
|
|
|
|
signal(onsig, SIG_IGN);
|
|
|
|
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(' ', "MBDIFF finished in %s", t_elapsed(t_start, t_end));
|
|
|
|
if (!do_quiet) {
|
|
colour(7, 0);
|
|
printf("\n");
|
|
}
|
|
ExitClient(onsig);
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i, Match, rc;
|
|
char *cmd, *nl = NULL, *nd = NULL, *nn, *p, *q, *arc, *wrk, *onl, *ond;
|
|
struct passwd *pw;
|
|
DIR *dp;
|
|
struct dirent *de;
|
|
|
|
InitConfig();
|
|
TermInit(1, 80, 25);
|
|
t_start = time(NULL);
|
|
umask(002);
|
|
|
|
/*
|
|
* Catch all signals we can, and ignore the rest.
|
|
*/
|
|
for (i = 0; i < NSIG; i++) {
|
|
if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV))
|
|
signal(i, (void (*))die);
|
|
else if ((i != SIGKILL) && (i != SIGSTOP))
|
|
signal(i, SIG_IGN);
|
|
}
|
|
|
|
if(argc < 3)
|
|
Help();
|
|
|
|
cmd = xstrcpy((char *)"Cmd: mbdiff");
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
cmd = xstrcat(cmd, (char *)" ");
|
|
cmd = xstrcat(cmd, argv[i]);
|
|
|
|
if (i == 1)
|
|
if ((nl = argv[i]) == NULL)
|
|
Help();
|
|
if (i == 2)
|
|
if ((nd = argv[i]) == NULL)
|
|
Help();
|
|
if (!strncasecmp(argv[i], "-q", 2))
|
|
do_quiet = TRUE;
|
|
|
|
}
|
|
|
|
ProgName();
|
|
pw = getpwuid(getuid());
|
|
InitClient(pw->pw_name, (char *)"mbdiff", CFG.location, CFG.logfile,
|
|
CFG.util_loglevel, CFG.error_log, CFG.mgrlog, CFG.debuglog);
|
|
|
|
Syslog(' ', " ");
|
|
Syslog(' ', "MBDIFF v%s", VERSION);
|
|
Syslog(' ', cmd);
|
|
free(cmd);
|
|
|
|
if (!do_quiet) {
|
|
colour(12, 0);
|
|
printf("\n");
|
|
}
|
|
|
|
if (!diskfree(CFG.freespace))
|
|
die(MBERR_DISK_FULL);
|
|
|
|
/*
|
|
* Extract work directory from the first commandline parameter
|
|
* and set that directory as default.
|
|
*/
|
|
show_log = TRUE;
|
|
wrk = xstrcpy(nl);
|
|
if (strrchr(wrk, '/') == NULL) {
|
|
WriteError("No path in nodelist name");
|
|
free(wrk);
|
|
die(MBERR_COMMANDLINE);
|
|
}
|
|
if (strrchr(wrk, '.') != NULL) {
|
|
WriteError("Filename extension given for nodelist");
|
|
free(wrk);
|
|
die(MBERR_COMMANDLINE);
|
|
}
|
|
if (strrchr(nd, '/') == NULL) {
|
|
WriteError("No path in nodediff name");
|
|
free(wrk);
|
|
die(MBERR_COMMANDLINE);
|
|
}
|
|
show_log = FALSE;
|
|
|
|
while (wrk[strlen(wrk) -1] != '/')
|
|
wrk[strlen(wrk) -1] = '\0';
|
|
wrk[strlen(wrk) -1] = '\0';
|
|
|
|
show_log = TRUE;
|
|
if (access(wrk, R_OK|W_OK)) {
|
|
WriteError("$No R/W access in %s", wrk);
|
|
free(wrk);
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
|
|
if (chdir(wrk)) {
|
|
WriteError("$Can't chdir to %s", wrk);
|
|
free(wrk);
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
show_log = FALSE;
|
|
|
|
onl = xstrcpy(strrchr(nl, '/') + 1);
|
|
onl = xstrcat(onl, (char *)".???");
|
|
|
|
if ((dp = opendir(wrk)) == 0) {
|
|
show_log = TRUE;
|
|
free(wrk);
|
|
WriteError("$Error opening directory %s", wrk);
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
|
|
Match = FALSE;
|
|
while ((de = readdir(dp))) {
|
|
if (strlen(de->d_name) == strlen(onl)) {
|
|
Match = TRUE;
|
|
for (i = 0; i < strlen(onl); i++) {
|
|
if ((onl[i] != '?') && (onl[i] != de->d_name[i]))
|
|
Match = FALSE;
|
|
}
|
|
if (Match) {
|
|
free(onl);
|
|
onl = xstrcpy(de->d_name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
closedir(dp);
|
|
if (!Match) {
|
|
show_log = TRUE;
|
|
free(wrk);
|
|
free(onl);
|
|
WriteError("Old nodelist not found");
|
|
die(MBERR_INIT_ERROR);
|
|
}
|
|
|
|
/*
|
|
* Now try to get the diff file into the workdir.
|
|
*/
|
|
if ((arc = unpacker(nd)) == NULL) {
|
|
show_log = TRUE;
|
|
free(onl);
|
|
free(wrk);
|
|
WriteError("Can't get filetype for %s", nd);
|
|
die(MBERR_CONFIG_ERROR);
|
|
}
|
|
|
|
ond = xstrcpy(strrchr(nd, '/') + 1);
|
|
|
|
if (strncmp(arc, "ASC", 3)) {
|
|
if (!getarchiver(arc)) {
|
|
show_log = TRUE;
|
|
free(onl);
|
|
free(wrk);
|
|
free(ond);
|
|
WriteError("Can't find unarchiver %s", arc);
|
|
die(MBERR_CONFIG_ERROR);
|
|
}
|
|
|
|
/*
|
|
* We may both use the unarchive command for files and mail,
|
|
* unarchiving isn't recursive anyway.
|
|
*/
|
|
if (strlen(archiver.funarc))
|
|
cmd = xstrcpy(archiver.funarc);
|
|
else
|
|
cmd = xstrcpy(archiver.munarc);
|
|
|
|
if ((cmd == NULL) || (cmd == "")) {
|
|
show_log = TRUE;
|
|
free(cmd);
|
|
free(onl);
|
|
free(wrk);
|
|
free(ond);
|
|
WriteError("No unarc command available for %s", arc);
|
|
die(MBERR_CONFIG_ERROR);
|
|
}
|
|
|
|
if (execute(cmd, nd, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) {
|
|
WriteError("Warning: unpack error, trying again after a sync");
|
|
sync();
|
|
sleep(1);
|
|
if (execute(cmd, nd, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) {
|
|
show_log = TRUE;
|
|
free(cmd);
|
|
free(onl);
|
|
free(wrk);
|
|
free(ond);
|
|
WriteError("Fatal: unpack error");
|
|
die(MBERR_EXEC_FAILED);
|
|
}
|
|
}
|
|
free(cmd);
|
|
|
|
Match = FALSE;
|
|
if ((dp = opendir(wrk)) != NULL) {
|
|
while ((de = readdir(dp))) {
|
|
if (strlen(ond) == strlen(de->d_name)) {
|
|
Match = TRUE;
|
|
for (i = 0; i < (strlen(ond) -3); i++)
|
|
if (toupper(ond[i]) != toupper(de->d_name[i]))
|
|
Match = FALSE;
|
|
if (Match) {
|
|
free(ond);
|
|
ond = xstrcpy(de->d_name);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
closedir(dp);
|
|
}
|
|
if (!Match) {
|
|
show_log = TRUE;
|
|
free(ond);
|
|
free(onl);
|
|
free(wrk);
|
|
WriteError("Could not find extracted file");
|
|
die(MBERR_DIFF_ERROR);
|
|
}
|
|
} else {
|
|
if ((rc = file_cp(nd, ond))) {
|
|
show_log = TRUE;
|
|
free(ond);
|
|
free(onl);
|
|
free(wrk);
|
|
WriteError("Copy %s failed, %s", nd, strerror(rc));
|
|
die(MBERR_DIFF_ERROR);
|
|
}
|
|
Syslog('s', "Copied %s", nd);
|
|
}
|
|
|
|
if (((p = strrchr(onl, '.'))) && ((q = strrchr(ond, '.'))) && (strlen(p) == strlen(q))) {
|
|
nn = xstrcpy(onl);
|
|
p = strrchr(nn, '.') + 1;
|
|
q++;
|
|
strcpy(p, q);
|
|
} else
|
|
nn = xstrcpy((char *)"newnodelist");
|
|
|
|
if (strcmp(onl, nn) == 0) {
|
|
show_log = TRUE;
|
|
WriteError("Attempt to update nodelist to the same version");
|
|
unlink(ond);
|
|
free(ond);
|
|
free(onl);
|
|
free(wrk);
|
|
free(nn);
|
|
die(MBERR_DIFF_ERROR);
|
|
}
|
|
|
|
Syslog('+', "Apply %s with %s to %s", onl, ond, nn);
|
|
if (!do_quiet) {
|
|
colour(3, 0);
|
|
printf("Apply %s with %s to %s\n", onl, ond, nn);
|
|
}
|
|
rc = apply(onl, ond, nn);
|
|
|
|
unlink(ond);
|
|
if (rc) {
|
|
unlink(nn);
|
|
free(nn);
|
|
free(ond);
|
|
free(onl);
|
|
free(wrk);
|
|
die(MBERR_DIFF_ERROR);
|
|
} else {
|
|
unlink(onl);
|
|
cmd = xstrcpy(archiver.farc);
|
|
|
|
if ((cmd == NULL) || (!strlen(cmd))) {
|
|
free(cmd);
|
|
Syslog('+', "No archive command for %s, fallback to ZIP", arc);
|
|
if (!getarchiver((char *)"ZIP")) {
|
|
WriteError("No ZIP command available");
|
|
free(ond);
|
|
free(onl);
|
|
free(wrk);
|
|
free(nn);
|
|
die(MBERR_DIFF_ERROR);
|
|
} else {
|
|
cmd = xstrcpy(archiver.farc);
|
|
}
|
|
} else {
|
|
free(cmd);
|
|
cmd = xstrcpy(archiver.farc);
|
|
}
|
|
|
|
if ((cmd == NULL) || (!strlen(cmd))) {
|
|
WriteError("No archiver command available");
|
|
} else {
|
|
free(onl);
|
|
onl = xstrcpy(nn);
|
|
onl[strlen(onl) -3] = tolower(archiver.name[0]);
|
|
tl(onl);
|
|
p = xstrcpy(onl);
|
|
p = xstrcat(p, (char *)" ");
|
|
p = xstrcat(p, nn);
|
|
if (execute(cmd, p, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"))
|
|
WriteError("Create %s failed", onl);
|
|
else {
|
|
CreateSema((char *)"mailin");
|
|
}
|
|
free(p);
|
|
free(cmd);
|
|
}
|
|
|
|
free(onl);
|
|
free(ond);
|
|
free(wrk);
|
|
free(nn);
|
|
die(MBERR_OK);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void Help(void)
|
|
{
|
|
do_quiet = FALSE;
|
|
ProgName();
|
|
|
|
colour(11, 0);
|
|
printf("\nUsage: mbdiff [nodelist] [nodediff] <options>\n\n");
|
|
colour(3, 0);
|
|
printf(" The nodelist must be the full path and filename\n");
|
|
printf(" without the dot and daynumber digits to the working\n");
|
|
printf(" directory of that nodelist.\n");
|
|
printf(" The nodediff must be the full path and filename\n");
|
|
printf(" to the (compressed) nodediff file in the download\n");
|
|
printf(" directory.\n");
|
|
colour(9, 0);
|
|
printf("\n Options are:\n\n");
|
|
colour(3, 0);
|
|
printf(" -quiet Quiet mode\n");
|
|
colour(7, 0);
|
|
printf("\n");
|
|
die(MBERR_COMMANDLINE);
|
|
}
|
|
|
|
|
|
|
|
int apply(char *nl, char *nd, char *nn)
|
|
{
|
|
FILE *fo, *fd, *fn;
|
|
unsigned char cmdbuf[BLKSIZ];
|
|
unsigned char lnbuf[BLKSIZ];
|
|
int i, count;
|
|
int ac = 0, cc = 0, dc = 0;
|
|
int rc = 0;
|
|
int firstline = 1;
|
|
unsigned short theircrc = 0, mycrc = 0;
|
|
unsigned char *p;
|
|
|
|
if ((fo = fopen(nl, "r")) == NULL) {
|
|
WriteError("$Can't open %s", nl);
|
|
return 2;
|
|
}
|
|
|
|
if ((fd = fopen(nd, "r")) == NULL) {
|
|
WriteError("$Can't open %s", nd);
|
|
fclose(fo);
|
|
return 2;
|
|
}
|
|
|
|
if ((fn = fopen(nn, "w")) == NULL) {
|
|
WriteError("$Can't open %s", nn);
|
|
fclose(fo);
|
|
fclose(fd);
|
|
return 2;
|
|
}
|
|
|
|
if ((fgets(cmdbuf, sizeof(cmdbuf)-1, fd) == NULL) ||
|
|
(fgets(lnbuf, sizeof(cmdbuf)-1, fo) == NULL) ||
|
|
(strcmp(cmdbuf, lnbuf) != 0)) {
|
|
rc = 6;
|
|
} else {
|
|
rewind(fo);
|
|
rewind(fd);
|
|
|
|
while ((rc == 0) && fgets(cmdbuf, sizeof(cmdbuf)-1, fd))
|
|
switch (cmdbuf[0]) {
|
|
case ';':
|
|
Striplf(cmdbuf);
|
|
break;
|
|
case 'A':
|
|
count = atoi(cmdbuf+1);
|
|
ac += count;
|
|
Striplf(cmdbuf);
|
|
for (i = 0;(i < count) && (rc == 0); i++)
|
|
if (fgets(lnbuf, sizeof(lnbuf)-1, fd)) {
|
|
if (firstline) {
|
|
firstline = 0;
|
|
if ((p = strrchr(lnbuf, ':'))) {
|
|
theircrc = atoi(p+1);
|
|
}
|
|
} else {
|
|
for (p = lnbuf; *p; p++)
|
|
mycrc = updcrc(*p, mycrc);
|
|
}
|
|
fputs(lnbuf, fn);
|
|
} else
|
|
rc = 3;
|
|
break;
|
|
case 'D':
|
|
count = atoi(cmdbuf + 1);
|
|
dc += count;
|
|
Striplf(cmdbuf);
|
|
for (i = 0;(i < count) && (rc == 0); i++)
|
|
if (fgets(lnbuf, sizeof(lnbuf)-1, fo) == NULL)
|
|
rc = 3;
|
|
break;
|
|
case 'C':
|
|
count = atoi(cmdbuf+1);
|
|
cc += count;
|
|
Striplf(cmdbuf);
|
|
for (i = 0; (i < count) && (rc == 0); i++)
|
|
if (fgets(lnbuf, sizeof(lnbuf) - 1, fo)) {
|
|
for (p = lnbuf; *p; p++)
|
|
mycrc = updcrc(*p, mycrc);
|
|
fputs(lnbuf, fn);
|
|
} else
|
|
rc = 3;
|
|
break;
|
|
default:
|
|
rc = 5;
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(fo);
|
|
fclose(fd);
|
|
fclose(fn);
|
|
|
|
if ((rc != 0) && !do_quiet) {
|
|
show_log = TRUE;
|
|
colour(12, 0);
|
|
}
|
|
|
|
if ((rc == 0) && (mycrc != theircrc))
|
|
rc = 4;
|
|
|
|
if (rc == 3)
|
|
WriteError("Could not read some of the files");
|
|
else if (rc == 4)
|
|
WriteError("CRC is %hu, should be %hu", mycrc, theircrc);
|
|
else if (rc == 5)
|
|
WriteError("Unknown input line: \"%s\"", cmdbuf);
|
|
else if (rc == 6)
|
|
WriteError("Diff does not match old list");
|
|
else {
|
|
Syslog('+', "Copied %d, added %d, deleted %d, difference %d", cc, ac, dc, ac-dc);
|
|
if (!do_quiet)
|
|
printf("Created new nodelist\n");
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|