This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/mbfido/mbdiff.c
2008-11-26 22:12:28 +00:00

575 lines
13 KiB
C

/*****************************************************************************
*
* $Id$
* Purpose ...............: Nodelist diff processor
* Original ideas ........: Eugene G. Crosser.
*
*****************************************************************************
* Copyright (C) 1997-2008
*
* 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;
mbse_colour(WHITE, BLACK);
printf("\nMBDIFF: MBSE BBS %s Nodelist diff processor\n", VERSION);
mbse_colour(YELLOW, BLACK);
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...
*/
execute_pth((char *)"stty", (char *)"sane", (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null");
}
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) {
mbse_colour(LIGHTGRAY, BLACK);
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();
mbse_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) || (i == SIGIOT))
signal(i, (void (*))die);
else if (i == SIGCHLD)
signal(i, SIG_DFL);
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) {
mbse_colour(LIGHTRED, BLACK);
printf("\n");
}
if (enoughspace(CFG.freespace) == 0)
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;
WriteError("Can't get filetype for %s", nd);
free(onl);
free(wrk);
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) || (strlen(cmd) == 0)) {
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_str(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);
}
}
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) {
mbse_colour(CYAN, BLACK);
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_str(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();
mbse_colour(LIGHTCYAN, BLACK);
printf("\nUsage: mbdiff [nodelist] [nodediff] <options>\n\n");
mbse_colour(CYAN, BLACK);
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");
mbse_colour(LIGHTBLUE, BLACK);
printf("\n Options are:\n\n");
mbse_colour(CYAN, BLACK);
printf(" -quiet Quiet mode\n");
mbse_colour(LIGHTGRAY, BLACK);
printf("\n");
die(MBERR_COMMANDLINE);
}
int apply(char *nl, char *nd, char *nn)
{
FILE *fo, *fd, *fn;
unsigned char cmdbuf[BLKSIZ], lnbuf[BLKSIZ];
char *p;
int i, count, ac = 0, cc = 0, dc = 0, rc = 0, firstline = 1;
unsigned short theircrc = 0, mycrc = 0;
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((char *)cmdbuf, sizeof(cmdbuf)-1, fd) == NULL) ||
(fgets((char *)lnbuf, sizeof(cmdbuf)-1, fo) == NULL) ||
(strcmp((char *)cmdbuf, (char *)lnbuf) != 0)) {
rc = 6;
} else {
rewind(fo);
rewind(fd);
while ((rc == 0) && fgets((char *)cmdbuf, sizeof(cmdbuf)-1, fd)) {
switch (cmdbuf[0]) {
case '\032': break;
case ';': Striplf((char *)cmdbuf);
break;
case 'A': count = atoi((char *)cmdbuf+1);
ac += count;
Striplf((char *)cmdbuf);
for (i = 0;(i < count) && (rc == 0); i++)
if (fgets((char *)lnbuf, sizeof(lnbuf)-1, fd)) {
if (firstline) {
firstline = 0;
if ((p = strrchr((char *)lnbuf, ':'))) {
theircrc = atoi((char *)p+1);
}
} else {
for (p = (char *)lnbuf; *p; p++)
mycrc = updcrc(*p, mycrc);
}
fputs((char *)lnbuf, fn);
} else
rc = 3;
break;
case 'D': count = atoi((char *)cmdbuf + 1);
dc += count;
Striplf((char *)cmdbuf);
for (i = 0;(i < count) && (rc == 0); i++)
if (fgets((char *)lnbuf, sizeof(lnbuf)-1, fo) == NULL)
rc = 3;
break;
case 'C': count = atoi((char *)cmdbuf+1);
cc += count;
Striplf((char *)cmdbuf);
for (i = 0; (i < count) && (rc == 0); i++)
if (fgets((char *)lnbuf, sizeof(lnbuf) - 1, fo)) {
/*
* Don't use EOF character for CRC test.
*/
if (lnbuf[0] != '\032') {
for (p = (char *)lnbuf; *p; p++)
mycrc = updcrc(*p, mycrc);
fputs((char *)lnbuf, fn);
}
} else
rc = 3;
break;
default: rc = 5;
break;
}
}
}
fclose(fo);
fclose(fd);
fputc('\032', fn);
fclose(fn);
if ((rc != 0) && !do_quiet) {
show_log = TRUE;
mbse_colour(LIGHTRED, BLACK);
}
if ((rc == 0) && (mycrc != theircrc))
rc = 4;
if (rc == 3) {
WriteError("Could not read some of the files");
if (!do_quiet)
printf("Could not read some of the files\n");
} else if (rc == 4) {
WriteError("CRC is %hu, should be %hu", mycrc, theircrc);
if (!do_quiet)
printf("CRC is %hu, should be %hu\n", mycrc, theircrc);
} else if (rc == 5) {
WriteError("Unknown input line: \"%s\"", cmdbuf);
if (!do_quiet)
printf("Unknown input line: \"%s\"\n", cmdbuf);
} else if (rc == 6) {
WriteError("Diff does not match old list");
if (!do_quiet)
printf("Diff does not match old list\n");
} 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;
}