root@uiucuxc.UUCP (07/02/83)
#N:uiucuxc:12500005:000:19678 uiucuxc!root Jul 1 23:55:00 1983 # #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 * 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) * * Warning: The routines skipfile and backspace use nonstandard * ioctl calls! */ #define Skiparg() argc--; argv++ #define MAXLINE 256 #define TRUE 1 #define FALSE 0 #define READ 0 #define READWRITE 2 /* 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 /* pad fields (reserved for future use) */ #define VRES1 20 #define VRES2 6 #define VRES3 28 #define HRES1 7 /* 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 { char h_labid[LABID]; /* label identifier: "HDR" or "EOF" */ char h_labno; /* label number */ char h_fileid[FILEID]; /* file identifier */ char h_setid[SETID]; /* file set identifier */ char h_secno[SECNO]; /* file section number */ char h_seqno[SEQNO]; /* file sequence number */ char h_genno[GENNO]; /* generation number */ char h_genvsno[GENVSNO]; /* generation vsn number */ char h_crdate[CRDATE]; /* creation date */ char h_exdate[EXDATE]; /* expiration date */ char h_access; /* accessibility */ char h_blocks[BLOCKS]; /* block count */ char h_system[SYSTEM]; /* system code */ char h_x1[7]; /* reserved */ }; struct vol vol1; struct hdr hdr1, eof1; char *tapefile = "/dev/rmt0"; char *buffer, *linebuffer, *malloc(), *index(); char **filetab; int blocksize = 512; int linesize = 0; int bfactor = 0; int labelsize = sizeof(struct vol); int tapeunit = 0; int tf; char *defvsn = ""; char curdate[CRDATE+1]; char *alongtime = " 99364"; int create, replace, xtract, table, verbose, confirm; int blocking; int RT11, Upper; 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)) fatal("label size must be >= %d\n", sizeof(struct hdr)); 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; default: if (isdigit(*ap)) { tapeunit = *ap; break; } fatal("bad flag: %c\n", *ap); } ap++; } filetab = argv; filetab[argc] = NULL; 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); else if (table) dotable(tf); else usage(); exit(0); } usage() { fatal("usage: ansitar crxtvbl [blocksize] [labelsize] file ...\n"); } dotable(tf) int tf; { char fileid[FILEID+1]; int files, n; int blocks; long bytes; getvol(tf, &vol1); prtvol(&vol1); putc('\n', stdout); files = 0; while (gethdr(tf, &hdr1)) { files++; if (verbose) prthdr(&hdr1); getmark(tf); sncpy(fileid, hdr1.h_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) int tf; { char fileid[FILEID+1]; FILE *fp; long bytes; int blocks; int n, xall; xall = (filetab[0] == NULL); getvol(tf, &vol1); if (verbose) prtvol(&vol1); while (gethdr(tf, &hdr1)) { getmark(tf); sncpy(fileid, hdr1.h_fileid, FILEID); trimsp(fileid); if (RT11) fromRT11(fileid); if ( (xall || lookup(filetab, fileid, Upper)) && checkw('x', fileid) ) { if (Upper) makelower(fileid); fp = fopen(fileid, "w"); if (fp == NULL) fatal("can't create %s\n", fileid); blocks = 0; bytes = 0L; while ((n = getrec(tf, buffer, blocksize)) > 0) { if (linesize) lunblock(fp, buffer, n, linesize); else fwrite(buffer, n, 1, fp); blocks++; bytes += n; } fclose(fp); if (verbose) printf("x %s %d blocks %D bytes\n", fileid, blocks, bytes); } else skipfile(tf); geteof(tf, &eof1); cmphdreof(&hdr1, &eof1); getmark(tf); } } doupdate(tf) int tf; { int i, n; int blocks; long bytes; char line[MAXLINE]; 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.h_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); inithdr(&hdr1, fileid, sequence); puthdr(tf, &hdr1); tapemark(tf); blocks = 0; bytes = 0L; 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; } else 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.h_labid, "EOF", LABID); utoaz(blocks, line, BLOCKS); blcopy(hdr1.h_blocks, line, BLOCKS); puthdr(tf, &hdr1); 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)); } 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)); if (n == labelsize && strncmp(hdr1.h_labid, "HDR", LABID) == 0) backspace(tf); else printf("Possible RT11 bootstrap block.\n"); } } int gethdr(tf, hdrp) int tf; struct hdr *hdrp; { int n; if (labelsize == sizeof(struct hdr)) n = read(tf, (char *)hdrp, sizeof(struct hdr)); else { n = read(tf, buffer, labelsize); bcopy((char *)hdrp, buffer, sizeof(struct hdr)); } if (n == 0) return(FALSE); if (n != labelsize || strncmp(hdrp->h_labid, "HDR", LABID) != 0 || hdrp->h_labno != '1') hdrerr(tf, hdrp); return(TRUE); } hdrerr(tf, hdrp) int tf; struct hdr *hdrp; { int found, n; printf("Warning: File label (HDR1) error - skipping\n"); found = FALSE; while (!found) { skipfile(tf); if (labelsize == sizeof(struct hdr)) n = read(tf, (char *)hdrp, sizeof(struct hdr)); else { n = read(tf, buffer, labelsize); bcopy((char *)hdrp, buffer, sizeof(struct hdr)); } if ((n == labelsize) && (strncmp(hdrp->h_labid, "HDR", LABID) == 0)) found = TRUE; } } geteof(tf, eofp) int tf; struct hdr *eofp; { int n; if (labelsize == sizeof(struct hdr)) /*###526 [lint] read arg. 2 used inconsistently llib-lc(41) :: ansitar.c(526)%%%*/ n = read(tf, eofp, sizeof(struct hdr)); else { n = read(tf, buffer, labelsize); bcopy((char *)eofp, buffer, sizeof(struct hdr)); } if (n != labelsize || strncmp(eofp->h_labid, "EOF", LABID) != 0 || eofp->h_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)]; int n; n = read(tf, rec, sizeof(rec)); if (n == 0) return; /* skip HDR2-9 */ while (n == sizeof(struct hdr) && (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 *hdrp, *eofp; { char line[MAXLINE]; static int len = FILEID+SETID+SECNO+SEQNO+GENNO+GENVSNO+ CRDATE+EXDATE+1; if (strncmp(hdrp->h_fileid, eofp->h_fileid, len) != 0 || strncmp(hdrp->h_system, eofp->h_system, SYSTEM) != 0) { sncpy(line, hdrp->h_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) int tf; struct hdr *hdrp; { int len; if (labelsize == sizeof(struct hdr)) { /*###625 [lint] write arg. 2 used inconsistently llib-lc(57) :: ansitar.c(625)%%%*/ write(tf, hdrp, sizeof(struct hdr)); return; } bcopy(buffer, (char *)hdrp, sizeof(struct hdr)); len = labelsize - sizeof(struct hdr); blcopy(&buffer[sizeof(struct hdr)], "", 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) struct hdr *hdrp; { 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]; sncpy(labid, hdrp->h_labid, LABID); sncpy(fileid, hdrp->h_fileid, FILEID); sncpy(setid, hdrp->h_setid, SETID); sncpy(secno, hdrp->h_secno, SECNO); sncpy(seqno, hdrp->h_seqno, SEQNO); sncpy(genno, hdrp->h_genno, GENNO); sncpy(genvsno, hdrp->h_genvsno, GENVSNO); sncpy(crdate, hdrp->h_crdate, CRDATE); sncpy(exdate, hdrp->h_exdate, EXDATE); sncpy(blocks, hdrp->h_blocks, BLOCKS); sncpy(system, hdrp->h_system, SYSTEM); printf("File Label:\n"); printf("\tLabel: %s%c File: %s\n", labid, hdrp->h_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, hdrp->h_access); printf("\tBlocks: %s System: %s\n", blocks, system); } 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'; } inithdr(hdrp, filename, seq) struct hdr *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)); blcopy(hdrp->h_labid, "HDR", LABID); hdrp->h_labno = '1'; blcopy(hdrp->h_fileid, filename, FILEID); blcopy(hdrp->h_secno, "0001", SECNO); utoaz(seq, seqno, SEQNO); blcopy(hdrp->h_seqno, seqno, SEQNO); blcopy(hdrp->h_genno, "0001", GENNO); blcopy(hdrp->h_genvsno, "00", GENVSNO); blcopy(hdrp->h_crdate, curdate, CRDATE); blcopy(hdrp->h_exdate, alongtime, EXDATE); blcopy(hdrp->h_blocks, "000000", BLOCKS); blcopy(hdrp->h_system, "Unix V7", SYSTEM); } 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); } 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++) if (strcmp(name, tab[i]) == 0 || (Upper && strcmp(lower, tab[i])==0)) 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); }