~ubuntu-branches/debian/jessie/eso-midas/jessie

« back to all changes in this revision

Viewing changes to libsrc/os/vms/osu.c

  • Committer: Package Import Robot
  • Author(s): Ole Streicher
  • Date: 2014-04-22 14:44:58 UTC
  • Revision ID: package-import@ubuntu.com-20140422144458-okiwi1assxkkiz39
Tags: upstream-13.09pl1.2+dfsg
ImportĀ upstreamĀ versionĀ 13.09pl1.2+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* @(#)osu.c    19.1 (ES0-DMD) 02/25/03 13:56:14 */
 
2
/*===========================================================================
 
3
  Copyright (C) 1995 European Southern Observatory (ESO)
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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, 
 
18
  MA 02139, USA.
 
19
 
 
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 
 
26
                        GERMANY
 
27
===========================================================================*/
 
28
 
 
29
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
30
.TYPE           Module
 
31
.NAME           osu
 
32
.LANGUAGE       C
 
33
.AUTHOR         Francois Ochsenbein [ESO]
 
34
.CATEGORY       Interface to i/o on devices like tapes / OD / etc
 
35
.ENVIRONMENT    VAX / VMS or Unix
 
36
.COMMENTS       
 
37
        The functions of this module perform basic i/o to/from magnetic tape
 
38
        and optical disks 
 
39
        on VAX/VMS environment. The maximum number of available special
 
40
        units is assumed to be MAXDEV (defined here)
 
41
\begin{TeX}
 
42
\\
 
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
 
46
        address...
 
47
 
 
48
{\bf Restrictions}: read/write on (optical) disks is limited to
 
49
        multiple of sectors.
 
50
 
 
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:
 
58
\begin{itemize}
 
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.
 
67
 
 
68
\end{itemize}
 
69
 
 
70
\end{TeX}
 
71
.VERSION        1.0     10-Mar-1986: Creation
 
72
.VERSION        1.1     21-Mar-1986 : Modified io1 and io2 for direct-access
 
73
                devices.
 
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)
 
96
 
 
97
-----------------------------------------------------------------------------*/
 
98
 
 
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... */
 
104
#include <errno.h>
 
105
#include <computer.h>
 
106
#include <atype.h>
 
107
 
 
108
typedef int (*FCT)();
 
109
#include <osdefos.h>
 
110
MID_EXTERN int oserror;
 
111
MID_EXTERN char *oserrmsg;
 
112
 
 
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
 
116
 
 
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                 */
 
123
 
 
124
        /* Definition of Functions */
 
125
 
 
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)       
 
140
 
 
141
 
 
142
        /* This structure, created for each device, allows to know
 
143
                the current position on any device
 
144
         */
 
145
typedef int (*FCT_PTR)();               /* Pointer to function */
 
146
 
 
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 */
 
173
     } FCB;
 
174
 
 
175
#define tgap            (fcb->density == 6250? (1500/12) : (3000/12))   \
 
176
                        /* Gap on tape due to the Tape-Mark     */
 
177
 
 
178
#define BADCLASSmsg     "Class of Device unknown:"
 
179
 
 
180
static FCB *Units[MAXDEV] = {0,0,0,0};
 
181
static FCB *fcb;
 
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           */
 
185
static struct {
 
186
        char msg[sizeof(BADCLASSmsg)];
 
187
        char klass[20];
 
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 */
 
192
 
 
193
long osufseek();
 
194
 
 
195
/*=====================================================================
 
196
                Internal Routines
 
197
*=====================================================================*/
 
198
 
 
199
static int osuerror(op)
 
200
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
201
.PURPOSE Set Error Message
 
202
.RETURNS -1
 
203
----------------------------------------------------------------------*/
 
204
int op; /* IN: The operation to execute */
 
205
{
 
206
        static char msg[60] = "Function not available: ";
 
207
        register char *pm, *pl;
 
208
        static  char *text[] = {
 
209
                /* U_INFO  */ "info",
 
210
                /* U_OPEN  */ "open",
 
211
                /* U_CLOSE */ "close",
 
212
                /* U_READ  */ "read",
 
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"
 
223
        };
 
224
 
 
225
  oserror = -1;
 
226
  oserrmsg = msg;
 
227
  pm = &msg[24];
 
228
 
 
229
        /* Append the signification of the function */
 
230
  for(pl = text[op]; *pl; pl++)         *(pm++) = *pl;
 
231
  *pm = '\0';
 
232
 
 
233
  return(-1);
 
234
}
 
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));}
 
250
 
 
251
static FCT err_fct[1+U_MAX] = {
 
252
        err0, err1, err2, err3, err4, err5, err6, err7, err8, err9,
 
253
        err10, err11, err12, err13};
 
254
 
 
255
static int uget(f)
 
256
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
257
.PURPOSE Retrieve the FCB structure
 
258
.RETURNS 0 (success) / -1 (failure)
 
259
.REMARKS 
 
260
----------------------------------------------------------------------*/
 
261
int f;          /* IN: Unit number      */
 
262
{
 
263
 
 
264
        oserrmsg = NULL_PTR(char);
 
265
        oserror  = 0;
 
266
        fcb      = NULL_PTR(FCB);
 
267
  
 
268
        if ((f >= START_DEV) && (f <= ncb))
 
269
                fcb = Units[f-START_DEV];
 
270
 
 
271
        if (fcb == NULL_PTR(FCB)) {
 
272
                oserror = -1;
 
273
                oserrmsg = "Bad Unit Number";
 
274
                }
 
275
 
 
276
        return(oserror);
 
277
}
 
