1
/* @(#)osu.c 19.1 (ES0-DMD) 02/25/03 13:56:14 */
2
/*===========================================================================
3
Copyright (C) 1995 European Southern Observatory (ESO)
5
This program is free software; you can redistribute it and/or
6
modify it under the terms of the GNU General Public License as
7
published by the Free Software Foundation; either version 2 of
8
the License, or (at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public
16
License along with this program; if not, write to the Free
17
Software Foundation, Inc., 675 Massachusetss Ave, Cambridge,
20
Corresponding concerning ESO-MIDAS should be addressed as follows:
21
Internet e-mail: midas@eso.org
22
Postal address: European Southern Observatory
23
Data Management Division
24
Karl-Schwarzschild-Strasse 2
25
D 85748 Garching bei Muenchen
27
===========================================================================*/
29
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
33
.AUTHOR Francois Ochsenbein [ESO]
34
.CATEGORY Interface to i/o on devices like tapes / OD / etc
35
.ENVIRONMENT VAX / VMS or Unix
37
The functions of this module perform basic i/o to/from magnetic tape
39
on VAX/VMS environment. The maximum number of available special
40
units is assumed to be MAXDEV (defined here)
43
{\bf Some Troubleshooting}: With TD interface, the error
44
``Invalid Buffer Length"
45
arises when the read/write buffer is not aligned at a 4-byte
48
{\bf Restrictions}: read/write on (optical) disks is limited to
51
A file, called DEVCAPFILE, is used to describe the various parameters of the
52
device(s). Each device is described in this file,
53
as {\tt node\_name{\bf!}device\_name} where {\tt device\_name}
54
is the {\em physical} name of the device.
55
Properties are described as {\tt pp}$=${value}, where {\tt pp} is
56
a 2-letter code specifying the item.
57
The most important items in this file are:
59
\item {\tt bs}$=$ blocksize (in bytes)
60
\item {\tt ss}$=$ sector size (in bytes)
61
\item {\tt us}$=$ Unit size in sectors
62
\item {\tt ds}$=$ density (concerns tapes only)
63
\item {\tt dc}$=$ Reference to another device in the DEVCAPFILE
64
\item {\tt cl}$=$ Device Class Name. This Name specifies the iodev class
65
which must be used to access the lower-level io functions.
66
\item {\tt bw}$=$ 0 if Backwards Movements are NOT available.
71
.VERSION 1.0 10-Mar-1986: Creation
72
.VERSION 1.1 21-Mar-1986 : Modified io1 and io2 for direct-access
74
.VERSION 1.2 17-Dec-1986: New FCB definition
75
.VERSION 1.3 21-May-1987: Suppress warning message
76
.VERSION 2.0 24-Feb-1988: Integrated as osu routines.
77
Tested on Gigadisk, Maxtor
78
.VERSION 3.0 03-Agu-1988: Implementation in mVAX-Ultrix. C Guirao.
79
.VERSION 3.1 28-Nov-1988: Implementation in VAX/VMS. C Guirao.
80
.VERSION 3.2 28-Nov-1988: Using MAXIO1 record. C Guirao.
81
.VERSION 3.3 05-May-1989: Forcing "tmove()" reading to check double
82
file mark. Translating WRITE in READ_WRITE in open mode,
83
and checking the proper mode in osuread. C Guirao.
84
.VERSION 3.4 18-Jul-1989: Devices are described in a file named $DEVCAPFILE
85
Added osubsize to get blocksize
86
.VERSION 4.0 12-Oct-1989: Use of external functions.
87
.VERSION 4.1 27-Oct-1989: Be sure that DEVCAPFILE exists.
88
Added tm (number of tm for End of Tape)
89
.VERSION 4.2 20-Dec-1989: Removed bug in scandev (F.O.)
90
Added functions for Disks, and EOM (End-Of-Media).
91
.VERSION 4.3 11-Jan-1990: Added osustat. Added NULL devices.
92
.VERSION 4.4 18-May-1990: 2 parameters for osuclose .
93
Loop check on findclass. FO
94
.VERSION 4.5 20-Nov-1990: osuclose properly handled for DA devices
95
.VERSION 4.6 23-Apr-1991: Corrected tmove (suppress error condition)
97
-----------------------------------------------------------------------------*/
99
#define MAXDEV 4 /* Maximal number of opened devices */
100
#include <osudef.h> /* Internal to osu / iodev */
101
#include <osnull.h> /* Contains NULL_DEV definition */
102
#include <devstat.h> /* Contains devstat structure */
103
#include <filedef.h> /* Contains READ, WRITE, etc... */
105
#include <computer.h>
108
typedef int (*FCT)();
110
MID_EXTERN int oserror;
111
MID_EXTERN char *oserrmsg;
113
#define MAX(x,y) ((x) >= (y) ? (x):(y) ) /* Maximum */
114
#define MIN(x,y) ((x) <= (y) ? (x):(y) ) /* Minimum */
115
#define NULL_PTR(x) (x *)0
117
#define IO_MAX MAXIO1
118
#define BUFTEST 2048 /* The size of a test buffer */
119
#define DEFAULT_DENSITY 1600 /* Density by default */
120
#define DEFAULT_SECTORSIZE 512 /* Size of one disk sector */
121
#define DEFAULT_USIZE 10240 /* Default number of sectors */
122
#define START_DEV 100 /* First Number */
124
/* Definition of Functions */
126
#define ioinfo(f,b,fn,bn) (*fcb->ops[U_INFO])(f,b,fn,bn)
127
#define ioopen(f,m,d) (*fcb->ops[U_OPEN])(f,m,d)
128
#define ioclose(f,o) (*fcb->ops[U_CLOSE])(f,o)
129
#define ioread(f,b,l) (*fcb->ops[U_READ])(f,b,l)
130
#define iowrite(f,b,l) (*fcb->ops[U_WRITE])(f,b,l)
131
#define iorew(f) (*fcb->ops[U_REWIND])(f)
132
#define ioeom(f) (*fcb->ops[U_EOM])(f)
133
#define ioweof(f) (*fcb->ops[U_WEOF])(f,1)
134
#define iofsf(f,n) (*fcb->ops[U_FMF])(f,n)
135
#define iobsf(f,n) (*fcb->ops[U_FMB])(f,n)
136
#define iofsr(f,n) (*fcb->ops[U_BMF])(f,n)
137
#define iobsr(f,n) (*fcb->ops[U_BMB])(f,n)
138
#define iosread(f,s,ss,b,l) (*fcb->ops[U_SREAD])(f,s,ss,b,l)
139
#define ioswrite(f,s,ss,b,l) (*fcb->ops[U_SWRITE])(f,s,ss,b,l)
142
/* This structure, created for each device, allows to know
143
the current position on any device
145
typedef int (*FCT_PTR)(); /* Pointer to function */
147
typedef struct { /* File Control Block */
148
char *name; /* PHYSICAL Device Name */
149
char *klass; /* Device Class Name */
150
unsigned char access; /* Access mode 0/1/2/3 */
151
#define FCB_AM 16 /* Append Mode available */
152
#define FCB_BW 32 /* Backwards available */
153
#define FCB_DA 64 /* Direct Access (Seek) */
154
#define FCB_TM 128 /* Tape Mode (erase's end) */
155
unsigned char ignore; /* ignore flags */
156
#define FCB_NOCOUNT 32 /* Unknown block number */
157
#define FCB_NOFEET 64 /* Unknown feet count */
158
unsigned char last_op; /* Last operation performed */
159
unsigned char eotm; /* Number of TM to write at end */
160
long feet; /* used tape length in feet/1000*/
161
long usize; /* bytes of file / total blocks */
162
long block_no; /* block position within file */
163
int tape_marks; /* Number of CONSECUTIVE TM */
164
int block_max; /* Maximum blocksize (tape) */
165
int block_min; /* Minimum blocksize (tape) */
166
int blocksize; /* Size of one block */
167
int sectorsize; /* Size of one sector */
168
int density; /* Density (Tapes), sector size */
169
int file_no; /* number of file (for MT) */
170
FCT_PTR ops[U_MAX+1]; /* Available Operations */
171
/* --- System-dependant Part----*/
172
int pfd; /* Tape file descriptor in UNIX */
175
#define tgap (fcb->density == 6250? (1500/12) : (3000/12)) \
176
/* Gap on tape due to the Tape-Mark */
178
#define BADCLASSmsg "Class of Device unknown:"
180
static FCB *Units[MAXDEV] = {0,0,0,0};
182
static int ncb = START_DEV; /* Number of opened units */
183
static char hasbw; /* 1 if Backward available */
184
static char hasam; /* 1 if Append Mode available */
186
char msg[sizeof(BADCLASSmsg)];
188
} theclass = { BADCLASSmsg, "mt" };
189
static struct osustat stbuf;
190
static int findclass_loop = 0;
191
#define MAX_findclass 50 /* Recursivity limit to find a device class */
195
/*=====================================================================
197
*=====================================================================*/
199
static int osuerror(op)
200
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
201
.PURPOSE Set Error Message
203
----------------------------------------------------------------------*/
204
int op; /* IN: The operation to execute */
206
static char msg[60] = "Function not available: ";
207
register char *pm, *pl;
208
static char *text[] = {
211
/* U_CLOSE */ "close",
213
/* U_WRITE */ "write",
214
/* U_REWIND*/ "rewind",
215
/* U_SREAD */ "sector_read",
216
/* U_SWRITE*/ "sector_write",
217
/* U_WEOF */ "write_EOF",
218
/* U_FMF */ "file_move_forward",
219
/* U_FMB */ "file_move_backwards",
220
/* U_BMF */ "block_move_forward",
221
/* U_BMB */ "block_move_backwards",
222
/* U_EOM */ "to_EOMedia"
229
/* Append the signification of the function */
230
for(pl = text[op]; *pl; pl++) *(pm++) = *pl;
235
/* Declare here the various error functions */
236
static int err0() { return(osuerror(0));}
237
static int err1() { return(osuerror(1));}
238
static int err2() { return(osuerror(2));}
239
static int err3() { return(osuerror(3));}
240
static int err4() { return(osuerror(4));}
241
static int err5() { return(osuerror(5));}
242
static int err6() { return(osuerror(6));}
243
static int err7() { return(osuerror(7));}
244
static int err8() { return(osuerror(8));}
245
static int err9() { return(osuerror(9));}
246
static int err10() { return(osuerror(10));}
247
static int err11() { return(osuerror(11));}
248
static int err12() { return(osuerror(12));}
249
static int err13() { return(osuerror(13));}
251
static FCT err_fct[1+U_MAX] = {
252
err0, err1, err2, err3, err4, err5, err6, err7, err8, err9,
253
err10, err11, err12, err13};
256
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
257
.PURPOSE Retrieve the FCB structure
258
.RETURNS 0 (success) / -1 (failure)
260
----------------------------------------------------------------------*/
261
int f; /* IN: Unit number */
264
oserrmsg = NULL_PTR(char);
268
if ((f >= START_DEV) && (f <= ncb))
269
fcb = Units[f-START_DEV];
271
if (fcb == NULL_PTR(FCB)) {
273
oserrmsg = "Bad Unit Number";
279
static long tfeet(blk)
280
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
281
.PURPOSE Compute the length of a block on a magnetic tape
282
.RETURNS The length in feet/1000
283
.REMARKS Only for tapes!
284
----------------------------------------------------------------------*/
285
unsigned int blk; /* IN: Size of the Block (bytes) */
287
register long ctrl, dblk;
291
switch(fcb->density) {
292
case 0: return(0); /* Unknown density */
293
case 6250: /* Formula for 6250bpi */
294
ctrl = ((blk-1)/790 + 1) * 20000;
295
return((301 + (dblk+ctrl)/fcb->density)/12);
296
default: /* Formula for other densities */
297
return(((dblk/fcb->density)+600)/12);
302
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
303
.PURPOSE Update fcb information when a new file starts
305
.REMARKS For disks, should be called only at open...
306
----------------------------------------------------------------------*/
308
fcb->ignore &= ~(FCB_NOCOUNT); /* count number is correct */
310
if (fcb->file_no < 0) { /* Beginning of Tape */
311
if (fcb->access & FCB_TM)
312
fcb->ignore &= ~(FCB_NOFEET),
313
fcb->feet= 0; /* No length for this file */
314
fcb->file_no = 0; /* First File */
316
else { /* Increment the file counter */
317
fcb->file_no += fcb->tape_marks;
318
fcb->feet += fcb->tape_marks * tgap;
320
fcb->tape_marks= 0; /* No tape-mark encountered */
321
fcb->block_no = 0; /* block position within file */
322
fcb->block_max = 0; /* Maximum blocksize */
323
fcb->block_min = 0; /* Minimum blocksize */
328
static int newpos(bytes)
329
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
330
.PURPOSE Computes the new position on the device
333
----------------------------------------------------------------------*/
334
int bytes; /* IN: number of bytes read/ written */
336
if (fcb->tape_marks) newfile();
338
if (fcb->access & FCB_DA) /* Direct Access */
339
{ fcb->block_no += (bytes/fcb->sectorsize);
340
if (bytes%fcb->sectorsize) fcb->block_no += 1;
342
else if (fcb->access & FCB_TM)
343
{ fcb->feet += tfeet(bytes);
347
fcb->block_max = MAX(fcb->block_max, bytes);
348
fcb->block_min = MIN(fcb->block_min, bytes);
349
if (fcb->block_min <= 0) fcb->block_min = bytes;
355
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
356
.PURPOSE Rewind the tape
357
.RETURNS 0 (success) / -1 (failure)
358
.REMARKS fcb updated.
359
----------------------------------------------------------------------*/
362
if (oserror) return(-1);
364
fcb->last_op = U_REWIND;
371
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
372
.PURPOSE Write EOF (Single TM)
373
.RETURNS 0 (success) / -1 (failure)
375
----------------------------------------------------------------------*/
381
(fcb->tape_marks)++, fcb->last_op = U_WEOF;
383
return(oserror ? -1 : 0);
387
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
388
.PURPOSE Move Forwards 1 TM.
389
.RETURNS 0 (success) / -1 (failure)
390
.REMARKS After move, the tape is positionned after a tape-mark.
391
----------------------------------------------------------------------*/
393
register int l, lbuf;
395
char test_buffer[BUFTEST];
397
/* If a TM was previously detected, ensure a physical */
398
/* reading to force the move */
399
if (fcb->tape_marks) {
400
lbuf = BUFTEST - (BUFTEST % fcb->blocksize);
401
l = ioread(fcb->pfd, test_buffer, lbuf);
402
if (l == -1) l = lbuf; /* Generally "too small buffer */
403
fcb->last_op = U_FMF;
408
newfile(); /* Tape_marks reset to zero */
412
if (iofsf(fcb->pfd, 1) == -1) return(-1);
414
fcb->ignore |= (FCB_NOFEET|FCB_NOCOUNT);
416
fcb->last_op = U_FMF;
422
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
423
.PURPOSE Move Backwards 1 TM.
424
.RETURNS 0 (success) / -1 (failure)
425
.REMARKS After move, the tape is positionned just before a tape-mark.
426
----------------------------------------------------------------------*/
429
fcb->tape_marks -= 1;
432
fcb->ignore |= (FCB_NOCOUNT|FCB_NOFEET);
435
if (fcb->file_no < 0)
438
iobsf(fcb->pfd,1), fcb->last_op = U_FMB;
440
return(oserror ? -1 : 0);
443
static struct iolist *findclass(aclass)
444
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
445
.PURPOSE Retrieve the class name
446
.RETURNS Pointer to found class / NULL
448
----------------------------------------------------------------------*/
449
char *aclass; /* IN: Class to look for */
451
struct iolist *plist, *iodev();
452
struct iolist *(*def)();
455
/* Follow the linked list of iolist's */
457
if (++findclass_loop > MAX_findclass)
458
return (NULL_PTR(struct iolist));
460
for (def = iodev; def; def = plist->next)
463
for(q=aclass, p=plist->klass; (*p == *q) && (*p); p++, q++) ;
464
if ((*q == '\0') && (*p == '\0')) break;
466
if (!def) /* Class Not Found */
467
plist = NULL_PTR(struct iolist);
472
static int getclass()
473
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
474
.PURPOSE Retrieve the class name, to retrieve operators.
475
.RETURNS 0 / -1 (class doesn't exist)
476
.REMARKS Functions added in FCB
477
----------------------------------------------------------------------*/
479
struct iolist *plist;
485
plist = findclass(theclass.klass);
487
oserror = -1, oserrmsg = (char *)&theclass;
488
theclass.msg[sizeof(theclass.msg)-1] = ' ';
492
fcb->klass = plist->klass;
495
** We have just to insert the functions in the list
498
for (pop = plist->oplist, i = plist->nop; --i >= 0; pop++)
499
fcb->ops[pop->opid] = pop->opf;
504
static int scandev(fd, dev)
505
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
506
.PURPOSE Get Capabilities in opened DEVCAPFILE
508
.REMARKS Recursive call if `dc=' is found.
509
----------------------------------------------------------------------*/
510
int fd; /* IN: DEVCAPFILE file descriptor */
511
char *dev; /* IN: Device name */
514
char buf[133]; /* One line of DEVCAPFILE */
517
/* Be sure dev is terminated with Null */
519
for (p = dev; isgraph(*p); p++) ;
522
osaseek(fd, 0L, FILE_START);
523
while (osaread(fd, buf, sizeof(buf)) >= 0)
525
if (buf[0] == '#') continue;
526
for (p = buf, q = dev; *q && (*p == *q); p++, q++) ;
527
if(*q == '\0') goto found_dev;
533
/* Here when device is found. Get interesting items, i.e.
543
while (isspace(*p)) p++; /* Skip blanks */
544
if(!*p) continue; /* Empty line */
546
if (*p == '\\') /* There is a continuation. Read Next record */
549
if (osaread(fd, buf, sizeof(buf)) < 0) buf[0] = '\0';
550
if (buf[0] == '#') /* It's a comment */
553
if (isspace(buf[0])) continue;
556
if (oscomp(p, "dc=", 3) == 0) /* Fetch another name */
557
return(scandev(fd, p+3));
558
if (oscomp(p, "bs=", 3) == 0) /* Blocksize */
559
{ if (!fcb->blocksize) fcb->blocksize = atoi(p+3); }
560
else if (oscomp(p, "us=", 3) == 0) /* Unit Size */
561
{ if (!fcb->usize) fcb->usize = atoi(p+3); }
562
else if (oscomp(p, "ss=", 3) == 0) /* Sector Size */
563
{ if (!fcb->sectorsize) fcb->sectorsize = atoi(p+3); }
564
else if (oscomp(p, "ds=", 3) == 0) /* Density */
565
{ if (!fcb->density) fcb->density = atoi(p+3); }
566
else if (oscomp(p, "tm=", 3) == 0) /* Number of tm */
567
{ if (!fcb->eotm) fcb->eotm = atoi(p+3); }
568
else if (oscomp(p, "am=", 3) == 0) /* BackWard */
569
{ if (hasam == 2) hasam = atoi(p+3); }
570
else if (oscomp(p, "bw=", 3) == 0) /* BackWard */
571
{ if (hasbw == 2) hasbw = atoi(p+3); }
572
else if (oscomp(p, "cl=", 3) == 0) /* Class */
573
{ for (i=0, p+=3; (i<sizeof(theclass.klass)-1)&&
574
(isgraph(*p)); i++, p++)
575
theclass.klass[i] = *p;
576
theclass.klass[i] = '\0';
578
while (isgraph(*p)) p++; /* Look for space */
585
static int getdev(dev)
586
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
587
.PURPOSE Get Capabilities from DEVCAPFILE.
589
.REMARKS Relevant Cap's are used to update the current fcb
590
----------------------------------------------------------------------*/
591
char *dev; /* IN: Device name */
593
char *devcapfile; /* DEVCAPFILE name */
597
/* Check if a DEVCAPFILE does exist */
599
devcapfile = oshenv("DEVCAPFILE", NULL_PTR(char));
601
oserror = -1; oserrmsg = "DEVCAPFILE is unknown...";
605
/* It does. Open in read_only mode */
607
fd = osaopen(devcapfile, READ);
609
oserror = -1; oserrmsg = "Entry unknown in DEVCAPFILE";
613
/* Scan the file for the device name, expand dc= references */
615
if (scandev(fd, dev) < 0) {
616
oserror = -1; oserrmsg = "Entry unknown in DEVCAPFILE";
620
/* Finally Close DEVCAPFILE */
626
/*=====================================================================
628
*=====================================================================*/
630
int osugrep (class_name, item)
631
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
632
.PURPOSE Get the item function in a class of devices
634
----------------------------------------------------------------------*/
635
char *class_name; /* IN: Class of Devices (NULL for any) */
636
OPITEM *item; /* OUT: op_code + Function Pointer */
638
struct iolist *plist, *iodev();
639
struct iolist *(*def)();
644
for (def = iodev; def; def = plist->next)
646
if (!class_name) /* Class not specified: look to next one */
648
else plist = findclass(class_name);
649
if (!plist) return(-1);
651
/* Retrieve the item in list */
653
for (pop = plist->oplist, i = plist->nop;
654
(--i >= 0) && (pop->opid != item->opid); pop++) ;
656
if (i >= 0) /* I found the relevant item... */
657
{ item->opf = pop->opf;
660
if (class_name) break;
667
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
668
.PURPOSE Retrieve name of an opened unit (current when f = -1)
669
.RETURNS Name / NULL pointer if failed
670
----------------------------------------------------------------------*/
671
int f; /* IN: The unit number */
675
return((char *)0); /* Bad unit number... */
677
return(fcb ? fcb->name : NULL_PTR(char));
681
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
682
.PURPOSE Retrieve opening mode
683
.RETURNS Mode / -1 when error
684
----------------------------------------------------------------------*/
685
int f; /* IN: The unit number */
689
return(-1); /* Bad unit number... */
691
return(fcb ? fcb->access & 3 : -1);
695
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
696
.PURPOSE Get the block size of the unit.
697
.RETURNS The size of blocks for block devices (1 for tapes)
698
----------------------------------------------------------------------*/
699
int f; /* IN: The unit number */
703
return(-1); /* Bad unit number... */
705
return(fcb ? fcb->blocksize : -1);
707
int osustatus(f, stat)
708
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
709
.PURPOSE Get the status of the device
711
----------------------------------------------------------------------*/
712
int f; /* IN: The unit number */
713
struct devstat *stat; /* OUT: Filled with known info */
716
return(-1); /* Bad unit number... */
718
stat->name = fcb->name;
719
stat->klass = fcb->klass;
720
stat->density = fcb->density;
721
stat->sectorsize = fcb->sectorsize;
722
stat->usize = fcb->usize;
723
stat->blocksize = fcb->blocksize;
724
stat->file_no = fcb->file_no;
725
stat->block_no = fcb->block_no;
726
stat->block_max = fcb->block_max;
727
stat->block_min = fcb->block_min;
728
stat->feet = fcb->feet;
729
stat->tape_marks = fcb->tape_marks;
734
int osuopen (device, mode, den)
735
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
736
.PURPOSE Assign (mount) a tape with a specified density
737
.RETURNS The device number / -1 on error
738
.REMARKS The default device class is "mt".
739
The mount is performed here.
740
If density is not specified or is zero, use DEFAULT_DENSITY
741
for write-only; get the density otherwise.
742
.REMARKS Open the device in APPEND mode does not work properly (it is
743
like READ mode instead). It has been implemented changing the
744
open mode to READ_WRITE and positioning the tape between the last
746
----------------------------------------------------------------------*/
747
char *device; /* IN: The unit name, blank or NULL for null device */
748
int mode; /* IN: open mode: READ, WRITE, READ_WRITE, APPEND */
749
int den; /* IN: The density or sector size; 0 if default */
752
register char *p, *q;
753
char *devname, isnulldev;
755
/* Convert NULL device name if necessary */
757
if (!devname) devname = "";
758
isnulldev = !*devname; /* Is zero for NULL device */
759
if (isnulldev) devname = NULL_DEV;
762
oserrmsg = NULL_PTR(char);
764
hasam = 2; /* Unknown Parameter */
765
hasbw = 2; /* Unknown Parameter */
768
/* Check if there are not too many devices */
770
for (i = 0; i < MAXDEV; i++)
771
if (!Units[i]) break;
775
oserrmsg = "Too many opened osu Units" ;
779
/* Allocate FCB, and Try to guess the device class from name:
780
if device name contrains a D, assume "disk" class
784
fcb = (FCB *)osmmget(sizeof(FCB) + l + 2);
785
/* Note: 2 for EOS and ':' */
789
if (isnulldev) p = "dumb";
790
else { /* Look for a `d' for Disk, eitherwise Tape */
791
q = devname + oscbloc(devname, l, '/') + 1;
792
l -= (q - devname); /* Keep filename */
793
if ((oscbloc(q, l, 'd') >= 0 ) || (oscbloc(q, l, 'D') >= 0))
797
oscopy(theclass.klass, p, 1+strlen(p));
799
/* Initialize the structure, and copy device name */
801
fcb->name = (char *)(fcb+1);
803
fcb->ignore = FCB_NOFEET;
808
fcb->block_max = 0; /* Maximum blocksize */
809
fcb->block_min = 0; /* Minimum blocksize */
814
for (l = 0; l < sizeof(fcb->ops)/sizeof(fcb->ops[0]); l++)
815
fcb->ops[l] = err_fct[l];
817
/* Fill fcb with Info from DEVCAPFILE */
820
/* Copy device name, but strip hostname info.
821
However, if getdev returned with an error,
822
and the ! is present (i.e. DEVCAPFILE doesn't find
823
the entry), return with an error.
824
Devices without the ! are assumed to be standard */
826
for (p = devname; (*p) && (*p != '!'); p++) ;
827
if (*p == '!') { if (l < 0) goto error_found; p++;}
829
for (q = fcb->name; *p; p++, q++) *q = *p;
831
oserror = 0; /* Clear error from getdev */
833
if (fcb->eotm == 0) /* Default = 2 TM */
836
hasam = (fcb->eotm < 2);
837
if (fcb->density <= 0)
838
fcb->density = DEFAULT_DENSITY;
839
if (fcb->blocksize <= 0)
840
fcb->blocksize = 1; /* Tapes have this blocksize... */
842
/* Find to which Class the Device belongs to. */
844
if (getclass() < 0) goto error_found;
846
/* Open the device. DON'T REWIND ! */
848
fcb->pfd = ioopen(fcb->name,
849
((mode == WRITE) ? READ_WRITE : mode),
851
if (oserror) goto error_found;
854
i += START_DEV; /* Actual returned unit number */
855
if (i >= ncb) ncb = i;
856
fcb->last_op = U_OPEN; /* Last Operation */
858
/* Get Other Info about Device */
860
ioinfo(fcb->pfd, &stbuf, &fcb->file_no, &fcb->block_no);
861
if (isnulldev) oserror = 0; /* This can't be a problem */
863
/* Fill the missing items with final info */
865
if (fcb->ops[U_EOM] == osuerror) hasam = 0;
866
if (stbuf.density) fcb->density = stbuf.density;
867
if (hasbw) fcb->access |= FCB_BW;
868
if (hasam) fcb->access |= FCB_AM;
870
/* Take defaults for DA devices */
872
{ fcb->access |= FCB_DA;
873
if (stbuf.blocksize == 0)
874
stbuf.blocksize = DEFAULT_SECTORSIZE;
875
if (fcb->sectorsize == 0)
876
fcb->sectorsize = den;
877
if (fcb->sectorsize < stbuf.blocksize)
878
fcb->sectorsize = stbuf.blocksize;
879
if (fcb->usize == 0) fcb->usize =
880
stbuf.usize/(fcb->sectorsize/stbuf.blocksize);
881
if (fcb->usize == 0) fcb->usize = DEFAULT_USIZE;
882
if (fcb->blocksize <= 1)
883
fcb->blocksize = fcb->sectorsize;
885
if (fcb->usize == 0) fcb->usize = stbuf.usize;
886
if (stbuf.istm) fcb->access |= FCB_TM;
889
* If the system doesn't know the position,
891
* Check position. If 2 TM indicate the End-Of-Tape, be sure that
892
* we are not between, or after 2 TM , i.e. rewind.
895
if (fcb->file_no < 0) {
900
if (fcb->file_no > 0 && fcb->eotm > 1 ) {
905
/* Position to EOF if Append */
907
fcb->last_op = U_OPEN; /* Last Operation */
908
if ((mode&3) == APPEND) osufseek(i, 0, FILE_END);
911
Units[i-START_DEV] = NULL_PTR(FCB);
921
int osuclose (f, option)
922
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
923
.PURPOSE Close (dismount) a tape / optical disk
925
.REMARKS Tape is always rewinded...
926
----------------------------------------------------------------------*/
927
int f; /* IN: The unit to close */
928
int option; /* IN: Option 1 to dismount / spin down */
931
return(-1); /* Bad unit number... */
933
/* Perform necessary checks. Write tape marks is previous operation
934
** was write or fclose.
937
if (fcb->access & FCB_DA) ;
939
if (fcb->last_op == U_WRITE) tfclose();
940
if ((fcb->last_op == U_WEOF) && (fcb->tape_marks < fcb->eotm))
944
if(oserror) return(-1);
946
if (ioclose(fcb->pfd, (option == 1 ? OPU_DISMOUNT : 0)))
950
Units[f-START_DEV] = NULL_PTR(FCB);
955
int osuread (f, buffer, length)
956
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
957
.PURPOSE Read a block from magnetic tape / optical disk.
958
.RETURNS Bytes read (>length if buffer too small) / 0 for EOF / -1 for
959
error; omsg provides an explanation.
960
.REMARKS The length MUST be a multiple of a sector size for
962
The returned length may be zero for virgin sectors.
963
.REMARKS Reading consecutive file marks, it is posible to go further
965
----------------------------------------------------------------------*/
966
int f; /* IN: The file control block */
967
char *buffer; /* OUT: The buffer */
968
int length; /* IN: The length of the buffer */
972
/* Check Buffer Length */
974
if (length < sizeof(long)) {
976
oserrmsg = "Too small buffer";
979
if (uget(f)) /* Bad unit number... */
983
** If device was opened in only_write mode, return error
984
** if trying to read something
987
if ((fcb->access & 3) == WRITE) {
992
** Check if some required blocksize MUST be used.
995
if (length%fcb->blocksize)
996
{ oserror = -1, oserrmsg = "Length not a multiple of Blocksize";
1001
** For Tapes, check for illegal read
1004
if (fcb->access & FCB_TM)
1005
{ if ((fcb->last_op == U_WRITE) || (fcb->last_op == U_WEOF))
1007
oserrmsg = "Can't read after write";
1013
** For Direct-Access devices, use iosread (0 means "virgin sector")
1014
** For Tapes, use ioread (0 means "tape-mark" )
1016
if (fcb->access & FCB_DA)
1017
l = iosread(fcb->pfd, fcb->block_no, fcb->sectorsize,
1020
l = ioread(fcb->pfd,buffer,length);
1021
if (l == 0) fcb->tape_marks++;
1024
/* Check special case oserror = -2, means TOO SHORT BUFFER */
1025
if (oserror == -2) {
1027
oserrmsg = "Too short buffer";
1028
fcb->ignore |= FCB_NOFEET;
1034
fcb->last_op = U_READ;
1036
if (l > 0) /* Something was read, update fcb contents */
1042
int osuwrite (f, buffer, length)
1043
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1044
.PURPOSE Write a block on magnetic tape / optical disk.
1045
.RETURNS Length written / -1 (error)
1047
----------------------------------------------------------------------*/
1048
int f; /* IN: The file control block */
1049
char *buffer; /* IN: The buffer */
1050
int length; /* IN: The length of the buffer */
1054
/* Check Buffer Length */
1056
if ((length <= 0) || (length > IO_MAX)) {
1058
oserrmsg = "Bad buffer size";
1062
if (uget(f)) /* Bad unit number... */
1065
/* Check if Write is Allowed */
1067
if ((fcb->access & 3) == READ) {
1073
** Check if some required blocksize MUST be used.
1076
if (length%fcb->blocksize)
1077
{ oserror = -1, oserrmsg = "Length not a multiple of Blocksize";
1082
** For Tapes, check if 2 TM were previously written;
1083
** if yes, the data will not be accessible...
1085
if (fcb->access & FCB_TM)
1086
{ if (fcb->tape_marks >= 2) {
1087
oserror = -1, oserrmsg = "Attempt to write beyond EOF";
1093
** For Direct-Access devices, use ioswrite .
1095
if (fcb->access & FCB_DA)
1096
l = ioswrite(fcb->pfd, fcb->block_no, fcb->sectorsize,
1098
else l = iowrite(fcb->pfd,buffer,length);
1105
fcb->last_op = U_WRITE;
1110
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1111
.PURPOSE Close a File (Write a Tape-Mark on the tape)
1113
.REMARKS Tape mouvements are optimized.
1114
Does nothing if file opened for read-only (returns
1116
----------------------------------------------------------------------*/
1117
int f; /* IN: The file control block */
1120
if (uget(f)) /* Bad unit number... */
1123
/* Check if Write is Allowed */
1125
if ((fcb->access & 3) == READ)
1131
long osufseek (f, offset, mode)
1132
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1133
.PURPOSE File seek (Move the tape, i.e. find tape-marks).
1134
Identical to osubseek for disks.
1135
.RETURNS New file number
1136
.REMARKS On return, the tape is always positioned at a
1137
file beginning. The tape move is always stopped
1138
when two consecutive tape-marks are encountered.
1139
----------------------------------------------------------------------*/
1140
int f; /* IN: Unit Number */
1141
long offset; /* IN : Offset for displacement */
1142
int mode; /* IN : mode of addressing */
1146
int fileno, blockno;
1148
if (uget(f)) /* Bad unit number... */
1152
** Perform necessary checks. Can't move tape after write...
1155
if (fcb->access & FCB_TM)
1156
{ if (fcb->last_op == U_WRITE) {
1157
oserror = -1, oserrmsg = "Can't move after write";
1167
if (n > 0) { oserror = ESPIPE; return(-1); }
1169
if (fcb->last_op == U_WEOF) { /* I just wrote a TM */
1170
if ( (n == 0) && (fcb->tape_marks == 1)) break;
1171
while ((fcb->tape_marks < 2) && (oserror == 0))
1174
ioinfo(fcb->pfd,&stbuf,&fileno,&blockno);
1175
if ( (n == 0) && (fcb->access & FCB_AM) && (blockno != -1) )
1177
/* Use fast EOM function if we know where we are */
1178
/* If ioeom ERROR, drops the FCB_AM flag */
1179
if ( ioeom(fcb->pfd) == 0) {
1180
ioinfo(fcb->pfd, &stbuf,&fcb->file_no,
1183
fcb->tape_marks = 0;
1184
fcb->ignore &= ~FCB_NOCOUNT;
1185
if (fcb->file_no == 0) rewind();
1186
else fcb->file_no -= 1,
1187
fcb->tape_marks = 1;
1190
else { fcb->access &= ~FCB_AM; oserror = 0; }
1192
while ((fcb->tape_marks < 2) && (oserror == 0))
1193
tmove(); /* Find EOTape */
1194
if ( (n == 0) && (fcb->access & FCB_AM) ) {
1195
/* Use fast EOM function. We know now where EOM is */
1196
iobsf(fcb->pfd,1); /* Move backward */
1197
if (ioeom(fcb->pfd) == 0)
1198
fcb->tape_marks = 1;
1199
else { fcb->access &= ~FCB_AM; oserror = 0; }
1202
n += fcb->file_no + 1;
1203
/* n is now Absolute File Number where to go */
1205
/* When I'm beyond the allowed number of TM indicating the
1206
end of the tape, it's better to rewind.
1208
if ((n <= 0) || (fcb->tape_marks > 1)) {
1209
if (fcb->last_op == U_WEOF) /* I just wrote a TM */
1214
n -= (fcb->file_no + fcb->tape_marks); /* Relative */
1215
/* n is now Relative File */
1217
an = n + fcb->file_no + fcb->tape_marks; /* Absolute File */
1219
if (fcb->last_op == U_WEOF) /* I just wrote a TM */
1224
if ( (n == 0) && (fcb->tape_marks)) /* I'm on a file beginning*/
1226
if (fcb->last_op == U_WEOF) /* I just wrote a TM */
1228
if (n <= 0) { /* Move -n-1 backwards, 1 time forwards */
1229
if (fcb->access & FCB_BW) {
1230
while ((n++ <= 0) && (oserror == 0))
1233
n = 0; /* We're OK */
1235
else { /* First Rewind, then Move Forw. */
1236
n = an; /* Where to go */
1240
/* Move n tape-marks forwards */
1241
while ((--n >=0) && (oserror==0) && (fcb->tape_marks <=1))
1246
oserrmsg = "Bad open mode";
1250
fn = fcb->file_no + fcb->tape_marks;
1252
return(oserror ? -1 : fn);
1256
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1257
.PURPOSE Compute current file number
1258
.RETURNS Current file number
1259
----------------------------------------------------------------------*/
1260
int f; /* IN: Unit Number */
1264
if (uget(f)) /* Bad unit number... */
1267
fn = fcb->file_no + fcb->tape_marks;
1273
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1274
.PURPOSE Compute position in feet/1000
1275
.RETURNS Current position / -1 if unknown
1277
----------------------------------------------------------------------*/
1278
int f; /* IN: Unit Number */
1282
if (uget(f)) /* Bad unit number... */
1285
ft = (fcb->ignore & FCB_NOFEET ? -1 : fcb->feet);
1290
long osubseek (f, offset, mode)
1291
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1292
.PURPOSE Block seek: Skip blocks on tape, skip sectors on
1294
.RETURNS New block number / -1 if error or unknown block number.
1295
.REMARKS Seek is stopped by a tape-mark, BUT the tape-mark is skipped.
1296
Disk: Simply set the position.
1297
----------------------------------------------------------------------*/
1298
int f; /* IN: Unit Number */
1299
long offset; /* IN : Offset for displacement */
1300
int mode; /* IN : mode of addressing */
1302
register long n, bn;
1305
if (uget(f)) /* Bad unit number... */
1311
if (fcb->access & FCB_DA) /* Disk Seek */
1314
{ case FILE_CURRENT: n += fcb->block_no;
1315
case FILE_START: break;
1316
case FILE_END: n = fcb->usize + n;
1320
if ((n < 0) || (n >= fcb->usize)) oserror = ESPIPE, bn = -1;
1321
else bn = fcb->block_no;
1327
/* Perform necessary checks. Write tape marks if previous operation
1328
** was write or fclose.
1331
if (fcb->last_op == U_WRITE) {
1332
oserror = -1, oserrmsg = "Can't move after write";
1336
if (fcb->last_op == U_WEOF) if (tfclose() < 0) return(-1);
1345
** Method: Move forwards, then backwards, then skip
1347
while ((fcb->tape_marks == 0) && (oserror == 0)) tmove();
1352
** If we don't know where we are, better to go to beginning
1355
if (fcb->ignore & FCB_NOCOUNT) osufseek(f, 0, FILE_CURRENT);
1356
else n -= fcb->block_no; /* Relative */
1360
bn = (fcb->tape_marks ? 0 : /* We are here */
1361
(fcb->ignore & FCB_NOCOUNT ? -1 : fcb->block_no));
1369
** I just passed over a tape mark.
1370
** If Move forward, do it.
1371
** Else move only 1 block!
1373
if (fcb->tape_marks) {
1376
fcb->ignore |= FCB_NOFEET;
1380
fcb->ignore |= FCB_NOCOUNT;
1383
else fcb->ignore |= FCB_NOFEET;
1386
st = iobsr(fcb->pfd,-n), fcb->last_op = U_BMB;
1389
st = iofsr(fcb->pfd,n), fcb->last_op = U_BMF;
1391
if (oserror) return(-1);
1394
** Tape-mark was encountered
1398
if (fcb->tape_marks) (fcb->tape_marks)--;
1399
else if (--(fcb->file_no) < 0) newfile();
1401
else fcb->tape_marks += 1;
1404
if (n > 0) fcb->block_no += bn;
1405
else fcb->block_no -= bn;
1407
bn = (fcb->tape_marks ? 0 : /* We are here */
1408
(fcb->ignore & FCB_NOCOUNT ? -1 : fcb->block_no));
1414
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1415
.PURPOSE Compute current block / sector number
1416
.RETURNS Current block number (in current file)
1418
----------------------------------------------------------------------*/
1419
int f; /* IN: Unit Number */
1423
if (uget(f)) /* Bad unit number... */
1426
bn = (fcb->tape_marks ? 0 : /* We are here */
1427
(fcb->ignore & FCB_NOCOUNT ? -1 : fcb->block_no));