1 /* DASDISUP.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* Hercules DASD Utilities: IEHIOSUP */
3
4 /*-------------------------------------------------------------------*/
5 /* This program performs the IEHIOSUP function of OS/360. */
6 /* It adjusts the TTRs in the XCTL tables in each of the */
7 /* Open/Close/EOV modules in SYS1.SVCLIB. */
8 /* */
9 /* The command format is: */
10 /* dasdisup ckdfile */
11 /* where: ckdfile is the name of the CKD image file */
12 /*-------------------------------------------------------------------*/
13
14 #include "hstdinc.h"
15
16 #include "hercules.h"
17 #include "dasdblks.h"
18
19 /*-------------------------------------------------------------------*/
20 /* Internal macro definitions */
21 /*-------------------------------------------------------------------*/
22 #define HEX00 ((BYTE)'\x00') /* EBCDIC low value */
23 #define HEX40 ((BYTE)'\x40') /* EBCDIC space */
24 #define HEXFF ((BYTE)'\xFF') /* EBCDIC high value */
25 #define OVERPUNCH_ZERO ((BYTE)'\xC0') /* EBCDIC 12-0 card punch */
26
27 /*-------------------------------------------------------------------*/
28 /* Definition of member information array entry */
29 /*-------------------------------------------------------------------*/
30 typedef struct _MEMINFO {
31 BYTE memname[8]; /* Member name (EBCDIC) */
32 BYTE ttrtext[3]; /* TTR of first text record */
33 BYTE dwdsize; /* Text size in doublewords */
34 BYTE alias; /* 1=This is an alias */
35 BYTE notable; /* 1=Member has no XCTL table*/
36 BYTE multitxt; /* 1=Member has >1 text rcd */
37 } MEMINFO;
38
39 #define MAX_MEMBERS 1000 /* Size of member info array */
40
41 /*-------------------------------------------------------------------*/
42 /* Static data areas */
43 /*-------------------------------------------------------------------*/
44
45 /* List of first loads for Open/Close/EOV routines */
46 static char *firstload[] = {
47 "IGC0001I", /* Open (SVC19) */
48 "IGC0002{", /* Close (SVC20) */
49 "IGC0002A", /* Stow (SVC21) */
50 "IGC0002B", /* OpenJ (SVC22) */
51 "IGC0002C", /* TClose (SVC23) */
52 "IGC0002I", /* Scratch (SVC29) */
53 "IGC0003A", /* FEOV (SVC31) */
54 "IGC0003B", /* Allocate (SVC32) */
55 "IGC0005E", /* EOV (SVC55) */
56 "IGC0008A", /* Setprt (SVC81) */
57 "IGC0008F", /* Atlas (SVC86) */
58 "IGC0009C", /* TSO (SVC93) */
59 "IGC0009D", /* TSO (SVC94) */
60 NULL }; /* End of list */
61
62 /* List of second loads for Open/Close/EOV routines */
63 static char *secondload[] = {
64 "IFG019", "IGG019", /* Open (SVC19) */
65 "IFG020", "IGG020", /* Close (SVC20) */
66 "IGG021", /* Stow (SVC21) */
67 "IFG023", "IGG023", /* TClose (SVC23) */
68 "IGG029", /* Scratch (SVC29) */
69 "IGG032", /* Allocate (SVC32) */
70 "IFG055", "IGG055", /* EOV (SVC55) */
71 "IGG081", /* Setprt (SVC81) */
72 "IGG086", /* Atlas (SVC86) */
73 "IGG093", /* TSO (SVC93) */
74 "IGG094", /* TSO (SVC94) */
75 NULL }; /* End of list */
76
77 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
78
79 #if 0
80 /*-------------------------------------------------------------------*/
81 /* Subroutine to process a member */
82 /* Input: */
83 /* cif -> CKD image file descriptor structure */
84 /* noext Number of extents in dataset */
85 /* extent Dataset extent array */
86 /* memname Member name (ASCIIZ) */
87 /* ttr Member TTR */
88 /* */
89 /* Return value is 0 if successful, or -1 if error */
90 /*-------------------------------------------------------------------*/
91 static int
92 process_member (CIFBLK *cif, int noext, DSXTENT extent[],
93 BYTE *memname, BYTE *ttr)
94 {
95 int rc; /* Return code */
96 int len; /* Record length */
97 int trk; /* Relative track number */
98 int cyl; /* Cylinder number */
99 int head; /* Head number */
100 int rec; /* Record number */
101 BYTE *buf; /* -> Data block */
102 FILE *ofp; /* Output file pointer */
103 BYTE ofname[256]; /* Output file name */
104 int offset; /* Offset of record in buffer*/
105 BYTE card[81]; /* Logical record (ASCIIZ) */
106 char pathname[MAX_PATH]; /* ofname in host path format*/
107
108 /* Build the output file name */
109 memset (ofname, 0, sizeof(ofname));
110 strncpy (ofname, memname, 8);
111 string_to_lower (ofname);
112 strcat (ofname, ".mac");
113
114 /* Open the output file */
115 hostpath(pathname, ofname, sizeof(pathname));
116 ofp = fopen (pathname, "w");
117 if (ofp == NULL)
118 {
119 fprintf (stderr,
120 "Cannot open %s: %s\n",
121 ofname, strerror(errno));
122 return -1;
123 }
124
125 /* Point to the start of the member */
126 trk = (ttr[0] << 8) | ttr[1];
127 rec = ttr[2];
128
129 fprintf (stdout,
130 "Member %s TTR=%4.4X%2.2X\n",
131 memname, trk, rec);
132
133 /* Read the member */
134 while (1)
135 {
136 /* Convert relative track to cylinder and head */
137 rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head);
138 if (rc < 0) return -1;
139
140 // fprintf (stdout,
141 // "CCHHR=%4.4X%4.4X%2.2X\n",
142 // cyl, head, rec);
143
144 /* Read a data block */
145 rc = read_block (cif, cyl, head, rec, NULL, NULL, &buf, &len);
146 if (rc < 0) return -1;
147
148 /* Move to next track if record not found */
149 if (rc > 0)
150 {
151 trk++;
152 rec = 1;
153 continue;
154 }
155
156 /* Exit at end of member */
157 if (len == 0) break;
158
159 /* Check length of data block */
160 if (len % 80 != 0)
161 {
162 fprintf (stdout,
163 "Bad block length %d at cyl %d head %d rec %d\n",
164 len, cyl, head, rec);
165 return -1;
166 }
167
168 /* Process each record in the data block */
169 for (offset = 0; offset < len; offset += 80)
170 {
171 if (asciiflag)
172 {
173 make_asciiz (card, sizeof(card), buf + offset, 72);
174 fprintf (ofp, "%s\n", card);
175 }
176 else
177 {
178 fwrite (buf+offset, 80, 1, ofp);
179 }
180
181 if (ferror(ofp))
182 {
183 fprintf (stdout,
184 "Error writing %s: %s\n",
185 ofname, strerror(errno));
186 return -1;
187 }
188 } /* end for(offset) */
189
190 /* Point to the next data block */
191 rec++;
192
193 } /* end while */
194
195 /* Close the output file and exit */
196 fclose (ofp);
197 return 0;
198
199 } /* end function process_member */
200 #endif
201
202 /*-------------------------------------------------------------------*/
203 /* Subroutine to process a directory block */
204 /* Input: */
205 /* cif -> CKD image file descriptor structure */
206 /* noext Number of extents in dataset */
207 /* extent Dataset extent array */
208 /* dirblk Pointer to directory block */
209 /* Input/output: */
210 /* memtab Member information array */
211 /* nmem Number of entries in member information array */
212 /* */
213 /* Directory information for each member is extracted from the */
214 /* directory block and saved in the member information array. */
215 /* */
216 /* Return value is 0 if OK, +1 if end of directory, or -1 if error */
217 /*-------------------------------------------------------------------*/
218 static int
process_dirblk(CIFBLK * cif,int noext,DSXTENT extent[],BYTE * dirblk,MEMINFO memtab[],int * nmem)219 process_dirblk (CIFBLK *cif, int noext, DSXTENT extent[],
220 BYTE *dirblk, MEMINFO memtab[], int *nmem)
221 {
222 int n; /* Member array subscript */
223 int i; /* Array subscript */
224 int totlen; /* Total module length */
225 int txtlen; /* Length of 1st text block */
226 int size; /* Size of directory entry */
227 int k; /* Userdata halfword count */
228 BYTE *dirptr; /* -> Next byte within block */
229 int dirrem; /* Number of bytes remaining */
230 PDSDIR *dirent; /* -> Directory entry */
231 char memnama[9]; /* Member name (ASCIIZ) */
232
233 UNREFERENCED(cif);
234 UNREFERENCED(noext);
235 UNREFERENCED(extent);
236
237 /* Load number of bytes in directory block */
238 dirptr = dirblk;
239 dirrem = (dirptr[0] << 8) | dirptr[1];
240 if (dirrem < 2 || dirrem > 256)
241 {
242 fprintf (stdout, _("HHCDS003E Directory block byte count is invalid\n"));
243 return -1;
244 }
245
246 /* Point to first directory entry */
247 dirptr += 2;
248 dirrem -= 2;
249
250 /* Process each directory entry */
251 for (n = *nmem; dirrem > 0; )
252 {
253 /* Point to next directory entry */
254 dirent = (PDSDIR*)dirptr;
255
256 /* Test for end of directory */
257 if (memcmp(dirent->pds2name, eighthexFF, 8) == 0)
258 return +1;
259
260 /* Load the user data halfword count */
261 k = dirent->pds2indc & PDS2INDC_LUSR;
262
263 /* Point to next directory entry */
264 size = 12 + k*2;
265 dirptr += size;
266 dirrem -= size;
267
268 /* Extract the member name */
269 make_asciiz (memnama, sizeof(memnama), dirent->pds2name, 8);
270 if (dirent->pds2name[7] == OVERPUNCH_ZERO)
271 memnama[7] = '{';
272
273 /* Find member in first load table */
274 for (i = 0; firstload[i] != NULL; i++)
275 if (strcmp(memnama, firstload[i]) == 0) break;
276
277 /* If not in first table, find in second table */
278 if (firstload[i] == NULL)
279 {
280 for (i = 0; secondload[i] != NULL; i++)
281 if (memcmp(memnama, secondload[i], 6) == 0) break;
282
283 /* If not in second table then skip member */
284 if (secondload[i] == NULL)
285 {
286 fprintf (stdout,
287 _("HHCDS018I %s %s skipped\n"),
288 memnama,
289 ((dirent->pds2indc & PDS2INDC_ALIAS) ?
290 "Alias" : "Member"));
291 continue;
292 }
293
294 } /* end if(firstload[i]==NULL) */
295
296 /* Check that member information array is not full */
297 if (n >= MAX_MEMBERS)
298 {
299 fprintf (stdout,
300 _("HHCDS004E Number of members exceeds MAX_MEMBERS\n"));
301 return -1;
302 }
303
304 /* Check that user data contains at least 1 TTR */
305 if (((dirent->pds2indc & PDS2INDC_NTTR) >> PDS2INDC_NTTR_SHIFT)
306 < 1)
307 {
308 fprintf (stdout,
309 _("HHCDS005E Member %s TTR count is zero\n"), memnama);
310 return -1;
311 }
312
313 /* Extract the total module length */
314 totlen = (dirent->pds2usrd[10] << 16)
315 | (dirent->pds2usrd[11] << 8)
316 | dirent->pds2usrd[12];
317
318 /* Extract the length of the first text block */
319 txtlen = (dirent->pds2usrd[13] << 8)
320 | dirent->pds2usrd[14];
321
322 /* Save member information in the array */
323 memcpy (memtab[n].memname, dirent->pds2name, 8);
324 memcpy (memtab[n].ttrtext, dirent->pds2usrd + 0, 3);
325 memtab[n].dwdsize = totlen / 8;
326
327 /* Flag the member if it is an alias */
328 memtab[n].alias = (dirent->pds2indc & PDS2INDC_ALIAS) ? 1 : 0;
329
330 /* Flag member if 7th character of name is non-numeric */
331 memtab[n].notable = (memnama[6] < '0' || memnama[6] > '9') ?
332 1 : 0;
333
334 /* Check that the member has a single text record */
335 if ((dirent->pds2usrd[8] & 0x01) == 0 || totlen != txtlen)
336 {
337 fprintf (stdout,
338 _("HHCDS006W Member %s is not single text record\n"),
339 memnama);
340 memtab[n].multitxt = 1;
341 } else {
342 memtab[n].multitxt = 0;
343 }
344
345 /* Check that the total module length does not exceed X'7F8' */
346 if (totlen > 255*8)
347 {
348 fprintf (stdout,
349 _("HHCDS007W Member %s size %4.4X "
350 "exceeds X\'7F8\' bytes\n"),
351 memnama, totlen);
352 }
353
354 /* Check that the total module length is a multiple of 8 */
355 if (totlen & 0x7)
356 {
357 fprintf (stdout,
358 _("HHCDS008W Member %s size %4.4X "
359 "is not a multiple of 8\n"),
360 memnama, totlen);
361 }
362
363 /* Increment number of entries in table */
364 *nmem = ++n;
365
366 } /* end for */
367
368 return 0;
369
370 } /* end function process_dirblk */
371
372 /*-------------------------------------------------------------------*/
373 /* Subroutine to resolve TTRs embedded within a member */
374 /* Input: */
375 /* cif -> CKD image file descriptor structure */
376 /* noext Number of extents in dataset */
377 /* extent Dataset extent array */
378 /* memp Array entry for member whose TTRs are to be resolved */
379 /* memtab Member information array */
380 /* nmem Number of entries in member information array */
381 /* */
382 /* Return value is 0 if OK, -1 if error */
383 /*-------------------------------------------------------------------*/
384 static int
resolve_xctltab(CIFBLK * cif,int noext,DSXTENT extent[],MEMINFO * memp,MEMINFO memtab[],int nmem)385 resolve_xctltab (CIFBLK *cif, int noext, DSXTENT extent[],
386 MEMINFO *memp, MEMINFO memtab[], int nmem)
387 {
388 int rc; /* Return code */
389 int i; /* Array subscript */
390 int len; /* Record length */
391 int cyl; /* Cylinder number */
392 int head; /* Head number */
393 int rec; /* Record number */
394 int trk; /* Relative track number */
395 int xctloff; /* Offset to XCTL table */
396 int warn; /* 1=Flag TTRL difference */
397 BYTE *blkptr; /* -> Text record data */
398 char memnama[9]; /* Member name (ASCIIZ) */
399 BYTE svcnum[3]; /* SVC number (EBCDIC) */
400 BYTE prefix[3]; /* IGG/IFG prefix (EBCDIC) */
401 BYTE refname[8]; /* Referred name (EBCDIC) */
402 char refnama[9]; /* Referred name (ASCIIZ) */
403
404 /* Extract the member name */
405 make_asciiz (memnama, sizeof(memnama), memp->memname, 8);
406 if (memp->memname[7] == OVERPUNCH_ZERO)
407 memnama[7] = '{';
408
409 /* Skip the member if it is an alias */
410 if (memp->alias)
411 {
412 fprintf (stdout, _("HHCDS009I Alias %s skipped\n"), memnama);
413 return 0;
414 }
415
416 /* Skip the member if it has no XCTL table */
417 if (memp->notable)
418 {
419 fprintf (stdout, _("HHCDS010I Member %s skipped\n"), memnama);
420 return 0;
421 }
422
423 /* Error if member is not a single text record */
424 if (memp->multitxt)
425 {
426 fprintf (stdout,
427 _("HHCDS011E Member %s has multiple text records\n"),
428 memnama);
429 return -1;
430 }
431
432 /* Convert relative track to cylinder and head */
433 trk = (memp->ttrtext[0] << 8) | memp->ttrtext[1];
434 rec = memp->ttrtext[2];
435 rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head);
436 if (rc < 0)
437 {
438 fprintf (stdout,
439 _("HHCDS012E Member %s has invalid TTR %4.4X%2.2X\n"),
440 memnama, trk, rec);
441 return -1;
442 }
443
444 fprintf (stdout,
445 _("HHCDS013I Processing member %s text record TTR=%4.4X%2.2X "
446 "CCHHR=%4.4X%4.4X%2.2X\n"),
447 memnama, trk, rec, cyl, head, rec);
448
449 /* Read the text record */
450 rc = read_block (cif, cyl, head, rec,
451 NULL, NULL, &blkptr, &len);
452 if (rc != 0)
453 {
454 fprintf (stdout,
455 _("HHCDS014E Member %s error reading TTR %4.4X%2.2X\n"),
456 memnama, trk, rec);
457 return -1;
458 }
459
460 /* Check for incorrect length record */
461 if (len < 8 || len > 1024 || (len & 0x7))
462 {
463 fprintf (stdout,
464 _("HHCDS015E Member %s TTR %4.4X%2.2X "
465 "text record length %4.4X is not valid\n"),
466 memnama, trk, rec, len);
467 return -1;
468 }
469
470 /* Check that text record length matches directory entry */
471 if (len != memp->dwdsize * 8)
472 {
473 fprintf (stdout,
474 _("HHCDS016E Member %s TTR %4.4X%2.2X "
475 "text record length %4.4X does not match "
476 "length %4.4X in directory\n"),
477 memnama, trk, rec, len, memp->dwdsize * 8);
478 return -1;
479 }
480
481 /* Extract the SVC number and the XCTL table offset
482 from the last 4 bytes of the text record */
483 memcpy (svcnum, blkptr + len - 4, sizeof(svcnum));
484 xctloff = blkptr[len-1] * 8;
485
486 /* For the first load of SVC 19, 20, 23, and 55, and for
487 IFG modules, the table is in two parts. The parts are
488 separated by a X'FFFF' delimiter. The first part refers
489 to IFG modules, the second part refers to IGG modules */
490 if ((memcmp(memnama, "IGC", 3) == 0
491 && (memcmp(svcnum, "\xF0\xF1\xF9", 3) == 0
492 || memcmp(svcnum, "\xF0\xF2\xF0", 3) == 0
493 || memcmp(svcnum, "\xF0\xF2\xF3", 3) == 0
494 || memcmp(svcnum, "\xF0\xF5\xF5", 3) == 0))
495 || memcmp(memnama, "IFG", 3) == 0)
496 convert_to_ebcdic (prefix, sizeof(prefix), "IFG");
497 else
498 convert_to_ebcdic (prefix, sizeof(prefix), "IGG");
499
500 /* Process each entry in the XCTL table */
501 while (1)
502 {
503 /* Exit at end of XCTL table */
504 if (blkptr[xctloff] == HEX00 && blkptr[xctloff+1] == HEX00)
505 break;
506
507 /* Switch prefix at end of first part of table */
508 if (blkptr[xctloff] == HEXFF && blkptr[xctloff+1] == HEXFF)
509 {
510 xctloff += 2;
511 convert_to_ebcdic (prefix, sizeof(prefix), "IGG");
512 continue;
513 }
514
515 /* Error if XCTL table overflows text record */
516 if (xctloff >= len - 10)
517 {
518 fprintf (stdout,
519 _("HHCDS017E Member %s TTR %4.4X%2.2X "
520 "XCTL table improperly terminated\n"),
521 memnama, trk, rec);
522 return -1;
523 }
524
525 /* Skip this entry if the suffix is blank */
526 if (blkptr[xctloff] == HEX40
527 && blkptr[xctloff+1] == HEX40)
528 {
529 xctloff += 6;
530 continue;
531 }
532
533 /* Build the name of the member referred to */
534 memcpy (refname, prefix, 3);
535 memcpy (refname + 3, svcnum, 3);
536 memcpy (refname + 6, blkptr+xctloff, 2);
537 make_asciiz (refnama, sizeof(refnama), refname, 8);
538
539 /* Display XCTL table entry */
540 fprintf (stdout,
541 _("HHCDS019I In member %s: %s TTRL=%2.2X%2.2X%2.2X%2.2X"),
542 memnama, refnama,
543 blkptr[xctloff+2], blkptr[xctloff+3],
544 blkptr[xctloff+4], blkptr[xctloff+5]);
545
546 /* Find the referred member in the member array */
547 for (i = 0; i < nmem; i++)
548 {
549 if (memcmp(memtab[i].memname, refname, 8) == 0)
550 break;
551 } /* end for(i) */
552
553 /* Loop if member not found */
554 if (i == nmem)
555 {
556 fprintf (stdout, " ** Member %s not found **\n", refnama);
557 xctloff += 6;
558 continue;
559 }
560
561 /* Loop if TTRL in the XCTL table matches actual TTRL */
562 if (memcmp(blkptr+xctloff+2, memtab[i].ttrtext, 3) == 0
563 && blkptr[xctloff+5] == memtab[i].dwdsize)
564 {
565 fprintf (stdout, "\n");
566 xctloff += 6;
567 continue;
568 }
569
570 /* Flag entries whose L differs */
571 if (blkptr[xctloff+5] != memtab[i].dwdsize)
572 warn = 1;
573 else
574 warn = 0;
575
576 /* Replace TTRL in the XCTL table by the actual TTRL */
577 memcpy (blkptr+xctloff+2, memtab[i].ttrtext, 3);
578 blkptr[xctloff+5] = memtab[i].dwdsize;
579
580 fprintf (stdout,
581 " replaced by TTRL=%2.2X%2.2X%2.2X%2.2X %s\n",
582 blkptr[xctloff+2], blkptr[xctloff+3],
583 blkptr[xctloff+4], blkptr[xctloff+5],
584 (warn ? "****" : ""));
585
586 /* Flag the track as modified to force rewrite */
587 cif->trkmodif = 1;
588
589 /* Point to next entry in XCTL table */
590 xctloff += 6;
591
592 } /* end while */
593
594 return 0;
595 } /* end function resolve_xctltab */
596
597 /*-------------------------------------------------------------------*/
598 /* DASDISUP main entry point */
599 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])600 int main (int argc, char *argv[])
601 {
602 int rc; /* Return code */
603 int i; /* Array subscript */
604 int len; /* Record length */
605 int cyl; /* Cylinder number */
606 int head; /* Head number */
607 int rec; /* Record number */
608 int trk; /* Relative track number */
609 char *fname; /* -> CKD image file name */
610 char *sfname; /* -> CKD shadow file name */
611 int noext; /* Number of extents */
612 DSXTENT extent[16]; /* Extent descriptor array */
613 BYTE *blkptr; /* -> PDS directory block */
614 CIFBLK *cif; /* CKD image file descriptor */
615 MEMINFO *memtab; /* -> Member info array */
616 int nmem = 0; /* Number of array entries */
617
618 INITIALIZE_UTILITY("dasdisup");
619
620 /* Display the program identification message */
621 display_version (stderr,
622 "Hercules IEHIOSUP program ", FALSE);
623
624 /* Check the number of arguments */
625 if (argc < 2 || argc > 3)
626 {
627 fprintf (stdout,
628 "Usage: %s ckdfile [sf=shadow-file-name]\n",
629 argv[0]);
630 return -1;
631 }
632
633 /* The first argument is the name of the CKD image file */
634 fname = argv[1];
635
636 /* The next argument, if there, is the name of the shadow file */
637 if (argc > 2) sfname = argv[2];
638 else sfname = NULL;
639
640 /* Obtain storage for the member information array */
641 memtab = (MEMINFO*) malloc (sizeof(MEMINFO) * MAX_MEMBERS);
642 if (memtab == NULL)
643 {
644 fprintf (stdout,
645 _("HHCDS001E Cannot obtain storage for member array: %s\n"),
646 strerror(errno));
647 return -1;
648 }
649
650 /* Open the CKD image file */
651 cif = open_ckd_image (fname, sfname, O_RDWR|O_BINARY, 0);
652 if (cif == NULL) return -1;
653
654 /* Build the extent array for the SVCLIB dataset */
655 rc = build_extent_array (cif, "SYS1.SVCLIB", extent, &noext);
656 if (rc < 0) return -1;
657
658 /* Point to the start of the directory */
659 trk = 0;
660 rec = 1;
661
662 /* Read the directory */
663 while (1)
664 {
665 /* Convert relative track to cylinder and head */
666 rc = convert_tt (trk, noext, extent, cif->heads, &cyl, &head);
667 if (rc < 0) return -1;
668
669 /* Read a directory block */
670 rc = read_block (cif, cyl, head, rec,
671 NULL, NULL, &blkptr, &len);
672 if (rc < 0) return -1;
673
674 /* Move to next track if block not found */
675 if (rc > 0)
676 {
677 trk++;
678 rec = 1;
679 continue;
680 }
681
682 /* Exit at end of directory */
683 if (len == 0) break;
684
685 /* Extract information for each member in directory block */
686 rc = process_dirblk (cif, noext, extent, blkptr,
687 memtab, &nmem);
688 if (rc < 0) return -1;
689 if (rc > 0) break;
690
691 /* Point to the next directory block */
692 rec++;
693
694 } /* end while */
695
696 fprintf (stdout,
697 _("HHCDS002I End of directory: %d members selected\n"),
698 nmem);
699
700 #ifdef EXTERNALGUI
701 if (extgui) fprintf (stderr,"NMEM=%d\n",nmem);
702 #endif /*EXTERNALGUI*/
703
704 /* Read each member and resolve the embedded TTRs */
705 for (i = 0; i < nmem; i++)
706 {
707 #ifdef EXTERNALGUI
708 if (extgui) fprintf (stderr,"MEM=%d\n",i);
709 #endif /*EXTERNALGUI*/
710 rc = resolve_xctltab (cif, noext, extent, memtab+i,
711 memtab, nmem);
712
713 } /* end for(i) */
714
715 /* Close the CKD image file and exit */
716 rc = close_ckd_image (cif);
717 free (memtab);
718 return rc;
719
720 } /* end function main */
721