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