1 /* HETTAPE.C    (c) Copyright Roger Bowler, 1999-2009                */
2 /*              Hercules Tape Device Handler for HETTAPE             */
3 
4 /* Original Author: Leland Lucius                                    */
5 /* Prime Maintainer: Ivan Warren                                     */
6 /* Secondary Maintainer: "Fish" (David B. Trout)                     */
7 
8 /*-------------------------------------------------------------------*/
9 /* This module contains the HET emulated tape format support.        */
10 /*                                                                   */
11 /* The subroutines in this module are called by the general tape     */
12 /* device handler (tapedev.c) when the tape format is HETTAPE.       */
13 /*                                                                   */
14 /* Messages issued by this module are prefixed HHCTA4nn              */
15 /*-------------------------------------------------------------------*/
16 
17 #include "hstdinc.h"
18 #include "hercules.h"  /* need Hercules control blocks               */
19 #include "tapedev.h"   /* Main tape handler header file              */
20 
21 //#define  ENABLE_TRACING_STMTS     // (Fish: DEBUGGING)
22 
23 #ifdef ENABLE_TRACING_STMTS
24   #if !defined(DEBUG)
25     #warning DEBUG required for ENABLE_TRACING_STMTS
26   #endif
27   // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h)
28 #else
29   #undef  TRACE
30   #undef  ASSERT
31   #undef  VERIFY
32   #define TRACE       1 ? ((void)0) : logmsg
33   #define ASSERT(a)
34   #define VERIFY(a)   ((void)(a))
35 #endif
36 
37 /*-------------------------------------------------------------------*/
38 /* Open an HET format file                                           */
39 /*                                                                   */
40 /* If successful, the het control blk is stored in the device block  */
41 /* and the return value is zero.  Otherwise the return value is -1.  */
42 /*-------------------------------------------------------------------*/
open_het(DEVBLK * dev,BYTE * unitstat,BYTE code)43 int open_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
44 {
45 int             rc;                     /* Return code               */
46 
47     /* Check for no tape in drive */
48     if (!strcmp (dev->filename, TAPE_UNLOADED))
49     {
50         build_senseX(TAPE_BSENSE_TAPEUNLOADED,dev,unitstat,code);
51         return -1;
52     }
53 
54     /* Open the HET file */
55     rc = het_open (&dev->hetb, dev->filename, dev->tdparms.logical_readonly ? HETOPEN_READONLY : HETOPEN_CREATE );
56     if (rc >= 0)
57     {
58         if(dev->hetb->writeprotect)
59         {
60             dev->readonly=1;
61         }
62         rc = het_cntl (dev->hetb,
63                     HETCNTL_SET | HETCNTL_COMPRESS,
64                     dev->tdparms.compress);
65         if (rc >= 0)
66         {
67             rc = het_cntl (dev->hetb,
68                         HETCNTL_SET | HETCNTL_METHOD,
69                         dev->tdparms.method);
70             if (rc >= 0)
71             {
72                 rc = het_cntl (dev->hetb,
73                             HETCNTL_SET | HETCNTL_LEVEL,
74                             dev->tdparms.level);
75                 if (rc >= 0)
76                 {
77                     rc = het_cntl (dev->hetb,
78                                 HETCNTL_SET | HETCNTL_CHUNKSIZE,
79                                 dev->tdparms.chksize);
80                 }
81             }
82         }
83     }
84 
85     /* Check for successful open */
86     if (rc < 0)
87     {
88         int save_errno = errno;
89         het_close (&dev->hetb);
90         errno = save_errno;
91 
92         logmsg (_("HHCTA401E %4.4X: Error opening %s: %s(%s)\n"),
93                 dev->devnum, dev->filename, het_error(rc), strerror(errno));
94 
95         strcpy(dev->filename, TAPE_UNLOADED);
96         build_senseX(TAPE_BSENSE_TAPELOADFAIL,dev,unitstat,code);
97         return -1;
98     }
99 
100     /* Indicate file opened */
101     dev->fd = 1;
102 
103     return 0;
104 
105 } /* end function open_het */
106 
107 /*-------------------------------------------------------------------*/
108 /* Close an HET format file                                          */
109 /*                                                                   */
110 /* The HET file is close and all device block fields reinitialized.  */
111 /*-------------------------------------------------------------------*/
close_het(DEVBLK * dev)112 void close_het (DEVBLK *dev)
113 {
114 
115     /* Close the HET file */
116     het_close (&dev->hetb);
117 
118     /* Reinitialize the DEV fields */
119     dev->fd = -1;
120     strcpy (dev->filename, TAPE_UNLOADED);
121     dev->blockid = 0;
122     dev->fenced = 0;
123 
124     return;
125 
126 } /* end function close_het */
127 
128 /*-------------------------------------------------------------------*/
129 /* Rewind HET format file                                            */
130 /*                                                                   */
131 /* The HET file is close and all device block fields reinitialized.  */
132 /*-------------------------------------------------------------------*/
rewind_het(DEVBLK * dev,BYTE * unitstat,BYTE code)133 int rewind_het(DEVBLK *dev,BYTE *unitstat,BYTE code)
134 {
135 int rc;
136     rc = het_rewind (dev->hetb);
137     if (rc < 0)
138     {
139         /* Handle seek error condition */
140         logmsg (_("HHCTA402E %4.4X: Error seeking to start of %s: %s(%s)\n"),
141                 dev->devnum, dev->filename, het_error(rc), strerror(errno));
142 
143         build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code);
144         return -1;
145     }
146     dev->nxtblkpos=0;
147     dev->prvblkpos=-1;
148     dev->curfilen=1;
149     dev->blockid=0;
150     dev->fenced = 0;
151     return 0;
152 }
153 
154 /*-------------------------------------------------------------------*/
155 /* Read a block from an HET format file                              */
156 /*                                                                   */
157 /* If successful, return value is block length read.                 */
158 /* If a tapemark was read, the return value is zero, and the         */
159 /* current file number in the device block is incremented.           */
160 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
161 /*-------------------------------------------------------------------*/
read_het(DEVBLK * dev,BYTE * buf,BYTE * unitstat,BYTE code)162 int read_het (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code)
163 {
164 int             rc;                     /* Return code               */
165 
166     rc = het_read (dev->hetb, buf);
167     if (rc < 0)
168     {
169         /* Increment file number and return zero if tapemark was read */
170         if (rc == HETE_TAPEMARK)
171         {
172             dev->curfilen++;
173             dev->blockid++;
174             return 0;
175         }
176 
177         /* Handle end of file (uninitialized tape) condition */
178         if (rc == HETE_EOT)
179         {
180             logmsg (_("HHCTA414E %4.4X: End of file (end of tape) "
181                     "at block %8.8X in file %s\n"),
182                     dev->devnum, dev->hetb->cblk, dev->filename);
183 
184             /* Set unit exception with tape indicate (end of tape) */
185             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
186             return -1;
187         }
188 
189         logmsg (_("HHCTA415E %4.4X: Error reading data block "
190                 "at block %8.8X in file %s: %s(%s)\n"),
191                 dev->devnum, dev->hetb->cblk, dev->filename,
192                 het_error(rc), strerror(errno));
193 
194         /* Set unit check with equipment check */
195         build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
196         return -1;
197     }
198     dev->blockid++;
199     /* Return block length */
200     return rc;
201 
202 } /* end function read_het */
203 
204 /*-------------------------------------------------------------------*/
205 /* Write a block to an HET format file                               */
206 /*                                                                   */
207 /* If successful, return value is zero.                              */
208 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
209 /*-------------------------------------------------------------------*/
write_het(DEVBLK * dev,BYTE * buf,U16 blklen,BYTE * unitstat,BYTE code)210 int write_het (DEVBLK *dev, BYTE *buf, U16 blklen,
211                       BYTE *unitstat,BYTE code)
212 {
213 int             rc;                     /* Return code               */
214 off_t           cursize;                /* Current size for size chk */
215 
216     /* Check if we have already violated the size limit */
217     if(dev->tdparms.maxsize>0)
218     {
219         cursize=het_tell(dev->hetb);
220         if(cursize>=dev->tdparms.maxsize)
221         {
222             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
223             return -1;
224         }
225     }
226     /* Write the data block */
227     rc = het_write (dev->hetb, buf, blklen);
228     if (rc < 0)
229     {
230         /* Handle write error condition */
231         logmsg (_("HHCTA416E %4.4X: Error writing data block "
232                 "at block %8.8X in file %s: %s(%s)\n"),
233                 dev->devnum, dev->hetb->cblk, dev->filename,
234                 het_error(rc), strerror(errno));
235 
236         /* Set unit check with equipment check */
237         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
238         return -1;
239     }
240     /* Check if we have violated the maxsize limit */
241     /* Also check if we are passed EOT marker */
242     if(dev->tdparms.maxsize>0)
243     {
244         cursize=het_tell(dev->hetb);
245         if(cursize>dev->tdparms.maxsize)
246         {
247             logmsg (_("HHCTA430I %4.4X: max tape capacity exceeded\n"),
248                     dev->devnum);
249             if(dev->tdparms.strictsize)
250             {
251                 logmsg (_("HHCTA431I %4.4X: max tape capacity enforced\n"),
252                         dev->devnum);
253                 het_bsb(dev->hetb);
254                 cursize=het_tell(dev->hetb);
255                 ftruncate( fileno(dev->hetb->fd),cursize);
256                 dev->hetb->truncated=TRUE; /* SHOULD BE IN HETLIB */
257             }
258             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
259             return -1;
260         }
261     }
262 
263     /* Return normal status */
264     dev->blockid++;
265 
266     return 0;
267 
268 } /* end function write_het */
269 
270 /*-------------------------------------------------------------------*/
271 /* Write a tapemark to an HET format file                            */
272 /*                                                                   */
273 /* If successful, return value is zero.                              */
274 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
275 /*-------------------------------------------------------------------*/
write_hetmark(DEVBLK * dev,BYTE * unitstat,BYTE code)276 int write_hetmark (DEVBLK *dev, BYTE *unitstat,BYTE code)
277 {
278 int             rc;                     /* Return code               */
279 
280     /* Write the tape mark */
281     rc = het_tapemark (dev->hetb);
282     if (rc < 0)
283     {
284         /* Handle error condition */
285         logmsg (_("HHCTA417E %4.4X: Error writing tape mark "
286                 "at block %8.8X in file %s: %s(%s)\n"),
287                 dev->devnum, dev->hetb->cblk, dev->filename,
288                 het_error(rc), strerror(errno));
289 
290         /* Set unit check with equipment check */
291         build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
292         return -1;
293     }
294 
295     /* Return normal status */
296     dev->blockid++;
297 
298     return 0;
299 
300 } /* end function write_hetmark */
301 
302 /*-------------------------------------------------------------------*/
303 /* Synchronize a HET format file   (i.e. flush its buffers to disk)  */
304 /*                                                                   */
305 /* If successful, return value is zero.                              */
306 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
307 /*-------------------------------------------------------------------*/
sync_het(DEVBLK * dev,BYTE * unitstat,BYTE code)308 int sync_het(DEVBLK *dev, BYTE *unitstat,BYTE code)
309 {
310 int             rc;                     /* Return code               */
311 
312     /* Perform the flush */
313     rc = het_sync (dev->hetb);
314     if (rc < 0)
315     {
316         /* Handle error condition */
317         if (HETE_PROTECTED == rc)
318             build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
319         else
320         {
321             logmsg (_("HHCTA488E %4.4X: Sync error on file %s: %s\n"),
322                 dev->devnum, dev->filename, strerror(errno));
323             build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code);
324         }
325         return -1;
326     }
327 
328     /* Return normal status */
329     return 0;
330 
331 } /* end function sync_het */
332 
333 /*-------------------------------------------------------------------*/
334 /* Forward space over next block of an HET format file               */
335 /*                                                                   */
336 /* If successful, return value +1.                                   */
337 /* If the block skipped was a tapemark, the return value is zero,    */
338 /* and the current file number in the device block is incremented.   */
339 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
340 /*-------------------------------------------------------------------*/
fsb_het(DEVBLK * dev,BYTE * unitstat,BYTE code)341 int fsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
342 {
343 int             rc;                     /* Return code               */
344 
345     /* Forward space one block */
346     rc = het_fsb (dev->hetb);
347 
348     if (rc < 0)
349     {
350         /* Increment file number and return zero if tapemark was read */
351         if (rc == HETE_TAPEMARK)
352         {
353             dev->blockid++;
354             dev->curfilen++;
355             return 0;
356         }
357 
358         logmsg (_("HHCTA418E %4.4X: Error forward spacing "
359                 "at block %8.8X in file %s: %s(%s)\n"),
360                 dev->devnum, dev->hetb->cblk, dev->filename,
361                 het_error(rc), strerror(errno));
362 
363         /* Set unit check with equipment check */
364         if(rc==HETE_EOT)
365         {
366             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
367         }
368         else
369         {
370             build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
371         }
372         return -1;
373     }
374 
375     dev->blockid++;
376 
377     /* Return +1 to indicate forward space successful */
378     return +1;
379 
380 } /* end function fsb_het */
381 
382 /*-------------------------------------------------------------------*/
383 /* Backspace to previous block of an HET format file                 */
384 /*                                                                   */
385 /* If successful, return value will be +1.                           */
386 /* If the block is a tapemark, the return value is zero,             */
387 /* and the current file number in the device block is decremented.   */
388 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
389 /*-------------------------------------------------------------------*/
bsb_het(DEVBLK * dev,BYTE * unitstat,BYTE code)390 int bsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
391 {
392 int             rc;                     /* Return code               */
393 
394     /* Back space one block */
395     rc = het_bsb (dev->hetb);
396     if (rc < 0)
397     {
398         /* Increment file number and return zero if tapemark was read */
399         if (rc == HETE_TAPEMARK)
400         {
401             dev->blockid--;
402             dev->curfilen--;
403             return 0;
404         }
405 
406         /* Unit check if already at start of tape */
407         if (rc == HETE_BOT)
408         {
409             build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
410             return -1;
411         }
412 
413         logmsg (_("HHCTA419E %4.4X: Error reading data block "
414                 "at block %8.8X in file %s: %s(%s)\n"),
415                 dev->devnum, dev->hetb->cblk, dev->filename,
416                 het_error(rc), strerror(errno));
417 
418         /* Set unit check with equipment check */
419         build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
420         return -1;
421     }
422 
423     dev->blockid--;
424 
425     /* Return +1 to indicate back space successful */
426     return +1;
427 
428 } /* end function bsb_het */
429 
430 /*-------------------------------------------------------------------*/
431 /* Forward space to next logical file of HET format file             */
432 /*                                                                   */
433 /* If successful, return value is zero, and the current file number  */
434 /* in the device block is incremented.                               */
435 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
436 /*-------------------------------------------------------------------*/
fsf_het(DEVBLK * dev,BYTE * unitstat,BYTE code)437 int fsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
438 {
439 int             rc;                     /* Return code               */
440 
441     /* Forward space to start of next file */
442     rc = het_fsf (dev->hetb);
443     if (rc < 0)
444     {
445         logmsg (_("HHCTA420E %4.4X: Error forward spacing to next file "
446                 "at block %8.8X in file %s: %s(%s)\n"),
447                 dev->devnum, dev->hetb->cblk, dev->filename,
448                 het_error(rc), strerror(errno));
449 
450         if(rc==HETE_EOT)
451         {
452             build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code);
453         }
454         else
455         {
456             build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code);
457         }
458         return -1;
459     }
460 
461     /* Maintain position */
462     dev->blockid = rc;
463     dev->curfilen++;
464 
465     /* Return success */
466     return 0;
467 
468 } /* end function fsf_het */
469 
470 /*-------------------------------------------------------------------*/
471 /* Check HET file is passed the allowed EOT margin                   */
472 /*-------------------------------------------------------------------*/
passedeot_het(DEVBLK * dev)473 int passedeot_het (DEVBLK *dev)
474 {
475 off_t cursize;
476     if(dev->fd>0)
477     {
478         if(dev->tdparms.maxsize>0)
479         {
480             cursize=het_tell(dev->hetb);
481             if(cursize+dev->eotmargin>dev->tdparms.maxsize)
482             {
483                 dev->eotwarning = 1;
484                 return 1;
485             }
486         }
487     }
488     dev->eotwarning = 0;
489     return 0;
490 }
491 
492 /*-------------------------------------------------------------------*/
493 /* Backspace to previous logical file of HET format file             */
494 /*                                                                   */
495 /* If successful, return value is zero, and the current file number  */
496 /* in the device block is decremented.                               */
497 /* If error, return value is -1 and unitstat is set to CE+DE+UC      */
498 /*-------------------------------------------------------------------*/
bsf_het(DEVBLK * dev,BYTE * unitstat,BYTE code)499 int bsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code)
500 {
501 int             rc;                     /* Return code               */
502 
503     /* Exit if already at BOT */
504     if (dev->curfilen==1 && dev->nxtblkpos == 0)
505     {
506         build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code);
507         return -1;
508     }
509 
510     rc = het_bsf (dev->hetb);
511     if (rc < 0)
512     {
513         logmsg (_("HHCTA421E %4.4X: Error back spacing to previous file "
514                 "at block %8.8X in file %s:\n %s(%s)\n"),
515                 dev->devnum, dev->hetb->cblk, dev->filename,
516                 het_error(rc), strerror(errno));
517 
518         build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code);
519         return -1;
520     }
521 
522     /* Maintain position */
523     dev->blockid = rc;
524     dev->curfilen--;
525 
526     /* Return success */
527     return 0;
528 
529 } /* end function bsf_het */
530