278
 
 
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)        */
 
286
{
 
287
        register long ctrl, dblk;
 
288
 
 
289
        dblk = blk*1000; 
 
290
 
 
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);
 
298
        }
 
299
}
 
300
 
 
301
static int newfile()
 
302
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
303
.PURPOSE Update fcb information when a new file starts
 
304
.RETURNS 0
 
305
.REMARKS For disks, should be called only at open...
 
306
----------------------------------------------------------------------*/
 
307
{
 
308
        fcb->ignore   &= ~(FCB_NOCOUNT); /* count number is correct     */
 
309
 
 
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                   */
 
315
                }
 
316
        else    {                       /* Increment the file counter   */
 
317
                fcb->file_no += fcb->tape_marks; 
 
318
                fcb->feet += fcb->tape_marks * tgap;
 
319
                }
 
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            */
 
324
 
 
325
        return(0);
 
326
}
 
327
 
 
328
static int newpos(bytes)
 
329
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
330
.PURPOSE Computes the new position on the device
 
331
.RETURNS 0
 
332
.REMARKS        
 
333
----------------------------------------------------------------------*/
 
334
int bytes;              /* IN: number of bytes read/ written    */
 
335
{
 
336
        if (fcb->tape_marks)    newfile();
 
337
 
 
338
        if (fcb->access & FCB_DA)       /* Direct Access */
 
339
        {       fcb->block_no   += (bytes/fcb->sectorsize);
 
340
                if (bytes%fcb->sectorsize)      fcb->block_no += 1;
 
341
        }
 
342
        else    if (fcb->access & FCB_TM)
 
343
        {       fcb->feet += tfeet(bytes);
 
344
                (fcb->block_no)++;
 
345
        }
 
346
 
 
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;
 
350
 
 
351
        return(0);
 
352
}
 
353
 
 
354
static int rewind ()
 
355
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
356
.PURPOSE Rewind the tape
 
357
.RETURNS 0 (success) / -1 (failure)
 
358
.REMARKS fcb updated.
 
359
----------------------------------------------------------------------*/
 
360
{
 
361
        iorew(fcb->pfd);
 
362
        if (oserror)    return(-1);
 
363
 
 
364
        fcb->last_op = U_REWIND;
 
365
        fcb->file_no = -1;
 
366
        newfile();
 
367
        return(0);
 
368
}
 
369
 
 
370
static int tfclose()
 
371
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
372
.PURPOSE Write EOF (Single TM)
 
373
.RETURNS 0 (success) / -1 (failure)
 
374
.REMARKS
 
375
----------------------------------------------------------------------*/
 
376
{
 
377
    if (oserror == 0)
 
378
        ioweof(fcb->pfd);
 
379
 
 
380
    if (oserror == 0)
 
381
        (fcb->tape_marks)++, fcb->last_op = U_WEOF;
 
382
    
 
383
    return(oserror ? -1 : 0);
 
384
}
 
385
 
 
386
static int tmove()
 
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
----------------------------------------------------------------------*/
 
392
{
 
393
        register int l, lbuf;
 
394
 
 
395
        char test_buffer[BUFTEST];
 
396
 
 
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;
 
404
                if (l == 0) { 
 
405
                        (fcb->tape_marks)++; 
 
406
                        return(0); 
 
407
                        }
 
408
                newfile();      /* Tape_marks reset to zero */
 
409
                }
 
410
 
 
411
        oserror = 0;
 
412
        if (iofsf(fcb->pfd, 1) == -1)           return(-1);
 
413
 
 
414
        fcb->ignore |= (FCB_NOFEET|FCB_NOCOUNT);
 
415
 
 
416
        fcb->last_op = U_FMF;
 
417
        fcb->tape_marks = 1;
 
418
        return(0);
 
419
}
 
420
 
 
421
static int bmove()
 
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
----------------------------------------------------------------------*/
 
427
{
 
428
        if (fcb->tape_marks)    
 
429
                fcb->tape_marks -= 1;
 
430
        else    {
 
431
                fcb->file_no -= 1;
 
432
                fcb->ignore |= (FCB_NOCOUNT|FCB_NOFEET);
 
433
                }
 
434
  
 
435
        if (fcb->file_no < 0)   
 
436
                rewind(); 
 
437
        else    
 
438
                iobsf(fcb->pfd,1), fcb->last_op = U_FMB;
 
439
 
 
440
        return(oserror ? -1 : 0);
 
441
}
 
442
 
 
443
static struct iolist *findclass(aclass)
 
444
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
445
.PURPOSE Retrieve the class name
 
446
.RETURNS Pointer to found class / NULL
 
447
.REMARKS 
 
448
----------------------------------------------------------------------*/
 
449
        char    *aclass;        /* IN: Class to look for */
 
450
{
 
451
        struct iolist *plist, *iodev();
 
452
        struct iolist *(*def)();
 
453
        char    *p, *q;
 
454
        
 
455
        /* Follow the linked list of iolist's */
 
456
 
 
457
   if (++findclass_loop > MAX_findclass)
 
458
        return (NULL_PTR(struct iolist));
 
459
 
 
460
   for (def = iodev; def; def = plist->next)
 
461
   {
 
462
        plist = (*def)();
 
463
        for(q=aclass, p=plist->klass; (*p == *q) && (*p); p++, q++) ;
 
464
        if ((*q == '\0') && (*p == '\0'))       break;
 
465
   }
 
466
   if (!def)    /* Class Not Found */
 
467
        plist = NULL_PTR(struct iolist);
 
468
   
 
469
   return(plist);
 
470
}
 
