1 /* BLDCFG.C     (c) Copyright Roger Bowler, 1999-2009                */
2 /*              ESA/390 Configuration Builder                        */
3 
4 /* Interpretive Execution - (c) Copyright Jan Jaeger, 1999-2009      */
5 
6 /*-------------------------------------------------------------------*/
7 /* This module builds the configuration tables for the Hercules      */
8 /* ESA/390 emulator.  It reads information about the processors      */
9 /* and I/O devices from a configuration file.  It allocates          */
10 /* main storage and expanded storage, initializes control blocks,    */
11 /* and creates detached threads to handle console attention          */
12 /* requests and to maintain the TOD clock and CPU timers.            */
13 /*-------------------------------------------------------------------*/
14 
15 /*-------------------------------------------------------------------*/
16 /* Additional credits:                                               */
17 /*      TOD clock offset contributed by Jay Maynard                  */
18 /*      Dynamic device attach/detach by Jan Jaeger                   */
19 /*      OSTAILOR parameter by Jay Maynard                            */
20 /*      PANRATE parameter by Reed H. Petty                           */
21 /*      CPUPRIO parameter by Jan Jaeger                              */
22 /*      HERCPRIO, TODPRIO, DEVPRIO parameters by Mark L. Gaubatz     */
23 /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2009      */
24 /*      $(DEFSYM) symbol substitution support by Ivan Warren         */
25 /*      Patch for ${var=def} symbol substitution (hax #26),          */
26 /*          and INCLUDE <filename> support (modified hax #27),       */
27 /*          contributed by Enrico Sorichetti based on                */
28 /*          original patches by "Hackules"                           */
29 /*-------------------------------------------------------------------*/
30 
31 #include "hstdinc.h"
32 
33 #if !defined(_BLDCFG_C_)
34 #define _BLDCFG_C_
35 #endif
36 
37 #if !defined(_HENGINE_DLL_)
38 #define _HENGINE_DLL_
39 #endif
40 
41 #include "hercules.h"
42 #include "devtype.h"
43 #include "opcode.h"
44 #include "hostinfo.h"
45 
46 #if defined(OPTION_FISHIO)
47 #include "w32chan.h"
48 #endif // defined(OPTION_FISHIO)
49 
50 #if defined( OPTION_TAPE_AUTOMOUNT )
51 #include "tapedev.h"
52 #endif
53 
54 #if !defined(_GEN_ARCH)
55 
56 #if defined(_ARCHMODE3)
57  #define  _GEN_ARCH _ARCHMODE3
58  #include "bldcfg.c"
59  #undef   _GEN_ARCH
60 #endif
61 
62 #if defined(_ARCHMODE2)
63  #define  _GEN_ARCH _ARCHMODE2
64  #include "bldcfg.c"
65  #undef   _GEN_ARCH
66 #endif
67 
68 typedef struct _DEVARRAY
69 {
70     U16 cuu1;
71     U16 cuu2;
72 } DEVARRAY;
73 
74 typedef struct _DEVNUMSDESC
75 {
76     BYTE lcss;
77     DEVARRAY *da;
78 } DEVNUMSDESC;
79 
80 /*-------------------------------------------------------------------*/
81 /* Static data areas                                                 */
82 /*-------------------------------------------------------------------*/
83 #define MAX_INC_LEVEL 8                 /* Maximum nest level        */
84 static int  inc_level;                  /* Current nesting level     */
85 // following commented out ISW 20061009 : Not referenced anywhere.
86 // static int  inc_fname[MAX_INC_LEVEL];   /* filename (base or incl)   */
87 static int  inc_stmtnum[MAX_INC_LEVEL]; /* statement number          */
88 static int  inc_ignore_errors = 0;      /* 1==ignore include errors  */
89 #ifdef EXTERNALGUI
90 static char buf[1024];                  /* Config statement buffer   */
91 #else /*!EXTERNALGUI*/
92 static char buf[256];                   /* Config statement buffer   */
93 #endif /*EXTERNALGUI*/
94 static char *keyword;                   /* -> Statement keyword      */
95 static char *operand;                   /* -> First argument         */
96 static int  addargc;                    /* Number of additional args */
97 static char *addargv[MAX_ARGS];         /* Additional argument array */
98 
99 
100 /*-------------------------------------------------------------------*/
101 /* Subroutine to parse an argument string. The string that is passed */
102 /* is modified in-place by inserting null characters at the end of   */
103 /* each argument found. The returned array of argument pointers      */
104 /* then points to each argument found in the original string. Any    */
105 /* argument that begins with '#' comment indicator causes early      */
106 /* termination of the parsing and is not included in the count. Any  */
107 /* argument found that starts with a quote or apostrophe causes      */
108 /* all characters up to the next quote or apostrophe to be           */
109 /* included as part of that argument. The quotes/apostrophes them-   */
110 /* selves are not considered part of any argument and are ignored.   */
111 /* p            Points to string to be parsed.                       */
112 /* maxargc      Maximum allowable number of arguments. (Prevents     */
113 /*              overflowing the pargv array)                         */
114 /* pargv        Pointer to buffer for argument pointer array.        */
115 /* pargc        Pointer to number of arguments integer result.       */
116 /* Returns number of arguments found. (same value as at *pargc)      */
117 /*-------------------------------------------------------------------*/
parse_args(char * p,int maxargc,char ** pargv,int * pargc)118 DLL_EXPORT int parse_args (char* p, int maxargc, char** pargv, int* pargc)
119 {
120     for (*pargc = 0; *pargc < MAX_ARGS; ++*pargc) addargv[*pargc] = NULL;
121 
122     *pargc = 0;
123     *pargv = NULL;
124 
125     while (*p && *pargc < maxargc)
126     {
127         while (*p && isspace(*p)) p++; if (!*p) break; // find start of arg
128 
129         if (*p == '#') break; // stop on comments
130 
131         *pargv = p; ++*pargc; // count new arg
132 
133         while (*p && !isspace(*p) && *p != '\"' && *p != '\'') p++; if (!*p) break; // find end of arg
134 
135         if (*p == '\"' || *p == '\'')
136         {
137             char delim = *p;
138             if (p == *pargv) *pargv = p+1;
139             while (*++p && *p != delim) {}; if (!*p) break; // find end of quoted string
140         }
141 
142         *p++ = 0; // mark end of arg
143         pargv++; // next arg ptr
144     }
145 
146     return *pargc;
147 }
148 
delayed_exit(int exit_code)149 void delayed_exit (int exit_code)
150 {
151     /* Delay exiting is to give the system
152      * time to display the error message. */
153     fflush(stderr);
154     fflush(stdout);
155     usleep(100000);
156 //  hdl_shut();
157     do_shutdown();
158     fflush(stderr);
159     fflush(stdout);
160     usleep(100000);
161     exit(exit_code);
162 }
163 
164 
165 /* storage configuration routine. To be moved *JJ */
config_storage(unsigned mainsize,unsigned xpndsize)166 static void config_storage(unsigned mainsize, unsigned xpndsize)
167 {
168 int off;
169 
170     /* Obtain main storage */
171     sysblk.mainsize = mainsize * 1024 * 1024ULL;
172 
173     sysblk.mainstor = calloc((size_t)(sysblk.mainsize + 8192), 1);
174 
175     if (sysblk.mainstor != NULL)
176         sysblk.main_clear = 1;
177     else
178         sysblk.mainstor = malloc((size_t)(sysblk.mainsize + 8192));
179 
180     if (sysblk.mainstor == NULL)
181     {
182         logmsg(_("HHCCF031S Cannot obtain %dMB main storage: %s\n"),
183                 mainsize, strerror(errno));
184         delayed_exit(1);
185     }
186 
187     /* Trying to get mainstor aligned to the next 4K boundary - Greg */
188     off = (uintptr_t)sysblk.mainstor & 0xFFF;
189     sysblk.mainstor += off ? 4096 - off : 0;
190 
191     /* Obtain main storage key array */
192     sysblk.storkeys = calloc((size_t)(sysblk.mainsize / STORAGE_KEY_UNITSIZE), 1);
193     if (sysblk.storkeys == NULL)
194     {
195         sysblk.main_clear = 0;
196         sysblk.storkeys = malloc((size_t)(sysblk.mainsize / STORAGE_KEY_UNITSIZE));
197     }
198     if (sysblk.storkeys == NULL)
199     {
200         logmsg(_("HHCCF032S Cannot obtain storage key array: %s\n"),
201                 strerror(errno));
202         delayed_exit(1);
203     }
204 
205     /* Initial power-on reset for main storage */
206     storage_clear();
207 
208 #if 0   /*DEBUG-JJ-20/03/2000*/
209     /* Mark selected frames invalid for debugging purposes */
210     for (i = 64 ; i < (sysblk.mainsize / STORAGE_KEY_UNITSIZE); i += 2)
211         if (i < (sysblk.mainsize / STORAGE_KEY_UNITSIZE) - 64)
212             sysblk.storkeys[i] = STORKEY_BADFRM;
213         else
214             sysblk.storkeys[i++] = STORKEY_BADFRM;
215 #endif
216 
217     if (xpndsize != 0)
218     {
219 #ifdef _FEATURE_EXPANDED_STORAGE
220 
221         /* Obtain expanded storage */
222         sysblk.xpndsize = xpndsize * (1024*1024 / XSTORE_PAGESIZE);
223         sysblk.xpndstor = calloc(sysblk.xpndsize, XSTORE_PAGESIZE);
224         if (sysblk.xpndstor)
225             sysblk.xpnd_clear = 1;
226         else
227             sysblk.xpndstor = malloc((size_t)sysblk.xpndsize * XSTORE_PAGESIZE);
228         if (sysblk.xpndstor == NULL)
229         {
230             logmsg(_("HHCCF033S Cannot obtain %dMB expanded storage: "
231                     "%s\n"),
232                     xpndsize, strerror(errno));
233             delayed_exit(1);
234         }
235         /* Initial power-on reset for expanded storage */
236         xstorage_clear();
237 #else /*!_FEATURE_EXPANDED_STORAGE*/
238         logmsg(_("HHCCF034W Expanded storage support not installed\n"));
239 #endif /*!_FEATURE_EXPANDED_STORAGE*/
240     } /* end if(sysblk.xpndsize) */
241 }
242 
243 #if defined( OPTION_TAPE_AUTOMOUNT )
244 /*-------------------------------------------------------------------*/
245 /* Add directory to AUTOMOUNT allowed/disallowed directories list    */
246 /*                                                                   */
247 /* Input:  tamdir     pointer to work character array of at least    */
248 /*                    MAX_PATH size containing an allowed/disallowed */
249 /*                    directory specification, optionally prefixed   */
250 /*                    with the '+' or '-' indicator.                 */
251 /*                                                                   */
252 /*         ppTAMDIR   address of TAMDIR ptr that upon successful     */
253 /*                    completion is updated to point to the TAMDIR   */
254 /*                    entry that was just successfully added.        */
255 /*                                                                   */
256 /* Output: upon success, ppTAMDIR is updated to point to the TAMDIR  */
257 /*         entry just added. Upon error, ppTAMDIR is set to NULL and */
258 /*         the original input character array is set to the inter-   */
259 /*         mediate value being processed when the error occurred.    */
260 /*                                                                   */
261 /* Returns:  0 == success                                            */
262 /*           1 == unresolvable path                                  */
263 /*           2 == path inaccessible                                  */
264 /*           3 == conflict w/previous                                */
265 /*           4 == duplicates previous                                */
266 /*           5 == out of memory                                      */
267 /*                                                                   */
268 /*-------------------------------------------------------------------*/
add_tamdir(char * tamdir,TAMDIR ** ppTAMDIR)269 DLL_EXPORT int add_tamdir( char *tamdir, TAMDIR **ppTAMDIR )
270 {
271     int  rc, rej = 0;
272     char dirwrk[ MAX_PATH ] = {0};
273 
274     *ppTAMDIR = NULL;
275 
276     if (*tamdir == '-')
277     {
278         rej = 1;
279         memmove (tamdir, tamdir+1, MAX_PATH);
280     }
281     else if (*tamdir == '+')
282     {
283         rej = 0;
284         memmove (tamdir, tamdir+1, MAX_PATH);
285     }
286 
287     /* Convert tamdir to absolute path ending with a slash */
288 
289 #if defined(_MSVC_)
290     /* (expand any embedded %var% environment variables) */
291     rc = expand_environ_vars( tamdir, dirwrk, MAX_PATH );
292     if (rc == 0)
293         strlcpy (tamdir, dirwrk, MAX_PATH);
294 #endif
295 
296     if (!realpath( tamdir, dirwrk ))
297         return (1); /* ("unresolvable path") */
298     strlcpy (tamdir, dirwrk, MAX_PATH);
299 
300     /* Verify that the path is valid */
301     if (access( tamdir, R_OK | W_OK ) != 0)
302         return (2); /* ("path inaccessible") */
303 
304     /* Append trailing path separator if needed */
305     rc = strlen( tamdir );
306     if (tamdir[rc-1] != *PATH_SEP)
307         strlcat (tamdir, PATH_SEP, MAX_PATH);
308 
309     /* Check for duplicate/conflicting specification */
310     for (*ppTAMDIR = sysblk.tamdir;
311          *ppTAMDIR;
312          *ppTAMDIR = (*ppTAMDIR)->next)
313     {
314         if (strfilenamecmp( tamdir, (*ppTAMDIR)->dir ) == 0)
315         {
316             if ((*ppTAMDIR)->rej != rej)
317                 return (3); /* ("conflict w/previous") */
318             else
319                 return (4); /* ("duplicates previous") */
320         }
321     }
322 
323     /* Allocate new AUTOMOUNT directory entry */
324     *ppTAMDIR = malloc( sizeof(TAMDIR) );
325     if (!*ppTAMDIR)
326         return (5); /* ("out of memory") */
327 
328     /* Fill in the new entry... */
329     (*ppTAMDIR)->dir = strdup (tamdir);
330     (*ppTAMDIR)->len = strlen (tamdir);
331     (*ppTAMDIR)->rej = rej;
332     (*ppTAMDIR)->next = NULL;
333 
334     /* Add new entry to end of existing list... */
335     if (sysblk.tamdir == NULL)
336         sysblk.tamdir = *ppTAMDIR;
337     else
338     {
339         TAMDIR *pTAMDIR = sysblk.tamdir;
340         while (pTAMDIR->next)
341             pTAMDIR = pTAMDIR->next;
342         pTAMDIR->next = *ppTAMDIR;
343     }
344 
345     /* Use first allowable dir as default */
346     if (rej == 0 && sysblk.defdir == NULL)
347         sysblk.defdir = (*ppTAMDIR)->dir;
348 
349     return (0); /* ("success") */
350 }
351 #endif /* OPTION_TAPE_AUTOMOUNT */
352 
353 /*-------------------------------------------------------------------*/
354 /* Subroutine to read a statement from the configuration file        */
355 /* The statement is then parsed into keyword, operand, and           */
356 /* additional arguments.  The output values are:                     */
357 /* keyword      Points to first word of statement                    */
358 /* operand      Points to second word of statement                   */
359 /* addargc      Contains number of additional arguments              */
360 /* addargv      An array of pointers to each additional argument     */
361 /* Returns 0 if successful, -1 if end of file                        */
362 /*-------------------------------------------------------------------*/
read_config(char * fname,FILE * fp)363 static int read_config (char *fname, FILE *fp)
364 {
365 int     i;                              /* Array subscript           */
366 int     c;                              /* Character work area       */
367 int     stmtlen;                        /* Statement length          */
368 #if defined( OPTION_ENHANCED_CONFIG_SYMBOLS )
369 int     inc_dollar;                     /* >=0 Ndx of dollar         */
370 int     inc_lbrace;                     /* >=0 Ndx of lbrace + 1     */
371 int     inc_colon;                      /* >=0 Ndx of colon          */
372 int     inc_equals;                     /* >=0 Ndx of equals         */
373 char    *inc_envvar;                    /* ->Environment variable    */
374 #endif // defined( OPTION_ENHANCED_CONFIG_SYMBOLS )
375 int     lstarted;                       /* Indicate if non-whitespace*/
376                                         /* has been seen yet in line */
377 char   *cnfline;                        /* Pointer to copy of buffer */
378 #if defined(OPTION_CONFIG_SYMBOLS)
379 char   *buf1;                           /* Pointer to resolved buffer*/
380 #endif /*defined(OPTION_CONFIG_SYMBOLS)*/
381 
382 #if defined( OPTION_ENHANCED_CONFIG_SYMBOLS )
383     inc_dollar = -1;
384     inc_lbrace = -1;
385     inc_colon  = -1;
386     inc_equals = -1;
387 #endif // defined( OPTION_ENHANCED_CONFIG_SYMBOLS )
388 
389     while (1)
390     {
391         /* Increment statement number */
392         inc_stmtnum[inc_level]++;
393 
394         /* Read next statement from configuration file */
395         for (stmtlen = 0, lstarted = 0; ;)
396         {
397             /* Read character from configuration file */
398             c = fgetc(fp);
399 
400             /* Check for I/O error */
401             if (ferror(fp))
402             {
403                 logmsg(_("HHCCF001S Error reading file %s line %d: %s\n"),
404                     fname, inc_stmtnum[inc_level], strerror(errno));
405                 delayed_exit(1);
406             }
407 
408             /* Check for end of file */
409             if (stmtlen == 0 && (c == EOF || c == '\x1A'))
410                 return -1;
411 
412             /* Check for end of line */
413             if (c == '\n' || c == EOF || c == '\x1A')
414                 break;
415 
416             /* Ignore nulls and carriage returns */
417             if (c == '\0' || c == '\r') continue;
418 
419             /* Check if it is a white space and no other character yet */
420             if(!lstarted && isspace(c)) continue;
421             lstarted=1;
422 
423             /* Check that statement does not overflow buffer */
424             if (stmtlen >= (int)(sizeof(buf) - 1))
425             {
426                 logmsg(_("HHCCF002S File %s line %d is too long\n"),
427                     fname, inc_stmtnum[inc_level]);
428                 delayed_exit(1);
429             }
430 
431 #if defined( OPTION_ENHANCED_CONFIG_SYMBOLS )
432             /* inc_dollar already processed? */
433             if (inc_dollar >= 0)
434             {
435                 /* Left brace already processed? */
436                 if (inc_lbrace >= 0)
437                 {
438                     /* End of variable spec? */
439                     if (c == '}')
440                     {
441                         /* Terminate it */
442                         buf[stmtlen] = '\0';
443 
444                         /* Terminate var name if we have a inc_colon specifier */
445                         if (inc_colon >= 0)
446                         {
447                             buf[inc_colon] = '\0';
448                         }
449 
450                         /* Terminate var name if we have a default value */
451                         if (inc_equals >= 0)
452                         {
453                             buf[inc_equals] = '\0';
454                         }
455 
456                         /* Reset statement index to start of variable */
457                         stmtlen = inc_dollar;
458 
459                         /* Get variable value */
460                         inc_envvar = getenv (&buf[inc_lbrace]);
461 
462                         /* Variable unset? */
463                         if (inc_envvar == NULL)
464                         {
465                             /* Substitute default if specified */
466                             if (inc_equals >= 0)
467                             {
468                                 inc_envvar = &buf[inc_equals+1];
469                             }
470                         }
471                         else // (environ variable defined)
472                         {
473                             /* Have ":=" specification? */
474                             if (/*inc_colon >= 0 && */inc_equals >= 0)
475                             {
476                                 /* Substitute default if value is NULL */
477                                 if (strlen (inc_envvar) == 0)
478                                 {
479                                     inc_envvar = &buf[inc_equals+1];
480                                 }
481                             }
482                         }
483 
484                         /* Have a value? (environment or default) */
485                         if (inc_envvar != NULL)
486                         {
487                             /* Check that statement does not overflow buffer */
488                             if (stmtlen+strlen(inc_envvar) >= sizeof(buf) - 1)
489                             {
490                                 logmsg(_("HHCCF002S File %s line %d is too long\n"),
491                                                 fname, inc_stmtnum[inc_level]);
492                                 delayed_exit(1);
493                             }
494 
495                             /* Copy to buffer and update index */
496                             stmtlen += sprintf (&buf[stmtlen], "%s", inc_envvar);
497                         }
498 
499                         /* Reset indexes */
500                         inc_equals = -1;
501                         inc_colon = -1;
502                         inc_lbrace = -1;
503                         inc_dollar = -1;
504                         continue;
505                     }
506                     else if (c == ':' && inc_colon < 0 && inc_equals < 0)
507                     {
508                         /* Remember possible start of default specifier */
509                         inc_colon = stmtlen;
510                     }
511                     else if (c == '=' && inc_equals < 0)
512                     {
513                         /* Remember possible start of default specifier */
514                         inc_equals = stmtlen;
515                     }
516                 }
517                 else // (inc_lbrace < 0)
518                 {
519                     /* Remember start of variable name */
520                     if (c == '{')
521                     {
522                         inc_lbrace = stmtlen + 1;
523                     }
524                     else
525                     {
526                         /* Reset inc_dollar specifier if immediately following
527                            character is not a left brace */
528                         inc_dollar = -1;
529                     }
530                 }
531             }
532             else // (inc_dollar < 0)
533             {
534                 /* Enter variable substitution state */
535                 if (c == '$')
536                 {
537                     inc_dollar = stmtlen;
538                 }
539             }
540 #endif // defined( OPTION_ENHANCED_CONFIG_SYMBOLS )
541 
542             /* Append character to buffer */
543             buf[stmtlen++] = c;
544 
545         } /* end for(stmtlen) */
546 
547         /* Remove trailing blanks and tabs */
548         while (stmtlen > 0 && (buf[stmtlen-1] == SPACE
549                 || buf[stmtlen-1] == '\t')) stmtlen--;
550         buf[stmtlen] = '\0';
551 
552         /* Ignore comments and null statements */
553         if (stmtlen == 0 || buf[0] == '*' || buf[0] == '#')
554            continue;
555 
556         cnfline = strdup(buf);
557 
558         /* Parse the statement just read */
559 
560 #if defined(OPTION_CONFIG_SYMBOLS)
561 
562         /* Perform variable substitution */
563         /* First, set some 'dynamic' symbols to their own values */
564 
565         set_symbol("CUU","$(CUU)");
566         set_symbol("cuu","$(cuu)");
567         set_symbol("CCUU","$(CCUU)");
568         set_symbol("ccuu","$(ccuu)");
569 
570         /* VERISION will be set here, earlier than in           @PJJ */
571         /* console.c in order to make it usable in the          @PJJ */
572         /* hercules configuration file.                         @PJJ */
573         set_symbol("VERSION", VERSION);
574 
575         buf1=resolve_symbol_string(buf);
576 
577         if(buf1!=NULL)
578         {
579             if(strlen(buf1)>=sizeof(buf))
580             {
581                 logmsg(_("HHCCF002S File %s line %d is too long\n"),
582                     fname, inc_stmtnum[inc_level]);
583                 free(buf1);
584                 delayed_exit(1);
585             }
586             strcpy(buf,buf1);
587 
588             /* Free buf1 as explicitly stated to be needed in   @PJJ */
589             /* resolve_symbol_string.                           @PJJ */
590             free(buf1);
591 
592         }
593 #endif /*defined(OPTION_CONFIG_SYMBOLS)*/
594 
595         parse_args (buf, MAX_ARGS, addargv, &addargc);
596 
597 #if defined(OPTION_DYNAMIC_LOAD)
598         if(config_command)
599         {
600             if( config_command(addargc, (char**)addargv, cnfline) )
601             {
602                 free(cnfline);
603                 continue;
604             }
605         }
606 #endif /*defined(OPTION_DYNAMIC_LOAD)*/
607 
608         if( !ProcessConfigCommand (addargc, (char**)addargv, cnfline) )
609         {
610             free(cnfline);
611             continue;
612         }
613 
614         free(cnfline);
615 
616         /* Move the first two arguments to separate variables */
617 
618         keyword = addargv[0];
619         operand = addargv[1];
620 
621         addargc = (addargc > 2) ? (addargc-2) : (0);
622 
623         for (i = 0; i < MAX_ARGS; i++)
624         {
625             if (i < (MAX_ARGS-2)) addargv[i] = addargv[i+2];
626             else addargv[i] = NULL;
627         }
628 
629         break;
630     } /* end while */
631 
632     return 0;
633 } /* end function read_config */
634 
lyear_adjust(int epoch)635 static inline S64 lyear_adjust(int epoch)
636 {
637 int year, leapyear;
638 U64 tod = hw_clock();
639 
640     if(tod >= TOD_YEAR)
641     {
642         tod -= TOD_YEAR;
643         year = (tod / TOD_4YEARS * 4) + 1;
644         tod %= TOD_4YEARS;
645         if((leapyear = tod / TOD_YEAR) == 4)
646             year--;
647         year += leapyear;
648     }
649     else
650        year = 0;
651 
652     if(epoch > 0)
653         return (((year % 4) != 0) && (((year % 4) - (epoch % 4)) <= 0)) ? -TOD_DAY : 0;
654     else
655         return (((year % 4) == 0 && (-epoch % 4) != 0) || ((year % 4) + (-epoch % 4) > 4)) ? TOD_DAY : 0;
656 }
657 
658 
659 DLL_EXPORT char *config_cnslport = "3270";
660 /*-------------------------------------------------------------------*/
661 /* Function to build system configuration                            */
662 /*-------------------------------------------------------------------*/
build_config(char * fname)663 void build_config (char *fname)
664 {
665 int     rc;                             /* Return code               */
666 int     i;                              /* Array subscript           */
667 int     scount;                         /* Statement counter         */
668 int     cpu;                            /* CPU number                */
669 int     count;                          /* Counter                   */
670 FILE   *inc_fp[MAX_INC_LEVEL];          /* Configuration file pointer*/
671 
672 char   *sserial;                        /* -> CPU serial string      */
673 char   *smodel;                         /* -> CPU model string       */
674 char   *sversion;                       /* -> CPU version string     */
675 char   *smainsize;                      /* -> Main size string       */
676 char   *sxpndsize;                      /* -> Expanded size string   */
677 char   *smaxcpu;                        /* -> Maximum number of CPUs */
678 char   *snumcpu;                        /* -> Number of CPUs         */
679 char   *snumvec;                        /* -> Number of VFs          */
680 char   *sengines;                       /* -> Processor engine types */
681 char   *ssysepoch;                      /* -> System epoch           */
682 char   *syroffset;                      /* -> System year offset     */
683 char   *stzoffset;                      /* -> System timezone offset */
684 char   *shercprio;                      /* -> Hercules base priority */
685 char   *stodprio;                       /* -> Timer thread priority  */
686 char   *scpuprio;                       /* -> CPU thread priority    */
687 char   *sdevprio;                       /* -> Device thread priority */
688 char   *slogofile;                      /* -> 3270 logo file         */
689 #if defined(_FEATURE_ECPSVM)
690 char   *secpsvmlevel;                   /* -> ECPS:VM Keyword        */
691 char   *secpsvmlvl;                     /* -> ECPS:VM level (or 'no')*/
692 int    ecpsvmac;                        /* -> ECPS:VM add'l arg cnt  */
693 #endif /*defined(_FEATURE_ECPSVM)*/
694 #if defined(OPTION_SHARED_DEVICES)
695 char   *sshrdport;                      /* -> Shared device port nbr */
696 #endif /*defined(OPTION_SHARED_DEVICES)*/
697 U16     version = 0x00;                 /* CPU version code          */
698 int     dfltver = 1;                    /* Default version code      */
699 U32     serial;                         /* CPU serial number         */
700 U16     model;                          /* CPU model number          */
701 unsigned mainsize;                      /* Main storage size (MB)    */
702 unsigned xpndsize;                      /* Expanded storage size (MB)*/
703 U16     maxcpu;                         /* Maximum number of CPUs    */
704 U16     numcpu;                         /* Number of CPUs            */
705 U16     numvec;                         /* Number of VFs             */
706 #if defined(OPTION_SHARED_DEVICES)
707 U16     shrdport;                       /* Shared device port number */
708 #endif /*defined(OPTION_SHARED_DEVICES)*/
709 S32     sysepoch;                       /* System epoch year         */
710 S32     tzoffset;                       /* System timezone offset    */
711 S32     yroffset;                       /* System year offset        */
712 S64     ly1960;                         /* Leap offset for 1960 epoch*/
713 int     hercprio;                       /* Hercules base priority    */
714 int     todprio;                        /* Timer thread priority     */
715 int     cpuprio;                        /* CPU thread priority       */
716 int     devprio;                        /* Device thread priority    */
717 DEVBLK *dev;                            /* -> Device Block           */
718 char   *sdevnum;                        /* -> Device number string   */
719 char   *sdevtype;                       /* -> Device type string     */
720 int     devtmax;                        /* Max number device threads */
721 #if defined(_FEATURE_ECPSVM)
722 int     ecpsvmavail;                    /* ECPS:VM Available flag    */
723 int     ecpsvmlevel;                    /* ECPS:VM declared level    */
724 #endif /*defined(_FEATURE_ECPSVM)*/
725 BYTE    c;                              /* Work area for sscanf      */
726 char   *styp;                           /* -> Engine type string     */
727 char   *styp_values[] = {"CP","CF","AP","IL","??","IP"}; /* type values */
728 BYTE    ptyp;                           /* Processor engine type     */
729 #ifdef OPTION_SELECT_KLUDGE
730 int     dummyfd[OPTION_SELECT_KLUDGE];  /* Dummy file descriptors --
731                                            this allows the console to
732                                            get a low fd when the msg
733                                            pipe is opened... prevents
734                                            cygwin from thrashing in
735                                            select(). sigh            */
736 #endif
737 char    hlogofile[FILENAME_MAX+1] = ""; /* File name from HERCLOGO   */
738 char    pathname[MAX_PATH];             /* file path in host format  */
739 
740     /* Initialize SETMODE and set user authority */
741     SETMODE(INIT);
742 
743 #ifdef OPTION_SELECT_KLUDGE
744     /* Reserve some fd's to be used later for the message pipes */
745     for (i = 0; i < OPTION_SELECT_KLUDGE; i++)
746         dummyfd[i] = dup(fileno(stderr));
747 #endif
748 
749     /* Open the base configuration file */
750     hostpath(pathname, fname, sizeof(pathname));
751     inc_level = 0;
752     inc_fp[inc_level] = fopen (pathname, "r");
753     if (inc_fp[inc_level] == NULL)
754     {
755         logmsg(_("HHCCF003S Open error file %s: %s\n"),
756                 fname, strerror(errno));
757         delayed_exit(1);
758     }
759     inc_stmtnum[inc_level] = 0;
760 
761     /* Set the default system parameter values */
762     serial = 0x000001;
763     model = 0x0586;
764     mainsize = 2;
765     xpndsize = 0;
766     maxcpu = 0;
767     numcpu = 0;
768     numvec = MAX_CPU_ENGINES;
769     sysepoch = 1900;
770     yroffset = 0;
771     tzoffset = 0;
772 #if defined(_390)
773     sysblk.arch_mode = ARCH_390;
774 #else
775     sysblk.arch_mode = ARCH_370;
776 #endif
777 #if defined(_900)
778     sysblk.arch_z900 = ARCH_900;
779 #endif
780     sysblk.pgminttr = OS_NONE;
781 
782     sysblk.timerint = DEFAULT_TIMER_REFRESH_USECS;
783 
784 #if defined( HTTP_SERVER_CONNECT_KLUDGE )
785     sysblk.http_server_kludge_msecs = 10;
786 #endif // defined( HTTP_SERVER_CONNECT_KLUDGE )
787 
788     hercprio = DEFAULT_HERCPRIO;
789     todprio  = DEFAULT_TOD_PRIO;
790     cpuprio  = DEFAULT_CPU_PRIO;
791     devprio  = DEFAULT_DEV_PRIO;
792     devtmax  = MAX_DEVICE_THREADS;
793     sysblk.kaidle = KEEPALIVE_IDLE_TIME;
794     sysblk.kaintv = KEEPALIVE_PROBE_INTERVAL;
795     sysblk.kacnt  = KEEPALIVE_PROBE_COUNT;
796 #if defined(_FEATURE_ECPSVM)
797     ecpsvmavail = 0;
798     ecpsvmlevel = 20;
799 #endif /*defined(_FEATURE_ECPSVM)*/
800 #if defined(OPTION_SHARED_DEVICES)
801     shrdport = 0;
802 #endif /*defined(OPTION_SHARED_DEVICES)*/
803 
804 #if defined(_FEATURE_ASN_AND_LX_REUSE)
805     sysblk.asnandlxreuse = 0;  /* ASN And LX Reuse is defaulted to DISABLE */
806 #endif
807 
808 #ifdef PANEL_REFRESH_RATE
809     sysblk.panrate = PANEL_REFRESH_RATE_SLOW;
810 #endif
811 
812     /* Initialize locks, conditions, and attributes */
813     initialize_lock (&sysblk.todlock);
814     initialize_lock (&sysblk.mainlock);
815     sysblk.mainowner = LOCK_OWNER_NONE;
816     initialize_lock (&sysblk.intlock);
817     initialize_lock (&sysblk.iointqlk);
818     sysblk.intowner = LOCK_OWNER_NONE;
819     initialize_lock (&sysblk.sigplock);
820 //  initialize_detach_attr (&sysblk.detattr);   // (moved to impl.c)
821 //  initialize_join_attr   (&sysblk.joinattr);  // (moved to impl.c)
822     initialize_condition (&sysblk.cpucond);
823     for (i = 0; i < MAX_CPU_ENGINES; i++)
824         initialize_lock (&sysblk.cpulock[i]);
825     initialize_condition (&sysblk.sync_cond);
826     initialize_condition (&sysblk.sync_bc_cond);
827 #if defined(OPTION_INSTRUCTION_COUNTING)
828     initialize_lock (&sysblk.icount_lock);
829 #endif
830 
831 #ifdef OPTION_PTTRACE
832     ptt_trace_init (0, 1);
833 #endif
834 
835 #if defined(_FEATURE_MESSAGE_SECURITY_ASSIST)
836     /* Initialize the wrapping key registers lock */
837     initialize_lock(&sysblk.wklock);
838 #endif /*defined(_FEATURE_MESSAGE_SECURITY_ASSIST)*/
839 
840 #if defined(OPTION_FISHIO)
841     InitIOScheduler                     // initialize i/o scheduler...
842     (
843         sysblk.arch_mode,               // (for calling execute_ccw_chain)
844         &sysblk.devprio,                // (ptr to device thread priority)
845         MAX_DEVICE_THREAD_IDLE_SECS,    // (maximum device thread wait time)
846         devtmax                         // (maximum #of device threads allowed)
847     );
848 #else // !defined(OPTION_FISHIO)
849     initialize_lock (&sysblk.ioqlock);
850     initialize_condition (&sysblk.ioqcond);
851     /* Set max number device threads */
852     sysblk.devtmax = devtmax;
853     sysblk.devtwait = sysblk.devtnbr =
854     sysblk.devthwm  = sysblk.devtunavail = 0;
855 #endif // defined(OPTION_FISHIO)
856 
857     /* Default the licence setting */
858     losc_set(PGM_PRD_OS_RESTRICTED);
859 
860     /* Default CPU type CP */
861     for (i = 0; i < MAX_CPU_ENGINES; i++)
862         sysblk.ptyp[i] = SCCB_PTYP_CP;
863 
864     /* Cap the default priorities at zero if setuid not available */
865 #if !defined(NO_SETUID)
866     if (sysblk.suid != 0)
867     {
868 #endif /*!defined(NO_SETUID)*/
869         if (hercprio < 0)
870             hercprio = 0;
871         if (todprio < 0)
872             todprio = 0;
873         if (cpuprio < 0)
874             cpuprio = 0;
875         if (devprio < 0)
876             devprio = 0;
877 #if !defined(NO_SETUID)
878     }
879 #endif /*!defined(NO_SETUID)*/
880 
881     /*****************************************************************/
882     /* Parse configuration file system parameter statements...       */
883     /*****************************************************************/
884 
885     for (scount = 0; ; scount++)
886     {
887         /* Read next record from the configuration file */
888         while (inc_level >= 0 && read_config (fname, inc_fp[inc_level]))
889         {
890             fclose (inc_fp[inc_level--]);
891         }
892         if (inc_level < 0)
893         {
894             logmsg(_("HHCCF004S No device records in file %s\n"),
895                     fname);
896             delayed_exit(1);
897         }
898 
899 #if defined( OPTION_ENHANCED_CONFIG_INCLUDE )
900         if  (strcasecmp (keyword, "ignore") == 0)
901         {
902             if  (strcasecmp (operand, "include_errors") == 0)
903             {
904                 logmsg( _("HHCCF081I %s Will ignore include errors .\n"),
905                         fname);
906                 inc_ignore_errors = 1 ;
907             }
908 
909             continue ;
910         }
911 
912         /* Check for include statement */
913         if (strcasecmp (keyword, "include") == 0)
914         {
915             if (++inc_level >= MAX_INC_LEVEL)
916             {
917                 logmsg(_( "HHCCF082S Error in %s line %d: "
918                         "Maximum nesting level (%d) reached\n"),
919                         fname, inc_stmtnum[inc_level-1], MAX_INC_LEVEL);
920                 delayed_exit(1);
921             }
922 
923             logmsg( _("HHCCF083I %s Including %s at %d.\n"),
924                         fname, operand, inc_stmtnum[inc_level-1]);
925             hostpath(pathname, operand, sizeof(pathname));
926             inc_fp[inc_level] = fopen (pathname, "r");
927             if (inc_fp[inc_level] == NULL)
928             {
929                 inc_level--;
930                 if ( inc_ignore_errors == 1 )
931                 {
932                     logmsg(_("HHCCF084W %s Open error ignored file %s: %s\n"),
933                                     fname, operand, strerror(errno));
934                     continue ;
935                 }
936                 else
937                 {
938                     logmsg(_("HHCCF085S %s Open error file %s: %s\n"),
939                                     fname, operand, strerror(errno));
940                     delayed_exit(1);
941                 }
942             }
943             inc_stmtnum[inc_level] = 0;
944             continue;
945         }
946 #endif // defined( OPTION_ENHANCED_CONFIG_INCLUDE )
947 
948         /* Exit loop if first device statement found */
949         if (strlen(keyword) <= 4
950             && sscanf(keyword, "%x%c", &rc, &c) == 1)
951             break;
952         /* ISW */
953         /* Also exit if keyword contains '-', ',' or '.' */
954         /* Added because device statements may now be a compound device number specification */
955         if(strchr(keyword,'-'))
956         {
957             break;
958         }
959         if(strchr(keyword,'.'))
960         {
961             break;
962         }
963         if(strchr(keyword,','))
964         {
965             break;
966         }
967         /* Also exit if keyword contains ':' (added by Harold Grovesteen jan2008) */
968         /* Added because device statements may now contain channel set or LCSS id */
969         if(strchr(keyword,':'))
970         {
971             break;
972         }
973 
974         /* Clear the operand value pointers */
975         sserial = NULL;
976         smodel = NULL;
977         sversion = NULL;
978         smainsize = NULL;
979         sxpndsize = NULL;
980         smaxcpu = NULL;
981         snumcpu = NULL;
982         snumvec = NULL;
983         sengines = NULL;
984         ssysepoch = NULL;
985         syroffset = NULL;
986         stzoffset = NULL;
987         shercprio = NULL;
988         stodprio = NULL;
989         scpuprio = NULL;
990         sdevprio = NULL;
991         slogofile = NULL;
992 #if defined(_FEATURE_ECPSVM)
993         secpsvmlevel = NULL;
994         secpsvmlvl = NULL;
995         ecpsvmac = 0;
996 #endif /*defined(_FEATURE_ECPSVM)*/
997 
998 #if defined(OPTION_SHARED_DEVICES)
999         sshrdport = NULL;
1000 #endif /*defined(OPTION_SHARED_DEVICES)*/
1001 
1002         /* Check for old-style CPU statement */
1003         if (scount == 0 && addargc == 5 && strlen(keyword) == 6
1004             && sscanf(keyword, "%x%c", &rc, &c) == 1)
1005         {
1006             sserial = keyword;
1007             smodel = operand;
1008             smainsize = addargv[0];
1009             sxpndsize = addargv[1];
1010             config_cnslport = strdup(addargv[2]);
1011             snumcpu = addargv[3];
1012             set_loadparm(addargv[4]);
1013         }
1014         else
1015         {
1016             if (strcasecmp (keyword, "cpuserial") == 0)
1017             {
1018                 sserial = operand;
1019             }
1020             else if (strcasecmp (keyword, "cpumodel") == 0)
1021             {
1022                 smodel = operand;
1023             }
1024             else if (strcasecmp (keyword, "mainsize") == 0)
1025             {
1026                 smainsize = operand;
1027             }
1028             else if (strcasecmp (keyword, "xpndsize") == 0)
1029             {
1030                 sxpndsize = operand;
1031             }
1032             else if (strcasecmp (keyword, "cnslport") == 0)
1033             {
1034                 config_cnslport = strdup(operand);
1035             }
1036             else if (strcasecmp (keyword, "maxcpu") == 0)
1037             {
1038                 smaxcpu = operand;
1039             }
1040             else if (strcasecmp (keyword, "numcpu") == 0)
1041             {
1042                 snumcpu = operand;
1043             }
1044             else if (strcasecmp (keyword, "numvec") == 0)
1045             {
1046                 snumvec = operand;
1047             }
1048             else if (strcasecmp (keyword, "engines") == 0)
1049             {
1050                 sengines = operand;
1051             }
1052             else if (strcasecmp (keyword, "sysepoch") == 0)
1053             {
1054                 ssysepoch = operand;
1055                 if (addargc > 0)
1056                 {
1057                     syroffset = addargv[0];
1058                     addargc--;
1059                 }
1060             }
1061             else if (strcasecmp (keyword, "yroffset") == 0)
1062             {
1063                 syroffset = operand;
1064             }
1065             else if (strcasecmp (keyword, "tzoffset") == 0)
1066             {
1067                 stzoffset = operand;
1068             }
1069             else if (strcasecmp (keyword, "cpuverid") == 0)
1070             {
1071                 sversion = operand;
1072             }
1073             else if (strcasecmp (keyword, "hercprio") == 0)
1074             {
1075                 shercprio = operand;
1076             }
1077             else if (strcasecmp (keyword, "todprio") == 0)
1078             {
1079                 stodprio = operand;
1080             }
1081             else if (strcasecmp (keyword, "cpuprio") == 0)
1082             {
1083                 scpuprio = operand;
1084             }
1085             else if (strcasecmp (keyword, "devprio") == 0)
1086             {
1087                 sdevprio = operand;
1088             }
1089             else if (strcasecmp (keyword, "logofile") == 0)
1090             {
1091                 logmsg(_("HHCCF061W Warning in %s line %d: "
1092                     "LOGOFILE statement deprecated. Use HERCLOGO instead\n"),
1093                     fname, inc_stmtnum[inc_level]);
1094                 slogofile=operand;
1095             }
1096             else if (strcasecmp (keyword, "herclogo") == 0)
1097             {
1098                 slogofile=operand;
1099             }
1100 #if defined(_FEATURE_ECPSVM)
1101             /* ECPS:VM support */
1102             else if(strcasecmp(keyword, "ecps:vm") == 0)
1103             {
1104                 secpsvmlevel=operand;
1105                 secpsvmlvl=addargv[0];
1106                 ecpsvmac=addargc;
1107                 logmsg(_("HHCCF061W Warning in %s line %d: "
1108                     "ECPS:VM Statement deprecated. Use ECPSVM instead\n"),
1109                     fname, inc_stmtnum[inc_level]);
1110                 addargc=0;
1111             }
1112             else if(strcasecmp(keyword, "ecpsvm") == 0)
1113             {
1114                 secpsvmlevel=operand;
1115                 secpsvmlvl=addargv[0];
1116                 ecpsvmac=addargc;
1117                 addargc=0;
1118             }
1119 #endif /*defined(_FEATURE_ECPSVM)*/
1120 
1121 #if defined(OPTION_SHARED_DEVICES)
1122             else if (strcasecmp (keyword, "shrdport") == 0)
1123             {
1124                 sshrdport = operand;
1125             }
1126 #endif /*defined(OPTION_SHARED_DEVICES)*/
1127 
1128             else
1129             {
1130                 logmsg( _("HHCCF008E Error in %s line %d: "
1131                         "Syntax error: %s\n"),
1132                         fname, inc_stmtnum[inc_level], keyword);
1133                 operand = "";
1134                 addargc = 0;
1135             }
1136 
1137             /* Check for one and only one operand */
1138             if (operand == NULL || addargc != 0)
1139             {
1140                 logmsg( _("HHCCF009E Error in %s line %d: "
1141                         "Incorrect number of operands\n"),
1142                         fname, inc_stmtnum[inc_level]);
1143             }
1144 
1145         } /* end else (not old-style CPU statement) */
1146 
1147         /* Parse CPU version number operand */
1148         if (sversion != NULL)
1149         {
1150             if (strlen(sversion) != 2
1151                 || sscanf(sversion, "%hx%c", &version, &c) != 1
1152                 || version>255)
1153             {
1154                 logmsg(_("HHCCF012S Error in %s line %d: "
1155                         "%s is not a valid CPU version code\n"),
1156                         fname, inc_stmtnum[inc_level], sversion);
1157                 delayed_exit(1);
1158             }
1159             dfltver = 0;
1160         }
1161 
1162         /* Parse CPU serial number operand */
1163         if (sserial != NULL)
1164         {
1165             if (strlen(sserial) != 6
1166                 || sscanf(sserial, "%x%c", &serial, &c) != 1)
1167             {
1168                 logmsg(_("HHCCF051S Error in %s line %d: "
1169                         "%s is not a valid serial number\n"),
1170                         fname, inc_stmtnum[inc_level], sserial);
1171                 delayed_exit(1);
1172             }
1173         }
1174 
1175         /* Parse CPU model number operand */
1176         if (smodel != NULL)
1177         {
1178             if (strlen(smodel) != 4
1179                 || sscanf(smodel, "%hx%c", &model, &c) != 1)
1180             {
1181                 logmsg(_("HHCCF012S Error in %s line %d: "
1182                         "%s is not a valid CPU model\n"),
1183                         fname, inc_stmtnum[inc_level], smodel);
1184                 delayed_exit(1);
1185             }
1186         }
1187 
1188         /* Parse main storage size operand */
1189         if (smainsize != NULL)
1190         {
1191             if (sscanf(smainsize, "%u%c", &mainsize, &c) != 1
1192              || mainsize < 2
1193              || (mainsize > 4095 && sizeof(sysblk.mainsize) < 8)
1194              || (mainsize > 4095 && sizeof(size_t) < 8))
1195             {
1196                 logmsg(_("HHCCF013S Error in %s line %d: "
1197                         "Invalid main storage size %s\n"),
1198                         fname, inc_stmtnum[inc_level], smainsize);
1199                 delayed_exit(1);
1200             }
1201         }
1202 
1203         /* Parse expanded storage size operand */
1204         if (sxpndsize != NULL)
1205         {
1206             if (sscanf(sxpndsize, "%u%c", &xpndsize, &c) != 1
1207                 || xpndsize > (0x100000000ULL / XSTORE_PAGESIZE) - 1
1208                 || (xpndsize > 4095 && sizeof(size_t) < 8))
1209             {
1210                 logmsg(_("HHCCF014S Error in %s line %d: "
1211                         "Invalid expanded storage size %s\n"),
1212                         fname, inc_stmtnum[inc_level], sxpndsize);
1213                 delayed_exit(1);
1214             }
1215         }
1216 
1217         /* Parse Hercules priority operand */
1218         if (shercprio != NULL)
1219             if (sscanf(shercprio, "%d%c", &hercprio, &c) != 1)
1220             {
1221                 logmsg(_("HHCCF016S Error in %s line %d: "
1222                         "Invalid Hercules process group thread priority %s\n"),
1223                         fname, inc_stmtnum[inc_level], shercprio);
1224                 delayed_exit(1);
1225             }
1226 
1227 #if !defined(NO_SETUID)
1228         if(sysblk.suid != 0 && hercprio < 0)
1229         {
1230             logmsg(_("HHCCF017W Hercules is not running as setuid root, "
1231                     "cannot raise Hercules process group thread priority\n"));
1232             hercprio = 0;               /* Set priority to Normal     */
1233         }
1234 #endif /*!defined(NO_SETUID)*/
1235 
1236         sysblk.hercprio = hercprio;
1237 
1238         /* Parse TOD Clock priority operand */
1239         if (stodprio != NULL)
1240             if (sscanf(stodprio, "%d%c", &todprio, &c) != 1)
1241             {
1242                 logmsg(_("HHCCF016S Error in %s line %d: "
1243                         "Invalid TOD Clock thread priority %s\n"),
1244                         fname, inc_stmtnum[inc_level], stodprio);
1245                 delayed_exit(1);
1246             }
1247 
1248 #if !defined(NO_SETUID)
1249         if(sysblk.suid != 0 && todprio < 0)
1250         {
1251             logmsg(_("HHCCF017W Hercules is not running as setuid root, "
1252                     "cannot raise TOD Clock thread priority\n"));
1253             todprio = 0;                /* Set priority to Normal     */
1254         }
1255 #endif /*!defined(NO_SETUID)*/
1256 
1257         sysblk.todprio = todprio;
1258 
1259         /* Parse CPU thread priority operand */
1260         if (scpuprio != NULL)
1261             if (sscanf(scpuprio, "%d%c", &cpuprio, &c) != 1)
1262             {
1263                 logmsg(_("HHCCF016S Error in %s line %d: "
1264                         "Invalid CPU thread priority %s\n"),
1265                         fname, inc_stmtnum[inc_level], scpuprio);
1266                 delayed_exit(1);
1267             }
1268 
1269 #if !defined(NO_SETUID)
1270         if(sysblk.suid != 0 && cpuprio < 0)
1271         {
1272             logmsg(_("HHCCF017W Hercules is not running as setuid root, "
1273                     "cannot raise CPU priority\n"));
1274             cpuprio = 0;                /* Set priority to Normal     */
1275         }
1276 #endif /*!defined(NO_SETUID)*/
1277 
1278             sysblk.cpuprio = cpuprio;
1279 
1280         /* Parse Device thread priority operand */
1281         if (sdevprio != NULL)
1282             if (sscanf(sdevprio, "%d%c", &devprio, &c) != 1)
1283             {
1284                 logmsg(_("HHCCF016S Error in %s line %d: "
1285                         "Invalid device thread priority %s\n"),
1286                         fname, inc_stmtnum[inc_level], sdevprio);
1287                 delayed_exit(1);
1288             }
1289 
1290 #if !defined(NO_SETUID)
1291         if(sysblk.suid != 0 && devprio < 0)
1292             logmsg(_("HHCCF017W Hercules is not running as setuid root, "
1293                     "cannot raise device thread priority\n"));
1294 #endif /*!defined(NO_SETUID)*/
1295 
1296         sysblk.devprio = devprio;
1297 
1298         /* Parse Device thread priority operand */
1299         if (sdevprio != NULL)
1300             if (sscanf(sdevprio, "%d%c", &devprio, &c) != 1)
1301             {
1302                 logmsg(_("HHCCF016S Error in %s line %d: "
1303                         "Invalid device thread priority %s\n"),
1304                         fname, inc_stmtnum[inc_level], sdevprio);
1305                 delayed_exit(1);
1306             }
1307 
1308 #if !defined(NO_SETUID)
1309         if(sysblk.suid != 0 && devprio < 0)
1310             logmsg(_("HHCCF017W Hercules is not running as setuid root, "
1311                     "cannot raise device thread priority\n"));
1312 #endif /*!defined(NO_SETUID)*/
1313 
1314         sysblk.devprio = devprio;
1315 
1316         /* Parse maximum number of CPUs operand */
1317         if (smaxcpu != NULL)
1318         {
1319             if (sscanf(smaxcpu, "%hu%c", &maxcpu, &c) != 1
1320                 || maxcpu < 1
1321                 || maxcpu > MAX_CPU_ENGINES)
1322             {
1323                 fprintf(stderr, _("HHCCF021S Error in %s line %d: "
1324                         "Invalid maximum number of CPUs %s\n"),
1325                         fname, inc_stmtnum[inc_level], smaxcpu);
1326                 delayed_exit(1);
1327             }
1328         }
1329 
1330         /* Parse number of CPUs operand */
1331         if (snumcpu != NULL)
1332         {
1333             if (sscanf(snumcpu, "%hu%c", &numcpu, &c) != 1
1334                 || numcpu > MAX_CPU_ENGINES)
1335             {
1336                 logmsg(_("HHCCF018S Error in %s line %d: "
1337                         "Invalid number of CPUs %s\n"),
1338                         fname, inc_stmtnum[inc_level], snumcpu);
1339                 delayed_exit(1);
1340             }
1341         }
1342         sysblk.numcpu = numcpu ? numcpu : 1;
1343 
1344         /* Parse number of VFs operand */
1345         if (snumvec != NULL)
1346         {
1347 #ifdef _FEATURE_VECTOR_FACILITY
1348             if (sscanf(snumvec, "%hu%c", &numvec, &c) != 1
1349                 || numvec > MAX_CPU_ENGINES)
1350             {
1351                 logmsg(_("HHCCF019S Error in %s line %d: "
1352                         "Invalid number of VFs %s\n"),
1353                         fname, inc_stmtnum[inc_level], snumvec);
1354                 delayed_exit(1);
1355             }
1356 #else /*!_FEATURE_VECTOR_FACILITY*/
1357             logmsg(_("HHCCF020W Vector Facility support not configured\n"));
1358 #endif /*!_FEATURE_VECTOR_FACILITY*/
1359         }
1360         sysblk.numvec = numvec;
1361 
1362         /* Parse processor engine types operand */
1363         /* example: ENGINES 4*CP,AP,2*IP */
1364         if (sengines != NULL)
1365         {
1366             styp = strtok(sengines,",");
1367             for (cpu = 0; styp != NULL; )
1368             {
1369                 count = 1;
1370                 if (isdigit(styp[0]))
1371                 {
1372                     if (sscanf(styp, "%d%c", &count, &c) != 2
1373                         || c != '*' || count < 1)
1374                     {
1375                         logmsg(_("HHCCF074S Error in %s line %d: "
1376                                 "Invalid engine syntax %s\n"),
1377                                 fname, inc_stmtnum[inc_level], styp);
1378                         delayed_exit(1);
1379                         break;
1380                     }
1381                     styp = strchr(styp,'*') + 1;
1382                 }
1383                 if (strcasecmp(styp,"cp") == 0)
1384                     ptyp = SCCB_PTYP_CP;
1385                 else if (strcasecmp(styp,"cf") == 0)
1386                     ptyp = SCCB_PTYP_ICF;
1387                 else if (strcasecmp(styp,"il") == 0)
1388                     ptyp = SCCB_PTYP_IFL;
1389                 else if (strcasecmp(styp,"ap") == 0)
1390                     ptyp = SCCB_PTYP_IFA;
1391                 else if (strcasecmp(styp,"ip") == 0)
1392                     ptyp = SCCB_PTYP_SUP;
1393                 else {
1394                     logmsg(_("HHCCF075S Error in %s line %d: "
1395                             "Invalid engine type %s\n"),
1396                             fname, inc_stmtnum[inc_level], styp);
1397                     delayed_exit(1);
1398                     break;
1399                 }
1400                 while (count-- > 0 && cpu < MAX_CPU_ENGINES)
1401                 {
1402                     logmsg("HHCCF077I Engine %d set to type %d (%s)\n",
1403                             cpu, ptyp, styp_values[ptyp]);
1404                     sysblk.ptyp[cpu++] = ptyp;
1405                 }
1406                 styp = strtok(NULL,",");
1407             }
1408         }
1409 
1410         /* Parse system epoch operand */
1411         if (ssysepoch != NULL)
1412         {
1413             if (strlen(ssysepoch) != 4
1414                 || sscanf(ssysepoch, "%d%c", &sysepoch, &c) != 1
1415                 || sysepoch <= 1800 || sysepoch >= 2100)
1416             {
1417                 logmsg(_("HHCCF022S Error in %s line %d: "
1418                         "%s is not a valid system epoch.\n"
1419                         "          The only valid values are "
1420                         "1801-2099\n"),
1421                         fname, inc_stmtnum[inc_level], ssysepoch);
1422                 delayed_exit(1);
1423             }
1424         }
1425 
1426         /* Parse year offset operand */
1427         if (syroffset != NULL)
1428         {
1429             if (sscanf(syroffset, "%d%c", &yroffset, &c) != 1
1430                 || (yroffset < -142) || (yroffset > 142))
1431             {
1432                 logmsg(_("HHCCF070S Error in %s line %d: "
1433                         "%s is not a valid year offset\n"),
1434                         fname, inc_stmtnum[inc_level], syroffset);
1435                 delayed_exit(1);
1436             }
1437         }
1438 
1439         /* Parse timezone offset operand */
1440         if (stzoffset != NULL)
1441         {
1442             if (strlen(stzoffset) != 5
1443                 || sscanf(stzoffset, "%d%c", &tzoffset, &c) != 1
1444                 || (tzoffset < -2359) || (tzoffset > 2359))
1445             {
1446                 logmsg(_("HHCCF023S Error in %s line %d: "
1447                         "%s is not a valid timezone offset\n"),
1448                         fname, inc_stmtnum[inc_level], stzoffset);
1449                 delayed_exit(1);
1450             }
1451         }
1452 
1453 
1454         /* Parse terminal logo option */
1455         if (slogofile != NULL)
1456         {
1457             strncpy(hlogofile, slogofile, sizeof(hlogofile)-1);
1458             hlogofile[sizeof(hlogofile)-1] = '\0';
1459         }
1460 
1461 #if defined(_FEATURE_ECPSVM)
1462         /* Parse ECPS:VM level */
1463         if(secpsvmlevel != NULL)
1464         {
1465             while(1)        /* Dummy while loop for break support */
1466             {
1467                 ecpsvmavail=0;
1468                 ecpsvmlevel=0;
1469                 if(strcasecmp(secpsvmlevel,"no")==0)
1470                 {
1471                     ecpsvmavail=0;
1472                     break;
1473                 }
1474                 if(strcasecmp(secpsvmlevel,"yes")==0)
1475                 {
1476                     ecpsvmavail=1;
1477                     ecpsvmlevel=20;
1478                     break;
1479                 }
1480                 if(strcasecmp(secpsvmlevel,"level")==0)
1481                 {
1482                     ecpsvmavail=1;
1483                     if(ecpsvmac==0)
1484                     {
1485                         logmsg(_("HHCCF062W Warning in %s line %d: "
1486                                 "Missing ECPSVM level value. 20 Assumed\n"),
1487                                 fname, inc_stmtnum[inc_level]);
1488                         ecpsvmavail=1;
1489                         ecpsvmlevel=20;
1490                         break;
1491                     }
1492                     if (sscanf(secpsvmlvl, "%d%c", &ecpsvmlevel, &c) != 1)
1493                     {
1494                         logmsg(_("HHCCF051W Warning in %s line %d: "
1495                                 "Invalid ECPSVM level value : %s. 20 Assumed\n"),
1496                                 fname, inc_stmtnum[inc_level], secpsvmlevel);
1497                         ecpsvmavail=1;
1498                         ecpsvmlevel=20;
1499                         break;
1500                     }
1501                     break;
1502                 }
1503                 ecpsvmavail=1;
1504                 if (sscanf(secpsvmlevel, "%d%c", &ecpsvmlevel, &c) != 1)
1505                 {
1506                     logmsg(_("HHCCF051W Error in %s line %d: "
1507                             "Invalid ECPSVM keyword : %s. NO Assumed\n"),
1508                             fname, inc_stmtnum[inc_level], secpsvmlevel);
1509                     ecpsvmavail=0;
1510                     ecpsvmlevel=0;
1511                     break;
1512                 }
1513                 else
1514                 {
1515                     logmsg(_("HHCCF063W Warning in %s line %d: "
1516                             "Specifying ECPSVM level directly is deprecated. Use the 'LEVEL' keyword instead.\n"),
1517                             fname, inc_stmtnum[inc_level]);
1518                     break;
1519                 }
1520                 break;
1521             }
1522             sysblk.ecpsvm.available=ecpsvmavail;
1523             sysblk.ecpsvm.level=ecpsvmlevel;
1524         }
1525 #endif /*defined(_FEATURE_ECPSVM)*/
1526 
1527 #if defined(OPTION_SHARED_DEVICES)
1528         /* Parse shared device port number operand */
1529         if (sshrdport != NULL)
1530         {
1531             if (sscanf(sshrdport, "%hu%c", &shrdport, &c) != 1
1532                 || shrdport < 1024 )
1533             {
1534                 logmsg(_("HHCCF029S Error in %s line %d: "
1535                         "Invalid SHRDPORT port number %s\n"),
1536                         fname, inc_stmtnum[inc_level], sshrdport);
1537                 delayed_exit(1);
1538             }
1539         }
1540 #endif /*defined(OPTION_SHARED_DEVICES)*/
1541 
1542     } /* end for(scount) (end of configuration file statement loop) */
1543 
1544     /* Read the logofile */
1545     if (sysblk.logofile == NULL) /* LogoFile NOT passed in command line */
1546     {
1547         if (hlogofile[0] != '\0') /* LogoFile SET in hercules config */
1548         {
1549             readlogo(hlogofile);
1550         }
1551         else /* Try to Read Logo File using Default FileName */
1552         {
1553             slogofile=getenv("HERCLOGO");
1554             if (slogofile==NULL)
1555             {
1556                 readlogo("herclogo.txt");
1557             }
1558             else
1559             {
1560                 readlogo(slogofile);
1561             }
1562         } /* Otherwise Use Internal LOGO */
1563     }
1564     else /* LogoFile passed in command line */
1565     {
1566         readlogo(sysblk.logofile);
1567     }
1568 
1569 #if defined( OPTION_TAPE_AUTOMOUNT )
1570     /* Define default AUTOMOUNT directory if needed */
1571     if (sysblk.tamdir && sysblk.defdir == NULL)
1572     {
1573         char cwd[ MAX_PATH ];
1574         TAMDIR *pNewTAMDIR = malloc( sizeof(TAMDIR) );
1575         if (!pNewTAMDIR)
1576         {
1577             logmsg( _("HHCCF900S Out of memory!\n"));
1578             delayed_exit(1);
1579         }
1580         VERIFY( getcwd( cwd, sizeof(cwd) ) != NULL );
1581         rc = strlen( cwd );
1582         if (cwd[rc-1] != *PATH_SEP)
1583             strlcat (cwd, PATH_SEP, sizeof(cwd));
1584         pNewTAMDIR->dir = strdup (cwd);
1585         pNewTAMDIR->len = strlen (cwd);
1586         pNewTAMDIR->rej = 0;
1587         pNewTAMDIR->next = sysblk.tamdir;
1588         sysblk.tamdir = pNewTAMDIR;
1589         sysblk.defdir = pNewTAMDIR->dir;
1590         logmsg(_("HHCCF090I Default Allowed AUTOMOUNT directory = \"%s\"\n"),
1591             sysblk.defdir);
1592     }
1593 #endif /* OPTION_TAPE_AUTOMOUNT */
1594 
1595     /* Set root mode in order to set priority */
1596     SETMODE(ROOT);
1597 
1598     /* Set Hercules base priority */
1599     if (setpriority(PRIO_PGRP, 0, hercprio))
1600         logmsg (_("HHCCF064W Hercules set priority %d failed: %s\n"),
1601                 hercprio, strerror(errno));
1602 
1603     /* Back to user mode */
1604     SETMODE(USER);
1605 
1606     /* Display Hercules thread information on control panel */
1607     logmsg (_("HHCCF065I Hercules: tid="TIDPAT", pid=%d, pgid=%d, "
1608               "priority=%d\n"),
1609             thread_id(), getpid(), getpgrp(),
1610             getpriority(PRIO_PGRP,0));
1611 
1612 #if defined(OPTION_SHARED_DEVICES)
1613     sysblk.shrdport = shrdport;
1614 #endif /*defined(OPTION_SHARED_DEVICES)*/
1615 
1616 #if defined(_370) || defined(_390)
1617     if(dfltver)
1618         version =
1619 #if defined(_900)
1620                   (sysblk.arch_mode == ARCH_900) ? 0x00 :
1621 #endif
1622                                                           0xFD;
1623 #endif
1624     /* Build CPU identifier */
1625     sysblk.cpuid = ((U64)version << 56)
1626                  | ((U64)serial << 32)
1627                  | ((U64)model << 16);
1628 
1629     /* Reset the clock steering registers */
1630     csr_reset();
1631 
1632     /* Set up the system TOD clock offset: compute the number of
1633      * microseconds offset to 0000 GMT, 1 January 1900 */
1634 
1635     if(sysepoch != 1900 && sysepoch != 1960)
1636     {
1637         if(sysepoch < 1960)
1638             logmsg(_("HHCCF072W SYSEPOCH %04d is deprecated. "
1639                      "Please specify \"SYSEPOCH 1900 %s%d\".\n"),
1640                      sysepoch, 1900-sysepoch > 0 ? "+" : "", 1900-sysepoch);
1641         else
1642             logmsg(_("HHCCF073W SYSEPOCH %04d is deprecated. "
1643                      "Please specify \"SYSEPOCH 1960 %s%d\".\n"),
1644                      sysepoch, 1960-sysepoch > 0 ? "+" : "", 1960-sysepoch);
1645     }
1646 
1647     if(sysepoch == 1960 || sysepoch == 1988)
1648         ly1960 = TOD_DAY;
1649     else
1650         ly1960 = 0;
1651 
1652     sysepoch -= 1900 + yroffset;
1653 
1654     set_tod_epoch(((sysepoch*365+(sysepoch/4))*-TOD_DAY)+lyear_adjust(sysepoch)+ly1960);
1655 
1656     sysblk.sysepoch = sysepoch;
1657 
1658     /* Set the timezone offset */
1659     adjust_tod_epoch((tzoffset/100*3600+(tzoffset%100)*60)*16000000LL);
1660 
1661     /* Gabor Hoffer (performance option) */
1662     copy_opcode_tables();
1663 
1664     /*****************************************************************/
1665     /* Parse configuration file device statements...                 */
1666     /*****************************************************************/
1667 
1668     while(1)
1669     {
1670         /* First two fields are device number and device type */
1671         sdevnum = keyword;
1672         sdevtype = operand;
1673 
1674         if (sdevnum == NULL || sdevtype == NULL)
1675         {
1676             logmsg(_("HHCCF035S Error in %s line %d: "
1677                     "Missing device number or device type\n"),
1678                     fname, inc_stmtnum[inc_level]);
1679             delayed_exit(1);
1680         }
1681         /* Parse devnum */
1682         rc=parse_and_attach_devices(sdevnum,sdevtype,addargc,addargv);
1683 
1684         if(rc==-2)
1685         {
1686             logmsg(_("HHCCF036S Error in %s line %d: "
1687                     "%s is not a valid device number(s) specification\n"),
1688                     fname, inc_stmtnum[inc_level], sdevnum);
1689             delayed_exit(1);
1690         }
1691 
1692         /* Read next device record from the configuration file */
1693 #if defined( OPTION_ENHANCED_CONFIG_INCLUDE )
1694         while (1)
1695         {
1696             while (inc_level >= 0 && read_config (fname, inc_fp[inc_level]) )
1697             {
1698                 fclose (inc_fp[inc_level--]);
1699             }
1700 
1701             if (inc_level < 0 || strcasecmp (keyword, "include") != 0)
1702                 break;
1703 
1704             if (++inc_level >= MAX_INC_LEVEL)
1705             {
1706                 logmsg(_( "HHCCF082S Error in %s line %d: "
1707                         "Maximum nesting level (%d) reached\n"),
1708                         fname, inc_stmtnum[inc_level-1], MAX_INC_LEVEL);
1709                 delayed_exit(1);
1710             }
1711 
1712             logmsg( _("HHCCF083I %s Including %s at %d .\n"),
1713                         fname, operand, inc_stmtnum[inc_level-1]);
1714             hostpath(pathname, operand, sizeof(pathname));
1715             inc_fp[inc_level] = fopen (pathname, "r");
1716             if (inc_fp[inc_level] == NULL)
1717             {
1718                 inc_level--;
1719                 if ( inc_ignore_errors == 1 )
1720                 {
1721                     logmsg(_("HHCCF084W %s Open error ignored file %s: %s\n"),
1722                                     fname, operand, strerror(errno));
1723                     continue ;
1724                 }
1725                 else
1726                 {
1727                     logmsg(_("HHCCF085E %s Open error file %s: %s\n"),
1728                                     fname, operand, strerror(errno));
1729                     delayed_exit(1);
1730                 }
1731             }
1732             inc_stmtnum[inc_level] = 0;
1733             continue;
1734         }
1735 
1736         if (inc_level < 0)
1737 #else // !defined( OPTION_ENHANCED_CONFIG_INCLUDE )
1738         if (read_config (fname, inc_fp[inc_level]))
1739 #endif // defined( OPTION_ENHANCED_CONFIG_INCLUDE )
1740             break;
1741 
1742     } /* end while(1) */
1743 
1744 #if !defined( OPTION_ENHANCED_CONFIG_INCLUDE )
1745     /* close configuration file */
1746     rc = fclose(inc_fp[inc_level]);
1747 #endif // !defined( OPTION_ENHANCED_CONFIG_INCLUDE )
1748 
1749     /* Now configure storage.  We do this after processing the device
1750      * statements so the fork()ed hercifc process won't require as much
1751      * virtual storage.  We will need to update all the devices too.
1752      */
1753     config_storage(mainsize, xpndsize);
1754     for (dev = sysblk.firstdev; dev; dev = dev->nextdev)
1755     {
1756         dev->mainstor = sysblk.mainstor;
1757         dev->storkeys = sysblk.storkeys;
1758         dev->mainlim = sysblk.mainsize - 1;
1759     }
1760 
1761 #if defined(_FEATURE_REGION_RELOCATE)
1762     /* Initialize base zone storage view (SIE compat) */
1763     for(i = 0; i < FEATURE_SIE_MAXZONES; i++)
1764     {
1765         sysblk.zpb[i].mso = 0;
1766         sysblk.zpb[i].msl = (sysblk.mainsize - 1) >> 20;
1767         if(sysblk.xpndsize)
1768         {
1769             sysblk.zpb[i].eso = 0;
1770             sysblk.zpb[i].esl = ((size_t)sysblk.xpndsize * XSTORE_PAGESIZE - 1) >> 20;
1771         }
1772         else
1773         {
1774             sysblk.zpb[i].eso = -1;
1775             sysblk.zpb[i].esl = -1;
1776         }
1777     }
1778 #endif
1779 
1780     /* Initialize dummy regs.
1781      * Dummy regs are used by the panel or gui when the target cpu
1782      * (sysblk.pcpu) is not configured (ie cpu_thread not started).
1783      */
1784     sysblk.dummyregs.mainstor = sysblk.mainstor;
1785     sysblk.dummyregs.psa = (PSA*)sysblk.mainstor;
1786     sysblk.dummyregs.storkeys = sysblk.storkeys;
1787     sysblk.dummyregs.mainlim = sysblk.mainsize - 1;
1788     sysblk.dummyregs.dummy = 1;
1789     initial_cpu_reset (&sysblk.dummyregs);
1790     sysblk.dummyregs.arch_mode = sysblk.arch_mode;
1791     sysblk.dummyregs.hostregs = &sysblk.dummyregs;
1792 
1793 #ifdef OPTION_SELECT_KLUDGE
1794     /* Release the dummy file descriptors */
1795     for (i = 0; i < OPTION_SELECT_KLUDGE; i++)
1796         close(dummyfd[i]);
1797 #endif
1798 
1799     /* Set default maximum number of CPUs */
1800 #ifdef _FEATURE_CPU_RECONFIG
1801     sysblk.maxcpu = sysblk.arch_mode == ARCH_370 ? numcpu : MAX_CPU_ENGINES;
1802 #else
1803     sysblk.maxcpu = numcpu;
1804 #endif /*_FEATURE_CPU_RECONFIG*/
1805 
1806     /* Set maximum number of CPUs to specified value */
1807     if (maxcpu > 0) {
1808         sysblk.maxcpu = maxcpu;
1809     }
1810 
1811     /* Check that numcpu does not exceed maxcpu */
1812     if (sysblk.numcpu > sysblk.maxcpu) {
1813         logmsg(_("HHCCF086S Error in %s: NUMCPU %d must not exceed MAXCPU %d\n"),
1814                 fname, sysblk.numcpu, sysblk.maxcpu);
1815         delayed_exit(1);
1816     }
1817 
1818     /* Start the CPUs */
1819     OBTAIN_INTLOCK(NULL);
1820     for(i = 0; i < numcpu; i++)
1821         configure_cpu(i);
1822     RELEASE_INTLOCK(NULL);
1823 
1824 } /* end function build_config */
1825 
1826 #endif /*!defined(_GEN_ARCH)*/
1827