/***************************************************************************** * * $Id$ * Purpose ...............: Nodelist diff processor * Original ideas ........: Eugene G. Crosser. * ***************************************************************************** * 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/mberrors.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; #ifdef MEMWATCH mwInit(); #endif InitConfig(); TermInit(1); 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 == SIGKILL)) signal(i, (void (*))die); else 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); 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")) { Syslog('!', "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); sync(); 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"); } sync(); 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] \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; }