-
Notifications
You must be signed in to change notification settings - Fork 41
/
dasdload.c
5159 lines (4541 loc) · 204 KB
/
dasdload.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* DASDLOAD.C (c) Copyright Roger Bowler, 1999-2014 */
/* Hercules DASD Utilities: DASD image loader */
/*-------------------------------------------------------------------*/
/* This program creates a virtual DASD volume from a list of */
/* datasets previously unloaded using the TSO XMIT command. */
/*-------------------------------------------------------------------*/
/*-------------------------------------------------------------------*/
/* Additional credits: */
/* Corrections to CVOL initialization logic by Jay Maynard */
/* IEBCOPY native dataset support by Ronen Tzur */
/*-------------------------------------------------------------------*/
#include "hstdinc.h"
#include "hercules.h"
#include "dasdblks.h"
/*-------------------------------------------------------------------*/
/* Internal table sizes */
/*-------------------------------------------------------------------*/
#define MAXDBLK 10000 /* Maximum number of directory
blocks per dataset */
#define MAXTTR 50000 /* Maximum number of TTRs
per dataset */
#define MAXDSCB 1000 /* Maximum number of DSCBs */
/*-------------------------------------------------------------------*/
/* Internal macro definitions */
/*-------------------------------------------------------------------*/
#define CASERET(s) case s: return (#s)
#define XMINF info_msg
#define XMINFF info_msg
#define XMERR printf
#define XMERRF printf
#define R0_DATALEN 8
#define IPL1_KEYLEN 4
#define IPL1_DATALEN 24
#define IPL2_KEYLEN 4
#define IPL2_DATALEN 144
#define VOL1_KEYLEN 4
#define VOL1_DATALEN 80
#define EBCDIC_END "\xC5\xD5\xC4"
#define EBCDIC_TXT "\xE3\xE7\xE3"
/*-------------------------------------------------------------------*/
/* Definition of LOGREC header record */
/*-------------------------------------------------------------------*/
typedef struct _DIPHDR {
HWORD recid; /* Record identifier (0xFFFF)*/
HWORD bcyl; /* Extent begin cylinder */
HWORD btrk; /* Extent begin track */
HWORD ecyl; /* Extent end cylinder */
HWORD etrk; /* Extent end track */
BYTE resv; /* Unused */
BYTE restart[7]; /* Restart area BBCCHHR */
HWORD trkbal; /* Bytes remaining on track */
HWORD trklen; /* Total bytes on track */
BYTE reused[7]; /* Last reused BBCCHHR */
HWORD lasthead; /* Last track on cylinder */
HWORD trklen90; /* 90% of track length */
BYTE devcode; /* Device type code */
BYTE cchh90[4]; /* 90% full track CCHH */
BYTE switches; /* Switches */
BYTE endid; /* Check byte (0xFF) */
} DIPHDR;
/*-------------------------------------------------------------------*/
/* Definition of internal extent descriptor array entry */
/*-------------------------------------------------------------------*/
typedef struct _EXTDESC {
U16 bcyl; /* Begin cylinder */
U16 btrk; /* Begin track */
U16 ecyl; /* End cylinder */
U16 etrk; /* End track */
U16 ntrk; /* Number of tracks */
} EXTDESC;
/*-------------------------------------------------------------------*/
/* Definition of internal TTR conversion table array entry */
/*-------------------------------------------------------------------*/
typedef struct _TTRCONV {
BYTE origttr[3]; /* TTR in original dataset */
BYTE outpttr[3]; /* TTR in output dataset */
} TTRCONV;
/*-------------------------------------------------------------------*/
/* Definitions for dataset initialization methods */
/*-------------------------------------------------------------------*/
#define METHOD_EMPTY 0
#define METHOD_XMIT 1
#define METHOD_DIP 2
#define METHOD_CVOL 3
#define METHOD_VTOC 4
#define METHOD_VS 5
#define METHOD_SEQ 6
#define METHOD_XMSEQ 7
#define METHOD_TEXT 8
/*-------------------------------------------------------------------*/
/* Static data areas */
/*-------------------------------------------------------------------*/
static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
BYTE twelvehex00[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
BYTE cvol_low_key[] = {0, 0, 0, 0, 0, 0, 0, 1};
BYTE iplpsw[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
BYTE iplccw1[8] = {0x06, 0x00, 0x3A, 0x98, 0x60, 0x00, 0x00, 0x60};
BYTE iplccw2[8] = {0x08, 0x00, 0x3A, 0x98, 0x00, 0x00, 0x00, 0x00};
BYTE ipl2data[] = {0x07, 0x00, 0x3A, 0xB8, 0x40, 0x00, 0x00, 0x06,
0x31, 0x00, 0x3A, 0xBE, 0x40, 0x00, 0x00, 0x05,
0x08, 0x00, 0x3A, 0xA0, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x7f, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*BBCCHH*/
0x00, 0x00, 0x00, 0x00, 0x04}; /*CCHHR*/
BYTE noiplpsw[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F};
BYTE noiplccw1[8] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
BYTE noiplccw2[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/* Information message level: 0=None, 1=File name, 2=File information,
3=Member information, 4=Text units, record headers, 5=Dump data */
int infolvl = 1;
/*-------------------------------------------------------------------*/
/* Subroutine to display command syntax and exit */
/*-------------------------------------------------------------------*/
static void
argexit ( int code )
{
fprintf (stderr,
"dasdload creates a DASD image file from a list "
"of TSO XMIT files\n"
"Syntax:\tdasdload [options] ctlfile outfile [msglevel]\n"
"where:\tctlfile = name of input control file\n"
"\toutfile = name of DASD image file to be created\n"
"\tmsglevel = Value 0-5 controls output verbosity\n"
"\noptions:\n"
"\t-0: no compression (default)\n"
"\t-a: output disk will include alternate cylinders\n"
#ifdef CCKD_COMPRESS_ZLIB
"\t-z: compress using zlib\n"
#endif
#ifdef CCKD_COMPRESS_BZIP2
"\t-bz2: compress using bzip2\n"
#endif
);
if (sizeof(off_t) > 4)
fprintf (stderr,
"\t-lfs: create single large output file\n"
);
exit(code);
} /* end function argexit */
/*-------------------------------------------------------------------*/
/* Subroutine to display an informational message */
/*-------------------------------------------------------------------*/
static void
info_msg (int lvl, char *msg, ...)
{
va_list vl;
if (infolvl >= lvl)
{
va_start(vl, msg);
vprintf (msg, vl);
}
} /* end function info_msg */
/*-------------------------------------------------------------------*/
/* Subroutine to load a S/390 integer value from a buffer */
/*-------------------------------------------------------------------*/
static int
make_int (BYTE *src, int srclen)
{
int result = 0; /* Result accumulator */
int i; /* Array subscript */
for (i=0; i < srclen; i++)
{
result <<= 8;
result |= src[i];
}
return result;
} /* end function make_int */
/*-------------------------------------------------------------------*/
/* Subroutine to return the name of a dataset organization */
/*-------------------------------------------------------------------*/
static char *
dsorg_name (BYTE *dsorg)
{
static char name[8]; /* Name of dsorg */
if (dsorg[0] & DSORG_IS)
strcpy (name, "IS");
else if (dsorg[0] & DSORG_PS)
strcpy (name, "PS");
else if (dsorg[0] & DSORG_DA)
strcpy (name, "DA");
else if (dsorg[0] & DSORG_PO)
strcpy (name, "PO");
if (dsorg[0] & DSORG_U) strcat (name, "U");
return name;
} /* end function dsorg_name */
/*-------------------------------------------------------------------*/
/* Subroutine to return the name of a record format */
/*-------------------------------------------------------------------*/
static char *
recfm_name (BYTE *recfm)
{
static char name[8]; /* Name of record format */
switch (recfm[0] & RECFM_FORMAT) {
case RECFM_FORMAT_V:
strcpy (name, "V"); break;
case RECFM_FORMAT_F:
strcpy (name, "F"); break;
case RECFM_FORMAT_U:
strcpy (name, "U"); break;
default:
strcpy (name,"??");
} /* end switch */
if (recfm[0] & RECFM_TRKOFLOW) strcat (name, "T");
if (recfm[0] & RECFM_BLOCKED) strcat (name, "B");
if (recfm[0] & RECFM_SPANNED) strcat (name, "S");
switch (recfm[0] & RECFM_CTLCHAR) {
case RECFM_CTLCHAR_A:
strcpy (name, "A"); break;
case RECFM_CTLCHAR_M:
strcpy (name, "M"); break;
} /* end switch */
return name;
} /* end function recfm_name */
/*-------------------------------------------------------------------*/
/* Subroutine to return the name of a DASD device from the UCB type */
/*-------------------------------------------------------------------*/
static char *
dasd_name (FWORD ucbtype)
{
if (ucbtype[2] != 0x20) return "????";
switch (ucbtype[3]) {
case 0x01: return "2311";
case 0x02: return "2301";
case 0x03: return "2303";
case 0x04: if (ucbtype[1] == 0x00) return "2302";
else return "9345";
case 0x05: return "2321";
case 0x06: return "2305-1";
case 0x07: return "2305-2";
case 0x08: return "2314";
case 0x09: return "3330";
case 0x0A: return "3340";
case 0x0B: return "3350";
case 0x0C: return "3375";
case 0x0D: return "3330-11";
case 0x0E: return "3380";
case 0x0F: return "3390";
} /* end switch(key) */
return "????";
} /* end function dasd_name */
/*-------------------------------------------------------------------*/
/* Subroutine to return the UCBTYPE of a DASD device */
/*-------------------------------------------------------------------*/
static U32
ucbtype_code (U16 devtype)
{
switch (devtype) {
case 0x2311: return 0x30002001;
case 0x2301: return 0x30402002;
case 0x2303: return 0x30002003;
case 0x2302: return 0x30002004;
case 0x2321: return 0x30002005;
case 0x2305: return 0x30002006;
case 0x2314: return 0x30C02008;
case 0x3330: return 0x30502009;
case 0x3340: return 0x3050200A;
case 0x3350: return 0x3050200B;
case 0x3375: return 0x3050200C;
case 0x3380: return 0x3050200E;
case 0x3390: return 0x3050200F;
case 0x9345: return 0x30502004;
} /* end switch(key) */
return 0;
} /* end function ucbtype_code */
/*-------------------------------------------------------------------*/
/* Subroutine to calculate relative track address */
/* Input: */
/* cyl Cylinder number */
/* head Head number */
/* heads Number of heads per cylinder */
/* numext Number of extents */
/* xarray Array containing 1-16 extent descriptions */
/* Output: */
/* The return value is the relative track number, */
/* or -1 if an error occurred. */
/*-------------------------------------------------------------------*/
static int
calculate_ttr (int cyl, int head, int heads, int numext,
EXTDESC xarray[])
{
int i; /* Array subscript */
int track; /* Relative track number */
/* Search the extent descriptor array */
for (i = 0, track = 0; i < numext; track += xarray[i++].ntrk)
{
if (cyl < xarray[i].bcyl || cyl > xarray[i].ecyl)
continue;
if (cyl == xarray[i].bcyl && head < xarray[i].btrk)
continue;
if (cyl == xarray[i].ecyl && head > xarray[i].etrk)
continue;
track += (cyl - xarray[i].bcyl) * heads
- xarray[i].btrk + head;
break;
} /* end for(i) */
/* Error if track was not found in extent table */
if (i == numext)
{
XMERRF ("HHCDL033E CCHH=%4.4X%4.4X not found in extent table\n",
cyl, head);
return -1;
}
/* Return relative track number */
return track;
} /* end function calculate_ttr */
/*-------------------------------------------------------------------*/
/* Subroutine to read IPL text from an EBCDIC object file */
/* Input: */
/* iplfnm Name of EBCDIC card image object file */
/* iplbuf Address of buffer in which to build IPL text record */
/* buflen Length of buffer */
/* Output: */
/* The return value is the length of the IPL text built */
/* in the buffer if successful, or -1 if error */
/* Note: */
/* Only TXT records are processed; ESD and RLD records are */
/* ignored because the IPL text is non-relocatable and is */
/* assumed to have zero origin. An END card must be present. */
/*-------------------------------------------------------------------*/
static int
read_ipl_text (char *iplfnm, BYTE *iplbuf, int buflen)
{
int rc; /* Return code */
int ipllen = 0; /* Length of IPL text */
int txtlen; /* Byte count from TXT card */
int txtadr; /* Address from TXT card */
int tfd; /* Object file descriptor */
BYTE objrec[80]; /* Object card image */
char pathname[MAX_PATH]; /* iplfnm in host path format*/
/* Open the object file */
hostpath(pathname, iplfnm, sizeof(pathname));
tfd = hopen(pathname, O_RDONLY|O_BINARY);
if (tfd < 0)
{
XMERRF ("HHCDL034E Cannot open %s: %s\n",
iplfnm, strerror(errno));
return -1;
}
/* Read the object file */
while (1)
{
/* Read a card image from the object file */
rc = read (tfd, objrec, 80);
if (rc < 80)
{
XMERRF ("HHCDL035E Cannot read %s: %s\n",
iplfnm, strerror(errno));
close (tfd);
return -1;
}
/* Column 1 of each object card must contain X'02' */
if (objrec[0] != 0x02)
{
XMERRF ("HHCDL036E %s is not a valid object file\n",
iplfnm);
close (tfd);
return -1;
}
/* Exit if END card has been read */
if (memcmp(objrec+1, EBCDIC_END, 3) == 0)
break;
/* Ignore any cards which are not TXT cards */
if (memcmp(objrec+1, EBCDIC_TXT, 3) != 0)
continue;
/* Load the address from TXT card columns 6-8 */
txtadr = (objrec[5] << 16) | (objrec[6] << 8) | objrec[7];
/* Load the byte count from TXT card columns 11-12 */
txtlen = (objrec[10] << 8) | objrec[11];
XMINFF (5, "HHCDL037I IPL text address=%6.6X length=%4.4X\n",
txtadr, txtlen);
/* Check that the byte count is valid */
if (txtlen > 56)
{
XMERRF ("HHCDL038E TXT record in %s has invalid count %d\n",
iplfnm, txtlen);
close (tfd);
return -1;
}
/* Check that the text falls within the buffer */
if (txtadr + txtlen > buflen)
{
XMERRF ("HHCDL039E IPL text in %s exceeds %d bytes\n",
iplfnm, buflen);
close (tfd);
return -1;
}
/* Copy the IPL text to the buffer */
memcpy (iplbuf + txtadr, objrec+16, txtlen);
/* Update the total size of the IPL text */
if (txtadr + txtlen > ipllen)
ipllen = txtadr + txtlen;
} /* end while */
return ipllen;
} /* end function read_ipl_text */
/*-------------------------------------------------------------------*/
/* Subroutine to initialize the output track buffer */
/* Input: */
/* trklen Track length of virtual output device */
/* trkbuf Pointer to track buffer */
/* cyl Cylinder number on output device */
/* head Head number on output device */
/* Output: */
/* usedv Number of bytes written to track of virtual device */
/*-------------------------------------------------------------------*/
static void
init_track (int trklen, BYTE *trkbuf, int cyl, int head, int *usedv)
{
CKDDASD_TRKHDR *trkhdr; /* -> Track header */
CKDDASD_RECHDR *rechdr; /* -> Record header */
/* Clear the track buffer to zeroes */
memset (trkbuf, 0, trklen);
/* Build the home address in the track buffer */
trkhdr = (CKDDASD_TRKHDR*)trkbuf;
trkhdr->bin = 0;
trkhdr->cyl[0] = (cyl >> 8) & 0xFF;
trkhdr->cyl[1] = cyl & 0xFF;
trkhdr->head[0] = (head >> 8) & 0xFF;
trkhdr->head[1] = head & 0xFF;
/* Build a standard record zero in the track buffer */
rechdr = (CKDDASD_RECHDR*)(trkbuf + CKDDASD_TRKHDR_SIZE);
rechdr->cyl[0] = (cyl >> 8) & 0xFF;
rechdr->cyl[1] = cyl & 0xFF;
rechdr->head[0] = (head >> 8) & 0xFF;
rechdr->head[1] = head & 0xFF;
rechdr->rec = 0;
rechdr->klen = 0;
rechdr->dlen[0] = (R0_DATALEN >> 8) & 0xFF;
rechdr->dlen[1] = R0_DATALEN & 0xFF;
/* Set number of bytes used in track buffer */
*usedv = CKDDASD_TRKHDR_SIZE + CKDDASD_RECHDR_SIZE + R0_DATALEN;
/* Build end of track marker at end of buffer */
memcpy (trkbuf + *usedv, eighthexFF, 8);
} /* end function init_track */
/*-------------------------------------------------------------------*/
/* Subroutine to write track buffer to output file */
/* Input: */
/* cif -> CKD image file descriptor */
/* ofname Output file name */
/* heads Number of tracks per cylinder on output device */
/* trklen Track length of virtual output device */
/* Input/output: */
/* usedv Number of bytes written to track of virtual device */
/* reltrk Relative track number on output device */
/* cyl Cylinder number on output device */
/* head Head number on output device */
/* Output: */
/* The return value is 0 if successful, -1 if error occurred. */
/*-------------------------------------------------------------------*/
static int
write_track (CIFBLK *cif, char *ofname, int heads, int trklen,
int *usedv, int *reltrk, int *cyl, int *head)
{
int rc; /* Return code */
UNREFERENCED(ofname);
UNREFERENCED(trklen);
/* Don't overwrite HA */
if (*usedv == 0)
*usedv = CKDDASD_TRKHDR_SIZE;
/* Build end of track marker at end of buffer */
memcpy (cif->trkbuf + *usedv, eighthexFF, 8);
cif->trkmodif = 1;
/* Reset values for next track */
(*reltrk)++;
(*head)++;
if (*head >= heads)
{
(*cyl)++;
*head = 0;
}
*usedv = 0;
/* Read the next track */
if (*cyl < (int)cif->devblk.ckdcyls)
{
rc = read_track (cif, *cyl, *head);
if (rc < 0) return -1;
}
return 0;
} /* end function write_track */
/*-------------------------------------------------------------------*/
/* Subroutine to add a data block to the output track buffer */
/* Input: */
/* cif -> CKD image file descriptor */
/* ofname Output file name */
/* blk Pointer to data block */
/* keylen Key length */
/* datalen Data length */
/* devtype Output device type */
/* heads Number of tracks per cylinder on output device */
/* trklen Track length of virtual output device */
/* maxtrk Maximum number of tracks to be written */
/* Input/output: */
/* usedv Number of bytes written to track of virtual device */
/* usedr Number of bytes written to track, calculated */
/* according to the formula for a real device */
/* trkbal Number of bytes remaining on track, calculated */
/* according to the formula for a real device */
/* reltrk Relative track number on output device */
/* cyl Cylinder number on output device */
/* head Head number on output device */
/* rec Record number on output device */
/* Output: */
/* The return value is 0 if successful, -1 if error occurred. */
/*-------------------------------------------------------------------*/
static int
write_block (CIFBLK *cif, char *ofname, DATABLK *blk, int keylen,
int datalen, U16 devtype, int heads, int trklen,
int maxtrk, int *usedv, int *usedr,
int *trkbal, int *reltrk, int *cyl, int *head, int *rec)
{
int rc; /* Return code */
int cc; /* Capacity calculation code */
CKDDASD_RECHDR *rechdr; /* -> Record header */
UNREFERENCED(devtype);
/* Determine whether record will fit on current track */
cc = capacity_calc (cif, *usedr, keylen, datalen,
usedr, trkbal, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
if (cc < 0) return -1;
/* Move to next track if record will not fit */
if (cc > 0 && *usedr > 0)
{
/* Write current track to output file */
rc = write_track (cif, ofname, heads, trklen,
usedv, reltrk, cyl, head);
if (rc < 0) return -1;
/* Clear bytes used and record number for new track */
*usedr = 0;
*rec = 0;
/* Determine whether record will fit on new track */
cc = capacity_calc (cif, *usedr, keylen, datalen,
usedr, trkbal, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
if (cc < 0) return -1;
} /* end if */
/* Error if record will not even fit on an empty track */
if (cc > 0)
{
XMERRF ("HHCDL040E Input record CCHHR=%2.2X%2.2X%2.2X%2.2X%2.2X "
"exceeds output device track size\n",
blk->cyl[0], blk->cyl[1],
blk->head[0], blk->head[1], blk->rec);
return -1;
}
/* Determine whether end of extent has been reached */
if (*reltrk >= maxtrk)
{
XMERRF ("HHCDL041E Dataset exceeds extent size: reltrk=%d, "
"maxtrk=%d\n",
*reltrk, maxtrk);
return -1;
}
/* Build home address and record 0 if new track */
if (*usedv == 0)
{
init_track (trklen, cif->trkbuf, *cyl, *head, usedv);
}
/* Double check that record will not exceed virtual track size */
if (*usedv + CKDDASD_RECHDR_SIZE + keylen + datalen + 8
> trklen)
{
XMERRF ("HHCDL042E Input record CCHHR=%2.2X%2.2X%2.2X%2.2X%2.2X "
"exceeds virtual device track size\n",
blk->cyl[0], blk->cyl[1],
blk->head[0], blk->head[1], blk->rec);
return -1;
}
/* Add data block to virtual track buffer */
(*rec)++;
rechdr = (CKDDASD_RECHDR*)(cif->trkbuf + *usedv);
rechdr->cyl[0] = (*cyl >> 8) & 0xFF;
rechdr->cyl[1] = *cyl & 0xFF;
rechdr->head[0] = (*head >> 8) & 0xFF;
rechdr->head[1] = *head & 0xFF;
rechdr->rec = *rec;
rechdr->klen = keylen;
rechdr->dlen[0] = (datalen >> 8) & 0xFF;
rechdr->dlen[1] = datalen & 0xFF;
*usedv += CKDDASD_RECHDR_SIZE;
memcpy (cif->trkbuf + *usedv, blk->kdarea, keylen + datalen);
*usedv += keylen + datalen;
cif->trkmodif = 1;
return 0;
} /* end function write_block */
/*-------------------------------------------------------------------*/
/* Subroutine to write track zero */
/* Input: */
/* cif -> CKD image file descriptor */
/* ofname Output file name */
/* volser Volume serial number (ASCIIZ) */
/* devtype Output device type */
/* heads Number of tracks per cylinder on output device */
/* trklen Track length of virtual output device */
/* iplfnm Name of file containing IPL text object deck */
/* Output: */
/* reltrk Next relative track number on output device */
/* outcyl Cylinder number of next track on output device */
/* outhead Head number of next track on output device */
/* The return value is 0 if successful, -1 if error occurred. */
/*-------------------------------------------------------------------*/
static int
write_track_zero (CIFBLK *cif, char *ofname, char *volser, U16 devtype,
int heads, int trklen, char *iplfnm,
int *reltrk, int *outcyl, int *outhead)
{
int rc; /* Return code */
int outusedv = 0; /* Output bytes used on track
of virtual device */
int outusedr = 0; /* Output bytes used on track
of real device */
int outtrkbr = 0; /* Output bytes remaining on
track of real device */
int outtrk = 0; /* Output relative track */
int outrec = 0; /* Output record number */
int keylen; /* Key length */
int datalen; /* Data length */
int maxtrks = 1; /* Maximum track count */
DATABLK *datablk; /* -> data block */
BYTE buf[32768]; /* Buffer for data block */
/* For 2311 the IPL text will not fit on track 0 record 4,
so adjust the IPL2 so that it loads from track 1 record 1 */
if (devtype == 0x2311)
{
memcpy (ipl2data + 32, "\x00\x00\x00\x00\x00\x01", 6);
memcpy (ipl2data + 38, "\x00\x00\x00\x01\x01", 5);
maxtrks = 2;
}
/* Read track 0 */
rc = read_track (cif, 0, 0);
if (rc < 0) return -1;
/* Initialize the track buffer */
*outcyl = 0; *outhead = 0;
init_track (trklen, cif->trkbuf, *outcyl, *outhead, &outusedv);
cif->trkmodif = 1;
/* Build the IPL1 record */
memset (buf, 0, sizeof(buf));
datablk = (DATABLK*)buf;
convert_to_ebcdic (datablk->kdarea, 4, "IPL1");
if (iplfnm != NULL)
{
memcpy (datablk->kdarea+4, iplpsw, 8);
memcpy (datablk->kdarea+12, iplccw1, 8);
memcpy (datablk->kdarea+20, iplccw2, 8);
}
else
{
memcpy (datablk->kdarea+4, noiplpsw, 8);
memcpy (datablk->kdarea+12, noiplccw1, 8);
memcpy (datablk->kdarea+20, noiplccw2, 8);
}
keylen = IPL1_KEYLEN;
datalen = IPL1_DATALEN;
rc = write_block (cif, ofname, datablk, keylen, datalen,
devtype, heads, trklen, maxtrks,
&outusedv, &outusedr, &outtrkbr,
&outtrk, outcyl, outhead, &outrec);
if (rc < 0) return -1;
/* Build the IPL2 record */
memset (buf, 0, sizeof(buf));
datablk = (DATABLK*)buf;
convert_to_ebcdic (datablk->kdarea, 4, "IPL2");
if (iplfnm != NULL)
{
memcpy (datablk->kdarea+4, ipl2data, sizeof(ipl2data));
}
keylen = IPL2_KEYLEN;
datalen = IPL2_DATALEN;
rc = write_block (cif, ofname, datablk, keylen, datalen,
devtype, heads, trklen, maxtrks,
&outusedv, &outusedr, &outtrkbr,
&outtrk, outcyl, outhead, &outrec);
if (rc < 0) return -1;
/* Build the VOL1 record */
memset (buf, 0x40, sizeof(buf));
datablk = (DATABLK*)buf;
convert_to_ebcdic (datablk->kdarea, 4, "VOL1");
convert_to_ebcdic (datablk->kdarea+4, 4, "VOL1");
convert_to_ebcdic (datablk->kdarea+8, 6, volser);
memset(datablk->kdarea+15, 0, 5);
convert_to_ebcdic (datablk->kdarea+45, 8, "HERCULES");
keylen = VOL1_KEYLEN;
datalen = VOL1_DATALEN;
rc = write_block (cif, ofname, datablk, keylen, datalen,
devtype, heads, trklen, maxtrks,
&outusedv, &outusedr, &outtrkbr,
&outtrk, outcyl, outhead, &outrec);
if (rc < 0) return -1;
/* Build the IPL text from the object file */
if (iplfnm != NULL)
{
memset (buf, 0, sizeof(buf));
datalen = read_ipl_text (iplfnm, buf+12, sizeof(buf)-12);
if (datalen < 0) return -1;
datablk = (DATABLK*)buf;
keylen = 0;
rc = write_block (cif, ofname, datablk, keylen, datalen,
devtype, heads, trklen, maxtrks,
&outusedv, &outusedr, &outtrkbr,
&outtrk, outcyl, outhead, &outrec);
if (rc < 0) return -1;
}
/* Write track zero to the output file */
rc = write_track (cif, ofname, heads, trklen,
&outusedv, reltrk, outcyl, outhead);
if (rc < 0) return -1;
return 0;
} /* end function write_track_zero */
/*-------------------------------------------------------------------*/
/* Subroutine to update a data block in the output file */
/* Input: */
/* cif -> CKD image file descriptor */
/* ofname Output file name */
/* blk Pointer to data block structure */
/* cyl Cylinder number */
/* head Head number */
/* rec Record number */
/* keylen Key length */
/* datalen Data length */
/* heads Number of tracks per cylinder on output device */
/* trklen Track length of virtual output device */
/* Output: */
/* The return value is 0 if successful, -1 if error occurred. */
/*-------------------------------------------------------------------*/
static int
update_block (CIFBLK *cif, char *ofname, DATABLK *blk, int cyl,
int head, int rec, int keylen, int datalen, int heads, int trklen)
{
int rc; /* Return code */
int curcyl; /* Original cylinder */
int curhead; /* Original head */
int klen; /* Record key length */
int dlen; /* Record data length */
int skiplen; /* Number of bytes to skip */
int offset; /* Offset into trkbuf */
CKDDASD_TRKHDR trkhdr; /* Track header */
CKDDASD_RECHDR rechdr; /* Record header */
UNREFERENCED(heads);
UNREFERENCED(trklen);
/* Save the current position in the output file */
curcyl = cif->curcyl;
curhead = cif->curhead;
/* Read the requested track */
rc = read_track (cif, cyl, head);
if (rc < 0)
{
XMERRF ("HHCDL043E %s cyl %d head %d read error\n",
ofname, cyl, head);
return -1;
}
/* Copy the track header */
memcpy (&trkhdr, cif->trkbuf, CKDDASD_TRKHDR_SIZE);
offset = CKDDASD_TRKHDR_SIZE;
/* Validate the track header */
if (trkhdr.bin != 0
|| trkhdr.cyl[0] != (cyl >> 8)
|| trkhdr.cyl[1] != (cyl & 0xFF)
|| trkhdr.head[0] != (head >> 8)
|| trkhdr.head[1] != (head & 0xFF))
{
XMERRF ("HHCDL044E %s cyl %d head %d invalid track header "
"%2.2X%2.2X%2.2X%2.2X%2.2X\n",
ofname, cyl, head,
trkhdr.bin, trkhdr.cyl[0], trkhdr.cyl[1],
trkhdr.head[0], trkhdr.head[1]);
return -1;
}
/* Search for the record to be updated */
while (1)
{
/* Copy the next record header */
memcpy (&rechdr, cif->trkbuf + offset, CKDDASD_RECHDR_SIZE);
offset += CKDDASD_RECHDR_SIZE;
/* Check for end of track */
if (memcmp(&rechdr, eighthexFF, 8) == 0)
{
XMERRF ("HHCDL045E %s cyl %d head %d rec %d record not found\n",
ofname, cyl, head, rec);
return -1;
}
/* Extract record key length and data length */
klen = rechdr.klen;
dlen = (rechdr.dlen[0] << 8) | rechdr.dlen[1];
/* Exit loop if matching record number */
if (rechdr.rec == rec)
break;
/* Skip the key and data areas */
skiplen = klen + dlen;
offset += skiplen;
} /* end while */
/* Check for attempt to change key length or data length */
if (keylen != klen || datalen != dlen)
{
XMERRF ("HHCDL046E Cannot update cyl %d head %d rec %d: "
"Unmatched KL/DL\n",
cyl, head, rec);
return -1;
}
/* Copy the updated block to the trkbuf */
memcpy (cif->trkbuf + offset, blk->kdarea, keylen + datalen);
cif->trkmodif = 1;
/* Restore original track */
rc = read_track (cif, curcyl, curhead);
if (rc < 0)
{
XMERRF ("HHCDL047E %s cyl %d head %d read error\n",
ofname, curcyl, curhead);
return -1;
}
XMINFF (4, "HHCDL048I Updating cyl %u head %u rec %d kl %d dl %d\n",
cyl, head, rec, keylen, datalen);
return 0;
} /* end function update_block */
/*-------------------------------------------------------------------*/
/* Subroutine to build a format 1 DSCB */
/* Input: */
/* dscbtab Array of pointers to DSCB data blocks */
/* dscbnum Number of entries in dscbtab array */
/* dsname Dataset name (ASCIIZ) */
/* volser Volume serial number (ASCIIZ) */
/* dsorg 1st byte of dataset organization bits */
/* recfm 1st byte of record format bits */
/* lrecl Logical record length */
/* blksz Block size */
/* keyln Key length */
/* dirblu Bytes used in last directory block */
/* lasttrk Relative track number of last-used track of dataset */
/* lastrec Record number of last-used block of dataset */
/* trkbal Bytes remaining on last-used track */
/* units Allocation units (C=CYL, T=TRK) */
/* spsec Secondary allocation quantity */
/* bcyl Extent begin cylinder number */
/* bhead Extent begin head number */
/* ecyl Extent end cylinder number */
/* ehead Extent end head number */
/* Output: */
/* The return value is 0 if successful, or -1 if error */
/* */
/* This subroutine allocates a DATABLK structure, builds a DSCB */
/* within the structure, and adds the structure to the DSCB array. */
/*-------------------------------------------------------------------*/
static int
build_format1_dscb (DATABLK *dscbtab[], int dscbnum,
char *dsname, char *volser,
BYTE dsorg, BYTE recfm, int lrecl, int blksz,
int keyln, int dirblu, int lasttrk, int lastrec,
int trkbal, BYTE units, int spsec,
int bcyl, int bhead, int ecyl, int ehead)
{
DATABLK *datablk; /* -> Data block structure */
FORMAT1_DSCB *f1dscb; /* -> DSCB within data block */
int blklen; /* Size of data block */
struct tm *tmptr; /* -> Date and time structure*/
time_t timeval; /* Current time value */
/* Obtain the current time */
time(&timeval);
tmptr = localtime(&timeval);
/* Allocate storage for a DATABLK structure */
blklen = 12 + sizeof(FORMAT1_DSCB);
datablk = (DATABLK*)malloc(blklen);
if (datablk == NULL)
{
XMERRF ("HHCDL049E Cannot obtain storage for DSCB: %s\n",
strerror(errno));
return -1;
}
/* Check that there is room in the DSCB pointer array */
if (dscbnum >= MAXDSCB)
{
XMERRF ("HHCDL050E DSCB count exceeds %d, increase MAXDSCB\n",
MAXDSCB);
return -1;
}
/* Clear the data block and save its address in the DSCB array */
memset (datablk, 0, blklen);
dscbtab[dscbnum] = datablk;