-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcopytape
563 lines (503 loc) · 14 KB
/
copytape
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
Path: uunet!rs
From: [email protected] (Rich Salz)
Newsgroups: comp.sources.unix
Subject: v10i099: NEW version of magtape copy program
Message-ID: <[email protected]>
Date: 7 Aug 87 11:26:06 GMT
Organization: UUNET Communications Services, Arlington, VA
Lines: 553
Approved: [email protected]
Submitted-by: sundc!hqda-ai!merlin (David S. Hayes)
Posting-number: Volume 10, Issue 99
Archive-name: copytape
[ This replaces what was published a few days ago. --r$ ]
Sorry, Rich, luck is with me again. About 2 weeks ago, someone here
brought me a very odd tape, and it exposed several problems with copytape
(v10 i90). I corrected the source, but I forget that I had sent it to
you.
Here's a corrected copytape. I thought of making a diff, but that was
13k, and the whole shar was only 14k!
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file". (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# Makefile copytape.1 copytape.5 copytape.c
#
#!/bin/sh
echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
MAN1 = /usr/man/man1
MAN5 = /usr/man/man5
BIN = /usr/local/bin
CFLAGS = -O
CC = cc $(CFLAGS)
copytape: copytape.c
$(CC) -o copytape copytape.c
install: copytape
install -s -m 0511 copytape ${BIN}
man: man1 man5
man1: ${MAN1}/copytape.1
cp copytape.1 ${MAN1}
man5: ${MAN5}/copytape.5
cp copytape.5 ${MAN5}
//E*O*F Makefile//
echo x - copytape.1
cat > "copytape.1" << '//E*O*F copytape.1//'
.TH COPYTAPE 1 "25 June 1986"
.\"@(#)copytape.1 1.0 86/07/08 AICenter; by David S. Hayes
.SH NAME
copytape \- duplicate magtapes
.SH SYNOPSIS
.B copytape
\[\-f\]
\[\-t\]
\[\-s\fInnn\fP\]
\[\-l\fInnn\fP\]
\[\-v\]
.I
\[input \[output\]\]
.SH DESCRIPTION
.LP
.I copytape
duplicates magtapes. It is intended for duplication of
bootable or other non-file-structured (non-tar-structured)
magtapes on systems with only one tape drive.
.I copytape
is blissfully ignorant of tape formats. It merely makes
a bit-for-bit copy of its input.
.PP
In normal use,
.I copytape
would be run twice. First, a boot tape is copied to an
intermediate disk file. The file is in a special format that
preserves the record boundaries and tape marks. On the second
run,
.I copytape
reads this file and generates a new tape. The second step
may be repeated if multiple copies are required. The typical
process would look like this:
.sp
.RS +.5i
tutorial% copytape /dev/rmt8 tape.tmp
.br
tutorial% copytape tape.tmp /dev/rmt8
.br
tutorial% rm tape.tmp
.RE
.PP
.I copytape
copies from the standard input to the standard output, unless
input and output arguments are provided. It will automatically
determine whether its input and output are physical tapes, or
data files. Data files are encoded in a special (human-readable)
format.
.PP
Since
.I copytape
will automatically determine what sort of thing its input
and output are, a twin-drive system can duplicate a tape in
one pass. The command would be
.RS +.5i
tutorial% copytape /dev/rmt8 /dev/rmt9
.RE
.SH OPTIONS
.TP 3
.RI \-s nnn
Skip tape marks. The specified number of tape marks are skipped
on the input tape, before the copy begins. By default, nothing is
skipped, resulting in a copy of the complete input tape. Multiple
tar(1) and dump(1) archives on a single tape are normally
separated by a single tape mark. On ANSI or IBM labelled tapes,
each file has three associated tape marks. Count carefully.
.TP 3
.RI \-l nnn
Limit. Only nnn files (data followed by a tape mark), at most,
are copied. This can be used to terminate a copy early. If the
skip option is also specified, the files skipped do not count
against the limit.
.TP 3
\-f
From tape. The input is treated as though it were a physical
tape, even if it is a data file. This option can be used
to copy block-structured device files other than magtapes.
.TP 3
\-t
To tape. The output is treated as though it were a physical
tape, even if it is a data file. Normally, data files mark
physical tape blocks with a (human\-readable) header describing
the block. If the \-t option is used when the output is
actually a disk file, these headers will not be written.
This will extract all the information from the tape, but
.I copytape
will not be able to duplicate the original tape based on
the resulting data file.
.TP 3
\-v
Verbose.
.I copytape
does not normally produce any output on the control terminal.
The verbose option will identify the input and output files,
tell whether they are physical tapes or data files, and
announce the size of each block copied. This can produce
a lot of output on even relatively short tapes. It is
intended mostly for diagnostic work.
.SH FILES
/dev/rmt*
.SH "SEE ALSO"
ansitape(1), dd(1), tar(1), mtio(4), copytape(5)
.SH AUTHOR
David S. Hayes, Site Manager, US Army Artificial Intelligence Center.
Originally developed September 1984 at Rensselaer Polytechnic Institute,
Troy, New York.
Revised July 1986. This software is in the public domain.
.SH BUGS
.LP
.I copytape
treats two successive file marks as logical end-of-tape.
.LP
The intermediate data file can consume huge amounts of
disk space. A 2400-foot reel at 6250-bpi can burn 140 megabytes.
This is not strictly speaking a bug, but users should
be aware of the possibility. Check disk space with
.I df(1)
before starting
.IR copytape .
Caveat Emptor!
.LP
A 256K buffer is used internally. This limits the maximum block
size of the input tape.
//E*O*F copytape.1//
echo x - copytape.5
cat > "copytape.5" << '//E*O*F copytape.5//'
.TH COPYTAPE 5 "8 August 1986"
.SH NAME
copytape \- copytape intermediate data file format
.SH DESCRIPTION
.I copytape
duplicates magtapes on single\-tape systems by making
an intermediate copy of the tape in a disk file.
This disk file has a special format that preserves
the block boundaries and tape marks of the original
physical tape.
.PP
Each block is preceded by a header identifying what
sort of block it is. In the case of data blocks,
the length of the data is also given. Each header is
on a separate text line, followed by a newline character.
.sp
.TP 3
CPTP:BLK \fInnnnnn\fP
.ti -3
\fIdata\fP\\n
.sp
A data block is identified by the keyword
.IR BLK .
The length of the block is given in a six\-character
numeric field. The field is zero\-padded on the left if
less than six characters are needed. The header is
followed by a newline character.
The original data follows. The data may have any characters
in it, since
.I copytape
uses a read(2) to extract it.
The data is followed by a newline, to make the file easy
to view with an editor.
.TP 3
CPTP:MRK
A tape mark was encountered in the original tape.
.TP 3
CPTP:EOT
When two consecutive tape marks are encountered,
.I copytape
treats the second as a logical end\-of\-tape. On
output, both MRK and EOT generate
a physical tape mark.
.I copytape
stops processing after copying an EOT.
.SH "SEE ALSO"
mtio(4)
.SH BUGS
Some weird tapes may not use two consecutive tape marks
as logical end\-of\-tape.
//E*O*F copytape.5//
echo x - copytape.c
cat > "copytape.c" << '//E*O*F copytape.c//'
/*
* COPYTAPE.C
*
* This program duplicates magnetic tapes, preserving the
* blocking structure and placement of tape marks.
*
* This program was updated at
*
* U.S. Army Artificial Intelligence Center
* HQDA (Attn: DACS-DMA)
* Pentagon
* Washington, DC 20310-0200
*
* Phone: (202) 694-6900
*
**************************************************
*
* THIS PROGRAM IS IN THE PUBLIC DOMAIN
*
**************************************************
*
* July 1986 David S. Hayes
* Made data file format human-readable.
*
* April 1985 David S. Hayes
* Original Version.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/file.h>
extern int errno;
#define BUFLEN 262144 /* max tape block size */
#define TAPE_MARK -100 /* return record length if we read a
* tape mark */
#define END_OF_TAPE -101 /* 2 consecutive tape marks */
#define FORMAT_ERROR -102 /* data file munged */
int totape = 0, /* treat destination as a tape drive */
fromtape = 0; /* treat source as a tape drive */
int verbose = 0; /* tell what we're up to */
char *source = "stdin",
*dest = "stdout";
char tapebuf[BUFLEN];
main(argc, argv)
int argc;
char *argv[];
{
int from = 0,
to = 1;
int len; /* number of bytes in record */
int skip = 0; /* number of files to skip before
* copying */
unsigned int limit = 0xffffffff;
int i;
struct mtget status;
for (i = 1; i < argc && argv[i][0] == '-'; i++) {
switch (argv[i][1]) {
case 's': /* skip option */
skip = atoi(&argv[i][2]);
break;
case 'l':
limit = atoi(&argv[i][2]);
break;
case 'f': /* from tape option */
fromtape = 1;
break;
case 't': /* to tape option */
totape = 1;
break;
case 'v': /* be wordy */
verbose = 1;
break;
default:
fprintf(stderr, "usage: copytape [-f] [-t] [-lnn] [-snn] [-v] from to\n");
exit(-1);
}
}
if (i < argc) {
from = open(argv[i], O_RDONLY);
source = argv[i];
if (from == -1) {
perror("copytape: input open failed");
exit(-1);
}
i++;;
}
if (i < argc) {
to = open(argv[i], O_WRONLY | O_CREAT | O_TRUNC, 0666);
dest = argv[i];
if (to == -1) {
perror("copytape: output open failed");
exit(-1);
}
i++;
}
if (i < argc)
perror("copytape: extra arguments ignored");
/*
* Determine if source and/or destination is a tape device. Try to
* issue a magtape ioctl to it. If it doesn't error, then it was a
* magtape.
*/
errno = 0;
ioctl(from, MTIOCGET, &status);
fromtape |= errno == 0;
errno = 0;
ioctl(to, MTIOCGET, &status);
totape |= errno == 0;
errno = 0;
if (verbose) {
fprintf(stderr, "copytape: from %s (%s)\n",
source, fromtape ? "tape" : "data");
fprintf(stderr, " to %s (%s)\n",
dest, totape ? "tape" : "data");
}
/*
* Skip number of files, specified by -snnn, given on the command
* line. This is used to copy second and subsequent files on the
* tape.
*/
if (verbose && skip) {
fprintf(stderr, "copytape: skipping %d input files\n", skip);
}
for (i = 0; i < skip; i++) {
do {
len = input(from);
} while (len > 0);
if (len == FORMAT_ERROR) {
perror(stderr, "copytape: format error on skip");
exit(-1);
};
if (len == END_OF_TAPE) {
fprintf(stderr, "copytape: only %d files in input\n", i);
exit(-1);
};
};
/*
* Do the copy.
*/
len = 0;
while (limit && !(len == END_OF_TAPE || len == FORMAT_ERROR)) {
do {
do {
len = input(from);
if (len == FORMAT_ERROR)
perror("copytape: data format error - block ignored");
} while (len == FORMAT_ERROR);
output(to, len);
if (verbose) {
switch (len) {
case TAPE_MARK:
fprintf(stderr, " copied MRK\n");
break;
case END_OF_TAPE:
fprintf(stderr, " copied EOT\n");
break;
default:
fprintf(stderr, " copied %d bytes\n", len);
};
};
} while (len > 0);
limit--;
}
exit(0);
}
/*
* Input up to 256K from a file or tape. If input file is a tape, then
* do markcount stuff. Input record length will be supplied by the
* operating system.
*/
input(fd)
int fd;
{
static markcount = 0; /* number of consecutive tape
* marks */
int len,
l2,
c;
char header[40];
if (fromtape) {
len = read(fd, tapebuf, BUFLEN);
switch (len) {
case -1:
perror("copytape: can't read input");
return END_OF_TAPE;
case 0:
if (++markcount == 2)
return END_OF_TAPE;
else
return TAPE_MARK;
default:
markcount = 0; /* reset tape mark count */
return len;
};
}
/* Input is really a data file. */
l2 = read(fd, header, 5);
if (l2 != 5 || strncmp(header, "CPTP:", 5) != 0)
return FORMAT_ERROR;
l2 = read(fd, header, 4);
if (strncmp(header, "BLK ", 4) == 0) {
l2 = read(fd, header, 7);
if (l2 != 7)
return FORMAT_ERROR;
header[6] = '\0';
len = atoi(header);
l2 = read(fd, tapebuf, len);
if (l2 != len)
return FORMAT_ERROR;
read(fd, header, 1); /* skip trailing newline */
} else if (strncmp(header, "MRK\n", 4) == 0)
return TAPE_MARK;
else if (strncmp(header, "EOT\n", 4) == 0)
return END_OF_TAPE;
else
return FORMAT_ERROR;
return len;
}
/*
* Copy a buffer out to a file or tape.
*
* If output is a tape, write the record. A length of zero indicates that
* a tapemark should be written.
*
* If not a tape, write len to the output file, then the buffer.
*/
output(fd, len)
int fd,
len;
{
struct mtop op;
char header[20];
if (totape && (len == TAPE_MARK || len == END_OF_TAPE)) {
op.mt_op = MTWEOF;
op.mt_count = 1;
ioctl(fd, MTIOCTOP, &op);
return;
}
if (!totape) {
switch (len) {
case TAPE_MARK:
write(fd, "CPTP:MRK\n", 9);
break;
case END_OF_TAPE:
write(fd, "CPTP:EOT\n", 9);
break;
case FORMAT_ERROR:
break;
default:
sprintf(header, "CPTP:BLK %06d\n", len);
write(fd, header, strlen(header));
write(fd, tapebuf, len);
write(fd, "\n", 1);
}
} else
write(fd, tapebuf, len);
}
//E*O*F copytape.c//
echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
20 43 315 Makefile
123 661 3961 copytape.1
50 259 1472 copytape.5
301 949 6532 copytape.c
494 1912 12280 total
!!!
wc Makefile copytape.1 copytape.5 copytape.c | sed 's=[^ ]*/==' | diff -b $temp -
exit 0
--
David S. Hayes, The Merlin of Avalon PhoneNet: (202) 694-6900
UUCP: *!seismo!sundc!hqda-ai!merlin ARPA: merlin%[email protected]
--
Rich $alz "Anger is an energy"
Cronus Project, BBN Labs [email protected]
Moderator, comp.sources.unix [email protected]