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
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
|
.help mtio Aug83 "Magnetic Tape I/O"
.sh
1. Introduction
This document describes the Magnetic Tape I/O (MTIO) package,
i.e., the interface by which IRAF programs access magnetic tapes.
Included are the requirements and specifications for the package,
and a discussion of the interface between MTIO and FIO.
.sh
2. MTIO Requirements
.ls 4
.ls (1)
The machine independent part of the MTIO package shall be written in
the SPP language in compliance with the standards and conventions of IRAF.
.le
.ls (2)
The MTIO package shall provide a single interface to all magtape
devices on all IRAF target machines.
.le
.ls (3)
MTIO shall interface to FIO, making it possible to read and write a magtape
file via the FIO interface in a device independent fashion.
.le
.ls (4)
All functions shall take an error action if a hardware error occurs,
or if an illegal function is requested.
No hardware exception or trap shall occur while accessing a magtape
file via MTIO which is not caught by MTIO and converted into an
IRAF error action.
.le
.ls (5)
All error actions shall be defined symbolically in the system error
code file <syserr.h>. The MTIO error messages shall have the
form SYS_MT<function>, i.e., SYS_MTOPEN. The error message strings
shall be placed in the system error message file, "syserrmsg".
.le
.ls (6)
The MTIO code shall be divided into a machine independent part and
a machine dependent part. All machine independent function and error
checking shall be done in the machine independent part, to minimize
the size and complexity of the machine dependent part, and therefore
maximize the transportability of the package.
.le
.ls (7)
MTIO shall interface to FIO by implementing the standard FIO binary file
z-routines ZOPNMT, ZCLSMT, ZARDMT, ZAWRMT, ZAWTMT, and ZSTTMT.
The specifications for these routines are given elsewhere.
.le
.sh
3. MTIO Specifications
A magtape file is opened with MTOPEN and then accessed as a binary
file via the device independent FIO interface. Upon input, FIO merges
all tape records together into a binary byte stream. Upon output,
FIO writes records equal in size to the FIO buffers, unless FLUSH or
CLOSE is called, causing a partially filled buffer to be flushed to tape.
The data within a tape file may not be randomly accessed; only sequential
accesses are permitted. When i/o is complete, CLOSE should be called
to close the file and return all buffer space.
fd = mtopen (filename, access_mode, buf_size)
The format of a nonblank magnetic tape consists of beginning-of-tape (BOT),
followed by zero or more files, followed by end-of-tape (EOT).
Each file consists of one or more records, followed by a tape mark (EOF).
EOT is defined as two consecutive tape marks, i.e., as a file containing
zero records. MTIO knows nothing about labeled tapes.
Tape records need not all be the same length, but for transportability
reasons records should be an integral number of computer words in length,
and very short records should be avoided (short records are used by some
operating systems for special purposes). The term "computer word"
is not well defined; the size of a tape record in bytes should be evenly
divisible by 2, 4, or 8, where the transportability increases with the
size of the divisor. To avoid loss of data when reading a tape,
the FIO buffer must be at least as large as the longest record on the tape.
.sh
3.1 Opening a Magtape
MTOPEN opens a file on the named magtape device. The following
device naming convention determines the tape drive and density:
mt[a-z][800|1600|6250]
The letter in the second field determines which drive is to be used,
and the third field, which is optional, determines the density.
If the density is not specified, a system or drive dependent default
density will be selected. Thus, to access a file on drive A at 1600 bpi,
one would open the file "mta1600".
The significance of the terms "drive A", "drive B", etc., is installation
dependent, and need not imply distinct physical drives. A tape drive may
have to be allocated before it can be opened by MTIO; MTIO does not attempt
to allocate devices.
The device name may optionally be followed by a subscript specifying
the index of the file to which the tape is to be positioned.
Thus, opening "mta[3]" causes device A to be opened with the default
density, positioned to BOF of the third file on the tape.
The field N, as in "mta[N]" may have the following values:
.ls 4
.ls 12 absent
If the entire subscript is absent, or if N is absent the tape is opened
at the current position, i.e., the tape is not physically moved.
.le
.ls N >= 1
If an integer number greater than or equal to 1 (one) is given,
the tape is opened positioned to that file.
.le
.ls N == EOT
If the file number is given as "EOT" or as "eot", the tape is opened
positioned at EOT.
.le
.le
If called with a non "mt"-prefixed file name, MTOPEN assumes that the file
is a regular disk resident binary file, and attempts to open the named
file. A program which normally reads directly from a magtape device may
therefore be used to read from a regular binary file, or from the
standard input (the special file "STDIN").
The following access modes are recognized by MTOPEN:
.ls 4
.ls 12 READ_ONLY
The device is opened for reading, positioned to the beginning of
a file, BOT, EOT, or to the "current position".
Any attempt to write to the device will cause an error.
.le
.ls WRITE_ONLY
The device is opened for writing, positioned to the beginning of a file,
BOT, EOT, or to the "current position". When the file is subsequently
closed, a new EOT mark will be written. Existing tape files may be overwritten.
.le
.ls APPEND
The device is opened for writing, positioned at the end of tape (EOT).
Append mode must not be used with blank tapes. Note that the significance
of APPEND mode is different for MTOPEN than for a regular file open;
the tape is to be extended by adding a new file, whereas in FIO it is
the file itself which is extended.
.le
.ls NEW_TAPE
The device is opened for writing, positioned at BOT. Any existing
data on the tape is overwritten. Recommended mode for blank tapes.
.le
.le
FIO can read any tape with a maximum record size less than or equal
to the buffer size. In buffered mode, FIO normally writes records equal
in size to the FIO internal buffers. Smaller records may be written if
FLUSH or CLOSE is called; records of any size may be written in unbuffered
mode.
The third argument to MTOPEN is used to set the FIO buffer size.
If the buffer size is given as zero, a default value is used.
The default value chosen depends on the mode of access and upon the
maximum record size permitted by the host system. MTOPEN will automatically
allocate the maximum size FIO buffer if the tape is opened for reading.
The FIO buffer size may be changed in an FSET call anytime before
the first buffered i/o on the file.
.sh
3.2 Ordinary I/O to a Magtape Device
Seeks are not permitted on magtape files. A tape may be opened for
reading or for writing, but not for both at the same time. A magtape
device is much like the standard input and output; STDIN is read only,
STDOUT is write only, and seeking is not permitted on either. STDIN
differs from ordinary files in that data may continue to be read after
an EOF; the same is true of magtape files. If a read returning EOF is
followed by another read on a magtape device, the second read will
access the first record of the next file. Once EOT is reached, every
read will return EOF. There is no way to advance beyond EOT on a read.
An EOF mark may only be written by closing the tape (see next section).
.sh
3.3 Closing a Magtape
The CLOSE function is called either explicitly by the user task,
or implicilty by the IRAF main upon normal or abnormal task termination.
If the file was opened for writing, CLOSE flushes the output buffer and
writes an EOT mark at the current position. A file opened for writing
is left positioned ready to write the first record of the next file on
the tape (i.e., after the EOF of the file just written). A file opened
for reading, if closed immediately after reading EOF, is left positioned
ready to read or write the first record of the next file on the tape.
.sh
3.4 Bytes and Records
Upon input, the size of a record will be rounded up to an integral
number of "chars". No data will be lost, but one or more extra bytes of
data may be added. A tape conversion program which must deal with
odd-sized records must know the size of tape records to properly extract
the data. FIO cannot write odd-sized records.
The binary i/o routines do not transform the data in any way,
including byte swapping. If byte swapping is necessary, the conversion
program must do the byte swapping explicitly. The predefined machine
constants BYTE_SWAP and WORD_SWAP indicate whether byte or word swapping
is necessary on the local machine (word swapping refers to the two 16 bit
words in a long integer). Floating point data should not be stored in
binary on tape, unless the tape is to be read only by the machine which
wrote it.
Routines are available elsewhere in the PI for manipulating bytes.
The routines BYTMOV, BYTSWP, and BYTPAK are particularly useful for cracking
foreign tapes.
.sh
3.5 Low level I/O to a Magtape
The asynchronous, unbuffered FIO routines AREAD, AWRITE, and AWAIT
may be used to perform record i/o on a magtape. A single tape record
is read or written by each call; the FIO buffer is not used. AWAIT must
be called after each read or write, before initiating the next i/o transfer.
Although in general it is unwise to mix buffered and unbuffered i/o on
the same file, it is safe to perform one or more unbuffered transfers
immediately after opening a file, before performing any buffered i/o.
If an application must do something peculiar, like write an odd-sized
record, the MTIO z-routines may be called directly. The z-routines transfer
data in units of machine bytes.
.sh
3.6 CL level tape commands
The four routines ALLOCATE, DEALLOCATE, REWIND and MTSTATUS will be
available at the CL level. A tape drive ("mta", "mtb", etc.) must be
explicitly allocated before it can be accessed with MTOPEN.
A drive may be allocated to only one user at a time. MTIO keeps track
of the position of an allocated tape; once a drive has been allocated,
the tape must not be manually positioned by the user. Tapes can be
changed without reallocating the drive provided REWIND is first used to
rewind the tape. DEALLOCATE automatically rewinds the tape before
deallocating the drive. MTSTATUS tells whether or not a particular drive
has been allocated, and if so, gives the name of the owner, the density,
whether not the device is physically open, and so on.
.sh
3.6 Example
The following program reads an ASCII card image file from the
input tape and converts it to an ordinary text stream, which is written
to the standard output. This program is insensitive to the number of
cards per tape record, and may be used to read card image disk files
as well as tape files.
The following CL commands might be entered to read the second card image
file on the 800 bpi input tape into file "myfile", converting to lower case:
.ks
.nf
cl> allocate mta
cl> rcardimage "mta800[2]" | lcase > myfile
.fi
.ke
The source for the program "rcardimage" follows:
.ks
.nf
# RCARDIMAGE -- CL callable task which reads a card image
# file, writing the converted cards to the standard output.
procedure rcardimage()
char filename[SZ_FNAME]
int input, mtopen()
begin
call clgstr ("filename", filename, SZ_FNAME)
input = mtopen (filename, READ_ONLY, 0)
call read_card_image_file (input, STDOUT)
call close (input)
end
.fi
.ke
.ks
.nf
define SZ_CARD 80
# READ_CARD_IMAGE_FILE -- Read the named card image file, convert
# to a regular character stream, and write to the output file.
procedure read_card_image_file (input, output)
int input, output # input, output files
char cardbuf[SZ_CARD] # raw card
char linebuf[SZ_CARD+1] # add 1 char for newline
int last_char
int read()
errchk read, putline
begin
# Read successive cards until EOF is reached. Unpack the
# card, strip trailing whitespace, and write the processed
# line to the output file.
while (read (input, cardbuf, SZ_CARD) != EOF) {
call chrupk (cardbuf, 1, linebuf, 1, SZ_CARD)
# Strip trailing whitespace, add newline.
last_char = 0
for (ip=1; ip <= SZ_CARD; ip=ip+1)
if (! IS_WHITE (linebuf[ip]))
last_char = ip
linebuf[last_char+1] = '\n'
linebuf[last_char+2] = EOS
call putline (output, linebuf)
}
end
.fi
.ke
.endhelp
.helpsys mtio Nov83 "MTIO Interface Detailed Design"
.sh
Strategies for Interfacing MTIO
The specifications for MTIO have been kept as simple as possible for maximum
machine independence. There is only one high level call, MTOPEN, which is
used to open the device; it does little more than call FIO. Thereafter
everything is done through the six FIO z-routines:
.nf
zopnmt (filespec, access_mode; channel|ERR)
zclsmt (channel)
zardmt (channel, buffer, maxbytes, one_indexed_byte_offset)
zawrmt (channel, buffer, nbytes, one_indexed_byte_offset)
zawtmt (channel; nbytes|ERR)
zsttmt (channel, parameter; long_value)
.fi
These z-routines may be written in any language so long as they are SPP (i.e.,
Fortran) callable. The "filespec" argument is a packed string. The access
modes and ERR code are system constants defined in <iraf.h>. Channel may be
anything you wish. The file offsets will always be zero since the magtape
device is a streaming (sequential) device.
Be sure that the z-routines, if written partially in the SPP language, do not
make calls to high level program interface routines, especially any which do
i/o. Doing so violates the reentrancy restrictions of the SPP language (and
of Fortran). It may also lead to problems with the way libraries are searched.
More explicitly, any calls to error or iferr, to any of the FIO routines, or to
any of the printf or scan routines are absolutely forbidden. It is ok to use
the string primitives (because they do not do any i/o or call error), but it
is best to avoid even those if possible. It is perfectly all right to call
other z-routines provided they do not directly or indirectly call you back
(none will call mtio).
.sh
Virtual Device Model
Though in general the z-routines may have to be completely rewritten for
a new OS, in fact many systems have functionally similar primitive magtape
interfaces. If your system can be described by the model defined below,
the "z?*.x" files in this directory can be used unchanged, and all you need to
provide are the equivalents of the "zz" prefixed files.
Basically, the model requires that the zz-routine which opens the magtape
be capable of positioning the tape to the first record of any file, given the
file number to which the tape is positioned at open time. The high level MTIO
interface code is charged with keeping track of the position of the tape at
all times, including while the tape is closed. The high level code does not
explicitly move the tape, though it does implicitly move it during open and when
it commands an i/o operation. The high level code assumes nothing about tape
motions; all zz-primitives return status values stating how many records or
files the tape moved in the last operation. Thus, the details of the function
of a zz-routine can vary depending on the system, without requiring
modifications to the z-routines.
.ls 4
.ls (1)
The following open/close primitives are required. ZZOPMT opens a tape
drive positioned ready to read or write the first record of the specified
file.
.ls zzopmt (drive,density,acmode, oldrec,oldfile; newfile; oschan|ERR)
.br
.ls 10 drive
Logical drive number (1,2,3,...).
.le
.ls density
Drive density. A positive integer, i.e., 800, 1600 or 6250. A value
of zero implies that an OS default density is to be selected.
.le
.ls acmode
Access mode. Read_only or write_only. Modes new_file and append are
dealt with by the "newfile" file number parameter.
.le
.ls oldrecord
The number of the record to which we are currently positioned in the
oldfile. We have to know this to know whether or not the file has to
be rewound. The first record is number one.
.le
.ls oldfile
The number of the file to which the tape is currently positioned.
.le
.ls newfile
The number of the file to be opened, where 1 specifies that the tape is
to be rewound. If newfile <= 0, open at EOT. On output, contains the
actual file number of the new file; this may differ from the requested
value if EOT is encountered. It is not an error (as far as the zz-routine
is concerned) to attempt to position to a file beyond EOT.
.le
.ls oschan
The channel number by which the file is to be referred in calls to the
other zz-routines, or ERR if the file cannot be opened. ZZOPMT should
set oschan IMMEDIATELY AFTER PHYSICALLY OPENING THE DEVICE, so that the
error recovery code can close the file if an interrupt occurs.
.le
.le
.ls 4 zzclmt (oschan, access_mode; nfile)
Close tape. Write a new EOT at the current position if writing.
Returns the file number increment (in the event that a file mark or two
has to be written).
.le
.le
.ls (2)
The following i/o primitives are required.
.ls zzrdmt (oschan, buf, maxbytes)
Initiate a read of up to maxbytes bytes from the next tape
record into buffer buf. It is not an error if fewer than "maxbytes"
bytes are read; in fact maxbytes will normally be larger than the largest
record on the tape. In general it is difficult to tell if the tape record
was larger than maxbytes; the user code should select a large maxbytes and
consider it an error if the full maxbytes are read. If EOF is encountered,
return a zero byte count in the next call to zzwtmt.
.le
.ls zzwrmt (oschan, buf, nbytes)
Initiate a write of "nbytes" bytes to the tape. It is an error
if all data is not written.
.le
.ls zzwtmt (oschan; nbytes|ERR, nrecord, nfile)
Wait for i/o to complete, and return the number of bytes read or
written in the last transfer; return 0 if we read a tape mark.
Keep returning the same thing in redundant calls. If an error
occurs the error status should be cleared when the next i/o
transfer is initiated. Return nrecord=1 for each tape record read,
but not for file marks. Return nfile=1 if a filemark is skipped.
A read of 0 bytes signifies that EOF was seen, but does not necessarily
imply that a tape mark has been skipped.
.le
.le
.le
.sh
Program Structure
The drive must be allocated before MTOPEN is called; MTOPEN verifies
that the drive has been allocated and then calls FIO to install the magtape
device and open the desired file on the drive. Allocating a file involves
a call to the OS to allocate and/or mount the device, followed by creation
of the device lock file in the dev$ directory. The lock file is used to
indicate that the drive has been allocated, and to keep track of the tape
position when the drive is closed.
.ks
.nf
mtopen
mt_parse_filespec
mt_get_tape_position
various FIO routines
fopnbf
zopnmt
zzopmt
zsttmt
fset [to set buffer size]
Structure of the MTOPEN Procedure
.fi
.ke
The ZCLSMT procedure is called by CLOSE to close a file opened with MTOPEN.
CLOSE may be called by the user, by the IRAF main if the task completes w/o
closing the file, or during error recovery. An error occurring during MTOPEN
may result in a call to CLOSE. We do not have to worry about reentrancy here
because none of the MTIO z-routines called by ZOPNMT call error (they will
return an ERR status to FOPNBF and therefore terminate before ZCLSMT is called).
.ks
.nf
close
zclsmt
mt_update_lockfile
smark,salloc,sfree
fvfn_to_osfn
mktemp
zopntx
zputtx
zclstx
zfdele
zfrnam
fatal
zzclmt
Structure of the ZCLSMT procedure
.fi
.ke
The i/o procedures keep track of the number of records read or written and
ensure that we do not read past EOF or EOT. We need to keep track of the
number of records written so that we can detect a null file write.
.ks
.nf
aread awrite
zardmt zawrmt
zzrdmt zzwrmt
await
zawtmt
zzwtmt
Structure of the I/O Procedures
.fi
.ke
The final routine is the ZSTTMT status procedure. This routine is self
contained, except that access to the MTIO common is required to get the
access mode (which determines the default buffer size).
.sh
Semicode
We do as much of the work in MTOPEN as we can, since it is the only
high level, machine independent routine we have (we can call anything in this
routine without reentrancy problems). We check that the drive has been
allocated (to us), allocate an mtio device descriptor, check that the same
drive has not been reopened, parse the filespec and save the pieces in the
descriptor (for later use by ZOPNMT), read in the current tape position from
the lock file, and then call fopnbf which in turn calls ZOPNMT to open the
drive and position to the desired file.
.tp 8
.nf
int procedure mtopen (filespec, access_mode, bufsize)
begin
if (file not mt-prefixed) {
call open to open regular binary file
return (file descriptor returned by open)
}
get mtio device descriptor slot but do not allocate it yet
if (slots all taken)
error: magtape device multiply opened (filespec)
call mt_parse_filespec to break out drivename, density,
filenumber and set up mtio device descriptor
if (drive is already open)
error: magtape device multiply opened (filespec)
check that the named drive has been allocated to us
if (drive not allocated to us)
error: magtape not allocated (filespec)
decode lock file to get old position of drive, save in
device descriptor
call fopnbf to install the magtape device and open file
if (bufsize is nonzero)
call fset to set non-default FIO buffer size
return (file descriptor)
end
.fi
ZOPNMT is passed a mostly initialized magtape file descriptor in the mtio
common by MTOPEN. The "filespec" string is not actually used by ZOPNMT.
We physically open the file and set up the remaining fields in the tape file
descriptor. NOTE: if an interrupt occurs during the call to ZZOPMT,
ZCLSMT will be called to perform error recovery. If this happens the
position of the tape is undefined.
.ks
.nf
procedure zopnmt (filespec, access_mode; chan|ERR)
[we are passed the mtio file descriptor in the mtio common]
begin
set flag for ZCLSMT in case we are interrupted
call ZZOPMT to open tape positioned to the beginning of the
indicated file.
if (cannot open tape)
return (chan = ERR)
if (actual file < requested file)
if (reading)
set at-eof flag and at_eot flag, so that reads return EOF
else {
call zzclmt to close device
return (mtchan = ERR)
}
save oschan in descriptor
save actual file number in descriptor
initialize the remaining descriptor fields
return (chan = mtio descriptor index)
end
.fi
.ke
Opening a file for writing and then immediately closing it poses problems.
There is no way to write a zero-length file on an unlabeled tape. We cannot
just write a tape mark because that might mean writing a spurious double
tapemark (false EOT) in the middle of the tape. We could just ignore the
request and not write any file, but that is not quite right either (if a
disk file is opened for writing and then immediately closed, a file is
still created). We compromise by writing a single short record containing
the packed ASCII character string "NULLFILE". The actual length of the
physical nullfile record is machine dependent.
We may or may not need to bump the file counter when the file is closed;
the OS tells us which. If we have just written a file and ZZCLMT must
write a tape mark, for example, we might be left positioned before EOT,
between the tape marks, or (unlikely) after the tape marks.
If an error (i.e., console interrupt) occurs while the tape is being
positioned by ZZOPMT, we will be called by the error recovery system
with a garbage mtchan argument. We must be able to detect this type
of call and modify the lock file, marking the position of the tape
as UNDEFINED. The next open call will then automatically rewind the
tape, ensuring accurate positioning. In a normal close we write out
a lockfile identifying the file and record to which the tape is positioned.
.ks
.nf
procedure zclsmt (mtchan)
begin
if (error recovery in progress for ZOPNMT)
mark current position as undefined
else {
if (file was opened for writing but nothing was written)
write out "null file" short record
call zzclmt (oschan, access_mode; nfiles)
file += nfiles
if (nfiles > 0)
record = 1
}
call mt_update_lockfile to save tape status, position
deallocate the mtio device descriptor slot
end
.fi
.ke
Ignore all read requests once EOF or EOT has been reached. The only operation
possible at that point is to close the device; there is no rewind or backskip
function for a streaming device. We do not "know" what would happen if we
called ZZRDMT after reaching EOF; this is OS dependent, and we do not want
to require any particular behavior (some systems would return the first
record of the next file, others would keep returning EOF).
.ks
.nf
procedure zardmt (mtchan, buf, maxbytes, offset)
begin
if (not at EOF or EOT)
call zzrdmt (oschan, buf, maxbytes)
end
.fi
.ke
We cannot hit EOF or EOT on a write, so merely post the request and return.
Ignore the "offset" parameter since magtape is a streaming device.
.ks
.nf
procedure zawrmt (mtchan, buf, nbytes, offset)
begin
call zzwrmt (oschan, buf, nbytes)
end
.fi
.ke
FIO insures that ZAWTMT is called once and only once after every asynchronous
i/o read or write request. Once we hit EOF or EOT on a read, we return
EOF (nchars = 0) on every subsequent request until the file is closed.
After each real data transfer we update the record,file counters as
directed by the OS.
.ks
.nf
procedure zawtmt (mtchan; status)
begin
if (reading and at EOF or EOT)
return (status = 0)
call zzwtmt (oschan, nchars, nrecords_skipped, nfiles_skipped)
if (nfiles_skipped > 0) {
set at-EOF flag
record = 1
}
file += nfiles_skipped # keep track of position
record += nrecords_skipped
nrecords += nrecords_skipped # count records rd|wr
status = nchars
end
.fi
.ke
.sh
Error Recovery
Error recovery during magtape operations is tricky since we are trying
to keep track of the position of the drive. If an error occurs while the
tape is being positioned by ZZOPMT we must detect the condition and mark the
position of the tape as indefinite (forcing a rewind on the next open).
If an interrupt occurs while positioning to EOT for a write, we do not
want ZZCLMT to write the new EOT mark somewhere in the middle of the tape,
truncating the tape.
Interrupts or other errors while reading or writing are comparatively
harmless. Interrupting a write results in a short but otherwise normal
file on the tape; interrupting a read leaves us positioned to some
arbitrary record within the file (harmless). Conceivably a read
could be interrupted just as we were reading a tape mark, causing the
file position to be lost. We have not protected against this.
.sh
Data Structures
The mtio device descriptor structure describes the status of each magtape
device in use. The maximum number of magtape files which can be open at one
time is the maximum number of tape drives. Only one file can be open on each
drive at a time.
.ks
.nf
struct mtiodes {
int mt_drive # 1,2, etc. (c.t. a,b,...)
int mt_density # 0,800,1600,6250, etc.
int mt_oldfile # file number at open time
int mt_oldrecord # record number at open time
int mt_file # file being accessed (0=EOT)
int mt_record # next record to be accessed
int mt_nrecords # nrecords read/written
int mt_acmode # access mode
int mt_oschan # OS channel number
int mt_ateof # true when at EOF
int mt_ateot # true when at EOT
} mtiocom[MAX_TAPES]
.fi
.ke
When a device is allocated, a lock file is created in the system logical device
directory "dev$". For example, the lock file for magtape unit A is the
file "dev$mta.lok". This is a human readable text file; it is typed out on
the terminal when the user types "devstatus mta". The lock file is updated
when the drive is closed and deleted when the drive is deallocated. The drive
is automatically deallocated when the user logs out of the CL.
.ks
.nf
Sample Lock File:
# Magtape unit 'mta' allocated to 'user' Sun 20:06:13 27-Nov-83
current file = 4
current record = 1
72 records read, EOF seen
.fi
.ke
The preliminary comments are written when the lock file is created, i.e.,
when the device is allocated. Any number of comment lines are permitted.
They are merely copied when ZCLSMT updates the lock file. The remaining
records are written by ZCLSMT to record the current position of the tape,
and to inform the user of the device status.
|