1 /* DASDUTIL.C   (c) Copyright Roger Bowler, 1999-2010                */
2 /*              Hercules DASD Utilities: Common subroutines          */
3 
4 /*-------------------------------------------------------------------*/
5 /* This module contains common subroutines used by DASD utilities    */
6 /*-------------------------------------------------------------------*/
7 
8 #include "hstdinc.h"
9 
10 #define _DASDUTIL_C_
11 #define _HDASD_DLL_
12 
13 #include "hercules.h"
14 #include "dasdblks.h"
15 #include "devtype.h"
16 #include "opcode.h"
17 
18 /*-------------------------------------------------------------------*/
19 /* External references         (defined in ckddasd.c)                */
20 /*-------------------------------------------------------------------*/
21 extern DEVHND ckddasd_device_hndinfo;
22 
23 /*-------------------------------------------------------------------*/
24 /* Internal macro definitions                                        */
25 /*-------------------------------------------------------------------*/
26 
27 /*-------------------------------------------------------------------*/
28 /* Static data areas                                                 */
29 /*-------------------------------------------------------------------*/
30 static int verbose = 0;                /* Be chatty about reads etc. */
31 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
32 static BYTE iplpsw[8]    = {0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x0F};
33 static BYTE iplccw1[8]   = {0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x01};
34 static BYTE iplccw2[8]   = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
35 static int  nextnum = 0;
36 
37 #if 0
38 SYSBLK sysblk; /* Currently required for shared.c */
39 #endif
40 
41 /*-------------------------------------------------------------------*/
42 /* Subroutine to convert a null-terminated string to upper case      */
43 /*-------------------------------------------------------------------*/
string_to_upper(char * source)44 DLL_EXPORT void string_to_upper (char *source)
45 {
46 int     i;                              /* Array subscript           */
47 
48     for (i = 0; source[i] != '\0'; i++)
49         source[i] = toupper(source[i]);
50 
51 } /* end function string_to_upper */
52 
53 /*-------------------------------------------------------------------*/
54 /* Subroutine to convert a null-terminated string to lower case      */
55 /*-------------------------------------------------------------------*/
string_to_lower(char * source)56 DLL_EXPORT void string_to_lower (char *source)
57 {
58 int     i;                              /* Array subscript           */
59 
60     for (i = 0; source[i] != '\0'; i++)
61         source[i] = tolower(source[i]);
62 
63 } /* end function string_to_lower */
64 
65 /*-------------------------------------------------------------------*/
66 /* Subroutine to convert a string to EBCDIC and pad with blanks      */
67 /*-------------------------------------------------------------------*/
convert_to_ebcdic(BYTE * dest,int len,char * source)68 DLL_EXPORT void convert_to_ebcdic (BYTE *dest, int len, char *source)
69 {
70 int     i;                              /* Array subscript           */
71 
72     set_codepage(NULL);
73 
74     for (i = 0; i < len && source[i] != '\0'; i++)
75         dest[i] = host_to_guest(source[i]);
76 
77     while (i < len)
78         dest[i++] = 0x40;
79 
80 } /* end function convert_to_ebcdic */
81 
82 /*-------------------------------------------------------------------*/
83 /* Subroutine to convert an EBCDIC string to an ASCIIZ string.       */
84 /* Removes trailing blanks and adds a terminating null.              */
85 /* Returns the length of the ASCII string excluding terminating null */
86 /*-------------------------------------------------------------------*/
make_asciiz(char * dest,int destlen,BYTE * src,int srclen)87 DLL_EXPORT int make_asciiz (char *dest, int destlen, BYTE *src, int srclen)
88 {
89 int             len;                    /* Result length             */
90 
91     set_codepage(NULL);
92 
93 
94     for (len=0; len < srclen && len < destlen-1; len++)
95         dest[len] = guest_to_host(src[len]);
96     while (len > 0 && dest[len-1] == SPACE) len--;
97     dest[len] = '\0';
98 
99     return len;
100 
101 } /* end function make_asciiz */
102 
103 /*-------------------------------------------------------------------*/
104 /* Subroutine to print a data block in hex and character format.     */
105 /*-------------------------------------------------------------------*/
data_dump(void * addr,int len)106 DLL_EXPORT void data_dump ( void *addr, int len )
107 {
108 unsigned int    maxlen = 2048;
109 unsigned int    i, xi, offset, startoff = 0;
110 BYTE            c;
111 BYTE           *pchar;
112 char            print_chars[17];
113 char            hex_chars[64];
114 char            prev_hex[64] = "";
115 int             firstsame = 0;
116 int             lastsame = 0;
117 
118     set_codepage(NULL);
119 
120     pchar = (BYTE *)addr;
121 
122     for (offset=0; ; )
123     {
124         if (offset >= maxlen && offset <= len - maxlen)
125         {
126             offset += 16;
127             pchar += 16;
128             prev_hex[0] = '\0';
129             continue;
130         }
131         if ( offset > 0 )
132         {
133             if ( strcmp ( hex_chars, prev_hex ) == 0 )
134             {
135                 if ( firstsame == 0 ) firstsame = startoff;
136                 lastsame = startoff;
137             }
138             else
139             {
140                 if ( firstsame != 0 )
141                 {
142                     if ( lastsame == firstsame )
143                         printf ("Line %4.4X same as above\n",
144                                 firstsame );
145                     else
146                         printf ("Lines %4.4X to %4.4X same as above\n",
147                                 firstsame, lastsame );
148                     firstsame = lastsame = 0;
149                 }
150                 printf ("+%4.4X %s %s\n",
151                         startoff, hex_chars, print_chars);
152                 strcpy ( prev_hex, hex_chars );
153             }
154         }
155 
156         if ( offset >= (U32)len ) break;
157 
158         memset ( print_chars, 0, sizeof(print_chars) );
159         memset ( hex_chars, SPACE, sizeof(hex_chars) );
160         startoff = offset;
161         for (xi=0, i=0; i < 16; i++)
162         {
163             c = *pchar++;
164             if (offset < (U32)len) {
165                 sprintf(hex_chars+xi, "%2.2X", c);
166                 print_chars[i] = '.';
167                 if (isprint(c)) print_chars[i] = c;
168                 c = guest_to_host(c);
169                 if (isprint(c)) print_chars[i] = c;
170             }
171             offset++;
172             xi += 2;
173             hex_chars[xi] = SPACE;
174             if ((offset & 3) == 0) xi++;
175         } /* end for(i) */
176         hex_chars[xi] = '\0';
177 
178     } /* end for(offset) */
179 
180 } /* end function data_dump */
181 
182 /*-------------------------------------------------------------------*/
183 /* Subroutine to read a track from the CKD DASD image                */
184 /* Input:                                                            */
185 /*      cif     -> CKD image file descriptor structure               */
186 /*      cyl     Cylinder number                                      */
187 /*      head    Head number                                          */
188 /* Output:                                                           */
189 /*      The track is read into trkbuf, and curcyl and curhead        */
190 /*      are set to the cylinder and head number.                     */
191 /*                                                                   */
192 /* Return value is 0 if successful, -1 if error                      */
193 /*-------------------------------------------------------------------*/
read_track(CIFBLK * cif,int cyl,int head)194 DLL_EXPORT int read_track (CIFBLK *cif, int cyl, int head)
195 {
196 int             rc;                     /* Return code               */
197 int             trk;                    /* Track number              */
198 DEVBLK         *dev;                    /* -> CKD device block       */
199 BYTE            unitstat;               /* Unit status               */
200 
201     /* Exit if required track is already in buffer */
202     if (cif->curcyl == cyl && cif->curhead == head)
203         return 0;
204 
205     dev = &cif->devblk;
206 
207     if (cif->trkmodif)
208     {
209         cif->trkmodif = 0;
210         if (verbose) /* Issue progress message */
211            fprintf (stdout, _("HHCDU001I Updating cyl %d head %d\n"),
212                     cif->curcyl, cif->curhead);
213         trk = (cif->curcyl * cif->heads) + cif->curhead;
214         rc = (dev->hnd->write)(dev, trk, 0, NULL, cif->trksz, &unitstat);
215         if (rc < 0)
216         {
217             fprintf (stderr, _("HHCDU002E %s write track error: stat=%2.2X\n"),
218                     cif->fname, unitstat);
219             return -1;
220         }
221     }
222 
223     if (verbose) /* Issue progress message */
224        fprintf (stdout, _("HHCDU003I Reading cyl %d head %d\n"), cyl, head);
225 
226     trk = (cyl * cif->heads) + head;
227     rc = (dev->hnd->read)(dev, trk, &unitstat);
228     if (rc < 0)
229     {
230         fprintf (stderr, _("HHCDU004E %s read track error: stat=%2.2X\n"),
231                 cif->fname, unitstat);
232         return -1;
233     }
234 
235     /* Set current buf, cylinder and head */
236     cif->trkbuf = dev->buf;
237     cif->curcyl = cyl;
238     cif->curhead = head;
239 
240     return 0;
241 } /* end function read_track */
242 
243 /*-------------------------------------------------------------------*/
244 /* Subroutine to read a block from the CKD DASD image                */
245 /* Input:                                                            */
246 /*      cif     -> CKD image file descriptor structure               */
247 /*      cyl     Cylinder number of requested block                   */
248 /*      head    Head number of requested block                       */
249 /*      rec     Record number of requested block                     */
250 /* Output:                                                           */
251 /*      keyptr  Pointer to record key                                */
252 /*      keylen  Actual key length                                    */
253 /*      dataptr Pointer to record data                               */
254 /*      datalen Actual data length                                   */
255 /*                                                                   */
256 /* Return value is 0 if successful, +1 if end of track, -1 if error  */
257 /*-------------------------------------------------------------------*/
read_block(CIFBLK * cif,int cyl,int head,int rec,BYTE ** keyptr,int * keylen,BYTE ** dataptr,int * datalen)258 DLL_EXPORT int read_block (CIFBLK *cif, int cyl, int head, int rec, BYTE **keyptr,
259                 int *keylen, BYTE **dataptr, int *datalen)
260 {
261 int             rc;                     /* Return code               */
262 BYTE           *ptr;                    /* -> byte in track buffer   */
263 CKDDASD_RECHDR *rechdr;                 /* -> Record header          */
264 int             kl;                     /* Key length                */
265 int             dl;                     /* Data length               */
266 
267     /* Read the required track into the track buffer if necessary */
268     rc = read_track (cif, cyl, head);
269     if (rc < 0) return -1;
270 
271     /* Search for the requested record in the track buffer */
272     ptr = cif->trkbuf;
273     ptr += CKDDASD_TRKHDR_SIZE;
274 
275     while (1)
276     {
277         /* Exit with record not found if end of track */
278         if (memcmp(ptr, eighthexFF, 8) == 0)
279             return +1;
280 
281         /* Extract key length and data length from count field */
282         rechdr = (CKDDASD_RECHDR*)ptr;
283         kl = rechdr->klen;
284         dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1];
285 
286         /* Exit if requested record number found */
287         if (rechdr->rec == rec)
288             break;
289 
290         /* Issue progress message */
291 //      fprintf (stdout,
292 //              "Skipping CCHHR=%2.2X%2.2X%2.2X%2.2X"
293 //              "%2.2X KL=%2.2X DL=%2.2X%2.2X\n",
294 //              rechdr->cyl[0], rechdr->cyl[1],
295 //              rechdr->head[0], rechdr->head[1],
296 //              rechdr->rec, rechdr->klen,
297 //              rechdr->dlen[0], rechdr->dlen[1]);
298 
299         /* Point past count key and data to next block */
300         ptr += CKDDASD_RECHDR_SIZE + kl + dl;
301     }
302 
303     /* Return key and data pointers and lengths */
304     if (keyptr != NULL) *keyptr = ptr + CKDDASD_RECHDR_SIZE;
305     if (keylen != NULL) *keylen = kl;
306     if (dataptr != NULL) *dataptr = ptr + CKDDASD_RECHDR_SIZE + kl;
307     if (datalen != NULL) *datalen = dl;
308     return 0;
309 
310 } /* end function read_block */
311 
312 /*-------------------------------------------------------------------*/
313 /* Subroutine to search a dataset for a specified key                */
314 /* Input:                                                            */
315 /*      cif     -> CKD image file descriptor structure               */
316 /*      key     Key value                                            */
317 /*      keylen  Key length                                           */
318 /*      noext   Number of extents                                    */
319 /*      extent  Dataset extent array                                 */
320 /* Output:                                                           */
321 /*      cyl     Cylinder number of requested block                   */
322 /*      head    Head number of requested block                       */
323 /*      rec     Record number of requested block                     */
324 /*                                                                   */
325 /* Return value is 0 if successful, +1 if key not found, -1 if error */
326 /*-------------------------------------------------------------------*/
search_key_equal(CIFBLK * cif,BYTE * key,int keylen,int noext,DSXTENT extent[],int * cyl,int * head,int * rec)327 DLL_EXPORT int search_key_equal (CIFBLK *cif, BYTE *key, int keylen, int noext,
328                     DSXTENT extent[], int *cyl, int *head, int *rec)
329 {
330 int             rc;                     /* Return code               */
331 int             ccyl;                   /* Cylinder number           */
332 int             chead;                  /* Head number               */
333 int             cext;                   /* Extent sequence number    */
334 int             ecyl;                   /* Extent end cylinder       */
335 int             ehead;                  /* Extent end head           */
336 BYTE           *ptr;                    /* -> byte in track buffer   */
337 CKDDASD_RECHDR *rechdr;                 /* -> Record header          */
338 int             kl;                     /* Key length                */
339 int             dl;                     /* Data length               */
340 
341     /* Start at first track of first extent */
342     cext = 0;
343     ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1];
344     chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1];
345     ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1];
346     ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1];
347 
348     if (verbose)
349     {
350        fprintf (stdout,
351                _("HHCDU005I Searching extent %d begin (%d,%d) end (%d,%d)\n"),
352                cext, ccyl, chead, ecyl, ehead);
353     }
354 
355     while (1)
356     {
357         /* Read the required track into the track buffer */
358         rc = read_track (cif, ccyl, chead);
359         if (rc < 0) return -1;
360 
361         /* Search for the requested record in the track buffer */
362         ptr = cif->trkbuf;
363         ptr += CKDDASD_TRKHDR_SIZE;
364 
365         while (1)
366         {
367             /* Exit loop at end of track */
368             if (memcmp(ptr, eighthexFF, 8) == 0)
369                 break;
370 
371             /* Extract key length and data length from count field */
372             rechdr = (CKDDASD_RECHDR*)ptr;
373             kl = rechdr->klen;
374             dl = (rechdr->dlen[0] << 8) | rechdr->dlen[1];
375 
376             /* Return if requested record key found */
377             if (kl == keylen
378                 && memcmp(ptr + CKDDASD_RECHDR_SIZE, key, 44) == 0)
379             {
380                 *cyl = ccyl;
381                 *head = chead;
382                 *rec = rechdr->rec;
383                 return 0;
384             }
385 
386             /* Issue progress message */
387 //          fprintf (stdout,
388 //                  "Skipping CCHHR=%2.2X%2.2X%2.2X%2.2X"
389 //                  "%2.2X KL=%2.2X DL=%2.2X%2.2X\n",
390 //                  rechdr->cyl[0], rechdr->cyl[1],
391 //                  rechdr->head[0], rechdr->head[1],
392 //                  rechdr->rec, rechdr->klen,
393 //                  rechdr->dlen[0], rechdr->dlen[1]);
394 
395             /* Point past count key and data to next block */
396             ptr += CKDDASD_RECHDR_SIZE + kl + dl;
397 
398         } /* end while */
399 
400         /* Point to the next track */
401         chead++;
402         if (chead >= cif->heads)
403         {
404             ccyl++;
405             chead = 0;
406         }
407 
408         /* Loop if next track is within current extent */
409         if (ccyl < ecyl || (ccyl == ecyl && chead <= ehead))
410             continue;
411 
412         /* Move to next extent */
413         cext++;
414         if (cext >= noext) break;
415         ccyl = (extent[cext].xtbcyl[0] << 8) | extent[cext].xtbcyl[1];
416         chead = (extent[cext].xtbtrk[0] << 8) | extent[cext].xtbtrk[1];
417         ecyl = (extent[cext].xtecyl[0] << 8) | extent[cext].xtecyl[1];
418         ehead = (extent[cext].xtetrk[0] << 8) | extent[cext].xtetrk[1];
419 
420        if (verbose)
421        {
422            fprintf (stdout,
423                    _("HHCDU006I Searching extent %d begin (%d,%d) end (%d,%d)\n"),
424                    cext, ccyl, chead, ecyl, ehead);
425        }
426 
427     } /* end while */
428 
429     /* Return record not found at end of extents */
430     return +1;
431 
432 } /* end function search_key_equal */
433 
434 /*-------------------------------------------------------------------*/
435 /* Subroutine to convert relative track to cylinder and head         */
436 /* Input:                                                            */
437 /*      tt      Relative track number                                */
438 /*      noext   Number of extents in dataset                         */
439 /*      extent  Dataset extent array                                 */
440 /*      heads   Number of tracks per cylinder                        */
441 /* Output:                                                           */
442 /*      cyl     Cylinder number                                      */
443 /*      head    Head number                                          */
444 /*                                                                   */
445 /* Return value is 0 if successful, or -1 if error                   */
446 /*-------------------------------------------------------------------*/
convert_tt(int tt,int noext,DSXTENT extent[],int heads,int * cyl,int * head)447 DLL_EXPORT int convert_tt (int tt, int noext, DSXTENT extent[], int heads,
448                 int *cyl, int *head)
449 {
450 int             i;                      /* Extent sequence number    */
451 int             trk;                    /* Relative track number     */
452 int             bcyl;                   /* Extent begin cylinder     */
453 int             btrk;                   /* Extent begin head         */
454 int             ecyl;                   /* Extent end cylinder       */
455 int             etrk;                   /* Extent end head           */
456 int             start;                  /* Extent begin track        */
457 int             end;                    /* Extent end track          */
458 int             extsize;                /* Extent size in tracks     */
459 
460     for (i = 0, trk = tt; i < noext; i++)
461     {
462         bcyl = (extent[i].xtbcyl[0] << 8) | extent[i].xtbcyl[1];
463         btrk = (extent[i].xtbtrk[0] << 8) | extent[i].xtbtrk[1];
464         ecyl = (extent[i].xtecyl[0] << 8) | extent[i].xtecyl[1];
465         etrk = (extent[i].xtetrk[0] << 8) | extent[i].xtetrk[1];
466 
467         start = (bcyl * heads) + btrk;
468         end = (ecyl * heads) + etrk;
469         extsize = end - start + 1;
470 
471         if (trk < extsize)
472         {
473             trk += start;
474             *cyl = trk / heads;
475             *head = trk % heads;
476             return 0;
477         }
478 
479         trk -= extsize;
480 
481     } /* end for(i) */
482 
483     fprintf (stderr,
484             _("HHCDU007E Track %d not found in extent table\n"),
485             tt);
486     return -1;
487 
488 } /* end function convert_tt */
489 
490 /*-------------------------------------------------------------------*/
491 /* Subroutine to open a CKD image file                               */
492 /* Input:                                                            */
493 /*      fname    CKD image file name                                 */
494 /*      sfname   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx           */
495 /*      omode    Open mode: O_RDONLY or O_RDWR                       */
496 /*      dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx           */
497 /*                                                                   */
498 /* The CKD image file is opened, a track buffer is obtained,         */
499 /* and a CKD image file descriptor structure is built.               */
500 /* Return value is a pointer to the CKD image file descriptor        */
501 /* structure if successful, or NULL if unsuccessful.                 */
502 /*-------------------------------------------------------------------*/
open_ckd_image(char * fname,char * sfname,int omode,int dasdcopy)503 DLL_EXPORT CIFBLK* open_ckd_image (char *fname, char *sfname, int omode,
504                        int dasdcopy)
505 {
506 int             fd;                     /* File descriptor           */
507 int             rc;                     /* Return code               */
508 int             len;                    /* Record length             */
509 CKDDASD_DEVHDR  devhdr;                 /* CKD device header         */
510 CIFBLK         *cif;                    /* CKD image file descriptor */
511 DEVBLK         *dev;                    /* CKD device block          */
512 CKDDEV         *ckd;                    /* CKD DASD table entry      */
513 char           *rmtdev;                 /* Possible remote device    */
514 char           *argv[2];                /* Arguments to              */
515 int             argc=0;                 /*                           */
516 char            sfxname[FILENAME_MAX*2];/* Suffixed file name        */
517 char            typname[64];
518 char            pathname[MAX_PATH];     /* file path in host format  */
519 
520     /* Obtain storage for the file descriptor structure */
521     cif = (CIFBLK*) calloc (sizeof(CIFBLK), 1);
522     if (cif == NULL)
523     {
524         fprintf (stderr,
525                 _("HHCDU008E Cannot obtain storage for device descriptor "
526                 "buffer: %s\n"),
527                 strerror(errno));
528         return NULL;
529     }
530 
531     /* Initialize the devblk */
532     dev = &cif->devblk;
533     if ((omode & O_RDWR) == 0) dev->ckdrdonly = 1;
534     dev->fd = -1;
535     dev->batch = 1;
536     dev->dasdcopy = dasdcopy;
537 
538     /* If the filename has a `:' then it may be a remote device */
539     rmtdev = strchr(fname, ':');
540 
541     /* Read the device header so we can determine the device type */
542     strcpy (sfxname, fname);
543     hostpath(pathname, sfxname, sizeof(pathname));
544     fd = hopen(pathname, omode);
545     if (fd < 0)
546     {
547         /* If no shadow file name was specified, then try opening the
548            file with the file sequence number in the name */
549         if (sfname == NULL)
550         {
551             int i;
552             char *s,*suffix;
553 
554             /* Look for last slash marking end of directory name */
555             s = strrchr (fname, '/');
556             if (s == NULL) s = fname;
557 
558             /* Insert suffix before first dot in file name, or
559                append suffix to file name if there is no dot.
560                If the filename already has a place for the suffix
561                then use that. */
562             s = strchr (s, '.');
563             if (s != NULL)
564             {
565                 i = s - fname;
566                 if (i > 2 && fname[i-2] == '_')
567                     suffix = sfxname + i - 1;
568                 else
569                 {
570                     strcpy (sfxname + i, "_1");
571                     strcat (sfxname, fname + i);
572                     suffix = sfxname + i + 1;
573                 }
574             }
575             else
576             {
577                 if (strlen(sfxname) < 2 || sfxname[strlen(sfxname)-2] != '_')
578                     strcat (sfxname, "_1");
579                 suffix = sfxname + strlen(sfxname) - 1;
580             }
581             *suffix = '1';
582             hostpath(pathname, sfxname, sizeof(pathname));
583             fd = hopen(pathname, omode);
584         }
585         if (fd < 0 && rmtdev == NULL)
586         {
587             fprintf (stderr, _("HHCDU009E Cannot open %s: %s\n"),
588                      fname, strerror(errno));
589             free (cif);
590             return NULL;
591         }
592         else if (fd < 0) strcpy (sfxname, fname);
593     }
594 
595     /* If not a possible remote devic, check the dasd header
596        and set the device type */
597     if (fd >= 0)
598     {
599         len = read (fd, &devhdr, CKDDASD_DEVHDR_SIZE);
600         if (len < 0)
601         {
602             fprintf (stderr, _("HHCDU010E %s read error: %s\n"),
603                      fname, strerror(errno));
604             close (fd);
605             free (cif);
606             return NULL;
607         }
608         close (fd);
609         if (len < (int)CKDDASD_DEVHDR_SIZE
610          || (memcmp(devhdr.devid, "CKD_P370", 8)
611           && memcmp(devhdr.devid, "CKD_C370", 8)))
612         {
613             fprintf (stderr, _("HHCDU011E %s CKD header invalid\n"), fname);
614             free (cif);
615             return NULL;
616         }
617 
618         /* Set the device type */
619         ckd = dasd_lookup (DASD_CKDDEV, NULL, devhdr.devtype, 0);
620         if (ckd == NULL)
621         {
622             fprintf(stderr, _("HHCDU012E DASD table entry not found for "
623                         "devtype 0x%2.2X\n"),
624                     devhdr.devtype);
625             free (cif);
626             return NULL;
627         }
628         dev->devtype = ckd->devt;
629         snprintf(typname,64,"%4.4X",dev->devtype);
630         dev->typname=typname;   /* Makes HDL Happy */
631     }
632 
633     /* Set the device handlers */
634     dev->hnd = &ckddasd_device_hndinfo;
635 
636     /* Set the device number */
637     dev->devnum = ++nextnum;
638 
639     /* Build arguments for ckddasd_init_handler */
640     argv[0] = sfxname;
641     argc++;
642     if (sfname != NULL)
643     {
644         argv[1] = sfname;
645         argc++;
646     }
647 
648     /* Call the device handler initialization function */
649     rc = (dev->hnd->init)(dev, argc, argv);
650     if (rc < 0)
651     {
652         fprintf (stderr, _("HHCDU013E CKD initialization failed for %s\n"),
653                  fname);
654         free (cif);
655         return NULL;
656     }
657 
658     /* Call the device start exit */
659     if (dev->hnd->start) (dev->hnd->start) (dev);
660 
661     /* Set CIF fields */
662     cif->fname = fname;
663     cif->fd = dev->fd;
664 
665     /* Extract the number of heads and the track size */
666     cif->heads = dev->ckdheads;
667     cif->trksz = ((U32)(devhdr.trksize[3]) << 24)
668                 | ((U32)(devhdr.trksize[2]) << 16)
669                 | ((U32)(devhdr.trksize[1]) << 8)
670                 | (U32)(devhdr.trksize[0]);
671     if (verbose)
672     {
673        fprintf (stderr,
674                _("HHCDU014I %s heads=%d trklen=%d\n"),
675                cif->fname, cif->heads, cif->trksz);
676     }
677 
678     /* Indicate that the track buffer is empty */
679     cif->curcyl = -1;
680     cif->curhead = -1;
681     cif->trkmodif = 0;
682 
683     return cif;
684 } /* end function open_ckd_image */
685 
686 /*-------------------------------------------------------------------*/
687 /* Subroutine to close a CKD image file                              */
688 /* Input:                                                            */
689 /*      cif     -> CKD image file descriptor structure               */
690 /*                                                                   */
691 /* The track buffer is flushed and released, the CKD image file      */
692 /* is closed, and the file descriptor structure is released.         */
693 /* Return value is 0 if successful, -1 if error                      */
694 /*-------------------------------------------------------------------*/
close_ckd_image(CIFBLK * cif)695 DLL_EXPORT int close_ckd_image (CIFBLK *cif)
696 {
697 int             rc;                     /* Return code               */
698 int             trk;                    /* Track number              */
699 DEVBLK         *dev;                    /* -> CKD device block       */
700 BYTE            unitstat;               /* Unit status               */
701 
702     dev = &cif->devblk;
703 
704     /* Write the last track if modified */
705     if (cif->trkmodif)
706     {
707         if (verbose) /* Issue progress message */
708            fprintf (stdout, _("HHCDU015I Updating cyl %d head %d\n"),
709                     cif->curcyl, cif->curhead);
710         trk = (cif->curcyl * cif->heads) + cif->curhead;
711         rc = (dev->hnd->write)(dev, trk, 0, NULL, cif->trksz, &unitstat);
712         if (rc < 0)
713         {
714             fprintf (stderr, _("HHCDU016E %s write track error: stat=%2.2X\n"),
715                     cif->fname, unitstat);
716         }
717     }
718 
719     /* Call the END exit */
720     if (dev->hnd->end) (dev->hnd->end) (dev);
721 
722     /* Close the CKD image file */
723     (dev->hnd->close)(dev);
724 
725     /* Release the file descriptor structure */
726     free (cif);
727 
728     return 0;
729 } /* end function close_ckd_image */
730 
731 /*-------------------------------------------------------------------*/
732 /* Subroutine to open a FBA image file                               */
733 /* Input:                                                            */
734 /*      fname    FBA image file name                                 */
735 /*      sfname   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx           */
736 /*      omode    Open mode: O_RDONLY or O_RDWR                       */
737 /*      dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx           */
738 /*                                                                   */
739 /* The FBA image file is opened, a track buffer is obtained,         */
740 /* and a FBA image file descriptor structure is built.               */
741 /* Return value is a pointer to the FBA image file descriptor        */
742 /* structure if successful, or NULL if unsuccessful.                 */
743 /*-------------------------------------------------------------------*/
open_fba_image(char * fname,char * sfname,int omode,int dasdcopy)744 DLL_EXPORT CIFBLK* open_fba_image (char *fname, char *sfname, int omode,
745                         int dasdcopy)
746 {
747 int             rc;                     /* Return code               */
748 CIFBLK         *cif;                    /* FBA image file descriptor */
749 DEVBLK         *dev;                    /* FBA device block          */
750 FBADEV         *fba;                    /* FBA DASD table entry      */
751 char           *argv[2];                /* Arguments to              */
752 int             argc=0;                 /*  device open              */
753 
754     /* Obtain storage for the file descriptor structure */
755     cif = (CIFBLK*) calloc (sizeof(CIFBLK), 1);
756     if (cif == NULL)
757     {
758         fprintf (stderr,
759                 _("HHCDU017E Cannot obtain storage for device descriptor "
760                 "buffer: %s\n"),
761                 strerror(errno));
762         return NULL;
763     }
764 
765     /* Initialize the devblk */
766     dev = &cif->devblk;
767     if ((omode & O_RDWR) == 0) dev->ckdrdonly = 1;
768     dev->batch = 1;
769     dev->dasdcopy = dasdcopy;
770 
771     /* Set the device type */
772     fba = dasd_lookup (DASD_FBADEV, NULL, DEFAULT_FBA_TYPE, 0);
773     if (fba == NULL)
774     {
775         fprintf(stderr, _("HHCDU018E DASD table entry not found for "
776                         "devtype 0x%2.2X\n"),
777                 DEFAULT_FBA_TYPE);
778         free (cif);
779         return NULL;
780     }
781     dev->devtype = fba->devt;
782 
783     /* Set the device handlers */
784     dev->hnd = &fbadasd_device_hndinfo;
785 
786     /* Set the device number */
787     dev->devnum = ++nextnum;
788 
789     /* Build arguments for fbadasd_init_handler */
790     argv[0] = fname;
791     argc++;
792     if (sfname != NULL)
793     {
794         argv[1] = sfname;
795         argc++;
796     }
797 
798     /* Call the device handler initialization function */
799     rc = (dev->hnd->init)(dev, argc, argv);
800     if (rc < 0)
801     {
802         fprintf (stderr, _("HHCDU019E FBA initialization failed for %s\n"),
803                  fname);
804         free (cif);
805         return NULL;
806     }
807 
808     /* Set CIF fields */
809     cif->fname = fname;
810     cif->fd = dev->fd;
811 
812     /* Extract the number of sectors and the sector size */
813     cif->heads = dev->fbanumblk;
814     cif->trksz = dev->fbablksiz;
815     if (verbose)
816     {
817        fprintf (stderr,
818                _("HHCDU020I %s sectors=%d size=%d\n"),
819                cif->fname, cif->heads, cif->trksz);
820     }
821 
822     /* Indicate that the track buffer is empty */
823     cif->curcyl = -1;
824     cif->curhead = -1;
825     cif->trkmodif = 0;
826 
827     return cif;
828 } /* end function open_fba_image */
829 
830 /*-------------------------------------------------------------------*/
831 /* Subroutine to build extent array for specified dataset            */
832 /* Input:                                                            */
833 /*      cif     -> CKD image file descriptor structure               */
834 /*      dsnama  -> Dataset name (ASCIIZ)                             */
835 /* Output:                                                           */
836 /*      extent  Extent array (up to 16 entries)                      */
837 /*      noext   Number of extents                                    */
838 /*                                                                   */
839 /* Return value is 0 if successful, or -1 if error                   */
840 /*-------------------------------------------------------------------*/
build_extent_array(CIFBLK * cif,char * dsnama,DSXTENT extent[],int * noext)841 DLL_EXPORT int build_extent_array (CIFBLK *cif, char *dsnama, DSXTENT extent[],
842                         int *noext)
843 {
844 int             rc;                     /* Return code               */
845 int             len;                    /* Record length             */
846 int             cyl;                    /* Cylinder number           */
847 int             head;                   /* Head number               */
848 int             rec;                    /* Record number             */
849 BYTE           *vol1data;               /* -> Volume label           */
850 FORMAT1_DSCB   *f1dscb;                 /* -> Format 1 DSCB          */
851 FORMAT3_DSCB   *f3dscb;                 /* -> Format 3 DSCB          */
852 FORMAT4_DSCB   *f4dscb;                 /* -> Format 4 DSCB          */
853 BYTE            dsname[44];             /* Dataset name (EBCDIC)     */
854 char            volser[7];              /* Volume serial (ASCIIZ)    */
855 
856     /* Convert the dataset name to EBCDIC */
857     convert_to_ebcdic (dsname, sizeof(dsname), dsnama);
858 
859     /* Read the volume label */
860     rc = read_block (cif, 0, 0, 3, NULL, NULL, &vol1data, &len);
861     if (rc < 0) return -1;
862     if (rc > 0)
863     {
864         fprintf (stderr, _("HHCDU021E VOL1 record not found\n"));
865         return -1;
866     }
867 
868     /* Extract the volume serial and the CCHHR of the format 4 DSCB */
869     make_asciiz (volser, sizeof(volser), vol1data+4, 6);
870     cyl = (vol1data[11] << 8) | vol1data[12];
871     head = (vol1data[13] << 8) | vol1data[14];
872     rec = vol1data[15];
873 
874     if (verbose)
875     {
876        fprintf (stdout,
877                _("HHCDU022I VOLSER=%s VTOC=%4.4X%4.4X%2.2X\n"),
878                 volser, cyl, head, rec);
879     }
880 
881     /* Read the format 4 DSCB */
882     rc = read_block (cif, cyl, head, rec,
883                     (void *)&f4dscb, &len, NULL, NULL);
884     if (rc < 0) return -1;
885     if (rc > 0)
886     {
887         fprintf (stderr, _("HHCDU023E F4DSCB record not found\n"));
888         return -1;
889     }
890 
891     if (verbose)
892     {
893        fprintf (stdout,
894                _("HHCDU023I VTOC start %2.2X%2.2X%2.2X%2.2X "
895                "end %2.2X%2.2X%2.2X%2.2X\n"),
896                f4dscb->ds4vtoce.xtbcyl[0], f4dscb->ds4vtoce.xtbcyl[1],
897                f4dscb->ds4vtoce.xtbtrk[0], f4dscb->ds4vtoce.xtbtrk[1],
898                f4dscb->ds4vtoce.xtecyl[0], f4dscb->ds4vtoce.xtecyl[1],
899                f4dscb->ds4vtoce.xtetrk[0], f4dscb->ds4vtoce.xtetrk[1]);
900     }
901 
902     /* Search for the requested dataset in the VTOC */
903     rc = search_key_equal (cif, dsname, sizeof(dsname),
904                             1, &(f4dscb->ds4vtoce),
905                             &cyl, &head, &rec);
906     if (rc < 0) return -1;
907     if (rc > 0)
908     {
909         fprintf (stderr,
910                 _("HHCDU024E Dataset %s not found in VTOC\n"),
911                 dsnama);
912         return -1;
913     }
914 
915     if (verbose)
916     {
917        fprintf (stdout,
918                _("HHCDU025I DSNAME=%s F1DSCB CCHHR=%4.4X%4.4X%2.2X\n"),
919                dsnama, cyl, head, rec);
920     }
921 
922     /* Read the format 1 DSCB */
923     rc = read_block (cif, cyl, head, rec,
924                     (void *)&f1dscb, &len, NULL, NULL);
925     if (rc < 0) return -1;
926     if (rc > 0)
927     {
928         fprintf (stderr, _("HHCDU026E F1DSCB record not found\n"));
929         return -1;
930     }
931 
932     /* Extract number of extents and first 3 extent descriptors */
933     *noext = f1dscb->ds1noepv;
934     extent[0] = f1dscb->ds1ext1;
935     extent[1] = f1dscb->ds1ext2;
936     extent[2] = f1dscb->ds1ext3;
937 
938     /* Obtain additional extent descriptors */
939     if (f1dscb->ds1noepv > 3)
940     {
941         /* Read the format 3 DSCB */
942         cyl = (f1dscb->ds1ptrds[0] << 8) | f1dscb->ds1ptrds[1];
943         head = (f1dscb->ds1ptrds[2] << 8) | f1dscb->ds1ptrds[3];
944         rec = f1dscb->ds1ptrds[4];
945         rc = read_block (cif, cyl, head, rec,
946                         (void *)&f3dscb, &len, NULL, NULL);
947         if (rc < 0) return -1;
948         if (rc > 0)
949         {
950             fprintf (stderr, _("HHCDU027E F3DSCB record not found\n"));
951             return -1;
952         }
953 
954         /* Extract the next 13 extent descriptors */
955         extent[3] = f3dscb->ds3extnt[0];
956         extent[4] = f3dscb->ds3extnt[1];
957         extent[5] = f3dscb->ds3extnt[2];
958         extent[6] = f3dscb->ds3extnt[3];
959         extent[7] = f3dscb->ds3adext[0];
960         extent[8] = f3dscb->ds3adext[1];
961         extent[9] = f3dscb->ds3adext[2];
962         extent[10] = f3dscb->ds3adext[3];
963         extent[11] = f3dscb->ds3adext[4];
964         extent[12] = f3dscb->ds3adext[5];
965         extent[13] = f3dscb->ds3adext[6];
966         extent[14] = f3dscb->ds3adext[7];
967         extent[15] = f3dscb->ds3adext[8];
968     }
969 
970     return 0;
971 } /* end function build_extent_array */
972 
973 /*-------------------------------------------------------------------*/
974 /* Subroutine to calculate physical device track capacities          */
975 /* Input:                                                            */
976 /*      cif     -> CKD image file descriptor structure               */
977 /*      used    Number of bytes used so far on track,                */
978 /*              excluding home address and record 0                  */
979 /*      keylen  Key length of proposed new record                    */
980 /*      datalen Data length of proposed new record                   */
981 /* Output:                                                           */
982 /*      newused Number of bytes used including proposed new record   */
983 /*      trkbaln Number of bytes remaining on track                   */
984 /*      physlen Number of bytes on physical track (=ds4devtk)        */
985 /*      kbconst Overhead for non-last keyed block (=ds4devi)         */
986 /*      lbconst Overhead for last keyed block (=ds4devl)             */
987 /*      nkconst Overhead difference for non-keyed block (=ds4devk)   */
988 /*      devflag Device flag byte for VTOC (=ds4devfg)                */
989 /*      tolfact Device tolerance factor (=ds4devtl)                  */
990 /*      maxdlen Maximum data length for non-keyed record 1           */
991 /*      numrecs Number of records of specified length per track      */
992 /*      numhead Number of tracks per cylinder                        */
993 /*      numcyls Number of cylinders per volume                       */
994 /* Note:                                                             */
995 /*      A NULL address may be specified for any of the output        */
996 /*      fields if the output value is not required.                  */
997 /*      The return value is 0 if the record will fit on the track,   */
998 /*      +1 if record will not fit on track, or -1 if unknown devtype */
999 /* Note:                                                             */
1000 /*      Although the virtual DASD image file contains no interrecord */
1001 /*      gaps, this subroutine performs its calculations taking into  */
1002 /*      account the gaps that would exist on a real device, so that  */
1003 /*      the track capacities of the real device are not exceeded.    */
1004 /*-------------------------------------------------------------------*/
capacity_calc(CIFBLK * cif,int used,int keylen,int datalen,int * newused,int * trkbaln,int * physlen,int * kbconst,int * lbconst,int * nkconst,BYTE * devflag,int * tolfact,int * maxdlen,int * numrecs,int * numhead,int * numcyls)1005 DLL_EXPORT int capacity_calc (CIFBLK *cif, int used, int keylen, int datalen,
1006                 int *newused, int *trkbaln, int *physlen, int *kbconst,
1007                 int *lbconst, int *nkconst, BYTE*devflag, int *tolfact,
1008                 int *maxdlen, int *numrecs, int *numhead, int *numcyls)
1009 {
1010 CKDDEV         *ckd;                    /* -> CKD device table entry */
1011 int             heads;                  /* Number of tracks/cylinder */
1012 int             cyls;                   /* Number of cyls/volume     */
1013 int             trklen;                 /* Physical track length     */
1014 int             maxlen;                 /* Maximum data length       */
1015 int             devi, devl, devk;       /* Overhead fields for VTOC  */
1016 BYTE            devfg;                  /* Flag field for VTOC       */
1017 int             devtl;                  /* Tolerance field for VTOC  */
1018 int             b1;                     /* Bytes used by new record
1019                                            when last record on track */
1020 int             b2;                     /* Bytes used by new record
1021                                            when not last on track    */
1022 int             nrecs;                  /* Number of record/track    */
1023 int             c, d1, d2, x;           /* 23xx/3330/3350 factors    */
1024 int             f1, f2, f3, f4, f5, f6; /* 3380/3390/9345 factors    */
1025 int             fl1, fl2, int1, int2;   /* 3380/3390/9345 calculation*/
1026 
1027     ckd = cif->devblk.ckdtab;
1028     trklen = ckd->len;
1029     maxlen = ckd->r1;
1030     heads = ckd->heads;
1031     cyls = ckd->cyls;
1032 
1033     switch (ckd->formula) {
1034 
1035     case -2:  /* 2311, 2314 */
1036         c = ckd->f1; x = ckd->f2; d1 = ckd->f3; d2 = ckd->f4;
1037         b1 = keylen + datalen + (keylen == 0 ? 0 : c);
1038         b2 = ((keylen + datalen) * d1 / d2)
1039                 + (keylen == 0 ? 0 : c) + x;
1040         nrecs = (trklen - b1)/b2 + 1;
1041         devi = c + x; devl = c; devk = c; devtl = d1 / (d2/512);
1042         devfg = 0x01;
1043         break;
1044 
1045     case -1:  /* 3330, 3340, 3350 */
1046         c = ckd->f1; x = ckd->f2;
1047         b1 = b2 = keylen + datalen + (keylen == 0 ? 0 : c) + x;
1048         nrecs = trklen / b2;
1049         devi = c + x; devl = c + x; devk = c; devtl = 512;
1050         devfg = 0x01;
1051         break;
1052 
1053     case 1:  /* 3375, 3380 */
1054         f1 = ckd->f1; f2 = ckd->f2; f3 = ckd->f3;
1055         fl1 = datalen + f2;
1056         fl2 = (keylen == 0 ? 0 : keylen + f3);
1057         fl1 = ((fl1 + f1 - 1) / f1) * f1;
1058         fl2 = ((fl2 + f1 - 1) / f1) * f1;
1059         b1 = b2 = fl1 + fl2;
1060         nrecs = trklen / b2;
1061         devi = 0; devl = 0; devk = 0; devtl = 0; devfg = 0x30;
1062         break;
1063 
1064     case 2:  /* 3390, 9345 */
1065         f1 = ckd->f1; f2 = ckd->f2; f3 = ckd->f3;
1066         f4 = ckd->f4; f5 = ckd->f5; f6 = ckd->f6;
1067         int1 = ((datalen + f6) + (f5*2-1)) / (f5*2);
1068         int2 = ((keylen + f6) + (f5*2-1)) / (f5*2);
1069         fl1 = (f1 * f2) + datalen + f6 + f4*int1;
1070         fl2 = (keylen == 0 ? 0 : (f1 * f3) + keylen + f6 + f4*int2);
1071         fl1 = ((fl1 + f1 - 1) / f1) * f1;
1072         fl2 = ((fl2 + f1 - 1) / f1) * f1;
1073         b1 = b2 = fl1 + fl2;
1074         nrecs = trklen / b2;
1075         devi = 0; devl = 0; devk = 0; devtl = 0; devfg = 0x30;
1076         break;
1077 
1078     default:
1079         return -1;
1080     } /* end switch(ckd->formula) */
1081 
1082     /* Return VTOC fields and maximum data length */
1083     if (physlen != NULL) *physlen = trklen;
1084     if (kbconst != NULL) *kbconst = devi;
1085     if (lbconst != NULL) *lbconst = devl;
1086     if (nkconst != NULL) *nkconst = devk;
1087     if (devflag != NULL) *devflag = devfg;
1088     if (tolfact != NULL) *tolfact = devtl;
1089     if (maxdlen != NULL) *maxdlen = maxlen;
1090 
1091     /* Return number of records per track */
1092     if (numrecs != NULL) *numrecs = nrecs;
1093 
1094     /* Return number of tracks per cylinder
1095        and usual number of cylinders per volume */
1096     if (numhead != NULL) *numhead = heads;
1097     if (numcyls != NULL) *numcyls = cyls;
1098 
1099     /* Return if record will not fit on the track */
1100     if (used + b1 > trklen)
1101         return +1;
1102 
1103     /* Calculate number of bytes used and track balance */
1104     if (newused != NULL)
1105         *newused = used + b2;
1106     if (trkbaln != NULL)
1107         *trkbaln = (used + b2 > trklen) ? 0 : trklen - used - b2;
1108 
1109     return 0;
1110 } /* end function capacity_calc */
1111 
1112 /*-------------------------------------------------------------------*/
1113 /* Subroutine to create a CKD DASD image file                        */
1114 /* Input:                                                            */
1115 /*      fname    DASD image file name                                */
1116 /*      fseqn    Sequence number of this file (1=first)              */
1117 /*      devtype  Device type                                         */
1118 /*      heads    Number of heads per cylinder                        */
1119 /*      trksize  DADS image track length                             */
1120 /*      buf      -> Track image buffer                               */
1121 /*      start    Starting cylinder number for this file              */
1122 /*      end      Ending cylinder number for this file                */
1123 /*      volcyls  Total number of cylinders on volume                 */
1124 /*      volser   Volume serial number                                */
1125 /*      comp     Compression algorithm for a compressed device.      */
1126 /*               Will be 0xff if device is not to be compressed.     */
1127 /*      dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      */
1128 /*      nullfmt  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      */
1129 /*      rawflag  create raw image (skip special track 0 handling)    */
1130 /*-------------------------------------------------------------------*/
1131 static int
create_ckd_file(char * fname,int fseqn,U16 devtype,U32 heads,U32 trksize,BYTE * buf,U32 start,U32 end,U32 volcyls,char * volser,BYTE comp,int dasdcopy,int nullfmt,int rawflag)1132 create_ckd_file (char *fname, int fseqn, U16 devtype, U32 heads,
1133                 U32 trksize, BYTE *buf, U32 start, U32 end,
1134                 U32 volcyls, char *volser, BYTE comp, int dasdcopy,
1135                 int nullfmt, int rawflag)
1136 {
1137 int             rc;                     /* Return code               */
1138 off_t           rcoff;                  /* Return value from lseek() */
1139 int             fd;                     /* File descriptor           */
1140 int             i;                      /* Loop counter              */
1141 int             n;                      /* Loop delimiter            */
1142 CKDDASD_DEVHDR  devhdr;                 /* Device header             */
1143 CCKDDASD_DEVHDR cdevhdr;                /* Compressed device header  */
1144 CCKD_L1ENT     *l1=NULL;                /* -> Primary lookup table   */
1145 CCKD_L2ENT      l2[256];                /* Secondary lookup table    */
1146 CKDDASD_TRKHDR *trkhdr;                 /* -> Track header           */
1147 CKDDASD_RECHDR *rechdr;                 /* -> Record header          */
1148 U32             cyl;                    /* Cylinder number           */
1149 U32             head;                   /* Head number               */
1150 int             trk = 0;                /* Track number              */
1151 int             trks;                   /* Total number tracks       */
1152 BYTE            r;                      /* Record number             */
1153 BYTE           *pos;                    /* -> Next position in buffer*/
1154 U32             cpos = 0;               /* Offset into cckd file     */
1155 int             len = 0;                /* Length used in track      */
1156 int             keylen = 4;             /* Length of keys            */
1157 int             ipl1len = 24;           /* Length of IPL1 data       */
1158 int             ipl2len = 144;          /* Length of IPL2 data       */
1159 int             vol1len = 80;           /* Length of VOL1 data       */
1160 int             rec0len = 8;            /* Length of R0 data         */
1161 int             fileseq;                /* CKD header sequence number*/
1162 int             highcyl;                /* CKD header high cyl number*/
1163 int             x=O_EXCL;               /* Open option               */
1164 CKDDEV         *ckdtab;                 /* -> CKD table entry        */
1165 char            pathname[MAX_PATH];     /* file path in host format  */
1166 
1167     /* Locate the CKD dasd table entry */
1168     ckdtab = dasd_lookup (DASD_CKDDEV, NULL, devtype, volcyls);
1169     if (ckdtab == NULL)
1170     {
1171         fprintf (stderr,
1172                   _("HHCDU028E device type %4.4X not found in dasd table\n"),
1173                   devtype);
1174         return -1;
1175     }
1176 
1177     /* Set file sequence number to zero if this is the only file */
1178     if (fseqn == 1 && end + 1 == volcyls)
1179         fileseq = 0;
1180     else
1181         fileseq = fseqn;
1182 
1183     /* Set high cylinder number to zero if this is the last file */
1184     if (end + 1 == volcyls)
1185         highcyl = 0;
1186     else
1187         highcyl = end;
1188     cyl = end - start + 1;
1189 
1190     /* Special processing for ckd and dasdcopy */
1191     if (comp == 0xFF && dasdcopy)
1192     {
1193         highcyl = end;
1194         if (end + 1 == volcyls)
1195             fileseq = 0xff;
1196     }
1197 
1198     trks = volcyls * heads;
1199 
1200     /* if `dasdcopy' > 1 then we can replace the existing file */
1201     if (dasdcopy > 1) x = 0;
1202 
1203     /* Create the DASD image file */
1204     hostpath(pathname, fname, sizeof(pathname));
1205     fd = hopen(pathname, O_WRONLY | O_CREAT | x | O_BINARY,
1206                 S_IRUSR | S_IWUSR | S_IRGRP);
1207     if (fd < 0)
1208     {
1209         fprintf (stderr, _("HHCDU028E %s open error: %s\n"),
1210                 fname, strerror(errno));
1211         return -1;
1212     }
1213 
1214     /* Create the device header */
1215     memset(&devhdr, 0, CKDDASD_DEVHDR_SIZE);
1216     if (comp == 0xff)
1217         memcpy(devhdr.devid, "CKD_P370", 8);
1218     else
1219         memcpy(devhdr.devid, "CKD_C370", 8);
1220     devhdr.heads[3] = (heads >> 24) & 0xFF;
1221     devhdr.heads[2] = (heads >> 16) & 0xFF;
1222     devhdr.heads[1] = (heads >> 8) & 0xFF;
1223     devhdr.heads[0] = heads & 0xFF;
1224     devhdr.trksize[3] = (trksize >> 24) & 0xFF;
1225     devhdr.trksize[2] = (trksize >> 16) & 0xFF;
1226     devhdr.trksize[1] = (trksize >> 8) & 0xFF;
1227     devhdr.trksize[0] = trksize & 0xFF;
1228     devhdr.devtype = devtype & 0xFF;
1229     devhdr.fileseq = fileseq;
1230     devhdr.highcyl[1] = (highcyl >> 8) & 0xFF;
1231     devhdr.highcyl[0] = highcyl & 0xFF;
1232 
1233     /* Write the device header */
1234     rc = write (fd, &devhdr, CKDDASD_DEVHDR_SIZE);
1235     if (rc < (int)CKDDASD_DEVHDR_SIZE)
1236     {
1237         fprintf (stderr, _("HHCDU029E %s device header write error: %s\n"),
1238                 fname, errno ? strerror(errno) : "incomplete");
1239         return -1;
1240     }
1241 
1242     /* Build a compressed CKD file */
1243     if (comp != 0xff)
1244     {
1245         /* Create the compressed device header */
1246         memset(&cdevhdr, 0, CCKDDASD_DEVHDR_SIZE);
1247         cdevhdr.vrm[0] = CCKD_VERSION;
1248         cdevhdr.vrm[1] = CCKD_RELEASE;
1249         cdevhdr.vrm[2] = CCKD_MODLVL;
1250         if (cckd_endian())  cdevhdr.options |= CCKD_BIGENDIAN;
1251         cdevhdr.options |= (CCKD_ORDWR | CCKD_NOFUDGE);
1252         cdevhdr.numl1tab = (volcyls * heads + 255) / 256;
1253         cdevhdr.numl2tab = 256;
1254         cdevhdr.cyls[3] = (volcyls >> 24) & 0xFF;
1255         cdevhdr.cyls[2] = (volcyls >> 16) & 0xFF;
1256         cdevhdr.cyls[1] = (volcyls >>    8) & 0xFF;
1257         cdevhdr.cyls[0] = volcyls & 0xFF;
1258         cdevhdr.compress = comp;
1259         cdevhdr.compress_parm = -1;
1260         cdevhdr.nullfmt = nullfmt;
1261 
1262         /* Write the compressed device header */
1263         rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE);
1264         if (rc < (int)CCKDDASD_DEVHDR_SIZE)
1265         {
1266             fprintf (stderr, _("HHCDU030E %s compressed device header "
1267                              "write error: %s\n"),
1268                     fname, errno ? strerror(errno) : "incomplete");
1269             return -1;
1270         }
1271 
1272         /* Create the primary lookup table */
1273         l1 = calloc (cdevhdr.numl1tab, CCKD_L1ENT_SIZE);
1274         if (l1 == NULL)
1275         {
1276             fprintf (stderr, _("HHCDU031E Cannot obtain l1tab buffer: %s\n"),
1277                     strerror(errno));
1278             return -1;
1279         }
1280         l1[0] = CCKD_L1TAB_POS + cdevhdr.numl1tab * CCKD_L1ENT_SIZE;
1281 
1282         /* Write the primary lookup table */
1283         rc = write (fd, l1, cdevhdr.numl1tab * CCKD_L1ENT_SIZE);
1284         if (rc < (int)(cdevhdr.numl1tab * CCKD_L1ENT_SIZE))
1285         {
1286             fprintf (stderr, _("HHCDU032E %s primary lookup table "
1287                              "write error: %s\n"),
1288                     fname, errno ? strerror(errno) : "incomplete");
1289             return -1;
1290         }
1291 
1292         /* Create the secondary lookup table */
1293         memset (&l2, 0, CCKD_L2TAB_SIZE);
1294 
1295         /* Write the seondary lookup table */
1296         rc = write (fd, &l2, CCKD_L2TAB_SIZE);
1297         if (rc < (int)CCKD_L2TAB_SIZE)
1298         {
1299             fprintf (stderr, _("HHCDU033E %s secondary lookup table "
1300                              "write error: %s\n"),
1301                     fname, errno ? strerror(errno) : "incomplete");
1302             return -1;
1303         }
1304 
1305         cpos = l1[0] + CCKD_L2TAB_SIZE;
1306     }
1307 
1308     if (!dasdcopy)
1309     {
1310         /* Write each cylinder */
1311         for (cyl = start; cyl <= end; cyl++)
1312         {
1313             /* Display progress message every 10 cylinders */
1314             if (cyl && !(cyl % 10))
1315             {
1316 #ifdef EXTERNALGUI
1317                 if (extgui)
1318                     fprintf (stderr, "CYL=%u\n", cyl);
1319                 else
1320 #endif /*EXTERNALGUI*/
1321                 fprintf (stderr, "Writing cylinder %u\r", cyl);
1322             }
1323 
1324             for (head = 0; head < heads; head++)
1325             {
1326                 /* Clear the track to zeroes */
1327                 memset (buf, 0, trksize);
1328 
1329                 /* Build the track header */
1330                 trkhdr = (CKDDASD_TRKHDR*)buf;
1331                 trkhdr->bin = 0;
1332                 store_hw(&trkhdr->cyl, cyl);
1333                 store_hw(&trkhdr->head, head);
1334                 pos = buf + CKDDASD_TRKHDR_SIZE;
1335 
1336                 /* Build record zero */
1337                 r = 0;
1338                 rechdr = (CKDDASD_RECHDR*)pos;
1339                 pos += CKDDASD_RECHDR_SIZE;
1340                 store_hw(&rechdr->cyl, cyl);
1341                 store_hw(&rechdr->head, head);
1342                 rechdr->rec = r;
1343                 rechdr->klen = 0;
1344                 store_hw(&rechdr->dlen, rec0len);
1345                 pos += rec0len;
1346                 r++;
1347 
1348                 /* Track 0 contains IPL records and volume label */
1349                 if (!rawflag && fseqn == 1 && trk == 0)
1350                 {
1351                     /* Build the IPL1 record */
1352                     rechdr = (CKDDASD_RECHDR*)pos;
1353                     pos += CKDDASD_RECHDR_SIZE;
1354 
1355                     store_hw(&rechdr->cyl, cyl);
1356                     store_hw(&rechdr->head, head);
1357                     rechdr->rec = r;
1358                     rechdr->klen = keylen;
1359                     store_hw(&rechdr->dlen, ipl1len);
1360                     r++;
1361 
1362                     convert_to_ebcdic (pos, keylen, "IPL1");
1363                     pos += keylen;
1364 
1365                     memcpy (pos, iplpsw, 8);
1366                     memcpy (pos+8, iplccw1, 8);
1367                     memcpy (pos+16, iplccw2, 8);
1368                     pos += ipl1len;
1369 
1370                     /* Build the IPL2 record */
1371                     rechdr = (CKDDASD_RECHDR*)pos;
1372                     pos += CKDDASD_RECHDR_SIZE;
1373 
1374                     store_hw(&rechdr->cyl, cyl);
1375                     store_hw(&rechdr->head, head);
1376                     rechdr->rec = r;
1377                     rechdr->klen = keylen;
1378                     store_hw(&rechdr->dlen, ipl2len);
1379                     r++;
1380 
1381                     convert_to_ebcdic (pos, keylen, "IPL2");
1382                     pos += keylen;
1383 
1384                     pos += ipl2len;
1385 
1386                     /* Build the VOL1 record */
1387                     rechdr = (CKDDASD_RECHDR*)pos;
1388                     pos += CKDDASD_RECHDR_SIZE;
1389 
1390                     store_hw(&rechdr->cyl, cyl);
1391                     store_hw(&rechdr->head, head);
1392                     rechdr->rec = r;
1393                     rechdr->klen = keylen;
1394                     store_hw(&rechdr->dlen, vol1len);
1395                     r++;
1396 
1397                     convert_to_ebcdic (pos, keylen, "VOL1");
1398                     pos += keylen;
1399 
1400                     convert_to_ebcdic (pos, 4, "VOL1");             //VOL1
1401                     convert_to_ebcdic (pos+4, 6, volser);           //volser
1402                     pos[10] = 0x40;                                 //security
1403                     store_hw(pos+11,0);                             //vtoc CC
1404                     store_hw(pos+13,1);                             //vtoc HH
1405                     pos[15] = 0x01;                                 //vtoc R
1406                     memset(pos+16, 0x40, 21);                       //reserved
1407                     convert_to_ebcdic (pos+37, 14, "    HERCULES"); //ownerid
1408                     memset(pos+51, 0x40, 29);                       //reserved
1409                     pos += vol1len;
1410 
1411                     /* 9 4096 data blocks for linux volume */
1412                     if (nullfmt == CKDDASD_NULLTRK_FMT2)
1413                     {
1414                         for (i = 0; i < 9; i++)
1415                         {
1416                             rechdr = (CKDDASD_RECHDR*)pos;
1417                             pos += CKDDASD_RECHDR_SIZE;
1418 
1419                             store_hw(&rechdr->cyl, cyl);
1420                             store_hw(&rechdr->head, head);
1421                             rechdr->rec = r;
1422                             rechdr->klen = 0;
1423                             store_hw(&rechdr->dlen, 4096);
1424                             pos += 4096;
1425                             r++;
1426                         }
1427                     }
1428                 } /* end if(trk == 0) */
1429 
1430                 /* Track 1 for linux contains an empty VTOC */
1431                 else if (fseqn == 1 && trk == 1 && nullfmt == CKDDASD_NULLTRK_FMT2)
1432                 {
1433                     /* build format 4 dscb */
1434                     rechdr = (CKDDASD_RECHDR*)pos;
1435                     pos += CKDDASD_RECHDR_SIZE;
1436 
1437                     /* track 1 record 1 count */
1438                     store_hw(&rechdr->cyl, cyl);
1439                     store_hw(&rechdr->head, head);
1440                     rechdr->rec = r;
1441                     rechdr->klen = 44;
1442                     store_hw(&rechdr->dlen, 96);
1443                     r++;
1444 
1445                     /* track 1 record 1 key */
1446                     memset (pos, 0x04, 44);
1447                     pos += 44;
1448 
1449                     /* track 1 record 1 data */
1450                     memset (pos, 0, 96);
1451                     pos[0] = 0xf4;                            // DS4IDFMT
1452                     store_hw(pos + 6, 10);                    // DS4DSREC
1453                     pos[14] = trks > 65535 ? 0xa0 : 0;        // DS4VTOCI
1454                     pos[15] = 1;                              // DS4NOEXT
1455                     store_hw(pos+18, volcyls);                // DS4DSCYL
1456                     store_hw(pos+20, heads);                  // DS4DSTRK
1457                     store_hw(pos+22, ckdtab->len);            // DS4DEVTK
1458                     pos[27] = 0x30;                           // DS4DEVFG
1459                     pos[30] = 0x0c;                           // DS4DEVDT
1460                     pos[61] = 0x01;                           // DS4VTOCE + 00
1461                     pos[66] = 0x01;                           // DS4VTOCE + 05
1462                     pos[70] = 0x01;                           // DS4VTOCE + 09
1463                     pos[81] = trks > 65535 ? 7 : 0;           // DS4EFLVL
1464                     pos[85] = trks > 65535 ? 1 : 0;           // DS4EFPTR + 03
1465                     pos[86] = trks > 65535 ? 3 : 0;           // DS4EFPTR + 04
1466                     pos += 96;
1467 
1468                     /* build format 5 dscb */
1469                     rechdr = (CKDDASD_RECHDR*)pos;
1470                     pos += CKDDASD_RECHDR_SIZE;
1471 
1472                     /* track 1 record 1 count */
1473                     store_hw(&rechdr->cyl, cyl);
1474                     store_hw(&rechdr->head, head);
1475                     rechdr->rec = r;
1476                     rechdr->klen = 44;
1477                     store_hw(&rechdr->dlen, 96);
1478                     r++;
1479 
1480                     /* track 1 record 2 key */
1481                     memset (pos, 0x05, 4);                    // DS5KEYID
1482                     memset (pos+4, 0, 40);
1483                     if (trks <= 65535)
1484                     {
1485                         store_hw(pos+4, 2);                   // DS5AVEXT + 00
1486                         store_hw(pos+6, volcyls - 1);         // DS5AVEXT + 02
1487                         pos[8] = heads - 2;                   // DS5AVEXT + 04
1488                     }
1489                     pos += 44;
1490 
1491                     /* track 1 record 2 data */
1492                     memset (pos, 0, 96);
1493                     pos[0] = 0xf5;                            // DS5FMTID
1494                     pos += 96;
1495 
1496                     /* build format 7 dscb */
1497                     if (trks > 65535)
1498                     {
1499                         rechdr = (CKDDASD_RECHDR*)pos;
1500                         pos += CKDDASD_RECHDR_SIZE;
1501 
1502                         /* track 1 record 3 count */
1503                         store_hw(&rechdr->cyl, cyl);
1504                         store_hw(&rechdr->head, head);
1505                         rechdr->rec = r;
1506                         rechdr->klen = 44;
1507                         store_hw(&rechdr->dlen, 96);
1508                         r++;
1509 
1510                         /* track 1 record 2 key */
1511                         memset (pos, 0x07, 4);                // DS7KEYID
1512                         memset (pos+4, 0, 40);
1513                         store_fw(pos+4, 2);                   // DS7EXTNT + 00
1514                         store_fw(pos+8, trks - 1);            // DS7EXTNT + 04
1515                         pos += 44;
1516 
1517                         /* track 1 record 2 data */
1518                         memset (pos, 0, 96);
1519                         pos[0] = 0xf7;                        // DS7FMTID
1520                         pos += 96;
1521                     }
1522 
1523                     n = 12 - r + 1;
1524                     for (i = 0; i < n; i++)
1525                     {
1526                         rechdr = (CKDDASD_RECHDR*)pos;
1527                         pos += CKDDASD_RECHDR_SIZE;
1528 
1529                         store_hw(&rechdr->cyl, cyl);
1530                         store_hw(&rechdr->head, head);
1531                         rechdr->rec = r;
1532                         rechdr->klen = 44;
1533                         store_hw(&rechdr->dlen, 96);
1534                         pos += 140;
1535                         r++;
1536                     }
1537                 }
1538 
1539                 /* Specific null track formatting */
1540                 else if (nullfmt == CKDDASD_NULLTRK_FMT0)
1541                 {
1542                     rechdr = (CKDDASD_RECHDR*)pos;
1543                     pos += CKDDASD_RECHDR_SIZE;
1544 
1545                     store_hw(&rechdr->cyl, cyl);
1546                     store_hw(&rechdr->head, head);
1547                     rechdr->rec = r;
1548                     rechdr->klen = 0;
1549                     store_hw(&rechdr->dlen, 0);
1550                     r++;
1551                 }
1552                 else if (nullfmt == CKDDASD_NULLTRK_FMT2)
1553                 {
1554                     /* Other linux tracks have 12 4096 data records */
1555                     for (i = 0; i < 12; i++)
1556                     {
1557                         rechdr = (CKDDASD_RECHDR*)pos;
1558                         pos += CKDDASD_RECHDR_SIZE;
1559                         store_hw(&rechdr->cyl, cyl);
1560                         store_hw(&rechdr->head, head);
1561                         rechdr->rec = r;
1562                         rechdr->klen = 0;
1563                         store_hw(&rechdr->dlen, 4096);
1564                         pos += 4096;
1565                         r++;
1566                     }
1567                 }
1568 
1569                 /* End-of-track marker */
1570                 memcpy (pos, eighthexFF, 8);
1571                 pos += 8;
1572 
1573                 /* Calculate length to write */
1574                 if (comp == 0xff)
1575                     len = (int)trksize;
1576                 else
1577                 {
1578                     len = (int)(pos - buf);
1579                     l2[trk].pos = cpos;
1580                     l2[trk].len = l2[trk].size = len;
1581                     cpos += len;
1582                 }
1583 
1584                 /* Write the track to the file */
1585                 rc = write (fd, buf, len);
1586                 if (rc != len)
1587                 {
1588                     fprintf (stderr,
1589                             _("HHCDU035E %s cylinder %u head %u "
1590                             "write error: %s\n"),
1591                             fname, cyl, head,
1592                             errno ? strerror(errno) : "incomplete");
1593                     return -1;
1594                 }
1595 
1596                 /* Exit if compressed disk and current track is 1 */
1597                 if (comp != 0xff && trk == 1) break;
1598 
1599                 trk++;
1600 
1601             } /* end for(head) */
1602 
1603             /* Exit if compressed disk */
1604             if (comp != 0xff) break;
1605 
1606         } /* end for(cyl) */
1607 
1608     } /* `dasdcopy' bit is off */
1609     else
1610         cyl = end + 1;
1611 
1612     /* Complete building the compressed file */
1613     if (comp != 0xff)
1614     {
1615         cdevhdr.size = cdevhdr.used = cpos;
1616 
1617         /* Rewrite the compressed device header */
1618         rcoff = lseek (fd, CKDDASD_DEVHDR_SIZE, SEEK_SET);
1619         if (rcoff == -1)
1620         {
1621             fprintf (stderr, _("HHCDU036E %s compressed device header "
1622                              "lseek error: %s\n"),
1623                     fname, strerror(errno));
1624             return -1;
1625         }
1626         rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE);
1627         if (rc < (int)CCKDDASD_DEVHDR_SIZE)
1628         {
1629             fprintf (stderr, _("HHCDU037E %s compressed device header "
1630                              "write error: %s\n"),
1631                     fname, errno ? strerror(errno) : "incomplete");
1632             return -1;
1633         }
1634 
1635         /* Rewrite the secondary lookup table */
1636         rcoff = lseek (fd, (off_t)l1[0], SEEK_SET);
1637         if (rcoff == -1)
1638         {
1639             fprintf (stderr, _("HHCDU038E %s secondary lookup table "
1640                              "lseek error: %s\n"),
1641                     fname, strerror(errno));
1642             return -1;
1643         }
1644         rc = write (fd, &l2, CCKD_L2TAB_SIZE);
1645         if (rc < (int)CCKD_L2TAB_SIZE)
1646         {
1647             fprintf (stderr, _("HHCDU039E %s secondary lookup table "
1648                              "write error: %s\n"),
1649                     fname, errno ? strerror(errno) : "incomplete");
1650             return -1;
1651         }
1652         rc = ftruncate(fd, (off_t)cdevhdr.size);
1653 
1654         free (l1);
1655         cyl = volcyls;
1656     }
1657 
1658     /* Close the DASD image file */
1659     rc = close (fd);
1660     if (rc < 0)
1661     {
1662         fprintf (stderr, _("HHCDU040E %s close error: %s\n"),
1663                 fname, strerror(errno));
1664         return -1;
1665     }
1666 
1667     /* Display completion message */
1668     fprintf (stderr,
1669             _("HHCDU041I %u cylinders successfully written to file %s\n"),
1670             cyl - start, fname);
1671     return 0;
1672 
1673 } /* end function create_ckd_file */
1674 
1675 /*-------------------------------------------------------------------*/
1676 /* Subroutine to create a CKD DASD image                             */
1677 /* Input:                                                            */
1678 /*      fname    DASD image file name                                */
1679 /*      devtype  Device type                                         */
1680 /*      heads    Number of heads per cylinder                        */
1681 /*      maxdlen  Maximum R1 record data length                       */
1682 /*      volcyls  Total number of cylinders on volume                 */
1683 /*      volser   Volume serial number                                */
1684 /*      comp     Compression algorithm for a compressed device.      */
1685 /*               Will be 0xff if device is not to be compressed.     */
1686 /*      lfs      build large (uncompressed) file (if supported)      */
1687 /*      dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      */
1688 /*      nullfmt  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      */
1689 /*      rawflag  create raw image (skip special track 0 handling)    */
1690 /*                                                                   */
1691 /* If the total number of cylinders exceeds the capacity of a 2GB    */
1692 /* file, then multiple CKD image files will be created, with the     */
1693 /* suffix _1, _2, etc suffixed to the specified file name.           */
1694 /* Otherwise a single file is created without a suffix.              */
1695 /*-------------------------------------------------------------------*/
1696 DLL_EXPORT int
create_ckd(char * fname,U16 devtype,U32 heads,U32 maxdlen,U32 volcyls,char * volser,BYTE comp,int lfs,int dasdcopy,int nullfmt,int rawflag)1697 create_ckd (char *fname, U16 devtype, U32 heads, U32 maxdlen,
1698            U32 volcyls, char *volser, BYTE comp, int lfs, int dasdcopy,
1699            int nullfmt, int rawflag)
1700 {
1701 int             i;                      /* Array subscript           */
1702 int             rc;                     /* Return code               */
1703 char            *s;                     /* String pointer            */
1704 int             fileseq;                /* File sequence number      */
1705 char            sfname[FILENAME_MAX];   /* Suffixed name of this file*/
1706 char            *suffix;                /* -> Suffix character       */
1707 U32             endcyl;                 /* Last cylinder of this file*/
1708 U32             cyl;                    /* Cylinder number           */
1709 U32             cylsize;                /* Cylinder size in bytes    */
1710 BYTE           *buf;                    /* -> Track data buffer      */
1711 U32             mincyls;                /* Minimum cylinder count    */
1712 U32             maxcyls;                /* Maximum cylinder count    */
1713 U32             maxcpif;                /* Maximum number of cylinders
1714                                            in each CKD image file    */
1715 int             rec0len = 8;            /* Length of R0 data         */
1716 U32             trksize;                /* DASD image track length   */
1717 
1718     /* Compute the DASD image track length */
1719     trksize = sizeof(CKDDASD_TRKHDR)
1720                 + sizeof(CKDDASD_RECHDR) + rec0len
1721                 + sizeof(CKDDASD_RECHDR) + maxdlen
1722                 + sizeof(eighthexFF);
1723     trksize = ROUND_UP(trksize,512);
1724 
1725     /* Compute minimum and maximum number of cylinders */
1726     cylsize = trksize * heads;
1727     mincyls = 1;
1728     if (comp == 0xff && !lfs)
1729     {
1730         maxcpif = (0x7fffffff - CKDDASD_DEVHDR_SIZE + 1) / cylsize;
1731         maxcyls = maxcpif * CKD_MAXFILES;
1732     }
1733     else
1734         maxcpif = maxcyls = volcyls;
1735     if (maxcyls > 65536) maxcyls = 65536;
1736 
1737     /* Check for valid number of cylinders */
1738     if (volcyls < mincyls || volcyls > maxcyls)
1739     {
1740         fprintf (stderr,
1741                 _("HHCDU042E Cylinder count %u is outside range %u-%u\n"),
1742                 volcyls, mincyls, maxcyls);
1743         return -1;
1744     }
1745 
1746     /* Obtain track data buffer */
1747     buf = malloc(trksize);
1748     if (buf == NULL)
1749     {
1750         fprintf (stderr, _("HHCDU043E Cannot obtain track buffer: %s\n"),
1751                 strerror(errno));
1752         return -1;
1753     }
1754 
1755     /* Display progress message */
1756     fprintf (stderr,
1757             _("HHCDU044I Creating %4.4X volume %s: %u cyls, "
1758             "%u trks/cyl, %u bytes/track\n"),
1759             devtype, rawflag ? "" : volser, volcyls, heads, trksize);
1760 
1761     /* Copy the unsuffixed DASD image file name */
1762     strcpy (sfname, fname);
1763     suffix = NULL;
1764 
1765     /* Create the suffixed file name if volume will exceed 2GB */
1766     if (volcyls > maxcpif)
1767     {
1768         /* Look for last slash marking end of directory name */
1769         s = strrchr (fname, '/');
1770         if (s == NULL) s = fname;
1771 
1772         /* Insert suffix before first dot in file name, or
1773            append suffix to file name if there is no dot.
1774            If the filename already has a place for the suffix
1775            then use that. */
1776         s = strchr (s, '.');
1777         if (s != NULL)
1778         {
1779             i = s - fname;
1780             if (i > 2 && fname[i-2] == '_')
1781                 suffix = sfname + i - 1;
1782             else
1783             {
1784                 strcpy (sfname + i, "_1");
1785                 strcat (sfname, fname + i);
1786                 suffix = sfname + i + 1;
1787             }
1788         }
1789         else
1790         {
1791             if (strlen(sfname) < 2 || sfname[strlen(sfname)-2] == '_')
1792                 strcat (sfname, "_1");
1793             suffix = sfname + strlen(sfname) - 1;
1794         }
1795     }
1796 
1797     /* Create the DASD image files */
1798     for (cyl = 0, fileseq = 1; cyl < volcyls;
1799             cyl += maxcpif, fileseq++)
1800     {
1801         /* Insert the file sequence number in the file name */
1802         if (suffix)
1803         {
1804             if (fileseq <= 9)
1805                 *suffix = '0' + fileseq;
1806             else
1807                 *suffix = 'A' - 10 + fileseq;
1808         }
1809 
1810         /* Calculate the ending cylinder for this file */
1811         if (cyl + maxcpif < volcyls)
1812             endcyl = cyl + maxcpif - 1;
1813         else
1814             endcyl = volcyls - 1;
1815 
1816         /* Create a CKD DASD image file */
1817         rc = create_ckd_file (sfname, fileseq, devtype, heads,
1818                     trksize, buf, cyl, endcyl, volcyls, volser,
1819                     comp, dasdcopy, nullfmt, rawflag);
1820         if (rc < 0) return -1;
1821     }
1822 
1823     /* Release data buffer */
1824     free (buf);
1825 
1826     return 0;
1827 } /* end function create_ckd */
1828 
1829 /*-------------------------------------------------------------------*/
1830 /* Subroutine to create an FBA DASD image file                       */
1831 /* Input:                                                            */
1832 /*      fname    DASD image file name                                */
1833 /*      devtype  Device type                                         */
1834 /*      sectsz   Sector size                                         */
1835 /*      sectors  Number of sectors                                   */
1836 /*      volser   Volume serial number                                */
1837 /*      comp     Compression algorithm for a compressed device.      */
1838 /*               Will be 0xff if device is not to be compressed.     */
1839 /*      lfs      build large (uncompressed) file (if supported)      */
1840 /*      dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      */
1841 /*      rawflag  create raw image (skip sector 1 VOL1 processing)    */
1842 /*-------------------------------------------------------------------*/
1843 DLL_EXPORT int
create_fba(char * fname,U16 devtype,U32 sectsz,U32 sectors,char * volser,BYTE comp,int lfs,int dasdcopy,int rawflag)1844 create_fba (char *fname, U16 devtype, U32 sectsz, U32 sectors,
1845             char *volser, BYTE comp, int lfs, int dasdcopy, int rawflag)
1846 {
1847 int             rc;                     /* Return code               */
1848 int             fd;                     /* File descriptor           */
1849 U32             sectnum;                /* Sector number             */
1850 BYTE           *buf;                    /* -> Sector data buffer     */
1851 U32             minsect;                /* Minimum sector count      */
1852 U32             maxsect;                /* Maximum sector count      */
1853 int             x=O_EXCL;               /* Open option               */
1854 char            pathname[MAX_PATH];     /* file path in host format  */
1855 
1856     /* Special processing for compressed fba */
1857     if (comp != 0xff)
1858     {
1859         rc = create_compressed_fba (fname, devtype, sectsz, sectors,
1860                                     volser, comp, lfs, dasdcopy, rawflag);
1861         return rc;
1862     }
1863 
1864     /* Compute minimum and maximum number of sectors */
1865     minsect = 64;
1866     maxsect = 0x80000000 / sectsz;
1867 
1868     /* Check for valid number of sectors */
1869     if (sectors < minsect || (!lfs && sectors > maxsect))
1870     {
1871         fprintf (stderr,
1872                 _("HHCDU045E Sector count %u is outside range %u-%u\n"),
1873                 sectors, minsect, maxsect);
1874         return -1;
1875     }
1876 
1877     /* Obtain sector data buffer */
1878     buf = malloc(sectsz);
1879     if (buf == NULL)
1880     {
1881         fprintf (stderr, _("HHCDU046E Cannot obtain sector buffer: %s\n"),
1882                 strerror(errno));
1883         return -1;
1884     }
1885 
1886     /* Display progress message */
1887     fprintf (stderr,
1888             _("HHCDU047I Creating %4.4X volume %s: "
1889             "%u sectors, %u bytes/sector\n"),
1890             devtype, rawflag ? "" : volser, sectors, sectsz);
1891 
1892     /* if `dasdcopy' > 1 then we can replace the existing file */
1893     if (dasdcopy > 1) x = 0;
1894 
1895     /* Create the DASD image file */
1896     hostpath(pathname, fname, sizeof(pathname));
1897     fd = hopen(pathname, O_WRONLY | O_CREAT | x | O_BINARY,
1898                 S_IRUSR | S_IWUSR | S_IRGRP);
1899     if (fd < 0)
1900     {
1901         fprintf (stderr, _("HHCDU048I %s open error: %s\n"),
1902                 fname, strerror(errno));
1903         return -1;
1904     }
1905 
1906     /* If the `dasdcopy' bit is on then simply allocate the space */
1907     if (dasdcopy)
1908     {
1909         off_t sz = sectors * sectsz;
1910         rc = ftruncate (fd, sz);
1911         if (rc < 0)
1912         {
1913             fprintf (stderr, _("HHCDU049E %s dasdcopy ftruncate error: %s\n"),
1914                     fname, strerror(errno));
1915             return -1;
1916         }
1917     }
1918     /* Write each sector */
1919     else
1920     {
1921         for (sectnum = 0; sectnum < sectors; sectnum++)
1922         {
1923             /* Clear the sector to zeroes */
1924             memset (buf, 0, sectsz);
1925 
1926             /* Sector 1 contains the volume label */
1927             if (!rawflag && sectnum == 1)
1928             {
1929                 convert_to_ebcdic (buf, 4, "VOL1");
1930                 convert_to_ebcdic (buf+4, 6, volser);
1931             } /* end if(sectnum==1) */
1932 
1933             /* Display progress message every 100 sectors */
1934             if ((sectnum % 100) == 0)
1935 #ifdef EXTERNALGUI
1936             {
1937                 if (extgui) fprintf (stderr, "BLK=%u\n", sectnum);
1938                 else fprintf (stderr, "Writing sector %u\r", sectnum);
1939             }
1940 #else /*!EXTERNALGUI*/
1941             fprintf (stderr, "Writing sector %u\r", sectnum);
1942 #endif /*EXTERNALGUI*/
1943 
1944             /* Write the sector to the file */
1945             rc = write (fd, buf, sectsz);
1946             if (rc < (int)sectsz)
1947             {
1948                 fprintf (stderr, _("HHCDU050E %s sector %u write error: %s\n"),
1949                         fname, sectnum,
1950                         errno ? strerror(errno) : "incomplete");
1951                 return -1;
1952             }
1953         } /* end for(sectnum) */
1954     } /* `dasdcopy' bit is off */
1955 
1956     /* Close the DASD image file */
1957     rc = close (fd);
1958     if (rc < 0)
1959     {
1960         fprintf (stderr, _("HHCDU051E %s close error: %s\n"),
1961                 fname, strerror(errno));
1962         return -1;
1963     }
1964 
1965     /* Release data buffer */
1966     free (buf);
1967 
1968     /* Display completion message */
1969     fprintf (stderr,
1970             _("HHCDU052I %u sectors successfully written to file %s\n"),
1971             sectors, fname);
1972 
1973     return 0;
1974 } /* end function create_fba */
1975 
1976 /*-------------------------------------------------------------------*/
1977 /* Subroutine to create a compressed FBA DASD image file             */
1978 /* Input:                                                            */
1979 /*      fname    DASD image file name                                */
1980 /*      devtype  Device type                                         */
1981 /*      sectsz   Sector size                                         */
1982 /*      sectors  Number of sectors                                   */
1983 /*      volser   Volume serial number                                */
1984 /*      comp     Compression algorithm for a compressed device.      */
1985 /*      lfs      build large (uncompressed) file (if supported)      */
1986 /*      dasdcopy xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      */
1987 /*      rawflag  create raw image (skip sector 1 VOL1 processing)    */
1988 /*-------------------------------------------------------------------*/
1989 int
create_compressed_fba(char * fname,U16 devtype,U32 sectsz,U32 sectors,char * volser,BYTE comp,int lfs,int dasdcopy,int rawflag)1990 create_compressed_fba (char *fname, U16 devtype, U32 sectsz,
1991            U32 sectors, char *volser, BYTE comp, int lfs, int dasdcopy,
1992            int rawflag)
1993 {
1994 int             rc;                     /* Return code               */
1995 off_t           rcoff;                  /* Return value from lseek() */
1996 int             fd;                     /* File descriptor           */
1997 CKDDASD_DEVHDR  devhdr;                 /* Device header             */
1998 CCKDDASD_DEVHDR cdevhdr;                /* Compressed device header  */
1999 int             blkgrps;                /* Number block groups       */
2000 int             numl1tab, l1tabsz;      /* Level 1 entries, size     */
2001 CCKD_L1ENT     *l1;                     /* Level 1 table pointer     */
2002 CCKD_L2ENT      l2[256];                /* Level 2 table             */
2003 unsigned long   len2;                   /* Compressed buffer length  */
2004 BYTE            buf2[256];              /* Compressed buffer         */
2005 BYTE            buf[65536];             /* Buffer                    */
2006 int             x=O_EXCL;               /* Open option               */
2007 char            pathname[MAX_PATH];     /* file path in host format  */
2008 
2009     UNREFERENCED(lfs);
2010 
2011     /* Calculate the size of the level 1 table */
2012     blkgrps = (sectors / CFBA_BLOCK_NUM) + 1;
2013     numl1tab = (blkgrps + 255) / 256;
2014     l1tabsz = numl1tab * CCKD_L1ENT_SIZE;
2015     if (l1tabsz > 65536)
2016     {
2017         fprintf (stderr, _("HHCDU053E File size too large: %" I64_FMT "ud [%d]\n"),
2018                  (U64)(sectors * sectsz), numl1tab);
2019         return -1;
2020     }
2021 
2022     /* if `dasdcopy' > 1 then we can replace the existing file */
2023     if (dasdcopy > 1) x = 0;
2024 
2025     /* Create the DASD image file */
2026     hostpath(pathname, fname, sizeof(pathname));
2027     fd = hopen(pathname, O_WRONLY | O_CREAT | x | O_BINARY,
2028                 S_IRUSR | S_IWUSR | S_IRGRP);
2029     if (fd < 0)
2030     {
2031         fprintf (stderr, _("HHCDU054E %s open error: %s\n"),
2032                 fname, strerror(errno));
2033         return -1;
2034     }
2035 
2036     /* Display progress message */
2037     fprintf (stderr,
2038             _("HHCDU055I Creating %4.4X compressed volume %s: "
2039             "%u sectors, %u bytes/sector\n"),
2040             devtype, rawflag ? "" : volser, sectors, sectsz);
2041 
2042     /* Write the device header */
2043     memset (&devhdr, 0, CKDDASD_DEVHDR_SIZE);
2044     memcpy (&devhdr.devid, "FBA_C370", 8);
2045     rc = write (fd, &devhdr, CKDDASD_DEVHDR_SIZE);
2046     if (rc < (int)CKDDASD_DEVHDR_SIZE)
2047     {
2048         fprintf (stderr, _("HHCDU056E %s devhdr write error: %s\n"),
2049                  fname, errno ? strerror(errno) : "incomplete");
2050             return -1;
2051     }
2052 
2053     /* Write the compressed device header */
2054     memset (&cdevhdr, 0, CCKDDASD_DEVHDR_SIZE);
2055     cdevhdr.vrm[0] = CCKD_VERSION;
2056     cdevhdr.vrm[1] = CCKD_RELEASE;
2057     cdevhdr.vrm[2] = CCKD_MODLVL;
2058     if (cckd_endian())  cdevhdr.options |= CCKD_BIGENDIAN;
2059     cdevhdr.options |= (CCKD_ORDWR | CCKD_NOFUDGE);
2060     cdevhdr.numl1tab = numl1tab;
2061     cdevhdr.numl2tab = 256;
2062     cdevhdr.cyls[3] = (sectors >> 24) & 0xFF;
2063     cdevhdr.cyls[2] = (sectors >> 16) & 0xFF;
2064     cdevhdr.cyls[1] = (sectors >>    8) & 0xFF;
2065     cdevhdr.cyls[0] = sectors & 0xFF;
2066     cdevhdr.compress = comp;
2067     cdevhdr.compress_parm = -1;
2068     rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE);
2069     if (rc < (int)CCKDDASD_DEVHDR_SIZE)
2070     {
2071         fprintf (stderr, _("HHCDU057E %s cdevhdr write error: %s\n"),
2072                  fname, errno ? strerror(errno) : "incomplete");
2073         return -1;
2074     }
2075 
2076     /* Write the level 1 table */
2077     l1 = (CCKD_L1ENT *)&buf;
2078     memset (l1, 0, l1tabsz);
2079     l1[0] = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz;
2080     rc = write (fd, l1, l1tabsz);
2081     if (rc < l1tabsz)
2082     {
2083         fprintf (stderr, _("HHCDU058E %s l1tab write error: %s\n"),
2084                  fname, errno ? strerror(errno) : "incomplete");
2085         return -1;
2086     }
2087 
2088     /* Write the 1st level 2 table */
2089     memset (&l2, 0, CCKD_L2TAB_SIZE);
2090     l2[0].pos = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz +
2091                 CCKD_L2TAB_SIZE;
2092     rc = write (fd, &l2, CCKD_L2TAB_SIZE);
2093     if (rc < (int)CCKD_L2TAB_SIZE)
2094     {
2095         fprintf (stderr, _("HHCDU059E %s l2tab write error: %s\n"),
2096                  fname, errno ? strerror(errno) : "incomplete");
2097         return -1;
2098     }
2099 
2100     /* Write the 1st block group */
2101     memset (&buf, 0, CKDDASD_DEVHDR_SIZE + CFBA_BLOCK_SIZE);
2102     if (!rawflag)
2103     {
2104         convert_to_ebcdic (&buf[CKDDASD_TRKHDR_SIZE+sectsz], 4, "VOL1");
2105         convert_to_ebcdic (&buf[CKDDASD_TRKHDR_SIZE+sectsz+4], 6, volser);
2106     }
2107     len2 = sizeof(buf2);
2108 #ifdef HAVE_LIBZ
2109     rc = compress2 (&buf2[0], &len2, &buf[CKDDASD_TRKHDR_SIZE],
2110                     CFBA_BLOCK_SIZE, -1);
2111     if (comp && rc == Z_OK)
2112     {
2113         buf[0] = CCKD_COMPRESS_ZLIB;
2114         rc = write (fd, &buf, CKDDASD_TRKHDR_SIZE);
2115         if (rc < (int)CKDDASD_TRKHDR_SIZE)
2116         {
2117             fprintf (stderr, _("HHCDU060E %s block header write error: %s\n"),
2118                      fname, errno ? strerror(errno) : "incomplete");
2119             return -1;
2120         }
2121         rc = write (fd, &buf2, len2);
2122         if (rc < (int)len2)
2123         {
2124             fprintf (stderr, _("HHCDU061E %s block write error: %s\n"),
2125                      fname, errno ? strerror(errno) : "incomplete");
2126             return -1;
2127         }
2128         l2[0].len = l2[0].size = CKDDASD_TRKHDR_SIZE + len2;
2129         cdevhdr.size = cdevhdr.used = CKDDASD_DEVHDR_SIZE +
2130                        CCKDDASD_DEVHDR_SIZE + l1tabsz + CCKD_L2TAB_SIZE +
2131                        CKDDASD_TRKHDR_SIZE + len2;
2132     }
2133     else
2134 #endif // defined(HAVE_LIBZ)
2135     {
2136         rc = write (fd, &buf, CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE);
2137         if (rc < (int)(CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE))
2138         {
2139             fprintf (stderr, _("HHCDU062E %s block write error: %s\n"),
2140                      fname, errno ? strerror(errno) : "incomplete");
2141             return -1;
2142         }
2143         l2[0].len = l2[0].size = CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE;
2144         cdevhdr.size = cdevhdr.used = CKDDASD_DEVHDR_SIZE +
2145                        CCKDDASD_DEVHDR_SIZE + l1tabsz + CCKD_L2TAB_SIZE +
2146                        CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE;
2147     }
2148 
2149     /* Re-write the compressed device header */
2150     rcoff = lseek (fd, CKDDASD_DEVHDR_SIZE, SEEK_SET);
2151     if (rcoff < 0)
2152     {
2153         fprintf (stderr, _("HHCDU063E %s cdevhdr lseek error: %s\n"),
2154                  fname, strerror(errno));
2155         return -1;
2156     }
2157     rc = write (fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE);
2158     if (rc < (int)CCKDDASD_DEVHDR_SIZE)
2159     {
2160         fprintf (stderr, _("HHCDU064E %s cdevhdr rewrite error: %s\n"),
2161                  fname, errno ? strerror(errno) : "incomplete");
2162         return -1;
2163     }
2164 
2165     /* Re-write the 1st level 2 table */
2166     rcoff = lseek (fd, CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1tabsz, SEEK_SET);
2167     if (rcoff < 0)
2168     {
2169         fprintf (stderr, _("HHCDU065E %s l2tab lseek error: %s\n"),
2170                  fname, strerror(errno));
2171         return -1;
2172     }
2173     rc = write (fd, &l2, CCKD_L2TAB_SIZE);
2174     if (rc < (int)CCKD_L2TAB_SIZE)
2175     {
2176         fprintf (stderr, _("HHCDU066E %s l2tab rewrite error: %s\n"),
2177                  fname, errno ? strerror(errno) : "incomplete");
2178         return -1;
2179     }
2180 
2181     /* Close the DASD image file */
2182     rc = close (fd);
2183     if (rc < 0)
2184     {
2185         fprintf (stderr, _("HHCDU067E %s close error: %s\n"),
2186                 fname, strerror(errno));
2187         return -1;
2188     }
2189 
2190     /* Display completion message */
2191     fprintf (stderr,
2192             _("HHCDU068I %u sectors successfully written to file %s\n"),
2193             sectors, fname);
2194 
2195     return 0;
2196 } /* end function create_compressed_fba */
2197 
2198 
get_verbose_util(void)2199 int get_verbose_util(void)
2200 {
2201     return verbose;
2202 }
2203 
set_verbose_util(int v)2204 DLL_EXPORT void set_verbose_util(int v)
2205 {
2206     verbose = v;
2207 }
2208 
valid_dsname(const char * pszdsname)2209 DLL_EXPORT int valid_dsname( const char *pszdsname )
2210 {
2211     int i;
2212     int iLen = (int)strlen(pszdsname);
2213 
2214     if ( iLen > 44 || iLen == 0 ) return FALSE;
2215 
2216     for ( i = 0; i < iLen; i++ )
2217     {
2218         BYTE c = pszdsname[i];
2219         if ( isalnum( c ) )
2220             continue;
2221         else if ( c == '$' )
2222             continue;
2223         else if ( c == '@' )
2224             continue;
2225         else if ( c == '#' )
2226             continue;
2227         else if ( c == '-' )
2228             continue;
2229         else if ( c == '.' )
2230             continue;
2231         else if ( c == '{' )
2232             continue;
2233         else if ( i > 1 && c == '\0' )
2234             break;
2235         else
2236             return FALSE;
2237     }
2238     return TRUE;
2239 }
2240