124973Sbloom /*
2*68193Spendry * Copyright (c) 1985, 1987, 1993, 1995
362301Sbostic * The Regents of the University of California. All rights reserved.
432759Sbostic *
542770Sbostic * %sccs.include.redist.c%
624973Sbloom */
724973Sbloom
824973Sbloom #ifndef lint
962301Sbostic static char copyright[] =
1062301Sbostic "@(#) Copyright (c) 1985, 1987, 1993\n\
1162301Sbostic The Regents of the University of California. All rights reserved.\n";
1232759Sbostic #endif /* not lint */
1324973Sbloom
1424973Sbloom #ifndef lint
15*68193Spendry static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 01/23/95";
1632759Sbostic #endif /* not lint */
1724973Sbloom
1837859Sbostic #include <sys/types.h>
1956106Sbostic #include <sys/stat.h>
2024973Sbloom #include <sys/ioctl.h>
2124973Sbloom #include <sys/mtio.h>
2256106Sbostic
23*68193Spendry #include <err.h>
2456106Sbostic #include <errno.h>
2556106Sbostic #include <fcntl.h>
2651629Sbostic #include <signal.h>
2737859Sbostic #include <stdio.h>
2856106Sbostic #include <stdlib.h>
2956106Sbostic #include <string.h>
3056106Sbostic #include <unistd.h>
3156106Sbostic
3237859Sbostic #include "pathnames.h"
3324973Sbloom
3434185Sbostic #define MAXREC (64 * 1024)
3534185Sbostic #define NOCOUNT (-2)
3634185Sbostic
3734185Sbostic int filen, guesslen, maxblk = MAXREC;
38*68193Spendry long lastrec, record;
39*68193Spendry off_t size, tsize;
4066855Smckusick FILE *msg = stdout;
4124973Sbloom
4256106Sbostic void *getspace __P((int));
4356106Sbostic void intr __P((int));
4456106Sbostic void usage __P((void));
4556106Sbostic void verify __P((int, int, char *));
4656106Sbostic void writeop __P((int, int));
4756106Sbostic
4856106Sbostic int
main(argc,argv)4924973Sbloom main(argc, argv)
5032759Sbostic int argc;
5156106Sbostic char *argv[];
5224973Sbloom {
53*68193Spendry int ch, needeof, nw, inp, outp;
54*68193Spendry ssize_t lastnread, nread;
5534185Sbostic enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
5639834Sbostic sig_t oldsig;
5756106Sbostic char *buff, *inf;
5824973Sbloom
5934185Sbostic guesslen = 1;
6066855Smckusick while ((ch = getopt(argc, argv, "cs:vx")) != EOF)
6134185Sbostic switch((char)ch) {
6234185Sbostic case 'c':
6334185Sbostic op = COPYVERIFY;
6434185Sbostic break;
6530870Skarels case 's':
6634185Sbostic maxblk = atoi(optarg);
6730870Skarels if (maxblk <= 0) {
68*68193Spendry warnx("illegal block size");
6934185Sbostic usage();
7030870Skarels }
7130870Skarels guesslen = 0;
7230870Skarels break;
7334185Sbostic case 'v':
7434185Sbostic op = VERIFY;
7534185Sbostic break;
7666855Smckusick case 'x':
7766855Smckusick msg = stderr;
7866855Smckusick break;
7934185Sbostic case '?':
8034185Sbostic default:
8134185Sbostic usage();
8230870Skarels }
8334185Sbostic argc -= optind;
8434185Sbostic argv += optind;
8534185Sbostic
8634185Sbostic switch(argc) {
8734185Sbostic case 0:
8834185Sbostic if (op != READ)
8934185Sbostic usage();
9037859Sbostic inf = _PATH_DEFTAPE;
9134185Sbostic break;
9234185Sbostic case 1:
9334185Sbostic if (op != READ)
9434185Sbostic usage();
9534185Sbostic inf = argv[0];
9634185Sbostic break;
9734185Sbostic case 2:
9834185Sbostic if (op == READ)
9934185Sbostic op = COPY;
10034185Sbostic inf = argv[0];
10166855Smckusick if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
10266855Smckusick op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
103*68193Spendry err(3, argv[1]);
10434185Sbostic }
10534185Sbostic break;
10634185Sbostic default:
10734185Sbostic usage();
10830870Skarels }
10934185Sbostic
110*68193Spendry if ((inp = open(inf, O_RDONLY, 0)) < 0)
111*68193Spendry err(1, inf);
11234185Sbostic
11334185Sbostic buff = getspace(maxblk);
11434185Sbostic
11534185Sbostic if (op == VERIFY) {
11634185Sbostic verify(inp, outp, buff);
11734185Sbostic exit(0);
11824973Sbloom }
11934185Sbostic
12034185Sbostic if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
12130870Skarels (void) signal(SIGINT, intr);
12234185Sbostic
12334185Sbostic needeof = 0;
12434185Sbostic for (lastnread = NOCOUNT;;) {
12534185Sbostic if ((nread = read(inp, buff, maxblk)) == -1) {
12634185Sbostic while (errno == EINVAL && (maxblk -= 1024)) {
12734185Sbostic nread = read(inp, buff, maxblk);
12834185Sbostic if (nread >= 0)
12934185Sbostic goto r1;
13030870Skarels }
131*68193Spendry err(1, "read error, file %d, record %ld",
13230870Skarels filen, record);
13334185Sbostic } else if (nread != lastnread) {
13434185Sbostic if (lastnread != 0 && lastnread != NOCOUNT) {
13530870Skarels if (lastrec == 0 && nread == 0)
13666855Smckusick fprintf(msg, "%ld records\n", record);
13730870Skarels else if (record - lastrec > 1)
13866855Smckusick fprintf(msg, "records %ld to %ld\n",
13930870Skarels lastrec, record);
14030870Skarels else
14166855Smckusick fprintf(msg, "record %ld\n", lastrec);
14230870Skarels }
14330870Skarels if (nread != 0)
14466855Smckusick fprintf(msg, "file %d: block size %d: ",
14530870Skarels filen, nread);
14632759Sbostic (void) fflush(stdout);
14730870Skarels lastrec = record;
14824973Sbloom }
14934185Sbostic r1: guesslen = 0;
15030870Skarels if (nread > 0) {
15145518Skarels if (op == COPY || op == COPYVERIFY) {
15230870Skarels if (needeof) {
15334185Sbostic writeop(outp, MTWEOF);
15434185Sbostic needeof = 0;
15530870Skarels }
15630870Skarels nw = write(outp, buff, nread);
15730870Skarels if (nw != nread) {
158*68193Spendry int error = errno;
15930870Skarels fprintf(stderr,
16032759Sbostic "write error, file %d, record %ld: ",
16130870Skarels filen, record);
16230870Skarels if (nw == -1)
163*68193Spendry fprintf(stderr,
164*68193Spendry ": %s", strerror(error));
16530870Skarels else
16630870Skarels fprintf(stderr,
16730870Skarels "write (%d) != read (%d)\n",
16830870Skarels nw, nread);
16930870Skarels fprintf(stderr, "copy aborted\n");
17030870Skarels exit(5);
17130870Skarels }
17230870Skarels }
17330870Skarels size += nread;
17430870Skarels record++;
17530870Skarels } else {
17634185Sbostic if (lastnread <= 0 && lastnread != NOCOUNT) {
17766855Smckusick fprintf(msg, "eot\n");
17824973Sbloom break;
17924973Sbloom }
18066855Smckusick fprintf(msg,
181*68193Spendry "file %d: eof after %ld records: %qd bytes\n",
18266855Smckusick filen, record, size);
18330870Skarels needeof = 1;
18424973Sbloom filen++;
18524973Sbloom tsize += size;
18634185Sbostic size = record = lastrec = 0;
18734185Sbostic lastnread = 0;
18824973Sbloom }
18934185Sbostic lastnread = nread;
19024973Sbloom }
191*68193Spendry fprintf(msg, "total length: %qd bytes\n", tsize);
19234185Sbostic (void)signal(SIGINT, oldsig);
19345518Skarels if (op == COPY || op == COPYVERIFY) {
19434185Sbostic writeop(outp, MTWEOF);
19534185Sbostic writeop(outp, MTWEOF);
19634185Sbostic if (op == COPYVERIFY) {
19734185Sbostic writeop(outp, MTREW);
19834185Sbostic writeop(inp, MTREW);
19934185Sbostic verify(inp, outp, buff);
20034185Sbostic }
20134185Sbostic }
20234185Sbostic exit(0);
20324973Sbloom }
20424973Sbloom
20556106Sbostic void
verify(inp,outp,outb)20634185Sbostic verify(inp, outp, outb)
207*68193Spendry int inp, outp;
208*68193Spendry char *outb;
20934185Sbostic {
210*68193Spendry int eot, inmaxblk, inn, outmaxblk, outn;
211*68193Spendry char *inb;
21234185Sbostic
21334185Sbostic inb = getspace(maxblk);
21434185Sbostic inmaxblk = outmaxblk = maxblk;
21534185Sbostic for (eot = 0;; guesslen = 0) {
21634185Sbostic if ((inn = read(inp, inb, inmaxblk)) == -1) {
21734185Sbostic if (guesslen)
21834185Sbostic while (errno == EINVAL && (inmaxblk -= 1024)) {
21934185Sbostic inn = read(inp, inb, inmaxblk);
22034185Sbostic if (inn >= 0)
22134185Sbostic goto r1;
22234185Sbostic }
223*68193Spendry warn("read error");
22436197Sbostic break;
22534185Sbostic }
22634185Sbostic r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
22734185Sbostic if (guesslen)
22834185Sbostic while (errno == EINVAL && (outmaxblk -= 1024)) {
22934185Sbostic outn = read(outp, outb, outmaxblk);
23034185Sbostic if (outn >= 0)
23134185Sbostic goto r2;
23234185Sbostic }
233*68193Spendry warn("read error");
23436197Sbostic break;
23534185Sbostic }
23636197Sbostic r2: if (inn != outn) {
23766855Smckusick fprintf(msg,
23866855Smckusick "%s: tapes have different block sizes; %d != %d.\n",
23966855Smckusick "tcopy", inn, outn);
24034185Sbostic break;
24136197Sbostic }
24234185Sbostic if (!inn) {
24334185Sbostic if (eot++) {
244*68193Spendry fprintf(msg, "%s: tapes are identical.\n",
245*68193Spendry "tcopy");
24634185Sbostic return;
24734185Sbostic }
24834185Sbostic } else {
24936197Sbostic if (bcmp(inb, outb, inn)) {
25066855Smckusick fprintf(msg,
251*68193Spendry "%s: tapes have different data.\n",
252*68193Spendry "tcopy");
25334185Sbostic break;
25436197Sbostic }
25534185Sbostic eot = 0;
25634185Sbostic }
25734185Sbostic }
25834185Sbostic exit(1);
25934185Sbostic }
26034185Sbostic
26139834Sbostic void
intr(signo)26256106Sbostic intr(signo)
26356106Sbostic int signo;
26424973Sbloom {
26530870Skarels if (record)
26630870Skarels if (record - lastrec > 1)
26766855Smckusick fprintf(msg, "records %ld to %ld\n", lastrec, record);
26824973Sbloom else
26966855Smckusick fprintf(msg, "record %ld\n", lastrec);
27066855Smckusick fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
271*68193Spendry fprintf(msg, "total length: %qd bytes\n", tsize + size);
27224973Sbloom exit(1);
27324973Sbloom }
27434185Sbostic
27556106Sbostic void *
getspace(blk)27634185Sbostic getspace(blk)
27734185Sbostic int blk;
27834185Sbostic {
27956106Sbostic void *bp;
28034185Sbostic
281*68193Spendry if ((bp = malloc((size_t)blk)) == NULL)
282*68193Spendry errx(11, "no memory");
283*68193Spendry
28456106Sbostic return (bp);
28534185Sbostic }
28634185Sbostic
28756106Sbostic void
writeop(fd,type)28834185Sbostic writeop(fd, type)
28934185Sbostic int fd, type;
29034185Sbostic {
29134185Sbostic struct mtop op;
29234185Sbostic
29334185Sbostic op.mt_op = type;
29434185Sbostic op.mt_count = (daddr_t)1;
295*68193Spendry if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
296*68193Spendry err(6, "tape op");
29734185Sbostic }
29834185Sbostic
29956106Sbostic void
usage()30034185Sbostic usage()
30134185Sbostic {
302*68193Spendry
30366855Smckusick fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
30434185Sbostic exit(1);
30534185Sbostic }
306