471
 
 
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
----------------------------------------------------------------------*/
 
478
{
 
479
        struct  iolist *plist;
 
480
        int     i;
 
481
        OPITEM  *pop;
 
482
        
 
483
   findclass_loop = 0;
 
484
 
 
485
   plist = findclass(theclass.klass);
 
486
   if (!plist)  {
 
487
        oserror = -1, oserrmsg = (char *)&theclass;
 
488
        theclass.msg[sizeof(theclass.msg)-1] = ' ';
 
489
        return(-1);
 
490
   }
 
491
 
 
492
   fcb->klass = plist->klass;
 
493
 
 
494
   /*
 
495
   ** We have just to insert the functions in the list
 
496
   */
 
497
 
 
498
   for (pop = plist->oplist, i = plist->nop; --i >= 0; pop++)
 
499
        fcb->ops[pop->opid] = pop->opf;
 
500
   
 
501
   return(0);
 
502
}
 
503
 
 
504
static int scandev(fd, dev)
 
505
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
506
.PURPOSE Get Capabilities in opened DEVCAPFILE
 
507
.RETURNS 0  / -1
 
508
.REMARKS Recursive call if `dc=' is found.
 
509
----------------------------------------------------------------------*/
 
510
        int     fd;     /* IN: DEVCAPFILE file descriptor */
 
511
        char    *dev;   /* IN: Device name */
 
512
{
 
513
        int     i;
 
514
        char    buf[133];       /* One line of DEVCAPFILE */
 
515
        char    *p, *q;
 
516
 
 
517
        /* Be sure dev is terminated with Null */
 
518
 
 
519
  for (p = dev; isgraph(*p); p++)       ;
 
520
  *p = '\0';
 
521
 
 
522
  osaseek(fd, 0L, FILE_START);
 
523
  while (osaread(fd, buf, sizeof(buf)) >= 0)
 
524
  {
 
525
        if (buf[0] == '#')      continue;
 
526
        for (p = buf, q = dev; *q && (*p == *q); p++, q++)      ;
 
527
        if(*q == '\0')          goto found_dev;
 
528
  }
 
529
  return(-1); 
 
530
 
 
531
 
 
532
  found_dev:
 
533
        /* Here when device is found. Get interesting items, i.e.
 
534
         * bs= blocksize
 
535
         * us= unit size 
 
536
         * ss= sector size 
 
537
         * ds= density
 
538
         * cl= class_name
 
539
         * dc= Synonym
 
540
         */
 
541
  while(*p)
 
542
  {     
 
543
        while (isspace(*p))     p++;    /* Skip blanks  */
 
544
        if(!*p) continue;               /* Empty line   */
 
545
 
 
546
        if (*p == '\\')         /* There is a continuation. Read Next record */
 
547
        {
 
548
                next_record:
 
549
                if (osaread(fd, buf, sizeof(buf)) < 0)  buf[0] = '\0';
 
550
                if (buf[0] == '#')      /* It's a comment */
 
551
                        goto next_record;       
 
552
                p = buf;
 
553
                if (isspace(buf[0]))    continue;
 
554
                goto terminated;
 
555
        }
 
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';
 
577
                }
 
578
        while (isgraph(*p))     p++;            /* Look for space */
 
579
  }
 
580
 
 
581
  terminated:
 
582
  return(0);
 
583
}
 
584
 
 
585
static int getdev(dev)
 
586
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
587
.PURPOSE Get Capabilities from DEVCAPFILE.
 
588
.RETURNS 0 / -1
 
589
.REMARKS Relevant Cap's are used to update the current fcb
 
590
----------------------------------------------------------------------*/
 
591
        char    *dev;   /* IN: Device name */
 
592
{
 
593
        char    *devcapfile;    /* DEVCAPFILE name */
 
594
        int     fd;
 
595
        char    *oshenv();
 
596
 
 
597
        /* Check if a DEVCAPFILE does exist     */
 
598
 
 
599
  devcapfile = oshenv("DEVCAPFILE", NULL_PTR(char));
 
600
  if(!devcapfile){ 
 
601
        oserror = -1; oserrmsg = "DEVCAPFILE is unknown...";
 
602
        return(-1);
 
603
  }
 
604
  
 
605
        /* It does. Open in read_only mode      */
 
606
 
 
607
  fd = osaopen(devcapfile, READ);
 
608
  if (fd < 0){
 
609
        oserror = -1; oserrmsg = "Entry unknown in DEVCAPFILE";
 
610
        return(-1);
 
611
  }
 
612
  
 
613
        /* Scan the file for the device name, expand dc= references */
 
614
         
 
615
  if (scandev(fd, dev) < 0) {
 
616
        oserror = -1; oserrmsg = "Entry unknown in DEVCAPFILE";
 
617
        return(-1);
 
618
  }
 
619
 
 
620
        /* Finally Close DEVCAPFILE     */
 
621
 
 
622
  osaclose(fd);
 
623
  return(0);
 
624
}
 
625
 
 
626
/*=====================================================================
 
627
                Callable Routines
 
628
 *=====================================================================*/
 
629
 
 
630
int osugrep (class_name, item)
 
631
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
632
.PURPOSE Get the item function in a class of devices
 
633
.RETURNS 0 / -1
 
634
----------------------------------------------------------------------*/
 
635
        char    *class_name;    /* IN: Class of Devices (NULL for any) */
 
636
        OPITEM  *item;          /* OUT: op_code + Function Pointer */
 
637
 
638
        struct iolist *plist, *iodev();
 
639
        struct iolist *(*def)();
 
640
        int     i;
 
641
        OPITEM  *pop;
 
642
        
 
643
                        
 
644
   for (def = iodev; def; def = plist->next)
 
645
   {
 
646
        if (!class_name)        /* Class not specified: look to next one */
 
647
                plist = (*def)();
 
648
        else    plist = findclass(class_name);
 
649
        if (!plist)             return(-1);
 
650
 
 
651
                /* Retrieve the item in list */
 
652
        
 
653
        for (pop = plist->oplist, i = plist->nop; 
 
654
                (--i >= 0) && (pop->opid != item->opid);  pop++)  ;
 
655
 
 
656
        if (i >= 0)             /* I found the relevant item... */
 
657
        {       item->opf = pop->opf;
 
658
                return(0);
 
659
        }
 
660
        if (class_name)         break;
 
661
        
 
662
   }
 
663
   return(-1);
 
664
}
 
665
 
 
666
char *osuname(f)
 
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  */
 
672
 
673
    if (f != -1)
 
674
        if (uget(f))            
 
675
                return((char *)0);      /* Bad unit number...   */
 
676
 
 
677
    return(fcb ? fcb->name : NULL_PTR(char));
 
678
}
 
679
 
 
680
int osumode(f)
 
681
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
682
.PURPOSE Retrieve opening mode
 
683
.RETURNS Mode / -1 when error
 
684
----------------------------------------------------------------------*/
 
685
        int f;          /* IN: The unit number  */
 
686
 
687
    if (f != -1)
 
688
        if (uget(f))            
 
689
                return(-1);     /* Bad unit number...   */
 
690
 
 
691
    return(fcb ? fcb->access & 3 : -1);
 
692
}
 
693
 
 
694
int osubsize(f)
 
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  */
 
700
 
701
    if (f != -1)
 
702
        if (uget(f))            
 
703
                return(-1);     /* Bad unit number...   */
 
704
 
 
705
    return(fcb ? fcb->blocksize : -1);
 
706
}
 
707
int osustatus(f, stat)
 
708
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
709
.PURPOSE Get the status of the device
 
710
.RETURNS 0 / -1
 
711
----------------------------------------------------------------------*/
 
712
int f;                  /* IN: The unit number  */
 
713
struct devstat *stat;   /* OUT: Filled with known info */
 
714
 
715
  if (uget(f))          
 
716
        return(-1);     /* Bad unit number...   */
 
717
 
 
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;
 
730
 
 
731
  return(0);
 
732
}
 
733
 
 
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
 
745
         two file marks.
 
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 */
 
750
{
 
751
        register int l, i;
 
752
        register char *p, *q;
 
753
        char    *devname, isnulldev;
 
754
 
 
755
        /* Convert NULL device name if necessary */
 
756
        devname = device;
 
757
        if (!devname)   devname = "";
 
758
        isnulldev = !*devname;          /* Is zero for NULL device */
 
759
        if (isnulldev)  devname = NULL_DEV;
 
760
 
 
761
        oserror = 0;
 
762
        oserrmsg = NULL_PTR(char);
 
763
        fcb = NULL_PTR(FCB);
 
764
        hasam  = 2;             /* Unknown Parameter */
 
765
        hasbw  = 2;             /* Unknown Parameter */
 
766
 
 
767
 
 
768
        /* Check if there are not too many devices      */
 
769
 
 
770
        for (i = 0; i < MAXDEV; i++)  
 
771
                if (!Units[i])  break;
 
772
 
 
773
        if (i >= MAXDEV) {      
 
774
                oserror = -1;
 
775
                oserrmsg = "Too many opened osu Units" ;
 
776
                return(-1);
 
777
                }
 
778
 
 
779
        /* Allocate FCB, and Try to guess the device class from name:
 
780
                if device name contrains a D, assume "disk" class
 
781
         */
 
782
  
 
783
        l = strlen(devname);
 
784
        fcb = (FCB *)osmmget(sizeof(FCB) + l + 2); 
 
785
                                                /* Note: 2 for EOS and ':' */
 
786
        if (!fcb)       
 
787
                return(-1);
 
788
 
 
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))
 
794
                        p = "disk";
 
795
                else    p = "mt";
 
796
        }
 
797
        oscopy(theclass.klass, p, 1+strlen(p));
 
798
 
 
799
        /* Initialize the structure, and copy device name */
 
800
 
 
801
        fcb->name         = (char *)(fcb+1);
 
802
        fcb->access       = mode;
 
803
        fcb->ignore       = FCB_NOFEET;
 
804
        fcb->eotm         = 0;
 
805
        fcb->feet         = 0;
 
806
        fcb->usize        = 0;
 
807
        fcb->tape_marks   = 0;
 
808
        fcb->block_max    = 0;          /* Maximum blocksize            */
 
809
        fcb->block_min    = 0;          /* Minimum blocksize            */
 
810
        fcb->blocksize    = 0;
 
811
        fcb->sectorsize   = 0;
 
812
        fcb->density      = den;
 
813
        fcb->file_no      = -1;
 
814
        for (l = 0; l < sizeof(fcb->ops)/sizeof(fcb->ops[0]); l++)
 
815
                fcb->ops[l] = err_fct[l];
 
816
 
 
817
                /* Fill fcb with Info from DEVCAPFILE */
 
818
        l = getdev(devname);
 
819
 
 
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 */
 
825
 
 
826
        for (p = devname; (*p) && (*p != '!'); p++)     ;
 
827
        if (*p == '!')  { if (l < 0) goto error_found; p++;}
 
828
        else            p = devname;
 
829
        for (q = fcb->name; *p; p++, q++)       *q = *p;
 
830
        *q = '\0';
 
831
        oserror = 0;            /* Clear error from getdev      */
 
832
 
 
833
        if (fcb->eotm == 0)     /* Default = 2 TM               */
 
834
                fcb->eotm = 2;
 
835
        if (hasam == 2)
 
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... */
 
841
 
 
842
                /* Find to which Class the Device belongs to.  */
 
843
 
 
844
        if (getclass() < 0)     goto error_found;
 
845
 
 
846
                /* Open the device. DON'T REWIND ! */
 
847
 
 
848
        fcb->pfd = ioopen(fcb->name, 
 
849
                ((mode == WRITE) ? READ_WRITE : mode), 
 
850
                fcb->density);
 
851
        if (oserror) goto error_found;
 
852
 
 
853
        Units[i] = fcb;
 
854
        i += START_DEV;         /* Actual returned unit number  */
 
855
        if (i >= ncb)   ncb = i;
 
856
        fcb->last_op = U_OPEN;          /* Last Operation */
 
857
 
 
858
                /* Get Other Info about Device */
 
859
        
 
860
        ioinfo(fcb->pfd, &stbuf, &fcb->file_no, &fcb->block_no);
 
861
        if (isnulldev)  oserror = 0;    /* This can't be a problem      */
 
862
 
 
863
                /* Fill the missing items with final info */
 
864
 
 
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;
 
869
        
 
870
                /* Take defaults for DA devices */
 
871
        if (stbuf.isda)
 
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;
 
884
        }
 
885
        if (fcb->usize == 0)    fcb->usize = stbuf.usize;
 
886
        if (stbuf.istm)         fcb->access |= FCB_TM;
 
887
 
 
888
        /*
 
889
         * If the system doesn't know the position,
 
890
         * rewind anyway.
 
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.
 
893
        */
 
894
 
 
895
        if (fcb->file_no < 0)   {
 
896
                iorew(fcb->pfd);
 
897
                newfile();
 
898
        }
 
899
 
 
900
        if (fcb->file_no > 0 && fcb->eotm > 1 ) {
 
901
                bmove();
 
902
                bmove();
 
903
        }
 
904
 
 
905
                /* Position to EOF if Append    */
 
906
 
 
907
        fcb->last_op = U_OPEN;          /* Last Operation */
 
908
        if ((mode&3) == APPEND) osufseek(i, 0, FILE_END);
 
909
 
 
910
        if (oserror) {
 
911
                Units[i-START_DEV] = NULL_PTR(FCB);
 
912
                goto error_found;
 
913
                }
 
914
        return(i);
 
915
 
 
916
  error_found:
 
917
        osmmfree(fcb);
 
918
        return(-1);
 
919
}
 
920
 
 
921
int osuclose (f, option)
 
922
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
923
.PURPOSE        Close (dismount) a tape / optical disk
 
924
.RETURNS        0 / -1
 
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 */
 
929
{
 
930
        if (uget(f)) 
 
931
                return(-1);     /* Bad unit number...   */
 
932
  
 
933
        /* Perform necessary checks. Write tape marks is previous operation
 
934
        ** was write or fclose.
 
935
        */
 
936
 
 
937
        if (fcb->access & FCB_DA) ;
 
938
        else    {
 
939
                if (fcb->last_op == U_WRITE)    tfclose();
 
940
                if ((fcb->last_op == U_WEOF) && (fcb->tape_marks < fcb->eotm))
 
941
                        tfclose();
 
942
        }
 
943
 
 
944
        if(oserror)             return(-1);
 
945
 
 
946
        if (ioclose(fcb->pfd, (option == 1 ? OPU_DISMOUNT : 0)))
 
947
                return(-1);
 
948
 
 
949
        osmmfree(fcb);
 
950
        Units[f-START_DEV] = NULL_PTR(FCB);
 
951
 
 
952
        return(0);
 
953
}
 
954
 
 
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
 
961
         optical disks.
 
962
         The returned length may be zero for virgin sectors.
 
963
.REMARKS Reading consecutive file marks, it is posible to go further 
 
964
         than two file marks.
 
965
----------------------------------------------------------------------*/
 
966
int     f;              /* IN: The file control block   */
 
967
char    *buffer;        /* OUT: The buffer                      */
 
968
int     length;         /* IN: The length of the buffer */
 
969
 
970
        register int l;
 
971
 
 
972
        /* Check Buffer Length  */
 
973
 
 
974
        if (length < sizeof(long)) {
 
975
                oserror = -1;
 
976
                oserrmsg = "Too small buffer";
 
977
                }
 
978
 
 
979
        if (uget(f))            /* Bad unit number...   */
 
980
                return(-1);
 
981
 
 
982
        /*
 
983
        ** If device was opened in only_write mode, return error
 
984
        ** if trying to read something
 
985
        */
 
986
 
 
987
        if ((fcb->access & 3) == WRITE) {
 
988
                oserror=EACCES;
 
989
                return(-1);
 
990
                }
 
991
        /*
 
992
        ** Check if some required blocksize MUST be used.
 
993
        */
 
994
 
 
995
        if (length%fcb->blocksize)      
 
996
        {       oserror = -1, oserrmsg = "Length not a multiple of Blocksize";
 
997
                return(-1);
 
998
        }
 
999
 
 
1000
        /*
 
1001
        **      For Tapes, check for illegal read
 
1002
        */
 
1003
        
 
1004
        if (fcb->access & FCB_TM)
 
1005
        {       if ((fcb->last_op == U_WRITE) || (fcb->last_op == U_WEOF))
 
1006
                {       oserror = -1;
 
1007
                        oserrmsg = "Can't read after write";
 
1008
                        return(-1);
 
1009
                }
 
1010
        }
 
1011
        
 
1012
        /*
 
1013
        ** For Direct-Access devices, use iosread (0 means "virgin sector")
 
1014
        ** For Tapes, use ioread                  (0 means "tape-mark"    )
 
1015
        */
 
1016
        if (fcb->access & FCB_DA)
 
1017
                l = iosread(fcb->pfd, fcb->block_no, fcb->sectorsize,
 
1018
                        buffer, length);
 
1019
        else    {
 
1020
                l = ioread(fcb->pfd,buffer,length);
 
1021
                if (l == 0)     fcb->tape_marks++;
 
1022
        }
 
1023
 
 
1024
        /* Check special case oserror = -2, means TOO SHORT BUFFER */
 
1025
        if (oserror == -2) {
 
1026
                oserror = -1;
 
1027
                oserrmsg = "Too short buffer";
 
1028
                fcb->ignore  |= FCB_NOFEET;
 
1029
                newpos(length);
 
1030
        }
 
1031
 
 
1032
        if (oserror)
 
1033
                return(-1);
 
1034
        fcb->last_op = U_READ;
 
1035
 
 
1036
        if (l > 0)              /* Something was read, update fcb contents */
 
1037
                newpos(l);
 
1038
 
 
1039
        return(l);
 
1040
}
 
1041
 
 
1042
int osuwrite (f, buffer, length)
 
1043
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
1044
.PURPOSE Write a block on magnetic tape / optical disk.
 
1045
.RETURNS Length written / -1 (error)
 
1046
.REMARKS 
 
1047
----------------------------------------------------------------------*/
 
1048
int     f;              /* IN: The file control block   */
 
1049
char    *buffer;        /* IN: The buffer               */
 
1050
int     length;         /* IN: The length of the buffer */
 
1051
 
1052
        register int l;
 
1053
 
 
1054
        /* Check Buffer Length  */
 
1055
 
 
1056
        if ((length <= 0) || (length > IO_MAX)) {
 
1057
                oserror = -1; 
 
1058
                oserrmsg = "Bad buffer size";
 
1059
                return(-1);
 
1060
                }
 
1061
 
 
1062
        if (uget(f))            /* Bad unit number...   */
 
1063
                return(-1);
 
1064
  
 
1065
        /* Check if Write is Allowed */
 
1066
 
 
1067
        if ((fcb->access & 3) == READ) { 
 
1068
                oserror = EACCES; 
 
1069
                return(-1); 
 
1070
                }
 
1071
 
 
1072
        /*
 
1073
        ** Check if some required blocksize MUST be used.
 
1074
        */
 
1075
 
 
1076
        if (length%fcb->blocksize)      
 
1077
        {       oserror = -1, oserrmsg = "Length not a multiple of Blocksize";
 
1078
                return(-1);
 
1079
        }
 
1080
 
 
1081
        /*
 
1082
        **      For Tapes, check if 2 TM were previously written; 
 
1083
        **           if yes, the data will not be accessible... 
 
1084
        */
 
1085
        if (fcb->access & FCB_TM)
 
1086
        {       if (fcb->tape_marks >= 2) {
 
1087
                        oserror = -1, oserrmsg = "Attempt to write beyond EOF";
 
1088
                        return(-1); 
 
1089
                }
 
1090
        }
 
1091
        
 
1092
        /*
 
1093
        ** For Direct-Access devices, use ioswrite .
 
1094
        */
 
1095
        if (fcb->access & FCB_DA)
 
1096
                l = ioswrite(fcb->pfd, fcb->block_no, fcb->sectorsize,
 
1097
                        buffer, length);
 
1098
        else    l = iowrite(fcb->pfd,buffer,length);
 
1099
 
 
1100
        if (l == -1)
 
1101
                return(-1);
 
1102
 
 
1103
        if (l > 0)
 
1104
                newpos(l);
 
1105
        fcb->last_op = U_WRITE;
 
1106
        return(l);
 
1107
}
 
1108
 
 
1109
int osufclose (f)
 
1110
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
1111
.PURPOSE Close a File (Write a Tape-Mark on the tape)
 
1112
.RETURNS 0 / -1
 
1113
.REMARKS Tape mouvements are optimized.
 
1114
         Does nothing if file opened for read-only (returns
 
1115
         wihout error)
 
1116
----------------------------------------------------------------------*/
 
1117
int f;          /* IN: The file control block   */
 
1118
{
 
1119
 
 
1120
        if (uget(f))            /* Bad unit number...   */
 
1121
                return(-1);
 
1122
 
 
1123
        /* Check if Write is Allowed */
 
1124
 
 
1125
        if ((fcb->access & 3) == READ)
 
1126
                return(0);
 
1127
 
 
1128
        return(tfclose());
 
1129
}
 
1130
 
 
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 */
 
1143
{
 
1144
        register long fn;
 
1145
        register int n, an;
 
1146
        int fileno, blockno;
 
1147
 
 
1148
        if (uget(f))            /* Bad unit number...   */
 
1149
                return(-1);
 
1150
 
 
1151
        /* 
 
1152
        ** Perform necessary checks. Can't move tape after write...
 
1153
        */
 
1154
 
 
1155
        if (fcb->access & FCB_TM)
 
1156
        {       if (fcb->last_op == U_WRITE) {
 
1157
                        oserror = -1, oserrmsg = "Can't move after write";
 
1158
                        return(-1);
 
1159
                }
 
1160
        }
 
1161
                
 
1162
        n = offset;
 
1163
        fn = 0;
 
1164
 
 
1165
        switch(mode) { 
 
1166
          case FILE_END: 
 
1167
                if (n > 0) { oserror = ESPIPE;  return(-1);  }
 
1168
 
 
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))
 
1172
                        tfclose();
 
1173
                    }
 
1174
                ioinfo(fcb->pfd,&stbuf,&fileno,&blockno);
 
1175
                if ( (n == 0) && (fcb->access & FCB_AM) && (blockno != -1) )
 
1176
                        {
 
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,
 
1181
                                        &fcb->block_no);
 
1182
                                fcb->block_no = 0;
 
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;
 
1188
                                break;
 
1189
                        }
 
1190
                        else { fcb->access &= ~FCB_AM; oserror = 0; }
 
1191
                    }
 
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; }
 
1200
                        break;
 
1201
                        }
 
1202
                n += fcb->file_no + 1;  
 
1203
                        /* n is now Absolute File Number where to go    */
 
1204
          case FILE_START:
 
1205
                /* When I'm beyond the allowed number of TM indicating the
 
1206
                        end of the tape, it's better to rewind.
 
1207
                */
 
1208
                if ((n <= 0) || (fcb->tape_marks > 1)) { 
 
1209
                        if (fcb->last_op == U_WEOF)     /* I just wrote a TM */
 
1210
                                tfclose();
 
1211
                        rewind(); 
 
1212
                        if (n <= 0)     break; 
 
1213
                        }
 
1214
                n -= (fcb->file_no + fcb->tape_marks);  /* Relative */
 
1215
                        /* n is now Relative File */
 
1216
          case FILE_CURRENT:
 
1217
                an = n + fcb->file_no + fcb->tape_marks; /* Absolute File */
 
1218
                if (an <= 0) {
 
1219
                        if (fcb->last_op == U_WEOF)     /* I just wrote a TM */
 
1220
                                tfclose();
 
1221
                        rewind(); 
 
1222
                        break; 
 
1223
                        }
 
1224
                if ( (n == 0) && (fcb->tape_marks)) /* I'm on a file beginning*/
 
1225
                        break;
 
1226
                if (fcb->last_op == U_WEOF)     /* I just wrote a TM */
 
1227
                        n--, tfclose();
 
1228
                if (n <= 0) {   /* Move -n-1 backwards, 1 time forwards */
 
1229
                        if (fcb->access & FCB_BW) {
 
1230
                                while ((n++ <= 0) && (oserror == 0))    
 
1231
                                        bmove();
 
1232
                                tmove();
 
1233
                                n = 0;  /* We're OK */
 
1234
                                }
 
1235
                        else    {       /* First Rewind, then Move Forw. */
 
1236
                                n = an;         /* Where to go */
 
1237
                                rewind();
 
1238
                                }
 
1239
                        }
 
1240
                                /* Move n tape-marks forwards */
 
1241
                while ((--n >=0) && (oserror==0) && (fcb->tape_marks <=1))
 
1242
                        tmove();
 
1243
                break; 
 
1244
          default:
 
1245
                oserror = -1;
 
1246
                oserrmsg = "Bad open mode";
 
1247
                return(-1);
 
1248
        }
 
1249
 
 
1250
        fn = fcb->file_no + fcb->tape_marks;
 
1251
 
 
1252
        return(oserror ? -1 : fn);
 
1253
}
 
1254
 
 
1255
long osuftell (f)
 
1256
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
1257
.PURPOSE Compute current file number
 
1258
.RETURNS Current file number
 
1259
----------------------------------------------------------------------*/
 
1260
int     f;              /* IN: Unit Number      */
 
1261
{
 
1262
        register long fn;
 
1263
 
 
1264
        if (uget(f))            /* Bad unit number...   */
 
1265
                return(-1);
 
1266
 
 
1267
        fn = fcb->file_no + fcb->tape_marks;
 
1268
 
 
1269
        return(fn);
 
1270
}
 
1271
 
 
1272
long osufeet (f)
 
1273
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
1274
.PURPOSE Compute position in feet/1000
 
1275
.RETURNS Current position / -1 if unknown
 
1276
.REMARKS
 
1277
----------------------------------------------------------------------*/
 
1278
int     f;              /* IN: Unit Number      */
 
1279
{
 
1280
        long ft;
 
1281
 
 
1282
        if (uget(f))            /* Bad unit number...   */
 
1283
                return(-1);
 
1284
 
 
1285
        ft = (fcb->ignore & FCB_NOFEET ? -1 : fcb->feet);
 
1286
 
 
1287
        return(ft);
 
1288
}
 
1289
 
 
1290
long osubseek (f, offset, mode)
 
1291
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
1292
.PURPOSE Block seek: Skip blocks on tape, skip sectors on
 
1293
         optical disks.
 
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 */
 
1301
{
 
1302
        register long n, bn;
 
1303
        int st;
 
1304
 
 
1305
    if (uget(f))                /* Bad unit number...   */
 
1306
        return(-1);
 
1307
 
 
1308
    n = offset; 
 
1309
    bn = 0; 
 
1310
 
 
1311
    if (fcb->access & FCB_DA)   /* Disk Seek    */
 
1312
    {
 
1313
        switch(mode)
 
1314
        { case FILE_CURRENT:    n += fcb->block_no;
 
1315
          case FILE_START:      break;
 
1316
          case FILE_END:        n = fcb->usize + n;
 
1317
                                break;
 
1318
        }
 
1319
        fcb->block_no = n;
 
1320
        if ((n < 0) || (n >= fcb->usize))       oserror = ESPIPE, bn = -1;
 
1321
        else    bn = fcb->block_no;
 
1322
 
 
1323
        return(bn);  
 
1324
        
 
1325
    }
 
1326
 
 
1327
        /* Perform necessary checks. Write tape marks if previous operation
 
1328
        ** was write or fclose.
 
1329
        */
 
1330
 
 
1331
    if (fcb->last_op == U_WRITE) {
 
1332
        oserror = -1, oserrmsg = "Can't move after write";
 
1333
        return(-1);
 
1334
    }
 
1335
                
 
1336
    if (fcb->last_op == U_WEOF) if (tfclose() < 0) return(-1);
 
1337
 
 
1338
    switch(mode) {
 
1339
        case FILE_END: 
 
1340
                if (n > 0) { 
 
1341
                        oserror = ESPIPE; 
 
1342
                        return(-1); 
 
1343
                        }
 
1344
                /*
 
1345
                ** Method: Move forwards, then backwards, then skip
 
1346
                */
 
1347
                while ((fcb->tape_marks == 0) && (oserror == 0)) tmove();
 
1348
                        bmove();
 
1349
                break;
 
1350
        case FILE_START:
 
1351
                /* 
 
1352
                ** If we don't know where we are, better to go to beginning
 
1353
                ** of current file 
 
1354
                */
 
1355
                if (fcb->ignore & FCB_NOCOUNT)  osufseek(f, 0, FILE_CURRENT);
 
1356
                else            n -= fcb->block_no;     /* Relative */
 
1357
          case FILE_CURRENT:
 
1358
                break;
 
1359
    }
 
1360
    bn = (fcb->tape_marks ? 0 :                 /* We are here */
 
1361
        (fcb->ignore & FCB_NOCOUNT ? -1 : fcb->block_no));
 
1362
 
 
1363
    if (oserror)
 
1364
        return(-1);
 
1365
    if (n == 0)
 
1366
        return(bn);
 
1367
 
 
1368
        /* 
 
1369
        ** I just passed over a tape mark.
 
1370
        ** If Move forward, do it. 
 
1371
        ** Else move only 1 block!      
 
1372
        */
 
1373
    if (fcb->tape_marks) {      
 
1374
        if (n > 0) {
 
1375
                newfile(); 
 
1376
                fcb->ignore |= FCB_NOFEET;
 
1377
                }
 
1378
        else    {
 
1379
                n = -1;
 
1380
                fcb->ignore |= FCB_NOCOUNT;
 
1381
                }
 
1382
        }
 
1383
    else        fcb->ignore |= FCB_NOFEET; 
 
1384
 
 
1385
    if (n<0)
 
1386
        st = iobsr(fcb->pfd,-n), fcb->last_op = U_BMB;
 
1387
 
 
1388
    else
 
1389
        st = iofsr(fcb->pfd,n), fcb->last_op = U_BMF;
 
1390
 
 
1391
    if (oserror)        return(-1);
 
1392
 
 
1393
        /* 
 
1394
        ** Tape-mark was encountered
 
1395
        */
 
1396
    if (st < 0) {               
 
1397
        if (n < 0) {
 
1398
                if (fcb->tape_marks)    (fcb->tape_marks)--;
 
1399
                else if (--(fcb->file_no) < 0)  newfile();
 
1400
                }
 
1401
        else    fcb->tape_marks += 1;
 
1402
        }
 
1403
    else        {
 
1404
        if (n > 0)      fcb->block_no += bn;
 
1405
        else            fcb->block_no -= bn;
 
1406
        }
 
1407
    bn = (fcb->tape_marks ? 0 :                 /* We are here */
 
1408
        (fcb->ignore & FCB_NOCOUNT ? -1 : fcb->block_no));
 
1409
 
 
1410
    return(bn);
 
1411
}
 
1412
 
 
1413
long osubtell (f)
 
1414
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
1415
.PURPOSE Compute current block / sector number
 
1416
.RETURNS Current block number (in current file)
 
1417
.REMARKS
 
1418
----------------------------------------------------------------------*/
 
1419
int     f;              /* IN: Unit Number      */
 
1420
{
 
1421
        register long bn;
 
1422
 
 
1423
        if (uget(f))            /* Bad unit number...   */
 
1424
                return(-1);
 
1425
 
 
1426
        bn = (fcb->tape_marks ? 0 :             /* We are here */
 
1427
                (fcb->ignore & FCB_NOCOUNT ? -1 : fcb->block_no));
 
1428
 
 
1429
        return(bn);
 
1430
}