source: trunk/src/libsrc/util/startstop_unix_generic.c @ 3177

Revision 3177, 60.2 KB checked in by paulf, 12 years ago (diff)

fixed check for classname

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1
2 /********************************************************************
3  *                     Startstop_Unix_Generic                       *
4  *                                                                  *
5  *  Unlike most of Earthworm where "unix" means "Linux", in this    *
6  *  case "unix" means "unix", which covers both Linux and Solaris.  *
7  *  This basically was startstop main() for Linux and Solaris.      *
8  *  Dropped in this library here so that it can be easily accessed  *
9  *  by all unix platforms. If you need to make changes, please      *
10  *  put them in here with #ifdefs rather than creating new code     *
11  *  branches.                                                       *
12
13  ********************************************************************/
14#include <startstop_unix_generic.h>
15
16#define VERSION "v7.1 2007-02-26"
17#define PROGRAM_NAME "startstop"
18
19int RunEarthworm ( int argc, char *argv[] )
20{
21   /* Allot space for status message
22    ********************************/
23   int  i, j, rc, placeholder;
24   char *runPath;
25   char      msg[512];
26   long      msgsize = 0L;
27   MSG_LOGO  getLogo[4]; /* if you change this '3' here, you need to change the parameter to tport_getmsg as well */
28   MSG_LOGO  msglogo;
29#ifdef _USE_POSIX_SIGNALS
30   struct sigaction act;
31#endif
32
33   done=0;
34
35   strcpy ( metaring.Version, VERSION );
36/* Set name of configuration file
37   ******************************/
38   strcpy ( metaring.ConfigFile, DEF_CONFIG );
39   if ( argc == 2 ) {
40         if ((strlen(argv[1]) == 2) /* checking for /v or -v or /h or -h */
41                  && ((argv[1][0] == '/')
42                  || (argv[1][0] == '-'))) {
43            if ((argv[1][1] == 'v') || (argv[1][1] == 'V')) {
44                printf("%s %s\n",PROGRAM_NAME, VERSION);
45            } else if ((argv[1][1] == 'h') || (argv[1][1] == 'H')) {
46                printf("%s %s\n",PROGRAM_NAME, VERSION);
47                printf("usage: %s <config file name>\n", PROGRAM_NAME);
48                printf("       If no config file name is used, then the default config file is used,\n");
49                printf("       in this case %s.\n", DEF_CONFIG);
50            }
51            exit (0);
52        } else {
53            strcpy ( metaring.ConfigFile, argv[1] );
54            logit_init( argv[1], (short) metaring.MyModId, MAXLINE*3, metaring.LogSwitch );
55        }
56    }
57
58   fprintf( stderr, "startstop: Using config file %s\n", metaring.ConfigFile );
59
60/* Change working directory to environment variable EW_PARAMS value
61   ***************************************************************/
62   runPath = getenv( "EW_PARAMS" );
63
64   if ( runPath == NULL )
65   {
66      printf( "startstop: Environment variable EW_PARAMS not defined." );
67      printf( " Exiting.\n" );
68      exit (-1);
69   }
70
71   if ( *runPath == '\0' )
72   {
73      printf( "startstop: Environment variable EW_PARAMS " );
74      printf( "defined, but has no value. Exiting.\n" );
75      exit (-1);
76   }
77
78   if ( chdir( runPath ) == -1 )
79   {
80      printf( "startstop: Params directory not found: %s\n", runPath );
81      printf( "startstop: Reset environment variable EW_PARAMS." );
82      printf( " Exiting.\n" );
83      exit (-1);
84   }
85
86   LockStartstop(metaring.ConfigFile, argv[0]);
87
88/* Set our "nice" value back to the default value.
89 * This does nothing if you started at the default.
90 * Requested by D. Chavez, University of Utah.
91 *************************************************/
92 nice( -nice( 0 ) );
93
94/* Catch process termination signals
95   *********************************/
96#ifdef _USE_POSIX_SIGNALS
97   act.sa_flags = SA_SIGINFO; sigemptyset(&act.sa_mask);
98   act.sa_sigaction = SigtermHandler;
99   sigaction(SIGTERM, &act, (struct sigaction *)NULL);
100   act.sa_flags = 0;
101   act.sa_handler = SIG_IGN;
102   sigaction(SIGINT, &act, (struct sigaction *)NULL);
103   sigaction(SIGQUIT, &act, (struct sigaction *)NULL);
104   sigaction(SIGTTIN, &act, (struct sigaction *)NULL);
105#else
106   sigignore( SIGINT );             /* Control-c */
107   sigignore( SIGQUIT );            /* Control-\ */
108#ifdef NEEDTOFIXTHIS_DEBUG
109   sigset( SIGTERM, SigtermHandler );
110#endif
111
112/* Catch tty input signal, in case we are in background */
113   sigignore( SIGTTIN );
114#endif
115
116/* Allocate array of children
117   **************************/
118   child = (CHILD *) calloc( MAX_CHILD, sizeof(CHILD) );
119   for (i = 0; i < MAX_CHILD; i++) {
120     for (j = 0; j < MAX_ARG; j++)
121       child[i].argv[j] = NULL;
122     child[i].use_uname[0] = '\0';
123     child[i].use_gname[0] = '\0';
124   }
125
126
127/* Read configuration parameters
128   *****************************/
129   nChild    = 0;
130   GetConfig();
131
132/* Allocate one region structure per ring
133   **************************************/
134   metaring.Region = (SHM_INFO *) calloc( (size_t)MAX_RING, sizeof(SHM_INFO) );
135   if ( metaring.Region == NULL )
136   {
137      printf( "startstop: Error allocating region structures. Exiting.\n" );
138      return -1;
139   }
140
141/* Look up this installation id
142   ****************************/
143   if ( GetLocalInst ( &(metaring.InstId) ) != 0 )
144   {
145      printf( "startstop: Error getting local installation id. Exiting.\n" );
146      return -1;
147   }
148
149/* Look up module id & message types of interest
150   *********************************************/
151   if ( GetModId( metaring.MyModName, &(metaring.MyModId) ) != 0 )
152   {
153      printf( "startstop: Invalid module name <%s>. Exiting.\n", metaring.MyModName );
154      return -1;
155   }
156
157   if ( GetModId( "MOD_WILDCARD", &(metaring.ModWildcard) ) != 0 )
158   {
159      printf( "startstop: Invalid module name <MOD_WILDCARD>. Exiting.\n" );
160      return -1;
161   }
162
163   if ( GetType( "TYPE_HEARTBEAT", &(metaring.TypeHeartBeat) ) != 0 )
164   {
165      printf( "startstop: Unknown message type <TYPE_HEARTBEAT>. Exiting.\n" );
166      return -1;
167   }
168
169   if ( GetType( "TYPE_ERROR", &(metaring.TypeError) ) != 0 )
170   {
171      printf( "startstop: Unknown message type <TYPE_ERROR>. Exiting.\n" );
172      return -1;
173   }
174
175   if ( GetType( "TYPE_RESTART", &(metaring.TypeRestart) ) != 0 )
176   {
177      printf( "startstop: Unknown message type <TYPE_RESTART>. Exiting.\n" );
178      return -1;
179   }
180
181   if ( GetType( "TYPE_STOP", &(metaring.TypeStop) ) != 0 )
182   {
183      printf( "startstop: Unknown message type <TYPE_STOP>. Exiting.\n" );
184      return -1;
185   }
186   if ( GetType( "TYPE_REQSTATUS", &(metaring.TypeReqStatus) ) != 0 )
187   {
188      printf( "startstop: Unknown message type <TYPE_REQSTATUS>. Exiting.\n" );
189      return -1;
190   }
191
192   if ( GetType( "TYPE_STATUS", &(metaring.TypeStatus) ) != 0 )
193   {
194      printf( "startstop: Unknown message type <TYPE_STATUS>. Exiting.\n" );
195      return -1;
196   }
197
198   if ( GetType( "TYPE_RECONFIG", &(metaring.TypeReconfig) ) != 0 )
199   {
200      printf( "startstop: Unknown message type <TYPE_RECONFIG>. Exiting.\n" );
201      return -1;
202   }
203
204   parent.pid = getpid();
205   parent.processName = argv[0];
206   parent.args = (argc == 2 ? argv[1] : (char *)NULL);
207
208/* Initialize name of log-file & open it
209   *************************************/
210   if ( argc == 2 )
211     logit_init( argv[1], (short) metaring.MyModId, MAXLINE*3, metaring.LogSwitch );
212   else
213     logit_init( argv[0], (short) metaring.MyModId, MAXLINE*3, metaring.LogSwitch );
214
215   logit( "" , "startstop: Read command file <%s>\n", metaring.ConfigFile );
216
217/* Make startstop be the process group leader */
218   if ( setpgid( parent.pid, parent.pid ) != 0 )
219     logit( "e", "startstop: failed to set process group ID\n" );
220
221/* Set the priority of startstop
222   *****************************/
223   SetPriority( P_MYID, parent.className, parent.priority );
224
225/* Start everything
226   ****************/
227   StartEarthworm( argv[0] );
228/* Watch transport rings for kill flags, status requests & restart requests
229   ************************************************************************/
230
231   for (i = 0; i < 4; i++) {
232       getLogo[i].instid = metaring.InstId;
233       getLogo[i].mod    = metaring.ModWildcard;
234   }
235
236   getLogo[0].type   = metaring.TypeRestart;
237   getLogo[1].type   = metaring.TypeReqStatus;
238   getLogo[2].type   = metaring.TypeReconfig;
239   getLogo[3].type   = metaring.TypeStop;
240
241
242   while ( !done )
243   {
244   /* Send hearbeat, if it's time
245    *****************************/
246      Heartbeat( &metaring );
247      for ( i = 0; i < metaring.nRing; i++ )
248      {
249      /* Is "kill flag" there?
250       ***********************/
251        if ( tport_getflag( &(metaring.Region[i]) ) == TERMINATE )
252         {
253            StopEarthworm();
254            return 0;
255         }
256
257      /* Look for any interesting new messages
258       ***************************************/
259         rc = tport_getmsg( &(metaring.Region[i]), getLogo, 4,
260                            &msglogo, &msgsize, msg, sizeof(msg)-1 );
261         if( rc==GET_NONE || rc==GET_TOOBIG ) continue;
262      /* Process a new message
263       ***********************/
264         msg[msgsize]='\0';
265
266         if     ( msglogo.type == metaring.TypeRestart   ){
267            RestartChild( msg );
268         } else if( msglogo.type == metaring.TypeStatus )  {
269            msg[msgsize]=0;
270            fprintf(stderr,"%s\n",msg);
271         } else if( msglogo.type == metaring.TypeReqStatus ) {
272            SendStatus( i );
273         } else if( msglogo.type == metaring.TypeReconfig ) {
274            logit( "e" , "startstop: Reconfigure: Re-reading command file <%s>\n", metaring.ConfigFile );
275            /* We're re-reading the startstop*.d file here, and adding any new modules or rings */
276            /* Even if this new GetConfig returns an error, we don't want to bail out on our running earthworm */
277            oldNChild = nChild;
278            GetUtil_LoadTable(); /* reread earthworm.d and earthworm_global.d */
279            GetConfig(); /* reread startstop*.d*/
280            for ( j = metaring.nRing; j < (newNRing); j++ ) {
281                logit( "e" , "tport_create: creating ring number <%d>\n", j );
282                tport_create( &(metaring.Region[j]),
283                    1024 * metaring.ringSize[j],
284                    metaring.ringKey[j] );
285                metaring.nRing ++;
286            }
287            SpawnChildren();
288            logit( "e" , "startstop: Final reconfigure step: Restart statmgr\n" );
289            sprintf (msg, "%d", child[metaring.statmgr_location].pid);
290            RestartChild( msg  );
291         } else if( msglogo.type == metaring.TypeStop   ) {
292            StopChild( msg, &placeholder );
293         } else logit("e","Got unexpected msg type %d from transport region: %s\n",
294                        (int) msglogo.type, metaring.ringName[i] );
295      }
296      sleep_ew( 1000 );
297    }
298
299   StopEarthworm();
300   return 0;
301} /* end RunEarthworm */
302
303 /********************************************************************
304  *                            GetConfig()                           *
305  *                                                                  *
306  *  Processes command file using kom.c functions.                   *
307  *  Exits if any errors are encountered.                            *
308  *  Commands are expected in a given order in startstop.cnf         *
309  ********************************************************************/
310
311void GetConfig()
312{
313   int      state;        /* the part of the config file you are reading  */
314   char     missed[30];
315   char    *com;
316   char    *str;
317   char    saveStr[MAXLINE];
318   char    *ptr;
319   int      nfiles;
320   int      i, ir, j;
321   int      ichild;
322   boolean  firstTimeThrough = FALSE;
323   boolean  duplicate = FALSE;
324
325/* Definitions for state while reading file
326 ******************************************/
327   #define READ_NRING       0
328   #define READ_RINGINFO    1
329   #define READ_MODID       2
330   #define READ_HEARTBEAT   3
331   #define READ_MYCLASS     4
332   #define READ_MYPRIORITY  5
333   #define READ_LOGSWITCH   6
334   #define READ_KILLDELAY   7
335   #define READ_SLEEPTIME   8
336   #define READ_PROCESS     9
337   #define READ_PRIORITY   10
338   #define READ_AGENT      11
339
340/* Initialize some things
341 ************************/
342   state     = READ_NRING;
343   missed[0] = '\0';
344
345   if (nChild == 0){
346       firstTimeThrough = TRUE;
347       oldNChild = 0;
348   }
349/* Open the main configuration file
350 **********************************/
351   nfiles = k_open( metaring.ConfigFile );
352   if ( nfiles == 0 )
353   {
354        printf( "startstop: Error opening command file <%s>. Exiting.\n",
355                 metaring.ConfigFile );
356        exit( -1 );
357   }
358
359/* Process all command files
360   *************************/
361   while (nfiles > 0)              /* While there are command files open */
362   {
363        while (k_rd())             /* Read next line from active file  */
364        {
365            com = k_str();         /* Get the first token from line */
366
367        /* Ignore blank lines & comments
368           *****************************/
369            if( !com )           continue;
370            if( com[0] == '#' )  continue;
371
372        /* Process anything else as a command;
373           Expect commands in a certain order!
374           ***********************************/
375            switch (state)
376            {
377
378            /* Read the number of transport rings
379               **********************************/
380            case READ_NRING:
381                if ( !k_its( "nRing" ) )
382                {
383                    strcpy( missed, "nRing" );
384                    break;
385                }
386                if (firstTimeThrough) {/* Only if we're reading the config for the first time do we keep track */
387                    metaring.nRing  = k_int();
388                }
389                state  = READ_RINGINFO;
390                if (firstTimeThrough) {
391                    ir = 0;
392                } else {
393                    ir = metaring.nRing;
394                }
395                break;
396
397            /* Read the transport ring names & keys & size
398               *******************************************/
399            case READ_RINGINFO:
400                if ( !k_its( "Ring" ) )
401                {
402                    if ((k_its( "MyModuleId" )) && (!firstTimeThrough)) {
403                        /* OK to skip MyModuleId on 2nd time through; we already know it */
404                        state = READ_HEARTBEAT;
405                        /* if this isn't the first time through we want to add the rings we just found to nRing */
406                        newNRing = ir;
407
408                    } else {
409                       strcpy( missed, "Ring" );
410                    }
411                    break;
412                }
413                if ( ir == MAX_RING )
414                {
415                    logit( "e" , "startstop: Too many Ring commands, max=%d;"
416                            " exiting!\n", MAX_RING );
417                    exit( -1 );
418                }
419                str = k_str();
420                if( !str ) break;
421                if ( strlen( str ) > 19 )
422                {
423                  printf( "startstop: Ring name <%s> too long; exiting!\n",
424                      str );
425                  exit( -1 );
426                }
427                for ( i = 0; i < ir; i++ ) {
428                    if ( strcmp (str, metaring.ringName[i]) == 0 ){
429                        duplicate = TRUE;
430                    }
431                }
432                if (duplicate) {
433                    if (firstTimeThrough) {
434                        logit( "e", "Duplicate ring name <%s>; exiting!\n", str);
435                    }
436                    duplicate = FALSE;
437                } else {
438                    strcpy( metaring.ringName[ir], str );
439                    metaring.ringSize[ir] = k_int();
440                    if ( (metaring.ringKey[ir]= GetKey(metaring.ringName[ir])) == -1 )
441                    {
442                       logit( "e" , "startstop: Invalid Ring name <%s>; exiting!\n",
443                               metaring.ringName[ir] );
444                       exit( -1 );
445                    }
446                    if ( ++ir == metaring.nRing )  state = READ_MODID;
447                }
448                break;
449
450            /* Read stuff concerning startstop itself
451               **************************************/
452            case READ_MODID:
453                if ( !k_its("MyModuleId") )
454                {
455                    strcpy( missed, "MyModuleId" );
456                    break;
457                }
458                str = k_str();
459                if ( !str ) break;
460                if ( strlen( str ) > 39 )
461                {
462                  logit( "e" , "startstop: MyModuleId name <%s> too long;"
463                                  " exiting!\n", str );
464                  exit ( -1 );
465                }
466                strcpy( metaring.MyModName, str );
467                state = READ_HEARTBEAT;
468                break;
469
470            case READ_HEARTBEAT:
471                if ( !k_its("HeartbeatInt") )
472                {
473                    strcpy( missed, "HeartbeatInt" );
474                    break;
475                }
476                metaring.HeartbeatInt = k_int();
477                state = READ_MYCLASS;
478                break;
479
480            case READ_MYCLASS:
481                if ( !k_its("MyClassName") )
482                {
483                    strcpy( missed, "MyClassName" );
484                    break;
485                }
486                str = k_str();
487                if ( !str ) break;
488                if ( strlen( str ) > MAX_CLASSNAME_SIZE )
489                {
490                  logit( "e" , "startstop: MyClassName <%s> too long; exiting!\n",
491                      str );
492                  exit( -1 );
493                }
494                strcpy( parent.className, str );
495                state = READ_MYPRIORITY;
496                break;
497
498            case READ_MYPRIORITY:
499                if ( !k_its("MyPriority") )
500                {
501                    strcpy( missed, "MyPriority" );
502                    break;
503                }
504                parent.priority = k_int();
505                state  = READ_LOGSWITCH;
506                break;
507
508            case READ_LOGSWITCH:
509                if ( !k_its("LogFile") )
510                {
511                    strcpy( missed, "LogFile" );
512                    break;
513                }
514                metaring.LogSwitch = k_int();
515                state     = READ_KILLDELAY;
516                break;
517
518        case READ_KILLDELAY:
519          if ( !k_its("KillDelay") )
520          {
521        strcpy( missed, "KillDelay" );
522        break;
523          }
524          metaring.KillDelay = k_int();
525          state     = READ_SLEEPTIME;
526          break;
527
528        /* Optional command to tell startstop to wait a number
529         of seconds after starting statmgr John Patton*/
530        case READ_SLEEPTIME:
531          if ( !k_its("statmgrDelay") )
532          {
533            state     = READ_PROCESS;
534
535            /* since we're optonal, and not present, jump to the next */
536            /*  command in line instead of declaring an error */
537            goto no_sleep_time;
538          }
539          metaring.statmgr_sleeptime = (k_int() * 1000);
540          state     = READ_PROCESS;
541          break;
542
543
544
545           /* Read a command to start a child
546              *******************************/
547            case READ_PROCESS:
548                no_sleep_time:
549                if ( !k_its("Process") )
550                {
551                    strcpy( missed, "Process" );
552                    break;
553                }
554                Get_Process:  /* back door from optional "Agent" (below) */
555                if ( nChild == MAX_CHILD )
556                {
557                    logit( "e" , "startstop: Too many child processes in file %s, max=%d;"
558                            " exiting!\n", metaring.ConfigFile, MAX_CHILD );
559                    exit( -1 );
560                }
561                str = k_str();
562                if ( !str ) break;
563                if ( strlen( str ) > MAXLINE - 1 )
564                {
565                    logit( "e" , "startstop: Process command line <%s> too long in file %s,"
566                            " max=%d; exiting!\n", str, metaring.ConfigFile, MAXLINE - 1 );
567                    exit( -1 );
568                }
569               duplicate = FALSE;
570               for ( ichild = 0; ichild < nChild; ichild++ ) {
571                   if ( strcmp (str, child[ichild].commandLine) == 0 ) {
572                       /* logit ( "", "Skipping twin, no duplicate children allowed: %s\n", str); */
573                       duplicate = TRUE;
574                   }
575               }
576               if (duplicate) {
577                   state = READ_PRIORITY;
578                   break;
579               }
580                strcpy( child[nChild].commandLine, str );
581                strcpy( child[nChild].parm, str );
582
583
584                /* Cut the command line into tokens
585                ********************************/
586                j = 0;
587
588                ptr = strtok( child[nChild].parm, " " );
589                child[nChild].argv[j++] = ptr;
590
591                do
592                {
593                    ptr = child[nChild].argv[j++] = strtok( NULL , " " );
594                }
595                while ( ptr != NULL );
596
597                child[nChild].processName = child[nChild].argv[0];
598
599                if (strcmp( child[nChild].processName, "statmgr") == 0)
600                {
601                    /* Store statmgr's location in the child array so that we can start it first */
602                    metaring.statmgr_location = nChild;
603                }
604
605                state = READ_PRIORITY;
606                break;
607
608            /* Read the child's priority
609               *************************/
610            case READ_PRIORITY:
611
612                if ( !k_its("Class/Priority") )
613                {
614                    strcpy( missed, "Class/Priority" );
615                    break;
616                }
617                str = k_str();
618                if ( !str ) break;
619                if (duplicate) {
620                   state = READ_AGENT;
621                   break;
622                }
623                if ( strlen ( str ) > MAX_CLASSNAME_SIZE )
624                {
625                    logit( "e" , "startstop: Class name <%s> too long; exiting!\n",
626                            str );
627                    exit( -1 );
628                }
629                strcpy( child[nChild].className, str );
630                child[nChild].priority = k_int();
631                (nChild)++;
632                state = READ_AGENT;
633                break;
634
635        /* Read the child's agent
636           **********************/
637        case READ_AGENT:
638                            if ( !k_its("Agent") )
639            {   /* "Agent" is optional; if it's missing then the
640                 * the command should be another "Process" */
641                if ( k_its("Process") ) goto Get_Process;
642                break;
643            }
644            str = k_str();
645            if ( !str ) break;
646            if (duplicate) {
647               state = READ_PROCESS;
648               break;
649            }
650            if ( strlen( str ) > LOGNAME_MAX )
651            {
652                logit( "e" , "startstop: Agent user <%s> too long; exiting!\n",
653                        str );
654                exit( -1 );
655            }
656            strcpy( child[nChild - 1].use_uname, str );
657            str = k_str();
658           if (( !str ) || duplicate) break;
659            if ( strlen( str ) > LOGNAME_MAX )
660            {
661                logit( "e" , "startstop: Agent group <%s> too long; exiting!\n",
662                        str );
663                exit( -1 );
664            }
665            strcpy( child[nChild - 1].use_gname, str );
666            state = READ_PROCESS;
667            break;
668        } /*end switch*/
669
670        /* Complain if we got an unexpected command
671           ****************************************/
672            if( missed[0] )
673            {
674                logit( "e" , "startstop:  Expected: <%s>  Found: <%s>\n",
675                         missed, com );
676                logit( "e" , "startstop:  Incorrect command order in <%s>;",
677                         metaring.ConfigFile );
678                logit( "e" , " exiting!\n" );
679                exit( -1 );
680            }
681
682        /* See if there were any errors processing this command
683           ****************************************************/
684            if( k_err() )
685            {
686               logit( "e" , "startstop: Bad <%s> command in <%s>; exiting!\n",
687                        com, metaring.ConfigFile );
688               logit( "e" , "Offending line: %s\n", k_com() );
689               exit( -1 );
690            }
691        }
692        nfiles = k_close();
693   }
694   return;
695}
696
697 /******************************************************************
698  *                             Threads()                          *
699  ******************************************************************/
700
701void Threads( void *fun( void * ), thread_t *tid ) /* *tid is pointer to thread id */
702{
703   const size_t stackSize = 0;          /* Use default values */
704#ifdef _USE_PTHREADS
705   /* Just use the ew library call (since POSIX doesn't do daemons) */
706   if ( StartThread(fun,stackSize,tid) == -1 ) {
707    fprintf(stderr, "startstop: can't create thread\n");
708    exit( -1 );
709   }
710#else
711   int rc;  /* used in non-P_THREADS situations */
712   rc = thr_create( (void *)0, stackSize, fun, (void *)0,
713                    THR_DETACHED|THR_NEW_LWP|THR_DAEMON, tid );
714   if ( rc != 0 )
715   {
716    perror( "startstop: thr_create" );
717    exit( -1 );
718   }
719#endif
720}
721
722  /******************************************************************
723   *                         SigtermHandler()                       *
724   *                                                                *
725   *             Stop the whole system based on SIGTERM             *
726   ******************************************************************/
727
728#ifdef _USE_POSIX_SIGNALS
729void SigtermHandler( int sig, siginfo_t *sip, void *up )
730#else
731void SigtermHandler( int sig )
732#endif
733{
734    StopEarthworm();
735    exit(0);
736}
737
738
739  /******************************************************************
740   *                         StopEarthworm()                        *
741   *                                                                *
742   *                      Stop the whole system                     *
743   ******************************************************************/
744
745void StopEarthworm()
746{
747   int    i;
748   int    status;
749   char   tstr[TIMESTR_LEN];
750#ifdef _USE_POSIX_SIGNALS
751   struct    sigaction act;
752#endif
753
754/* Say goodbye
755   ***********/
756   GetCurrentUTC( tstr );
757   logit( "t", " Earthworm stopping at local time: %s\n", tstr );
758
759/* Set kill flag, and wait for the children to terminate.
760   If the children don't die in KillDelay seconds, send them a SIGTERM signal.
761   ******************************************************************/
762   for ( i = 0; i < metaring.nRing; i++ )
763      tport_putflag( &(metaring.Region[i]), TERMINATE );
764
765   printf( "Earthworm will stop in %d seconds...\n", metaring.KillDelay );
766   for ( i = 0; i < metaring.KillDelay; i++ )
767   {
768      if ( waitpid( (pid_t)0, &status, WNOHANG ) == -1 && errno == ECHILD )
769         break;
770      sleep_ew( 1000 );
771   }
772
773/* Catch process termination signals.
774   Send a kill signal to the current process group.
775   Wait for all children to die.
776   ************************************************/
777#ifdef _USE_POSIX_SIGNALS
778   act.sa_flags = 0; sigemptyset(&act.sa_mask);
779   act.sa_handler = SIG_IGN;
780   sigaction(SIGTERM, &act, (struct sigaction *)NULL);
781#else
782   sigignore( SIGTERM );
783#endif
784   kill( (pid_t)0, SIGTERM );
785   while ( waitpid( (pid_t)0, &status, 0 ) > 0 );
786
787/* Destroy shared memory regions
788   *****************************/
789   for( i = 0; i < metaring.nRing; i++ )  tport_destroy( &(metaring.Region[i]) );
790
791/* Free allocated space
792   ********************/
793   free( metaring.Region );
794   free( child  );
795
796
797}
798
799
800
801 /******************************************************************
802 *                          EncodeStatus()                        *
803 *                                                                *
804 *                    Encode the status message                   *
805 ******************************************************************/
806
807void EncodeStatus( char *statusMsg )
808{
809   FILE *fp;
810   char phrase[MAXLINE];
811   char line[MAXLINE];
812   char string[20];
813   char tty[20], tim[20];
814   char tstr[TIMESTR_LEN];
815   int i, j;
816   int dummy;
817   struct statvfs buf;
818   struct utsname uts;
819   pid_t status, pid;
820
821#ifdef _USE_SCHED
822   struct sched_param sc_prm;
823   int sc_pol;
824#else
825   union
826   {
827      tsparms_t tsp;
828      rtparms_t rtp;
829      long      clp[PC_CLPARMSZ];
830   } u;
831
832   pcinfo_t  cid;
833   pcparms_t pcp;
834#endif
835
836#if defined(_LINUX) || defined(_MACOSX) /* Tested on RedHat and Fedora Core */
837   gid_t groupid; /* need <unistd.h> and <sys/types.h> */
838
839/* Get cpu used for the parent and each child
840   ******************************************/
841   groupid = getgid(); /* gets group ID for current process */
842   sprintf( line, "/bin/ps -G %d \0", groupid );
843#else /* below line works for Solaris */
844   sprintf( line, "/usr/bin/ps -g %d\0", parent.pid );
845#endif
846   fp = popen( line, "r" );
847   if ( fp == NULL )
848   {
849      printf( "startstop/EncodeStatus: popen failed.\n" );
850      return;
851   }
852
853   strcpy( parent.tcum, "0:00" );             /* Initialize to zero cpu used */
854   for ( i = 0; i < nChild; i++ )
855      strcpy( child[i].tcum, "0:00" );
856
857   fgets( line, 100, fp );                    /* Skip heading */
858   while ( fgets( line, 100, fp ) != NULL )
859   {
860      sscanf( line, "%d%s%s", &pid, tty, tim );
861      if ( parent.pid == pid )
862         strcpy( parent.tcum, tim );
863      for ( i = 0; i < nChild; i++ )
864         if ( child[i].pid == pid )
865            strcpy( child[i].tcum, tim );
866   }
867   pclose( fp );
868
869/* Get system information
870   **********************/
871   if ( uname( &uts ) == -1 )
872      printf( "startstop/EncodeStatus: Error getting system information\n" );
873
874   sprintf( statusMsg, "                    EARTHWORM SYSTEM STATUS\n\n" );
875
876   sprintf( line, "        Hostname-OS:            %s - %s %s\n",
877                          uts.nodename, uts.sysname, uts.release );
878   strcat( statusMsg, line );
879   sprintf( line, "        Start time (UTC):       %s", metaring.tstart );
880   strcat( statusMsg, line );
881
882   GetCurrentUTC( tstr );
883   sprintf( line, "        Current time (UTC):     %s", tstr );
884   strcat( statusMsg, line );
885
886   if ( statvfs( ".", &buf ) == -1 )
887      printf( "startstop: Error getting file system info\n" );
888   else {
889      sprintf( line, "        Disk space avail:       %d kb\n",
890        buf.f_frsize ? (buf.f_bavail * buf.f_frsize) / 1024 :
891        buf.f_bsize ? (buf.f_bavail * buf.f_bsize) / 1024 : buf.f_bavail );
892      strcat( statusMsg, line );
893   }
894
895   for ( i = 0; i < metaring.nRing; i++ )
896   {
897      sprintf( line, "        Ring %2d name/key/size:  %s / %d / %d kb\n",
898               i+1, metaring.ringName[i], metaring.ringKey[i], metaring.ringSize[i] );
899      strcat( statusMsg, line );
900   }
901
902   sprintf( line,    "        Startstop Version:      %s\n", metaring.Version );
903   strcat( statusMsg, line );
904
905/* Get and print status of the parent process
906   ******************************************/
907   sprintf( line, "\n         Process  Process           Class/    CPU\n" );
908   strcat( statusMsg, line );
909   sprintf( line,   "          Name      Id     Status  Priority   Used  Argument\n" );
910   strcat( statusMsg, line );
911   sprintf( line,   "         -------  -------  ------  --------   ----  --------\n" );
912   strcat( statusMsg, line );
913
914   sprintf( line, "%16s", parent.processName );
915   sprintf( phrase, " %7d", parent.pid );
916   strcat( line, phrase );
917   sprintf( phrase, "   Alive " );
918   strcat( line, phrase );
919
920#ifdef _USE_SCHED
921   /* get POSIX scheduling policy */
922#ifdef _MACOSX
923   strcat( line, "    **" );
924   strcat( line, "/**" );
925#else /* _MACOSX */
926   if ( (sc_pol = sched_getscheduler(parent.pid)) == -1 ) {
927      printf( "startstop/EncodeStatus: parent sched_getscheduler error: %s\n",strerror(errno));
928      strcat( line, "    **" );
929   } else {
930      strcat( line, phrase );
931   }
932   /* get POSIX scheduling priority */
933   if ( sched_getparam(parent.pid, &sc_prm) ) {
934      printf( "startstop/EncodeStatus: parent sched_getparam error: %s\n",strerror(errno));
935      strcat( line, "/**" );
936   } else {
937      sprintf( phrase, "/%2d", sc_prm.sched_priority );
938      strcat( line, phrase );
939   }
940#endif /* _MACOSX */
941#else  /* _USE_SCHED */
942/* Get and print class of parent
943   *****************************/
944   pcp.pc_cid = PC_CLNULL;
945   if ( priocntl( P_PID, parent.pid, PC_GETPARMS,
946                  (caddr_t)&pcp ) == -1 )
947      printf( "startstop/EncodeStatus: Error getting parent parameters\n" );
948
949   cid.pc_cid = pcp.pc_cid;
950   if ( priocntl( (idtype_t)0, (id_t)0, PC_GETCLINFO,
951                  (caddr_t)&cid ) == -1 )
952      printf( "startstop/EncodeStatus: priocntl getclinfo error\n" );
953   sprintf( phrase, "   %s", cid.pc_clname );
954   strcat( line, phrase );
955
956/* Get and print priority of parent
957   ********************************/
958   for ( j = 0; j < PC_CLPARMSZ; j++ )
959      u.clp[j] = pcp.pc_clparms[j];
960
961   if ( strcmp( cid.pc_clname, "RT" ) == 0 )
962   {
963      sprintf( phrase, "/%2d", u.rtp.rt_pri );
964      strcat( line, phrase );
965   }
966
967   if ( strcmp( cid.pc_clname, "TS" ) == 0 )
968   {
969      sprintf( phrase, "/%2d", u.tsp.ts_upri );
970      strcat( line, phrase );
971   }
972#endif  /* _USE_SCHED */
973
974/* Print cumulative cpu time used by parent
975   ****************************************/
976   sprintf( phrase, "%9s", parent.tcum );
977   strcat( line, phrase );
978
979/* Print the parent argument list without the command itself */
980   if ( parent.args != (char *)NULL ) {
981    sprintf( phrase, "  %s\n", parent.args );
982    strcat( line, phrase );
983    if ( strlen(line) > 80 ) {
984        line[79] = '\n';
985        line[80] = '\0';
986    }
987   } else
988    strcat(line,"  -\n");
989   strcat( statusMsg, line );
990
991/* Get and print status of each child
992   **********************************/
993   /* build a line in `line[]', to check its length */
994   for ( i = 0; i < nChild; i++ )
995   {
996      sprintf( line, "%16s", child[i].processName );
997      sprintf( phrase, " %7d", child[i].pid );
998      strcat( line, phrase );
999#ifdef _LINUX /* Linux-only __WALL wait-all */
1000      status = waitpid( child[i].pid, &dummy, WNOHANG | __WALL );
1001#else /*_LINUX */
1002      status = waitpid( child[i].pid, &dummy, WNOHANG );
1003#endif /*_LINUX */
1004      strcpy( string,    "   Zombie " );
1005      if ( status == 0 )
1006         strcpy( string, "   Alive " );
1007      if ( (status == -1) && (errno == ECHILD) ) {
1008          if( strcmp( child[i].status, "Stopped" ) == 0 ) {
1009              strcpy( string, "   Stop   " );
1010          } else {
1011              strcpy( string, "   Dead   " );
1012          }
1013      }
1014      sprintf( phrase, "%s", string );
1015      strcat( line, phrase );
1016
1017/* Get and print class of each child
1018   *********************************/
1019      if (status == 0) {
1020#ifdef _USE_SCHED
1021        /* get POSIX scheduling policy */
1022#ifdef _MACOSX
1023        strcat( line, "    **" );
1024        strcat( line, "/**" );
1025#else /* _MACOSX */
1026        if ( (sc_pol = sched_getscheduler(child[i].pid)) == -1 ) {
1027           printf( "startstop/EncodeStatus: child (%d) sched_getscheduler error: %s\n",i,strerror(errno));
1028           strcat( line, "    **" );
1029        } else {
1030           sprintf( phrase, " %s",
1031#if !defined(_LINUX)
1032        sc_pol == SCHED_NP ? "  NP" :
1033        sc_pol == SCHED_TS ? "  TS" :
1034#endif /* ndef _LINUX */
1035        sc_pol == SCHED_FIFO ? "FIFO" :
1036        sc_pol == SCHED_RR ? "  RR" : "  ??");
1037           strcat( line, phrase );
1038        }
1039        /* get POSIX scheduling priority */
1040        if ( sched_getparam(child[i].pid, &sc_prm) ) {
1041           printf( "startstop/EncodeStatus: child (%d) sched_getparam error: %s\n",i,strerror(errno));
1042           strcat( line, "/**" );
1043        } else {
1044           sprintf( phrase, "/%2d", sc_prm.sched_priority );
1045           strcat( line, phrase );
1046        }
1047#endif /* _MACOSX */
1048#else /* _USE_SCHED */
1049        pcp.pc_cid = PC_CLNULL;
1050        if ( priocntl( P_PID, child[i].pid, PC_GETPARMS,
1051                       (caddr_t)&pcp ) == -1 )
1052          printf( "startstop/EncodeStatus: Error getting child parameters\n" );
1053
1054        cid.pc_cid = pcp.pc_cid;
1055        if ( priocntl( (idtype_t)0, (id_t)0, PC_GETCLINFO,
1056                       (caddr_t)&cid ) == -1 )
1057          printf( "startstop/EncodeStatus: priocntl getclinfo error\n" );
1058        sprintf( phrase, "   %s", cid.pc_clname );
1059        strcat( line, phrase );
1060
1061        /* Get and print priority of each child
1062        ************************************/
1063        for ( j = 0; j < PC_CLPARMSZ; j++ )
1064          u.clp[j] = pcp.pc_clparms[j];
1065
1066        if ( strcmp( cid.pc_clname, "RT" ) == 0 ) {
1067          sprintf( phrase, "/%2d", u.rtp.rt_pri );
1068        } else if ( strcmp( cid.pc_clname, "TS" ) == 0 ) {
1069          sprintf( phrase, "/%2d", u.tsp.ts_upri );
1070        }
1071        strcat( line, phrase );
1072#endif /* _USE_SCHED */
1073        /* Print cumulative cpu time used by each child
1074        ********************************************/
1075        sprintf( phrase, "%9s ", child[i].tcum );
1076        strcat( line, phrase );
1077      } else {  /* status != 0 */
1078        sprintf( phrase, "                 " );
1079        strcat( line, phrase );
1080      }
1081
1082      /* Print the argument list without the command itself
1083       ****************************************************/
1084      for (j = 1; j < MAX_ARG; j++) {
1085        if (child[i].argv[j] == NULL ) break;
1086        /* do we have enough room on 80-column screen (including the space) */
1087        if ( (strlen(line) + strlen(child[i].argv[j]) ) > 79 ) break;
1088        sprintf( phrase, " %s", child[i].argv[j] );
1089        strcat( line, phrase );
1090      }
1091      strcat( statusMsg, line );
1092
1093/* Attach a newline to the end of the line
1094   ***************************************/
1095      sprintf( line, "\n" );
1096      strcat( statusMsg, line );
1097   }
1098   return;
1099} /* end EncodeStatus */
1100
1101
1102  /******************************************************************
1103   *                          ConstructIds                         *
1104   *     Look up user id and group id numbers for Agents            *
1105   ******************************************************************/
1106void ConstructIds( char *user, char *group, uid_t *uid, gid_t *gid )
1107{
1108    struct group grp;
1109    struct passwd passwd;
1110    char    grbuffer[BUFSIZ];
1111    char    pwbuffer[BUFSIZ];
1112    uid_t   my_uid;
1113    struct passwd my_passwd;
1114    char   mypwbuffer[BUFSIZ];
1115
1116#if _USE_PTHREADS
1117    struct passwd pwe, *pwptr;
1118    struct group gre, *grptr;
1119#endif
1120
1121    my_uid = getuid();
1122#if _USE_PTHREADS
1123    pwptr = & my_passwd;
1124    getpwuid_r( my_uid, &pwe, mypwbuffer, BUFSIZ, &pwptr );
1125#else
1126    getpwuid_r( my_uid, &my_passwd, mypwbuffer, BUFSIZ );
1127#endif
1128
1129    if( !strcmp( user, "" ) )
1130    {   /* Use the real userID if user hasn't been specified */
1131        *uid = getuid();
1132    }
1133
1134    /* Don't allow "root" as the Agent user; use the real uid instead */
1135    else if ( !strcmp( user, "root") && my_uid != 0 )
1136    {
1137      fprintf( stderr, "`root' user Agent not permitted; using `%s'\n",
1138           my_passwd.pw_name );
1139      *uid = my_uid;
1140    }
1141#if _USE_PTHREADS
1142    else if( ! (pwptr = &passwd, getpwnam_r( user, &pwe, &pwbuffer[0], BUFSIZ, &pwptr )) )
1143#else
1144    else if( ! getpwnam_r( user, &passwd, &pwbuffer[0], BUFSIZ ) )
1145#endif
1146    {
1147        fprintf( stderr, "Failed to find password entry for user %s\n",
1148             user );
1149        *uid = my_uid;
1150    }
1151    else
1152    {
1153        *uid = passwd.pw_uid;
1154    }
1155
1156    if( !strcmp( group, "" ) )
1157    {   /* Use the real groupIP if group hasn't been specified */
1158        *gid = getgid();
1159    }
1160#if _USE_PTHREADS
1161    else if( ! (grptr = &grp, getgrnam_r( group, &gre, &grbuffer[0], BUFSIZ, &grptr )) )
1162#else
1163    else if( ! getgrnam_r( group, &grp, &grbuffer[0], BUFSIZ ) )
1164#endif
1165    {
1166        fprintf( stderr, "Failed to find entry for group %s\n", group );
1167        *gid = getgid();
1168    }
1169    else
1170    {
1171        *gid = grp.gr_gid;
1172    }
1173
1174    return;
1175} /* end ConstructIds */
1176
1177
1178
1179  /******************************************************************
1180   *                           RestartChild                         *
1181   *                                                                *
1182   *      Restart a specific child, given a TYPE_RESTART msg        *
1183   ******************************************************************/
1184
1185void RestartChild( char *restartmsg )
1186{
1187    boolean NotInitialStartup = TRUE;
1188
1189    int ich = 0, ir, ret;
1190
1191    /* stop */
1192    ret = StopChild( restartmsg, &ich );
1193    if (ret == EXIT) {
1194       return;
1195    }
1196
1197    /* and now start */
1198    switch ( StartChild( ich, NotInitialStartup ) )
1199    {
1200        case -1:
1201            logit("et","startstop: failed to restart <%s>\n",
1202                  child[ich].processName);
1203            break;
1204        case 0:
1205            logit("et","startstop: successfully restarted <%s>\n",
1206                  child[ich].processName);
1207            break;
1208        default:
1209            return;
1210    }
1211
1212
1213} /* end RestartChild */
1214
1215
1216
1217  /******************************************************************
1218   *                           StopChild                            *
1219   *                                                                *
1220   *     Stop a specific child given a TYPE_RESTART or              *
1221   *     TYPE_STOP message                                          *
1222   ******************************************************************/
1223int StopChild ( char *restartmsg, int *ich )
1224{
1225   int ir, childNum;
1226   int status  = 0;
1227   int procId  = 0;
1228   int nsec    = 0;
1229   int timeout = 30;
1230   char ErrText[MAXLINE];
1231
1232   /* Find this process id in the list of children
1233    **********************************************/
1234      procId = atoi( restartmsg );
1235
1236      for ( childNum = 0; childNum < nChild; childNum++ )
1237      {
1238         if ( child[childNum].pid == procId ) break;
1239      }
1240
1241      if( childNum==nChild )
1242      {
1243         sprintf( ErrText, "Cannot restart pid=%d; it is not my child!\n",
1244                  procId );
1245         ReportError( ERR_STARTCHILD, ErrText, &metaring );
1246         return EXIT;
1247      }
1248   #ifdef _UNIX
1249   /* Kill the current incarnation of the child
1250    *******************************************/
1251      kill( (pid_t)child[childNum].pid, SIGKILL );
1252      while( waitpid( (pid_t)child[childNum].pid, &status, 0 ) > 0 )
1253      {
1254         sleep_ew(1000);
1255         nsec++;
1256         if ( nsec > timeout )
1257         {
1258           sprintf( ErrText, "terminating <%s> (pid=%d) in %d sec failed;"
1259                   " cannot restart!\n",
1260                    child[childNum].processName, procId, timeout );
1261           ReportError( ERR_STARTCHILD, ErrText, &metaring );
1262           return EXIT;
1263   #else
1264
1265   /* Give child a chance to shut down gracefully...
1266    ************************************************/
1267      for( ir=0; ir<metaring.nRing; ir++ ) tport_putflag( &(metaring.Region[ir]), child[childNum].pid );
1268      nsec = 0;
1269      while( waitpid((pid_t)child[childNum].pid, &status, WNOHANG) == 0 )
1270      {
1271         sleep_ew(1000);
1272         nsec++;
1273
1274      /* ...but if it takes too long:
1275         Kill the current incarnation of the child. Use SIGTERM - by
1276         default it causes an exit, but it can be blocked, allowing us
1277         to protect writes to shared memory (SIGKILL cannot be blocked)
1278       ****************************************************************/
1279         if( nsec > metaring.KillDelay ) {
1280            sigsend( P_PID, (pid_t)child[childNum].pid, SIGTERM );
1281            logit( "et", "startstop: <%s> (pid=%d) did not shut down in %d sec;"
1282                   " terminating it!\n",
1283                    child[childNum].processName, procId, metaring.KillDelay );
1284            nsec = 0;
1285            while( waitpid((pid_t)child[childNum].pid, &status, WNOHANG) == 0 )
1286            {
1287               sleep_ew(1000);
1288               nsec++;
1289               if ( nsec > metaring.KillDelay )
1290               {
1291                 sprintf( ErrText, "terminating <%s> (pid=%d) in %d sec failed;"
1292                         " cannot restart!\n",
1293                          child[childNum].processName, procId, metaring.KillDelay );
1294                 ReportError( ERR_STARTCHILD, ErrText, &metaring );
1295                 return EXIT;
1296               }
1297            }
1298            break;
1299   #endif
1300         }
1301    }
1302    strcpy( child[childNum].status, "Stopped" );
1303    *ich = childNum;
1304    return SUCCESS;
1305}
1306
1307
1308int StartChild ( int ich, boolean NotInitialStartup ) {
1309    char ErrText[512];
1310    /*
1311     *     From fork(2) man page:
1312     *     In applications that use the Solaris threads API rather than
1313     *     the POSIX threads API (applications linked with -lthread but
1314     *     not -lpthread),fork() duplicates in the  child  process  all
1315     *     threads  (see  thr_create(3THR)) and LWPs in the parent pro-
1316     *     cess. The  fork1()  function  duplicates  only  the  calling
1317     *     thread (LWP) in the child process.
1318     *
1319     *     Thus, we use fork1 for restarts to take fewer resources
1320     */
1321    if ( NotInitialStartup ) { /* not initial startup, so use fork1 */
1322        child[ich].pid = fork1();
1323    } else {
1324        child[ich].pid = fork();
1325    }
1326    switch ( child[ich].pid )
1327    {
1328      case -1:
1329         perror( "startstop: fork" );
1330         sprintf( ErrText, "fork failed; cannot start <%s>\n",
1331                  child[ich].processName );
1332         ReportError( ERR_STARTCHILD, ErrText, &metaring );
1333         sleep_ew( 500 );
1334         return(-1);
1335         break;
1336      case 0:   /* the child */
1337         setgid( child[ich].use_gid );
1338         setuid( child[ich].use_uid );
1339          /* fprintf(stderr,"PIDS at exec %d %d\n",getpid(),getppid()); */
1340         fprintf(stderr,"%s %s %s \n",child[ich].processName,child[ich].argv[0],child[ich].argv[1] );
1341         execvp( child[ich].processName, child[ich].argv );
1342         /* logit("e", "debug: error with: child[ich].processName = %s\n", child[ich].processName); */
1343         perror( "startstop: execvp" );
1344         sprintf( ErrText, "execvp failed; cannot restart <%s>\n",
1345            child[ich].processName );
1346         ReportError( ERR_STARTCHILD, ErrText, &metaring );
1347         StartError( ich, child[ich].processName, &metaring, &nChild );
1348         /* StartError ends the child process completely */
1349         logit("e", "debug2: error with: child[ich].processName = %s %d\n", child[ich].processName, child[ich].pid);
1350         sleep_ew( 500 );
1351         return(1);
1352         break;
1353      default:  /* the parent */
1354        break;
1355    }
1356    SetPriority( child[ich].pid, child[ich].className, child[ich].priority );
1357    strcpy( child[ich].status, "Alive" );
1358    /* Sleep for 0.5 second to allow fork to complete it's business.
1359    This was motivated by message:
1360    "startstop: fork: Resource temporarily unavailable" on Sparc5 - newt
1361    ********************************************************************/
1362    return(0);
1363
1364} /* end StartChild */
1365
1366/******************************************************************
1367 *                         StartEarthworm()                       *
1368 *                                                                *
1369 *                      Start the whole system                    *
1370 ******************************************************************/
1371
1372void StartEarthworm( char *ProgName )
1373{
1374   int      i;
1375   thread_t tid;
1376   boolean RestartStatus = FALSE;
1377
1378
1379/* Print start time
1380   ****************/
1381   GetCurrentUTC( metaring.tstart );         /* Get UTC as a 26 char string */
1382   logit( "t", " Earthworm starting at local time: %s\n", metaring.tstart );
1383
1384/* Create the transport rings
1385   **************************/
1386   for ( i = 0; i < metaring.nRing; i++ )
1387      tport_create( &(metaring.Region[i]), 1024 * metaring.ringSize[i], metaring.ringKey[i] );
1388
1389/* Spawn the child processes.  Results are
1390   unpredictable if other threads start before this loop.
1391   *****************************************************/
1392#ifdef _SOLARIS
1393
1394/* Start Statmgr first if present */
1395
1396    if (metaring.statmgr_location != (MAX_CHILD + 1))
1397        /* aka if we did find a statmgr in GetConfig */
1398    {
1399
1400        ConstructIds( child[metaring.statmgr_location].use_uname,
1401                      child[metaring.statmgr_location].use_gname,
1402                      &child[metaring.statmgr_location].use_uid,
1403                      &child[metaring.statmgr_location].use_gid );
1404
1405        switch( child[metaring.statmgr_location].pid = fork() )
1406        {
1407            case -1:
1408                perror( "startstop: fork" );
1409                exit( 1 );
1410                break;
1411            case 0: /* the child */
1412                setgid( child[metaring.statmgr_location].use_gid );
1413                setuid( child[metaring.statmgr_location].use_uid );
1414                execvp( child[metaring.statmgr_location].processName, child[metaring.statmgr_location].argv );
1415                perror( "startstop: execvp" );
1416                StartError( metaring.statmgr_location, child[metaring.statmgr_location].processName, &metaring, &nChild );
1417                break;
1418            default:    /* the parent */
1419                break;
1420        }
1421        SetPriority( child[metaring.statmgr_location].pid, child[metaring.statmgr_location].className, child[metaring.statmgr_location].priority );
1422
1423        /* Tell the user why it's taking so long to start up */
1424        logit("et","startstop: sleeping <%d> second(s) for statmgr startup.\n",
1425              (metaring.statmgr_sleeptime/1000) );
1426
1427        /* Sleep after starting statmgr to allow statmgr to come up first */
1428        sleep_ew(metaring.statmgr_sleeptime);
1429    }
1430#endif /* _SOLARIS */
1431
1432   for ( i = 0; i < nChild; i++ )
1433   {
1434#ifdef _SOLARIS
1435        /* To prevent starting statmgr a second time, we'll just skip over it
1436         If it's not there, then the index to skip defaults to one past MAXCHILD, so
1437         no other modules will be skipped. */
1438         if (i != metaring.statmgr_location)
1439         {
1440#endif /* _SOLARIS */
1441            ConstructIds( child[i].use_uname,
1442                          child[i].use_gname,
1443                          &child[i].use_uid,
1444                          &child[i].use_gid );
1445            if ( StartChild ( i, RestartStatus ) != 0 ){
1446                logit("et","startstop: process <%s> <%d> failed to start.\n",
1447                                  child[i].parm, child[i].pid );
1448            } else {
1449                logit("et","startstop: process <%s> <%d> started.\n",
1450                                  child[i].parm, child[i].pid );
1451            }
1452
1453#ifdef _SOLARIS
1454         }
1455#endif /* _SOLARIS */
1456   }
1457
1458
1459/* Start the interactive thread
1460   ****************************/
1461    Threads( Interactive, &tid );
1462   return;
1463} /* end StartEarthworm */
1464
1465
1466 /********************************************************************
1467  *                            SetPriority()                         *
1468  *                                                                  *
1469  *        Set the priorities of all threads in this process.        *
1470  *         Valid TS/RT priority ranges depend on O/S and POSIX      *
1471  *         compliance (RT 0 to 59 for solaris w/o POSIX).           *
1472  ********************************************************************/
1473
1474void SetPriority( pid_t pid, char *ClassName, int Priority )
1475{
1476
1477#ifdef _USE_SCHED
1478   struct sched_param sc_prm;
1479   int sc_pol, sc_pri_min, sc_pri_max;
1480
1481   /* get POSIX scheduling policy for requested class */
1482   sc_pol =
1483    strcmp( ClassName, "FIFO" ) == 0 ? SCHED_FIFO : /* FIFO (RR with no time out) */
1484    strcmp( ClassName, "RR" ) == 0 ? SCHED_RR : /* Round robbin */
1485    strcmp( ClassName, "RT" ) == 0 ? SCHED_RR : /* SOLARIS compatibility = RR */
1486#if !defined(_UNIX)
1487    strcmp( ClassName, "TS" ) == 0 ? SCHED_TS : /* Time share */
1488    strcmp( ClassName, "NP" ) == 0 ? SCHED_NP : /* who knows */
1489#endif
1490    strcmp( ClassName, "OTHER" ) == 0 ? SCHED_OTHER : -1;   /* OTHER -> revert to TS */
1491   if ( sc_pol == -1 ) {
1492      printf( "startstop: unknown class: %s\n",ClassName);
1493      return;
1494   }
1495   /* get POSIX min and max priority for requested policy */
1496   if ( (sc_pri_min = sched_get_priority_min(sc_pol)) == -1 ) {
1497      printf( "startstop: sched_get_priority_min error: %s\n",strerror(errno));
1498      return;
1499   }
1500   if ( (sc_pri_max = sched_get_priority_max(sc_pol)) == -1 ) {
1501      printf( "startstop: sched_get_priority_max error: %s\n",strerror(errno));
1502      return;
1503   }
1504   /* keep requested priority within allowed min and max priority */
1505   sc_prm.sched_priority = MIN(MAX(Priority,sc_pri_min),sc_pri_max);
1506   if ( sc_prm.sched_priority != Priority )
1507       printf( "startstop: requested %s priority (%d) not between %d and %d: reset to %d\n",
1508                ClassName,Priority,sc_pri_min,sc_pri_max,sc_prm.sched_priority);
1509   /* for safety, keep real-time priorities lower than all system and device processes */
1510# ifdef __sgi
1511#  define MAX_USR_PRI 89
1512   if ( (sc_pol == SCHED_FIFO || sc_pol == SCHED_RR) && sc_prm.sched_priority > MAX_USR_PRI ) {
1513      sc_prm.sched_priority = MAX_USR_PRI;
1514      printf( "startstop: requested priority (%d) too high: set to %d\n",
1515                Priority,sc_prm.sched_priority);
1516   }
1517#  undef MAX_USR_PRI
1518# endif
1519   /* set POSIX scheduling policy and priority */
1520#ifndef _MACOSX
1521   if ( sched_setscheduler(pid, sc_pol, &sc_prm) == -1 ) {
1522#if !defined(_UNIX)
1523      printf( "startstop: sched_setscheduler error: PID %d (policy/priority %s/%d):\n\t%s\n",
1524            pid, (sc_pol == SCHED_FIFO ? "FIFO" : sc_pol == SCHED_RR ? "RR" :
1525            sc_pol == SCHED_TS ? "TS" : sc_pol == SCHED_NP ? "NP" : "??"),
1526        sc_prm.sched_priority, strerror(errno));
1527#else /* _UNIX */
1528      printf( "startstop: sched_setscheduler error: PID %d (policy/priority %s/%d):\n\t%s\n",
1529            pid, (sc_pol == SCHED_FIFO ? "FIFO" : sc_pol == SCHED_RR ? "RR" :
1530             "??"),
1531        sc_prm.sched_priority, strerror(errno));
1532#endif /* _UNIX */
1533      printf( "\tCheck that startstop is setuid root!!\n");
1534      return;
1535   }
1536#endif /* ndef _MACOSX */
1537#else
1538   int i;
1539   union{
1540      tsparms_t tsp;
1541      rtparms_t rtp;
1542      long      clp[PC_CLPARMSZ];
1543   } u;
1544
1545   pcinfo_t  cid;
1546   pcparms_t pcp;
1547   rtparms_t rtp;
1548   strcpy( cid.pc_clname, ClassName );
1549   if ( priocntl( P_PID, (id_t)pid, PC_GETCID, (caddr_t)&cid ) == -1 )
1550      perror( "startstop: priocntl getcid" );
1551
1552   pcp.pc_cid = cid.pc_cid;
1553
1554   if ( strcmp( ClassName, "TS" ) == 0 )
1555   {
1556      u.tsp.ts_uprilim = TS_NOCHANGE;            /* Use the default */
1557      u.tsp.ts_upri    = Priority;               /* Desired priority */
1558   }
1559
1560   if ( strcmp( ClassName, "RT" ) == 0 )
1561   {
1562      u.rtp.rt_pri     = Priority;               /* Desired priority */
1563      u.rtp.rt_tqsecs  = 0;
1564      u.rtp.rt_tqnsecs = RT_TQDEF;               /* Use default time quantum */
1565   }
1566   for ( i = 0; i < PC_CLPARMSZ; i++ )
1567      pcp.pc_clparms[i] = u.clp[i];
1568
1569   if ( priocntl( P_PID, (id_t)pid, PC_SETPARMS, (caddr_t)&pcp ) == -1 )
1570      perror( "startstop: priocntl setparms" );
1571#endif
1572} /* end SetPriority */
1573
1574  /*********************************************************************
1575   *                           Interactive()                           *
1576   *                                                                   *
1577   *          Thread function to get commands from keyboard            *
1578   *********************************************************************/
1579
1580void *Interactive( void *dummy) {
1581   char ewstat[MAX_STATUS_LEN];
1582   char      message[512];/**/
1583   MSG_LOGO  logo;/**/
1584   int  i, scan_return, placeholder;
1585   char line[MAXLINE];
1586   char param[MAXLINE];
1587
1588#ifdef _LINUX
1589
1590   EncodeStatus( ewstat );                          /* One free status */
1591   printf( "\n%s\n", ewstat );
1592#else /* if not LINUX */
1593   int z;
1594   int quit = 0;
1595
1596   for ( z = 0; z < metaring.nRing; z++ )
1597   {
1598      if ( tport_getflag( &(metaring.Region[z]) ) == TERMINATE )
1599      {
1600          quit = 1;
1601      }
1602   }
1603
1604   if ( quit != 1 )
1605   {
1606      EncodeStatus( ewstat );/* One free status */
1607      printf( "\n%s", ewstat );
1608   }
1609#endif /* ifdef _LINUX */
1610   do
1611   {
1612      printf( "\n   Press return to print Earthworm status, or\n" );
1613      printf( "   type restart nnn where nnn is proc id or name to restart, or\n" );
1614      printf( "   type quit<cr> to stop Earthworm.\n\n" );
1615
1616/* With SIGTTIN ignored, reading from tty (stdin) when in background
1617 * will return with errno set to EIO. Or if startstop is run from a script,
1618 * errno will be set to ESPIPE.
1619 * If that happens, just return from this thread.
1620 */
1621
1622      fgets(line, MAXLINE, stdin );
1623#ifdef _LINUX
1624      {
1625      if ((errno == EIO) || (errno == ESPIPE) ||(errno == ENOTTY))
1626      {
1627    fprintf(stderr,"XXX %d %s ZZZ\n",errno,strerror(errno));
1628    thr_exit( (void *)0 );
1629      }
1630      }
1631#endif
1632
1633      if ((strlen(line) == 0) && ((errno == EIO) || (errno == ESPIPE))) {
1634#ifdef _LINUX
1635    fprintf(stderr,"XX1X %d %s ZZZ\n",errno,strerror(errno));
1636#endif
1637        thr_exit( (void *)0 );
1638      }
1639
1640      if ( strlen( line ) == 1 )
1641      {
1642#ifdef _LINUX
1643
1644/* Build status request message
1645   ****************************/
1646   sprintf(message,"%d\n", metaring.MyModId );
1647
1648/* Set logo values of message
1649   **************************/
1650   logo.type   = metaring.TypeReqStatus;
1651   logo.mod    = metaring.MyModId;
1652   logo.instid = metaring.InstId;
1653
1654/* Send status message to transport ring
1655   **************************************/
1656   if ( tport_putmsg( &(metaring.Region[0]), &logo, strlen(message), message ) != PUT_OK )
1657   {
1658    fprintf(stderr, "status: Error sending message to transport region.\n" );
1659    return ( 1 );
1660   }
1661#endif /* if not _LINUX IGD 2006/11/27 moved the condition up to allow EncodeStatus on Linux*/
1662         EncodeStatus( ewstat );
1663         printf( "\n%s", ewstat );
1664/* #endif IGD 2006/11/27 commented out*/
1665      }
1666
1667
1668      for ( i = 0; i < (int)strlen( line ); i++ )
1669         line[i] = tolower( line[i] );
1670      param[0] = 0;
1671     scan_return = sscanf(line, "%*s %s", param);
1672
1673     if (strncmp( line, "restart", 7)==0 && scan_return == 1)
1674     {
1675       for( i = 0; i < nChild; i++ )
1676       {
1677         if( strcmp(child[i].processName, param)==0 )
1678         {
1679           sprintf(param,"%d", child[i].pid);
1680           break;
1681         }
1682       }
1683
1684       fprintf( stderr, "sending restart message to the ring for %s\n", param);      /* sending it to the ring rather than starting directly so statmgr can keep track */
1685      /* RestartChild(param ); */
1686       SendRestartReq(&metaring, param);
1687     }
1688
1689     if (((strncmp( line, "stop", 4)==0) || (strncmp( line, "stopmodule", 10)==0)) && scan_return == 1)
1690     {
1691       for( i = 0; i < nChild; i++ )
1692       {
1693         if( strcmp(child[i].processName, param)==0 )
1694         {
1695           sprintf(param,"%d", child[i].pid);
1696           break;
1697         }
1698       }
1699       fprintf( stderr, "sending stop message to the ring for %s\n", param);
1700       /* sending it to the ring rather than starting directly so statmgr can keep track */
1701       /* StopChild(param, &placeholder);; */
1702       SendStopReq(&metaring, param);
1703
1704     }
1705
1706     /* reconfigure */
1707     if ((strncmp( line, "recon", 5)==0) || (strncmp( line, "reconfigure", 11)==0)) {
1708        /* Send a message requesting reconfigure */
1709        /* message is just MyModId
1710           ****************************/
1711           sprintf(message,"%d\n", metaring.MyModId );
1712        /* Set logo values of message
1713           **************************/
1714           logo.type   = metaring.TypeReconfig;
1715           logo.mod    = metaring.MyModId;
1716           logo.instid = metaring.InstId;
1717
1718        /* Send status message to transport ring
1719           **************************************/
1720           if ( tport_putmsg( &(metaring.Region[0]), &logo, strlen(message), message ) != PUT_OK ) {
1721                logit( "e" , "status: Error sending message to transport region.\n" );
1722                return 0;
1723           }
1724     }
1725
1726
1727
1728   } while ( strcmp( line, "quit\n" ) != 0 );
1729
1730   done = 1;
1731
1732   thr_exit( (void *)0 );
1733   return 0;
1734} /* end Interactive */
1735
1736/******************************************************************
1737 *                            SendStatus()                        *
1738 *    Build a status message and put it in a transport ring       *
1739 ******************************************************************/
1740
1741void SendStatus( int iring )
1742{
1743   MSG_LOGO logo;
1744   int length;
1745   char ewstat[MAX_STATUS_LEN];
1746
1747   logo.instid = metaring.InstId;
1748   logo.mod    = metaring.MyModId;
1749   logo.type   = metaring.TypeStatus;
1750
1751   EncodeStatus( ewstat );
1752   length = strlen( ewstat );
1753
1754   if ( tport_putmsg( &(metaring.Region[iring]), &logo, length, ewstat ) != PUT_OK )
1755      logit("t", "startstop: Error sending status msg to transport region: %s\n",
1756             metaring.ringName[iring] );
1757   return;
1758} /* end SendStatus */
1759
1760void SpawnChildren (){
1761    /* Start the child processes
1762    *************************/
1763    int ichild;
1764    boolean NotInitialStartup = TRUE;
1765
1766    /* The following changes were made by John Patton to fix the
1767     processes dying before statmgr comes up bug */
1768   for ( ichild = oldNChild; ichild < nChild; ichild++ )
1769   {
1770        /* To prevemt starting statmgr a second time, we'll just skip over it
1771          If it's not there, then the index to skip defaults to one past MAXCHILD, so
1772          no other modules will be skipped. */
1773        if (ichild != metaring.statmgr_location)
1774        {
1775            if ( StartChild( ichild, NotInitialStartup ) == 0 )
1776            {
1777                logit("et","startstop: process <%s> <%d> started.\n",
1778                  child[ichild].parm, child[ichild].pid );
1779            } else {
1780                logit("et","startstop: process <%s> <%d> failed to start.\n",
1781                                  child[ichild].parm, child[ichild].pid );
1782            }
1783        }
1784   }
1785} /* end SpawnChildren */
Note: See TracBrowser for help on using the repository browser.