/* $Id: explode.c,v 6.4 2012/11/12 20:47:00 ksb Exp $ * This program burstes M.I.C.E. archieves into common C code. (ksb) * * Kevin S Braunsdorf * msrc at ksb.npcguild.noSpam.org */ #include #include #include #include #include #include #include #include #include #include #include "machine.h" #include "explode.h" #include "main.h" extern struct passwd *getpwnam(); #if HAVE_STRINGS #include #else #include #endif /* we have to die because we are out of core (ksb) */ static void OutOfMem() { static char acFailMem[] = ": out of memory\n"; write(2, progname, strlen(progname)); write(2, acFailMem, sizeof(acFailMem)-1); exit(ENOMEM); } static char acNull[]= "/dev/null", /* the bit bucket */ acTty[]= "/dev/tty", /* the users tty */ acAppend[]= "Append", acHead[]= "Header", acExp[] = "Explode", acRem[] = "Remove", acVersion[] = "Version", acIns[] = "Insert", acShell[] = "Shell", acMsg[] = "Message"; #define MAXLINE 2048 /* max C code line ANSI sez 509 */ static char *pcTemp, /* the real temp file name */ acTemp[] = /* file name template for header */ "/tmp/explXXXXXX", acStdin[] = /* internal name for "-" on cmd line */ "stdin"; /* search a path (colon separated) for a directory that has the file (ksb) * fall back on ./file always first, and full paths are not scanned */ static FILE * SearchOpen(pcPath, pcFile, pcHow) char *pcPath, *pcFile, *pcHow; { register char *pcNext; static char acColon[] = ":"; register FILE *fpFound; auto char acTry[MAXPATHLEN+1]; if (acStdin == pcFile) { if (fPrint) { printf("-\n"); } return stdin; } if ((FILE *)0 != (fpFound = fopen(pcFile, pcHow)) || '/' == pcFile[0]) { if (fPrint && (FILE *)0 != fpFound) { printf("%s\n", pcFile); } return fpFound; } for (; *pcPath != '\000'; (*pcNext = ':'), pcPath = pcNext+1) { pcNext = strchr(pcPath, ':'); if ((char *)0 == pcNext) pcNext = acColon; *pcNext = '\000'; if ('~' == pcPath[0]) { register char *pcSlash; register struct passwd *pwd; static char acSlash[] = "/"; if ((char *)0 == (pcSlash = strchr(pcPath+1, '/'))) pcSlash = acSlash; *pcSlash = '\000'; pwd = ('\000' == pcPath[1]) ? getpwuid(getuid()) : getpwnam(pcPath+1); *pcSlash = '/'; if ((struct passwd *)0 == pwd) { continue; } sprintf(acTry, "%s/%s/%s", pwd->pw_dir, pcSlash+1, pcFile); } else { sprintf(acTry, "%s/%s", pcPath, pcFile); } if (fVerbose) { fprintf(stderr, "%s: search for %s as %s\n", progname, pcFile, acTry); } if ((FILE *)0 != (fpFound = fopen(acTry, pcHow))) { *pcNext = ':'; if (fPrint) { printf("%s\n", acTry); } return fpFound; } } return (FILE *)0; } /* make sure global flages are consistant (ksb) * and build temp file name */ void SetGlobals() { extern char *mktemp(); register int iFd; if (!fActive) { fVerbose = 1; } #if USE_MKSTEMP if (-1 == (iFd = mkstemp(acTemp))) { fprintf(stderr, "%s: mkstemp: %s\n", progname, strerror(errno)); exit(EX_TEMPFAIL); } pcTemp = acTemp; #else /* Try to make mktemp as safe as we can (ksb) */ if ((char *)0 == (pcTemp = mktemp(acTemp))) { fprintf(stderr, "%s: mktemp: %s\n", progname, strerror(errno)); exit(EX_TEMPFAIL); } if (-1 == (iFd = open(pcTemp, O_RDWR, 0600))) { fprintf(stderr, "%s: open: %s: %s\n", progname, pcTemp, strerror(errno)); (void)unlink(pcTemp); exit(EX_TEMPFAIL); } if (-1 == fchmod(iFd, 0600)) { fprintf(stderr, "%s: fchmod: %s: %s\n", progname, pcTemp, strerror(errno)); (void)unlink(pcTemp); exit(EX_TEMPFAIL); } #endif (void)close(iFd); } /* zap the temp file (ksb) */ void RemoveTemp() { (void)unlink(pcTemp); } /* tell if we need this file (ksb) * We need all files if none are asked for, we need only those * in the list is any are asked for. */ static int Need(pc) char *pc; { register char *pcCur, *pcNext; static char acComma[] = ","; if ((char *)0 == (pcCur = pcUnpack)) { return 1; } for (; *pcCur != '\000'; (*pcNext = ','), pcCur = pcNext+1) { pcNext = strchr(pcCur, ','); if ((char *)0 == pcNext) pcNext = acComma; *pcNext = '\000'; if (0 == strcmp(pc, pcCur)) { *pcNext = ','; return 1; } } return 0; } /* qwery the user WRT this file, should we alter it (ksb) */ static int Asked(pcFile) char *pcFile; { static char *pcTold = (char *)0; auto char acAns[32]; register char *pcCur, *pcNext; static char acComma[] = ","; if (!fAsk) { return 0; } /* is this in the list we already asked about? */ if ((char *)0 != (pcCur = pcTold)) { for (pcCur = pcTold; *pcCur != '\000'; (*pcNext = ','), pcCur = pcNext+1) { pcNext = strchr(pcCur, ','); if ((char *)0 == pcNext) pcNext = acComma; *pcNext = '\000'; if (0 == strcmp(pcFile, pcCur+1)) { *pcNext = ','; return 'y' == *pcCur; } } } fprintf(stdout, "%s: modify %s? [ny] ", progname, pcFile); fflush(stdout); if ((char *)0 == fgets(acAns, sizeof(acAns), stdin)) { fprintf(stdout, "no\n"); acAns[0] = 'n'; } for (pcCur = acAns; isspace(*pcCur); ++pcCur) /* nothing */; acAns[0] = ('Y' == *pcCur || 'y' == *pcCur) ? 'y' : 'n'; if ((char *)0 == pcTold) { pcTold = pcCur = malloc(1+strlen(pcFile)+1); if ((char *)0 == pcTold) { OutOfMem(); } } else { register int i; i = strlen(pcTold); pcTold = realloc(pcTold, i+1+1+strlen(pcFile)+1); if ((char *)0 == pcTold) { OutOfMem(); } pcCur = pcTold + i; *pcCur++ = ','; } *pcCur++ = acAns[0]; (void)strcpy(pcCur, pcFile); return 'y' == acAns[0]; } /* does all the work of unpacking the files from the MICE archive (ksb) */ void UnPack(pcFile, pcBase) char *pcFile, *pcBase; { static char acPath[MAXPATHLEN+1], acWMode[] = "w", acAMode[] = "a"; auto char acLine[MAXLINE+1]; auto char acBase[255]; register FILE *fpIn, *fpOut; register char *pcMode, *pc; register FILE *fpHead; register int fNewHeader; if (NULL == pcFile || ('-' == pcFile[0] && '\000' == pcFile[1])) { pcFile = acStdin; if ((char *)0 == pcBase) { pcBase = acStdin; } } else if (NULL == pcBase) { pc = strrchr(pcFile, '/'); if (NULL == pc) pc = pcFile; else ++pc; (void)strcpy(acBase, pc); pc = strrchr(acBase, '.'); if (NULL != pc) *pc = '\000'; pcBase = acBase; } SetDelExt(pcFile); if (fVerbose) { if (fTable) fprintf(stdout, "%s: contents of ", progname); else fprintf(stdout, "%s: unpack ", progname); if ((char *)0 != pcUnpack) fprintf(stdout, "only %s in ", pcUnpack); fprintf(stdout, "%s to %s*%s\n", acStdin == pcFile ? "" : pcFile, pcBase, pcExt); } if (NULL == (fpIn = SearchOpen(pcIncl, pcFile, "r"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcFile, strerror(errno)); exit(EX_NOINPUT); } if (fPrint) { return; } fpOut = (FILE *)0; if (fWhole) { if ('-' != pcBase[0] || '\000' != pcBase[1]) { sprintf(acPath, "%s%s", pcBase, pcExt); if (0 == fOverwrite && 0 == access(acPath, F_OK) && 0 == Asked(acPath)) { fprintf(stderr, "%s: won't overwrite %s\n", progname, acPath); exit(EX_DATAERR); } if (fVerbose) { fprintf(stdout, "%s: found %s\n", progname, acPath); } if (! fActive) { goto get_out; } if (NULL == (fpOut = fopen(acPath, acWMode))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, acPath, strerror(errno)); exit(EX_CANTCREAT); } } else if (! fActive) { goto get_out; } else { fpOut = stdout; } while (NULL != fgets(acLine, sizeof(acLine), fpIn)) { fputs(acLine, fpOut); } goto get_out; } if (NULL == (fpHead = fopen(pcTemp, "w"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcTemp, strerror(errno)); exit(EX_OSERR); } #ifdef DEBUG fprintf(fpHead, "%s no header given */\n", pcDel); #endif /* DEBUG */ fclose(fpHead); if ((FILE *)0 == (fpOut = fopen(acNull, "w"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, acNull, strerror(errno)); exit(EX_OSERR); } fNewHeader = 0; while (NULL != fgets(acLine, sizeof(acLine), fpIn)) { if (0 != strncmp(pcDel, acLine, iDelLen)) { fputs(acLine, fpOut); continue; } pc = & acLine[iDelLen]; while (isspace(*pc)) ++pc; pcMode = acWMode; if (fTable) { register char *pcFind; static char acCurVer[2048]; if (0 == strncmp(pc, acVersion, sizeof(acVersion)-1)) { pc += sizeof(acVersion)-1; while (isspace(*pc)) ++pc; pcFind = acCurVer; while (*pc != cClose) *pcFind++ = *pc++; *pcFind = '\000'; continue; } else if (0 == strncmp(pc, acExp, sizeof(acExp)-1)) { pc += sizeof(acExp); } else if (0 == strncmp(pc, acHead, sizeof(acHead)-1)) { pc += sizeof(acHead); } else { continue; } while (isspace(*pc)) ++pc; pcFind = pc; while (!isspace(*pc) && *pc != cClose) ++pc; *pc = '\000'; if ('\000' == *pcFind) pcFind = "*"; else if ((char *)0 != pcUnpack && ! Need(pcFind)) continue; printf("%s\t%s%s%s", pcFile, pcBase, pcFind, pcExt); if ('\000' != acCurVer[0]) printf("\t%s", acCurVer); printf("\n"); continue; } if (0 == strncmp(pc, acExp, sizeof(acExp)-1) || (pcMode = acAMode, 0 == strncmp(pc, acAppend, sizeof(acAppend)-1))) { register char *pcFind; pc += pcMode == acExp ? sizeof(acExp) : sizeof(acAppend); while (isspace(*pc)) ++pc; pcFind = pc; while (!isspace(*pc) && *pc != cClose) ++pc; *pc = '\000'; if ((char *)0 != pcUnpack && ! Need(pcFind)) { goto dev_null; } if (stdout != fpOut) { fclose(fpOut); } if ('-' != pcBase[0] || '\000' != pcBase[1]) { sprintf(acPath, "%s%s%s", pcBase, pcFind, pcExt); if (0 == fOverwrite && acWMode == pcMode && 0 == access(acPath, F_OK) && 0 == Asked(acPath)) { fprintf(stderr, "%s: won't overwrite %s\n", progname, acPath); exit(EX_DATAERR); } if (fVerbose) { fprintf(stdout, "%s: %s %s\n", progname, acWMode == pcMode ? "create" : "append", acPath); } if (! fActive) { continue; } if (NULL == (fpOut = fopen(acPath, pcMode))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, acPath, strerror(errno)); exit(EX_CANTCREAT); } } else if (! fActive) { continue; } else { fpOut = stdout; if (! fNewHeader) { continue; } } if (acWMode != pcMode) { continue; } if (NULL == (fpHead = fopen(pcTemp, "r"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcTemp, strerror(errno)); exit(EX_OSERR); } while (NULL != fgets(acLine, sizeof(acLine), fpHead)) { fputs(acLine, fpOut); } fclose(fpHead); fNewHeader = 0; } else if (0 == strncmp(pc, acIns, sizeof(acIns)-1)) { register int iStop; if (fVerbose) fprintf(stdout, "%s: insert text\n", progname); pc += sizeof(acIns)-1; while (isspace(*pc)) ++pc; iStop = *pc; while (iStop != *++pc) putc(*pc, fpOut); putc('\n', fpOut); } else if (0 == strncmp(pc, acShell, sizeof(acShell)-1)) { register int iStop; register char *pcCmd; register FILE *fpShell; pc += sizeof(acShell)-1; while (isspace(*pc)) ++pc; iStop = *pc; pcCmd = pc+1; while (iStop != *++pc) ; *pc = '\000'; if (fVerbose) fprintf(stdout, "%s: shell `%s'\n", progname, pcCmd); if ((FILE *)0 == (fpShell = popen(pcCmd, "r"))) { fprintf(stdout, "%s: shell fail: %s\n", progname, strerror(errno)); exit(EX_UNAVAILABLE); } while (EOF != (iStop = getc(fpShell))) { putc(iStop, fpOut); } pclose(fpShell); } else if (0 == strncmp(pc, acHead, sizeof(acHead)-1)) { if (fVerbose) fprintf(stdout, "%s: new header\n", progname); fNewHeader = fHeader; fflush(fpOut); if (stdout != fpOut) fclose(fpOut); if (fActive && NULL == (fpOut = fopen(pcTemp, "w"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, pcTemp, strerror(errno)); exit(EX_OSERR); } } else if (0 == strncmp(pc, acRem, sizeof(acRem)-1)) { if (fVerbose) fprintf(stdout, "%s: remove text\n", progname); fflush(fpOut); dev_null: if (stdout != fpOut) fclose(fpOut); if (fActive && NULL == (fpOut = fopen(acNull, "w"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, acNull, strerror(errno)); exit(EX_OSERR); } } else if (0 == strncmp(pc, acMsg, sizeof(acMsg)-1)) { if (fVerbose) fprintf(stdout, "%s: message text\n", progname); fflush(fpOut); if (stdout != fpOut) fclose(fpOut); if (fActive && NULL == (fpOut = fopen(acTty, "w"))) { fprintf(stderr, "%s: fopen: %s: %s\n", progname, acTty, strerror(errno)); exit(EX_IOERR); } } } get_out: if ((FILE *)0 != fpIn && stdin != fpIn) { fclose(fpIn); } if ((FILE *)0 != fpOut && stdout != fpOut) fclose(fpOut); RemoveTemp(); }