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