eager@amd.UUCP (Mike Eager) (11/30/84)
Here is a new copy of the ansitar utility that was distributed across the net some months ago. A manual page has been created, several bugs fixed, and a couple options added. These options keep the tape from re-winding when the program completes, improved support VMS "D" type files. See manual page for more info. ---------------------ansitar.1------------------------ .TH ANSITAR 1 "AMD local" .SH NAME ANSITAR \- a program to read and write ANSI labeled tapes .SH SYNOPSIS .B ansitar [crxtvblnf] [blocksize] [labelsize] [filecount] file .SH DESCRIPTION .PP .I Ansitar is a program which reads and writes ANSI format labelled tapes. Its options are similar to tar: .TP 8 .B c create a tape .TP 8 .B r replace (update) a tape .TP 8 .B x extract files .TP 8 .B t print table of contents .TP 8 .B v set verbose mode: for crx, print names; for t print labels .TP 8 .B 0-9 select drive 0-9 (default 0) .TP 8 .B b use next argument as a block size (default is 2048 bytes) .TP 8 .B B use next argument as tape block size, and following argument as line size (for blocking/unblocking) .TP 8 .B l use next arg as a label size .TP 8 .B U select upper(out)/lower(in) case translation of names .TP 8 .B R use RT11 label and name conventions (UGH!) .TP 8 .B S use RSTS conventions (==RT11 except 80-byte labels) .TP 8 .B P create/read files in "pip" (FILES-11) counted format. .TP 8 .B D read variable length records (D format) .TP 8 .B n do not rewind tape at completion of processing .TP 8 .B f use next argument as number of files to search for .B t or .B x options. Ignored if file names specified. .PP The filename may contain * to indicate a wild card; however, the asterisk should be enclosed in quotes to prevent the shell from interpreting it. .PP Examples of usage: .PP ansitar tv Verbose table of contents .PP ansitar xvDUb 2000 file1 file2 Extract file1 and file2 from .br tape with 2000 bytes/block .br and variable length records .PP ansitar xv *.c Extract all files with .c .br extension from tape with .br 2048 byte/block .PP ansitar tvfn 5 List contents of first 5 .br files and do not rewind tape .PP ansitar xvf 5 Extract the first five files .SH FILES /dev/mt?? .SH SEE ALSO tar(1), mt(4) .SH DIAGNOSTICS .PP Many and verbose. Most are self-explanatory. .PP bad block size: block size <= 0 .PP bad line size: line size <= 0 or not divisor of block size .PP label size must be >= <int>: label size too small to hold header .PP can't open <tapefile>: couldn't open tape device .PP can't allocate buffer of <int> bytes: malloc couldn't get buffer .PP can't allocate line buffer of <int> bytes: malloc couldn't get buffer .PP can't create <file> .PP can't open <file> .SH BUGS .PP Writing variable length records (D format) is not implemented. .PP Wild cards have not been extensively tested. .PP Warning: The routines skipfile and backspace use nonstandard (4.1BSD) ioctl calls! .SH AUTHOR Gotten from varian!david Wed Mar 28 14:05:58 1984. .PP Man page written by Phil Ngai. ---------------------ansitar.c------------------------ /* >From varian!david Wed Mar 28 14:05:58 1984 Message-ID: <201@varian.UUCP> ANSITAR - a program to read and write ANSI labeled tapes The following extremely useful program was posted to net last summer by uiucuxc!root (sorry I can't give any better credits than that, the poster's name seems to be lost due to notes); we here at Varian and utah-gr!thomas have made a few improvements since. I mentioned the existence of ansitar in net.unix last week, and the response was such that I felt it was time to post it. Sorry there's no manual page, but there is a note on usage in the source. I'd love to hear about bugs and improvements. David Brown (415) 945-2199 Varian Instruments 2700 Mitchell Dr. Walnut Creek, Ca. 94598 {zehntel,amd70,fortune}!varian!david */ /* >From pur-ee!uiucdcs!uiucuxc!root Sat Jul 2 04:31:32 1983 Subject: Ansitar.c - (nf) * * 08/29/84 MJE: extract only first copy of file & stop reading tape when * all requested files have been extracted * 08/29/84 MJE: make blocksize symbolic & default to 2048 (same default as * VMS output tapes. * 08/30/84 MJE: add -n option to keep tape from rewinding at end * 08/30/84 MJE: add -f # count of files to process option * 10/28/83 DRB: new option 'D': read variable length records (D format) * 10/29/83 FGH: 1. wildcard ability added to filenames. * 2. when output filename isn't valid for Unix (as it's perhaps * taken from a foreign tape), this program now just skips that * file rather than exiting the whole job. * 10/30/83 FGH: 1. some problems with varunblock's handling of end of record. * still must use 'D' option with 'b' such that b's argument * exceeds the tape's physical record size (2048 in my case) * 2. changed varunblock/doxtract to correct the byte count. * * 10/31/83 DRB: * new option P - create/read files in "pip" (FILES-11) counted format. * handle tape read error * From utah-gr!thomas Tue Aug 2 21:27:08 1983 * (=Spencer) (#ifdef PIP) */ #define VARIAN #define PIP #ifdef VARIAN #define DEBUG 0 /* set to nonzero to debug new Varian code */ #define DBG if(DEBUG) fprintf(stderr, #define WILDCARD '*' #endif VARIAN #include <stdio.h> #include <ctype.h> #include <time.h> #include <pwd.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/mtio.h> /* ansitar -- archiver for ansi-format labelled tapes * * ansitar [crxtvbl] [blocksize] [labelsize] file ... * * The options are similar to tar: * c - create a tape * r - replace (update) a tape * x - extract files * t - print table of contents * v - set verbose mode: for crx, print names; for t print labels * 0-9 - select drive 0-9 * b - use next argument as a block size (default is 2048) * B - use next argument as tape block size, and * following argument as line size (for blocking/unblocking) * l - use next arg as a label size * U - select upper(out)/lower(in) case translation of names * R - use RT11 label and name conventions (UGH!) * S - use RSTS conventions (==RT11 except 80-byte labels) * P - create/read files in "pip" (FILES-11) counted format. * D - read variable length records (D format) * n - do not rewind tape at end of processing * f - use next argument as count of files to process (options t & x) * V - use next argument as volume serial number * * The filename may contain * to indicate a wild card; however, the * asterick should be enclosed in quotes to prevent the shell from * interpreting it. * * Examples of usage: * ansitar tv Verbose table of contents * ansitar xvDUb 2000 file1 file2 Extract file1 and file2 from * tape with 2000 bytes/block * and variable length records * * BUGS: * Writing variable length records (D format) is not implemented. * Wild cards have not been extensively tested. * * Warning: The routines skipfile and backspace use nonstandard * (4.1BSD) ioctl calls! */ #define Skiparg() argc--; argv++ #define MAXLINE 256 #define TRUE 1 #define FALSE 0 #define READ 0 #define READWRITE 2 #define BLKSIZE 2048 /* default blocksize = VMS standard blocksize */ /* field sizes */ #define LABID 3 #define SERIAL 6 #define OWNER 14 #define FILEID 17 #define SETID 6 #define SECNO 4 #define SEQNO 4 #define GENNO 4 #define GENVSNO 2 #define CRDATE 6 #define EXDATE 6 #define BLOCKS 6 #define SYSTEM 13 #define BLKLEN 5 #define RECLEN 5 #define BUFOFF 2 /* pad fields (reserved for future use) */ #define VRES1 20 #define VRES2 6 #define VRES3 28 #define H1RES1 7 #define H2RES1 35 #define H2RES2 28 /* Volume header label */ struct vol { char v_labid[LABID]; /* label identifier "VOL" */ char v_labno; /* label number */ char v_serial[SERIAL]; /* volume serial number */ char v_access; /* accessibility */ char v_res1[VRES1]; /* reserved for future use */ char v_res2[VRES2]; /* reserved for future use */ char v_owner[OWNER]; /* owner identifier */ char v_res3[VRES3]; /* reserved for future use */ char v_stdlabel; /* standard label flag */ }; /* file header/eof label */ struct hdr_1 { char h1_labid[LABID]; /* label identifier */ char h1_labno; /* label number */ char h1_fileid[FILEID]; /* file identifier */ char h1_setid[SETID]; /* file set identifier */ char h1_secno[SECNO]; /* file section number */ char h1_seqno[SEQNO]; /* file sequence number */ char h1_genno[GENNO]; /* generation number */ char h1_genvsno[GENVSNO]; /* generation vsn number */ char h1_crdate[CRDATE]; /* creation date */ char h1_exdate[EXDATE]; /* expiration date */ char h1_access; /* accessibility */ char h1_blocks[BLOCKS]; /* block count */ char h1_system[SYSTEM]; /* system code */ char h1_x1[7]; /* reserved */ } ; struct hdr_2 { char h2_labid[LABID]; /* label identifier */ char h2_labno; /* label number */ char h2_recfm; /* record format */ char h2_blklen[BLKLEN]; /* block length */ char h2_reclen[RECLEN]; /* record length */ char h2_res1[H2RES1]; /* reserved */ char h2_bufoff[BUFOFF]; /* buffer offset */ char h2_res2[H2RES2]; /* reserved */ } ; struct vol vol1; struct hdr_1 hdr1, eof1; struct hdr_2 hdr2; char *tapefile = "/dev/rmt8"; char *buffer, *linebuffer, *malloc(), *index(); char **filetab; int blocksize = BLKSIZE; int linesize = 0; int bfactor = 0; int labelsize = sizeof(struct vol); char recfm = 'F'; char line[MAXLINE]; int tapeunit = 0; int tf; char *defvsn = ""; char curdate[CRDATE+1]; char *alongtime = " 99364"; #ifdef PIP int create, replace, xtract, table, verbose, confirm, filecnt, norewind, pipfile; #else int create, replace, xtract, table, verbose, confirm, filecnt, norewind; #endif int blocking; int RT11, Upper; #ifdef VARIAN int Varlen; #endif VARIAN main(argc, argv) int argc; char **argv; { char *ap; int bufsize, openmode; if (argc < 2) usage(); Skiparg(); openmode = READ; ap = argv[0]; Skiparg(); while (*ap) { switch (*ap) { case 'c': create++; openmode = READWRITE; break; case 'r': replace++; openmode = READWRITE; break; case 'x': xtract++; break; case 't': table++; break; case 'v': verbose++; break; case 'w': confirm++; break; case 'b': case 'B': blocking++; blocksize = atoi(argv[0]); if (blocksize <= 0) fatal("bad block size %s\n", argv[0]); Skiparg(); if (*ap == 'B') { linesize = atoi(argv[0]); if (linesize <= 0 || blocksize % linesize != 0) fatal("bad line size %s\n", argv[0]); bfactor = blocksize / linesize; Skiparg(); } break; case 'l': labelsize = atoi(argv[0]); if (labelsize < sizeof(struct hdr_1)) fatal("label size must be >= %d\n", sizeof(struct hdr_1)); Skiparg(); break; case 'U': Upper++; break; case 'V': defvsn = argv[0]; if (strlen(defvsn) > SERIAL) defvsn[SERIAL] = '\0'; Skiparg(); break; case 'S': case 'R': RT11++; Upper++; if (*ap == 'R') labelsize = 512; break; #ifdef VARIAN case 'D': Varlen++; recfm = 'D'; break; #endif VARIAN #ifdef PIP case 'P': pipfile++; break; #endif PIP case 'n': norewind++; break; case 'f': filecnt = atoi(argv[0]); if (filecnt <= 0) fatal("bad file count: %s\n", argv[0]); Skiparg(); break; default: if (isdigit(*ap)) { tapeunit = *ap; break; } fatal("bad flag: %c\n", *ap); } ap++; } filetab = argv; filetab[argc] = NULL; if (norewind) tapefile = "/dev/rmt12"; if (filecnt == 0) filecnt = 32767; if (tapeunit) tapefile[strlen(tapefile)-1] = tapeunit; tf = open(tapefile, openmode); if (tf < 0) fatal("can't open %s%s\n", tapefile, (openmode != READ) ? " for writing" : ""); bufsize = max(blocksize, labelsize); /*###218 [lint] malloc arg. 1 used inconsistently llib-lc(59) :: ansitar.c(218)%%%*/ buffer = malloc(bufsize + 10); if (buffer == NULL) fatal("can't allocate buffer of %d bytes\n", blocksize); if (linesize) { /*###222 [lint] malloc arg. 1 used inconsistently llib-lc(59) :: ansitar.c(222)%%%*/ linebuffer = malloc(linesize + 10); if (linebuffer == NULL) fatal("can't allocate line buffer of %d bytes\n", linesize); } getansidate(curdate); if (verbose && blocking) { printf("Blocksize: %d", blocksize); if (linesize) printf(" Linesize: %d", linesize); putc('\n', stdout); } if (create || replace) doupdate(tf); else if (xtract) doxtract(tf, filecnt); else if (table) dotable(tf, filecnt); else usage(); exit(0); } usage() { fatal("usage: ansitar crxtvblnf [blocksize] [labelsize] [filecnt] file ...\n"); } dotable(tf, fc) int tf, fc; { char fileid[FILEID+1]; int files, n; int blocks; long bytes; getvol(tf, &vol1); prtvol(&vol1); putc('\n', stdout); files = 0; while ((files < fc) && (gethdr(tf, &hdr1))) { files++; if (verbose) { prthdr(&hdr1); if (gethdr(tf, &hdr2)) prthdr(&hdr2); } getmark(tf); sncpy(fileid, hdr1.h1_fileid, FILEID); blocks = 0; bytes = 0L; while ((n = getrec(tf, buffer, blocksize)) > 0) { blocks++; bytes += n; } geteof(tf, &eof1); if (verbose) { prthdr(&eof1); putc('\n', stdout); } getmark(tf); cmphdreof(&hdr1, &eof1); printf("t %s %d blocks %D bytes\n", fileid, blocks, bytes); if (verbose) putc('\n', stdout); } printf("\n%d files\n", files); } doxtract(tf, fc) int tf, fc; { char fileid[FILEID+1]; FILE *fp; long bytes; int blocks; int n, xall; #ifdef VARIAN int newn; #endif VARIAN if (filetab[0] == NULL) if ((xall = fc) == 0) xall = 65535; getvol(tf, &vol1); if (verbose) prtvol(&vol1); while ((xall || morefiles(filetab)) && gethdr(tf, &hdr1)) { getmark(tf); sncpy(fileid, hdr1.h1_fileid, FILEID); trimsp(fileid); if (RT11) fromRT11(fileid); /* if 1.you're doing all the files or 2. this file matches */ /* one of the the names in the arglist, then copy it, else */ /* skip this file. filetab is really 'argv' list. */ if ( (xall || lookup(filetab, fileid, Upper)) && checkw('x', fileid) ) { if (xall) xall--; if (Upper) makelower(fileid); /* name to lower case*/ fp = fopen(fileid, "w"); #ifdef VARIAN if (fp == NULL) { printf("can't create %s - will skip\n", fileid); skipfile(tf); } #else if (fp == NULL) fatal("can't create %s\n", fileid); #endif VARIAN else{ /* file OK, do the copy */ blocks = 0; bytes = 0L; while ((n = getrec(tf, buffer, blocksize)) > 0) { if (linesize) lunblock(fp, buffer, n, linesize); else #ifdef VARIAN if (Varlen) { newn = varunblock(fp,buffer,n); n = newn; /* now it's # written */ } else #endif VARIAN #ifdef PIP if (pipfile) pipunblock(fp, buffer, n); else #endif PIP fwrite(buffer, n, 1, fp); blocks++; bytes += n; } fclose(fp); if (verbose) printf("x %s %d blocks %D bytes\n", fileid, blocks, bytes); } /* end 'if file open was OK' */ } /* end 'if filename OK or copying all' */ else /* if this file is not be copied */ skipfile(tf); geteof(tf, &eof1); cmphdreof(&hdr1, &eof1); getmark(tf); } } doupdate(tf) int tf; { int i, n; int blocks; long bytes; char fileid[FILEID+1]; FILE *fp; int sequence; sequence = 0; if (create) { initvol(&vol1); putvol(tf, &vol1); } else { /* replace */ getvol(tf, &vol1); while (gethdr(tf, &hdr1)) { sncpy(line, hdr1.h1_seqno, SEQNO); sequence = atoi(line); getmark(tf); skipfile(tf); geteof(tf, &eof1); getmark(tf); } backspace(tf); } for (i=0; filetab[i] != NULL; i++) { if (!checkw('a', filetab[i])) continue; strncpy(fileid, filetab[i], FILEID); fileid[FILEID] = '\0'; fp = fopen(fileid, "r"); if (fp == NULL) fatal("can't open %s\n", fileid); sequence++; if (RT11) toRT11(fileid); if (Upper) makeupper(fileid); inithdr1(&hdr1, fileid, sequence); puthdr(tf, &hdr1, sizeof(struct hdr_1)); inithdr2(&hdr2, recfm, blocksize, (linesize == 0) ? blocksize : linesize); puthdr(tf, &hdr2, sizeof(struct hdr_2)); tapemark(tf); blocks = 0; bytes = 0L; *line = '\0'; if (Varlen) while ((n = dblock(fp, buffer, blocksize)) > 0) { n = write(tf, buffer, n); blocks++; bytes += n; } else if (linesize) while ((n = lblock(fp, buffer, linesize, bfactor)) > 0) { if (n % 2) { buffer[n] = '\0'; n++; } n = write(tf, buffer, n); blocks++; bytes += n; } #ifdef PIP else if (pipfile) while ((n = pipblock(fp, buffer, blocksize)) > 0) { n = write(tf, buffer, n); blocks++; bytes += n; } else #else else #endif PIP while ((n = fread(buffer, sizeof(char), blocksize, fp)) > 0) { if (n % 2) { buffer[n] = '\0'; n++; } n = write(tf, buffer, n); blocks++; bytes += n; } fclose(fp); tapemark(tf); blcopy(hdr1.h1_labid, "EOF", LABID); utoaz(blocks, line, BLOCKS); blcopy(hdr1.h1_blocks, line, BLOCKS); puthdr(tf, &hdr1, sizeof(struct hdr_1)); tapemark(tf); if (verbose) printf("a %s %d blocks %D bytes\n", fileid, blocks, bytes); } tapemark(tf); } getvol(tf, volp) int tf; struct vol *volp; { int n; if (labelsize == sizeof(struct vol)) n = read(tf, (char *)volp, sizeof(struct vol)); else { n = read(tf, buffer, labelsize); bcopy((char *)volp, buffer, sizeof(struct vol)); } #ifdef PIP if (n<0) { perror("Tape read error"); exit(1); } #endif PIP if (n != labelsize || strncmp(volp->v_labid, "VOL", LABID) != 0 || volp->v_labno != '1') { printf("Warning: Volume label (VOL1) missing\n"); backspace(tf); return; } /* check for RT11 boot block between VOL1 and first HDR1 */ if (RT11) { /* must have labelsize = 512 */ n = read(tf, buffer, labelsize); bcopy((char *)&hdr1, buffer, sizeof(struct hdr_1)); if (n == labelsize && strncmp(hdr1.h1_labid, "HDR", LABID) == 0) backspace(tf); else printf("Possible RT11 bootstrap block.\n"); } } int gethdr(tf, hdrp) int tf; char *hdrp; { int n; if (labelsize == sizeof(struct hdr_1)) n = read(tf, hdrp, sizeof(struct hdr_1)); else { n = read(tf, buffer, labelsize); bcopy(hdrp, buffer, sizeof(struct hdr_1)); } if (n == 0) return(FALSE); if (n != labelsize || strncmp(hdrp, "HDR", LABID) != 0) hdrerr(tf, hdrp); return(TRUE); } hdrerr(tf, hdrp) int tf; char *hdrp; { int found, n; printf("Warning: File label error - skipping\n"); found = FALSE; while (!found) { skipfile(tf); if (labelsize == sizeof(struct hdr_1)) n = read(tf, hdrp, sizeof(struct hdr_1)); else { n = read(tf, buffer, labelsize); bcopy(hdrp, buffer, sizeof(struct hdr_1)); } if ((n == labelsize) && (strncmp(hdrp, "HDR", LABID) == 0)) found = TRUE; } } geteof(tf, eofp) int tf; struct hdr_1 *eofp; { int n; if (labelsize == sizeof(struct hdr_1)) /*###526 [lint] read arg. 2 used inconsistently llib-lc(41) :: ansitar.c(526)%%%*/ n = read(tf, eofp, sizeof(struct hdr_1)); else { n = read(tf, buffer, labelsize); bcopy((char *)eofp, buffer, sizeof(struct hdr_1)); } if (n != labelsize || strncmp(eofp->h1_labid, "EOF", LABID) != 0 || eofp->h1_labno != '1') printf("Warning: File label (EOF1) error\n"); } int getrec(f, buf, size) int f; char *buf; int size; { int n; n = read(f, buf, size); if (n < 0) fatal("Read error (record may be larger than %db)\n", size); return(n); } getmark(tf) int tf; { char rec[sizeof(struct hdr_1)]; int n; n = read(tf, rec, sizeof(rec)); if (n == 0) return; /* skip HDR3-9 */ while (n == sizeof(struct hdr_1) && (strncmp("HDR", rec, 3)==0 || strncmp("EOF", rec, 3)==0)) { n = read(tf, rec, sizeof(rec)); if (n == 0) return; } printf("Warning: tape mark missing\n"); } cmphdreof(hdrp, eofp) struct hdr_1 *hdrp, *eofp; { char line[MAXLINE]; static int len = FILEID+SETID+SECNO+SEQNO+GENNO+GENVSNO+ CRDATE+EXDATE+1; if (strncmp(hdrp->h1_fileid, eofp->h1_fileid, len) != 0 || strncmp(hdrp->h1_system, eofp->h1_system, SYSTEM) != 0) { sncpy(line, hdrp->h1_fileid, FILEID); fprintf(stderr, "Warning: HDR and EOF labels for %s disagree\n", line); } } putvol(tf, volp) int tf; struct vol *volp; { int len; if (labelsize == sizeof(struct vol)) { /*###606 [lint] write arg. 2 used inconsistently llib-lc(57) :: ansitar.c(606)%%%*/ write(tf, volp, sizeof(struct vol)); return; } bcopy(buffer, (char *)volp, sizeof(struct vol)); len = labelsize - sizeof(struct vol); blcopy(&buffer[sizeof(struct vol)], "", len); write(tf, buffer, labelsize); } puthdr(tf, hdrp, hdrlen) int tf; char *hdrp; { int len; if (labelsize == hdrlen) { /*###625 [lint] write arg. 2 used inconsistently llib-lc(57) :: ansitar.c(625)%%%*/ write(tf, hdrp, hdrlen); return; } bcopy(buffer, (char *)hdrp, hdrlen); len = labelsize - hdrlen; blcopy(&buffer[hdrlen], "", len); write(tf, buffer, labelsize); } prtvol(volp) struct vol *volp; { char labid[LABID+1], serial[SERIAL+1], owner[OWNER+1]; sncpy(labid, volp->v_labid, LABID); sncpy(serial, volp->v_serial, SERIAL); sncpy(owner, volp->v_owner, OWNER); printf("Volume label:\n"); printf("\tLabel: %s%c Serial: %s Access: %c\n", labid, volp->v_labno, serial, volp->v_access); printf("\tOwner: %s Standard: %c\n", owner, volp->v_stdlabel); } prthdr(hdrp) char *hdrp; { struct hdr_1 *hdrp1; struct hdr_2 *hdrp2; char labid[LABID+1], fileid[FILEID+1], setid[SETID+1]; char secno[SECNO+1], seqno[SEQNO+1]; char genno[GENNO+1], genvsno[GENVSNO+1]; char crdate[CRDATE+1], exdate[EXDATE+1]; char blocks[BLOCKS+1], system[SYSTEM+1]; char blklen[BLKLEN+1], reclen[RECLEN+1]; hdrp1 = (struct hdr_1 *)hdrp; hdrp2 = (struct hdr_2 *)hdrp; switch (hdrp1->h1_labno) { case '1': sncpy(labid, hdrp1->h1_labid, LABID); sncpy(fileid, hdrp1->h1_fileid, FILEID); sncpy(setid, hdrp1->h1_setid, SETID); sncpy(secno, hdrp1->h1_secno, SECNO); sncpy(seqno, hdrp1->h1_seqno, SEQNO); sncpy(genno, hdrp1->h1_genno, GENNO); sncpy(genvsno, hdrp1->h1_genvsno, GENVSNO); sncpy(crdate, hdrp1->h1_crdate, CRDATE); sncpy(exdate, hdrp1->h1_exdate, EXDATE); sncpy(blocks, hdrp1->h1_blocks, BLOCKS); sncpy(system, hdrp1->h1_system, SYSTEM); printf("\nFile Label: %s%c File: %s\n", labid, hdrp1->h1_labno, fileid); printf("\tSet: %s Section: %s Sequence: %s\n", setid, secno, seqno); printf("\tGeneration: %s Generation Version: %s\n", genno, genvsno); printf("\tCreated: %s Expires: %s Access: %c\n", crdate, exdate, hdrp1->h1_access); printf("\tBlocks: %s System: %s\n", blocks, system); break; case '2': sncpy(labid, hdrp2->h2_labid, LABID); sncpy(blklen, hdrp2->h2_blklen, BLKLEN); sncpy(reclen, hdrp2->h2_reclen, RECLEN); printf("\nFile Label: %s%c\n", labid, hdrp2->h2_labno); printf("\tRecord Format: %c Block length: %s\n", hdrp2->h2_recfm, blklen); printf("\tRecord length: %s\n", reclen); break; } } initvol(volp) struct vol *volp; { struct passwd *passwp, *getpwuid(); /*###697 [lint] blcopy arg. 1 used inconsistently ansitar.c(799) :: ansitar.c(697)%%%*/ blcopy(volp, "", sizeof(struct vol)); blcopy(volp->v_labid, "VOL", LABID); volp->v_labno = '1'; blcopy(volp->v_serial, defvsn, SERIAL); volp->v_access = ' '; passwp = getpwuid(getuid()); blcopy(volp->v_owner, passwp->pw_name, OWNER); volp->v_stdlabel = '1'; } inithdr1(hdrp, filename, seq) struct hdr_1 *hdrp; char *filename; int seq; { char seqno[SEQNO+1]; /*###718 [lint] blcopy arg. 1 used inconsistently ansitar.c(799) :: ansitar.c(718)%%%*/ blcopy(hdrp, "", sizeof(struct hdr_1)); blcopy(hdrp->h1_labid, "HDR", LABID); hdrp->h1_labno = '1'; blcopy(hdrp->h1_fileid, filename, FILEID); blcopy(hdrp->h1_secno, "0001", SECNO); utoaz(seq, seqno, SEQNO); blcopy(hdrp->h1_seqno, seqno, SEQNO); blcopy(hdrp->h1_genno, "0001", GENNO); blcopy(hdrp->h1_genvsno, "00", GENVSNO); blcopy(hdrp->h1_crdate, curdate, CRDATE); blcopy(hdrp->h1_exdate, alongtime, EXDATE); blcopy(hdrp->h1_blocks, "000000", BLOCKS); blcopy(hdrp->h1_system, "Unix V7", SYSTEM); } inithdr2(hdrp, recfm, blklen, reclen) struct hdr_2 *hdrp; int recfm, blklen, reclen; { char line[MAXLINE]; blcopy(hdrp, "", sizeof(struct hdr_2)); blcopy(hdrp->h2_labid, "HDR", LABID); hdrp->h2_labno = '2'; hdrp->h2_recfm = recfm; utoaz(blklen, line, BLKLEN); blcopy(hdrp->h2_blklen, line, BLKLEN); utoaz(reclen, line, RECLEN); blcopy(hdrp->h2_reclen, line, RECLEN); blcopy(hdrp->h2_bufoff, "00", BUFOFF); } int lblock(fp, buffer, lsize, bfactor) FILE *fp; char *buffer; int lsize, bfactor; { register char *lp, *linelim; register int c; int i; char *bp; bp = buffer; for (i=0; i<bfactor; i++) { lp = bp; linelim = &lp[lsize]; while (lp < linelim) { c = getc(fp); if (c == '\n' || c == EOF) break; *lp++ = c; } if (c == EOF && lp == bp) break; while (c != '\n' && c != EOF) c = getc(fp); while (lp < linelim) *lp++ = ' '; bp += lsize; } return(bp - buffer); } int dblock(fp, buffer, blocksize) FILE *fp; char *buffer; int blocksize; { int i; char *bp, *blocklim; bp = buffer; blocklim = bp + blocksize; if (*line) { if ((i = strlen(line) - 1) > blocksize-4) { printf("Line too long (%d), truncated\n", i); i = blocksize-4; } sprintf(bp, "%04d", i+4); bp+= 4; bcopy(bp, line, i); bp+= i; *line = '\0'; } while (fgets(line, MAXLINE, fp) != NULL) { i = strlen(line) - 1; if ((bp + i + 4) > blocklim) break; sprintf(bp, "%04d", i+4); bp+= 4; bcopy(bp, line, i); bp+= i; *line = '\0'; } if (bp == buffer) return(0); while (bp < blocklim) *bp++ = 0x5e; return(bp - buffer); } lunblock(fp, buffer, blen, lsize) FILE *fp; char *buffer; int blen, lsize; { register char *lastp, *bp1; char *bp, *buflim; buflim = &buffer[blen]; bp = buffer; while (bp < buflim) { lastp = &bp[lsize-1]; while (lastp >= bp && isspace(*lastp)) lastp--; for (bp1=bp; bp1<=lastp; bp1++) putc(*bp1, fp); putc('\n', fp); bp += lsize; } } blcopy(dest, src, n) char *dest, *src; int n; /*###799 [lint] blcopy arg. 1 used inconsistently ansitar.c(799) :: ansitar.c(718)%%%*/ /*###799 [lint] blcopy arg. 1 used inconsistently ansitar.c(799) :: ansitar.c(697)%%%*/ { int i; i=0; while (i < n && *src) { *dest++ = *src++; i++; } while (i++ < n) *dest++ = ' '; } sncpy(dest, src, n) char *dest, *src; int n; { int i; i = 0; while (*src && i<n) { *dest++ = *src++; i++; } *dest = '\0'; } utoaz(n, buf, size) int n; char *buf; int size; { char *p; p = &buf[size-1]; while (p >= buf && n != 0) { *p = '0' + (n % 10); n /= 10; p--; } while (p >= buf) { *p = '0'; p--; } } tapemark(tf) int tf; { struct mtop mtop; mtop.mt_count = 1; mtop.mt_op = MTWEOF; ioctl(tf, MTIOCTOP, &mtop); } skipfile(tf) int tf; { struct mtop mtop; mtop.mt_count = 1; mtop.mt_op = MTFSF; ioctl(tf, MTIOCTOP, &mtop); } backspace(tf) int tf; { struct mtop mtop; mtop.mt_count = 1; mtop.mt_op = MTBSR; ioctl(tf, MTIOCTOP, &mtop); } /* getansidate -- return the current date in ansi format * * Ansi dates are strings of the form " yyddd" where * yy = the year and ddd = the day in the year. There must * be an initial blank. */ getansidate(curdate) char *curdate; { time_t now, time(); struct tm *timep, *localtime(); /*###901 [lint] time value declared inconsistently llib-lc(54) :: ansitar.c(901)%%%*/ /*###901 [lint] time value used inconsistently llib-lc(54) :: ansitar.c(901)%%%*/ /*###901 [lint] time arg. 1 used inconsistently llib-lc(54) :: ansitar.c(901)%%%*/ now = time(NULL); /*###902 [lint] localtime arg. 1 used inconsistently llib-lc(90) :: ansitar.c(902)%%%*/ timep = localtime(&now); curdate[0] = ' '; utoaz(timep->tm_year, &curdate[1], 2); utoaz(timep->tm_yday, &curdate[3], 3); curdate[6] = '\0'; } int lookup(tab, name, Upper) char *tab[]; char *name; int Upper; { int i; char lower[MAXLINE]; if (Upper) { strcpy(lower, name); makelower(lower); } for (i=0; tab[i] != NULL; i++) #ifdef VARIAN if (wildcmp(tab[i], name, WILDCARD) == 0 || (Upper && wildcmp(tab[i], lower, WILDCARD)==0)) #else if (strcmp(tab[i], name) == 0 || (Upper && strcmp(tab[i], lower)==0)) #endif VARIAN { if (!(index(tab[i], '*'))) *tab[i] = '\0'; return(TRUE); } return(FALSE); } morefiles(tab) char *tab[]; { int i; for (i=0; tab[i] != NULL; i++) if (*tab[i]) return(TRUE); return(FALSE); } makelower(s) char *s; { register char *p; p = s; while (*p) { if (isupper(*p)) *p = tolower(*p); p++; } } makeupper(s) char *s; { register char *p; p = s; while (*p) { if (islower(*p)) *p = toupper(*p); p++; } } int haslower(p) register char *p; { while (*p) { if (islower(*p)) return(TRUE); p++; } return(FALSE); } toRT11(name) char *name; { char buf[32], *extp; extp = index(name, '.'); if (extp != NULL) { *extp = '\0'; extp++; } blcopy(buf, name, 6); buf[6] = '.'; if (extp != NULL) blcopy(&buf[7], extp, 3); else strcpy(&buf[7], "ext"); buf[10] = '\0'; /*###1001 [lint] strcpy value declared inconsistently llib-lc(49) :: ansitar.c(1001)%%%*/ strcpy(name, buf); } fromRT11(name) char *name; { char *op, *np; op = np = name; while (*op) { if (!isspace(*op)) *np++ = *op; op++; } *np = '\0'; } trimsp(s) char *s; { register char *p; p = &s[strlen(s)-1]; while (p >= s && isspace(*p)) p--; *++p = '\0'; } bcopy(dest, src, size) char *dest, *src; int size; { while (size-- > 0) *dest++ = *src++; } int max(a, b) int a, b; { if (a > b) return(a); return(b); } int checkw(c, name) char c, *name; { if (!confirm) return(TRUE); printf("%c %s:", c, name); c = getchar(); if (c != '\n') while ((c = getchar()) != '\n') ; return(c == 'y' || c == 'Y'); } /* VARARGS */ fatal(s, a1, a2, a3, a4) char *s; { fprintf(stderr, "ansitar: "); fprintf(stderr, s, a1, a2, a3, a4); exit(1); } #ifdef VARIAN /* varunblock - unblock variable length records ("D" format) * Beginning of each record contains a 4 digit number which is the * length of the record (including the count). * There are no line terminators (CR or LF). */ varunblock(fp, buffer, blen) FILE *fp; char *buffer; int blen; { /* the function now returns the # of bytes it decided to write */ register char *lastp, *bp1; char *bp, *buflim; int count; int newblen; /* this will count the actual bytes written out */ buflim = &buffer[blen]; bp = buffer; newblen = 0; #if DEBUG DBG" varunblock called. length %d\n",blen); if(DEBUG)hexdmp(" buffer passed to varunblock",buffer,blen); DBG" "); #endif DEBUG while (bp < buflim) { #if DEBUG DBG" count being made from %2x %2x %2x %2x %2x\n", *bp,*(bp+1),*(bp+2),*(bp+3),*(bp+4)); #endif sscanf(bp,"%4d",&count); count = count - 4; /* count includes the count itself */ #if DEBUG DBG" count %3d\n ",count); #endif if (*bp == 0x5e) /* if fill encountered for length */ { /* then abandon this record */ #if DEBUG DBG" hit filler. assume eor. break\n"); #endif break; } bp = bp+4; /* point to the end of line */ lastp = bp + count; while (bp<lastp) { #if DEBUG if(DEBUG) putc(*bp, stderr); #endif putc(*bp++, fp); newblen++; } #if DEBUG if(DEBUG) putc('\n', stderr); #endif putc('\n', fp); newblen++; } return(newblen); } wildcmp(wilds,str,wc) /* compare 2 strings. 1st can have a wildcard '*' */ char *wilds; /* input string possibly containing a wildcard chr*/ char *str; /* 2nd input string. wild chrs in it aren't 'wild'*/ char wc; /* the 'wild card' character, often a '*' */ { /* function return is 0 if equal (like strcmp). < > not supported */ char *l,*s; int flag; /* will watch for multiple *'s in 'wild'*/ char wcrd; if (strlen(str) == 0) return(-1); /* don't match phantom */ wcrd = wc & 127; flag = 0; /* wildcard not encountered yet */ for (l=wilds,s=str ; *l != '\0' ; ) { if (*l == wcrd) /* if wildcard emcountered, adjust pointers*/ { if (flag) return(0); flag = 1; l++; /* skip the wildcard */ s = str + strlen(str) - (strlen(wilds) - (l - wilds) ); } else{ /* no wildcard, increment pointers normally */ if (*l != *s) return(*l - *s); l++; s++; } } if (*s != '\0') return(*l - *s); return(0); /* returning "success" indicator. they were equal */ } #endif VARIAN #ifdef PIP /***************************************************************** * TAG( pipunblock ) * * Unblock pip records. These are in a counted format with a 4 byte * count, followed by the record. (Count includes the length of the * count). Blank space at the end of a block is filled with '^' * characters. */ pipunblock(fp, buffer, n) FILE *fp; char *buffer; { register char *cp; int len, i; for (cp=buffer; cp<buffer+n; ) { for (i=0, len=0; i<4; i++) len = len*10 + *cp++ - '0'; for (len -= 4; len > 0; len--) putc(*cp++, fp); putc('\n', fp); while (*cp == '^' && cp<buffer+n) cp++; } } /***************************************************************** * TAG( pipblock ) * * Read lines from the input file and block them pip-style into the * buffer. Make logical blocks of 512 bytes and fill space at the end * of the logical blocks with '^' characters. */ pipblock(fp, buffer, blocksize) FILE *fp; char *buffer; { register char *cp; static char linebuf[512]; /* lines not allowed longer than this? */ static int nline = 0; int n; if (blocksize%512) { fprintf(stderr, "Blocksize must be a multiple of 512 for pip tapes\n"); exit(1); } for (cp=buffer; cp<(buffer+blocksize); ) { if (nline <= 0) if (fgets(linebuf, 508, fp) == NULL) nline = -1; else { linebuf[508] = '\0'; nline = strlen(linebuf); if (linebuf[nline-1] == '\n') linebuf[--nline] = '\0'; } if (nline > (508 - (cp-buffer)%512) || (nline < 0 && (cp-buffer)%512 != 0)) while ( (cp-buffer)%512 != 0 ) *cp++ = '^'; if (cp-buffer >= blocksize || nline < 0) return cp-buffer; sprintf(cp, "%04d", nline+4); cp += 4; strncpy(cp, linebuf, 508); cp += nline; nline = 0; } return cp-buffer; /* should never get here, but you never know */ } #endif PIP ---------------------Makefile------------------------- CFLAGS = -O all: ansitar.1 ansitar ansitar: ansitar.o cc -o ansitar ansitar.o install: all install -s ansitar /usr/local/bin cp ansitar.1 /usr/man/man1 ------------------------------------------------------