/* ansi.c 1.4 83/10/04 */ /* ****************************************************************** * ANSI standard tape handler * * Usage: ansi [cxrt][012][d][v][s rec_siz] files.... * Default: t1 (lists all files on device /dev/rmt1) * Compile: cc -O ansi.c -o ansi * * Writes the ansi standard two header format. * Assumes 80 character maximum record length when writing tapes. * * Warren Gee * University of California, San Francisco * April, 1981 * * Revision History * ... Many mods by Laurie Jarvis and Tom Ferrin * 5aug83 Changed Extract to allocate larger input buffer * when buffer size exceeded (sizeof Buffer) - Conrad Huang * **************************************************************** */ #include #include #include #include #include #include #include #include #define NRMT0 "/dev/nrmt0" /* 800 bpi */ #define NRMT1 "/dev/nrmt1" /* 1600 bpi */ #define RMT0 "/dev/rmt0" #define RMT1 "/dev/rmt1" #define TESTFILE "ansi.out" #define Fill(A, B, C, D) strncpy(&A[B - 1], C, D) #define NULLCHAR '\0' #define BLANK ' ' #define TRUE 1 #define FALSE 0 #define HEAD_SIZE 81 #define BLOCK 2048 #define REC_SIZ 84 /* max record size assumed when writing including 4 byte label */ #define READ 0 #define WRITE 1 #define READ_WRITE 2 #define APPEND 0 #define CREATE 1 #define EXTRACT 2 #define TABLE 3 #define USAGE "Usage: %s [cxrt][01][dv][s rec_size] [files]\n" #define VMUNIX /* Define this if the gethostname call exists */ char *Command; char *Device; char *Nrmt0; char *Nrmt1; char *Testfile; char *Rmt0; char *Rmt1; char *TapeName; char TNBuffer[10]; char Buffer[4096]; char File[20]; char Hdr1[HEAD_SIZE]; char Hdr2[HEAD_SIZE]; char OBuffer[BLOCK]; char OpChar; char Temp[BLOCK]; char Vol[HEAD_SIZE]; extern errno; int filecnt; int CharCnt; int Chars; int Cnt; int Debug; int Eof; int Finish; int InFD; int InitHead; int InitVol; int Intrd; int Mode; int N; int OutFD; int Pntr; int RecSiz; int StartCnt; int Stop; int ThisLen; int Verbose; int Writing; long ByteTol; long lseek(); main(Argc, Argv) int Argc; char **Argv; { int i; struct mtop TapeOp; int Close(); int StopAppend(); RecSiz = REC_SIZ; if(GetArgs(Argc, Argv) != Argc) { Argc--; Argv++; } switch (Mode) { case APPEND : if (Argc == 2) Usage(); signal(SIGINT, StopAppend); signal(SIGHUP, StopAppend); InFD = OpenDev(READ); Extract((char **)0, 0); TapeOp.mt_op = MTBSR; TapeOp.mt_count = 2; ioctl(InFD, MTIOCTOP, &TapeOp); close(InFD); InitVol = TRUE; /* falls through */ case CREATE : signal(SIGINT, Close); signal(SIGHUP, Close); if (Argc == 2) Usage(); OutFD = OpenDev(WRITE); filecnt = 1; for (i = 2; i < Argc; i++) { TapeWrite(Argv[i]); filecnt++; } close(OutFD); if(Device != Testfile) Device = (Device == Nrmt0) ? Rmt0 : Rmt1; OutFD = OpenDev(WRITE); close(OutFD); break; case EXTRACT : case TABLE : Device = (Device == Nrmt0) ? Rmt0 : Rmt1; InFD = OpenDev(READ); Extract(&Argv[2], Argc - 2); break; default : if (Debug) fprintf(stderr, "Bad Mode in main switch\n"); break; } } /* * FixTapeName - make Tape name buffer 6 characters long */ FixTapeName(buf) char *buf; { int done = 0, i; for (i=0; i<=6; i++) { if (done) { buf[i]=' '; } else if (buf[i]=='\0') { done=1; buf[i]=' '; } } buf[7]='\0'; } /* * GetArgs - get param line arguments and initialize status flags */ GetArgs(Argc, Argv) int Argc; char **Argv; { char *Chr; char *ModeStr; Writing = FALSE; Rmt0 = RMT0; Rmt1 = RMT1; Nrmt0 = NRMT0; Nrmt1 = NRMT1; Testfile = TESTFILE; Mode = TABLE; ModeStr = "TABLE"; Verbose = FALSE; InitVol = FALSE; Debug = FALSE; Device = Nrmt1; Command = *Argv; Eof = FALSE; Stop = FALSE; Intrd = FALSE; if (Argc < 2) Usage(); Argv++; Chr = *Argv; OpChar = 't'; while (*Chr != NULLCHAR) { switch (*Chr) { case 's' : Argv++; Argc--; sscanf(*Argv,"%d",&RecSiz); RecSiz += 4; break; case 'c' : Mode = CREATE; OpChar = *Chr; #ifdef VMUNIX if (gethostname(TNBuffer, 6) == -1) strcpy(TNBuffer, "UCSF "); else { register char *cp; register i; for (i = 0, cp = TNBuffer; i < 6; i++, cp++) { if (*cp == '\0') break; if (islower(*cp)) *cp = toupper(*cp); } while (i++ < 6) *cp++ = ' '; *cp = '\0'; } #else VMUNIX strcpy(TNBuffer, "UCSF "); #endif VMUNIX TapeName = TNBuffer; ModeStr = "CREATE"; break; case 'l' : Argv++; Argc--; sscanf(*Argv,"%s",TNBuffer); TapeName = TNBuffer; FixTapeName(TapeName); break; case 'x' : Mode = EXTRACT; OpChar = *Chr; ModeStr = "EXTRACT"; break; case 't' : Mode = TABLE; OpChar = *Chr; ModeStr = "TABLE"; break; case 'r' : Mode = APPEND; OpChar = *Chr; ModeStr = "APPEND"; break; case '1' : Device = Nrmt1; break; case '0' : Device = Nrmt0; break; case '2' : Device = Testfile; break; case 'v' : Verbose = TRUE; break; case 'd' : Debug = TRUE; break; default : fprintf(stderr, "unknown option '"); PrintChr(*Chr, stderr); fprintf(stderr, "'\n"); Usage(); break; } Chr++; } if (Debug) { fprintf(stdout,"Debug : set\n"); if (Verbose) fprintf(stdout,"Verbose : Set\n"); fprintf(stdout,"Mode = %s\n", ModeStr); fprintf(stdout,"Device = %s\n", Device); fprintf(stdout,"Max record size = %d\n",RecSiz); } return(Argc); } /* * PrintChar - print ascii character */ PrintChr(Chr, Stream) char Chr; FILE *Stream; { if (isprint(Chr) || Chr == BLANK) fprintf(Stream, "%c", Chr); else if (0 <= Chr && Chr < BLANK) fprintf(Stream, "^%c", Chr + 'A' - 1); else fprintf(Stream, "\\0%o", Chr); } /* * Usage - print usage diagnostic and exit */ Usage() { fprintf(stderr, USAGE, Command); exit(-1); } /* * TapeWrite - write a file to tape */ TapeWrite(FileName) char *FileName; { int i; char StrTmp[10]; int OverFlow; int Written; int blkcnt; /* block count */ struct stat Buf; InFD = open(FileName, READ); if (InFD == -1) { perror(FileName); return; } fstat(InFD, &Buf); if (Buf.st_mode & S_IFDIR) { fprintf(stderr, "%s: directory\n", FileName); return; } if (Buf.st_mode & S_IEXEC) { fprintf(stderr, "%s: executable\n", FileName); return; } if(strlen(FileName) > 17) fprintf(stderr,"Warning: Filename %s exceeds 17 characters : truncated\n",FileName); sprintf(File, "%-17.17s", FileName); ByteTol = 0; Finish = FALSE; N = 4; /* current position in output buffer */ StartCnt = 0; /* start of current record in output buffer */ Cnt = 4; /* byte count relative to StartCnt */ CharCnt = 0; /* set by GetChar() */ Chars = -1; /* set by GetChar() */ blkcnt = 0; /* initialize block count */ OBuffer[N] = GetChar(); OverFlow = FALSE; Written = FALSE; InitHead = FALSE; while (!Finish) { if (OBuffer[N] == '\n') { sprintf(StrTmp, "%04d", Cnt); /* zero-filled byte count */ if(Cnt > RecSiz) fprintf(stdout,"Warning: Record exceeds %d characters [file %s]; use -s to increase limit\n",RecSiz - 4,FileName); strncpy(&OBuffer[StartCnt], StrTmp, 4); StartCnt = N; N += 4; Cnt = 4; if (N >= BLOCK) { N = 4; OverFlow = TRUE; } } else { N++; Cnt++; if (N >= BLOCK) { N = BLOCK - StartCnt; OverFlow = TRUE; } } if (OverFlow) { if (StartCnt == 0) { fprintf(stderr, "Line too long, must be less than %d characters\n", BLOCK); Close(); break; } strncpy(Temp,&OBuffer[StartCnt + 4],N - 4); for (i = StartCnt; i < BLOCK; i++) OBuffer[i] = '^'; if (!InitHead) Headers(); Write(OutFD, OBuffer, BLOCK); blkcnt++; Written = TRUE; strncpy(&OBuffer[4], Temp, N - 4); StartCnt = 0; Cnt = N; OverFlow = FALSE; } OBuffer[N] = GetChar(); } if (N > 4 || !Written) { while (StartCnt < BLOCK) { OBuffer[StartCnt] = '^'; StartCnt++; } if (!InitHead) Headers(); Write(OutFD, OBuffer, BLOCK); blkcnt++; } close(InFD); TapeMark(); Fill(Hdr1, 1, "EOF", 3); sprintf(StrTmp,"%06d",blkcnt); Fill(Hdr1,55, StrTmp , 6); Write(OutFD, Hdr1, 80); Fill(Hdr2, 1, "EOF", 3); Fill(Hdr2, 51, "00", 2); Write(OutFD, Hdr2, 80); Writing = FALSE; if (Verbose) fprintf(stdout,"%c - %7D bytes \"%s\"\n", OpChar, ByteTol, FileName); TapeMark(); if (Intrd) Close(); /* close output device and exit */ } /* * Headers - write ansi file headers to output device */ Headers() { char StrTmp[10]; Writing = TRUE; if (!InitVol) { blk_fil(Vol, 1, 80); /*** VOLUMN LABEL #1 ***/ Fill(Vol, 1, "VOL", 3); Fill(Vol, 4, "1", 1); Fill(Vol, 5, TapeName, 6); Fill(Vol, 11, " ", 1); blk_fil(Vol, 12, 26); Fill(Vol, 38, "D%B 1", 14); blk_fil(Vol, 52, 28); Fill(Vol, 80, "3", 1); Write(OutFD, Vol, 80); if (Debug) Write(1, Vol, 80); InitVol = TRUE; } blk_fil(Hdr1, 1, 80); /*** HEADER LABEL #1 ***/ Fill(Hdr1, 1, "HDR", 3); Fill(Hdr1, 4, "1", 1); Fill(Hdr1, 5, File, 17); Fill(Hdr1, 22, TapeName, 6); Fill(Hdr1, 28, "0001", 4); sprintf(StrTmp, "%04d", filecnt); Fill(Hdr1, 32, StrTmp, 4); Fill(Hdr1, 36, "0001", 4); Fill(Hdr1, 40, "00", 2); Fill(Hdr1, 42, "000000", 6); Fill(Hdr1, 48, "000000", 6); blk_fil(Hdr1, 54, 1); Fill(Hdr1, 55, "000000", 6); Fill(Hdr1, 61, "DECUNIX ", 13); blk_fil(Hdr1, 74, 7); Write(OutFD, Hdr1, 80); if (Debug) Write(1, Hdr1, 80); blk_fil(Hdr2, 1, 80); /*** HEADER LABEL #2 ***/ Fill(Hdr2, 1, "HDR", 3); Fill(Hdr2, 4, "2", 1); Fill(Hdr2, 5, "D", 1); sprintf(StrTmp, "%05d", BLOCK); Fill(Hdr2, 6, StrTmp, 5); sprintf(StrTmp, "%05d", RecSiz); Fill(Hdr2, 11, StrTmp, 5); blk_fil(Hdr2, 16, 21); Fill(Hdr2, 37, " ", 1); blk_fil(Hdr2, 38, 13); Fill(Hdr2, 51,"00", 2); blk_fil(Hdr2, 53, 28); Write(OutFD, Hdr2, 80); if (Debug) Write(1, Hdr2, 80); TapeMark(); InitHead = TRUE; } /* * GetChar - returns next character from input */ GetChar() { CharCnt++; if (CharCnt >= Chars) { Chars = read(InFD, Buffer, 4096); if (Chars == -1) { perror(Device); exit(-1); } else if (Chars == 0) { Finish = TRUE; return (-1); } ByteTol += Chars; CharCnt = 0; } return (Buffer[CharCnt]); } /* * blk_fil - blank fill str beginning at start for count bytes */ blk_fil(str,start,count) char *str; { char *s; if(start <= 0) return; s = &str[start - 1]; for(;count > 0;count--) *s++ = BLANK; } /* * Extract - scans ansi input for FileCnt files specified in **File * if FileCnt == 0, extracts all files * does not write files to disk if mode is APPEND or TABLE */ Extract(File, FileCnt) char **File; int FileCnt; { char FileName[20]; char RecFrmt; char FrmtCntl; char *InputBuf; int RecLen; int BlckSize; int ByteCnt; long ByteTol; int WriteIt; int i; char *malloc(); GetLabel("VOL1"); GetLabel("HDR1"); while (!Eof) { sscanf(&Buffer[4], "%17s", FileName); for (i = 16; (i >= 0) && (FileName[i] == ' '); i--) ; FileName[i + 1] = NULLCHAR; if (Mode == TABLE || Mode == APPEND) WriteIt = FALSE; else if (FileCnt == 0) WriteIt = TRUE; else { WriteIt = FALSE; for (i = 0; i < FileCnt; i++) if (!strcmp(File[i], FileName)) WriteIt = TRUE; } if (WriteIt) { if( (OutFD = creat(FileName, 0666)) == -1) { perror(FileName); exit(-1); } /* CheckStat(OutFD, FileName); */ } RecFrmt = 'D'; FrmtCntl = BLANK; RecLen = BLOCK; BlckSize = BLOCK; GetLabel("HDR2"); sscanf(&Buffer[5], "%5d", &BlckSize); sscanf(&Buffer[10], "%5d", &RecLen); RecFrmt = Buffer[4]; if (RecFrmt == 'S' || RecFrmt == 'U') { fprintf(stderr, "Format '%c' is not supported\n", RecFrmt); exit(-1); } FrmtCntl = Buffer[36]; GetEof(); if (BlckSize <= sizeof Buffer) InputBuf = Buffer; else { InputBuf = malloc(BlckSize); if (InputBuf == NULL) { fprintf(stderr, "Not enough memory for buffering %d bytes\n", BlckSize); exit(1); } } ThisLen = RecLen; ByteTol = 0; while ((ByteCnt = read(InFD, InputBuf, BlckSize)) > 0) { if(ByteCnt != BlckSize) fprintf(stderr,"Unexpected data record: asked for %d, got %d\n", BlckSize,ByteCnt); ByteTol += ByteCnt; Pntr = 0; if (ThisLen != RecLen) { Pntr = RecLen - ThisLen; if (WriteIt) Write(OutFD, InputBuf, Pntr); Pntr += (RecLen % 2); if (FrmtCntl != 'M') { ByteTol -= 3; if (WriteIt) Write(OutFD, "\n", 1); } } while (Pntr < ByteCnt) { if (RecFrmt == 'D') { if (InputBuf[Pntr] == '^') { Pntr++; ByteTol--; continue; } sscanf(&InputBuf[Pntr], "%4d", &RecLen); RecLen -= 4; Pntr += 4; if (RecLen == -1 || RecLen == -257) break; if (RecLen > 2 * BlckSize || RecLen < 0) { fprintf(stdout,"Bad variable record length %d\n",RecLen); fprintf(stdout,"Switching over to fixed length\n"); RecFrmt = 'F'; RecLen = BlckSize; FrmtCntl = 'M'; Pntr -= 4; } } ThisLen = (Pntr + RecLen > BlckSize) ? BlckSize - Pntr : RecLen; if (WriteIt) Write(OutFD, &InputBuf[Pntr], ThisLen); if (FrmtCntl != 'M' && ThisLen == RecLen) { ByteTol -= 3; if (WriteIt) Write(OutFD, "\n", 1); } Pntr += ThisLen; } } if(ByteTol == 0 && (Verbose || Debug) ) fprintf(stderr,"Null file found: %s\n",FileName); close(OutFD); if ((WriteIt && (Verbose || Debug)) || (Verbose && Mode == TABLE && FileCnt == 0)) fprintf(stdout,"%c - %7D bytes \"%s\"\n", OpChar, ByteTol, FileName); else if (Mode == TABLE && FileCnt == 0 && !Verbose) fprintf(stdout,"\"%s\"\n", FileName); else if (Mode == TABLE && FileCnt != 0) for (i = 0; i < FileCnt; i++) if (!strcmp(File[i], FileName)) if (Verbose) fprintf(stdout,"%c - %7D bytes \"%s\"\n", OpChar, ByteTol, FileName); else fprintf(stdout,"\"%s\"\n", FileName); GetLabel("EOF1"); GetLabel("EOF2"); if (Stop) { close(InFD); Device = (Device == Nrmt0) ? Rmt0 : Rmt1; InFD = OpenDev(READ); close(InFD); exit(0); } GetEof(); GetLabel("HDR1"); if (InputBuf != Buffer) free(InputBuf); } } /* * GetLabel - read next record from input; check for Key record type */ GetLabel(Key) char *Key; { int ByteCnt; ByteCnt = read(InFD, Buffer, 80); if ((ByteCnt == 0) && !strncmp(Key, "HDR1", 4)) { if ((Debug || Verbose) && OpChar != 'r') fprintf(stdout,"End of Tape\n"); Eof = TRUE; } else if (ByteCnt != 80 || strncmp(Buffer, Key, 4)) { fprintf(stderr, "Unsuccessful attempt to find %s record\n", Key); exit(-1); } } /* * Write - write BCount bytes of Str to file descriptor FD */ Write(FD, Str, BCount) int FD; char *Str; int BCount; { if (write(FD, Str, BCount) != BCount) { perror(Device); fprintf(stderr, "Unable to write to %s\n", Device); } } /* * Close - close output device and exit */ Close() { signal(SIGINT, SIG_IGN); Intrd = TRUE; if (Writing) return; close(OutFD); if(Device != Testfile) { /* if not a testfile, rewind */ Device = (Device == Nrmt0) ? Rmt0 : Rmt1; OutFD = OpenDev(WRITE); close(OutFD); } exit(-1); } /* * StopAppend - ignore signals */ StopAppend() { signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); Stop = TRUE; } OpenDev(OpenMode) int OpenMode; { register FD; register Count; FD = open(Device, OpenMode); for (Count = 0; FD == -1 && Count < 3; Count++) { if(Device == Testfile) /* if device is a file */ FD = creat(Device, 0666); else FD = open(Device, OpenMode); } if (FD == -1) { if (errno == EIO) fprintf(stderr, "%s offline or needs write ring\n", Device); else if (errno == ENXIO) fprintf(stderr, "%s already in use\n", Device); else perror(Device); exit(-1); } return (FD); } TapeMark() { static int mtdevice = 1; static struct mtop mtop = {MTWEOF, 1L}; struct mtget mtget; if (mtdevice == 1) mtdevice = ioctl(OutFD, MTIOCGET, &mtget); if (mtdevice == 0) { if (ioctl(OutFD, MTIOCTOP, &mtop) < 0) { fprintf(stderr, "ansi: error writing EOF\n"); exit(1); } } } GetEof() { static int mtdevice = 1; static struct mtop mtop = {MTFSF, 1L}; struct mtget mtget; /* while (read(InFD, Buffer, 80) != 0) ; */ if (mtdevice == 1) mtdevice = ioctl(InFD, MTIOCGET, &mtget); if (mtdevice == 0) { if (ioctl(InFD, MTIOCTOP, &mtop) < 0) { fprintf(stderr, "ansi: error positioning tape\n"); exit(1); } } else fprintf(stderr,"ansi: GetEOF ioctl fails\n"); }