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(&copyr1->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 (&notelist, 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, &notelist, 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", &copyfiln,
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", &copyfiln,
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