/******************************************************** * File: crashecho.c * Created at Sun Jan 28 22:10:29 MSK 2001 by raorn // raorn@binec.ru * The CrashEcho itself * $Id: crashecho.c,v 1.26 2002/10/27 22:47:52 raorn Exp $ *******************************************************/ #include "crashecho.h" #ifdef HAVE_GETOPT_H # include #else # include #endif /* Version string to use when writing config */ uchar verstr[] = "CrashEcho/" PLATFORM_NAME " " VERSION; /*********************************** Global *******************************/ struct jbList PktList; bool nomem = FALSE; bool ioerror = FALSE; bool exitprg = FALSE; ulong ioerrornum = 0; ulong toss_total = 0; ulong toss_bad = 0; ulong toss_import = 0; ulong toss_written = 0; ulong toss_dupes = 0; ulong toss_cc = 0; ulong scan_total = 0; ulong rescan_total = 0; int nowdoing = DOING_NONE; struct ConfigNode *RescanNode; ulong DayStatsWritten; /* The area statistics are updated until * this day */ struct Config config; bool ctrlc; uchar *prinames[] = { "Normal", "Hold", "Normal", "Direct", "Crash" }; /**************************** Local for this file ****************************/ #define SHOWVER 128 bool init_openlog; bool init_dupebuf; void Free(void) { if (init_dupebuf) { FreeDupebuf(); init_dupebuf = 0; } if (init_openlog) { CloseLogfile(); init_openlog = FALSE; } jbFreeList(&PktList); } bool Init(void) { struct Area *area; if (!OpenLogfile(config.cfg_LogFile, config.cfg_LogLevel)) { Free(); return (FALSE); } init_openlog = TRUE; if (config.cfg_DupeMode != DUPE_IGNORE) { if (!AllocDupebuf()) { fprintf(stderr, "No memory for dupe-check buffer\n"); Free(); return (FALSE); } init_dupebuf = TRUE; if (!ReadDupes(config.cfg_DupeFile)) { Free(); return (FALSE); } } if (!ReadStats(config.cfg_StatsFile)) return (FALSE); for (area = (struct Area *) config.AreaList.First; area; area = area->Next) if (area->Messagebase) area->Messagebase->active = TRUE; return (TRUE); } void AfterScanToss(bool success) { struct Area *area; struct ConfigNode *cnode; uchar errbuf[200]; ulong day, d, e, i; LogWrite(6, SYSTEMINFO, "In AfterScanToss(%s)", success ? "TRUE" : "FALSE"); ClosePackets(); if (success) { if (config.cfg_BeforePack[0]) { int res, rc; LogWrite(2, TOSSINGINFO, "Executing BEFOREPACK script %s", config.cfg_BeforePack); res = Execute(config.cfg_BeforePack, &rc); if (!res) LogWrite(3, TOSSINGINFO, "BEFOREPACK script exited with rc = %d", rc); else LogWrite(3, TOSSINGINFO, "BEFOREPACK script failed"); } ArchiveOutbound(); } for (i = 0; AvailMessagebases[i].name; i++) if (AvailMessagebases[i].active && AvailMessagebases[i].afterfunc) (*AvailMessagebases[i].afterfunc) (success); if (success) { /* Rotate last8 if needed */ if (DayStatsWritten == 0) /* First time we use this statsfile */ DayStatsWritten = time(NULL) / (24 * 60 * 60); day = time(NULL) / (24 * 60 * 60); for (area = (struct Area *) config.AreaList.First; area; area = area->Next) if (day > DayStatsWritten) { for (d = DayStatsWritten; d < day; d++) { for (e = 0; e < 7; e++) area->Last8Days[7 - e] = area->Last8Days[7 - e - 1]; area->Last8Days[0] = 0; } } DayStatsWritten = day; /* Areas */ for (area = (struct Area *) config.AreaList.First; area; area = area->Next) if (area->NewTexts || area->NewDupes) { area->Texts += area->NewTexts; area->Last8Days[0] += area->NewTexts; area->Dupes += area->NewDupes; if (area->NewTexts) area->LastTime = time(NULL); if (area->NewTexts && area->FirstTime == 0) area->FirstTime = time(NULL); } for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next) { if (cnode->FirstTime == 0 && (cnode->GotEchomails != 0 || cnode->GotNetmails != 0 || cnode->SentEchomails != 0 || cnode->SentNetmails) != 0) cnode->FirstTime = time(NULL); } WriteStats(config.cfg_StatsFile); if (config.cfg_DupeMode != DUPE_IGNORE) WriteDupes(config.cfg_DupeFile); if (config.changed) { LogWrite(2, SYSTEMINFO, "Updating configuration file \"%s\"", config.filename); if (!UpdateConfig(&config, errbuf, 200)) LogWrite(1, SYSTEMERR, errbuf); LogWrite(2, SYSTEMINFO, "Updating areas file \"%s\"", config.areafile); if (!UpdateAreas(&config, errbuf, 200)) LogWrite(1, SYSTEMERR, errbuf); } } jbFreeList(&PktList); } bool BeforeScanToss(void) { struct Area *area; struct jbList NewPktFEList; struct FileEntry *fe; uchar buf[200]; int i; toss_total = 0; toss_bad = 0; toss_import = 0; toss_dupes = 0; toss_written = 0; toss_cc = 0; scan_total = 0; LogWrite(6, SYSTEMINFO, "In BeforeScanToss()"); for (area = (struct Area *) config.AreaList.First; area; area = area->Next) { area->NewDupes = 0; area->NewTexts = 0; } jbNewList(&PktList); /* Created packets */ /* Find orphan files */ if (!ReadDir(config.cfg_PacketCreate, &NewPktFEList, IsNewPkt)) { LogWrite(1, SYSTEMERR, "Failed to read directory \"%s\"", config.cfg_PacketCreate); LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno)); return (FALSE); } /* XXX */ for (fe = (struct FileEntry *) NewPktFEList.First; fe; fe = fe->Next) { uchar buf2[100]; uchar oldname[200]; ulong jbcpos; struct Pkt *pkttmp; struct Node4D n4d; LogWrite(1, SYSTEMINFO, "Found orphan tempfile %s", fe->Name); /* MakeFullPath(config.cfg_PacketCreate, fe->Name, buf, 200); unlink(buf); */ if (!(pkttmp = (struct Pkt *) calloc(1, sizeof(struct Pkt)))) { nomem = TRUE; return FALSE; } pkttmp->Type = PKTS_ECHOMAIL; mystrncpy(buf, fe->Name, 200); for (i = 0; buf[i]; i++) if (buf[i] == '_') buf[i] = ' '; jbcpos = 0; /* Get hexnum */ jbstrcpy(buf2, buf, 100, &jbcpos); sscanf(buf2, "%lx", &pkttmp->hexnum); /* Get pktorig */ jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Zone = atol(buf2); jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Net = atol(buf2); jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Node = atol(buf2); jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Point = atol(buf2); Copy4D(&pkttmp->Orig, &n4d); /* Get pktdest */ jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Zone = atol(buf2); jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Net = atol(buf2); jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Node = atol(buf2); jbstrcpy(buf2, buf, 100, &jbcpos); n4d.Point = atol(buf2); Copy4D(&pkttmp->Dest, &n4d); snprintf(buf2, 100, "%08lx.newpkt", pkttmp->hexnum); MakeFullPath(config.cfg_PacketCreate, fe->Name, oldname, 200); MakeFullPath(config.cfg_PacketCreate, buf2, buf, 200); if (rename(oldname, buf)) { LogWrite(1, SYSTEMERR, "Failed to rename %s to %s", oldname, buf); LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno)); free(pkttmp); return FALSE; } if (!(pkttmp->fh = fopen(buf, "r+b"))) { LogWrite(1, SYSTEMERR, "Unable to open packet %s", buf); LogWrite(1, SYSTEMERR, "Error: %s", strerror(errno)); free(pkttmp); return FALSE; } fseek(pkttmp->fh, -2L, SEEK_END); /* Step 2 bytes backwards */ pkttmp->Len = ftell(pkttmp->fh); jbAddNode(&PktList, (struct jbNode *) pkttmp); } jbFreeList(&NewPktFEList); for (i = 0; AvailMessagebases[i].name; i++) if (AvailMessagebases[i].active) if (AvailMessagebases[i].beforefunc) if (!(*AvailMessagebases[i].beforefunc) ()) return (FALSE); return (TRUE); } void Version(void) { int i; fprintf(stderr, "%s, compiled %s at %s\n", verstr, __DATE__, __TIME__); fprintf(stderr, "\n"); fprintf(stderr, "Available messagebase formats:\n"); for (i = 0; AvailMessagebases[i].name; i++) fprintf(stderr, " %-10.10s %s\n", AvailMessagebases[i].name, AvailMessagebases[i].desc); fprintf(stderr, "\n"); fprintf(stderr, "Features:\n"); #ifdef USE_SYSLOG fprintf(stderr, " syslog\n"); #endif } bool Rescan(uchar * areaname, uchar * node, ulong max) { struct Area *area; struct ConfigNode *cnode; struct Node4D n4d; bool success; if (!Parse4DTemplate(node, &n4d, &(((struct Aka *) (config.AkaList.First))->Node))) { LogWrite(1, USERERR, "Invalid node number %s", node); return (TRUE); } for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next) if (Compare4D(&cnode->Node, &n4d) == 0) break; if (!cnode) { LogWrite(1, USERERR, "Unknown node %u:%u/%u.%u", n4d.Zone, n4d.Net, n4d.Node, n4d.Point); return (TRUE); } for (area = (struct Area *) config.AreaList.First; area; area = area->Next) if (area->AreaType == AREATYPE_ECHOMAIL) if (stricmp(areaname, area->Tagname) == 0) break; if (!area) { LogWrite(1, USERERR, "Unknown area %s", areaname); return (TRUE); } if (!area->Messagebase) { LogWrite(1, USERERR, "Can't rescan %s, area is pass-through", areaname); return (TRUE); } if (!area->Messagebase->scanfunc) { LogWrite(1, USERERR, "Can't rescan %s", areaname); return (TRUE); } RescanNode = cnode; rescan_total = 0; success = (*area->Messagebase->scanfunc) (area, FALSE, FALSE, max, NULL, AcceptAny, HandleRescan); RescanNode = NULL; if (success) LogWrite(4, TOSSINGINFO, "Rescanned %lu messages", rescan_total); return (success); } bool SendAFList(uchar * node, short type) { struct Node4D n4d; struct ConfigNode *cnode; if (stricmp(node, "ALL") == 0) { for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next) if (cnode->Flags & NODE_NOTIFY) DoSendAFList(type, cnode); } else { if (!Parse4DTemplate(node, &n4d, &(((struct Aka *) (config.AkaList.First))->Node))) { LogWrite(1, USERERR, "Invalid node number \"%s\"", node); return (FALSE); } for (cnode = (struct ConfigNode *) config.CNodeList.First; cnode; cnode = cnode->Next) if (Compare4D(&cnode->Node, &n4d) == 0) break; if (cnode) { DoSendAFList(type, cnode); } else { LogWrite(1, USERERR, "Unknown node %u:%u/%u.%u", n4d.Zone, n4d.Net, n4d.Node, n4d.Point); return (FALSE); } } if (nomem || exitprg) return (FALSE); return (TRUE); } bool RemoveArea(uchar * areaname) { struct Area *area; for (area = (struct Area *) config.AreaList.First; area; area = area->Next) if (area->AreaType != AREATYPE_NETMAIL) if (stricmp(areaname, area->Tagname) == 0) break; if (!area) { LogWrite(1, USERERR, "Unknown area %s", areaname); return (TRUE); } LogWrite(1, AREAFIX, "AreaFix: Removing area %s", area->Tagname); SendRemoveMessages(area); area->AreaType=AREATYPE_DELETED; RemoveDeletedAreas(); return (TRUE); } bool done_initconfig = FALSE; bool done_welcomemsg = FALSE; bool done_init = FALSE; bool done_lockconfig = FALSE; bool LockConfig(uchar * file) { int i; bool rc = FALSE; for (i=0; i < 6 && !(rc=Lock(file, config.cfg_Flags & CFG_LOCKBYLINK, FALSE)); i++) { fprintf(stderr, "Configuration file %s is already in use, waiting 10 seconds...\n", file); #ifdef __MINGW32__ sleep(10000); #else sleep(10); #endif if (ctrlc) return (FALSE); } return rc; } void CleanUp(int err) { if (done_welcomemsg) LogWrite(2, SYSTEMINFO, "CrashEcho end"); if (done_lockconfig) Unlock(config.filename); if (done_init) Free(); if (done_initconfig) FreeConfig(&config); exit(err); } RETSIGTYPE breakfunc(int x) { ctrlc = TRUE; } bool CmdAreaFix(int argc, char **argv) { bool rc, check = FALSE; static struct option lopts[] = { {"help", 0, NULL, 'h'}, {"check", 0, NULL, 'c'}, {0, 0, 0, 0} }; static uchar optstr[] = "+hc"; static uchar helpstr[] = "Usage: crashecho areafix\n" "Scan primary netmail area for AreaFix requests\n" "\n" " -h, --help display this help and exit\n" " -c, --check only check for expired requests\n" "\n"; int ch, lopt_index; optind = 0; while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); return TRUE; /* Not reached */ case 'c': check = TRUE; break; } } argc -= optind; argv += optind; if(argc){ fprintf(stderr, helpstr); return FALSE; } if (!BeforeScanToss()) return FALSE; nowdoing = DOING_AFIX; if (check) rc = CheckAreaFix(); else rc = ScanAreaFix(); AfterScanToss(rc); return rc; } bool CmdToss(int argc, char **argv) { bool no_security = FALSE, tossbad = FALSE; static struct option lopts[] = { {"help", 0, NULL, 'h'}, {"bad", 0, NULL, 'b'}, {"no-security", 0, NULL, 's'}, {0, 0, 0, 0} }; static uchar optstr[] = "+hbs"; static uchar helpstr[] = "Usage: crashecho toss [OPTION]...\n" "Toss all .pkt files and bundles in inbound directories\n" "\n" " -h, --help display this help and exit\n" " -b, --bad retoss BAD area\n" " -s, --no-security process all packets without security checks\n" "\n"; int ch, lopt_index; optind = 0; while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); return TRUE; /* Not reached */ case 'b': tossbad = TRUE; break; case 's': no_security = TRUE; break; } } argc -= optind; argv += optind; if(argc){ fprintf(stderr, helpstr); return FALSE; } if (no_security) LogWrite(2, TOSSINGINFO, "Packets will be tossed without security checks"); if (!BeforeScanToss()) return (FALSE); nowdoing = DOING_TOSS; if (tossbad) { struct Area *area; for (area = (struct Area *) config.AreaList.First; area; area = area->Next) if (area->Messagebase && area->AreaType == AREATYPE_BAD) if (area->Messagebase->scanfunc) break; if (area) { LogWrite(2, TOSSINGINFO, "Retossing BAD area..."); nowdoing = DOING_TOSSBAD; if (!(*area->Messagebase->scanfunc) (area, FALSE, FALSE, 0, NULL, AcceptAny, HandleBad)) { AfterScanToss(FALSE); return (FALSE); } } else { LogWrite(2, TOSSINGINFO, "No BAD area configured"); } } else { /* Unpack bundles from ProtInbound to TempInbound */ if (!UnpackDir(config.cfg_ProtInbound, config.cfg_TempInbound)) { AfterScanToss(FALSE); return FALSE; } if (config.cfg_AfterUnpack[0]) { int res, rc; LogWrite(2, TOSSINGINFO, "Executing AFTERUNPACK script %s", config.cfg_AfterUnpack); res = Execute(config.cfg_AfterUnpack, &rc); if (!res) LogWrite(3, TOSSINGINFO, "AFTERUNPACK script exited with rc = %d", rc); else LogWrite(3, TOSSINGINFO, "AFTERUNPACK script failed"); } /* Toss packets in LocalInbound without security */ if (!TossDir(config.cfg_LocalInbound, TRUE, FALSE)) { AfterScanToss(FALSE); return FALSE; } /* Toss packets in ProtInbound */ if (!TossDir(config.cfg_ProtInbound, no_security, FALSE)) { AfterScanToss(FALSE); return FALSE; } /* Toss packets in TempInbound */ if (!TossDir(config.cfg_TempInbound, no_security, FALSE)) { AfterScanToss(FALSE); return FALSE; } /* Toss packets in Inbound */ if (!TossDir(config.cfg_Inbound, no_security, TRUE)) { AfterScanToss(FALSE); return FALSE; } } LogTossResults(); AfterScanToss(TRUE); return TRUE; } bool CmdScan(int argc, char **argv) { uchar *area = NULL, *list = NULL; bool rc; bool ignoreflags = FALSE; static struct option lopts[] = { {"help", 0, NULL, 'h'}, {"area", required_argument, NULL, 'a'}, {"list", required_argument, NULL, 'l'}, #ifdef MSGBASE_JAM {"ignore-flags", 0, NULL, 'i'}, #endif {0, 0, 0, 0} }; static uchar optstr[] = "+" "h" "a:" "l:" #ifdef MSGBASE_JAM "i" #endif ; static uchar helpstr[] = "Usage: crashecho scan [OPTION]...\n" "Scan areas for messages to export\n" "\n" " -h, --help display this help and exit\n" " -a, --area=NAME scan only specified area\n" " -l, --list=FILE scan only areas listed in the specified file\n" #ifdef MSGBASE_JAM " -i, --ignore-flags ignore netmail.jam/echomail.jam files\n" #endif "\n"; int ch, lopt_index; optind = 0; while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); return TRUE; /* Not reached */ case 'a': area = optarg; break; case 'l': list = optarg; break; #ifdef MSGBASE_JAM case 'i': ignoreflags = TRUE; break; #endif } } argc -= optind; argv += optind; if(argc){ fprintf(stderr, helpstr); return FALSE; } if (!BeforeScanToss()) return (FALSE); nowdoing = DOING_SCAN; if (area) rc = ScanArea(area); else if (list) rc = ScanList(list); else rc = Scan(ignoreflags); if (rc) LogScanResults(); AfterScanToss(rc); return rc; } bool CmdRescan(int argc, char **argv) { ulong num = 0; bool rc; static struct option lopts[] = { {"help", 0, NULL, 'h'}, {"max", required_argument, NULL, 'm'}, {0, 0, 0, 0} }; static uchar optstr[] = "+hm:"; static uchar helpstr[] = "Usage: crashecho rescan [OPTION]... AREA NODE\n" "Rescans the specified area for the specied node\n" "\n" " -h, --help display this help and exit\n" " -m, --max=NUMBER maximum number of messages to rescan\n" "\n"; int ch, lopt_index; optind = 0; while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); return TRUE; /* Not reached */ case 'm': num = atoi(optarg); break; } } argc -= optind; argv += optind; if(argc != 2){ fprintf(stderr, helpstr); return FALSE; } if (!BeforeScanToss()) return (FALSE); nowdoing = DOING_RESCAN; rc = Rescan(argv[0], argv[1], num); AfterScanToss(rc); return rc; } bool CmdRemove(int argc, char **argv) { static struct option lopts[] = { {"help", 0, NULL, 'h'}, {0, 0, 0, 0} }; static uchar optstr[] = "+h"; static uchar helpstr[] = "Usage: crashecho remove AREA [AREA]...\n" "Remove area(s) and unsubscribe\n" "\n" " -h, --help display this help and exit\n" "\n"; int ch, lopt_index; optind = 0; while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); return TRUE; /* Not reached */ } } argc -= optind; argv += optind; if(argc == 0){ fprintf(stderr, helpstr); return FALSE; } if (!BeforeScanToss()) return (FALSE); for (; argc > 0; argc--, argv++) RemoveArea(argv[0]); AfterScanToss(TRUE); return TRUE; } bool CmdNotify(int argc, char **argv) { int list = SENDLIST_INFO; bool rc = FALSE; static struct option lopts[] = { {"help", 0, NULL, 'h'}, {"HELP", 0, NULL, 'H'}, {"INFO", 0, NULL, 'I'}, {"LIST", 0, NULL, 'L'}, {"AVAIL", 0, NULL, 'A'}, {"QUERY", 0, NULL, 'Q'}, {"UNLINKED", 0, NULL, 'U'}, {0, 0, 0, 0} }; static uchar optstr[] = "+hHILAQU"; static uchar helpstr[] = "Usage: crashecho notify [OPTION] NODE\n" "Send AreaFix response to node\n" "\n" " -h, --help display this help and exit\n" " -H, --HELP send response to %%HELP command\n" " -I, --INFO send response to %%INFO command (default)\n" " -L, --LIST send response to %%LIST command\n" " -A, --AVAIL send response to %%AVAIL command\n" " -Q, --QUERY send response to %%QUERY command\n" " -U, --UNLINKED send response to %%UNLINKED command\n" "\n"; int ch, lopt_index; optind = 0; while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); return TRUE; /* Not reached */ case 'H': list = SENDLIST_HELP; break; case 'I': list = SENDLIST_INFO; break; case 'L': list = SENDLIST_FULL; break; case 'A': list = SENDLIST_AVAIL; break; case 'Q': list = SENDLIST_QUERY; break; case 'U': list = SENDLIST_UNLINKED; break; } } argc -= optind; argv += optind; if(argc != 1){ fprintf(stderr, helpstr); return FALSE; } if (!BeforeScanToss()) return FALSE; rc = SendAFList(argv[0], list); AfterScanToss(rc); return rc; } static struct cmd { char *name; bool (*func)(int, char **); } cmds[] = { {"areafix", CmdAreaFix}, {"toss", CmdToss}, {"scan", CmdScan}, {"rescan", CmdRescan}, {"remove", CmdRemove}, {"notify", CmdNotify}, {0, 0} }; int main(int argc, char **argv) { uchar *cfg = CONFIG_NAME; ulong cfgline; short seconderr = 0; uchar errorbuf[500]; static struct option lopts[] = { {"help", 0, NULL, 'h'}, {"config", required_argument, NULL, 'c'}, {"version", 0, NULL, SHOWVER}, {0, 0, 0, 0} }; static uchar optstr[] = "+hc:"; static uchar helpstr[] = "Usage: crashecho [OPTION]... COMMAND [OPTION]...\n" "\n" " -h, --help display this help and exit\n" " --version print version number and information about supported\n" " messagebases and features\n" " -c, --config=FILE use this configuration file instead of the default\n" "\n" "Valid commands are:\n" "\n" " areafix scan primary netmail area for AreaFix requests\n" " toss toss all .pkt files and bundles in inbound directory\n" " scan scan all areas for messages to export\n" " rescan rescans the specied area for the specied node\n" " remove remove specied area and unsubscribe\n" " notify send AreaFix response to a node\n" " lock lock CrashEcho's configuration file and exit\n" " unlock remove lock on CrashEcho's configuration file and exit\n" "\n" "(Specify the --help option for a list of other help options)\n" "\n"; static uchar helplock[] = "Usage: crashecho lock\n" "Lock CrashEcho's configuration file\n" "\n" " -h, --help display this help and exit\n" "\n"; static uchar helpunlock[] = "Usage: crashecho unlock\n" "Remove lock on CrashEcho's configuration file\n" "\n" " -h, --help display this help and exit\n" "\n"; int ch, lopt_index; signal(SIGINT, breakfunc); while((ch=getopt_long(argc, argv, optstr, lopts, &lopt_index)) != -1){ switch(ch){ case 'h': case '?': default: fprintf(stderr, helpstr); CleanUp(EXIT_OK); /* Not reached */ case SHOWVER: Version(); CleanUp(EXIT_OK); /* Not reached */ case 'c': cfg = optarg; break; } } argc -= optind; argv += optind; if (argc < 1) { fprintf(stderr, helpstr); CleanUp(EXIT_ERROR); } if (!stricmp(argv[0], "lock")) { if(argc != 1){ fprintf(stderr, helplock); if(!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) CleanUp(EXIT_OK); else CleanUp(EXIT_ERROR); } if (!LockConfig(cfg)) { fprintf(stderr, "Failed to lock configuration file %s\n", cfg); CleanUp(EXIT_ERROR); } fprintf(stderr, "CrashEcho is now locked, use `crashecho unlock' to unlock\n"); CleanUp(EXIT_OK); } if (!stricmp(argv[0], "unlock")) { if(argc != 1){ fprintf(stderr, helpunlock); if(!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) CleanUp(EXIT_OK); else CleanUp(EXIT_ERROR); } Unlock(cfg); CleanUp(EXIT_OK); } InitConfig(&config); done_initconfig = TRUE; if (!(done_lockconfig = LockConfig(cfg))) { fprintf(stderr, "Failed to lock configuration file %s\n", cfg); CleanUp(EXIT_ERROR); } if (!ReadConfig(cfg, &config, &seconderr, &cfgline, errorbuf, 500)) { if (seconderr == READCONFIG_INVALID) fprintf(stderr, "Configuration error in %s on line %ld:\n%s\n", cfg, cfgline, errorbuf); else if (seconderr == READCONFIG_NO_MEM) fprintf(stderr, "Out of memory\n"); else fprintf(stderr, "Failed to read configuration file %s\n", cfg); CleanUp(EXIT_ERROR); } if (config.areafile[0] == 0) { fprintf(stderr, "AREAFILE not defined in %s\n", cfg); CleanUp(EXIT_ERROR); } if (!ReadAreas(config.areafile, &config, &seconderr, &cfgline, errorbuf, 500)) { if (seconderr == READCONFIG_INVALID) fprintf(stderr, "Configuration error in %s on line %ld:\n%s\n", config.areafile, cfgline, errorbuf); else if (seconderr == READCONFIG_NO_MEM) fprintf(stderr, "Out of memory\n"); else fprintf(stderr, "Failed to read configuration file %s\n", config.areafile); CleanUp(EXIT_ERROR); } if (!CheckConfig(&config, errorbuf, 500)) { fprintf(stderr, "Configuration error:\n%s\n", errorbuf); CleanUp(EXIT_ERROR); } if (!Init()) CleanUp(EXIT_ERROR); done_init = TRUE; LogWrite(2, SYSTEMINFO, "%s started successfully!", verstr); done_welcomemsg = TRUE; for (ch = 0; cmds[ch].name; ch++) if (!stricmp(argv[0], cmds[ch].name)) break; if (!cmds[ch].name) { fprintf(stderr, helpstr); CleanUp(EXIT_ERROR); } if (!cmds[ch].func) { fprintf(stderr, "Command %s is not supported yet\n", cmds[ch].name); CleanUp(EXIT_ERROR); } (*cmds[ch].func)(argc, argv); if (nomem) LogWrite(1, SYSTEMERR, "Out of memory"); if (ioerror) LogWrite(1, SYSTEMERR, "I/O error: %s", strerror(ioerrornum)); if (ctrlc) LogWrite(1, SYSTEMERR, "*** User break ***"); CleanUp(EXIT_OK); /* The next line is never actually executed. * It is just there to stop gcc from giving a warning. */ return (0); }