1 /* DASDLOAD.C (c) Copyright Roger Bowler, 1999-2014 */
2 /* Hercules DASD Utilities: DASD image loader */
3
4 /*-------------------------------------------------------------------*/
5 /* This program creates a virtual DASD volume from a list of */
6 /* datasets previously unloaded using the TSO XMIT command. */
7 /*-------------------------------------------------------------------*/
8
9 /*-------------------------------------------------------------------*/
10 /* Additional credits: */
11 /* Corrections to CVOL initialization logic by Jay Maynard */
12 /* IEBCOPY native dataset support by Ronen Tzur */
13 /*-------------------------------------------------------------------*/
14
15 #include "hstdinc.h"
16
17 #include "hercules.h"
18 #include "dasdblks.h"
19
20 /*-------------------------------------------------------------------*/
21 /* Internal table sizes */
22 /*-------------------------------------------------------------------*/
23 #define MAXDBLK 10000 /* Maximum number of directory
24 blocks per dataset */
25 #define MAXTTR 50000 /* Maximum number of TTRs
26 per dataset */
27 #define MAXDSCB 1000 /* Maximum number of DSCBs */
28
29 /*-------------------------------------------------------------------*/
30 /* Internal macro definitions */
31 /*-------------------------------------------------------------------*/
32 #define CASERET(s) case s: return (#s)
33 #define XMINF info_msg
34 #define XMINFF info_msg
35 #define XMERR printf
36 #define XMERRF printf
37
38 #define R0_DATALEN 8
39 #define IPL1_KEYLEN 4
40 #define IPL1_DATALEN 24
41 #define IPL2_KEYLEN 4
42 #define IPL2_DATALEN 144
43 #define VOL1_KEYLEN 4
44 #define VOL1_DATALEN 80
45
46 #define EBCDIC_END "\xC5\xD5\xC4"
47 #define EBCDIC_TXT "\xE3\xE7\xE3"
48
49 /*-------------------------------------------------------------------*/
50 /* Definition of LOGREC header record */
51 /*-------------------------------------------------------------------*/
52 typedef struct _DIPHDR {
53 HWORD recid; /* Record identifier (0xFFFF)*/
54 HWORD bcyl; /* Extent begin cylinder */
55 HWORD btrk; /* Extent begin track */
56 HWORD ecyl; /* Extent end cylinder */
57 HWORD etrk; /* Extent end track */
58 BYTE resv; /* Unused */
59 BYTE restart[7]; /* Restart area BBCCHHR */
60 HWORD trkbal; /* Bytes remaining on track */
61 HWORD trklen; /* Total bytes on track */
62 BYTE reused[7]; /* Last reused BBCCHHR */
63 HWORD lasthead; /* Last track on cylinder */
64 HWORD trklen90; /* 90% of track length */
65 BYTE devcode; /* Device type code */
66 BYTE cchh90[4]; /* 90% full track CCHH */
67 BYTE switches; /* Switches */
68 BYTE endid; /* Check byte (0xFF) */
69 } DIPHDR;
70
71 /*-------------------------------------------------------------------*/
72 /* Definition of internal extent descriptor array entry */
73 /*-------------------------------------------------------------------*/
74 typedef struct _EXTDESC {
75 U16 bcyl; /* Begin cylinder */
76 U16 btrk; /* Begin track */
77 U16 ecyl; /* End cylinder */
78 U16 etrk; /* End track */
79 U16 ntrk; /* Number of tracks */
80 } EXTDESC;
81
82 /*-------------------------------------------------------------------*/
83 /* Definition of internal TTR conversion table array entry */
84 /*-------------------------------------------------------------------*/
85 typedef struct _TTRCONV {
86 BYTE origttr[3]; /* TTR in original dataset */
87 BYTE outpttr[3]; /* TTR in output dataset */
88 } TTRCONV;
89
90 /*-------------------------------------------------------------------*/
91 /* Definitions for dataset initialization methods */
92 /*-------------------------------------------------------------------*/
93 #define METHOD_EMPTY 0
94 #define METHOD_XMIT 1
95 #define METHOD_DIP 2
96 #define METHOD_CVOL 3
97 #define METHOD_VTOC 4
98 #define METHOD_VS 5
99 #define METHOD_SEQ 6
100 #define METHOD_XMSEQ 7
101 #define METHOD_TEXT 8
102
103 /*-------------------------------------------------------------------*/
104 /* Static data areas */
105 /*-------------------------------------------------------------------*/
106 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
107 BYTE twelvehex00[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
108 BYTE cvol_low_key[] = {0, 0, 0, 0, 0, 0, 0, 1};
109 BYTE iplpsw[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
110 BYTE iplccw1[8] = {0x06, 0x00, 0x3A, 0x98, 0x60, 0x00, 0x00, 0x60};
111 BYTE iplccw2[8] = {0x08, 0x00, 0x3A, 0x98, 0x00, 0x00, 0x00, 0x00};
112 BYTE ipl2data[] = {0x07, 0x00, 0x3A, 0xB8, 0x40, 0x00, 0x00, 0x06,
113 0x31, 0x00, 0x3A, 0xBE, 0x40, 0x00, 0x00, 0x05,
114 0x08, 0x00, 0x3A, 0xA0, 0x00, 0x00, 0x00, 0x00,
115 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x7f, 0xff,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*BBCCHH*/
117 0x00, 0x00, 0x00, 0x00, 0x04}; /*CCHHR*/
118 BYTE noiplpsw[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F};
119 BYTE noiplccw1[8] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
120 BYTE noiplccw2[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
121
122 /* Information message level: 0=None, 1=File name, 2=File information,
123 3=Member information, 4=Text units, record headers, 5=Dump data */
124 int infolvl = 1;
125
126 /*-------------------------------------------------------------------*/
127 /* Subroutine to display command syntax and exit */
128 /*-------------------------------------------------------------------*/
129 static void
argexit(int code)130 argexit ( int code )
131 {
132 fprintf (stderr,
133 "dasdload creates a DASD image file from a list "
134 "of TSO XMIT files\n"
135 "Syntax:\tdasdload [options] ctlfile outfile [msglevel]\n"
136 "where:\tctlfile = name of input control file\n"
137 "\toutfile = name of DASD image file to be created\n"
138 "\tmsglevel = Value 0-5 controls output verbosity\n"
139 "\noptions:\n"
140 "\t-0: no compression (default)\n"
141 "\t-a: output disk will include alternate cylinders\n"
142 #ifdef CCKD_COMPRESS_ZLIB
143 "\t-z: compress using zlib\n"
144 #endif
145 #ifdef CCKD_COMPRESS_BZIP2
146 "\t-bz2: compress using bzip2\n"
147 #endif
148 );
149 if (sizeof(off_t) > 4)
150 fprintf (stderr,
151 "\t-lfs: create single large output file\n"
152 );
153 exit(code);
154 } /* end function argexit */
155
156 /*-------------------------------------------------------------------*/
157 /* Subroutine to display an informational message */
158 /*-------------------------------------------------------------------*/
159 static void
info_msg(int lvl,char * msg,...)160 info_msg (int lvl, char *msg, ...)
161 {
162 va_list vl;
163
164 if (infolvl >= lvl)
165 {
166 va_start(vl, msg);
167 vprintf (msg, vl);
168 }
169 } /* end function info_msg */
170
171 /*-------------------------------------------------------------------*/
172 /* Subroutine to load a S/390 integer value from a buffer */
173 /*-------------------------------------------------------------------*/
174 static int
make_int(BYTE * src,int srclen)175 make_int (BYTE *src, int srclen)
176 {
177 int result = 0; /* Result accumulator */
178 int i; /* Array subscript */
179
180 for (i=0; i < srclen; i++)
181 {
182 result <<= 8;
183 result |= src[i];
184 }
185
186 return result;
187
188 } /* end function make_int */
189
190 /*-------------------------------------------------------------------*/
191 /* Subroutine to return the name of a dataset organization */
192 /*-------------------------------------------------------------------*/
193 static char *
dsorg_name(BYTE * dsorg)194 dsorg_name (BYTE *dsorg)
195 {
196 static char name[8]; /* Name of dsorg */
197
198 if (dsorg[0] & DSORG_IS)
199 strcpy (name, "IS");
200 else if (dsorg[0] & DSORG_PS)
201 strcpy (name, "PS");
202 else if (dsorg[0] & DSORG_DA)
203 strcpy (name, "DA");
204 else if (dsorg[0] & DSORG_PO)
205 strcpy (name, "PO");
206
207 if (dsorg[0] & DSORG_U) strcat (name, "U");
208
209 return name;
210 } /* end function dsorg_name */
211
212 /*-------------------------------------------------------------------*/
213 /* Subroutine to return the name of a record format */
214 /*-------------------------------------------------------------------*/
215 static char *
recfm_name(BYTE * recfm)216 recfm_name (BYTE *recfm)
217 {
218 static char name[8]; /* Name of record format */
219
220 switch (recfm[0] & RECFM_FORMAT) {
221 case RECFM_FORMAT_V:
222 strcpy (name, "V"); break;
223 case RECFM_FORMAT_F:
224 strcpy (name, "F"); break;
225 case RECFM_FORMAT_U:
226 strcpy (name, "U"); break;
227 default:
228 strcpy (name,"??");
229 } /* end switch */
230
231 if (recfm[0] & RECFM_TRKOFLOW) strcat (name, "T");
232 if (recfm[0] & RECFM_BLOCKED) strcat (name, "B");
233 if (recfm[0] & RECFM_SPANNED) strcat (name, "S");
234
235 switch (recfm[0] & RECFM_CTLCHAR) {
236 case RECFM_CTLCHAR_A:
237 strcpy (name, "A"); break;
238 case RECFM_CTLCHAR_M:
239 strcpy (name, "M"); break;
240 } /* end switch */
241
242 return name;
243 } /* end function recfm_name */
244
245 /*-------------------------------------------------------------------*/
246 /* Subroutine to return the name of a DASD device from the UCB type */
247 /*-------------------------------------------------------------------*/
248 static char *
dasd_name(FWORD ucbtype)249 dasd_name (FWORD ucbtype)
250 {
251 if (ucbtype[2] != 0x20) return "????";
252
253 switch (ucbtype[3]) {
254 case 0x01: return "2311";
255 case 0x02: return "2301";
256 case 0x03: return "2303";
257 case 0x04: if (ucbtype[1] == 0x00) return "2302";
258 else return "9345";
259 case 0x05: return "2321";
260 case 0x06: return "2305-1";
261 case 0x07: return "2305-2";
262 case 0x08: return "2314";
263 case 0x09: return "3330";
264 case 0x0A: return "3340";
265 case 0x0B: return "3350";
266 case 0x0C: return "3375";
267 case 0x0D: return "3330-11";
268 case 0x0E: return "3380";
269 case 0x0F: return "3390";
270 } /* end switch(key) */
271
272 return "????";
273
274 } /* end function dasd_name */
275
276 /*-------------------------------------------------------------------*/
277 /* Subroutine to return the UCBTYPE of a DASD device */
278 /*-------------------------------------------------------------------*/
279 static U32
ucbtype_code(U16 devtype)280 ucbtype_code (U16 devtype)
281 {
282 switch (devtype) {
283 case 0x2311: return 0x30002001;
284 case 0x2301: return 0x30402002;
285 case 0x2303: return 0x30002003;
286 case 0x2302: return 0x30002004;
287 case 0x2321: return 0x30002005;
288 case 0x2305: return 0x30002006;
289 case 0x2314: return 0x30C02008;
290 case 0x3330: return 0x30502009;
291 case 0x3340: return 0x3050200A;
292 case 0x3350: return 0x3050200B;
293 case 0x3375: return 0x3050200C;
294 case 0x3380: return 0x3050200E;
295 case 0x3390: return 0x3050200F;
296 case 0x9345: return 0x30502004;
297 } /* end switch(key) */
298
299 return 0;
300
301 } /* end function ucbtype_code */
302
303 /*-------------------------------------------------------------------*/
304 /* Subroutine to calculate relative track address */
305 /* Input: */
306 /* cyl Cylinder number */
307 /* head Head number */
308 /* heads Number of heads per cylinder */
309 /* numext Number of extents */
310 /* xarray Array containing 1-16 extent descriptions */
311 /* Output: */
312 /* The return value is the relative track number, */
313 /* or -1 if an error occurred. */
314 /*-------------------------------------------------------------------*/
315 static int
calculate_ttr(int cyl,int head,int heads,int numext,EXTDESC xarray[])316 calculate_ttr (int cyl, int head, int heads, int numext,
317 EXTDESC xarray[])
318 {
319 int i; /* Array subscript */
320 int track; /* Relative track number */
321
322 /* Search the extent descriptor array */
323 for (i = 0, track = 0; i < numext; track += xarray[i++].ntrk)
324 {
325 if (cyl < xarray[i].bcyl || cyl > xarray[i].ecyl)
326 continue;
327
328 if (cyl == xarray[i].bcyl && head < xarray[i].btrk)
329 continue;
330
331 if (cyl == xarray[i].ecyl && head > xarray[i].etrk)
332 continue;
333
334 track += (cyl - xarray[i].bcyl) * heads
335 - xarray[i].btrk + head;
336 break;
337 } /* end for(i) */
338
339 /* Error if track was not found in extent table */
340 if (i == numext)
341 {
342 XMERRF ("HHCDL033E CCHH=%4.4X%4.4X not found in extent table\n",
343 cyl, head);
344 return -1;
345 }
346
347 /* Return relative track number */
348 return track;
349 } /* end function calculate_ttr */
350
351 /*-------------------------------------------------------------------*/
352 /* Subroutine to read IPL text from an EBCDIC object file */
353 /* Input: */
354 /* iplfnm Name of EBCDIC card image object file */
355 /* iplbuf Address of buffer in which to build IPL text record */
356 /* buflen Length of buffer */
357 /* Output: */
358 /* The return value is the length of the IPL text built */
359 /* in the buffer if successful, or -1 if error */
360 /* Note: */
361 /* Only TXT records are processed; ESD and RLD records are */
362 /* ignored because the IPL text is non-relocatable and is */
363 /* assumed to have zero origin. An END card must be present. */
364 /*-------------------------------------------------------------------*/
365 static int
read_ipl_text(char * iplfnm,BYTE * iplbuf,int buflen)366 read_ipl_text (char *iplfnm, BYTE *iplbuf, int buflen)
367 {
368 int rc; /* Return code */
369 int ipllen = 0; /* Length of IPL text */
370 int txtlen; /* Byte count from TXT card */
371 int txtadr; /* Address from TXT card */
372 int tfd; /* Object file descriptor */
373 BYTE objrec[80]; /* Object card image */
374 char pathname[MAX_PATH]; /* iplfnm in host path format*/
375
376 /* Open the object file */
377 hostpath(pathname, iplfnm, sizeof(pathname));
378 tfd = hopen(pathname, O_RDONLY|O_BINARY);
379 if (tfd < 0)
380 {
381 XMERRF ("HHCDL034E Cannot open %s: %s\n",
382 iplfnm, strerror(errno));
383 return -1;
384 }
385
386 /* Read the object file */
387 while (1)
388 {
389 /* Read a card image from the object file */
390 rc = read (tfd, objrec, 80);
391 if (rc < 80)
392 {
393 XMERRF ("HHCDL035E Cannot read %s: %s\n",
394 iplfnm, strerror(errno));
395 close (tfd);
396 return -1;
397 }
398
399 /* Column 1 of each object card must contain X'02' */
400 if (objrec[0] != 0x02)
401 {
402 XMERRF ("HHCDL036E %s is not a valid object file\n",
403 iplfnm);
404 close (tfd);
405 return -1;
406 }
407
408 /* Exit if END card has been read */
409 if (memcmp(objrec+1, EBCDIC_END, 3) == 0)
410 break;
411
412 /* Ignore any cards which are not TXT cards */
413 if (memcmp(objrec+1, EBCDIC_TXT, 3) != 0)
414 continue;
415
416 /* Load the address from TXT card columns 6-8 */
417 txtadr = (objrec[5] << 16) | (objrec[6] << 8) | objrec[7];
418
419 /* Load the byte count from TXT card columns 11-12 */
420 txtlen = (objrec[10] << 8) | objrec[11];
421
422 XMINFF (5, "HHCDL037I IPL text address=%6.6X length=%4.4X\n",
423 txtadr, txtlen);
424
425 /* Check that the byte count is valid */
426 if (txtlen > 56)
427 {
428 XMERRF ("HHCDL038E TXT record in %s has invalid count %d\n",
429 iplfnm, txtlen);
430 close (tfd);
431 return -1;
432 }
433
434 /* Check that the text falls within the buffer */
435 if (txtadr + txtlen > buflen)
436 {
437 XMERRF ("HHCDL039E IPL text in %s exceeds %d bytes\n",
438 iplfnm, buflen);
439 close (tfd);
440 return -1;
441 }
442
443 /* Copy the IPL text to the buffer */
444 memcpy (iplbuf + txtadr, objrec+16, txtlen);
445
446 /* Update the total size of the IPL text */
447 if (txtadr + txtlen > ipllen)
448 ipllen = txtadr + txtlen;
449
450 } /* end while */
451
452 return ipllen;
453 } /* end function read_ipl_text */
454
455 /*-------------------------------------------------------------------*/
456 /* Subroutine to initialize the output track buffer */
457 /* Input: */
458 /* trklen Track length of virtual output device */
459 /* trkbuf Pointer to track buffer */
460 /* cyl Cylinder number on output device */
461 /* head Head number on output device */
462 /* Output: */
463 /* usedv Number of bytes written to track of virtual device */
464 /*-------------------------------------------------------------------*/
465 static void
init_track(int trklen,BYTE * trkbuf,int cyl,int head,int * usedv)466 init_track (int trklen, BYTE *trkbuf, int cyl, int head, int *usedv)
467 {
468 CKDDASD_TRKHDR *trkhdr; /* -> Track header */
469 CKDDASD_RECHDR *rechdr; /* -> Record header */
470
471 /* Clear the track buffer to zeroes */
472 memset (trkbuf, 0, trklen);
473
474 /* Build the home address in the track buffer */
475 trkhdr = (CKDDASD_TRKHDR*)trkbuf;
476 trkhdr->bin = 0;
477 trkhdr->cyl[0] = (cyl >> 8) & 0xFF;
478 trkhdr->cyl[1] = cyl & 0xFF;
479 trkhdr->head[0] = (head >> 8) & 0xFF;
480 trkhdr->head[1] = head & 0xFF;
481
482 /* Build a standard record zero in the track buffer */
483 rechdr = (CKDDASD_RECHDR*)(trkbuf + CKDDASD_TRKHDR_SIZE);
484 rechdr->cyl[0] = (cyl >> 8) & 0xFF;
485 rechdr->cyl[1] = cyl & 0xFF;
486 rechdr->head[0] = (head >> 8) & 0xFF;
487 rechdr->head[1] = head & 0xFF;
488 rechdr->rec = 0;
489 rechdr->klen = 0;
490 rechdr->dlen[0] = (R0_DATALEN >> 8) & 0xFF;
491 rechdr->dlen[1] = R0_DATALEN & 0xFF;
492
493 /* Set number of bytes used in track buffer */
494 *usedv = CKDDASD_TRKHDR_SIZE + CKDDASD_RECHDR_SIZE + R0_DATALEN;
495
496 /* Build end of track marker at end of buffer */
497 memcpy (trkbuf + *usedv, eighthexFF, 8);
498
499 } /* end function init_track */
500
501 /*-------------------------------------------------------------------*/
502 /* Subroutine to write track buffer to output file */
503 /* Input: */
504 /* cif -> CKD image file descriptor */
505 /* ofname Output file name */
506 /* heads Number of tracks per cylinder on output device */
507 /* trklen Track length of virtual output device */
508 /* Input/output: */
509 /* usedv Number of bytes written to track of virtual device */
510 /* reltrk Relative track number on output device */
511 /* cyl Cylinder number on output device */
512 /* head Head number on output device */
513 /* Output: */
514 /* The return value is 0 if successful, -1 if error occurred. */
515 /*-------------------------------------------------------------------*/
516 static int
write_track(CIFBLK * cif,char * ofname,int heads,int trklen,int * usedv,int * reltrk,int * cyl,int * head)517 write_track (CIFBLK *cif, char *ofname, int heads, int trklen,
518 int *usedv, int *reltrk, int *cyl, int *head)
519 {
520 int rc; /* Return code */
521
522 UNREFERENCED(ofname);
523 UNREFERENCED(trklen);
524
525 /* Don't overwrite HA */
526 if (*usedv == 0)
527 *usedv = CKDDASD_TRKHDR_SIZE;
528
529 /* Build end of track marker at end of buffer */
530 memcpy (cif->trkbuf + *usedv, eighthexFF, 8);
531 cif->trkmodif = 1;
532
533 /* Reset values for next track */
534 (*reltrk)++;
535 (*head)++;
536 if (*head >= heads)
537 {
538 (*cyl)++;
539 *head = 0;
540 }
541 *usedv = 0;
542
543 /* Read the next track */
544 if (*cyl < (int)cif->devblk.ckdcyls)
545 {
546 rc = read_track (cif, *cyl, *head);
547 if (rc < 0) return -1;
548 }
549
550 return 0;
551 } /* end function write_track */
552
553 /*-------------------------------------------------------------------*/
554 /* Subroutine to add a data block to the output track buffer */
555 /* Input: */
556 /* cif -> CKD image file descriptor */
557 /* ofname Output file name */
558 /* blk Pointer to data block */
559 /* keylen Key length */
560 /* datalen Data length */
561 /* devtype Output device type */
562 /* heads Number of tracks per cylinder on output device */
563 /* trklen Track length of virtual output device */
564 /* maxtrk Maximum number of tracks to be written */
565 /* Input/output: */
566 /* usedv Number of bytes written to track of virtual device */
567 /* usedr Number of bytes written to track, calculated */
568 /* according to the formula for a real device */
569 /* trkbal Number of bytes remaining on track, calculated */
570 /* according to the formula for a real device */
571 /* reltrk Relative track number on output device */
572 /* cyl Cylinder number on output device */
573 /* head Head number on output device */
574 /* rec Record number on output device */
575 /* Output: */
576 /* The return value is 0 if successful, -1 if error occurred. */
577 /*-------------------------------------------------------------------*/
578 static int
write_block(CIFBLK * cif,char * ofname,DATABLK * blk,int keylen,int datalen,U16 devtype,int heads,int trklen,int maxtrk,int * usedv,int * usedr,int * trkbal,int * reltrk,int * cyl,int * head,int * rec)579 write_block (CIFBLK *cif, char *ofname, DATABLK *blk, int keylen,
580 int datalen, U16 devtype, int heads, int trklen,
581 int maxtrk, int *usedv, int *usedr,
582 int *trkbal, int *reltrk, int *cyl, int *head, int *rec)
583 {
584 int rc; /* Return code */
585 int cc; /* Capacity calculation code */
586 CKDDASD_RECHDR *rechdr; /* -> Record header */
587
588 UNREFERENCED(devtype);
589
590 /* Determine whether record will fit on current track */
591 cc = capacity_calc (cif, *usedr, keylen, datalen,
592 usedr, trkbal, NULL, NULL, NULL, NULL, NULL,
593 NULL, NULL, NULL, NULL, NULL);
594 if (cc < 0) return -1;
595
596 /* Move to next track if record will not fit */
597 if (cc > 0 && *usedr > 0)
598 {
599 /* Write current track to output file */
600 rc = write_track (cif, ofname, heads, trklen,
601 usedv, reltrk, cyl, head);
602 if (rc < 0) return -1;
603
604 /* Clear bytes used and record number for new track */
605 *usedr = 0;
606 *rec = 0;
607
608 /* Determine whether record will fit on new track */
609 cc = capacity_calc (cif, *usedr, keylen, datalen,
610 usedr, trkbal, NULL, NULL, NULL, NULL,
611 NULL, NULL, NULL, NULL, NULL, NULL);
612 if (cc < 0) return -1;
613
614 } /* end if */
615
616 /* Error if record will not even fit on an empty track */
617 if (cc > 0)
618 {
619 XMERRF ("HHCDL040E Input record CCHHR=%2.2X%2.2X%2.2X%2.2X%2.2X "
620 "exceeds output device track size\n",
621 blk->cyl[0], blk->cyl[1],
622 blk->head[0], blk->head[1], blk->rec);
623 return -1;
624 }
625
626 /* Determine whether end of extent has been reached */
627 if (*reltrk >= maxtrk)
628 {
629 XMERRF ("HHCDL041E Dataset exceeds extent size: reltrk=%d, "
630 "maxtrk=%d\n",
631 *reltrk, maxtrk);
632 return -1;
633 }
634
635 /* Build home address and record 0 if new track */
636 if (*usedv == 0)
637 {
638 init_track (trklen, cif->trkbuf, *cyl, *head, usedv);
639 }
640
641 /* Double check that record will not exceed virtual track size */
642 if (*usedv + CKDDASD_RECHDR_SIZE + keylen + datalen + 8
643 > trklen)
644 {
645 XMERRF ("HHCDL042E Input record CCHHR=%2.2X%2.2X%2.2X%2.2X%2.2X "
646 "exceeds virtual device track size\n",
647 blk->cyl[0], blk->cyl[1],
648 blk->head[0], blk->head[1], blk->rec);
649 return -1;
650 }
651
652 /* Add data block to virtual track buffer */
653 (*rec)++;
654 rechdr = (CKDDASD_RECHDR*)(cif->trkbuf + *usedv);
655 rechdr->cyl[0] = (*cyl >> 8) & 0xFF;
656 rechdr->cyl[1] = *cyl & 0xFF;
657 rechdr->head[0] = (*head >> 8) & 0xFF;
658 rechdr->head[1] = *head & 0xFF;
659 rechdr->rec = *rec;
660 rechdr->klen = keylen;
661 rechdr->dlen[0] = (datalen >> 8) & 0xFF;
662 rechdr->dlen[1] = datalen & 0xFF;
663 *usedv += CKDDASD_RECHDR_SIZE;
664 memcpy (cif->trkbuf + *usedv, blk->kdarea, keylen + datalen);
665 *usedv += keylen + datalen;
666 cif->trkmodif = 1;
667
668 return 0;
669 } /* end function write_block */
670
671 /*-------------------------------------------------------------------*/
672 /* Subroutine to write track zero */
673 /* Input: */
674 /* cif -> CKD image file descriptor */
675 /* ofname Output file name */
676 /* volser Volume serial number (ASCIIZ) */
677 /* devtype Output device type */
678 /* heads Number of tracks per cylinder on output device */
679 /* trklen Track length of virtual output device */
680 /* iplfnm Name of file containing IPL text object deck */
681 /* Output: */
682 /* reltrk Next relative track number on output device */
683 /* outcyl Cylinder number of next track on output device */
684 /* outhead Head number of next track on output device */
685 /* The return value is 0 if successful, -1 if error occurred. */
686 /*-------------------------------------------------------------------*/
687 static int
write_track_zero(CIFBLK * cif,char * ofname,char * volser,U16 devtype,int heads,int trklen,char * iplfnm,int * reltrk,int * outcyl,int * outhead)688 write_track_zero (CIFBLK *cif, char *ofname, char *volser, U16 devtype,
689 int heads, int trklen, char *iplfnm,
690 int *reltrk, int *outcyl, int *outhead)
691 {
692 int rc; /* Return code */
693 int outusedv = 0; /* Output bytes used on track
694 of virtual device */
695 int outusedr = 0; /* Output bytes used on track
696 of real device */
697 int outtrkbr = 0; /* Output bytes remaining on
698 track of real device */
699 int outtrk = 0; /* Output relative track */
700 int outrec = 0; /* Output record number */
701 int keylen; /* Key length */
702 int datalen; /* Data length */
703 int maxtrks = 1; /* Maximum track count */
704 DATABLK *datablk; /* -> data block */
705 BYTE buf[32768]; /* Buffer for data block */
706
707 /* For 2311 the IPL text will not fit on track 0 record 4,
708 so adjust the IPL2 so that it loads from track 1 record 1 */
709 if (devtype == 0x2311)
710 {
711 memcpy (ipl2data + 32, "\x00\x00\x00\x00\x00\x01", 6);
712 memcpy (ipl2data + 38, "\x00\x00\x00\x01\x01", 5);
713 maxtrks = 2;
714 }
715
716 /* Read track 0 */
717 rc = read_track (cif, 0, 0);
718 if (rc < 0) return -1;
719
720 /* Initialize the track buffer */
721 *outcyl = 0; *outhead = 0;
722 init_track (trklen, cif->trkbuf, *outcyl, *outhead, &outusedv);
723 cif->trkmodif = 1;
724
725 /* Build the IPL1 record */
726 memset (buf, 0, sizeof(buf));
727 datablk = (DATABLK*)buf;
728 convert_to_ebcdic (datablk->kdarea, 4, "IPL1");
729
730 if (iplfnm != NULL)
731 {
732 memcpy (datablk->kdarea+4, iplpsw, 8);
733 memcpy (datablk->kdarea+12, iplccw1, 8);
734 memcpy (datablk->kdarea+20, iplccw2, 8);
735 }
736 else
737 {
738 memcpy (datablk->kdarea+4, noiplpsw, 8);
739 memcpy (datablk->kdarea+12, noiplccw1, 8);
740 memcpy (datablk->kdarea+20, noiplccw2, 8);
741 }
742
743 keylen = IPL1_KEYLEN;
744 datalen = IPL1_DATALEN;
745
746 rc = write_block (cif, ofname, datablk, keylen, datalen,
747 devtype, heads, trklen, maxtrks,
748 &outusedv, &outusedr, &outtrkbr,
749 &outtrk, outcyl, outhead, &outrec);
750 if (rc < 0) return -1;
751
752 /* Build the IPL2 record */
753 memset (buf, 0, sizeof(buf));
754 datablk = (DATABLK*)buf;
755 convert_to_ebcdic (datablk->kdarea, 4, "IPL2");
756
757 if (iplfnm != NULL)
758 {
759 memcpy (datablk->kdarea+4, ipl2data, sizeof(ipl2data));
760 }
761
762 keylen = IPL2_KEYLEN;
763 datalen = IPL2_DATALEN;
764
765 rc = write_block (cif, ofname, datablk, keylen, datalen,
766 devtype, heads, trklen, maxtrks,
767 &outusedv, &outusedr, &outtrkbr,
768 &outtrk, outcyl, outhead, &outrec);
769 if (rc < 0) return -1;
770
771 /* Build the VOL1 record */
772 memset (buf, 0x40, sizeof(buf));
773 datablk = (DATABLK*)buf;
774 convert_to_ebcdic (datablk->kdarea, 4, "VOL1");
775 convert_to_ebcdic (datablk->kdarea+4, 4, "VOL1");
776 convert_to_ebcdic (datablk->kdarea+8, 6, volser);
777 memset(datablk->kdarea+15, 0, 5);
778 convert_to_ebcdic (datablk->kdarea+45, 8, "HERCULES");
779 keylen = VOL1_KEYLEN;
780 datalen = VOL1_DATALEN;
781
782 rc = write_block (cif, ofname, datablk, keylen, datalen,
783 devtype, heads, trklen, maxtrks,
784 &outusedv, &outusedr, &outtrkbr,
785 &outtrk, outcyl, outhead, &outrec);
786 if (rc < 0) return -1;
787
788 /* Build the IPL text from the object file */
789 if (iplfnm != NULL)
790 {
791 memset (buf, 0, sizeof(buf));
792 datalen = read_ipl_text (iplfnm, buf+12, sizeof(buf)-12);
793 if (datalen < 0) return -1;
794
795 datablk = (DATABLK*)buf;
796 keylen = 0;
797
798 rc = write_block (cif, ofname, datablk, keylen, datalen,
799 devtype, heads, trklen, maxtrks,
800 &outusedv, &outusedr, &outtrkbr,
801 &outtrk, outcyl, outhead, &outrec);
802 if (rc < 0) return -1;
803 }
804
805 /* Write track zero to the output file */
806 rc = write_track (cif, ofname, heads, trklen,
807 &outusedv, reltrk, outcyl, outhead);
808 if (rc < 0) return -1;
809
810 return 0;
811 } /* end function write_track_zero */
812
813 /*-------------------------------------------------------------------*/
814 /* Subroutine to update a data block in the output file */
815 /* Input: */
816 /* cif -> CKD image file descriptor */
817 /* ofname Output file name */
818 /* blk Pointer to data block structure */
819 /* cyl Cylinder number */
820 /* head Head number */
821 /* rec Record number */
822 /* keylen Key length */
823 /* datalen Data length */
824 /* heads Number of tracks per cylinder on output device */
825 /* trklen Track length of virtual output device */
826 /* Output: */
827 /* The return value is 0 if successful, -1 if error occurred. */
828 /*-------------------------------------------------------------------*/
829 static int
update_block(CIFBLK * cif,char * ofname,DATABLK * blk,int cyl,int head,int rec,int keylen,int datalen,int heads,int trklen)830 update_block (CIFBLK *cif, char *ofname, DATABLK *blk, int cyl,
831 int head, int rec, int keylen, int datalen, int heads, int trklen)
832 {
833 int rc; /* Return code */
834 int curcyl; /* Original cylinder */
835 int curhead; /* Original head */
836 int klen; /* Record key length */
837 int dlen; /* Record data length */
838 int skiplen; /* Number of bytes to skip */
839 int offset; /* Offset into trkbuf */
840 CKDDASD_TRKHDR trkhdr; /* Track header */
841 CKDDASD_RECHDR rechdr; /* Record header */
842
843 UNREFERENCED(heads);
844 UNREFERENCED(trklen);
845
846 /* Save the current position in the output file */
847 curcyl = cif->curcyl;
848 curhead = cif->curhead;
849
850 /* Read the requested track */
851 rc = read_track (cif, cyl, head);
852 if (rc < 0)
853 {
854 XMERRF ("HHCDL043E %s cyl %d head %d read error\n",
855 ofname, cyl, head);
856 return -1;
857 }
858
859 /* Copy the track header */
860 memcpy (&trkhdr, cif->trkbuf, CKDDASD_TRKHDR_SIZE);
861 offset = CKDDASD_TRKHDR_SIZE;
862
863 /* Validate the track header */
864 if (trkhdr.bin != 0
865 || trkhdr.cyl[0] != (cyl >> 8)
866 || trkhdr.cyl[1] != (cyl & 0xFF)
867 || trkhdr.head[0] != (head >> 8)
868 || trkhdr.head[1] != (head & 0xFF))
869 {
870 XMERRF ("HHCDL044E %s cyl %d head %d invalid track header "
871 "%2.2X%2.2X%2.2X%2.2X%2.2X\n",
872 ofname, cyl, head,
873 trkhdr.bin, trkhdr.cyl[0], trkhdr.cyl[1],
874 trkhdr.head[0], trkhdr.head[1]);
875 return -1;
876 }
877
878 /* Search for the record to be updated */
879 while (1)
880 {
881 /* Copy the next record header */
882 memcpy (&rechdr, cif->trkbuf + offset, CKDDASD_RECHDR_SIZE);
883 offset += CKDDASD_RECHDR_SIZE;
884
885 /* Check for end of track */
886 if (memcmp(&rechdr, eighthexFF, 8) == 0)
887 {
888 XMERRF ("HHCDL045E %s cyl %d head %d rec %d record not found\n",
889 ofname, cyl, head, rec);
890 return -1;
891 }
892
893 /* Extract record key length and data length */
894 klen = rechdr.klen;
895 dlen = (rechdr.dlen[0] << 8) | rechdr.dlen[1];
896
897 /* Exit loop if matching record number */
898 if (rechdr.rec == rec)
899 break;
900
901 /* Skip the key and data areas */
902 skiplen = klen + dlen;
903 offset += skiplen;
904 } /* end while */
905
906 /* Check for attempt to change key length or data length */
907 if (keylen != klen || datalen != dlen)
908 {
909 XMERRF ("HHCDL046E Cannot update cyl %d head %d rec %d: "
910 "Unmatched KL/DL\n",
911 cyl, head, rec);
912 return -1;
913 }
914
915 /* Copy the updated block to the trkbuf */
916 memcpy (cif->trkbuf + offset, blk->kdarea, keylen + datalen);
917 cif->trkmodif = 1;
918
919 /* Restore original track */
920 rc = read_track (cif, curcyl, curhead);
921 if (rc < 0)
922 {
923 XMERRF ("HHCDL047E %s cyl %d head %d read error\n",
924 ofname, curcyl, curhead);
925 return -1;
926 }
927
928 XMINFF (4, "HHCDL048I Updating cyl %u head %u rec %d kl %d dl %d\n",
929 cyl, head, rec, keylen, datalen);
930
931 return 0;
932 } /* end function update_block */
933
934 /*-------------------------------------------------------------------*/
935 /* Subroutine to build a format 1 DSCB */
936 /* Input: */
937 /* dscbtab Array of pointers to DSCB data blocks */
938 /* dscbnum Number of entries in dscbtab array */
939 /* dsname Dataset name (ASCIIZ) */
940 /* volser Volume serial number (ASCIIZ) */
941 /* dsorg 1st byte of dataset organization bits */
942 /* recfm 1st byte of record format bits */
943 /* lrecl Logical record length */
944 /* blksz Block size */
945 /* keyln Key length */
946 /* dirblu Bytes used in last directory block */
947 /* lasttrk Relative track number of last-used track of dataset */
948 /* lastrec Record number of last-used block of dataset */
949 /* trkbal Bytes remaining on last-used track */
950 /* units Allocation units (C=CYL, T=TRK) */
951 /* spsec Secondary allocation quantity */
952 /* bcyl Extent begin cylinder number */
953 /* bhead Extent begin head number */
954 /* ecyl Extent end cylinder number */
955 /* ehead Extent end head number */
956 /* Output: */
957 /* The return value is 0 if successful, or -1 if error */
958 /* */
959 /* This subroutine allocates a DATABLK structure, builds a DSCB */
960 /* within the structure, and adds the structure to the DSCB array. */
961 /*-------------------------------------------------------------------*/
962 static int
build_format1_dscb(DATABLK * dscbtab[],int dscbnum,char * dsname,char * volser,BYTE dsorg,BYTE recfm,int lrecl,int blksz,int keyln,int dirblu,int lasttrk,int lastrec,int trkbal,BYTE units,int spsec,int bcyl,int bhead,int ecyl,int ehead)963 build_format1_dscb (DATABLK *dscbtab[], int dscbnum,
964 char *dsname, char *volser,
965 BYTE dsorg, BYTE recfm, int lrecl, int blksz,
966 int keyln, int dirblu, int lasttrk, int lastrec,
967 int trkbal, BYTE units, int spsec,
968 int bcyl, int bhead, int ecyl, int ehead)
969 {
970 DATABLK *datablk; /* -> Data block structure */
971 FORMAT1_DSCB *f1dscb; /* -> DSCB within data block */
972 int blklen; /* Size of data block */
973 struct tm *tmptr; /* -> Date and time structure*/
974 time_t timeval; /* Current time value */
975
976 /* Obtain the current time */
977 time(&timeval);
978 tmptr = localtime(&timeval);
979
980 /* Allocate storage for a DATABLK structure */
981 blklen = 12 + sizeof(FORMAT1_DSCB);
982 datablk = (DATABLK*)malloc(blklen);
983 if (datablk == NULL)
984 {
985 XMERRF ("HHCDL049E Cannot obtain storage for DSCB: %s\n",
986 strerror(errno));
987 return -1;
988 }
989
990 /* Check that there is room in the DSCB pointer array */
991 if (dscbnum >= MAXDSCB)
992 {
993 XMERRF ("HHCDL050E DSCB count exceeds %d, increase MAXDSCB\n",
994 MAXDSCB);
995 return -1;
996 }
997
998 /* Clear the data block and save its address in the DSCB array */
999 memset (datablk, 0, blklen);
1000 dscbtab[dscbnum] = datablk;
1001
1002 /* Point to the DSCB within the data block */
1003 f1dscb = (FORMAT1_DSCB*)(datablk->kdarea);
1004
1005 /* Build the format 1 DSCB */
1006 convert_to_ebcdic (f1dscb->ds1dsnam, 44, dsname);
1007 f1dscb->ds1fmtid = 0xF1;
1008 convert_to_ebcdic (f1dscb->ds1dssn, 6, volser);
1009 f1dscb->ds1volsq[0] = 0;
1010 f1dscb->ds1volsq[1] = 1;
1011 f1dscb->ds1credt[0] = tmptr->tm_year;
1012 f1dscb->ds1credt[1] = (tmptr->tm_yday >> 8) & 0xFF;
1013 f1dscb->ds1credt[2] = tmptr->tm_yday & 0xFF;
1014 f1dscb->ds1expdt[0] = 0;
1015 f1dscb->ds1expdt[1] = 0;
1016 f1dscb->ds1expdt[2] = 0;
1017 f1dscb->ds1noepv = 1;
1018 f1dscb->ds1bodbd = dirblu;
1019 convert_to_ebcdic (f1dscb->ds1syscd, 13, "HERCULES");
1020 f1dscb->ds1dsorg[0] = dsorg;
1021 f1dscb->ds1dsorg[1] = 0;
1022 f1dscb->ds1recfm = recfm;
1023 f1dscb->ds1optcd = 0;
1024 f1dscb->ds1blkl[0] = (blksz >> 8) & 0xFF;
1025 f1dscb->ds1blkl[1] = blksz & 0xFF;
1026 f1dscb->ds1lrecl[0] = (lrecl >> 8) & 0xFF;
1027 f1dscb->ds1lrecl[1] = lrecl & 0xFF;
1028 f1dscb->ds1keyl = keyln;
1029 f1dscb->ds1rkp[0] = 0;
1030 f1dscb->ds1rkp[1] = 0;
1031 f1dscb->ds1dsind = DS1DSIND_LASTVOL;
1032 if ((blksz & 0x07) == 0)
1033 f1dscb->ds1dsind |= DS1DSIND_BLKSIZ8;
1034 f1dscb->ds1scalo[0] =
1035 (units == 'C' ? DS1SCALO_UNITS_CYL : DS1SCALO_UNITS_TRK);
1036 f1dscb->ds1scalo[1] = (spsec >> 16) & 0xFF;
1037 f1dscb->ds1scalo[2] = (spsec >> 8) & 0xFF;
1038 f1dscb->ds1scalo[3] = spsec & 0xFF;
1039 f1dscb->ds1lstar[0] = (lasttrk >> 8) & 0xFF;
1040 f1dscb->ds1lstar[1] = lasttrk & 0xFF;
1041 f1dscb->ds1lstar[2] = lastrec;
1042 f1dscb->ds1trbal[0] = (trkbal >> 8) & 0xFF;
1043 f1dscb->ds1trbal[1] = trkbal & 0xFF;
1044 f1dscb->ds1ext1.xttype =
1045 (units == 'C' ? XTTYPE_CYLBOUND : XTTYPE_DATA);
1046 f1dscb->ds1ext1.xtseqn = 0;
1047 f1dscb->ds1ext1.xtbcyl[0] = (bcyl >> 8) & 0xFF;
1048 f1dscb->ds1ext1.xtbcyl[1] = bcyl & 0xFF;
1049 f1dscb->ds1ext1.xtbtrk[0] = (bhead >> 8) & 0xFF;
1050 f1dscb->ds1ext1.xtbtrk[1] = bhead & 0xFF;
1051 f1dscb->ds1ext1.xtecyl[0] = (ecyl >> 8) & 0xFF;
1052 f1dscb->ds1ext1.xtecyl[1] = ecyl & 0xFF;
1053 f1dscb->ds1ext1.xtetrk[0] = (ehead >> 8) & 0xFF;
1054 f1dscb->ds1ext1.xtetrk[1] = ehead & 0xFF;
1055
1056 return 0;
1057 } /* end function build_format1_dscb */
1058
1059 /*-------------------------------------------------------------------*/
1060 /* Subroutine to build a format 4 DSCB */
1061 /* Input: */
1062 /* dscbtab Array of pointers to DSCB data blocks */
1063 /* dscbnum Number of entries in dscbtab array */
1064 /* devtype Output device type */
1065 /* Output: */
1066 /* The return value is 0 if successful, or -1 if error */
1067 /* */
1068 /* This subroutine allocates a DATABLK structure, builds a DSCB */
1069 /* within the structure, and adds the structure to the DSCB array. */
1070 /* */
1071 /* Note: The VTOC extent descriptor, the highest F1 DSCB address, */
1072 /* and the number of unused DSCBs, are set to zeroes here and must */
1073 /* be updated later when the VTOC size and location are known. */
1074 /* The device size in cylinders is set to the normal size for the */
1075 /* device type and must be updated when the actual total number of */
1076 /* cylinders written to the volume is known. */
1077 /*-------------------------------------------------------------------*/
1078 static int
build_format4_dscb(DATABLK * dscbtab[],int dscbnum,CIFBLK * cif)1079 build_format4_dscb (DATABLK *dscbtab[], int dscbnum, CIFBLK *cif)
1080 {
1081 DATABLK *datablk; /* -> Data block structure */
1082 FORMAT4_DSCB *f4dscb; /* -> DSCB within data block */
1083 int blklen; /* Size of data block */
1084 int numdscb; /* Number of DSCBs per track */
1085 int numdblk; /* Number of dir blks/track */
1086 int physlen; /* Physical track length */
1087 int numcyls; /* Device size in cylinders */
1088 int numheads; /* Number of heads/cylinder */
1089 int kbconst; /* Keyed block constant */
1090 int lbconst; /* Last keyed block constant */
1091 int nkconst; /* Non-keyed block constant */
1092 BYTE devflag; /* Device flags for VTOC */
1093 int tolfact; /* Device tolerance */
1094
1095 /* Calculate the physical track length, block overheads, device
1096 size, and the number of DSCBs and directory blocks per track */
1097 capacity_calc (cif, 0, 44, 96, NULL, NULL, &physlen, &kbconst,
1098 &lbconst, &nkconst, &devflag, &tolfact, NULL,
1099 &numdscb, &numheads, &numcyls);
1100 capacity_calc (cif, 0, 8, 256, NULL, NULL, NULL,
1101 NULL, NULL, NULL, NULL, NULL, NULL,
1102 &numdblk, NULL, NULL);
1103
1104 /* Allocate storage for a DATABLK structure */
1105 blklen = 12 + sizeof(FORMAT4_DSCB);
1106 datablk = (DATABLK*)malloc(blklen);
1107 if (datablk == NULL)
1108 {
1109 XMERRF ("HHCDL051E Cannot obtain storage for DSCB: %s\n",
1110 strerror(errno));
1111 return -1;
1112 }
1113
1114 /* Check that there is room in the DSCB pointer array */
1115 if (dscbnum >= MAXDSCB)
1116 {
1117 XMERRF ("HHCDL052E DSCB count exceeds %d, increase MAXDSCB\n",
1118 MAXDSCB);
1119 return -1;
1120 }
1121
1122 /* Clear the data block and save its address in the DSCB array */
1123 memset (datablk, 0, blklen);
1124 dscbtab[dscbnum] = datablk;
1125
1126 /* Point to the DSCB within the data block */
1127 f4dscb = (FORMAT4_DSCB*)(datablk->kdarea);
1128
1129 /* Build the format 4 DSCB */
1130 memset (f4dscb->ds4keyid, 0x04, 44);
1131 f4dscb->ds4fmtid = 0xF4;
1132 f4dscb->ds4hcchh[0] = (numcyls >> 8) & 0xFF;
1133 f4dscb->ds4hcchh[1] = numcyls & 0xFF;
1134 f4dscb->ds4hcchh[2] = 0;
1135 f4dscb->ds4hcchh[3] = 0;
1136 f4dscb->ds4noatk[0] = 0;
1137 f4dscb->ds4noatk[1] = 0;
1138 f4dscb->ds4vtoci = DS4VTOCI_DOS;
1139 f4dscb->ds4noext = 1;
1140 f4dscb->ds4devsz[0] = (numcyls >> 8) & 0xFF;
1141 f4dscb->ds4devsz[1] = numcyls & 0xFF;
1142 f4dscb->ds4devsz[2] = (numheads >> 8) & 0xFF;
1143 f4dscb->ds4devsz[3] = numheads & 0xFF;
1144 f4dscb->ds4devtk[0] = (physlen >> 8) & 0xFF;
1145 f4dscb->ds4devtk[1] = physlen & 0xFF;
1146 f4dscb->ds4devi = kbconst;
1147 f4dscb->ds4devl = lbconst;
1148 f4dscb->ds4devk = nkconst;
1149 f4dscb->ds4devfg = devflag;
1150 f4dscb->ds4devtl[0] = (tolfact >> 8) & 0xFF;
1151 f4dscb->ds4devtl[1] = tolfact & 0xFF;
1152 f4dscb->ds4devdt = numdscb;
1153 f4dscb->ds4devdb = numdblk;
1154
1155 return 0;
1156 } /* end function build_format4_dscb */
1157
1158 /*-------------------------------------------------------------------*/
1159 /* Subroutine to build a format 5 DSCB */
1160 /* Input: */
1161 /* dscbtab Array of pointers to DSCB data blocks */
1162 /* dscbnum Number of entries in dscbtab array */
1163 /* Output: */
1164 /* The return value is 0 if successful, or -1 if error */
1165 /* */
1166 /* This subroutine allocates a DATABLK structure, builds a DSCB */
1167 /* within the structure, and adds the structure to the DSCB array. */
1168 /* */
1169 /* Note: The format 5 DSCB is built with no free space extents. */
1170 /* The DOS bit which is set in ds4vtoci forces the operating system */
1171 /* VTOC conversion routine to calculate the free space and update */
1172 /* the format 5 DSCB the first time the volume is accessed. */
1173 /*-------------------------------------------------------------------*/
1174 static int
build_format5_dscb(DATABLK * dscbtab[],int dscbnum)1175 build_format5_dscb (DATABLK *dscbtab[], int dscbnum)
1176 {
1177 DATABLK *datablk; /* -> Data block structure */
1178 FORMAT5_DSCB *f5dscb; /* -> DSCB within data block */
1179 int blklen; /* Size of data block */
1180
1181 /* Allocate storage for a DATABLK structure */
1182 blklen = 12 + sizeof(FORMAT5_DSCB);
1183 datablk = (DATABLK*)malloc(blklen);
1184 if (datablk == NULL)
1185 {
1186 XMERRF ("HHCDL053E Cannot obtain storage for DSCB: %s\n",
1187 strerror(errno));
1188 return -1;
1189 }
1190
1191 /* Check that there is room in the DSCB pointer array */
1192 if (dscbnum >= MAXDSCB)
1193 {
1194 XMERRF ("HHCDL054E DSCB count exceeds %d, increase MAXDSCB\n",
1195 MAXDSCB);
1196 return -1;
1197 }
1198
1199 /* Clear the data block and save its address in the DSCB array */
1200 memset (datablk, 0, blklen);
1201 dscbtab[dscbnum] = datablk;
1202
1203 /* Point to the DSCB within the data block */
1204 f5dscb = (FORMAT5_DSCB*)(datablk->kdarea);
1205
1206 /* Build the format 5 DSCB */
1207 memset (f5dscb->ds5keyid, 0x05, 4);
1208 f5dscb->ds5fmtid = 0xF5;
1209
1210 return 0;
1211 } /* end function build_format5_dscb */
1212
1213 /*-------------------------------------------------------------------*/
1214 /* Subroutine to write the VTOC */
1215 /* Input: */
1216 /* dscbtab Array of pointers to DSCB data blocks */
1217 /* numdscb Number of DSCBs including format 4 and format 5 */
1218 /* cif -> CKD image file descriptor */
1219 /* ofname Output file name */
1220 /* devtype Output device type */
1221 /* reqcyls Requested device size in cylinders, or zero */
1222 /* heads Number of tracks per cylinder on output device */
1223 /* trklen Track length of virtual output device */
1224 /* vtoctrk Starting relative track number for VTOC, or zero */
1225 /* vtocext Number of tracks in VTOC, or zero */
1226 /* Input/output: */
1227 /* nxtcyl Starting cylinder number for next dataset */
1228 /* nxthead Starting head number for next dataset */
1229 /* Output: */
1230 /* volvtoc VTOC starting CCHHR (5 bytes) */
1231 /* The return value is 0 if successful, or -1 if error */
1232 /* */
1233 /* If vtoctrk and vtocext are non-zero, then the VTOC is written */
1234 /* into the space previously reserved at the indicated location. */
1235 /* Otherwise, the VTOC is written at the next available dataset */
1236 /* location, using as many tracks as are necessary, and nextcyl */
1237 /* and nexthead are updated to point past the end of the VTOC. */
1238 /*-------------------------------------------------------------------*/
1239 static int
write_vtoc(DATABLK * dscbtab[],int numdscb,CIFBLK * cif,char * ofname,U16 devtype,int reqcyls,int heads,int trklen,int vtoctrk,int vtocext,int * nxtcyl,int * nxthead,BYTE volvtoc[])1240 write_vtoc (DATABLK *dscbtab[], int numdscb, CIFBLK *cif, char *ofname,
1241 U16 devtype, int reqcyls, int heads, int trklen,
1242 int vtoctrk, int vtocext,
1243 int *nxtcyl, int *nxthead, BYTE volvtoc[])
1244 {
1245 int rc; /* Return code */
1246 int i; /* Array subscript */
1247 DATABLK *datablk; /* -> Data block structure */
1248 FORMAT1_DSCB *f1dscb; /* -> Format 1 DSCB */
1249 FORMAT4_DSCB *f4dscb; /* -> Format 4 DSCB */
1250 int dscbpertrk; /* Number of DSCBs per track */
1251 int mintrks; /* Minimum VTOC size (tracks)*/
1252 int numtrks; /* Actual VTOC size (tracks) */
1253 int highcyl; /* Last used cylinder number */
1254 int highhead; /* Last used head number */
1255 int highrec; /* Last used record number */
1256 int numf0dscb; /* Number of unused DSCBs */
1257 int abstrk; /* Absolute track number */
1258 int endcyl; /* VTOC end cylinder number */
1259 int endhead; /* VTOC end head number */
1260 int numcyls; /* Volume size in cylinders */
1261 int outusedv = 0; /* Bytes used in track buffer*/
1262 int outusedr = 0; /* Bytes used on real track */
1263 int outtrkbr; /* Bytes left on real track */
1264 int outcyl; /* Output cylinder number */
1265 int outhead; /* Output head number */
1266 int outtrk = 0; /* Relative track number */
1267 int outrec = 0; /* Output record number */
1268 int prealloc = 0; /* 1=VTOC is preallocated */
1269 BYTE blankblk[152]; /* Data block for blank DSCB */
1270 int curcyl; /* Current cylinder in file */
1271 int curhead; /* Current head in file */
1272 char dsnama[45]; /* Dataset name (ASCIIZ) */
1273
1274 /* Determine if the VTOC is preallocated */
1275 prealloc = (vtoctrk != 0 && vtocext != 0);
1276
1277 /* Point to the format 4 DSCB within the first data block */
1278 f4dscb = (FORMAT4_DSCB*)(dscbtab[0]->kdarea);
1279
1280 /* Calculate the minimum number of tracks required for the VTOC */
1281 dscbpertrk = f4dscb->ds4devdt;
1282 mintrks = (numdscb + dscbpertrk - 1) / dscbpertrk;
1283
1284 /* Save the current position in the output file */
1285 curcyl = cif->curcyl;
1286 curhead = cif->curhead;
1287
1288 /* Obtain the VTOC starting location and size */
1289 if (prealloc)
1290 {
1291 /* Use preallocated VTOC location */
1292 outcyl = vtoctrk / heads;
1293 outhead = vtoctrk % heads;
1294 numtrks = vtocext;
1295 }
1296 else
1297 {
1298 /* Use next available dataset location for VTOC */
1299 outcyl = *nxtcyl;
1300 outhead = *nxthead;
1301 numtrks = mintrks;
1302 }
1303
1304 /* Check that VTOC extent size is sufficient */
1305 if (numtrks < mintrks)
1306 {
1307 XMERRF ("HHCDL055E VTOC too small, %d track%s required\n",
1308 mintrks, (mintrks == 1 ? "" : "s"));
1309 return -1;
1310 }
1311
1312 /* Read the first track of the VTOC */
1313 rc = read_track (cif, outcyl, outhead);
1314 if (rc < 0)
1315 {
1316 XMERRF ("HHCDL056E Error reading VTOC cyl %d head %d\n",
1317 outcyl, outhead);
1318 return -1;
1319 }
1320
1321 /* Calculate the CCHHR of the last format 1 DSCB */
1322 abstrk = (outcyl * heads) + outhead;
1323 abstrk += mintrks - 1;
1324 highcyl = abstrk / heads;
1325 highhead = abstrk % heads;
1326 highrec = ((numdscb - 1) % dscbpertrk) + 1;
1327
1328 /* Update the last format 1 CCHHR in the format 4 DSCB */
1329 f4dscb->ds4hpchr[0] = (highcyl >> 8) & 0xFF;
1330 f4dscb->ds4hpchr[1] = highcyl & 0xFF;
1331 f4dscb->ds4hpchr[2] = (highhead >> 8) & 0xFF;
1332 f4dscb->ds4hpchr[3] = highhead & 0xFF;
1333 f4dscb->ds4hpchr[4] = highrec;
1334
1335 /* Build the VTOC start CCHHR */
1336 volvtoc[0] = (outcyl >> 8) & 0xFF;
1337 volvtoc[1] = outcyl & 0xFF;
1338 volvtoc[2] = (outhead >> 8) & 0xFF;
1339 volvtoc[3] = outhead & 0xFF;
1340 volvtoc[4] = 1;
1341
1342 XMINFF (1, "HHCDL057I VTOC starts at cyl %d head %d and is %d track%s\n",
1343 outcyl, outhead, numtrks, (numtrks == 1 ? "" : "s"));
1344
1345 /* Calculate the number of format 0 DSCBs required to
1346 fill out the unused space at the end of the VTOC */
1347 numf0dscb = (numtrks * dscbpertrk) - numdscb;
1348
1349 /* Update the format 0 DSCB count in the format 4 DSCB */
1350 f4dscb->ds4dsrec[0] = (numf0dscb >> 8) & 0xFF;
1351 f4dscb->ds4dsrec[1] = numf0dscb & 0xFF;
1352
1353 /* Calculate the CCHH of the last track of the VTOC */
1354 abstrk = (outcyl * heads) + outhead;
1355 abstrk += numtrks - 1;
1356 endcyl = abstrk / heads;
1357 endhead = abstrk % heads;
1358
1359 /* Update the VTOC extent descriptor in the format 4 DSCB */
1360 f4dscb->ds4vtoce.xttype =
1361 (endhead == heads - 1 ? XTTYPE_CYLBOUND : XTTYPE_DATA);
1362 f4dscb->ds4vtoce.xtseqn = 0;
1363 f4dscb->ds4vtoce.xtbcyl[0] = (outcyl >> 8) & 0xFF;
1364 f4dscb->ds4vtoce.xtbcyl[1] = outcyl & 0xFF;
1365 f4dscb->ds4vtoce.xtbtrk[0] = (outhead >> 8) & 0xFF;
1366 f4dscb->ds4vtoce.xtbtrk[1] = outhead & 0xFF;
1367 f4dscb->ds4vtoce.xtecyl[0] = (endcyl >> 8) & 0xFF;
1368 f4dscb->ds4vtoce.xtecyl[1] = endcyl & 0xFF;
1369 f4dscb->ds4vtoce.xtetrk[0] = (endhead >> 8) & 0xFF;
1370 f4dscb->ds4vtoce.xtetrk[1] = endhead & 0xFF;
1371
1372 /* Calculate the mimimum volume size */
1373 if (prealloc)
1374 {
1375 /* The VTOC was preallocated, so the minimum volume
1376 size equals the next available cylinder number */
1377 numcyls = *nxtcyl;
1378 if (*nxthead != 0) numcyls++;
1379 }
1380 else
1381 {
1382 /* The VTOC will be written into the available space,
1383 so the minimum volume size is one more than the
1384 ending cylinder number of the VTOC */
1385 numcyls = endcyl + 1;
1386 }
1387
1388 /* If the minimum volume size is less than the requested
1389 size then use the requested size as the actual size */
1390 if (numcyls < reqcyls) numcyls = reqcyls;
1391
1392 /* Update the volume size in cylinders in the format 4 DSCB */
1393 f4dscb->ds4devsz[0] = (numcyls >> 8) & 0xFF;
1394 f4dscb->ds4devsz[1] = numcyls & 0xFF;
1395
1396 /* Format the track buffer */
1397 init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv);
1398 cif->trkmodif = 1;
1399
1400 /* Write the format 4, format 5, and format 1 DSCBs to the VTOC */
1401 for (i = 0; i < numdscb; i++)
1402 {
1403 /* Load the data block pointer from the DSCB table */
1404 datablk = dscbtab[i];
1405
1406 /* Extract the dataset name from the format 1 DSCB */
1407 memset (dsnama, 0, sizeof(dsnama));
1408 f1dscb = (FORMAT1_DSCB*)(datablk->kdarea);
1409 if (f1dscb->ds1fmtid == 0xF1)
1410 {
1411 make_asciiz (dsnama, sizeof(dsnama), f1dscb->ds1dsnam,
1412 sizeof(f1dscb->ds1dsnam));
1413 }
1414
1415 /* Add next DSCB to the track buffer */
1416 rc = write_block (cif, ofname, datablk, 44, 96,
1417 devtype, heads, trklen, numtrks,
1418 &outusedv, &outusedr, &outtrkbr,
1419 &outtrk, &outcyl, &outhead, &outrec);
1420 if (rc < 0) return -1;
1421
1422 XMINFF (4, "HHCDL058I Format %d DSCB CCHHR=%4.4X%4.4X%2.2X "
1423 "(TTR=%4.4X%2.2X) %s\n",
1424 datablk->kdarea[0] == 0x04 ? 4 :
1425 datablk->kdarea[0] == 0x05 ? 5 : 1,
1426 outcyl, outhead, outrec, outtrk, outrec, dsnama);
1427 if (infolvl >= 5) data_dump (datablk, 152);
1428
1429 } /* end for(i) */
1430
1431 /* Fill the remainder of the VTOC with format 0 DSCBs */
1432 for (i = 0; i < numf0dscb; i++)
1433 {
1434 /* Add a format 0 DSCB to the track buffer */
1435 memset (blankblk, 0, sizeof(blankblk));
1436 datablk = (DATABLK*)blankblk;
1437 rc = write_block (cif, ofname, datablk, 44, 96,
1438 devtype, heads, trklen, numtrks,
1439 &outusedv, &outusedr, &outtrkbr,
1440 &outtrk, &outcyl, &outhead, &outrec);
1441 if (rc < 0) return -1;
1442
1443 XMINFF (4, "HHCDL059I Format 0 DSCB CCHHR=%4.4X%4.4X%2.2X "
1444 "(TTR=%4.4X%2.2X)\n",
1445 outcyl, outhead, outrec, outtrk, outrec);
1446
1447 } /* end for(i) */
1448
1449 /* Write data remaining in last track buffer */
1450 rc = write_track (cif, ofname, heads, trklen,
1451 &outusedv, &outtrk, &outcyl, &outhead);
1452 if (rc < 0) return -1;
1453
1454 /* Restore original file position if VTOC was preallocated */
1455 if (prealloc)
1456 {
1457 /* Read the original track again */
1458 rc = read_track (cif, curcyl, curhead);
1459 if (rc < 0)
1460 {
1461 XMERRF ("HHCDL060E Error reading track cyl %d head %d\n",
1462 curcyl, curhead);
1463 return -1;
1464 }
1465 }
1466 else
1467 {
1468 /* Update next cyl and head if VTOC not preallocated */
1469 *nxtcyl = outcyl;
1470 *nxthead = outhead;
1471 }
1472
1473 return 0;
1474 } /* end function write_vtoc */
1475
1476 /*-------------------------------------------------------------------*/
1477 /* Subroutine to return the name of a text unit */
1478 /*-------------------------------------------------------------------*/
1479 static char *
tu_name(U16 key)1480 tu_name (U16 key)
1481 {
1482 switch (key) {
1483 CASERET(INMDDNAM);
1484 CASERET(INMDSNAM);
1485 CASERET(INMMEMBR);
1486 CASERET(INMDIR );
1487 CASERET(INMEXPDT);
1488 CASERET(INMTERM );
1489 CASERET(INMBLKSZ);
1490 CASERET(INMDSORG);
1491 CASERET(INMLRECL);
1492 CASERET(INMRECFM);
1493 CASERET(INMTNODE);
1494 CASERET(INMTUID );
1495 CASERET(INMFNODE);
1496 CASERET(INMFUID );
1497 CASERET(INMLREF );
1498 CASERET(INMLCHG );
1499 CASERET(INMCREAT);
1500 CASERET(INMFVERS);
1501 CASERET(INMFTIME);
1502 CASERET(INMTTIME);
1503 CASERET(INMFACK );
1504 CASERET(INMERRCD);
1505 CASERET(INMUTILN);
1506 CASERET(INMUSERP);
1507 CASERET(INMRECCT);
1508 CASERET(INMSIZE );
1509 CASERET(INMFFM );
1510 CASERET(INMNUMF );
1511 CASERET(INMTYPE );
1512 } /* end switch(key) */
1513
1514 return "????????";
1515
1516 } /* end function tu_name */
1517
1518 /*-------------------------------------------------------------------*/
1519 /* Subroutine to extract next text unit from buffer */
1520 /* Input: */
1521 /* xbuf Pointer to start of buffer */
1522 /* bufpos Position of next text unit within buffer */
1523 /* bufrem Number of bytes remaining in buffer */
1524 /* pkey Pointer to field to receive text unit key */
1525 /* pnum Pointer to field to receive number of data items */
1526 /* maxnum Maximum number of data items expected */
1527 /* plen Pointer to array to receive data item lengths */
1528 /* pdata Pointer to array to receive data item pointers */
1529 /* Output: */
1530 /* The function return value is the total length of the */
1531 /* text unit, or -1 if error. */
1532 /* */
1533 /* Text units are listed if infolvl is 4 or greater. */
1534 /*-------------------------------------------------------------------*/
1535 static int
next_tu(BYTE * xbuf,int bufpos,int bufrem,U16 * pkey,U16 * pnum,U16 maxnum,U16 plen[],BYTE * pdata[])1536 next_tu (BYTE *xbuf, int bufpos, int bufrem, U16 *pkey, U16 *pnum,
1537 U16 maxnum, U16 plen[], BYTE *pdata[])
1538 {
1539 int i, j; /* Array subscripts */
1540 U16 key, num; /* Text unit header */
1541 int field; /* Field number */
1542 int offset; /* Offset into text unit */
1543 U16 len; /* Field length */
1544 char *name; /* Text unit name */
1545 BYTE c, chars[9]; /* Character work areas */
1546 char hex[17]; /* Character work areas */
1547
1548 set_codepage(NULL);
1549
1550 /* Error if remaining length is insufficient for header */
1551 if (bufrem < 4)
1552 {
1553 XMERR ("HHCDL061E Incomplete text unit\n");
1554 return -1;
1555 }
1556
1557 /* Load the key and field count from the first 4 bytes */
1558 key = (xbuf[bufpos] << 8) | xbuf[bufpos+1];
1559 num = (xbuf[bufpos+2] << 8) | xbuf[bufpos+3];
1560
1561 /* Obtain the text unit name */
1562 name = tu_name(key);
1563
1564 /* Print the text unit name and field count */
1565 XMINFF (4, "HHCDL062I \t+%4.4X %-8.8s %4.4X %4.4X ",
1566 bufpos, name, key, num);
1567
1568 /* Error if number of fields exceeds maximum */
1569 if (num > maxnum)
1570 {
1571 XMINF (4, "\n");
1572 XMERR ("HHCDL063E Too many fields in text unit\n");
1573 return -1;
1574 }
1575
1576 /* Point to first field */
1577 offset = 4;
1578 bufrem -= 4;
1579
1580 /* Process each field in text unit */
1581 for (field = 0; field < num; field++)
1582 {
1583 /* Error if remaining length is insufficient for length */
1584 if (bufrem < 2)
1585 {
1586 XMINF (4, "\n");
1587 XMERR ("HHCDL064E Incomplete text unit\n");
1588 return -1;
1589 }
1590
1591 /* Load field length from next 2 bytes */
1592 len = (xbuf[bufpos+offset] << 8) | xbuf[bufpos+offset+1];
1593 offset += 2;
1594 bufrem -= 2;
1595
1596 /* Error if remaining length is insufficient for data */
1597 if (bufrem < len)
1598 {
1599 XMINF (4, "\n");
1600 XMERR ("HHCDL065E Incomplete text unit\n");
1601 return -1;
1602 }
1603
1604 /* Print field length and data */
1605 if (field > 0) XMINF (4, "\n\t\t\t\t ");
1606 XMINFF (4, "%4.4X ", len);
1607 memset (hex, '\0', sizeof(hex));
1608 memset (chars, '\0', sizeof(chars));
1609 for (i = 0, j = 0; i < len; i++, j++)
1610 {
1611 if (i > 0 && (i & 0x07) == 0)
1612 {
1613 XMINFF (4, "%-16.16s %-8.8s\n\t\t\t\t ",
1614 hex, chars);
1615 memset (hex, '\0', sizeof(hex));
1616 memset (chars, '\0', sizeof(chars));
1617 j = 0;
1618 }
1619 sprintf(hex+2*j, "%2.2X", xbuf[bufpos+offset+i]);
1620 c = guest_to_host(xbuf[bufpos+offset+i]);
1621 if (!isprint(c)) c = '.';
1622 chars[j] = c;
1623 } /* end for(i) */
1624 XMINFF (4, "%-16.16s %-8.8s", hex, chars);
1625
1626 /* Save field length and pointer in array */
1627 plen[field] = len;
1628 pdata[field] = xbuf + bufpos + offset;
1629
1630 /* Get offset of next field in text unit */
1631 offset += len;
1632 bufrem -= len;
1633
1634 } /* end for */
1635
1636 /* Print newline at end of text unit */
1637 XMINF (4, "\n");
1638
1639 /* Return key, number of fields, and total length */
1640 *pkey = key;
1641 *pnum = num;
1642 return offset;
1643
1644 } /* end function next_tu */
1645
1646 /*-------------------------------------------------------------------*/
1647 /* Subroutine to assemble a logical record from segments */
1648 /* Input: */
1649 /* xfd Input file descriptor */
1650 /* xfname Input file name */
1651 /* xbuf Pointer to buffer to receive logical record */
1652 /* Output: */
1653 /* ctl Zero=data record, non-zero=control record */
1654 /* The return value is the logical record length, */
1655 /* or -1 if an error occurred. */
1656 /*-------------------------------------------------------------------*/
1657 static int
read_xmit_rec(int xfd,char * xfname,BYTE * xbuf,BYTE * ctl)1658 read_xmit_rec (int xfd, char *xfname, BYTE *xbuf, BYTE *ctl)
1659 {
1660 int rc; /* Return code */
1661 int xreclen = 0; /* Cumulative record length */
1662 int segnum; /* Segment counter */
1663 int seglen; /* Segment data length */
1664 BYTE ctlind = 0x00; /* 0x20=Control record */
1665 BYTE seghdr[2]; /* Segment length and flags */
1666
1667 for (segnum = 0; ; segnum++)
1668 {
1669 /* Read the segment length and flags */
1670 rc = read (xfd, seghdr, 2);
1671 if (rc < 2)
1672 {
1673 XMERRF ("HHCDL066E %s read error: %s\n",
1674 xfname,
1675 (rc < 0 ? strerror(errno) :
1676 "Unexpected end of file"));
1677 return -1;
1678 }
1679
1680 /* Check for valid segment header */
1681 if (seghdr[0] < 2 || (seghdr[1] & 0x1F) != 0)
1682 {
1683 XMERRF ("HHCDL067E %s invalid segment header: %2.2X%2.2X\n",
1684 xfname, seghdr[0], seghdr[1]);
1685 return -1;
1686 }
1687
1688 /* Check flags for first segment */
1689 if (segnum == 0)
1690 {
1691 /* Check that first segment indicator is set */
1692 if ((seghdr[1] & 0x80) == 0)
1693 {
1694 XMERRF ("HHCDL068E %s first segment indicator expected\n",
1695 xfname);
1696 return -1;
1697 }
1698
1699 /* Save the control record indicator */
1700 ctlind = (seghdr[1] & 0x20);
1701 }
1702
1703 /* Check flags for subsequent segments */
1704 if (segnum > 0)
1705 {
1706 /* Check that first segment indicator is not set */
1707 if (seghdr[1] & 0x80)
1708 {
1709 XMERRF ("HHCDL069E %s first segment indicator not expected\n",
1710 xfname);
1711 return -1;
1712 }
1713
1714 /* Check if ctlrec indicator matches first segment */
1715 if ((seghdr[1] & 0x20) != ctlind)
1716 {
1717 XMERRF ("HHCDL070E %s control record indicator mismatch\n",
1718 xfname);
1719 return -1;
1720 }
1721 }
1722
1723 /* Read segment data into buffer */
1724 seglen = seghdr[0] - 2;
1725 rc = read (xfd, xbuf + xreclen, seglen);
1726 if (rc < seglen)
1727 {
1728 XMERRF ("HHCDL071E %s read error: %s\n",
1729 xfname,
1730 (rc < 0 ? strerror(errno) :
1731 "Unexpected end of file"));
1732 return -1;
1733 }
1734
1735 /* Accumulate total record length */
1736 xreclen += seglen;
1737
1738 /* Exit if last segment of record */
1739 if (seghdr[1] & 0x40)
1740 break;
1741
1742 } /* end for(segnum) */
1743
1744 /* Return record length and control indicator */
1745 *ctl = ctlind;
1746 return xreclen;
1747
1748 } /* end function read_xmit_rec */
1749
1750 /*-------------------------------------------------------------------*/
1751 /* Subroutine to assemble a logical record from DSORG=VS file */
1752 /* Input: */
1753 /* xfd Input file descriptor */
1754 /* xfname Input file name */
1755 /* xbuf Pointer to buffer to receive logical record */
1756 /* recnum Relative number for the record to be read */
1757 /* Output: */
1758 /* The return value is the logical record length, */
1759 /* or -1 if an error occurred. */
1760 /*-------------------------------------------------------------------*/
1761 static int
read_vs_rec(int xfd,char * xfname,BYTE * xbuf,int recnum)1762 read_vs_rec (int xfd, char *xfname, BYTE *xbuf, int recnum)
1763 {
1764 int rc; /* Return code */
1765 int xreclen; /* Cumulative record length */
1766 DATABLK *datablk; /* Data block */
1767
1768 if (recnum == 0) {
1769 xreclen = read(xfd, xbuf, 56); /* read COPYR1 plus some extras */
1770 if (xreclen < 56)
1771 {
1772 XMERRF ("HHCDL072E %s read error: %s\n",
1773 xfname,
1774 (xreclen < 0 ? strerror(errno) :
1775 "Unexpected end of file"));
1776 return -1;
1777 }
1778 }
1779
1780 else if (recnum == 1) {
1781 xreclen = read(xfd, xbuf, sizeof(COPYR2)); /* read COPYR2 */
1782 if (xreclen < (int)sizeof(COPYR2))
1783 {
1784 XMERRF ("HHCDL073E %s read error: %s\n",
1785 xfname,
1786 (xreclen < 0 ? strerror(errno) :
1787 "Unexpected end of file"));
1788 return -1;
1789 }
1790 }
1791
1792 else {
1793 rc = read(xfd, xbuf, 12); /* read header of DATABLK */
1794 if (rc == 0) /* read nothing? */
1795 return 0;
1796 if (rc < 12)
1797 {
1798 XMERRF ("HHCDL074E %s read error: %s\n",
1799 xfname,
1800 (rc < 0 ? strerror(errno) :
1801 "Unexpected end of file"));
1802 return -1;
1803 }
1804 datablk = (DATABLK *)xbuf;
1805 xreclen = ((datablk->dlen[0] << 8) | datablk->dlen[1])
1806 + datablk->klen;
1807 rc = read(xfd, xbuf + 12, xreclen); /* read kdarea of DATABLK */
1808 if (rc < xreclen)
1809 {
1810 XMERRF ("HHCDL075E %s read error: %s\n",
1811 xfname,
1812 (rc < 0 ? strerror(errno) :
1813 "Unexpected end of file"));
1814 return -1;
1815 }
1816 xreclen += 12; /* also count the header */
1817 }
1818
1819 /* Return record length */
1820 return xreclen;
1821
1822 } /* end function read_vs_rec */
1823
1824 /*-------------------------------------------------------------------*/
1825 /* Subroutine to process an INMR02 control record */
1826 /* Input: */
1827 /* xbuf Pointer to buffer containing control record */
1828 /* xreclen Length of control record */
1829 /* utiln Name of utility being processed (ASCIIZ) */
1830 /* filen Pointer to field to receive file sequence number */
1831 /* dsorg Pointer to byte to receive dataset organization */
1832 /* recfm Pointer to byte to receive record format */
1833 /* lrecl Pointer to integer to receive logical record length */
1834 /* blksz Pointer to integer to receive block size */
1835 /* keyln Pointer to integer to receive key length */
1836 /* dirnm Pointer to integer to number of directory blocks */
1837 /* Output: */
1838 /* If the record contains the text unit INMUTILN whose */
1839 /* value matches the name of the utility passed in utiln */
1840 /* then the dataset attributes are returned and the function */
1841 /* return value is 1. Otherwise the return value is 0 */
1842 /* and the dataset attributes remain unchanged. */
1843 /* If an error occurs then the return value is -1. */
1844 /* */
1845 /* File information is listed if infolvl is 2 or greater. */
1846 /*-------------------------------------------------------------------*/
1847 static int
process_inmr02(BYTE * xbuf,int xreclen,char * utiln,int * filen,BYTE * dsorg,BYTE * recfm,U16 * lrecl,U16 * blksz,U16 * keyln,U16 * dirnm)1848 process_inmr02 (BYTE *xbuf, int xreclen, char *utiln, int *filen,
1849 BYTE *dsorg, BYTE *recfm, U16 *lrecl, U16 *blksz,
1850 U16 *keyln, U16 *dirnm)
1851 {
1852 int rc; /* Return code */
1853 int i; /* Array subscript */
1854 int len; /* String length */
1855 U32 filenum; /* File number */
1856 int bufpos; /* Position of TU in buffer */
1857 int bufrem; /* Bytes remaining in buffer */
1858 char tuutiln[9]; /* Utility name */
1859 BYTE tukeyln; /* Key length */
1860 HWORD tudsorg; /* Data set organization */
1861 HWORD turecfm; /* Record format */
1862 U16 tulrecl; /* Logical record length */
1863 U16 tublksz; /* Block size */
1864 int tudirct; /* Number of directory blocks*/
1865 U16 tukey; /* Text unit key */
1866 U16 tunum; /* Number of text unit fields*/
1867 char tudsnam[45]; /* Data set name */
1868 #define MAXNUM 20 /* Maximum number of fields */
1869 U16 fieldlen[MAXNUM]; /* Array of field lengths */
1870 BYTE *fieldptr[MAXNUM]; /* Array of field pointers */
1871
1872 /* Extract the file number which follows the record name */
1873 filenum = (xbuf[6] << 24) | (xbuf[7] << 16)
1874 | (xbuf[8] << 8) | xbuf[9];
1875 XMINFF (4, "HHCDL076I File number: %d\n", filenum);
1876
1877 /* Point to the first text unit */
1878 bufpos = 10;
1879 bufrem = xreclen-10;
1880
1881 /* Clear values to be loaded from text units */
1882 memset (tudsnam, 0, sizeof(tudsnam));
1883 memset (tuutiln, 0, sizeof(tuutiln));
1884 memset (tudsorg, 0, sizeof(tudsorg));
1885 memset (turecfm, 0, sizeof(turecfm));
1886 tulrecl = 0;
1887 tublksz = 0;
1888 tukeyln = 0;
1889 tudirct = 0;
1890
1891 /* Process each text unit */
1892 while (bufrem > 0)
1893 {
1894 /* Extract the next text unit */
1895 rc = next_tu (xbuf, bufpos, bufrem, &tukey, &tunum,
1896 MAXNUM, fieldlen, fieldptr);
1897 if (rc < 0)
1898 {
1899 XMERRF ("HHCDL077E Invalid text unit at offset %4.4X\n",
1900 bufpos + 2);
1901 return -1;
1902 }
1903 bufpos += rc;
1904 bufrem -= rc;
1905
1906 /* Save the values from selected text units */
1907 switch (tukey) {
1908 case INMUTILN:
1909 make_asciiz (tuutiln, sizeof(tuutiln),
1910 fieldptr[0], fieldlen[0]);
1911 break;
1912 case INMDSORG:
1913 if (fieldlen[0] > sizeof(tudsorg))
1914 fieldlen[0] = sizeof(tudsorg);
1915 memcpy (tudsorg, fieldptr[0], fieldlen[0]);
1916 break;
1917 case INMRECFM:
1918 if (fieldlen[0] > sizeof(turecfm))
1919 fieldlen[0] = sizeof(turecfm);
1920 memcpy (turecfm, fieldptr[0], fieldlen[0]);
1921 break;
1922 case INMLRECL:
1923 tulrecl = make_int (fieldptr[0], fieldlen[0]);
1924 break;
1925 case INMBLKSZ:
1926 tublksz = make_int (fieldptr[0], fieldlen[0]);
1927 break;
1928 case INMTYPE:
1929 tukeyln = make_int (fieldptr[0], fieldlen[0]);
1930 break;
1931 case INMDIR:
1932 tudirct = make_int (fieldptr[0], fieldlen[0]);
1933 break;
1934 case INMDSNAM:
1935 memset (tudsnam, 0, sizeof(tudsnam));
1936 for (i = 0; i < tunum; i++)
1937 {
1938 len = strlen(tudsnam);
1939 if (i > 0 && len < (int)(sizeof(tudsnam) - 1))
1940 tudsnam[len++] = '.';
1941 make_asciiz (tudsnam + len, sizeof(tudsnam) - len,
1942 fieldptr[i], fieldlen[i]);
1943 } /* end for(i) */
1944 } /* end switch(tukey) */
1945 } /* end while(bufrem) */
1946
1947 /* Return the dataset values if this INMR02 record is for utiln */
1948 if (strcmp(tuutiln, utiln) == 0)
1949 {
1950 XMINFF (2, "HHCDL078I File %u: DSNAME=%s\n",
1951 filenum, tudsnam);
1952 XMINFF (2, "HHCDL079I DSORG=%s RECFM=%s "
1953 "LRECL=%d BLKSIZE=%d KEYLEN=%d DIRBLKS=%d\n",
1954 dsorg_name(tudsorg), recfm_name(turecfm),
1955 tulrecl, tublksz, tukeyln, tudirct);
1956 *filen = filenum;
1957 *dsorg = tudsorg[0];
1958 *recfm = turecfm[0];
1959 *lrecl = tulrecl;
1960 *blksz = tublksz;
1961 *keyln = tukeyln;
1962 *dirnm = tudirct;
1963 }
1964
1965 return 0;
1966 } /* end function process_inmr02 */
1967
1968 /*-------------------------------------------------------------------*/
1969 /* Subroutine to process a control record other than INMR02 */
1970 /* Input: */
1971 /* xbuf Pointer to buffer containing control record */
1972 /* xreclen Length of control record */
1973 /* Output: */
1974 /* The return value is 0 if successful, or -1 if error. */
1975 /*-------------------------------------------------------------------*/
1976 static int
process_inmrxx(BYTE * xbuf,int xreclen)1977 process_inmrxx (BYTE *xbuf, int xreclen)
1978 {
1979 int rc; /* Return code */
1980 int bufpos; /* Position of TU in buffer */
1981 int bufrem; /* Bytes remaining in buffer */
1982 U16 tukey; /* Text unit key */
1983 U16 tunum; /* Number of text unit fields*/
1984 #define MAXNUM 20 /* Maximum number of fields */
1985 U16 fieldlen[MAXNUM]; /* Array of field lengths */
1986 BYTE *fieldptr[MAXNUM]; /* Array of field pointers */
1987
1988 /* Point to the first text unit */
1989 bufpos = 6;
1990 bufrem = xreclen-6;
1991
1992 /* Process each text unit */
1993 while (bufrem > 0)
1994 {
1995 /* Extract the next text unit */
1996 rc = next_tu (xbuf, bufpos, bufrem, &tukey, &tunum,
1997 MAXNUM, fieldlen, fieldptr);
1998 if (rc < 0)
1999 {
2000 XMERRF ("HHCDL080E Invalid text unit at offset %4.4X\n",
2001 bufpos + 2);
2002 return -1;
2003 }
2004
2005 bufpos += rc;
2006 bufrem -= rc;
2007
2008 } /* end while(bufrem) */
2009
2010 return 0;
2011 } /* end function process_inmrxx */
2012
2013 /*-------------------------------------------------------------------*/
2014 /* Subroutine to process a COPYR1 header record */
2015 /* Input: */
2016 /* xbuf Pointer to buffer containing header record */
2017 /* xreclen Length of header record */
2018 /* Output: */
2019 /* The return value is the number of tracks per cylinder, */
2020 /* or -1 if an error occurred. */
2021 /*-------------------------------------------------------------------*/
2022 static int
process_copyr1(BYTE * xbuf,int xreclen)2023 process_copyr1 (BYTE *xbuf, int xreclen)
2024 {
2025 COPYR1 *copyr1 = (COPYR1*)xbuf; /* -> COPYR1 header record */
2026 U16 blksize; /* Block size */
2027 U16 lrecl; /* Logical record length */
2028 BYTE keylen; /* Key length */
2029 U16 cyls; /* Number of cylinders */
2030 U16 heads; /* Number of tracks/cylinder */
2031
2032 /* Check COPYR1 record for correct length */
2033 if (xreclen != sizeof(COPYR1)
2034 && xreclen != sizeof(COPYR1) - 4)
2035 {
2036 XMERR ("HHCDL081E COPYR1 record length is invalid\n");
2037 return -1;
2038 }
2039
2040 /* Check that COPYR1 header identifier is correct */
2041 if (memcmp(copyr1->hdrid, COPYR1_HDRID, 3) != 0)
2042 {
2043 XMERR ("HHCDL082E COPYR1 header identifier not correct\n");
2044 return -1;
2045 }
2046
2047 /* Check that the dataset is an old format unload */
2048 if ((copyr1->uldfmt & COPYR1_ULD_FORMAT)
2049 != COPYR1_ULD_FORMAT_OLD)
2050 {
2051 XMERR ("HHCDL083E COPYR1 unload format is unsupported\n");
2052 return -1;
2053 }
2054
2055 blksize = (copyr1->ds1blkl[0] << 8) | copyr1->ds1blkl[1];
2056 lrecl = (copyr1->ds1lrecl[0] << 8) | copyr1->ds1lrecl[1];
2057 keylen = copyr1->ds1keyl;
2058
2059 /* Display original dataset information */
2060 XMINFF (2, "HHCDL084I Original dataset: "
2061 "DSORG=%s RECFM=%s LRECL=%d BLKSIZE=%d KEYLEN=%d\n",
2062 dsorg_name(copyr1->ds1dsorg),
2063 recfm_name(©r1->ds1recfm),
2064 lrecl, blksize, keylen);
2065
2066 XMINFF (2, "HHCDL085I Dataset was unloaded from device type "
2067 "%2.2X%2.2X%2.2X%2.2X (%s)\n",
2068 copyr1->ucbtype[0], copyr1->ucbtype[1],
2069 copyr1->ucbtype[2], copyr1->ucbtype[3],
2070 dasd_name(copyr1->ucbtype));
2071
2072 cyls = (copyr1->cyls[0] << 8) | copyr1->cyls[1];
2073 heads = (copyr1->heads[0] << 8) | copyr1->heads[1];
2074
2075 XMINFF (2, "HHCDL086I Original device has %d cyls and %d heads\n",
2076 cyls, heads);
2077
2078 return heads;
2079 } /* end function process_copyr1 */
2080
2081 /*-------------------------------------------------------------------*/
2082 /* Subroutine to process a COPYR2 header record */
2083 /* Input: */
2084 /* xbuf Pointer to buffer containing header record */
2085 /* xreclen Length of header record */
2086 /* xarray Pointer to array to receive 1-16 extent descriptions */
2087 /* Output: */
2088 /* The return value is the number of extents, */
2089 /* or -1 if an error occurred. */
2090 /* */
2091 /* Extent information is listed if infolvl is 4 or greater. */
2092 /*-------------------------------------------------------------------*/
2093 static int
process_copyr2(BYTE * xbuf,int xreclen,EXTDESC xarray[])2094 process_copyr2 (BYTE *xbuf, int xreclen, EXTDESC xarray[])
2095 {
2096 COPYR2 *copyr2 = (COPYR2*)xbuf; /* -> COPYR2 header record */
2097 int numext; /* Number of extents */
2098 int i; /* Array subscript */
2099
2100 /* Check COPYR2 record for correct length */
2101 if (xreclen != sizeof(COPYR2))
2102 {
2103 XMERR ("HHCDL087I COPYR2 record length is invalid\n");
2104 return -1;
2105 }
2106
2107 /* Get number of extents from DEB basic section */
2108 numext = copyr2->debbasic[0];
2109 if (numext < 1 || numext > 16)
2110 {
2111 XMERRF ("HHCDL088I Invalid number of extents %d\n", numext);
2112 return -1;
2113 }
2114
2115 /* Copy each extent descriptor into the array */
2116 for (i = 0; i < numext; i++)
2117 {
2118 xarray[i].bcyl = (copyr2->debxtent[i][6] << 8)
2119 | copyr2->debxtent[i][7];
2120 xarray[i].btrk = (copyr2->debxtent[i][8] << 8)
2121 | copyr2->debxtent[i][9];
2122 xarray[i].ecyl = (copyr2->debxtent[i][10] << 8)
2123 | copyr2->debxtent[i][11];
2124 xarray[i].etrk = (copyr2->debxtent[i][12] << 8)
2125 | copyr2->debxtent[i][13];
2126 xarray[i].ntrk = (copyr2->debxtent[i][14] << 8)
2127 | copyr2->debxtent[i][15];
2128
2129 XMINFF (4, "HHCDL089I Extent %d: Begin CCHH=%4.4X%4.4X "
2130 "End CCHH=%4.4X%4.4X Tracks=%4.4X\n",
2131 i, xarray[i].bcyl, xarray[i].btrk,
2132 xarray[i].ecyl, xarray[i].etrk, xarray[i].ntrk);
2133
2134 } /* end for(i) */
2135
2136 /* Return number of extents */
2137 return numext;
2138 } /* end function process_copyr2 */
2139
2140 /*-------------------------------------------------------------------*/
2141 /* Subroutine to process a directory block record */
2142 /* Input: */
2143 /* xbuf Pointer to directory block */
2144 /* blklen Length of directory block */
2145 /* cyl Cylinder number of directory block in output file */
2146 /* head Head number of directory block in output file */
2147 /* rec Record number of directory block in output file */
2148 /* dirblka Array of pointers to directory blocks */
2149 /* dirblkn Number of directory blocks in dirblka array */
2150 /* Output: */
2151 /* dirblu Number of bytes used in directory block */
2152 /* The return value is 0 if successful, 1 if end of directory, */
2153 /* or -1 if an error occurred. */
2154 /* */
2155 /* A pointer to the directory block is saved in the dirblka array. */
2156 /* The copy of the data block is updated with the cylinder, head, */
2157 /* and record number of the directory block in the output file. */
2158 /* Directory information is listed if infolvl is 3 or greater. */
2159 /*-------------------------------------------------------------------*/
2160 static int
process_dirblk(DATABLK * xbuf,int blklen,int cyl,int head,int rec,DATABLK * dirblka[],int dirblkn,int * dirblu)2161 process_dirblk (DATABLK *xbuf, int blklen, int cyl, int head, int rec,
2162 DATABLK *dirblka[], int dirblkn, int *dirblu)
2163 {
2164 int size; /* Size of directory entry */
2165 int i, j; /* Array subscripts */
2166 int k; /* Userdata halfword count */
2167 DATABLK *blkp; /* -> Copy of directory block*/
2168 BYTE *dirptr; /* -> Next byte within block */
2169 int dirrem; /* Number of bytes remaining */
2170 PDSDIR *dirent; /* -> Directory entry */
2171 char memname[9]; /* Member name (ASCIIZ) */
2172 BYTE c, chars[25]; /* Character work areas */
2173 char hex[49]; /* Character work areas */
2174
2175 set_codepage(NULL);
2176
2177
2178 /* Check for end of directory */
2179 if (blklen == 12 && memcmp(xbuf, twelvehex00, 12) == 0)
2180 {
2181 XMINF (3, "HHCDL090I End of directory\n");
2182 return 1;
2183 }
2184
2185 /* Check directory block record for correct length */
2186 if (blklen != 276)
2187 {
2188 XMERR ("HHCDL091E Directory block record length is invalid\n");
2189 return -1;
2190 }
2191
2192 /* Obtain storage for a copy of the directory block */
2193 blkp = (DATABLK*)malloc(blklen);
2194 if (blkp == NULL)
2195 {
2196 XMERRF ("HHCDL092E Cannot obtain storage for directory block: %s\n",
2197 strerror(errno));
2198 return -1;
2199 }
2200
2201 /* Copy the directory block */
2202 memcpy (blkp, xbuf, blklen);
2203
2204 /* Check that there is room in the directory block pointer array */
2205 if (dirblkn >= MAXDBLK)
2206 {
2207 XMERRF ("HHCDL093E Number of directory blocks exceeds %d, "
2208 "increase MAXDBLK\n",
2209 MAXDBLK);
2210 return -1;
2211 }
2212
2213 /* Add the directory block to the pointer array */
2214 dirblka[dirblkn] = blkp;
2215
2216 /* Update the CCHHR in the copy of the directory block */
2217 blkp->cyl[0] = (cyl >> 8) & 0xFF;
2218 blkp->cyl[1] = cyl & 0xFF;
2219 blkp->head[0] = (head >> 8) & 0xFF;
2220 blkp->head[1] = head & 0xFF;
2221 blkp->rec = rec;
2222
2223 /* Load number of bytes in directory block */
2224 dirptr = xbuf->kdarea + 8;
2225 dirrem = (dirptr[0] << 8) | dirptr[1];
2226 if (dirrem < 2 || dirrem > 256)
2227 {
2228 XMERR ("HHCDL094E Directory block byte count is invalid\n");
2229 return -1;
2230 }
2231
2232 /* Return number of bytes used in directory block */
2233 *dirblu = dirrem;
2234
2235 /* Point to first directory entry */
2236 dirptr += 2;
2237 dirrem -= 2;
2238
2239 /* Process each directory entry */
2240 while (dirrem > 0)
2241 {
2242 /* Point to next directory entry */
2243 dirent = (PDSDIR*)dirptr;
2244
2245 /* Test for end of directory */
2246 if (memcmp(dirent->pds2name, eighthexFF, 8) == 0)
2247 break;
2248
2249 /* Extract the member name */
2250 make_asciiz (memname, sizeof(memname), dirent->pds2name, 8);
2251
2252 /* Display the directory entry */
2253 XMINFF (3, "HHCDL095I %s %-8.8s TTR=%2.2X%2.2X%2.2X ",
2254 (dirent->pds2indc & PDS2INDC_ALIAS) ?
2255 " Alias" : "Member",
2256 memname, dirent->pds2ttrp[0],
2257 dirent->pds2ttrp[1], dirent->pds2ttrp[2]);
2258
2259 /* Load the user data halfword count */
2260 k = dirent->pds2indc & PDS2INDC_LUSR;
2261
2262 /* Print the user data */
2263 if (k > 0) XMINF (3, "Userdata=");
2264 memset (hex, '\0', sizeof(hex));
2265 memset (chars, '\0', sizeof(chars));
2266 for (i = 0, j = 0; i < k*2; i++, j++)
2267 {
2268 if (i == 8 || i == 32 || i == 56)
2269 {
2270 if (i == 8)
2271 XMINFF (3, "%-16.16s %-8.8s\n ", hex, chars);
2272 else
2273 XMINFF (3, "%-16.16s %-16.16s %16.16s %-24.24s\n ",
2274 hex, hex+16, hex+32, chars);
2275 memset (hex, '\0', sizeof(hex));
2276 memset (chars, '\0', sizeof(chars));
2277 j = 0;
2278 }
2279 sprintf(hex+2*j, "%2.2X", dirent->pds2usrd[i]);
2280 c = guest_to_host(dirent->pds2usrd[i]);
2281 if (!isprint(c)) c = '.';
2282 chars[j] = c;
2283 } /* end for(i) */
2284 if (i <= 8)
2285 XMINFF (3, "%-16.16s %-8.8s\n", hex, chars);
2286 else
2287 XMINFF (3, "%-16.16s %-16.16s %-16.16s %-24.24s\n",
2288 hex, hex+16, hex+32, chars);
2289
2290 /* Point to next directory entry */
2291 size = 12 + k*2;
2292 dirptr += size;
2293 dirrem -= size;
2294 }
2295
2296 return 0;
2297 } /* end function process_dirblk */
2298
2299 /*-------------------------------------------------------------------*/
2300 /* Subroutine to replace a TTR in a PDS directory */
2301 /* Input: */
2302 /* memname Member name (ASCIIZ) */
2303 /* ttrptr Pointer to TTR to be replaced */
2304 /* ttrtab Pointer to TTR conversion table */
2305 /* numttr Number of entries in TTR conversion table */
2306 /* Output: */
2307 /* The TTR is replaced using the TTR conversion table. */
2308 /* */
2309 /* Return value is 0 if successful, or -1 if TTR not in table. */
2310 /* Directory information is listed if infolvl is 3 or greater. */
2311 /*-------------------------------------------------------------------*/
2312 static int
replace_ttr(char * memname,BYTE * ttrptr,TTRCONV * ttrtab,int numttr)2313 replace_ttr (char *memname, BYTE *ttrptr, TTRCONV *ttrtab, int numttr)
2314 {
2315 int i; /* Array subscript */
2316
2317 /* Search for the TTR in the conversion table */
2318 for (i = 0; i < numttr; i++)
2319 {
2320 if (memcmp(ttrptr, ttrtab[i].origttr, 3) == 0)
2321 {
2322 XMINFF (4, "HHCDL096I Member %s TTR=%2.2X%2.2X%2.2X "
2323 "replaced by TTR=%2.2X%2.2X%2.2X\n",
2324 memname, ttrptr[0], ttrptr[1], ttrptr[2],
2325 ttrtab[i].outpttr[0], ttrtab[i].outpttr[1],
2326 ttrtab[i].outpttr[2]);
2327 memcpy (ttrptr, ttrtab[i].outpttr, 3);
2328 return 0;
2329 }
2330 }
2331
2332 /* Return error if TTR not found in conversion table */
2333 XMERRF ("HHCDL097E Member %s TTR=%2.2X%2.2X%2.2X not found in dataset\n",
2334 memname, ttrptr[0], ttrptr[1], ttrptr[2]);
2335 return -1;
2336
2337 } /* end function replace_ttr */
2338
2339 /*-------------------------------------------------------------------*/
2340 /* Subroutine to update a note list record */
2341 /* Input: */
2342 /* cif -> CKD image file descriptor */
2343 /* ofname Output file name */
2344 /* heads Number of tracks per cylinder on output device */
2345 /* trklen Track length of virtual output device */
2346 /* dsstart Relative track number of start of dataset */
2347 /* memname Member name (ASCIIZ) */
2348 /* ttrn Pointer to TTRN of note list record */
2349 /* ttrtab Pointer to TTR conversion table */
2350 /* numttr Number of entries in TTR conversion table */
2351 /* Output: */
2352 /* Each original TTR in the note list record is replaced by the */
2353 /* corresponding output TTR from the TTR conversion table. */
2354 /* */
2355 /* Return value is 0 if successful, or -1 if error. */
2356 /*-------------------------------------------------------------------*/
2357 static int
update_note_list(CIFBLK * cif,char * ofname,int heads,int trklen,int dsstart,char * memname,BYTE * ttrn,TTRCONV * ttrtab,int numttr)2358 update_note_list (CIFBLK *cif, char *ofname, int heads, int trklen,
2359 int dsstart, char *memname, BYTE *ttrn,
2360 TTRCONV *ttrtab, int numttr)
2361 {
2362 int rc; /* Return code */
2363 int i; /* Loop counter */
2364 int trk; /* Relative track number */
2365 int cyl; /* Cylinder number */
2366 int head; /* Head number */
2367 int rec; /* Record number */
2368 int klen; /* Record key length */
2369 int dlen; /* Record data length */
2370 int numnl; /* Number of note list TTRs */
2371 int nllen; /* Note list length */
2372 BYTE *ttrptr; /* -> Note list TTR */
2373 int curcyl; /* Current cylinder */
2374 int curhead; /* Current head */
2375 int offset; /* Offset into track buffer */
2376 int skiplen; /* Number of bytes to skip */
2377 CKDDASD_TRKHDR trkhdr; /* Track header */
2378 CKDDASD_RECHDR rechdr; /* Record header */
2379 BYTE notelist[1024]; /* Note list */
2380
2381 UNREFERENCED(trklen);
2382
2383 /* Load the TTR of the note list record */
2384 trk = (ttrn[0] << 8) | ttrn[1];
2385 rec = ttrn[2];
2386
2387 /* Load number of note list TTRs and calculate note list length */
2388 numnl = ttrn[3];
2389 nllen = numnl * 4;
2390
2391 /* Calculate the CCHHR of the note list record */
2392 cyl = (dsstart + trk) / heads;
2393 head = (dsstart + trk) % heads;
2394
2395 XMINFF (4, "HHCDL098I Updating note list for member %s "
2396 "at TTR=%4.4X%2.2X CCHHR=%4.4X%4.4X%2.2X\n",
2397 memname, trk, rec, cyl, head, rec);
2398
2399 /* Save the current position in the output file */
2400 curcyl = cif->curcyl;
2401 curhead = cif->curhead;
2402
2403 /* Seek to start of track header */
2404 rc = read_track (cif, cyl, head);
2405 if (rc < 0)
2406 {
2407 XMERRF ("HHCDL099E %s cyl %d head %d read error\n",
2408 ofname, cyl, head);
2409 return -1;
2410 }
2411
2412 /* Copy the track header */
2413 memcpy (&trkhdr, cif->trkbuf, CKDDASD_TRKHDR_SIZE);
2414 offset = CKDDASD_TRKHDR_SIZE;
2415
2416 /* Validate the track header */
2417 if (trkhdr.bin != 0
2418 || trkhdr.cyl[0] != (cyl >> 8)
2419 || trkhdr.cyl[1] != (cyl & 0xFF)
2420 || trkhdr.head[0] != (head >> 8)
2421 || trkhdr.head[1] != (head & 0xFF))
2422 {
2423 XMERRF ("HHCDL100E %s cyl %d head %d invalid track header "
2424 "%2.2X%2.2X%2.2X%2.2X%2.2X\n",
2425 ofname, cyl, head,
2426 trkhdr.bin, trkhdr.cyl[0], trkhdr.cyl[1],
2427 trkhdr.head[0], trkhdr.head[1]);
2428 return -1;
2429 }
2430
2431 /* Search for the note list record */
2432 while (1)
2433 {
2434 /* Copy the next record header */
2435 memcpy (&rechdr, cif->trkbuf + offset, CKDDASD_RECHDR_SIZE);
2436 offset += CKDDASD_RECHDR_SIZE;
2437
2438 /* Check for end of track */
2439 if (memcmp(&rechdr, eighthexFF, 8) == 0)
2440 {
2441 XMERRF ("HHCDL101E %s cyl %d head %d rec %d "
2442 "note list record not found\n",
2443 ofname, cyl, head, rec);
2444 return -1;
2445 }
2446
2447 /* Extract record key length and data length */
2448 klen = rechdr.klen;
2449 dlen = (rechdr.dlen[0] << 8) | rechdr.dlen[1];
2450
2451 /* Exit loop if matching record number */
2452 if (rechdr.rec == rec)
2453 break;
2454
2455 /* Skip the key and data areas */
2456 skiplen = klen + dlen;
2457 offset += skiplen;
2458 } /* end while */
2459
2460 /* Check that the data length is sufficient */
2461 if (dlen < nllen)
2462 {
2463 XMERRF ("HHCDL102E Member %s note list at cyl %d head %d rec %d "
2464 "dlen %d is too short for %d TTRs",
2465 memname, cyl, head, rec, dlen, numnl);
2466 return -1;
2467 }
2468
2469 /* Skip the key area if present */
2470 offset += klen;
2471
2472 /* Copy the note list from the data area */
2473 memcpy (¬elist, cif->trkbuf + offset, nllen);
2474
2475 /* Replace the TTRs in the note list record */
2476 ttrptr = notelist;
2477 for (i = 0; i < numnl; i++)
2478 {
2479 rc = replace_ttr (memname, ttrptr, ttrtab, numttr);
2480 if (rc < 0) return -1;
2481 ttrptr += 4;
2482 } /* end for(i) */
2483
2484 /* Copy the updated note list to the buffer */
2485 memcpy (cif->trkbuf + offset, ¬elist, nllen);
2486 cif->trkmodif = 1;
2487
2488 /* Restore original file position */
2489 rc = read_track (cif, curcyl, curhead);
2490 if (rc < 0)
2491 {
2492 XMERRF ("HHCDL103E %s track read error cyl %d head %d\n",
2493 ofname, curcyl, curhead);
2494 return -1;
2495 }
2496
2497 XMINFF (4, "HHCDL104I Updating cyl %u head %u rec %d kl %d dl %d\n",
2498 cyl, head, rec, klen, dlen);
2499
2500 return 0;
2501 } /* end function update_note_list */
2502
2503 /*-------------------------------------------------------------------*/
2504 /* Subroutine to update a directory block record */
2505 /* Input: */
2506 /* cif -> CKD image file descriptor */
2507 /* ofname Output file name */
2508 /* heads Number of tracks per cylinder on output device */
2509 /* trklen Track length of virtual output device */
2510 /* dsstart Relative track number of start of dataset */
2511 /* xbuf Pointer to directory block */
2512 /* ttrtab Pointer to TTR conversion table */
2513 /* numttr Number of entries in TTR conversion table */
2514 /* Output: */
2515 /* Each original TTR in the directory block is replaced by the */
2516 /* corresponding output TTR from the TTR conversion table. */
2517 /* For any module which has note list entries, the note list */
2518 /* TTRs in the note list record are also updated. */
2519 /* */
2520 /* Return value is 0 if successful, or -1 if any directory entry */
2521 /* contains a TTR which is not found in the TTR conversion table. */
2522 /*-------------------------------------------------------------------*/
2523 static int
update_dirblk(CIFBLK * cif,char * ofname,int heads,int trklen,int dsstart,DATABLK * xbuf,TTRCONV * ttrtab,int numttr)2524 update_dirblk (CIFBLK *cif, char *ofname, int heads, int trklen,
2525 int dsstart, DATABLK *xbuf,
2526 TTRCONV *ttrtab, int numttr)
2527 {
2528 int rc; /* Return code */
2529 int size; /* Size of directory entry */
2530 int k; /* Userdata halfword count */
2531 BYTE *dirptr; /* -> Next byte within block */
2532 int dirrem; /* Number of bytes remaining */
2533 PDSDIR *dirent; /* -> Directory entry */
2534 BYTE *ttrptr; /* -> User TTR */
2535 int n; /* Number of user TTRs */
2536 int i; /* Loop counter */
2537 char memname[9]; /* Member name (ASCIIZ) */
2538
2539 /* Load number of bytes in directory block */
2540 dirptr = xbuf->kdarea + 8;
2541 dirrem = (dirptr[0] << 8) | dirptr[1];
2542 if (dirrem < 2 || dirrem > 256)
2543 {
2544 XMERR ("HHCDL105E Directory block byte count is invalid\n");
2545 return -1;
2546 }
2547
2548 /* Point to first directory entry */
2549 dirptr += 2;
2550 dirrem -= 2;
2551
2552 /* Process each directory entry */
2553 while (dirrem > 0)
2554 {
2555 /* Point to next directory entry */
2556 dirent = (PDSDIR*)dirptr;
2557
2558 /* Test for end of directory */
2559 if (memcmp(dirent->pds2name, eighthexFF, 8) == 0)
2560 break;
2561
2562 /* Extract the member name */
2563 make_asciiz (memname, sizeof(memname), dirent->pds2name, 8);
2564
2565 /* Replace the member TTR */
2566 rc = replace_ttr (memname, dirent->pds2ttrp, ttrtab, numttr);
2567 if (rc < 0) return -1;
2568
2569 /* Load the number of user TTRs */
2570 n = (dirent->pds2indc & PDS2INDC_NTTR) >> PDS2INDC_NTTR_SHIFT;
2571
2572 /* Replace the user TTRs */
2573 ttrptr = dirent->pds2usrd;
2574 for (i = 0; i < n; i++)
2575 {
2576 rc = replace_ttr (memname, ttrptr, ttrtab, numttr);
2577 if (rc < 0) return -1;
2578 ttrptr += 4;
2579 } /* end for(i) */
2580
2581 /* Update the note list record if note list TTRs exist */
2582 if ((dirent->pds2indc & PDS2INDC_ALIAS) == 0
2583 && n >= 2 && dirent->pds2usrd[7] != 0)
2584 {
2585 rc = update_note_list (cif, ofname, heads, trklen,
2586 dsstart, memname, dirent->pds2usrd+4,
2587 ttrtab, numttr);
2588 if (rc < 0) return -1;
2589 }
2590
2591 /* Load the user data halfword count */
2592 k = dirent->pds2indc & PDS2INDC_LUSR;
2593
2594 /* Point to next directory entry */
2595 size = 12 + k*2;
2596 dirptr += size;
2597 dirrem -= size;
2598 }
2599
2600 return 0;
2601 } /* end function update_dirblk */
2602
2603 /*-------------------------------------------------------------------*/
2604 /* Subroutine to read an IEBCOPY file and write to DASD image file */
2605 /* Input: */
2606 /* xfname XMIT input file name */
2607 /* ofname DASD image file name */
2608 /* cif -> CKD image file descriptor */
2609 /* devtype Output device type */
2610 /* heads Output device number of tracks per cylinder */
2611 /* trklen Output device virtual track length */
2612 /* outcyl Output starting cylinder number */
2613 /* outhead Output starting head number */
2614 /* maxtrks Maximum extent size in tracks */
2615 /* method METHOD_XMIT or METHOD_VS */
2616 /* Output: */
2617 /* odsorg Dataset organization */
2618 /* orecfm Record format */
2619 /* olrecl Logical record length */
2620 /* oblksz Block size */
2621 /* okeyln Key length */
2622 /* dirblu Bytes used in last directory block */
2623 /* lastrec Record number of last block written */
2624 /* trkbal Number of bytes remaining on last track */
2625 /* numtrks Number of tracks written */
2626 /* nxtcyl Starting cylinder number for next dataset */
2627 /* nxthead Starting head number for next dataset */
2628 /*-------------------------------------------------------------------*/
2629 static int
process_iebcopy_file(char * xfname,char * ofname,CIFBLK * cif,U16 devtype,int heads,int trklen,int outcyl,int outhead,int maxtrks,BYTE method,BYTE * odsorg,BYTE * orecfm,int * olrecl,int * oblksz,int * okeyln,int * dirblu,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)2630 process_iebcopy_file (char *xfname, char *ofname, CIFBLK *cif,
2631 U16 devtype, int heads, int trklen,
2632 int outcyl, int outhead, int maxtrks,
2633 BYTE method,
2634 BYTE *odsorg, BYTE *orecfm,
2635 int *olrecl, int *oblksz, int *okeyln,
2636 int *dirblu, int *lastrec, int *trkbal,
2637 int *numtrks, int *nxtcyl, int *nxthead)
2638 {
2639 int rc = 0; /* Return code */
2640 int i; /* Array subscript */
2641 int xfd; /* XMIT file descriptor */
2642 int dsstart; /* Relative track number of
2643 start of output dataset */
2644 BYTE *xbuf; /* -> Logical record buffer */
2645 int xreclen; /* Logical record length */
2646 BYTE xctl; /* 0x20=Control record */
2647 char xrecname[8]; /* XMIT control record name */
2648 int datarecn = 0; /* Data record counter */
2649 int datafiln = 0; /* Data file counter */
2650 int copyfiln = 0; /* Seq num of file to copy */
2651 BYTE dsorg=0; /* Dataset organization */
2652 BYTE recfm=0; /* Dataset record format */
2653 U16 lrecl=0; /* Dataset record length */
2654 U16 blksz=0; /* Dataset block size */
2655 U16 keyln=0; /* Dataset key length */
2656 U16 dirnm; /* Number of directory blocks*/
2657 int enddir = 0; /* 1=End of directory found */
2658 BYTE *blkptr; /* -> Data block in record */
2659 DATABLK *datablk; /* -> Data block */
2660 int blktrk; /* Data block relative track */
2661 int blkcyl; /* Data block cylinder number*/
2662 int blkhead; /* Data block head number */
2663 int blkrec; /* Data block record number */
2664 int keylen; /* Key length of data block */
2665 int datalen; /* Data length of data block */
2666 int blklen; /* Total length of data block*/
2667 int origheads = 0; /* Number of tracks/cylinder
2668 on original dataset */
2669 int numext = 0; /* Number of extents */
2670 EXTDESC xarray[16]; /* Extent descriptor array */
2671 DATABLK **dirblka; /* -> Directory block array */
2672 int dirblkn = 0; /* #of directory blocks read */
2673 int outusedv = 0; /* Output bytes used on track
2674 of virtual device */
2675 int outusedr = 0; /* Output bytes used on track
2676 of real device */
2677 int outtrkbr = 0; /* Output bytes remaining on
2678 track of real device */
2679 int outtrk = 0; /* Output relative track */
2680 int outrec = 0; /* Output record number */
2681 TTRCONV *ttrtab; /* -> TTR conversion table */
2682 int numttr = 0; /* TTR table array index */
2683 COPYR1 *copyr1; /* -> header record 1 */
2684 char pathname[MAX_PATH]; /* xfname in host path format*/
2685
2686 /* Open the input file */
2687 hostpath(pathname, xfname, sizeof(pathname));
2688 xfd = hopen(pathname, O_RDONLY|O_BINARY);
2689 if (xfd < 0)
2690 {
2691 XMERRF ("HHCDL106E Cannot open %s: %s\n",
2692 xfname, strerror(errno));
2693 return -1;
2694 }
2695
2696 /* Obtain the input logical record buffer */
2697 xbuf = malloc (65536);
2698 if (xbuf == NULL)
2699 {
2700 XMERRF ("HHCDL107E Cannot obtain input buffer: %s\n",
2701 strerror(errno));
2702 close (xfd);
2703 return -1;
2704 }
2705
2706 /* Obtain storage for the directory block array */
2707 dirblka = (DATABLK**)malloc (sizeof(DATABLK*) * MAXDBLK);
2708 if (dirblka == NULL)
2709 {
2710 XMERRF ("HHCDL108E Cannot obtain storage for directory block array: %s\n",
2711 strerror(errno));
2712 free (xbuf);
2713 close (xfd);
2714 return -1;
2715 }
2716
2717 /* Obtain storage for the TTR conversion table */
2718 ttrtab = (TTRCONV*)malloc (sizeof(TTRCONV) * MAXTTR);
2719 if (ttrtab == NULL)
2720 {
2721 XMERRF ("HHCDL109E Cannot obtain storage for TTR table: %s\n",
2722 strerror(errno));
2723 free (xbuf);
2724 free (dirblka);
2725 close (xfd);
2726 return -1;
2727 }
2728
2729 /* Calculate the relative track number of the dataset */
2730 dsstart = (outcyl * heads) + outhead;
2731
2732 /* Display the file information message */
2733 XMINFF (1, "HHCDL110I Processing file %s\n", xfname);
2734
2735 /* Read each logical record */
2736 while (1)
2737 {
2738 xctl=0;
2739 if (method == METHOD_XMIT)
2740 rc = read_xmit_rec (xfd, xfname, xbuf, &xctl);
2741 else if (method == METHOD_VS) {
2742 rc = read_vs_rec (xfd, xfname, xbuf, datarecn);
2743 if (rc == 0) /* end-of-file */
2744 break;
2745 } else
2746 rc = -1;
2747 if (rc < 0) return -1;
2748 xreclen = rc;
2749
2750 /* Process control records */
2751 if (method == METHOD_XMIT && xctl)
2752 {
2753 /* Extract the control record name */
2754 make_asciiz (xrecname, sizeof(xrecname), xbuf, 6);
2755 XMINFF (4, "HHCDL111I Control record: %s length %d\n",
2756 xrecname, xreclen);
2757
2758 /* Exit if control record is a trailer record */
2759 if (strcmp(xrecname, "INMR06") == 0)
2760 break;
2761
2762 /* Process control record according to type */
2763 if (strcmp(xrecname, "INMR02") == 0)
2764 {
2765 rc = process_inmr02 (xbuf, xreclen, "IEBCOPY", ©filn,
2766 &dsorg, &recfm, &lrecl, &blksz,
2767 &keyln, &dirnm);
2768 if (rc < 0) return -1;
2769 }
2770 else
2771 {
2772 rc = process_inmrxx (xbuf, xreclen);
2773 if (rc < 0) return -1;
2774 }
2775
2776 /* Reset the data counter if data control record */
2777 if (strcmp(xrecname, "INMR03") == 0)
2778 {
2779 datafiln++;
2780 datarecn = 0;
2781 XMINFF (4, "HHCDL112I File number: %d %s\n", datafiln,
2782 (datafiln == copyfiln) ? "(selected)"
2783 : "(not selected)");
2784 }
2785
2786 /* Loop to get next record */
2787 continue;
2788
2789 } /* end if(xctl) */
2790
2791 /* Process data records */
2792 datarecn++;
2793 XMINFF (4, "HHCDL113I Data record: length %d\n", xreclen);
2794 if (infolvl >= 5) data_dump (xbuf, xreclen);
2795
2796 /* If this is not the IEBCOPY file then ignore data record */
2797 if (method == METHOD_XMIT && datafiln != copyfiln)
2798 {
2799 continue;
2800 }
2801
2802 /* Process IEBCOPY header record 1 */
2803 if (datarecn == 1)
2804 {
2805 origheads = process_copyr1 (xbuf, xreclen);
2806 if (origheads < 0) exit(1);
2807 if (method == METHOD_VS) {
2808 copyr1 = (COPYR1 *)xbuf;
2809 dsorg = copyr1->ds1dsorg[0];
2810 recfm = copyr1->ds1recfm;
2811 lrecl = (copyr1->ds1lrecl[0] << 8) | copyr1->ds1lrecl[1];
2812 blksz = (copyr1->ds1blkl[0] << 8) | copyr1->ds1blkl[1];
2813 keyln = copyr1->ds1keyl;
2814 }
2815 continue;
2816 }
2817
2818 /* Process IEBCOPY header record 2 */
2819 if (datarecn == 2)
2820 {
2821 numext = process_copyr2 (xbuf, xreclen, xarray);
2822 if (numext < 0) exit(1);
2823 continue;
2824 }
2825
2826 /* Process each data block in data record */
2827 blkptr = xbuf;
2828 while (xreclen > 0)
2829 {
2830 /* Compute the length of the block */
2831 datablk = (DATABLK*)blkptr;
2832 blkcyl = (datablk->cyl[0] << 8)
2833 | datablk->cyl[1];
2834 blkhead = (datablk->head[0] << 8)
2835 | datablk->head[1];
2836 blkrec = datablk->rec;
2837 keylen = datablk->klen;
2838 datalen = (datablk->dlen[0] << 8)
2839 | datablk->dlen[1];
2840 blklen = 12 + keylen + datalen;
2841
2842 /* Calculate the TTR in the original dataset */
2843 blktrk = (enddir == 0) ? 0 :
2844 calculate_ttr (blkcyl, blkhead,
2845 origheads, numext, xarray);
2846
2847 /* Write the data block to the output file */
2848 rc = write_block (cif, ofname, datablk, keylen, datalen,
2849 devtype, heads, trklen, maxtrks,
2850 &outusedv, &outusedr, &outtrkbr,
2851 &outtrk, &outcyl, &outhead, &outrec);
2852 if (rc < 0)
2853 {
2854 XMERRF ("HHCDL114E write error: input record "
2855 "CCHHR=%4.4X%4.4X%2.2X "
2856 "(TTR=%4.4X%2.2X) KL=%d DL=%d\n",
2857 blkcyl, blkhead, blkrec,
2858 blktrk, blkrec, keylen, datalen);
2859 return -1;
2860 }
2861
2862 XMINFF (4, "HHCDL115I CCHHR=%4.4X%4.4X%2.2X "
2863 "(TTR=%4.4X%2.2X) KL=%d DL=%d "
2864 "-> CCHHR=%4.4X%4.4X%2.2X "
2865 "(TTR=%4.4X%2.2X)\n",
2866 blkcyl, blkhead, blkrec,
2867 blktrk, blkrec, keylen, datalen,
2868 outcyl, outhead, outrec, outtrk, outrec);
2869
2870 /* Process directory block or member block */
2871 if (enddir == 0)
2872 {
2873 rc = process_dirblk (datablk, blklen,
2874 outcyl, outhead, outrec,
2875 dirblka, dirblkn, dirblu);
2876 if (rc < 0) return -1;
2877 enddir = rc;
2878
2879 /* Count the number of directory blocks read */
2880 if (enddir == 0) dirblkn++;
2881 }
2882 else /* Not a directory block */
2883 {
2884 /* Check that TTR conversion table is not full */
2885 if (numttr >= MAXTTR)
2886 {
2887 XMERRF ("HHCDL116E TTR count exceeds %d, "
2888 "increase MAXTTR\n",
2889 MAXTTR);
2890 return -1;
2891 }
2892
2893 /* Add an entry to the TTR conversion table */
2894 ttrtab[numttr].origttr[0] = (blktrk >> 8) & 0xFF;
2895 ttrtab[numttr].origttr[1] = blktrk & 0xFF;
2896 ttrtab[numttr].origttr[2] = blkrec;
2897 ttrtab[numttr].outpttr[0] = (outtrk >> 8) & 0xFF;
2898 ttrtab[numttr].outpttr[1] = outtrk & 0xFF;
2899 ttrtab[numttr].outpttr[2] = outrec;
2900 numttr++;
2901 }
2902
2903 /* Point to next data block in data record */
2904 xreclen -= blklen;
2905 blkptr += blklen;
2906
2907 } /* end while(xreclen) */
2908
2909 } /* end while(1) */
2910
2911 /* Check for unsupported xmit utility */
2912 if (method == METHOD_XMIT && copyfiln == 0)
2913 {
2914 XMERRF ("HHCDL130W WARNING -- XMIT file utility is not IEBCOPY;"
2915 " file %s not loaded\n", xfname);
2916 }
2917
2918 /* Return the last record number and track balance */
2919 *lastrec = outrec;
2920 *trkbal = outtrkbr;
2921
2922 /* Write any data remaining in track buffer */
2923 rc = write_track (cif, ofname, heads, trklen,
2924 &outusedv, &outtrk, &outcyl, &outhead);
2925 if (rc < 0) return -1;
2926
2927 /* Update the directory and rewrite to output file */
2928 for (i = 0; i < dirblkn; i++)
2929 {
2930 /* Obtain the directory block pointer from the array */
2931 datablk = dirblka[i];
2932
2933 /* Update TTR pointers in this directory block */
2934 rc = update_dirblk (cif, ofname, heads, trklen, dsstart,
2935 datablk, ttrtab, numttr);
2936 if (rc < 0) return -1;
2937
2938 /* Rewrite the updated directory block */
2939 blkcyl = (datablk->cyl[0] << 8) | datablk->cyl[1];
2940 blkhead = (datablk->head[0] << 8) | datablk->head[1];
2941 blkrec = datablk->rec;
2942 keylen = datablk->klen;
2943 datalen = (datablk->dlen[0] << 8) | datablk->dlen[1];
2944
2945 rc = update_block (cif, ofname, datablk, blkcyl, blkhead,
2946 blkrec, keylen, datalen, heads, trklen);
2947 if (rc < 0) return -1;
2948
2949 } /* end for(i) */
2950
2951 /* Close input file and release buffers */
2952 close (xfd);
2953 for (i = 0; i < dirblkn; i++)
2954 free (dirblka[i]);
2955 free (dirblka);
2956 free (xbuf);
2957 free (ttrtab);
2958
2959 /* Return the dataset attributes */
2960 *odsorg = dsorg;
2961 *orecfm = recfm;
2962 *olrecl = lrecl;
2963 *oblksz = blksz;
2964 *okeyln = keyln;
2965
2966 /* Return number of tracks and starting address of next dataset */
2967 *numtrks = outtrk;
2968 *nxtcyl = outcyl;
2969 *nxthead = outhead;
2970 return 0;
2971
2972 } /* end function process_iebcopy_file */
2973
2974 /*-------------------------------------------------------------------*/
2975 /* Subroutine to initialize a SYSCTLG dataset as an OS CVOL */
2976 /* Input: */
2977 /* ofname DASD image file name */
2978 /* cif -> CKD image file descriptor */
2979 /* volser Volume serial number */
2980 /* devtype Output device type */
2981 /* heads Output device number of tracks per cylinder */
2982 /* trklen Output device virtual track length */
2983 /* outcyl Output starting cylinder number */
2984 /* outhead Output starting head number */
2985 /* extsize Extent size in tracks */
2986 /* Output: */
2987 /* lastrec Record number of last block written */
2988 /* trkbal Number of bytes remaining on last track */
2989 /* numtrks Number of tracks written */
2990 /* nxtcyl Starting cylinder number for next dataset */
2991 /* nxthead Starting head number for next dataset */
2992 /* Note: */
2993 /* This subroutine builds a minimal SYSCTLG containing only */
2994 /* the entries required on an OS/360 IPL volume. */
2995 /*-------------------------------------------------------------------*/
2996 static int
cvol_initialize(char * ofname,CIFBLK * cif,char * volser,U16 devtype,int heads,int trklen,int outcyl,int outhead,int extsize,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)2997 cvol_initialize (char *ofname, CIFBLK *cif, char *volser,
2998 U16 devtype, int heads, int trklen,
2999 int outcyl, int outhead, int extsize,
3000 int *lastrec, int *trkbal,
3001 int *numtrks, int *nxtcyl, int *nxthead)
3002 {
3003 int rc; /* Return code */
3004 int i; /* Array subscript */
3005 int keylen; /* Key length of data block */
3006 int datalen; /* Data length of data block */
3007 int outusedv = 0; /* Output bytes used on track
3008 of virtual device */
3009 int outusedr = 0; /* Output bytes used on track
3010 of real device */
3011 int outtrkbr = 0; /* Output bytes remaining on
3012 track of real device */
3013 int outtrk = 0; /* Output relative track */
3014 int outrec = 0; /* Output record number */
3015 int blkptrk; /* Number of blocks per track*/
3016 int totblks; /* Number of blocks in CVOL */
3017 int bytes; /* Bytes used in this block */
3018 U32 ucbtype; /* UCB device type */
3019 PDSDIR *catent; /* -> Catalog entry */
3020 DATABLK datablk; /* Data block */
3021 #define NUM_SYS1_DATASETS 8 /* Number of SYS1 datasets */
3022 static char *sys1name[NUM_SYS1_DATASETS] =
3023 {"DUMP", "IMAGELIB", "LINKLIB", "NUCLEUS",
3024 "PARMLIB", "PROCLIB", "SAMPLIB", "SYSJOBQE"};
3025
3026 /* Set the key length and data length for SYSCTLG dataset */
3027 keylen = 8;
3028 datalen = 256;
3029
3030 /* Obtain the number of blocks which will fit on a track */
3031 capacity_calc (cif, 0, keylen, datalen, NULL, NULL,
3032 NULL, NULL, NULL, NULL, NULL,
3033 NULL, NULL, &blkptrk, NULL, NULL);
3034
3035 /* Calculate the total number of blocks in the catalog */
3036 totblks = extsize * blkptrk;
3037
3038 /* Get the UCB device type */
3039 ucbtype = ucbtype_code (devtype);
3040
3041 /*-----------------------------------*/
3042 /* Initialize the volume index block */
3043 /*-----------------------------------*/
3044 memset (datablk.kdarea, 0, keylen + datalen);
3045
3046 /* The key field contains all X'FF' */
3047 memcpy (datablk.kdarea, eighthexFF, 8);
3048
3049 /* The first entry begins after the 2 byte count field */
3050 bytes = 2;
3051 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3052
3053 /* Build the volume index control entry (VICE) */
3054
3055 /* The VICE name is X'0000000000000001' */
3056 memcpy (catent->pds2name, cvol_low_key, 8);
3057
3058 /* Set TTR to highest block in volume index, i.e. X'000001' */
3059 catent->pds2ttrp[0] = 0;
3060 catent->pds2ttrp[1] = 0;
3061 catent->pds2ttrp[2] = 1;
3062
3063 /* Indicator byte X'05' means 5 user halfwords follow, and
3064 uniquely identifies this catalog entry as a VICE */
3065 catent->pds2indc = 5;
3066
3067 /* Set the TTR of the last block of the catalog */
3068 catent->pds2usrd[0] = ((extsize - 1) >> 8) & 0xFF;
3069 catent->pds2usrd[1] = (extsize - 1) & 0xFF;
3070 catent->pds2usrd[2] = blkptrk;
3071 catent->pds2usrd[3] = 0;
3072
3073 /* Set the TTR of the first unused block (X'000003') */
3074 catent->pds2usrd[4] = 0;
3075 catent->pds2usrd[5] = 0;
3076 catent->pds2usrd[6] = 3;
3077
3078 /* Remainder of user data is 0 */
3079 catent->pds2usrd[7] = 0;
3080 catent->pds2usrd[8] = 0;
3081 catent->pds2usrd[9] = 0;
3082
3083 /* Increment bytes used by the length of the VICE */
3084 bytes += 22;
3085 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3086
3087 /* Build the index pointer for SYS1 */
3088 convert_to_ebcdic (catent->pds2name, 8, "SYS1");
3089
3090 /* Set TTR of the SYS1 index block, i.e. X'000002' */
3091 catent->pds2ttrp[0] = 0;
3092 catent->pds2ttrp[1] = 0;
3093 catent->pds2ttrp[2] = 2;
3094
3095 /* Indicator byte X'00' means no user halfwords follow, and
3096 uniquely identifies this catalog entry as an index pointer */
3097 catent->pds2indc = 0;
3098
3099 /* Increment bytes used by the length of the index pointer */
3100 bytes += 12;
3101 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3102
3103 /* Set the last entry in block marker */
3104 memcpy (catent->pds2name, eighthexFF, 8);
3105
3106 /* Increment bytes used by the last entry marker */
3107 bytes += 12;
3108 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3109
3110 /* Set the number of bytes used in this block */
3111 datablk.kdarea[keylen+0] = (bytes >> 8) & 0xFF;
3112 datablk.kdarea[keylen+1] = bytes & 0xFF;
3113
3114 /* Write the volume index block to the output file */
3115 rc = write_block (cif, ofname, &datablk, keylen, datalen,
3116 devtype, heads, trklen, extsize,
3117 &outusedv, &outusedr, &outtrkbr,
3118 &outtrk, &outcyl, &outhead, &outrec);
3119 if (rc < 0) return -1;
3120
3121 XMINFF (4, "HHCDL117I Catalog block at cyl %d head %d rec %d\n",
3122 outcyl, outhead, outrec);
3123 if (infolvl >= 5) data_dump (datablk.kdarea, keylen + datalen);
3124
3125 /* Count number of blocks written */
3126 totblks--;
3127
3128 /*---------------------------------*/
3129 /* Initialize the SYS1 index block */
3130 /*---------------------------------*/
3131 memset (datablk.kdarea, 0, keylen + datalen);
3132
3133 /* The key field contains all X'FF' */
3134 memcpy (datablk.kdarea, eighthexFF, 8);
3135
3136 /* The first entry begins after the 2 byte count field */
3137 bytes = 2;
3138 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3139
3140 /* Build the index control entry (ICE) */
3141
3142 /* The ICE name is X'0000000000000001' */
3143 memcpy (catent->pds2name, cvol_low_key, 8);
3144
3145 /* Set TTR to highest block in this index, i.e. X'000002' */
3146 catent->pds2ttrp[0] = 0;
3147 catent->pds2ttrp[1] = 0;
3148 catent->pds2ttrp[2] = 2;
3149
3150 /* Indicator byte X'03' means 3 user halfwords follow, and
3151 uniquely identifies this catalog entry as an ICE */
3152 catent->pds2indc = 3;
3153
3154 /* Set the TTR of this block */
3155 catent->pds2usrd[0] = 0;
3156 catent->pds2usrd[1] = 0;
3157 catent->pds2usrd[2] = 2;
3158
3159 /* The next byte contains the alias count */
3160 catent->pds2usrd[3] = 0;
3161
3162 /* The remaining 2 bytes of userdata are zeroes */
3163 catent->pds2usrd[4] = 0;
3164 catent->pds2usrd[5] = 0;
3165
3166 /* Increment bytes used by the length of the ICE */
3167 bytes += 18;
3168
3169 /* Build the dataset pointers for SYS1.xxxxxxxx datasets */
3170 for (i = 0; i < NUM_SYS1_DATASETS; i++)
3171 {
3172 /* Point to next dataset pointer entry */
3173 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3174
3175 /* Set the name of the dataset pointer entry */
3176 convert_to_ebcdic (catent->pds2name, 8, sys1name[i]);
3177
3178 /* Set the TTR to zero */
3179 catent->pds2ttrp[0] = 0;
3180 catent->pds2ttrp[1] = 0;
3181 catent->pds2ttrp[2] = 0;
3182
3183 /* Indicator byte X'07' means 7 user halfwords follow, and
3184 uniquely identifies the entry as a dataset pointer */
3185 catent->pds2indc = 7;
3186
3187 /* The next two bytes contain the volume count (X'0001') */
3188 catent->pds2usrd[0] = 0;
3189 catent->pds2usrd[1] = 1;
3190
3191 /* The next four bytes contain the UCB type */
3192 catent->pds2usrd[2] = (ucbtype >> 24) & 0xFF;
3193 catent->pds2usrd[3] = (ucbtype >> 16) & 0xFF;
3194 catent->pds2usrd[4] = (ucbtype >> 8) & 0xFF;
3195 catent->pds2usrd[5] = ucbtype & 0xFF;
3196
3197 /* The next six bytes contain the volume serial number */
3198 convert_to_ebcdic (catent->pds2usrd+6, 6, volser);
3199
3200 /* The next two bytes contain the volume seq.no. (X'0000') */
3201 catent->pds2usrd[12] = 0;
3202 catent->pds2usrd[13] = 0;
3203
3204 /* Increment bytes used by the length of the dataset pointer */
3205 bytes += 26;
3206
3207 } /* end for(i) */
3208
3209 /* Point to last entry in block */
3210 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3211
3212 /* Set the last entry in block marker */
3213 memcpy (catent->pds2name, eighthexFF, 8);
3214
3215 /* Increment bytes used by the last entry marker */
3216 bytes += 12;
3217 catent = (PDSDIR*)(datablk.kdarea + keylen + bytes);
3218
3219 /* Set the number of bytes used in this block */
3220 datablk.kdarea[keylen+0] = (bytes >> 8) & 0xFF;
3221 datablk.kdarea[keylen+1] = bytes & 0xFF;
3222
3223 /* Write the index block to the output file */
3224 rc = write_block (cif, ofname, &datablk, keylen, datalen,
3225 devtype, heads, trklen, extsize,
3226 &outusedv, &outusedr, &outtrkbr,
3227 &outtrk, &outcyl, &outhead, &outrec);
3228 if (rc < 0) return -1;
3229
3230 XMINFF (4, "HHCDL118I Catalog block at cyl %d head %d rec %d\n",
3231 outcyl, outhead, outrec);
3232 if (infolvl >= 5) data_dump (datablk.kdarea, keylen + datalen);
3233
3234 /* Count number of blocks written */
3235 totblks--;
3236
3237 /*--------------------------------------------*/
3238 /* Initialize remaining unused catalog blocks */
3239 /*--------------------------------------------*/
3240 while (totblks > 0)
3241 {
3242 memset (datablk.kdarea, 0, keylen + datalen);
3243
3244 /* Write the volume index block to the output file */
3245 rc = write_block (cif, ofname, &datablk, keylen, datalen,
3246 devtype, heads, trklen, extsize,
3247 &outusedv, &outusedr, &outtrkbr,
3248 &outtrk, &outcyl, &outhead, &outrec);
3249 if (rc < 0) return -1;
3250
3251 XMINFF (4, "HHCDL119I Catalog block at cyl %d head %d rec %d\n",
3252 outcyl, outhead, outrec);
3253 if (infolvl >= 5) data_dump (datablk.kdarea, keylen + datalen);
3254
3255 /* Count number of blocks written */
3256 totblks--;
3257
3258 } /* end while(totblks) */
3259
3260 /* Set the last record number to X'FF' so that OS/360 catalog
3261 management routines can recognize that the CVOL has been
3262 initialized by detecting X'FF' at ds1lstar+2 in the VTOC */
3263 *lastrec = 0xFF;
3264
3265 /* Return the track balance */
3266 *trkbal = outtrkbr;
3267
3268 /* Write data remaining in track buffer */
3269 rc = write_track (cif, ofname, heads, trklen,
3270 &outusedv, &outtrk, &outcyl, &outhead);
3271 if (rc < 0) return -1;
3272
3273 /* Return number of tracks and starting address of next dataset */
3274 *numtrks = outtrk;
3275 *nxtcyl = outcyl;
3276 *nxthead = outhead;
3277 return 0;
3278
3279 } /* end function cvol_initialize */
3280
3281 /*-------------------------------------------------------------------*/
3282 /* Subroutine to initialize a LOGREC dataset with IFCDIP00 header */
3283 /* Input: */
3284 /* ofname DASD image file name */
3285 /* cif -> CKD image file descriptor */
3286 /* devtype Output device type */
3287 /* heads Output device number of tracks per cylinder */
3288 /* trklen Output device virtual track length */
3289 /* outcyl Output starting cylinder number */
3290 /* outhead Output starting head number */
3291 /* extsize Extent size in tracks */
3292 /* Output: */
3293 /* lastrec Record number of last block written */
3294 /* trkbal Number of bytes remaining on last track */
3295 /* numtrks Number of tracks written */
3296 /* nxtcyl Starting cylinder number for next dataset */
3297 /* nxthead Starting head number for next dataset */
3298 /*-------------------------------------------------------------------*/
3299 static int
dip_initialize(char * ofname,CIFBLK * cif,U16 devtype,int heads,int trklen,int outcyl,int outhead,int extsize,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)3300 dip_initialize (char *ofname, CIFBLK *cif,
3301 U16 devtype, int heads, int trklen,
3302 int outcyl, int outhead, int extsize,
3303 int *lastrec, int *trkbal,
3304 int *numtrks, int *nxtcyl, int *nxthead)
3305 {
3306 int rc; /* Return code */
3307 int keylen; /* Key length of data block */
3308 int datalen; /* Data length of data block */
3309 int outusedv = 0; /* Output bytes used on track
3310 of virtual device */
3311 int outusedr = 0; /* Output bytes used on track
3312 of real device */
3313 int outtrkbr = 0; /* Output bytes remaining on
3314 track of real device */
3315 int outtrk = 0; /* Output relative track */
3316 int outrec = 0; /* Output record number */
3317 int remlen; /* Bytes remaining on 1st trk*/
3318 int physlen; /* Physical track length */
3319 int lasthead; /* Highest head on cylinder */
3320 int endcyl; /* Extent end cylinder */
3321 int endhead; /* Extent end head */
3322 int trklen90; /* 90% of track length */
3323 int cyl90; /* 90% full cylinder number */
3324 int head90; /* 90% full head number */
3325 int reltrk90; /* 90% full relative track */
3326 DIPHDR *diphdr; /* -> Record in data block */
3327 DATABLK datablk; /* Data block */
3328
3329 /* Set the key length and data length for the header record */
3330 keylen = 0;
3331 datalen = sizeof(DIPHDR);
3332
3333 /* Obtain the physical track size and the track balance
3334 remaining on the first track after the header record */
3335 capacity_calc (cif, 0, keylen, datalen, NULL, &remlen,
3336 &physlen, NULL, NULL, NULL, NULL, NULL,
3337 NULL, NULL, NULL, NULL);
3338
3339 /* Calculate the end of extent cylinder and head */
3340 lasthead = heads - 1;
3341 endcyl = outcyl;
3342 endhead = outhead + extsize - 1;
3343 while (endhead >= heads)
3344 {
3345 endhead -= heads;
3346 endcyl++;
3347 }
3348
3349 /* Calculate the 90% full cylinder and head */
3350 trklen90 = physlen * 9 / 10;
3351 reltrk90 = extsize * trklen90 / physlen;
3352 if (reltrk90 == 0) reltrk90 = 1;
3353 cyl90 = outcyl;
3354 head90 = outhead + reltrk90 - 1;
3355 while (head90 >= heads)
3356 {
3357 head90 -= heads;
3358 cyl90++;
3359 }
3360
3361 /* Initialize the DIP header record */
3362 diphdr = (DIPHDR*)(datablk.kdarea);
3363 memset (diphdr, 0, sizeof(DIPHDR));
3364 diphdr->recid[0] = 0xFF;
3365 diphdr->recid[1] = 0xFF;
3366 diphdr->bcyl[0] = (outcyl >> 8) & 0xFF;
3367 diphdr->bcyl[1] = outcyl & 0xFF;
3368 diphdr->btrk[0] = (outhead >> 8) & 0xFF;
3369 diphdr->btrk[1] = outhead & 0xFF;
3370 diphdr->ecyl[0] = (endcyl >> 8) & 0xFF;
3371 diphdr->ecyl[1] = endcyl & 0xFF;
3372 diphdr->etrk[0] = (endhead >> 8) & 0xFF;
3373 diphdr->etrk[1] = endhead & 0xFF;
3374 diphdr->restart[2] = (outcyl >> 8) & 0xFF;
3375 diphdr->restart[3] = outcyl & 0xFF;
3376 diphdr->restart[4] = (outhead >> 8) & 0xFF;
3377 diphdr->restart[5] = outhead & 0xFF;
3378 diphdr->restart[6] = 1;
3379 diphdr->trkbal[0] = (remlen >> 8) & 0xFF;
3380 diphdr->trkbal[1] = remlen & 0xFF;
3381 diphdr->trklen[0] = (physlen >> 8) & 0xFF;
3382 diphdr->trklen[1] = physlen & 0xFF;
3383 diphdr->reused[2] = (outcyl >> 8) & 0xFF;
3384 diphdr->reused[3] = outcyl & 0xFF;
3385 diphdr->reused[4] = (outhead >> 8) & 0xFF;
3386 diphdr->reused[5] = outhead & 0xFF;
3387 diphdr->reused[6] = 1;
3388 diphdr->lasthead[0] = (lasthead >> 8) & 0xFF;
3389 diphdr->lasthead[1] = lasthead & 0xFF;
3390 diphdr->trklen90[0] = (trklen90 >> 8) & 0xFF;
3391 diphdr->trklen90[1] = trklen90 & 0xFF;
3392 diphdr->devcode = (ucbtype_code(devtype) & 0x0F) | 0xF0;
3393 diphdr->cchh90[0] = (cyl90 >> 8) & 0xFF;
3394 diphdr->cchh90[1] = cyl90 & 0xFF;
3395 diphdr->cchh90[2] = (head90 >> 8) & 0xFF;
3396 diphdr->cchh90[3] = head90 & 0xFF;
3397 diphdr->endid = 0xFF;
3398
3399 /* Write the data block to the output file */
3400 rc = write_block (cif, ofname, &datablk, keylen, datalen,
3401 devtype, heads, trklen, extsize,
3402 &outusedv, &outusedr, &outtrkbr,
3403 &outtrk, &outcyl, &outhead, &outrec);
3404 if (rc < 0) return -1;
3405
3406 XMINFF (3, "HHCDL120I DIP complete at cyl %d head %d rec %d\n",
3407 outcyl, outhead, outrec);
3408 if (infolvl >= 5) data_dump (diphdr, sizeof(DIPHDR));
3409
3410 /* Return the last record number and track balance */
3411 *lastrec = outrec;
3412 *trkbal = outtrkbr;
3413
3414 /* Write data remaining in track buffer */
3415 rc = write_track (cif, ofname, heads, trklen,
3416 &outusedv, &outtrk, &outcyl, &outhead);
3417 if (rc < 0) return -1;
3418
3419 /* Return number of tracks and starting address of next dataset */
3420 *numtrks = outtrk;
3421 *nxtcyl = outcyl;
3422 *nxthead = outhead;
3423 return 0;
3424
3425 } /* end function dip_initialize */
3426
3427 /*-------------------------------------------------------------------*/
3428 /* Subroutine to initialize a sequential dataset */
3429 /* Input: */
3430 /* sfname SEQ input file name */
3431 /* ofname DASD image file name */
3432 /* cif -> CKD image file descriptor */
3433 /* devtype Output device type */
3434 /* heads Output device number of tracks per cylinder */
3435 /* trklen Output device virtual track length */
3436 /* outcyl Output starting cylinder number */
3437 /* outhead Output starting head number */
3438 /* extsize Extent size in tracks */
3439 /* dsorg Dataset organization (DA or PS) */
3440 /* recfm Record Format (F or FB) */
3441 /* lrecl Record length */
3442 /* blksz Block size */
3443 /* keyln Key length */
3444 /* Output: */
3445 /* lastrec Record number of last block written */
3446 /* trkbal Number of bytes remaining on last track */
3447 /* numtrks Number of tracks written */
3448 /* nxtcyl Starting cylinder number for next dataset */
3449 /* nxthead Starting head number for next dataset */
3450 /*-------------------------------------------------------------------*/
3451 static int
seq_initialize(char * sfname,char * ofname,CIFBLK * cif,U16 devtype,int heads,int trklen,int outcyl,int outhead,int extsize,BYTE dsorg,BYTE recfm,int lrecl,int blksz,int keyln,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)3452 seq_initialize (char *sfname, char *ofname, CIFBLK *cif, U16 devtype,
3453 int heads, int trklen, int outcyl, int outhead,
3454 int extsize, BYTE dsorg, BYTE recfm,
3455 int lrecl, int blksz, int keyln,
3456 int *lastrec, int *trkbal,
3457 int *numtrks, int *nxtcyl, int *nxthead)
3458 {
3459 int rc; /* Return code */
3460 int sfd; /* Input seq file descriptor */
3461 int size; /* Size left in input file */
3462 int outusedv = 0; /* Output bytes used on track
3463 of virtual device */
3464 int outusedr = 0; /* Output bytes used on track
3465 of real device */
3466 int outtrkbr = 0; /* Output bytes remaining on
3467 track of real device */
3468 int outtrk = 0; /* Output relative track */
3469 int outrec = 0; /* Output record number */
3470 struct stat st; /* Data area for fstat() */
3471 DATABLK datablk; /* Data block */
3472 char pathname[MAX_PATH]; /* sfname in host path format*/
3473
3474 /* Perform some checks */
3475 if (!(dsorg & DSORG_PS) && !(dsorg & DSORG_DA))
3476 {
3477 XMERRF ("HHCDL121E SEQ dsorg must be PS or DA: dsorg=0x%2.2x\n",dsorg);
3478 return -1;
3479 }
3480 if (recfm != RECFM_FORMAT_F && recfm != (RECFM_FORMAT_F|RECFM_BLOCKED))
3481 {
3482 XMERRF ("HHCDL122E SEQ recfm must be F or FB: recfm=0x%2.2x\n",recfm);
3483 return -1;
3484 }
3485 if (blksz == 0) blksz = lrecl;
3486 if (lrecl == 0) lrecl = blksz;
3487 if (lrecl == 0 || blksz % lrecl != 0
3488 || (blksz != lrecl && recfm == RECFM_FORMAT_F))
3489 {
3490 XMERRF ("HHCDL123E SEQ invalid lrecl or blksz: lrecl=%d blksz=%d\n",
3491 lrecl,blksz);
3492 return -1;
3493 }
3494 if (keyln > 0 && blksz > lrecl)
3495 {
3496 XMERR ("HHCDL124E SEQ keyln must be 0 for blocked files\n");
3497 return -1;
3498 }
3499
3500 /* Open the input file */
3501 hostpath(pathname, sfname, sizeof(pathname));
3502 sfd = hopen(pathname, O_RDONLY|O_BINARY);
3503 if (sfd < 0)
3504 {
3505 XMERRF ("HHCDL125E Cannot open %s: %s\n",
3506 sfname, strerror(errno));
3507 return -1;
3508 }
3509
3510 /* Get input file status */
3511 rc = fstat(sfd, &st);
3512 if (rc < 0)
3513 {
3514 XMERRF ("HHCDL126E Cannot stat %s: %s\n",
3515 sfname, strerror(errno));
3516 close (sfd);
3517 return -1;
3518 }
3519 size = st.st_size;
3520
3521 /* Read the first track */
3522 rc = read_track (cif, *nxtcyl, *nxthead);
3523 if (rc < 0)
3524 {
3525 XMERRF ("HHCDL127E %s cyl %d head %d read error\n",
3526 ofname, *nxtcyl, *nxthead);
3527 close (sfd);
3528 return -1;
3529 }
3530
3531 while (size > 0)
3532 {
3533 /* Read a block of data from the input file */
3534 rc = read (sfd, &datablk.kdarea, blksz < size ? blksz : size);
3535 if (rc < (blksz < size ? blksz : size))
3536 {
3537 XMERRF ("HHCDL128E %s read error: %s\n",
3538 sfname, strerror(errno));
3539 close (sfd);
3540 return -1;
3541 }
3542 size -= rc;
3543
3544 /* Pad the block if necessary */
3545 if (rc < blksz)
3546 {
3547 /* Adjust blksize down to next
3548 highest multiple of lrecl */
3549 blksz = (((rc-1) / lrecl) + 1) * lrecl;
3550 memset (&datablk.kdarea[rc], 0, blksz - rc);
3551 }
3552
3553 rc = write_block (cif, ofname, &datablk, keyln, blksz - keyln,
3554 devtype, heads, trklen, extsize,
3555 &outusedv, &outusedr, &outtrkbr,
3556 &outtrk, &outcyl, &outhead, &outrec);
3557 if (rc < 0)
3558 {
3559 close (sfd);
3560 return -1;
3561 }
3562 }
3563
3564 /* Close the input file */
3565 close (sfd);
3566
3567 /* Create the end of file record */
3568 rc = write_block (cif, ofname, &datablk, 0, 0,
3569 devtype, heads, trklen, extsize,
3570 &outusedv, &outusedr, &outtrkbr,
3571 &outtrk, &outcyl, &outhead, &outrec);
3572 if (rc < 0) return -1;
3573
3574 /* Return the last record number and track balance */
3575 *lastrec = outrec;
3576 *trkbal = outtrkbr;
3577
3578 /* Write data remaining in track buffer */
3579 rc = write_track (cif, ofname, heads, trklen,
3580 &outusedv, &outtrk, &outcyl, &outhead);
3581 if (rc < 0) return -1;
3582
3583 /* Return number of tracks and starting address of next dataset */
3584 *numtrks = outtrk;
3585 *nxtcyl = outcyl;
3586 *nxthead = outhead;
3587 return 0;
3588
3589 } /* end function seq_initialize */
3590
3591 /*-------------------------------------------------------------------*/
3592 /* Subroutine to add a logical record to an output buffer */
3593 /* */
3594 /* If there is no room in the buffer for the logical record */
3595 /* then the block in the buffer is written to the output device */
3596 /* and the logical record is added to the now empty buffer. */
3597 /* A call with reclen=0 is a request to flush a partial block */
3598 /* without adding a new record. */
3599 /* */
3600 /* Input: */
3601 /* cif -> CKD image file descriptor */
3602 /* ofname Output file name */
3603 /* datablk Pointer to buffer containing data block */
3604 /* keylen Length of key in data block */
3605 /* devtype Output device type */
3606 /* heads Number of tracks per cylinder on output device */
3607 /* trklen Track length of virtual output device */
3608 /* maxtrks Maximum number of tracks to be written */
3609 /* recptr Pointer to record to be added (excluding RDW) */
3610 /* reclen Length of record to be added */
3611 /* recfm Output dataset record format */
3612 /* blksz Maximum blocksize of output dataset */
3613 /* Input/output: */
3614 /* blklen Number of data bytes currently in block */
3615 /* usedv Number of bytes written to track of virtual device */
3616 /* usedr Number of bytes written to track, calculated */
3617 /* according to the formula for a real device */
3618 /* trkbal Number of bytes remaining on track, calculated */
3619 /* according to the formula for a real device */
3620 /* reltrk Relative track number on output device */
3621 /* cyl Cylinder number on output device */
3622 /* head Head number on output device */
3623 /* rec Record number on output device */
3624 /* Output: */
3625 /* The return value is 0 if successful, -1 if error occurred. */
3626 /*-------------------------------------------------------------------*/
3627 static int
add_logical_record(CIFBLK * cif,char * ofname,DATABLK * datablk,int keylen,U16 devtype,int heads,int trklen,int maxtrks,BYTE * recptr,int reclen,BYTE recfm,int blksz,int * blklen,int * usedv,int * usedr,int * trkbal,int * reltrk,int * cyl,int * head,int * rec)3628 add_logical_record (CIFBLK *cif, char *ofname, DATABLK *datablk,
3629 int keylen, U16 devtype, int heads, int trklen,
3630 int maxtrks, BYTE *recptr, int reclen, BYTE recfm,
3631 int blksz, int *blklen, int *usedv, int *usedr,
3632 int *trkbal, int *reltrk, int *cyl, int *head, int *rec)
3633 {
3634 int rc; /* Return code */
3635 int recsize; /* Record length with RDW */
3636 BYTE *dataptr; /* -> byte in data block */
3637
3638 /* Calculate the logical record length including RDW */
3639 recsize = reclen;
3640 if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V) recsize += 4;
3641
3642 /* Flush the buffer if the record format is unblocked
3643 or there is no room for the record in the buffer
3644 or the requested record length is zero */
3645 if (*blklen > 0 && (!(recfm & RECFM_BLOCKED)
3646 || *blklen + recsize > blksz || reclen == 0))
3647 {
3648 if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V)
3649 {
3650 /* Build BDW for variable length block */
3651 dataptr = datablk->kdarea + keylen;
3652 dataptr[0] = *blklen >> 8;
3653 dataptr[1] = *blklen & 0xFF;
3654 dataptr[2] = 0x00;
3655 dataptr[3] = 0x00;
3656 }
3657
3658 /* Write the data block to the output file */
3659 rc = write_block (cif, ofname, datablk, keylen, *blklen,
3660 devtype, heads, trklen, maxtrks,
3661 usedv, usedr, trkbal, reltrk, cyl, head, rec);
3662 if (rc < 0) {
3663 return -1;
3664 }
3665
3666 XMINFF (4, "HHCDL135I CCHHR=%4.4X%4.4X%2.2X "
3667 "(TTR=%4.4X%2.2X) KL=%d DL=%d\n",
3668 *cyl, *head, *rec, *reltrk, *rec,
3669 keylen, *blklen);
3670
3671 /* Indicate that the buffer is now empty */
3672 *blklen = 0;
3673 }
3674
3675 /* Nothing more to do if record length is zero */
3676 if (reclen == 0) {
3677 return 0;
3678 }
3679
3680 /* Account for the BDW and RDW for variable length records */
3681 if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V)
3682 {
3683 /* Allow space for the BDW if at start of block */
3684 if (*blklen == 0) *blklen = 4;
3685
3686 /* Build RDW for variable length record */
3687 dataptr = datablk->kdarea + keylen + *blklen;
3688 dataptr[0] = recsize >> 8;
3689 dataptr[1] = recsize & 0xFF;
3690 dataptr[2] = 0x00;
3691 dataptr[3] = 0x00;
3692 *blklen += 4;
3693 }
3694
3695 /* Copy the logical record to the data block */
3696 dataptr = datablk->kdarea + keylen + *blklen;
3697 memcpy(dataptr, recptr, reclen);
3698 *blklen += reclen;
3699
3700 return 0;
3701 } /* end function add_logical_record */
3702
3703 /*-------------------------------------------------------------------*/
3704 /* Subroutine to read an INMCOPY file and write to DASD image file */
3705 /* Input: */
3706 /* xfname XMIT input file name */
3707 /* ofname DASD image file name */
3708 /* cif -> CKD image file descriptor */
3709 /* devtype Output device type */
3710 /* heads Output device number of tracks per cylinder */
3711 /* trklen Output device virtual track length */
3712 /* outcyl Output starting cylinder number */
3713 /* outhead Output starting head number */
3714 /* maxtrks Maximum extent size in tracks */
3715 /* Output: */
3716 /* odsorg Dataset organization */
3717 /* orecfm Record format */
3718 /* olrecl Logical record length */
3719 /* oblksz Block size */
3720 /* okeyln Key length */
3721 /* lastrec Record number of last block written */
3722 /* trkbal Number of bytes remaining on last track */
3723 /* numtrks Number of tracks written */
3724 /* nxtcyl Starting cylinder number for next dataset */
3725 /* nxthead Starting head number for next dataset */
3726 /*-------------------------------------------------------------------*/
3727 static int
process_inmcopy_file(char * xfname,char * ofname,CIFBLK * cif,U16 devtype,int heads,int trklen,int outcyl,int outhead,int maxtrks,BYTE * odsorg,BYTE * orecfm,int * olrecl,int * oblksz,int * okeyln,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)3728 process_inmcopy_file (char *xfname, char *ofname, CIFBLK *cif,
3729 U16 devtype, int heads, int trklen,
3730 int outcyl, int outhead, int maxtrks,
3731 BYTE *odsorg, BYTE *orecfm,
3732 int *olrecl, int *oblksz, int *okeyln,
3733 int *lastrec, int *trkbal,
3734 int *numtrks, int *nxtcyl, int *nxthead)
3735 {
3736 int rc = 0; /* Return code */
3737 int xfd; /* XMIT file descriptor */
3738 BYTE *xbuf; /* -> Logical record buffer */
3739 int xreclen; /* Logical record length */
3740 BYTE xctl; /* 0x20=Control record */
3741 char xrecname[8]; /* XMIT control record name */
3742 int datarecn = 0; /* Data record counter */
3743 int datafiln = 0; /* Data file counter */
3744 int copyfiln = 0; /* Seq num of file to copy */
3745 BYTE dsorg=0; /* Dataset organization */
3746 BYTE recfm=0; /* Dataset record format */
3747 U16 lrecl=0; /* Dataset record length */
3748 U16 blksz=0; /* Dataset block size */
3749 U16 keyln=0; /* Dataset key length */
3750 U16 dirnm; /* Number of directory blocks*/
3751 DATABLK datablk; /* Data block */
3752 int keylen; /* Key length of data block */
3753 int blklen; /* Data length of data block */
3754 int outusedv = 0; /* Output bytes used on track
3755 of virtual device */
3756 int outusedr = 0; /* Output bytes used on track
3757 of real device */
3758 int outtrkbr = 0; /* Output bytes remaining on
3759 track of real device */
3760 int outtrk = 0; /* Output relative track */
3761 int outrec = 0; /* Output record number */
3762 char pathname[MAX_PATH]; /* xfname in host path format*/
3763
3764 /* Open the input file */
3765 hostpath(pathname, xfname, sizeof(pathname));
3766 xfd = hopen(pathname, O_RDONLY|O_BINARY);
3767 if (xfd < 0)
3768 {
3769 XMERRF ("HHCDL136E Cannot open %s: %s\n",
3770 xfname, strerror(errno));
3771 return -1;
3772 }
3773
3774 /* Obtain the input logical record buffer */
3775 xbuf = malloc (65536);
3776 if (xbuf == NULL)
3777 {
3778 XMERRF ("HHCDL137E Cannot obtain input buffer: %s\n",
3779 strerror(errno));
3780 close (xfd);
3781 return -1;
3782 }
3783 keylen = 0;
3784 blklen = 0;
3785
3786 /* Display the file information message */
3787 XMINFF (1, "HHCDL139I Processing file %s\n", xfname);
3788
3789 /* Read each logical record */
3790 while (1)
3791 {
3792 xctl=0;
3793 rc = read_xmit_rec (xfd, xfname, xbuf, &xctl);
3794 if (rc < 0) return -1;
3795 xreclen = rc;
3796
3797 /* Process control records */
3798 if (xctl)
3799 {
3800 /* Extract the control record name */
3801 make_asciiz (xrecname, sizeof(xrecname), xbuf, 6);
3802 XMINFF (4, "HHCDL131I Control record: %s length %d\n",
3803 xrecname, xreclen);
3804
3805 /* Exit if control record is a trailer record */
3806 if (strcmp(xrecname, "INMR06") == 0)
3807 break;
3808
3809 /* Process control record according to type */
3810 if (strcmp(xrecname, "INMR02") == 0)
3811 {
3812 rc = process_inmr02 (xbuf, xreclen, "INMCOPY", ©filn,
3813 &dsorg, &recfm, &lrecl, &blksz,
3814 &keyln, &dirnm);
3815 if (rc < 0) return -1;
3816 }
3817 else
3818 {
3819 rc = process_inmrxx (xbuf, xreclen);
3820 if (rc < 0) return -1;
3821 }
3822
3823 /* Reset the data counter if data control record */
3824 if (strcmp(xrecname, "INMR03") == 0)
3825 {
3826 datafiln++;
3827 datarecn = 0;
3828 XMINFF (4, "HHCDL132I File number: %d %s\n", datafiln,
3829 (datafiln == copyfiln) ? "(selected)"
3830 : "(not selected)");
3831 }
3832
3833 /* Loop to get next record */
3834 continue;
3835
3836 } /* end if(xctl) */
3837
3838 /* Process data records */
3839 datarecn++;
3840 XMINFF (4, "HHCDL133I Data record: length %d\n", xreclen);
3841 if (infolvl >= 5) data_dump (xbuf, xreclen);
3842
3843 /* If this is not the INMCOPY file then ignore data record */
3844 if (datafiln != copyfiln)
3845 {
3846 continue;
3847 }
3848
3849 /* Copy the logical record to the data block, and
3850 write the block to the output file if necessary */
3851 rc = add_logical_record (cif, ofname, &datablk, keylen,
3852 devtype, heads, trklen, maxtrks,
3853 xbuf, xreclen, recfm, blksz, &blklen,
3854 &outusedv, &outusedr, &outtrkbr,
3855 &outtrk, &outcyl, &outhead, &outrec);
3856 if (rc < 0)
3857 {
3858 close(xfd);
3859 return -1;
3860 }
3861
3862 } /* end while(1) */
3863
3864 /* Flush the last partial data block to the output file */
3865 if (blklen > 0)
3866 {
3867 rc = add_logical_record (cif, ofname, &datablk, keylen,
3868 devtype, heads, trklen, maxtrks,
3869 NULL, 0, recfm, blksz, &blklen,
3870 &outusedv, &outusedr, &outtrkbr,
3871 &outtrk, &outcyl, &outhead, &outrec);
3872 if (rc < 0)
3873 {
3874 close(xfd);
3875 return -1;
3876 }
3877 }
3878
3879 /* Check for unsupported xmit utility */
3880 if (copyfiln == 0)
3881 {
3882 XMERRF ("HHCDL138W WARNING -- XMIT file utility is not INMCOPY;"
3883 " file %s not loaded\n", xfname);
3884 }
3885
3886 /* Close input file and release buffer */
3887 close (xfd);
3888 free (xbuf);
3889
3890 /* Create the end of file record */
3891 rc = write_block (cif, ofname, &datablk, 0, 0,
3892 devtype, heads, trklen, maxtrks,
3893 &outusedv, &outusedr, &outtrkbr,
3894 &outtrk, &outcyl, &outhead, &outrec);
3895 if (rc < 0) return -1;
3896
3897 /* Return the last record number and track balance */
3898 *lastrec = outrec;
3899 *trkbal = outtrkbr;
3900
3901 /* Write any data remaining in track buffer */
3902 rc = write_track (cif, ofname, heads, trklen,
3903 &outusedv, &outtrk, &outcyl, &outhead);
3904 if (rc < 0) return -1;
3905
3906 /* Return the dataset attributes */
3907 *odsorg = dsorg;
3908 *orecfm = recfm;
3909 *olrecl = lrecl;
3910 *oblksz = blksz;
3911 *okeyln = keyln;
3912
3913 /* Return number of tracks and starting address of next dataset */
3914 *numtrks = outtrk;
3915 *nxtcyl = outcyl;
3916 *nxthead = outhead;
3917 return 0;
3918
3919 } /* end function process_inmcopy_file */
3920
3921 /*-------------------------------------------------------------------*/
3922 /* Subroutine to read ASCII text file and write to DASD image file */
3923 /* Input: */
3924 /* tfname ASCII text input file name */
3925 /* ofname DASD image file name */
3926 /* cif -> CKD image file descriptor */
3927 /* devtype Output device type */
3928 /* heads Output device number of tracks per cylinder */
3929 /* trklen Output device virtual track length */
3930 /* outcyl Output starting cylinder number */
3931 /* outhead Output starting head number */
3932 /* maxtrks Maximum extent size in tracks */
3933 /* dsorg Dataset organization (DA or PS) */
3934 /* recfm Record Format (F or FB) */
3935 /* lrecl Record length */
3936 /* blksz Block size */
3937 /* keyln Key length */
3938 /* Output: */
3939 /* lastrec Record number of last block written */
3940 /* trkbal Number of bytes remaining on last track */
3941 /* numtrks Number of tracks written */
3942 /* nxtcyl Starting cylinder number for next dataset */
3943 /* nxthead Starting head number for next dataset */
3944 /*-------------------------------------------------------------------*/
3945 static int
process_text_file(char * tfname,char * ofname,CIFBLK * cif,U16 devtype,int heads,int trklen,int outcyl,int outhead,int maxtrks,BYTE dsorg,BYTE recfm,int lrecl,int blksz,int keyln,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)3946 process_text_file (char *tfname, char *ofname, CIFBLK *cif,
3947 U16 devtype, int heads, int trklen,
3948 int outcyl, int outhead, int maxtrks,
3949 BYTE dsorg, BYTE recfm,
3950 int lrecl, int blksz, int keyln,
3951 int *lastrec, int *trkbal,
3952 int *numtrks, int *nxtcyl, int *nxthead)
3953 {
3954 int rc = 0; /* Return code */
3955 FILE *tfp; /* Text file pointer */
3956 char *tbuf; /* -> Text buffer */
3957 int tbuflen = 65536; /* Text buffer length */
3958 int txtlen; /* Input text line length */
3959 int lineno = 0; /* Line number in input file */
3960 BYTE *rbuf; /* -> Logical record buffer */
3961 int reclen; /* Output record length */
3962 int maxlen; /* Maximum record length */
3963 DATABLK datablk; /* Data block */
3964 int keylen; /* Key length of data block */
3965 int blklen; /* Data length of data block */
3966 int reccount = 0; /* Number of records copied */
3967 int outusedv = 0; /* Output bytes used on track
3968 of virtual device */
3969 int outusedr = 0; /* Output bytes used on track
3970 of real device */
3971 int outtrkbr = 0; /* Output bytes remaining on
3972 track of real device */
3973 int outtrk = 0; /* Output relative track */
3974 int outrec = 0; /* Output record number */
3975 char format; /* Record format: F,V,U */
3976 char pathname[MAX_PATH]; /* tfname in host path format*/
3977
3978 /* Validate the DCB attributes */
3979 if (dsorg != DSORG_PS) {
3980 XMERRF ("HHCDL141E TEXT dsorg must be PS: dsorg=0x%2.2x\n", dsorg);
3981 return -1;
3982 }
3983 if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_F) format = 'F';
3984 else if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_V) format = 'V';
3985 else if ((recfm & RECFM_FORMAT) == RECFM_FORMAT_U) format = 'U';
3986 else {
3987 XMERRF ("HHCDL142E TEXT recfm must be F, V, or U: recfm=0x%2.2x\n", recfm);
3988 return -1;
3989 }
3990 if (blksz == 0) blksz = (format == 'V') ? lrecl + 4 : lrecl;
3991 if ((lrecl == 0 && format != 'U')
3992 || (format == 'F' && blksz % lrecl != 0)
3993 || (format == 'V' && lrecl < 5)
3994 || (format == 'V' && blksz < lrecl + 4)
3995 || (recfm == RECFM_FORMAT_F && blksz != lrecl))
3996 {
3997 XMERRF ("HHCDL143E TEXT invalid lrecl or blksz: lrecl=%d blksz=%d\n",
3998 lrecl, blksz);
3999 return -1;
4000 }
4001 if (keyln > 0)
4002 {
4003 XMERR ("HHCDL144E TEXT key length must be 0\n");
4004 return -1;
4005 }
4006
4007 /* Open the input file */
4008 hostpath(pathname, tfname, sizeof(pathname));
4009 tfp = fopen(pathname, "r");
4010 if (tfp == NULL)
4011 {
4012 XMERRF ("HHCDL145E Cannot open %s: %s\n",
4013 tfname, strerror(errno));
4014 return -1;
4015 }
4016
4017 /* Obtain the input and output buffers */
4018 maxlen = (format == 'F') ? lrecl : (format == 'V') ? lrecl - 4 : blksz;
4019 rbuf = malloc(maxlen + tbuflen);
4020 if (rbuf == NULL)
4021 {
4022 XMERRF ("HHCDL146E Cannot obtain input/output buffers: %s\n",
4023 strerror(errno));
4024 fclose(tfp);
4025 return -1;
4026 }
4027 tbuf = (char*)(rbuf + maxlen);
4028
4029 /* Copy each logical record to the output file */
4030 keylen = 0;
4031 blklen = 0;
4032 while (1)
4033 {
4034 /* Read next record from input file */
4035 lineno++;
4036 if (fgets (tbuf, tbuflen, tfp) == NULL)
4037 {
4038 /* Exit at end of input file */
4039 if (feof(tfp)) break;
4040
4041 /* Terminate if error reading input file */
4042 XMERRF ("HHCDL147E Cannot read %s line %d: %s\n",
4043 tfname, lineno, strerror(errno));
4044 fclose(tfp);
4045 return -1;
4046 }
4047
4048 /* Check for DOS end of file character */
4049 if (tbuf[0] == '\x1A')
4050 break;
4051
4052 /* Check that end of statement has been read */
4053 txtlen = strlen(tbuf);
4054 if (txtlen == tbuflen - 1 && tbuf[txtlen-1] != '\n')
4055 {
4056 XMERRF ("HHCDL148E No line feed found in line %d of %s\n",
4057 lineno, tfname);
4058 fclose(tfp);
4059 return -1;
4060 }
4061
4062 /* Remove trailing carriage return and line feed */
4063 txtlen--;
4064 if (txtlen > 0 && tbuf[txtlen-1] == '\r') txtlen--;
4065
4066 /* Remove trailing spaces and tab characters */
4067 while (txtlen > 0 && (tbuf[txtlen-1] == SPACE
4068 || tbuf[txtlen-1] == '\t')) txtlen--;
4069 tbuf[txtlen] = '\0';
4070
4071 /* Validate the record length */
4072 if (txtlen > maxlen) {
4073 XMERRF ("HHCDL149E Record length %d exceeds %d at line %d of %s\n",
4074 txtlen, maxlen, lineno, tfname);
4075 fclose(tfp);
4076 return -1;
4077 }
4078
4079 /* Translate from ASCII to EBCDIC and pad with blanks if fixed */
4080 reclen = (format == 'F') ? lrecl : txtlen;
4081 convert_to_ebcdic (rbuf, reclen, tbuf);
4082
4083 /* Copy the logical record to the data block, and
4084 write the block to the output file if necessary */
4085 rc = add_logical_record (cif, ofname, &datablk, keylen,
4086 devtype, heads, trklen, maxtrks,
4087 rbuf, reclen, recfm, blksz, &blklen,
4088 &outusedv, &outusedr, &outtrkbr,
4089 &outtrk, &outcyl, &outhead, &outrec);
4090 if (rc < 0)
4091 {
4092 fclose(tfp);
4093 return -1;
4094 }
4095 reccount++;
4096
4097 } /* end while(1) */
4098
4099 /* Flush the last partial data block to the output file */
4100 if (blklen > 0)
4101 {
4102 rc = add_logical_record (cif, ofname, &datablk, keylen,
4103 devtype, heads, trklen, maxtrks,
4104 NULL, 0, recfm, blksz, &blklen,
4105 &outusedv, &outusedr, &outtrkbr,
4106 &outtrk, &outcyl, &outhead, &outrec);
4107 if (rc < 0)
4108 {
4109 fclose(tfp);
4110 return -1;
4111 }
4112 }
4113
4114 /* Close input file and release buffers */
4115 fclose(tfp);
4116 free(rbuf);
4117
4118 /* Create the end of file record */
4119 rc = write_block (cif, ofname, &datablk, 0, 0,
4120 devtype, heads, trklen, maxtrks,
4121 &outusedv, &outusedr, &outtrkbr,
4122 &outtrk, &outcyl, &outhead, &outrec);
4123 if (rc < 0) return -1;
4124
4125 /* Return the last record number and track balance */
4126 *lastrec = outrec;
4127 *trkbal = outtrkbr;
4128
4129 /* Write any data remaining in track buffer */
4130 rc = write_track (cif, ofname, heads, trklen,
4131 &outusedv, &outtrk, &outcyl, &outhead);
4132 if (rc < 0) return -1;
4133
4134 /* Display number of records written */
4135 XMINFF (1, "HHCDL140I %d records copied from %s\n", reccount, tfname);
4136
4137 /* Return number of tracks and starting address of next dataset */
4138 *numtrks = outtrk;
4139 *nxtcyl = outcyl;
4140 *nxthead = outhead;
4141 return 0;
4142
4143 } /* end function process_text_file */
4144
4145 /*-------------------------------------------------------------------*/
4146 /* Subroutine to initialize an empty dataset */
4147 /* Input: */
4148 /* ofname DASD image file name */
4149 /* cif -> CKD image file descriptor */
4150 /* devtype Output device type */
4151 /* heads Output device number of tracks per cylinder */
4152 /* trklen Output device virtual track length */
4153 /* outcyl Output starting cylinder number */
4154 /* outhead Output starting head number */
4155 /* extsize Extent size in tracks */
4156 /* dsorg Dataset organization */
4157 /* dirblks Number of directory blocks */
4158 /* Output: */
4159 /* dirblu Bytes used in last directory block */
4160 /* lastrec Record number of last block written */
4161 /* trkbal Number of bytes remaining on last track */
4162 /* numtrks Number of tracks written */
4163 /* nxtcyl Starting cylinder number for next dataset */
4164 /* nxthead Starting head number for next dataset */
4165 /*-------------------------------------------------------------------*/
4166 static int
empty_initialize(char * ofname,CIFBLK * cif,U16 devtype,int heads,int trklen,int outcyl,int outhead,int extsize,BYTE dsorg,int dirblks,int * dirblu,int * lastrec,int * trkbal,int * numtrks,int * nxtcyl,int * nxthead)4167 empty_initialize (char *ofname, CIFBLK *cif, U16 devtype,
4168 int heads, int trklen, int outcyl, int outhead,
4169 int extsize, BYTE dsorg, int dirblks,
4170 int *dirblu, int *lastrec, int *trkbal,
4171 int *numtrks, int *nxtcyl, int *nxthead)
4172 {
4173 int rc; /* Return code */
4174 int i; /* Loop counter */
4175 int keylen; /* Key length of data block */
4176 int datalen; /* Data length of data block */
4177 int outusedv = 0; /* Output bytes used on track
4178 of virtual device */
4179 int outusedr = 0; /* Output bytes used on track
4180 of real device */
4181 int outtrkbr = 0; /* Output bytes remaining on
4182 track of real device */
4183 int outdblu = 0; /* Output bytes used in last
4184 directory block */
4185 int outtrk = 0; /* Output relative track */
4186 int outrec = 0; /* Output record number */
4187 DATABLK datablk; /* Data block */
4188
4189 /* Initialize the directory if dataset is a PDS */
4190 if (dsorg & DSORG_PO)
4191 {
4192 /* Build the first directory block */
4193 keylen = 8;
4194 datalen = 256;
4195 outdblu = 14;
4196 memset (datablk.kdarea, 0, keylen + datalen);
4197 memcpy (datablk.kdarea, eighthexFF, 8);
4198 datablk.kdarea[keylen] = (outdblu >> 8);
4199 datablk.kdarea[keylen+1] = outdblu & 0xFF;
4200 memcpy (datablk.kdarea + keylen + 2, eighthexFF, 8);
4201
4202 /* Write directory blocks to output dataset */
4203 for (i = 0; i < dirblks; i++)
4204 {
4205 /* Write a directory block */
4206 rc = write_block (cif, ofname, &datablk, keylen, datalen,
4207 devtype, heads, trklen, extsize,
4208 &outusedv, &outusedr, &outtrkbr,
4209 &outtrk, &outcyl, &outhead, &outrec);
4210 if (rc < 0) return -1;
4211
4212 /* Clear subsequent directory blocks to zero */
4213 memset (datablk.kdarea, 0, keylen + datalen);
4214
4215 } /* end for(i) */
4216
4217 } /* end if(DSORG_PO) */
4218
4219 /* Create the end of file record */
4220 keylen = 0;
4221 datalen = 0;
4222 rc = write_block (cif, ofname, &datablk, keylen, datalen,
4223 devtype, heads, trklen, extsize,
4224 &outusedv, &outusedr, &outtrkbr,
4225 &outtrk, &outcyl, &outhead, &outrec);
4226 if (rc < 0) return -1;
4227
4228 /* Return number of bytes used in last directory block */
4229 *dirblu = outdblu;
4230
4231 /* Return the last record number and track balance */
4232 *lastrec = outrec;
4233 *trkbal = outtrkbr;
4234
4235 /* Write data remaining in track buffer */
4236 rc = write_track (cif, ofname, heads, trklen,
4237 &outusedv, &outtrk, &outcyl, &outhead);
4238 if (rc < 0) return -1;
4239
4240 /* Return number of tracks and starting address of next dataset */
4241 *numtrks = outtrk;
4242 *nxtcyl = outcyl;
4243 *nxthead = outhead;
4244 return 0;
4245
4246 } /* end function empty_initialize */
4247
4248 /*-------------------------------------------------------------------*/
4249 /* Subroutine to read a statement from the control file */
4250 /* Input: */
4251 /* cfp Control file pointer */
4252 /* cfname Control file name */
4253 /* stmt Buffer to receive control statement */
4254 /* sbuflen Length of statement buffer */
4255 /* Output: */
4256 /* pstmtno Statement number */
4257 /* The return value is 0 if a statement was successfully read, */
4258 /* +1 if end of file, or -1 if error */
4259 /*-------------------------------------------------------------------*/
4260 static int
read_ctrl_stmt(FILE * cfp,char * cfname,char * stmt,int sbuflen,int * pstmtno)4261 read_ctrl_stmt (FILE *cfp, char *cfname, char *stmt, int sbuflen,
4262 int *pstmtno)
4263 {
4264 int stmtlen; /* Length of input statement */
4265 static int stmtno = 0; /* Statement number */
4266
4267 while (1)
4268 {
4269 /* Read next record from control file */
4270 stmtno++;
4271 *pstmtno = stmtno;
4272 if (fgets (stmt, sbuflen, cfp) == NULL)
4273 {
4274 /* Return code +1 if end of control file */
4275 if (feof(cfp)) return +1;
4276
4277 /* Return code -1 if control file input error */
4278 XMERRF ("HHCDL019E Cannot read %s line %d: %s\n",
4279 cfname, stmtno, strerror(errno));
4280 return -1;
4281 }
4282
4283 #ifdef EXTERNALGUI
4284 /* Indicate input file progess */
4285 if (extgui) fprintf (stderr, "IPOS=%" I64_FMT "d\n", (U64)ftell(cfp));
4286 #endif /*EXTERNALGUI*/
4287
4288 /* Check for DOS end of file character */
4289 if (stmt[0] == '\x1A')
4290 return +1;
4291
4292 /* Check that end of statement has been read */
4293 stmtlen = strlen(stmt);
4294 if (stmtlen == 0 || stmt[stmtlen-1] != '\n')
4295 {
4296 XMERRF ("HHCDL020E Line too long in %s line %d\n",
4297 cfname, stmtno);
4298 return -1;
4299 }
4300
4301 /* Remove trailing carriage return and line feed */
4302 stmtlen--;
4303 if (stmtlen > 0 && stmt[stmtlen-1] == '\r') stmtlen--;
4304
4305 /* Remove trailing spaces and tab characters */
4306 while (stmtlen > 0 && (stmt[stmtlen-1] == SPACE
4307 || stmt[stmtlen-1] == '\t')) stmtlen--;
4308 stmt[stmtlen] = '\0';
4309
4310 /* Print the input statement */
4311 XMINFF (0, "--------- %s\n", stmt);
4312
4313 /* Ignore comment statements */
4314 if (stmtlen == 0 || stmt[0] == '#' || stmt[0] == '*')
4315 continue;
4316
4317 break;
4318 } /* end while */
4319
4320 return 0;
4321 } /* end function read_ctrl_stmt */
4322
4323 /*-------------------------------------------------------------------*/
4324 /* Subroutine to parse a dataset statement from the control file */
4325 /* Input: */
4326 /* stmt Control statement */
4327 /* Output: */
4328 /* dsname ASCIIZ dataset name (1-44 bytes + terminator) */
4329 /* method Processing method (see METHOD_xxx defines) */
4330 /* */
4331 /* The following field is returned only for the XMIT method: */
4332 /* ifptr Pointer to XMIT initialization file name */
4333 /* */
4334 /* The following fields are returned for non-XMIT methods: */
4335 /* units Allocation units (C=CYL, T=TRK) */
4336 /* sppri Primary allocation quantity */
4337 /* spsec Secondary allocation quantity */
4338 /* spdir Directory allocation quantity */
4339 /* dsorg 1st byte of dataset organization bits */
4340 /* recfm 1st byte of record format bits */
4341 /* lrecl Logical record length */
4342 /* blksz Block size */
4343 /* keyln Key length */
4344 /* The return value is 0 if successful, or -1 if error. */
4345 /* Control statement format: */
4346 /* dsname method [initfile] [space [dcbattrib]] */
4347 /* The method can be: */
4348 /* XMIT = load PDS from initfile containing an IEBCOPY unload */
4349 /* dataset created using the TSO TRANSMIT command */
4350 /* EMPTY = create empty dataset (do not specify initfile) */
4351 /* DIP = initialize LOGREC dataset with IFCDIP00 header record */
4352 /* CVOL = initialize SYSCTLG dataset as an OS CVOL */
4353 /* VTOC = reserve space for the VTOC (dsname is ignored) */
4354 /* The space allocation can be: */
4355 /* CYL [pri [sec [dir]]] */
4356 /* TRK [pri [sec [dir]]] */
4357 /* If primary quantity is omitted then the dataset will be */
4358 /* allocated the minimum number of tracks or cylinders needed */
4359 /* to contain the data loaded from the initfile. */
4360 /* Default allocation is in tracks. */
4361 /* The dcb attributes can be: */
4362 /* dsorg recfm lrecl blksize keylen */
4363 /* For the XMIT method the dcb attributes are taken from the */
4364 /* initialization file and need not be specified. */
4365 /* Examples: */
4366 /* SYS1.PARMLIB XMIT /cdrom/os360/reslibs/parmlib.xmi */
4367 /* SYS1.NUCLEUS XMIT /cdrom/os360/reslibs/nucleus.xmi CYL */
4368 /* SYS1.SYSJOBQE EMPTY CYL 10 0 0 DA F 176 176 0 */
4369 /* SYS1.DUMP EMPTY CYL 10 2 0 PS FB 4104 4104 0 */
4370 /* SYS1.OBJPDS EMPTY CYL 10 2 50 PO FB 80 3120 0 */
4371 /* SYSVTOC VTOC CYL 1 */
4372 /* SYSCTLG CVOL TRK 10 */
4373 /* SYS1.LOGREC DIP CYL 1 */
4374 /*-------------------------------------------------------------------*/
4375 static int
parse_ctrl_stmt(char * stmt,char * dsname,BYTE * method,char ** ifptr,BYTE * units,int * sppri,int * spsec,int * spdir,BYTE * dsorg,BYTE * recfm,int * lrecl,int * blksz,int * keyln)4376 parse_ctrl_stmt (char *stmt, char *dsname, BYTE *method, char **ifptr,
4377 BYTE *units, int *sppri, int *spsec, int *spdir,
4378 BYTE *dsorg, BYTE *recfm,
4379 int *lrecl, int *blksz, int *keyln)
4380 {
4381 char *pdsnam; /* -> dsname in input stmt */
4382 char *punits; /* -> allocation units */
4383 char *psppri; /* -> primary space quantity */
4384 char *pspsec; /* -> secondary space qty. */
4385 char *pspdir; /* -> directory space qty. */
4386 char *pdsorg; /* -> dataset organization */
4387 char *precfm; /* -> record format */
4388 char *plrecl; /* -> logical record length */
4389 char *pblksz; /* -> block size */
4390 char *pkeyln; /* -> key length */
4391 char *pimeth; /* -> initialization method */
4392 char *pifile; /* -> initialization filename*/
4393 BYTE c; /* Character work area */
4394
4395 /* Parse the input statement */
4396 pdsnam = strtok (stmt, " \t");
4397 pimeth = strtok (NULL, " \t");
4398
4399 /* Check that all mandatory fields are present */
4400 if (pdsnam == NULL || pimeth == NULL)
4401 {
4402 XMERR ("HHCDL021E DSNAME or initialization method missing\n");
4403 return -1;
4404 }
4405
4406 /* Return the dataset name in EBCDIC and ASCII */
4407 string_to_upper (pdsnam);
4408 memset (dsname, 0, 45);
4409 strncpy (dsname, pdsnam, 44);
4410
4411 /* Set default dataset attribute values */
4412 *units = 'T';
4413 *sppri = 1;
4414 *spsec = 0;
4415 *spdir = 0;
4416 *dsorg = 0x00;
4417 *recfm = 0x00;
4418 *lrecl = 0;
4419 *blksz = 0;
4420 *keyln = 0;
4421 *ifptr = NULL;
4422
4423 /* Test for valid initialization method */
4424 if (strcasecmp(pimeth, "XMIT") == 0)
4425 *method = METHOD_XMIT;
4426 else if (strcasecmp(pimeth, "VS") == 0)
4427 *method = METHOD_VS;
4428 else if (strcasecmp(pimeth, "EMPTY") == 0)
4429 *method = METHOD_EMPTY;
4430 else if (strcasecmp(pimeth, "DIP") == 0)
4431 *method = METHOD_DIP;
4432 else if (strcasecmp(pimeth, "CVOL") == 0)
4433 *method = METHOD_CVOL;
4434 else if (strcasecmp(pimeth, "VTOC") == 0)
4435 *method = METHOD_VTOC;
4436 else if (strcasecmp(pimeth, "SEQ") == 0)
4437 *method = METHOD_SEQ;
4438 else if (strcasecmp(pimeth, "XMSEQ") == 0)
4439 *method = METHOD_XMSEQ;
4440 else if (strcasecmp(pimeth, "TEXT") == 0)
4441 *method = METHOD_TEXT;
4442 else
4443 {
4444 XMERRF ("HHCDL022E Invalid initialization method: %s\n", pimeth);
4445 return -1;
4446 }
4447
4448 /* Locate the initialization file name */
4449 if (*method == METHOD_XMIT || *method == METHOD_VS || *method == METHOD_SEQ
4450 || *method == METHOD_XMSEQ || *method == METHOD_TEXT)
4451 {
4452 pifile = strtok (NULL, " \t");
4453 if (pifile == NULL)
4454 {
4455 XMERR ("HHCDL023E Initialization file name missing\n");
4456 return -1;
4457 }
4458 *ifptr = pifile;
4459 }
4460
4461 /* Determine the space allocation units */
4462 punits = strtok (NULL, " \t");
4463 if (punits == NULL) return 0;
4464
4465 string_to_upper (punits);
4466 if (strcmp(punits, "CYL") == 0)
4467 *units = 'C';
4468 else if (strcmp(punits, "TRK") == 0)
4469 *units = 'T';
4470 else
4471 {
4472 XMERRF ("HHCDL024E Invalid allocation units: %s\n",
4473 punits);
4474 return -1;
4475 }
4476
4477 /* Determine the primary space allocation quantity */
4478 psppri = strtok (NULL, " \t");
4479 if (psppri == NULL) return 0;
4480
4481 if (sscanf(psppri, "%u%c", sppri, &c) != 1)
4482 {
4483 XMERRF ("HHCDL025E Invalid primary space: %s\n",
4484 psppri);
4485 return -1;
4486 }
4487
4488 /* Determine the secondary space allocation quantity */
4489 pspsec = strtok (NULL, " \t");
4490 if (pspsec == NULL) return 0;
4491
4492 if (sscanf(pspsec, "%u%c", spsec, &c) != 1)
4493 {
4494 XMERRF ("HHCDL026E Invalid secondary space: %s\n",
4495 pspsec);
4496 return -1;
4497 }
4498
4499 /* Determine the directory space allocation quantity */
4500 pspdir = strtok (NULL, " \t");
4501 if (pspdir == NULL) return 0;
4502
4503 if (sscanf(pspdir, "%u%c", spdir, &c) != 1)
4504 {
4505 XMERRF ("HHCDL027E Invalid directory space: %s\n",
4506 pspsec);
4507 return -1;
4508 }
4509
4510 /* Determine the dataset organization */
4511 pdsorg = strtok (NULL, " \t");
4512 if (pdsorg == NULL) return 0;
4513
4514 string_to_upper (pdsorg);
4515 if (strcmp(pdsorg, "IS") == 0)
4516 *dsorg = DSORG_IS;
4517 else if (strcmp(pdsorg, "PS") == 0)
4518 *dsorg = DSORG_PS;
4519 else if (strcmp(pdsorg, "DA") == 0)
4520 *dsorg = DSORG_DA;
4521 else if (strcmp(pdsorg, "PO") == 0)
4522 *dsorg = DSORG_PO;
4523 else
4524 {
4525 XMERRF ("HHCDL028E Invalid dataset organization: %s\n",
4526 pdsorg);
4527 return -1;
4528 }
4529
4530 /* Determine the record format */
4531 precfm = strtok (NULL, " \t");
4532 if (precfm == NULL) return 0;
4533
4534 string_to_upper (precfm);
4535 if (strcmp(precfm, "F") == 0)
4536 *recfm = RECFM_FORMAT_F;
4537 else if (strcmp(precfm, "FA") == 0)
4538 *recfm = RECFM_FORMAT_F | RECFM_CTLCHAR_A;
4539 else if (strcmp(precfm, "FM") == 0)
4540 *recfm = RECFM_FORMAT_F | RECFM_CTLCHAR_M;
4541 else if (strcmp(precfm, "FB") == 0)
4542 *recfm = RECFM_FORMAT_F | RECFM_BLOCKED;
4543 else if (strcmp(precfm, "FBA") == 0)
4544 *recfm = RECFM_FORMAT_F | RECFM_BLOCKED | RECFM_CTLCHAR_A;
4545 else if (strcmp(precfm, "FBM") == 0)
4546 *recfm = RECFM_FORMAT_F | RECFM_BLOCKED | RECFM_CTLCHAR_M;
4547 else if (strcmp(precfm, "FBS") == 0)
4548 *recfm = RECFM_FORMAT_F | RECFM_BLOCKED | RECFM_SPANNED;
4549 else if (strcmp(precfm, "V") == 0)
4550 *recfm = RECFM_FORMAT_V;
4551 else if (strcmp(precfm, "VA") == 0)
4552 *recfm = RECFM_FORMAT_V | RECFM_CTLCHAR_A;
4553 else if (strcmp(precfm, "VM") == 0)
4554 *recfm = RECFM_FORMAT_V | RECFM_CTLCHAR_M;
4555 else if (strcmp(precfm, "VB") == 0)
4556 *recfm = RECFM_FORMAT_V | RECFM_BLOCKED;
4557 else if (strcmp(precfm, "VBA") == 0)
4558 *recfm = RECFM_FORMAT_V | RECFM_BLOCKED | RECFM_CTLCHAR_A;
4559 else if (strcmp(precfm, "VBM") == 0)
4560 *recfm = RECFM_FORMAT_V | RECFM_BLOCKED | RECFM_CTLCHAR_M;
4561 else if (strcmp(precfm, "VBS") == 0)
4562 *recfm = RECFM_FORMAT_V | RECFM_BLOCKED | RECFM_SPANNED;
4563 else if (strcmp(precfm, "U") == 0)
4564 *recfm = RECFM_FORMAT_U;
4565 else
4566 {
4567 XMERRF ("HHCDL029E Invalid record format: %s\n",
4568 precfm);
4569 return -1;
4570 }
4571
4572 /* Determine the logical record length */
4573 plrecl = strtok (NULL, " \t");
4574 if (plrecl == NULL) return 0;
4575
4576 if (sscanf(plrecl, "%u%c", lrecl, &c) != 1
4577 || *lrecl > MAX_DATALEN)
4578 {
4579 XMERRF ("HHCDL030E Invalid logical record length: %s\n",
4580 plrecl);
4581 return -1;
4582 }
4583
4584 /* Determine the block size */
4585 pblksz = strtok (NULL, " \t");
4586 if (pblksz == NULL) return 0;
4587
4588 if (sscanf(pblksz, "%u%c", blksz, &c) != 1
4589 || *blksz > MAX_DATALEN)
4590 {
4591 XMERRF ("HHCDL031E Invalid block size: %s\n",
4592 pblksz);
4593 return -1;
4594 }
4595
4596 /* Determine the key length */
4597 pkeyln = strtok (NULL, " \t");
4598 if (pkeyln == NULL) return 0;
4599
4600 if (sscanf(pkeyln, "%u%c", keyln, &c) != 1
4601 || *keyln > 255)
4602 {
4603 XMERRF ("HHCDL032E Invalid key length: %s\n",
4604 pkeyln);
4605 return -1;
4606 }
4607
4608 return 0;
4609 } /* end function parse_ctrl_stmt */
4610
4611 /*-------------------------------------------------------------------*/
4612 /* Subroutine to process the control file */
4613 /* Input: */
4614 /* cfp Control file pointer */
4615 /* cfname Control file name */
4616 /* ofname DASD image file name */
4617 /* cif -> CKD image file descriptor */
4618 /* volser Output volume serial number (ASCIIZ) */
4619 /* devtype Output device type */
4620 /* reqcyls Requested device size in cylinders, or zero */
4621 /* heads Output device number of tracks per cylinder */
4622 /* trklen Output device virtual track length */
4623 /* outcyl Output starting cylinder number */
4624 /* outhead Output starting head number */
4625 /* Output: */
4626 /* Datasets are written to the DASD image file as indicated */
4627 /* by the control statements. */
4628 /*-------------------------------------------------------------------*/
4629 static int
process_control_file(FILE * cfp,char * cfname,char * ofname,CIFBLK * cif,char * volser,U16 devtype,int reqcyls,int heads,int trklen,int outcyl,int outhead)4630 process_control_file (FILE *cfp, char *cfname, char *ofname,
4631 CIFBLK *cif, char *volser, U16 devtype, int reqcyls,
4632 int heads, int trklen, int outcyl, int outhead)
4633 {
4634 int rc; /* Return code */
4635 int i; /* Array subscript */
4636 int n; /* Integer work area */
4637 char dsname[45]; /* Dataset name (ASCIIZ) */
4638 BYTE method; /* Initialization method */
4639 char *ifname; /* ->Initialization file name*/
4640 BYTE units; /* C=CYL, T=TRK */
4641 int sppri; /* Primary space quantity */
4642 int spsec; /* Secondary space quantity */
4643 int spdir; /* Directory space quantity */
4644 BYTE dsorg; /* Dataset organization */
4645 BYTE recfm; /* Record format */
4646 int lrecl; /* Logical record length */
4647 int blksz; /* Block size */
4648 int keyln; /* Key length */
4649 char stmt[256]; /* Control file statement */
4650 int stmtno; /* Statement number */
4651 int mintrks; /* Minimum size of dataset */
4652 int maxtrks; /* Maximum size of dataset */
4653 int outusedv; /* Bytes used in track buffer*/
4654 int tracks = 0; /* Tracks used in dataset */
4655 int numdscb = 0; /* Number of DSCBs */
4656 DATABLK **dscbtab; /* -> Array of DSCB pointers */
4657 int dirblu; /* Bytes used in last dirblk */
4658 int lasttrk; /* Relative track number of
4659 last used track of dataset*/
4660 int lastrec; /* Record number of last used
4661 block of dataset */
4662 int trkbal; /* Bytes unused on last track*/
4663 int bcyl; /* Dataset begin cylinder */
4664 int bhead; /* Dataset begin head */
4665 int ecyl; /* Dataset end cylinder */
4666 int ehead; /* Dataset end head */
4667 int vtoctrk = 0; /* VTOC start relative track */
4668 int vtocext = 0; /* VTOC extent size (tracks) */
4669 BYTE volvtoc[5]; /* VTOC begin CCHHR */
4670 int offset = 0; /* Offset into trkbuf */
4671 int fsflag = 0; /* 1=Free space message sent */
4672
4673 /* Obtain storage for the array of DSCB pointers */
4674 dscbtab = (DATABLK**)malloc (sizeof(DATABLK*) * MAXDSCB);
4675 if (dscbtab == NULL)
4676 {
4677 XMERRF ("HHCDL010E Cannot obtain storage for DSCB pointer array: %s\n",
4678 strerror(errno));
4679 return -1;
4680 }
4681
4682 /* Initialize the DSCB array with format 4 and format 5 DSCBs */
4683 rc = build_format4_dscb (dscbtab, numdscb, cif);
4684 if (rc < 0) return -1;
4685 numdscb++;
4686
4687 rc = build_format5_dscb (dscbtab, numdscb);
4688 if (rc < 0) return -1;
4689 numdscb++;
4690
4691 /* Read dataset statements from control file */
4692 while (1)
4693 {
4694 /* Read next statement from control file */
4695 rc = read_ctrl_stmt (cfp, cfname, stmt, sizeof(stmt), &stmtno);
4696 if (rc < 0) return -1;
4697
4698 /* Exit if end of file */
4699 if (rc > 0)
4700 break;
4701
4702 /* Parse dataset statement from control file */
4703 rc = parse_ctrl_stmt (stmt, dsname, &method, &ifname,
4704 &units, &sppri, &spsec, &spdir,
4705 &dsorg, &recfm, &lrecl, &blksz, &keyln);
4706
4707 /* Exit if error in control file */
4708 if (rc < 0)
4709 {
4710 XMERRF ("HHCDL011E Invalid statement in %s line %d\n",
4711 cfname, stmtno);
4712 return -1;
4713 }
4714
4715 /* Write empty tracks if allocation is in cylinders */
4716 while (units == 'C' && outhead != 0)
4717 {
4718 /* Initialize track buffer with empty track */
4719 init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv);
4720
4721 /* Write track to output file */
4722 rc = write_track (cif, ofname, heads, trklen,
4723 &outusedv, &tracks, &outcyl, &outhead);
4724 if (rc < 0) break;
4725
4726 } /* end while */
4727
4728 XMINFF (1, "HHCDL012I Creating dataset %s at cyl %d head %d\n",
4729 dsname, outcyl, outhead);
4730 bcyl = outcyl;
4731 bhead = outhead;
4732
4733 /* Calculate minimum size of dataset in tracks */
4734 mintrks = (units == 'C' ? sppri * heads : sppri);
4735
4736 /* Create dataset according to method specified */
4737 switch (method) {
4738
4739 case METHOD_XMIT: /* IEBCOPY wrapped in XMIT */
4740 case METHOD_VS: /* "straight" IEBCOPY */
4741 /* Create dataset using IEBCOPY file as input */
4742 maxtrks = MAX_TRACKS;
4743 rc = process_iebcopy_file (ifname, ofname, cif,
4744 devtype, heads, trklen,
4745 outcyl, outhead, maxtrks,
4746 method,
4747 &dsorg, &recfm,
4748 &lrecl, &blksz, &keyln,
4749 &dirblu, &lastrec, &trkbal,
4750 &tracks, &outcyl, &outhead);
4751 if (rc < 0) return -1;
4752 break;
4753
4754 case METHOD_DIP:
4755 /* Initialize LOGREC dataset */
4756 rc = dip_initialize (ofname, cif,
4757 devtype, heads, trklen,
4758 outcyl, outhead, mintrks,
4759 &lastrec, &trkbal,
4760 &tracks, &outcyl, &outhead);
4761 if (rc < 0) return -1;
4762 break;
4763
4764 case METHOD_CVOL:
4765 /* Initialize SYSCTLG dataset */
4766 rc = cvol_initialize (ofname, cif, volser,
4767 devtype, heads, trklen,
4768 outcyl, outhead, mintrks,
4769 &lastrec, &trkbal,
4770 &tracks, &outcyl, &outhead);
4771 if (rc < 0) return -1;
4772 break;
4773
4774 case METHOD_VTOC:
4775 /* Reserve space for VTOC */
4776 vtoctrk = (outcyl * heads) + outhead;
4777 vtocext = mintrks;
4778 tracks = 0;
4779 lastrec = 0;
4780 trkbal = 0;
4781 break;
4782
4783 case METHOD_SEQ:
4784 /* Create sequential dataset */
4785 rc = seq_initialize (ifname, ofname, cif,
4786 devtype, heads, trklen,
4787 outcyl, outhead, mintrks,
4788 dsorg, recfm, lrecl, blksz,
4789 keyln, &lastrec, &trkbal,
4790 &tracks, &outcyl, &outhead);
4791 if (rc < 0) return -1;
4792 break;
4793
4794 case METHOD_XMSEQ:
4795 /* Create sequential dataset using XMIT file as input */
4796 maxtrks = MAX_TRACKS;
4797 rc = process_inmcopy_file (ifname, ofname, cif,
4798 devtype, heads, trklen,
4799 outcyl, outhead, maxtrks,
4800 &dsorg, &recfm,
4801 &lrecl, &blksz, &keyln,
4802 &lastrec, &trkbal,
4803 &tracks, &outcyl, &outhead);
4804 if (rc < 0) return -1;
4805 break;
4806
4807 case METHOD_TEXT:
4808 /* Create sequential dataset using an ASCII text file as input */
4809 maxtrks = MAX_TRACKS;
4810 rc = process_text_file (ifname, ofname, cif,
4811 devtype, heads, trklen,
4812 outcyl, outhead, maxtrks,
4813 dsorg, recfm, lrecl, blksz, keyln,
4814 &lastrec, &trkbal,
4815 &tracks, &outcyl, &outhead);
4816 if (rc < 0) return -1;
4817 break;
4818
4819 default:
4820 case METHOD_EMPTY:
4821 /* Create empty dataset */
4822 rc = empty_initialize (ofname, cif,
4823 devtype, heads, trklen,
4824 outcyl, outhead, mintrks,
4825 dsorg, spdir,
4826 &dirblu, &lastrec, &trkbal,
4827 &tracks, &outcyl, &outhead);
4828 if (rc < 0) return -1;
4829 break;
4830
4831 } /* end switch(method) */
4832
4833 /* Calculate the relative track number of last used track */
4834 lasttrk = tracks - 1;
4835
4836 /* Round up space allocation if allocated in cylinders */
4837 if (units == 'C')
4838 {
4839 n = (tracks + heads - 1) / heads * heads;
4840 if (mintrks < n) mintrks = n;
4841 }
4842
4843 /* Fill unused space in dataset with empty tracks */
4844 while (tracks < mintrks)
4845 {
4846 /* Initialize track buffer with empty track */
4847 init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv);
4848
4849 /* Write track to output file */
4850 rc = write_track (cif, ofname, heads, trklen,
4851 &outusedv, &tracks, &outcyl, &outhead);
4852 if (rc < 0) return -1;
4853
4854 } /* end while(tracks) */
4855
4856 /* Print number of tracks written to dataset */
4857 XMINFF (2, "HHCDL013I Dataset %s contains %d track%s\n",
4858 dsname, tracks, (tracks == 1 ? "" : "s"));
4859
4860 /* Calculate end of extent cylinder and head */
4861 ecyl = (outhead > 0 ? outcyl : outcyl - 1);
4862 ehead = (outhead > 0 ? outhead - 1 : heads - 1);
4863
4864 /* Create format 1 DSCB for the dataset */
4865 if (method != METHOD_VTOC)
4866 {
4867 rc = build_format1_dscb (dscbtab, numdscb, dsname, volser,
4868 dsorg, recfm, lrecl, blksz,
4869 keyln, dirblu, lasttrk, lastrec,
4870 trkbal, units, spsec,
4871 bcyl, bhead, ecyl, ehead);
4872 if (rc < 0) return -1;
4873 numdscb++;
4874 }
4875
4876 } /* end while */
4877
4878 /* Write the VTOC */
4879 rc = write_vtoc (dscbtab, numdscb, cif, ofname, devtype,
4880 reqcyls, heads, trklen, vtoctrk, vtocext,
4881 &outcyl, &outhead, volvtoc);
4882 if (rc < 0) return -1;
4883
4884 /* Write empty tracks up to end of volume */
4885 while (outhead != 0 || outcyl < reqcyls)
4886 {
4887 /* Issue free space information message */
4888 if (fsflag == 0)
4889 {
4890 XMINFF (1, "HHCDL014I Free space starts at cyl %d head %d\n",
4891 outcyl, outhead);
4892 fsflag = 1;
4893 }
4894
4895 #ifdef EXTERNALGUI
4896 /* Indicate output file progess */
4897 if (extgui)
4898 if ((outcyl % 10) == 0)
4899 fprintf (stderr, "OUTCYL=%d\n", outcyl);
4900 #endif /*EXTERNALGUI*/
4901
4902 /* Initialize track buffer with empty track */
4903 init_track (trklen, cif->trkbuf, outcyl, outhead, &outusedv);
4904
4905 /* Write track to output file */
4906 rc = write_track (cif, ofname, heads, trklen,
4907 &outusedv, &tracks, &outcyl, &outhead);
4908 if (rc < 0) return -1;
4909
4910 } /* end while */
4911
4912 if (outcyl > reqcyls && reqcyls != 0)
4913 {
4914 XMINFF (0, "HHCDL015W Volume exceeds %d cylinders\n",
4915 reqcyls);
4916 }
4917
4918 XMINFF (0, "HHCDL016I Total of %d cylinders written to %s\n",
4919 outcyl, ofname);
4920
4921 /* Update the VTOC pointer in the volume label */
4922 offset = CKDDASD_TRKHDR_SIZE + CKDDASD_RECHDR_SIZE + 8
4923 + CKDDASD_RECHDR_SIZE + IPL1_KEYLEN + IPL1_DATALEN
4924 + CKDDASD_RECHDR_SIZE + IPL2_KEYLEN + IPL2_DATALEN
4925 + CKDDASD_RECHDR_SIZE + VOL1_KEYLEN + 11;
4926
4927 XMINFF (5, "HHCDL017I Updating VTOC pointer %2.2X%2.2X%2.2X%2.2X%2.2X\n",
4928 volvtoc[0], volvtoc[1], volvtoc[2], volvtoc[3],
4929 volvtoc[4]);
4930
4931 rc = read_track (cif, 0, 0);
4932 if (rc < 0)
4933 {
4934 XMERR ("HHCDL018E Cannot read VOL1 record\n");
4935 return -1;
4936 }
4937
4938 memcpy (cif->trkbuf + offset, volvtoc, sizeof(volvtoc));
4939 cif->trkmodif = 1;
4940
4941 /* Release the DSCB buffers */
4942 for (i = 0; i < numdscb; i++)
4943 free (dscbtab[i]);
4944
4945 /* Release the array of DSCB pointers */
4946 free (dscbtab);
4947
4948 return 0;
4949
4950 } /* end function process_control_file */
4951
4952 /*-------------------------------------------------------------------*/
4953 /* DASDLOAD main entry point */
4954 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])4955 int main (int argc, char *argv[])
4956 {
4957 int rc = 0; /* Return code */
4958 char *cfname; /* -> Control file name */
4959 char *ofname; /* -> Output file name */
4960 FILE *cfp; /* Control file pointer */
4961 CIFBLK *cif; /* -> CKD image block */
4962 CKDDEV *ckd; /* -> CKD table entry */
4963 char *volser; /* -> Volume serial (ASCIIZ) */
4964 char *sdevtp; /* -> Device type (ASCIIZ) */
4965 char *sdevsz; /* -> Device size (ASCIIZ) */
4966 char *iplfnm; /* -> IPL text file or NULL */
4967 BYTE c; /* Character work area */
4968 U16 devtype; /* Output device type */
4969 int devcyls; /* Default device size (cyls)*/
4970 int reqcyls; /* Requested device size (cyls)
4971 or 0 = use minimum size */
4972 int outheads; /* Output device trks/cyl */
4973 int outmaxdl; /* Output device maximum size
4974 record data length value */
4975 int outtrklv; /* Output device track length
4976 of virtual device */
4977 int reltrk; /* Output track number */
4978 int outcyl; /* Output cylinder number */
4979 int outhead; /* Output head number */
4980 char stmt[256]; /* Control file statement */
4981 int stmtno; /* Statement number */
4982 BYTE comp = 0xff; /* Compression algoritm */
4983 int altcylflag = 0; /* Alternate cylinders flag */
4984 int lfs = 0; /* 1 = Large file */
4985 char pathname[MAX_PATH]; /* cfname in host path format*/
4986
4987 INITIALIZE_UTILITY("dasdload");
4988
4989 /* Display the program identification message */
4990 display_version (stderr,
4991 "Hercules DASD loader program ", FALSE);
4992
4993 /* Process optional arguments */
4994 for ( ; argc > 1 && argv[1][0] == '-'; argv++, argc--)
4995 {
4996 if (strcmp("0", &argv[1][1]) == 0)
4997 comp = CCKD_COMPRESS_NONE;
4998 #ifdef CCKD_COMPRESS_ZLIB
4999 else if (strcmp("z", &argv[1][1]) == 0)
5000 comp = CCKD_COMPRESS_ZLIB;
5001 #endif
5002 #ifdef CCKD_COMPRESS_BZIP2
5003 else if (strcmp("bz2", &argv[1][1]) == 0)
5004 comp = CCKD_COMPRESS_BZIP2;
5005 #endif
5006 else if (strcmp("a", &argv[1][1]) == 0)
5007 altcylflag = 1;
5008 else if (strcmp("lfs", &argv[1][1]) == 0 && sizeof(off_t) > 4)
5009 lfs = 1;
5010 else argexit(0);
5011 }
5012
5013 /* Check the number of arguments */
5014 if (argc < 3 || argc > 4)
5015 argexit(4);
5016
5017 /* The first argument is the control file name */
5018 cfname = argv[1];
5019 if (argv[1] == NULL || strlen(argv[1]) == 0)
5020 argexit(1);
5021
5022 /* The second argument is the DASD image file name */
5023 ofname = argv[2];
5024 if (argv[2] == NULL || strlen(argv[2]) == 0)
5025 argexit(2);
5026
5027 /* The optional third argument is the message level */
5028 if (argc > 3 && argv[3] != NULL)
5029 {
5030 if (sscanf(argv[3], "%u%c", &infolvl, &c) != 1
5031 || infolvl > 5)
5032 argexit(3);
5033 }
5034
5035 /* Open the control file */
5036 hostpath(pathname, cfname, sizeof(pathname));
5037 cfp = fopen (pathname, "r");
5038 if (cfp == NULL)
5039 {
5040 XMERRF ("HHCDL001E Cannot open %s: %s\n",
5041 cfname, strerror(errno));
5042 return -1;
5043 }
5044
5045 /* Read first statement from control file */
5046 rc = read_ctrl_stmt (cfp, cfname, stmt, sizeof(stmt), &stmtno);
5047 if (rc < 0) return -1;
5048
5049 /* Error if end of file */
5050 if (rc > 0)
5051 {
5052 XMERRF ("HHCDL002E Volume serial statement missing from %s\n",
5053 cfname);
5054 return -1;
5055 }
5056
5057 /* Parse the volume serial statement */
5058 volser = strtok (stmt, " \t");
5059 sdevtp = strtok (NULL, " \t");
5060 sdevsz = strtok (NULL, " \t");
5061 iplfnm = strtok (NULL, " \t");
5062
5063 /* Validate the volume serial number */
5064 if (volser == NULL || strlen(volser) == 0 || strlen(volser) > 6)
5065 {
5066 XMERRF ("HHCDL003E Volume serial %s in %s line %d is not valid\n",
5067 volser, cfname, stmtno);
5068 return -1;
5069 }
5070 string_to_upper (volser);
5071
5072 /* Validate the device type */
5073 ckd = dasd_lookup (DASD_CKDDEV, sdevtp, 0, 0);
5074 if (ckd == NULL)
5075 {
5076 XMERRF ("HHCDL004E Device type %s in %s line %d is not recognized\n",
5077 sdevtp, cfname, stmtno);
5078 return -1;
5079 }
5080 devtype = ckd->devt;
5081
5082 /* Obtain number of heads per cylinder, maximum data length per
5083 track, and default number of cylinders per device */
5084 outheads = ckd->heads;
5085 devcyls = ckd->cyls;
5086 if (altcylflag) devcyls += ckd->altcyls;
5087 outmaxdl = ckd->r1;
5088
5089 /* Use default device size if requested size is omitted or
5090 is zero or is "*" or compression is specified */
5091 reqcyls = 0;
5092 if (sdevsz != NULL && strcmp(sdevsz, "*") != 0 && comp == 0xff)
5093 {
5094 /* Validate the requested device size in cylinders */
5095 if (sscanf(sdevsz, "%u%c", &reqcyls, &c) != 1)
5096 {
5097 XMERRF ("HHCDL005E %s in %s line %d is not a valid cylinder "
5098 "count\n",
5099 sdevsz, cfname, stmtno);
5100 return -1;
5101 }
5102 }
5103 if (reqcyls == 0)
5104 reqcyls = devcyls;
5105
5106 /* Calculate the track size of the virtual device */
5107 outtrklv = sizeof(CKDDASD_TRKHDR)
5108 + sizeof(CKDDASD_RECHDR) + R0_DATALEN
5109 + sizeof(CKDDASD_RECHDR) + outmaxdl
5110 + sizeof(eighthexFF);
5111 outtrklv = ROUND_UP(outtrklv,512);
5112
5113 /* Display progress message */
5114 XMINFF (0, "HHCDL006I Creating %4.4X volume %s: "
5115 "%u trks/cyl, %u bytes/track\n",
5116 devtype, volser, outheads, outtrklv);
5117
5118 /* Create the output file */
5119 #ifdef EXTERNALGUI
5120 if (extgui) fprintf (stderr, "REQCYLS=%d\n", reqcyls);
5121 #endif /*EXTERNALGUI*/
5122 rc = create_ckd (ofname, devtype, outheads, outmaxdl, reqcyls,
5123 volser, comp, lfs, 0, 0, 0);
5124 if (rc < 0)
5125 {
5126 XMERRF ("HHCDL007E Cannot create %s\n", ofname);
5127 return -1;
5128 }
5129
5130 /* Open the output file */
5131 cif = open_ckd_image (ofname, NULL, O_RDWR | O_BINARY, 0);
5132 if (!cif)
5133 {
5134 XMERRF ("HHCDL008E Cannot open %s\n", ofname);
5135 return -1;
5136 }
5137
5138 /* Display progress message */
5139 XMINFF (0, "HHCDL009I Loading %4.4X volume %s\n", devtype, volser);
5140
5141 /* Write track zero to the DASD image file */
5142 rc = write_track_zero (cif, ofname, volser, devtype,
5143 outheads, outtrklv, iplfnm,
5144 &reltrk, &outcyl, &outhead);
5145 if (rc < 0)
5146 return -1;
5147
5148 /* Process the control file to create the datasets */
5149 rc = process_control_file (cfp, cfname, ofname, cif, volser,
5150 devtype, reqcyls, outheads, outtrklv,
5151 outcyl, outhead);
5152
5153 /* Close files and release buffers */
5154 fclose (cfp);
5155 close_ckd_image (cif);
5156
5157 return rc;
5158
5159 } /* end function main */
5160