A few bug fixes related to the mlogft machine.
[charm.git] / src / arch / net / charmrun / charmrun.c
1 #include "converse.h"
2
3 #include "../sockRoutines.h"
4 #include "../sockRoutines.c"
5 #include "../ccs-auth.h"
6 #include "../ccs-auth.c"
7 #include "../ccs-server.h"
8 #include "../ccs-server.c"
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <setjmp.h>
15 #include <stdlib.h>
16 #include <signal.h>
17 #include <fcntl.h>
18 #include <time.h>
19 #include <assert.h>
20 #if CMK_BPROC
21 #include <sys/bproc.h>
22 #endif
23
24 #if defined(_WIN32) && !defined(__CYGWIN__)
25 /*Win32 has screwy names for the standard UNIX calls:*/
26 #define getcwd _getcwd
27 #define strdup _strdup
28 #define unlink _unlink
29 #define open _open
30 #define fdopen _fdopen
31 #define ftruncate _chsize
32 #include <winbase.h>
33 #include <direct.h>
34 #include <io.h>
35 #include <sys/timeb.h>
36 #include <process.h>
37 #define DIRSEP "\\"
38 #define SIGBUS -1  /*These signals don't exist in Win32*/
39 #define SIGKILL -1
40 #define SIGQUIT -1
41
42
43 #else /*UNIX*/
44 #include <pwd.h>   /*getcwd*/
45 #include <unistd.h>
46 #define DIRSEP "/"
47 #endif
48
49 #if CMK_RSH_NOT_NEEDED /*No RSH-- use daemon to start node-programs*/
50 #  define CMK_USE_RSH 0
51
52 #else /*Use RSH to start node-programs*/
53 #  define CMK_USE_RSH 1
54 #ifdef __MINGW_H
55 #  include <rpc.h>
56 #elif !defined(__CYGWIN__)
57 #  include <rpc/rpc.h>
58 #else
59 #  include <w32api/rpc.h>
60 #endif
61 #  if CMK_RSH_IS_A_COMMAND
62 #    define RSH_CMD "rsh"
63 #  endif
64
65 #  if CMK_RSH_USE_REMSH
66 #    define RSH_CMD "remsh"
67 #  endif
68 #endif
69
70 #include "daemon.h"
71
72 /*#define DEBUGF(x) printf x*/
73 #define DEBUGF(x) 
74
75 #ifndef MAXPATHLEN
76 #define MAXPATHLEN 1024
77 #endif
78
79 static double ftTimer;
80
81 int *rsh_pids=NULL;
82                                                                                 
83 double GetClock(void)
84 {
85 #if defined(_WIN32) && !defined(__CYGWIN__)
86   struct _timeb tv;
87   _ftime(&tv);
88   return (tv.time * 1.0 + tv.millitm * 1.0E-3);
89 #else
90   struct timeval tv; int ok;
91   ok = gettimeofday(&tv, NULL);
92   if (ok<0) { perror("gettimeofday"); exit(1); }
93   return (tv.tv_sec * 1.0 + tv.tv_usec * 1.0E-6);
94 #endif
95 }
96
97
98 int probefile(path)
99     char *path;
100 {
101         FILE *f=fopen(path,"r");
102         if (f==NULL) return 0;
103         fclose(f);
104         return 1;
105 }
106
107 char *mylogin(void)
108 {
109 #if defined(_WIN32) && !defined(__CYGWIN__)
110         static char name[100]={'d','u','n','n','o',0};
111         int len=100;
112         GetUserName(name,&len);
113         return name;
114 #else /*UNIX*/
115   struct passwd *self;
116
117   self = getpwuid(getuid());
118   if (self==0) { return "unknown"; }
119   return self->pw_name;
120 #endif
121
122
123 /**************************************************************************
124  *
125  * ping_developers
126  *
127  * Sends a single UDP packet to the charm developers notifying them
128  * that charm is in use.
129  *
130  **************************************************************************/
131
132 void ping_developers()
133 {
134 #ifdef NOTIFY
135   char               info[1000];
136   /*This is the resolved IP address of elegance.cs.uiuc.edu */
137   skt_ip_t destination_ip=skt_lookup_ip("128.174.241.211");
138   unsigned int destination_port=6571;
139   struct sockaddr_in addr=skt_build_addr(destination_ip,destination_port);
140   SOCKET             skt;
141   
142   skt = socket(AF_INET, SOCK_DGRAM, 0);
143   if (skt == INVALID_SOCKET) return;
144
145   sprintf(info,"%s",mylogin());
146   
147   sendto(skt, info, strlen(info), 0, (struct sockaddr *)&addr, sizeof(addr));
148   skt_close(skt);
149 #endif /* NOTIFY */
150 }
151
152 /**************************************************************************
153  *
154  * Pathfix : alters a path according to a set of rewrite rules
155  *
156  *************************************************************************/
157
158 typedef struct pathfixlist {
159   char *s1;
160   char *s2;
161   struct pathfixlist *next;
162 } *pathfixlist;
163
164 pathfixlist pathfix_append(char *s1, char *s2, pathfixlist l)
165 {
166   pathfixlist pf = (pathfixlist)malloc(sizeof(struct pathfixlist));
167   pf->s1 = s1;
168   pf->s2 = s2;
169   pf->next = l;
170   return pf;
171 }
172
173 char *pathfix(char *path, pathfixlist fixes)
174 {
175   char buffer[MAXPATHLEN]; pathfixlist l; 
176   char buf2[MAXPATHLEN]; 
177   char *offs; int mod, len;
178   strcpy(buffer,path);
179   mod = 1;
180   while (mod) {
181     mod = 0;
182     for (l=fixes; l; l=l->next) {
183       len = strlen(l->s1);
184       offs = strstr(buffer, l->s1);
185       if (offs) {
186         offs[0]=0;
187         sprintf(buf2,"%s%s%s",buffer,l->s2,offs+len);
188         strcpy(buffer,buf2);
189         mod = 1;
190       }
191     }
192   }
193   return strdup(buffer);
194 }
195
196 char *pathextfix(char *path, pathfixlist fixes, char *ext)
197 {
198   char *newpath = pathfix(path, fixes);
199   char *ret;
200   if (ext == NULL) return newpath;
201   ret = (char *)malloc(strlen(newpath)+strlen(ext)+2);
202   strcpy(ret, newpath);
203   strcat(ret, ext);
204   return ret;
205 }
206
207 /****************************************************************************
208  *
209  * Miscellaneous minor routines.
210  *
211  ****************************************************************************/
212
213 int is_quote(char c)
214 {
215   return (c=='\'' || c == '"');
216 }
217
218 void zap_newline(char *s)
219 {
220   char *p;
221   p = s + strlen(s)-1;
222   if (*p == '\n') *p = '\0';
223   /* in case of DOS ^m */
224   p--;
225   if (*p == '\15') *p = '\0';
226 }
227
228 /* get substring from lo to hi, remove quote chars */
229 char *substr(char *lo, char *hi)
230 {
231   int len;
232   char *res;
233   if (is_quote(*lo)) lo++;
234   if (is_quote(*(hi-1))) hi--;
235   len = hi-lo;
236   res = (char *)malloc(1+len);
237   memcpy(res, lo, len);
238   res[len]=0;
239   return res;
240 }
241
242 int subeqs(char *lo, char *hi, char *str)
243 {
244   int len = strlen(str);
245   if (hi-lo != len) return 0;
246   if (memcmp(lo, str, len)) return 0;
247   return 1;
248 }
249
250 /* advance pointer over blank characters */
251 char *skipblanks(char *p)
252 {
253   while ((*p==' ')||(*p=='\t')) p++;
254   return p;
255 }
256
257 /* advance pointer over nonblank characters and a quoted string */
258 char *skipstuff(char *p)
259 {
260   char quote = 0;
261   if (*p && (*p=='\'' || *p=='"')) { quote=*p; p++; }
262   if (quote != 0) {
263     while (*p&&*p!=quote) p++;
264     if (*p!=quote) {
265       fprintf(stderr, "ERROR> Unmatched quote in nodelist file.\n");
266       exit(1);
267     }
268     p++;
269   }
270   else
271     while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
272   return p;
273 }
274
275 #if CMK_USE_RSH
276 char *getenv_rsh()
277 {
278   char *e;
279
280   e = getenv("CONV_RSH");
281   return e ? e : RSH_CMD;
282 }
283 #endif
284
285 #if !defined(_WIN32) || defined(__CYGWIN__)
286 char *getenv_display()
287 {
288   static char result[100],ipBuf[200];
289   char *e, *p;
290   
291   e = getenv("DISPLAY");
292   if (e==0) return NULL;
293   p = strrchr(e, ':');
294   if (p==0) return NULL;
295   if ((e[0]==':')||(strncmp(e,"unix:",5)==0)) {
296     sprintf(result,"%s:%s",skt_print_ip(ipBuf,skt_my_ip()),p+1);
297   }
298   else strcpy(result, e);
299   return result;
300 }
301 char *getenv_display_no_tamper()
302 {
303   static char result[100],ipBuf[200];
304   char *e, *p;
305   
306   e = getenv("DISPLAY");
307   if (e==0) return NULL;
308   p = strrchr(e, ':');
309   if (p==0) return NULL;
310   strcpy(result, e);
311   return result;
312 }
313
314 #endif
315
316 /*****************************************************************************
317  *                                                                           *
318  * PPARAM - obtaining "program parameters" from the user.                    *
319  *                                                                           *
320  *****************************************************************************/
321
322 typedef struct ppdef
323 {
324   union {
325       int *i;
326       double *r;
327       char **s;
328       int *f;
329     } where;/*Where to store result*/
330   const char *lname; /*Argument name on command line*/
331   const char *doc;
332   char  type; /*One of i, r, s, f.*/
333   struct ppdef *next;
334 }
335 *ppdef;
336
337 static ppdef ppdefs;
338
339 static int     pparam_pos;
340 static char  **pparam_argv;
341 static char    pparam_optc='-';
342 char           pparam_error[100];
343
344 static ppdef pparam_find(lname)
345     const char *lname;
346 {
347   ppdef def;
348   for (def=ppdefs; def; def=def->next)
349     if (strcmp(def->lname, lname)==0)
350       return def;
351   return 0;
352 }
353
354 static ppdef pparam_cell(lname)
355     const char *lname;
356 {
357   ppdef def = pparam_find(lname);
358   if (def) return def;
359   def = (ppdef)malloc(sizeof(struct ppdef));
360   def->lname = lname;
361   def->type  = 's';
362   def->doc   = "(undocumented)";
363   def->next  = ppdefs;
364   ppdefs = def;
365   return def;
366 }
367
368
369
370 void pparam_int(int *where,int defValue,
371                                    const char *arg,const char *doc)
372 {
373   ppdef def = pparam_cell(arg);
374   def->type  = 'i';
375   def->where.i = where; *where=defValue;
376   def->lname=arg;
377   def->doc=doc;
378 }
379
380 void pparam_flag(int *where,int defValue,
381                                    const char *arg,const char *doc)
382 {
383   ppdef def = pparam_cell(arg);
384   def->type  = 'f';
385   def->where.f = where; *where=defValue;
386   def->lname=arg;
387   def->doc=doc;
388 }
389
390 void pparam_real(double *where,double defValue,
391                                    const char *arg,const char *doc)
392 {
393   ppdef def = pparam_cell(arg);
394   def->type  = 'r';
395   def->where.r = where; *where=defValue;
396   def->lname=arg;
397   def->doc=doc;
398 }
399 void pparam_str(char **where,char *defValue,
400                                    const char *arg,const char *doc)
401 {
402   ppdef def = pparam_cell(arg);
403   def->type  = 's';
404   def->where.s = where; *where=defValue;
405   def->lname=arg;
406   def->doc=doc;
407 }
408
409 static int pparam_setdef(def, value)
410     ppdef def; char *value;
411 {
412   char *p;
413   switch(def->type)
414     {
415     case 'i' :
416       *def->where.i = strtol(value, &p, 10);
417       if (*p) return -1;
418       return 0;
419     case 'r' :
420       *def->where.r = strtod(value, &p);
421       if (*p) return -1;
422       return 0;
423     case 's' :
424       *def->where.s = strdup(value);
425       return 0;
426     case 'f' :
427       *def->where.f = strtol(value, &p, 10);
428       if (*p) return -1;
429       return 0;
430     }
431   return -1;
432 }
433
434 int pparam_set(lname, value)
435     char *lname; char *value;
436 {
437   ppdef def = pparam_cell(lname);
438   return pparam_setdef(def, value);
439 }
440
441 char *pparam_getdef(def)
442     ppdef def;
443 {
444   static char result[100];
445   switch(def->type)
446     {
447     case 'i': sprintf(result,"%d", *def->where.i); return result;
448     case 'r': sprintf(result,"%f",*def->where.r); return result;
449     case 's': return *def->where.s?*def->where.s:"";
450     case 'f': sprintf(result,"%d", *def->where.f); return result;
451     }
452   return NULL;
453 }
454
455 void pparam_printdocs()
456 {
457   ppdef def; int len, maxname, maxdoc;
458   maxname = 0;
459   maxdoc = 0;
460   for (def=ppdefs; def; def=def->next)
461     {
462       len = strlen(def->lname);
463       if (len>maxname) maxname=len;
464       len = strlen(def->doc);
465       if (len>maxdoc) maxdoc=len;
466     }
467   fprintf(stderr,"\n");
468   fprintf(stderr,"Charmrun Command-line Parameters:\n");
469   for (def=ppdefs; def; def=def->next)
470     {
471       fprintf(stderr,"  %c%c%-*s ",pparam_optc,pparam_optc,maxname,def->lname);
472       fprintf(stderr,"  %-*s [%s]\n",maxdoc,def->doc,pparam_getdef(def));
473     }
474   fprintf(stderr,"\n");
475 }
476
477 void pparam_delarg(i)
478     int i;
479 {
480   int j;
481   for (j=i; pparam_argv[j]; j++)
482     pparam_argv[j]=pparam_argv[j+1];
483 }
484
485 int pparam_countargs(argv)
486     char **argv;
487 {
488   int argc;
489   for (argc=0; argv[argc]; argc++);
490   return argc;
491 }
492
493 int pparam_parseopt()
494 {
495   int ok; ppdef def=NULL;
496   char *opt = pparam_argv[pparam_pos];
497   /* handle ++ by skipping to end */
498   if ((opt[1]=='+')&&(opt[2]==0))
499     {
500       pparam_delarg(pparam_pos);
501       while (pparam_argv[pparam_pos]) pparam_pos++;
502       return 0;
503     }
504   /* handle + by itself - an error */
505   if (opt[1]==0) 
506     {
507       sprintf(pparam_error,"Illegal option +\n");
508       return -1;
509     }
510   /* look up option definition */
511   if (opt[1]=='+') def = pparam_find(opt+2);
512   else
513     {
514       char name[2];
515       name[0]=opt[1];
516       name[1]=0;
517       def = pparam_find(name);
518     }
519   if (def==NULL)
520   {
521     if (opt[1]=='+')
522     {
523        sprintf(pparam_error,"Option %s not recognized.",opt);
524        return -1;
525     } else {
526            /*Unrecognized + option-- skip it.*/
527            pparam_pos++;
528            return 0;
529         }
530   }
531   /* handle flag-options */
532   if ((def->type=='f')&&(opt[1]!='+')&&(opt[2]))
533     {
534       sprintf(pparam_error,"Option %s should not include a value",opt);
535       return -1;
536     }
537   if (def->type=='f')
538     {
539       *def->where.f = 1;
540       pparam_delarg(pparam_pos);
541       return 0;
542     }
543   /* handle non-flag options */
544   if ((opt[1]=='+')||(opt[2]==0))
545     {
546       pparam_delarg(pparam_pos);
547       opt = pparam_argv[pparam_pos];
548     }
549   else opt+=2;
550   if ((opt == 0)||(opt[0] == 0))
551     {
552       sprintf(pparam_error,"%s must be followed by a value.",opt);
553       return -1;
554     }
555   ok = pparam_setdef(def, opt);
556   pparam_delarg(pparam_pos);
557   if (ok<0)
558     {
559       sprintf(pparam_error,"Illegal value for %s",opt);
560       return -1;
561     }
562   return 0;
563 }
564
565 int pparam_parsecmd(optchr, argv)
566     char optchr; char **argv;
567 {
568   pparam_error[0]=0;
569   pparam_argv = argv;
570   pparam_optc = optchr;
571   pparam_pos  = 0;
572   while(1)
573     {
574       char *opt = pparam_argv[pparam_pos];
575       if (opt==0) break;
576       if (opt[0]!=optchr) pparam_pos++;
577       else if (pparam_parseopt()<0) return -1;
578     }
579   return 0;
580 }
581
582 /****************************************************************************
583  * 
584  * ARG
585  *
586  * The following module computes a whole bunch of miscellaneous values, which
587  * are all constant throughout the program.  Naturally, this includes the
588  * value of the command-line arguments.
589  *
590  *****************************************************************************/
591
592
593 #define MAX_NODES 1000
594 #define MAX_LINE_LENGTH 1000
595
596 char **arg_argv;
597 int    arg_argc;
598
599 int   arg_requested_pes;
600 int   arg_timeout;
601 int   arg_verbose;
602 char *arg_nodelist;
603 char *arg_nodegroup;
604 char *arg_runscript; /* script to run the node-program with */
605 char *arg_charmrunip;
606 #if CONVERSE_VERSION_VMI
607 char *arg_vmispecfile;
608 #endif
609
610 int   arg_debug;
611 int   arg_debug_no_pause;
612 int   arg_charmdebug;
613
614 int   arg_local;        /* start node programs directly by exec on localhost */
615 int   arg_batch_spawn;  /* control starting node programs, several at a time */
616 int   arg_scalable_start;
617
618 int   arg_help;         /* print help message */
619 int   arg_ppn;          /* pes per node */
620 int   arg_usehostname;
621
622 #ifdef _FAULT_MLOG_
623 int     arg_read_pes=0;
624 #endif
625
626 #if CMK_USE_RSH
627 int   arg_maxrsh;
628 char *arg_shell;
629 int   arg_in_xterm;
630 char *arg_debugger;
631 char *arg_xterm;
632 char *arg_display;
633 int arg_ssh_display;
634 char *arg_mylogin;
635 #endif
636
637 char *arg_nodeprog_a;
638 char *arg_nodeprog_r;
639 char *arg_currdir_a;
640 char *arg_currdir_r;
641
642 int   arg_server;
643 int   arg_server_port=0;
644 char *arg_server_auth=NULL;
645
646 #if CMK_BPROC
647 int   arg_startpe;
648 int   arg_endpe;
649 int   arg_singlemaster;
650 int   arg_skipmaster;
651 #endif
652
653 void arg_init(int argc, char **argv)
654 {
655   static char buf[1024];
656   
657   int i, local_def=0;
658 #if CMK_CHARMRUN_LOCAL
659   local_def=1; /*++local is the default*/
660 #endif
661   
662   pparam_int(&arg_requested_pes, 1, "p",             "number of processes to create");
663   pparam_int(&arg_timeout,      60, "timeout",       "seconds to wait per host connection");
664   pparam_flag(&arg_verbose,      0, "verbose",       "Print diagnostic messages");
665   pparam_str(&arg_nodelist,      0, "nodelist",      "file containing list of nodes");
666   pparam_str(&arg_nodegroup,"main", "nodegroup",     "which group of nodes to use");
667 #ifdef _FAULT_MLOG_
668         pparam_int(&arg_read_pes, 0, "readpe",             "number of host names to read into the host table");
669 #endif
670
671 #if CMK_CCS_AVAILABLE
672   pparam_flag(&arg_server,       0, "server",        "Enable client-server (CCS) mode");
673   pparam_int(&arg_server_port,   0, "server-port",   "Port to listen for CCS requests");
674   pparam_str(&arg_server_auth,   0, "server-auth",   "CCS Authentication file");
675 #endif
676   pparam_flag(&arg_local,       local_def, "local", "Start node programs locally without daemon");
677   pparam_int(&arg_batch_spawn,   0, "batch", "Rsh several node programs at a time, avoiding overloading charmrun pe");
678   pparam_flag(&arg_scalable_start, 0, "scalable-start", "scalable start");
679   pparam_flag(&arg_usehostname,  0, "usehostname", "Send nodes our symbolic hostname instead of IP address");
680   pparam_str(&arg_charmrunip,    0, "useip",      "Use IP address provided for charmrun IP");
681 #if CMK_USE_RSH
682   pparam_flag(&arg_debug,         0, "debug",         "Run each node under gdb in an xterm window");
683   pparam_flag(&arg_debug_no_pause,0, "debug-no-pause","Like debug, except doesn't pause at beginning");
684
685   /* When the ++charmdebug flag is used, charmrun listens from its stdin for
686      commands, and forwards them to the gdb info program (a child), or to the
687      processor gdbs. The stderr is redirected to the stdout, so the two streams
688      are mixed together. The channel for stderr is reused to forward the replies
689      of gdb back to the java debugger. */
690 #if !defined(_WIN32)
691   pparam_flag(&arg_charmdebug,    0, "charmdebug",    "Used only when charmrun is started by charmdebug");
692 #endif
693
694   pparam_int(&arg_maxrsh,        16, "maxrsh",        "Maximum number of rsh's to run at a time");
695   pparam_str(&arg_shell,          0, "remote-shell",  "which remote shell to use");
696   pparam_str(&arg_debugger,       0, "debugger",      "which debugger to use");
697   pparam_str(&arg_display,        0, "display",       "X Display for xterm");
698   pparam_flag(&arg_ssh_display,   0, "ssh-display",   "use own X Display for each ssh session");
699   pparam_flag(&arg_in_xterm,      0, "in-xterm",      "Run each node in an xterm window");
700   pparam_str(&arg_xterm,          0, "xterm",         "which xterm to use");
701 #endif
702 #ifdef CMK_BPROC
703   /* options for Scyld */
704   pparam_int(&arg_startpe,   0, "startpe",   "first pe to start job(SCYLD)");
705   pparam_int(&arg_endpe,  1000000, "endpe",   "last pe to start job(SCYLD)");
706   pparam_flag(&arg_singlemaster, 0, "singlemaster", "Only assign one process to master node(SCYLD)");
707   pparam_flag(&arg_skipmaster, 0, "skipmaster", "Donot assign any process to master node(SCYLD)");
708   if (arg_skipmaster && arg_singlemaster) {
709     printf("Charmrun> 'singlemaster' is ignored due to 'skipmaster'. \n");
710     arg_singlemaster = 0;
711   }
712   pparam_flag(&arg_debug,         0, "debug",         "turn on more verbose debug print");
713 #endif
714 #ifdef CONVERSE_VERSION_VMI
715   pparam_str (&arg_vmispecfile, 0, "specfile", "device specfile to load (VMI)");
716 #endif
717   pparam_str(&arg_runscript,    0, "runscript", "script to run node-program with");
718   pparam_flag(&arg_help,        0, "help", "print help messages");
719   pparam_int(&arg_ppn,          0, "ppn",             "number of pes per node");
720
721   if (pparam_parsecmd('+', argv) < 0) {
722     fprintf(stderr,"ERROR> syntax: %s\n",pparam_error);
723     pparam_printdocs();
724     exit(1);
725   }
726   
727   /* Check for (but do *not* remove) the "-?", "-h", or "--help" flags */
728   for (i=0;argv[i];i++) {
729         if (0==strcmp(argv[i],"-?") ||
730             0==strcmp(argv[i],"-h") ||
731             0==strcmp(argv[i],"--help")) 
732                 arg_help=1;
733   }
734   if (arg_help) {
735     pparam_printdocs();
736     /*exit(0);*/
737   }
738
739   arg_argv = argv+1; /*Skip over charmrun (0) here and program name (1) later*/
740   arg_argc = pparam_countargs(arg_argv);
741   if (arg_argc<1) {
742     fprintf(stderr,"ERROR> You must specify a node-program.\n");
743     pparam_printdocs();
744     exit(1);
745   }
746   arg_argv++; arg_argc--;
747
748   if (arg_server_port || arg_server_auth) arg_server=1;
749
750   if (arg_debug || arg_debug_no_pause) {
751         arg_verbose=1;
752         /*Pass ++debug along to program (used by machine.c)*/
753         arg_argv[arg_argc++]="++debug";
754   }
755
756 #ifdef CMK_BPROC
757   if (arg_local) {
758     fprintf(stderr,"Warning> ++local cannot be used in bproc version, ignored!\n");
759     arg_local = 0;
760   }
761 #endif
762
763 #if CMK_USE_RSH
764   /* Find the current value of the CONV_RSH variable */
765   if(!arg_shell) arg_shell = getenv_rsh();
766
767   /* Find the current value of the DISPLAY variable */
768   if(!arg_display)
769     arg_display = getenv_display_no_tamper();
770   if ((arg_debug || arg_debug_no_pause || arg_in_xterm) && (arg_display==0)) {
771     fprintf(stderr,"ERROR> DISPLAY must be set to use debugging mode\n");
772     exit(1);
773   }
774   if (arg_debug || arg_debug_no_pause) 
775     arg_timeout=8*60*60; /* Wait 8 hours for ++debug */
776
777   /* default debugger is gdb */
778   if(!arg_debugger)
779     arg_debugger = "gdb" ;
780   /* default xterm is xterm */
781   if(!arg_xterm)
782     arg_xterm = "xterm" ;
783
784   arg_mylogin = mylogin();
785 #endif
786
787 #if CONVERSE_VERSION_VMI
788   if (!arg_vmispecfile) {
789     arg_vmispecfile = getenv ("VMI_SPECFILE");
790   }
791
792   if (!arg_vmispecfile) {
793     fprintf (stderr, "ERROR> ++specfile not specified and VMI_SPECFILE not given in environment\n");
794     exit (1);
795   }
796 #endif
797
798   /* find the current directory, absolute version */
799   getcwd(buf, 1023);
800   arg_currdir_a = strdup(buf);
801     
802   /* find the node-program, absolute version */
803   arg_nodeprog_r = argv[1];
804
805   if (arg_nodeprog_r[0]=='-' || arg_nodeprog_r[0]=='+') 
806   { /*If it starts with - or +, it ain't a node program.
807       Chances are, the user screwed up and passed some unknown flag to charmrun*/
808      printf("Charmrun does not recognize the flag '%s'.\n",arg_nodeprog_r);
809      if (arg_nodeprog_r[0]=='+')
810        printf("Charm++'s flags need to be placed *after* the program name.\n");
811      pparam_printdocs();
812      exit(1);
813   }
814
815
816 #if defined(_WIN32) && !defined(__CYGWIN__)
817   if (argv[1][1]==':' || argv[1][0]=='\\' && argv[1][1]=='\\') { /*E.g.: "C:\foo\bar.exe*/
818 #else
819   if (argv[1][0]=='/') { /*E.g.: "\foo\bar"*/
820 #endif
821           /*Absolute path to node-program*/
822     arg_nodeprog_a = argv[1];
823   } else {
824     sprintf(buf,"%s%s%s",arg_currdir_a,DIRSEP,arg_nodeprog_r);
825     arg_nodeprog_a = strdup(buf);
826   }
827   if (arg_scalable_start) {
828     printf("Charmrun> scalable start enabled. \n");
829     if (arg_debug || arg_debug_no_pause) {
830       fprintf(stderr, "Charmrun> Error: ++scalable-start does not support debugging mode. \n");
831       exit(1);
832     }
833   }
834 }
835
836 /****************************************************************************
837  *                                                                           
838  * NODETAB:  The nodes file and nodes table.
839  *
840  ****************************************************************************/
841
842 static int portOk = 1;
843 static const char *nodetab_tempName=NULL;
844 char *nodetab_file_find()
845 {
846   char buffer[MAXPATHLEN];
847
848   /* Find a nodes-file as specified by ++nodelist */
849   if (arg_nodelist) {
850     char *path = arg_nodelist;
851     if (probefile(path)) return strdup(path);
852     fprintf(stderr,"ERROR> No such nodelist file %s\n",path);
853     exit(1);
854   }
855   /* Find a nodes-file as specified by getenv("NODELIST") */
856   if (getenv("NODELIST")) {
857     char *path = getenv("NODELIST");        
858     if (path && probefile(path)) return strdup(path);
859     fprintf(stderr,"ERROR> Cannot find nodelist file %s\n",path);
860     exit(1);
861   }
862   /* Find a nodes-file by looking under 'nodelist' in the current directory */
863   if (probefile("./nodelist")) return strdup("./nodelist");
864 #if defined(_WIN32) && !defined(__CYGWIN__)
865   tmpnam(buffer);
866   nodetab_tempName=strdup(buffer);
867 #else /*UNIX*/
868   if (getenv("HOME")) {
869     sprintf(buffer,"%s/.nodelist",getenv("HOME"));
870   }
871 #endif
872   if (!probefile(buffer)) 
873   {
874     /*Create a simple nodelist in the user's home*/
875     FILE *f=fopen(buffer,"w");
876     if (f==NULL) {
877       fprintf(stderr,"ERROR> Cannot create a 'nodelist' file.\n");
878       exit(1);
879     }
880     fprintf(f,"group main\nhost localhost\n");
881     fclose(f);
882   }
883   return strdup(buffer);
884 }
885
886 typedef struct nodetab_host {
887   char    *name;  /*Host DNS name*/
888   skt_ip_t ip; /*IP address of host*/
889   pathfixlist pathfixes;
890   char    *ext;  /*FIXME: What the heck is this?  OSL 9/8/00*/
891   int      cpus;  /* # of physical CPUs*/
892   int      rank;  /*Rank of this CPU*/
893   double   speed; /*Relative speed of each CPU*/
894   int      nice;  /* process priority */
895   int      forks; /* number of processes to fork on remote node */
896   /*These fields are set during node-startup*/
897   int     dataport;/*UDP port number*/
898   SOCKET  ctrlfd;/*Connection to control port*/
899 #if CMK_USE_RSH
900   char    *shell;  /*Rsh to use*/
901   char    *debugger ; /*Debugger to use*/
902   char    *xterm ;  /*Xterm to use*/
903   char    *login;  /*User login name to use*/
904   char    *passwd;  /*User login password*/
905   char    *setup;  /*Commands to execute on login*/
906 #endif
907
908 #if CMK_USE_IBVERBS
909         ChInfiAddr *qpData;
910 #endif
911 #if CMK_USE_IBUD
912         ChInfiAddr qp;
913 #endif
914
915
916 } nodetab_host;
917
918 nodetab_host **nodetab_table;
919 int           nodetab_max;
920 int           nodetab_size;
921 int          *nodetab_rank0_table;
922 int           nodetab_rank0_size;
923
924 #ifdef _FAULT_MLOG_
925 int                     loaded_max_pe;
926 #endif
927
928 void nodetab_reset(nodetab_host *h)
929 {
930   h->name="SET_H->NAME";
931   h->ip=_skt_invalid_ip;
932   h->pathfixes = 0;
933   h->ext = NULL;
934   h->speed = 1.0;
935   h->cpus = 1;
936   h->rank = 0;
937   h->nice=-100;
938   h->forks = 0;
939   h->dataport=-1;
940   h->ctrlfd=-1;
941 #if CMK_USE_RSH
942   h->shell = arg_shell;
943   h->debugger = arg_debugger;
944   h->xterm = arg_xterm;
945   h->login = arg_mylogin;
946   h->passwd = "*";
947   h->setup = "*";
948 #endif
949 }
950
951 void nodetab_add(nodetab_host *h)
952 {
953   if (h->rank == 0)
954     nodetab_rank0_table[nodetab_rank0_size++] = nodetab_size;
955   nodetab_table[nodetab_size] = (nodetab_host *) malloc(sizeof(nodetab_host));
956
957   if (arg_verbose) {
958     char ips[200];
959     skt_print_ip(ips,h->ip);
960     printf("Charmrun> adding client %d: \"%s\", IP:%s\n", nodetab_size, h->name, ips);
961   }
962
963   *nodetab_table[nodetab_size++] = *h;
964 }
965
966 void nodetab_makehost(char *name,nodetab_host *h)
967 {
968   h->name=strdup(name);
969   h->ip = skt_innode_lookup_ip(name);
970   if (skt_ip_match(h->ip,_skt_invalid_ip)) {
971 #ifdef CMK_BPROC
972     /* only the master node is used */
973     if (!(1 == arg_requested_pes && atoi(name)==-1))
974 #endif
975     {
976     fprintf(stderr,"ERROR> Cannot obtain IP address of %s\n", name);
977     exit(1);
978     }
979   }
980   if (nodetab_size == nodetab_max) return;
981   nodetab_add(h);
982 }
983
984 char *nodetab_args(char *args,nodetab_host *h)
985 {
986   if (arg_ppn>0) h->cpus = arg_ppn;
987   while(*args != 0) {
988     char *b1 = skipblanks(args), *e1 = skipstuff(b1);
989     char *b2 = skipblanks(e1), *e2 = skipstuff(b2);
990     while (*b1=='+') b1++;/*Skip over "++" on parameters*/
991 #if CMK_USE_RSH
992     if (subeqs(b1,e1,"login")) h->login = substr(b2,e2);
993     else if (subeqs(b1,e1,"passwd")) h->passwd = substr(b2,e2);
994     else if (subeqs(b1,e1,"setup")) h->setup = strdup(b2);
995     else if (subeqs(b1,e1,"shell")) h->shell = substr(b2,e2);
996     else if (subeqs(b1,e1,"debugger")) h->debugger = substr(b2,e2);
997     else if (subeqs(b1,e1,"xterm")) h->xterm = substr(b2,e2);
998     else 
999 #endif
1000     if (subeqs(b1,e1,"speed")) h->speed = atof(b2);
1001     else if (subeqs(b1,e1,"cpus")) {
1002       if (arg_ppn==0) h->cpus = atol(b2);       /* ignore if there is ++ppn */
1003     }
1004     else if (subeqs(b1,e1,"pathfix")) {
1005       char *b3 = skipblanks(e2), *e3 = skipstuff(b3);
1006       args = skipblanks(e3);
1007       h->pathfixes=pathfix_append(substr(b2,e2),substr(b3,e3),h->pathfixes);
1008       e2 = e3;       /* for the skipblanks at the end */
1009     } 
1010     else if (subeqs(b1,e1,"ext"))  h->ext = substr(b2,e2);
1011     else if (subeqs(b1,e1,"nice"))  h->nice = atoi(b2);
1012     else return args;
1013     args = skipblanks(e2);
1014   }
1015 #if CMK_SHARED_VARS_UNAVAILABLE
1016   if (h->cpus != 1) {
1017     fprintf(stderr,"Warning> Invalid cpus %d in nodelist ignored.\n", h->cpus);
1018     h->cpus = 1;
1019   }
1020 #endif
1021   return args;
1022 }
1023
1024 /*  setup nodetab as localhost only */
1025 void nodetab_init_for_local()
1026 {
1027   int tablesize, i, done=0;
1028   nodetab_host group;
1029
1030   tablesize = arg_requested_pes;
1031   nodetab_table=(nodetab_host**)malloc(tablesize*sizeof(nodetab_host*));
1032   nodetab_rank0_table=(int*)malloc(tablesize*sizeof(int));
1033   nodetab_max=tablesize;
1034
1035   nodetab_reset(&group);
1036   if (arg_ppn==0) arg_ppn=1;
1037 #if CMK_SHARED_VARS_UNAVAILABLE
1038   if (arg_ppn > 1) {
1039     fprintf(stderr,"Warning> Invalid ppn %d in nodelist ignored.\n", arg_ppn);
1040     arg_ppn=1;
1041   }
1042 #endif
1043   group.cpus = arg_ppn;
1044   i = 0;
1045   while (!done) {
1046     char *hostname = "127.0.0.1";
1047     for (group.rank = 0; group.rank<arg_ppn; group.rank++) {
1048       nodetab_makehost(hostname, &group);
1049       if (++i == arg_requested_pes) { done = 1; break; }
1050     }
1051   }
1052 }
1053
1054 void nodetab_init()
1055 {
1056   FILE *f,*fopen();
1057   char *nodesfile; 
1058   nodetab_host global,group,host;
1059   char input_line[MAX_LINE_LENGTH];
1060   int rightgroup, basicsize, i, remain;
1061   
1062   /* if arg_local is set, ignore the nodelist file */
1063   if (arg_local) {
1064     nodetab_init_for_local();
1065     goto fin;
1066   }
1067
1068   /* Open the NODES_FILE. */
1069   nodesfile = nodetab_file_find();
1070   if(arg_verbose)
1071     fprintf(stderr, "Charmrun> using %s as nodesfile\n", nodesfile);
1072   if (!(f = fopen(nodesfile,"r"))) {
1073     fprintf(stderr,"ERROR> Cannot read %s: %s\n",nodesfile,strerror(errno));
1074     exit(1);
1075   }
1076  
1077 #ifdef _FAULT_MLOG_
1078         if(arg_read_pes == 0){
1079         arg_read_pes = arg_requested_pes;
1080     }
1081         nodetab_table=(nodetab_host**)malloc(arg_read_pes*sizeof(nodetab_host*));
1082         nodetab_rank0_table=(int*)malloc(arg_read_pes*sizeof(int));
1083         nodetab_max=arg_read_pes;
1084     fprintf(stderr,"arg_read_pes %d arg_requested_pes %d\n",arg_read_pes,arg_requested_pes);
1085 #else
1086         nodetab_table=(nodetab_host**)malloc(arg_requested_pes*sizeof(nodetab_host*));
1087         nodetab_rank0_table=(int*)malloc(arg_requested_pes*sizeof(int));
1088         nodetab_max=arg_requested_pes;
1089 #endif
1090  
1091   
1092   nodetab_reset(&global);
1093   group=global;
1094   rightgroup = (strcmp(arg_nodegroup,"main")==0);
1095   
1096   while(fgets(input_line,sizeof(input_line)-1,f)!=0) {
1097 #ifdef _FAULT_MLOG_
1098         if (nodetab_size == arg_read_pes) break;
1099 #else
1100     if (nodetab_size == arg_requested_pes) break;
1101 #endif
1102     if (input_line[0]=='#') continue;
1103     zap_newline(input_line);
1104         if (!nodetab_args(input_line,&global)) {
1105                 /*An option line-- also add options to current group*/
1106                 nodetab_args(input_line,&group);
1107         }
1108         else {/*Not an option line*/
1109                 char *b1 = skipblanks(input_line), *e1 = skipstuff(b1);
1110                 char *b2 = skipblanks(e1), *e2 = skipstuff(b2);
1111                 char *b3 = skipblanks(e2);
1112                 if (subeqs(b1,e1,"host")) {
1113                         if (rightgroup) {
1114                                 host=group;
1115                                 nodetab_args(b3,&host);
1116                                 for (host.rank=0; host.rank<host.cpus; host.rank++)
1117                                         nodetab_makehost(substr(b2,e2),&host);
1118                         }
1119                 } else if (subeqs(b1,e1, "group")) {
1120                         group=global;
1121                         nodetab_args(b3,&group);
1122                         rightgroup = subeqs(b2,e2,arg_nodegroup);
1123                 } else if (b1!=b3) {
1124                         fprintf(stderr,"ERROR> unrecognized command in nodesfile:\n");
1125                         fprintf(stderr,"ERROR> %s\n", input_line);
1126                         exit(1);
1127                 }
1128         }
1129   }
1130   fclose(f);
1131   if (nodetab_tempName!=NULL) unlink(nodetab_tempName);
1132
1133   /*Wrap nodes in table around if there aren't enough yet*/
1134   basicsize = nodetab_size;
1135   if (basicsize==0) {
1136     fprintf(stderr,"ERROR> No hosts in group %s\n", arg_nodegroup);
1137     exit(1);
1138   }
1139   while ((nodetab_size < arg_requested_pes)&&(arg_requested_pes!=MAX_NODES))
1140      nodetab_add(nodetab_table[nodetab_size%basicsize]);
1141   
1142 fin:
1143   /*Clip off excess CPUs at end*/
1144   for (i=0; i<nodetab_size; i++) {
1145     if (nodetab_table[i]->rank == 0)
1146       remain = nodetab_size - i;
1147     if (nodetab_table[i]->cpus > remain)
1148       nodetab_table[i]->cpus = remain;
1149   }
1150
1151 #ifdef _FAULT_MLOG_
1152         loaded_max_pe = arg_requested_pes-1;
1153 #endif
1154
1155 }
1156
1157 /* Given a processor number, look up the nodetab info: */
1158 nodetab_host *nodetab_getinfo(int i)
1159 {
1160   if (nodetab_table==0) {
1161     fprintf(stderr,"ERROR> Node table not initialized.\n");
1162     exit(1);
1163   }
1164   return nodetab_table[i];
1165 }
1166
1167 /* Given a node number, look up the nodetab info: */
1168 nodetab_host *nodetab_getnodeinfo(int i)
1169 {
1170   return nodetab_getinfo(nodetab_rank0_table[i]);
1171 }
1172
1173 /*These routines all take *PE* numbers (NOT node numbers!)*/
1174 char        *nodetab_name(int i)     { return nodetab_getinfo(i)->name; }
1175 pathfixlist  nodetab_pathfixes(int i){ return nodetab_getinfo(i)->pathfixes; }
1176 char        *nodetab_ext(int i)      { return nodetab_getinfo(i)->ext; }
1177 skt_ip_t     nodetab_ip(int i)       { return nodetab_getinfo(i)->ip; }
1178 unsigned int nodetab_cpus(int i)     { return nodetab_getinfo(i)->cpus; }
1179 unsigned int nodetab_rank(int i)     { return nodetab_getinfo(i)->rank; }
1180 int          nodetab_dataport(int i) { return nodetab_getinfo(i)->dataport; }
1181 int          nodetab_nice(int i)     { return nodetab_getinfo(i)->nice; }
1182 SOCKET      nodetab_ctrlfd(int i)    { return nodetab_getinfo(i)->ctrlfd;}
1183 #if CMK_USE_RSH
1184 char        *nodetab_setup(int i)    { return nodetab_getinfo(i)->setup; }
1185 char        *nodetab_shell(int i)    { return nodetab_getinfo(i)->shell; }
1186 char        *nodetab_debugger(int i) { return nodetab_getinfo(i)->debugger; }
1187 char        *nodetab_xterm(int i)    { return nodetab_getinfo(i)->xterm; }
1188 char        *nodetab_login(int i)    { return nodetab_getinfo(i)->login; }
1189 char        *nodetab_passwd(int i)   { return nodetab_getinfo(i)->passwd; }
1190 #endif
1191
1192 /****************************************************************************
1193  *
1194  * Nodeinfo
1195  *
1196  * The global list of node PEs, IPs, and port numbers.
1197  * Stored in ChMachineInt_t format so the table can easily be sent
1198  * back to the nodes.
1199  *
1200  ****************************************************************************/
1201
1202 static ChNodeinfo *nodeinfo_arr;/*Indexed by node number.*/
1203
1204 void nodeinfo_allocate(void)
1205 {
1206         nodeinfo_arr=(ChNodeinfo *)malloc(nodetab_rank0_size*sizeof(ChNodeinfo));
1207 }
1208 void nodeinfo_add(const ChSingleNodeinfo *in,SOCKET ctrlfd)
1209 {
1210         int node=ChMessageInt(in->nodeNo);
1211         ChNodeinfo i=in->info;
1212         unsigned int nt;
1213         unsigned int pe;
1214         unsigned int dataport;
1215         int lid,qpn,psn;
1216         if (node<0 || node>=nodetab_rank0_size)
1217                 {fprintf(stderr,"Unexpected node %d registered!\n",node);exit(1);}
1218         nt=nodetab_rank0_table[node];/*Nodetable index for this node*/  
1219         i.nPE=ChMessageInt_new(nodetab_cpus(nt));
1220         i.IP=nodetab_ip(nt);
1221 #if CMK_USE_IBVERBS 
1222         nodeinfo_arr[node] = i;
1223         for (pe=0;pe<nodetab_cpus(nt);pe++){
1224                 nodetab_table[nt+pe]->ctrlfd=ctrlfd;
1225         }
1226         printf("Charmrun> client %d connected\n", nt);
1227 #else
1228         dataport = ChMessageInt(i.dataport);
1229         if (0==dataport)
1230                 {fprintf(stderr,"Node %d could not initialize network!\n",node);exit(1);}
1231         nodeinfo_arr[node]=i;
1232         for (pe=0;pe<nodetab_cpus(nt);pe++)
1233           {
1234             nodetab_table[nt+pe]->dataport=dataport;
1235             nodetab_table[nt+pe]->ctrlfd=ctrlfd;
1236 #if CMK_USE_IBUD
1237             nodetab_table[nt+pe]->qp=i.qp;
1238 #endif
1239           }
1240         if (arg_verbose) {
1241           char ips[200];
1242           skt_print_ip(ips,nodetab_ip(nt));
1243           printf("Charmrun> client %d connected (IP=%s data_port=%d)\n", nt, ips, dataport);
1244 #if CMK_USE_IBUD
1245           printf("Charmrun> client %d lid=%d qpn=%i psn=%i\n",nt,ChMessageInt(i.qp.lid),ChMessageInt(i.qp.qpn),ChMessageInt(i.qp.psn));
1246 #endif
1247         }
1248 #endif
1249 }
1250
1251 /****************************************************************************
1252  *
1253  * input handling
1254  *
1255  * You can use this module to read the standard input.  It supports
1256  * one odd function, input_scanf_chars, which is what makes it useful.
1257  * if you use this module, you may not read stdin yourself.
1258  *
1259  * void input_init(void)
1260  * char *input_gets(void)
1261  * char *input_scanf_chars(char *fmt)
1262  *
1263  ****************************************************************************/
1264
1265 char *input_buffer;
1266
1267 void input_extend()
1268 {
1269   char line[1024];
1270   int len = input_buffer?strlen(input_buffer):0;
1271   fflush(stdout);
1272   if (fgets(line, 1023, stdin)==0) { 
1273     fprintf(stderr,"end-of-file on stdin");
1274     exit(1);
1275   }
1276   input_buffer = realloc(input_buffer, len + strlen(line) + 1);
1277   strcpy(input_buffer+len, line);
1278 }
1279
1280 void input_init()
1281 {
1282   input_buffer = strdup("");
1283 }
1284
1285 char *input_extract(nchars)
1286     int nchars;
1287 {
1288   char *res = substr(input_buffer, input_buffer+nchars);
1289   char *tmp = substr(input_buffer+nchars, input_buffer+strlen(input_buffer));
1290   free(input_buffer);
1291   input_buffer = tmp;
1292   return res;
1293 }
1294
1295 char *input_gets()
1296 {
1297   char *p, *res; int len;
1298   while(1) {
1299     p = strchr(input_buffer,'\n');
1300     if (p) break;
1301     input_extend();
1302   }
1303   len = p-input_buffer;
1304   res = input_extract(len+1);
1305   res[len]=0;
1306   return res;
1307 }
1308
1309 /*FIXME: I am terrified by this routine. OSL 9/8/00*/
1310 char *input_scanf_chars(fmt)
1311     char *fmt;
1312 {
1313   char buf[8192]; int len, pos;
1314   static int fd; static FILE *file;
1315   fflush(stdout);
1316   if (file==0) {
1317 #if CMK_USE_MKSTEMP
1318     char tmp[128];
1319     strcpy(tmp, "/tmp/fnordXXXXXX");
1320     mkstemp(tmp);
1321 #else
1322     char *tmp=tmpnam(NULL);/*This was once /tmp/fnord*/
1323 #endif
1324     unlink(tmp);
1325     fd = open(tmp,O_RDWR | O_CREAT | O_TRUNC);
1326     if (fd<0) { 
1327       fprintf(stderr,"cannot open temp file /tmp/fnord");
1328       exit(1);
1329     }
1330     file = fdopen(fd, "r+");
1331     unlink(tmp);
1332   }
1333   while (1) {
1334     len = strlen(input_buffer);
1335     rewind(file);
1336     fwrite(input_buffer, len, 1, file);
1337     fflush(file);
1338     rewind(file);
1339     ftruncate(fd, len);
1340     fscanf(file, fmt, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf);
1341     pos = ftell(file);
1342     if (pos<len) break;
1343     input_extend();
1344   }
1345   return input_extract(pos);
1346 }
1347
1348 /***************************************************************************
1349 CCS Interface:
1350   Charmrun forwards CCS requests on to the node-programs' control
1351 sockets.
1352 ***************************************************************************/
1353
1354 #if CMK_CCS_AVAILABLE
1355
1356 #define REDIRECT_STDIO  "redirect stdio"
1357 #define FETCH_STDIO "fetch stdio"
1358 char *stdio_buffer = NULL;
1359 int stdio_size = 0;
1360 int stdio_alloc = 0;
1361 int stdio_waiting = 0;
1362 CcsImplHeader stdio_waiting_hdr;
1363
1364 /*The Ccs Server socket became active-- 
1365 rec'v the message and respond to the request,
1366 by forwarding the request to the appropriate node.
1367  */
1368 void req_ccs_connect(void)
1369 {
1370   const void *bufs[3]; int lens[3];
1371   struct {
1372    ChMessageHeader ch;/*Make a charmrun header*/
1373    CcsImplHeader hdr;/*Ccs internal header*/
1374   } h;
1375   void *reqData;/*CCS request data*/
1376   int pe,reqBytes;
1377   if (0==CcsServer_recvRequest(&h.hdr,&reqData))
1378     return;/*Malformed request*/
1379   pe=ChMessageInt(h.hdr.pe);
1380   reqBytes=ChMessageInt(h.hdr.len);
1381
1382   if (pe<0 || pe>=nodetab_size) {
1383         pe=0;
1384         h.hdr.pe=ChMessageInt_new(pe);
1385   }
1386
1387   if (strncmp(REDIRECT_STDIO, h.hdr.handler, strlen(REDIRECT_STDIO))==0) {
1388     /*This is a request to make a duplicate to stdio*/
1389     if (stdio_alloc == 0) {
1390       stdio_alloc = 4096;
1391       stdio_buffer = malloc(stdio_alloc);
1392     }
1393     CcsServer_sendReply(&h.hdr,0,0);
1394   }
1395   else if (strncmp(FETCH_STDIO, h.hdr.handler, strlen(FETCH_STDIO))==0) {
1396     /*Reply with the data loaded until now*/
1397     if (stdio_size > 0) {
1398       h.hdr.len = ChMessageInt_new(1); /* fake len to prevent socket closed without reply! */
1399       CcsServer_sendReply(&h.hdr,stdio_size,stdio_buffer);
1400       stdio_size = 0;
1401     } else {
1402       if (stdio_waiting) {
1403         CcsServer_sendReply(&stdio_waiting_hdr,0,0);
1404       }
1405       stdio_waiting = 1;
1406       stdio_waiting_hdr = h.hdr;
1407       stdio_waiting_hdr.len = ChMessageInt_new(1); /* fake len to prevent socket closed without reply! */
1408     }
1409   }
1410   else {
1411
1412 #define LOOPBACK 0
1413 #if LOOPBACK /*Immediately reply "there's nothing!" (for performance testing)*/
1414   CcsServer_sendReply(&h.hdr,0,0);
1415 #else
1416   /*Fill out the charmrun header & forward the CCS request*/
1417   ChMessageHeader_new("req_fw",sizeof(h.hdr)+reqBytes,&h.ch);  
1418   
1419   bufs[0]=&h; lens[0]=sizeof(h);
1420   bufs[1]=reqData; lens[1]=reqBytes;
1421   skt_sendV(nodetab_ctrlfd(pe),2,bufs,lens);
1422
1423 #endif
1424   }
1425   free(reqData);
1426 }
1427
1428 /*
1429 Forward the CCS reply (if any) from this client back to the 
1430 original network requestor, on the original request socket.
1431  */
1432 int req_ccs_reply_fw(ChMessage *msg,SOCKET srcFd) {
1433   int len=msg->len; /* bytes of data remaining to receive */
1434   
1435   /* First pull down the CCS header sent by the client. */
1436   CcsImplHeader hdr;
1437   skt_recvN(srcFd,&hdr,sizeof(hdr)); len-=sizeof(hdr);
1438   
1439 #define m (4*1024) /* packets of message to recv/send at once */
1440   if (len<m || hdr.attr.auth) 
1441   { /* short or authenticated message: grab the whole thing first */
1442      void *data=malloc(len);
1443      skt_recvN(srcFd,data,len);
1444      CcsServer_sendReply(&hdr,len,data);
1445      free(data);
1446   } 
1447   else 
1448   { /* long messages: packetize (for pipelined sending; a 2x bandwidth improvement!) */
1449     ChMessageInt_t outLen;
1450     int destFd; /* destination for data */
1451     skt_abortFn old=skt_set_abort(reply_abortFn);
1452     int destErrs=0;
1453     
1454     destFd=ChMessageInt(hdr.replyFd);
1455     outLen=ChMessageInt_new(len);
1456     skt_sendN(destFd,&outLen,sizeof(outLen)); /* first comes the length */
1457     while(len>0) {
1458        char buf[m];
1459        int r=m; if (r>len) r=len;
1460        skt_recvN(srcFd,buf,r);
1461        if (0==destErrs) /* don't keep sending to dead clients, but *do* clean out srcFd */
1462           destErrs|=skt_sendN(destFd,buf,r);
1463        len-=m;
1464 #undef m
1465     }
1466     skt_close(destFd);
1467   
1468     skt_set_abort(old); 
1469   }
1470   return 0;
1471 }
1472
1473 #else
1474 int req_ccs_reply_fw(ChMessage *msg,SOCKET srcFd) {
1475   
1476 }
1477 #endif /*CMK_CCS_AVAILABLE*/
1478
1479 /****************************************************************************
1480  *
1481  * REQUEST SERVICER
1482  *
1483  * The request servicer accepts connections on a TCP port.  The client
1484  * sends a sequence of commands (each is one line).  It then closes the
1485  * connection.  The server must then contact the client, sending replies.
1486  *
1487  ****************************************************************************/
1488  /** Macro to switch on the case when charmrun stays up even if
1489  one of the processor crashes*/
1490 /*#define __FAULT__*/
1491
1492 SOCKET *req_clients; /*TCP request sockets for each node*/
1493 int  req_nClients;/*Number of entries in above list (==nodetab_rank0_size)*/
1494 int             req_ending=0;
1495
1496 /* socket and std streams for the gdb info program */
1497 int gdb_info_pid=0;
1498 int gdb_info_std[3];
1499 FILE *gdb_stream=NULL;
1500
1501 #define REQ_OK 0
1502 #define REQ_FAILED -1
1503
1504 /* This is the only place where charmrun talks back to anyone. 
1505 */
1506 int req_reply(SOCKET fd, char *type, 
1507               const char *data, int dataLen)
1508 {
1509   ChMessageHeader msg;
1510   if (fd == INVALID_SOCKET) return REQ_FAILED;
1511   ChMessageHeader_new(type,dataLen,&msg);
1512   skt_sendN(fd,(const char *)&msg,sizeof(msg));
1513   skt_sendN(fd,data,dataLen);
1514   return REQ_OK;
1515 }
1516
1517 /* Request handlers:
1518 When a client asks us to do something, these are the
1519 routines that actually respond to the request.
1520 */
1521 /*Stash this new node's control and data ports.
1522  */
1523 int req_handle_initnode(ChMessage *msg,SOCKET fd)
1524 {
1525 #if CMK_USE_IBVERBS
1526         int i;
1527         ChSingleNodeinfo *nodeInfo = (ChSingleNodeinfo *)msg->data;
1528 //      printf("Charmrun> msg->len %d sizeof(ChSingleNodeinfo) %d sizeof(ChInfiAddr) %d \n",msg->len,sizeof(ChSingleNodeinfo),sizeof(ChInfiAddr));
1529         if(msg->len != sizeof(ChSingleNodeinfo) + (nodetab_rank0_size-1)*sizeof(ChInfiAddr)){
1530     fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
1531                 exit(1);
1532         }
1533         nodeInfo->info.qpList = malloc(sizeof(ChInfiAddr)*(nodetab_rank0_size-1));
1534         memcpy((char *)nodeInfo->info.qpList,&msg->data[sizeof(ChSingleNodeinfo)],sizeof(ChInfiAddr)*(nodetab_rank0_size-1));
1535 /*      for(i=0;i<nodetab_rank0_size-1;i++){
1536                 printf("i %d  0x%0x 0x%0x 0x%0x\n",i,ChMessageInt(nodeInfo->info.qpList[i].lid),ChMessageInt(nodeInfo->info.qpList[i].qpn),ChMessageInt(nodeInfo->info.qpList[i].psn));
1537         }*/
1538 #else
1539   if (msg->len!=sizeof(ChSingleNodeinfo)) {
1540     fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
1541     fprintf(stderr,"Charmrun: possibly because: %s.\n", msg->data);
1542     exit(1);
1543   }
1544 #endif  
1545   nodeinfo_add((ChSingleNodeinfo *)msg->data,fd);
1546   return REQ_OK;
1547 }
1548
1549 /*Get the array of node numbers, IPs, and ports.
1550 This is used by the node-programs to talk to one another.
1551 */
1552 int req_handle_initnodetab(ChMessage *msg,SOCKET fd)
1553 {
1554         ChMessageHeader hdr;
1555         ChMessageInt_t nNodes=ChMessageInt_new(nodetab_rank0_size);
1556         ChMessageHeader_new("initnodetab",sizeof(ChMessageInt_t)+
1557                             sizeof(ChNodeinfo)*nodetab_rank0_size,&hdr);
1558         skt_sendN(fd,(const char *)&hdr,sizeof(hdr));
1559         skt_sendN(fd,(const char *)&nNodes,sizeof(nNodes));
1560         skt_sendN(fd,(const char *)nodeinfo_arr,
1561                   sizeof(ChNodeinfo)*nodetab_rank0_size);
1562                         
1563         return REQ_OK;
1564 }
1565
1566 /* Check this return code from "printf". */
1567 static void checkPrintfError(int err) {
1568   if (err<0) {
1569     static int warned=0;
1570     if (!warned) {
1571       perror("charmrun WARNING> error in printf");
1572       warned=1;
1573     }
1574   }
1575 }
1576
1577 void write_stdio_duplicate(char* data) {
1578   if (stdio_alloc > 0) {
1579     int size = strlen(data);
1580     
1581     if (stdio_waiting) {
1582       stdio_waiting = 0;
1583       CcsServer_sendReply(&stdio_waiting_hdr,size+1,data);
1584     }
1585     else {
1586       if (size+stdio_size >= stdio_alloc) {
1587         char *newbuf;
1588         stdio_alloc += (size>4096 ? size : 4096);
1589         newbuf = malloc(stdio_alloc);
1590         memcpy(newbuf, stdio_buffer, stdio_size);
1591         free(stdio_buffer);
1592         stdio_buffer = newbuf;
1593       }
1594       strcpy(&stdio_buffer[stdio_size], data);
1595       stdio_size += size;
1596     }
1597   }
1598 }
1599
1600 int req_handle_print(ChMessage *msg,SOCKET fd)
1601 {
1602   checkPrintfError(printf("%s",msg->data));
1603   checkPrintfError(fflush(stdout));
1604   write_stdio_duplicate(msg->data);
1605   return REQ_OK;
1606 }
1607
1608
1609 int req_handle_printerr(ChMessage *msg,SOCKET fd)
1610 {
1611   fprintf(stderr,"%s",msg->data);
1612   fflush(stderr);
1613   return REQ_OK;
1614 }
1615
1616
1617 int req_handle_printsyn(ChMessage *msg,SOCKET fd)
1618 {
1619   checkPrintfError(printf("%s",msg->data));
1620   checkPrintfError(fflush(stdout));
1621   write_stdio_duplicate(msg->data);
1622   req_reply(fd, "printdone", "", 1);
1623   return REQ_OK;
1624 }
1625
1626
1627 int req_handle_printerrsyn(ChMessage *msg,SOCKET fd)
1628 {
1629   fprintf(stderr,"%s",msg->data);
1630   fflush(stderr);
1631   req_reply(fd, "printdone", "", 1);
1632   return REQ_OK;
1633 }
1634
1635
1636 int req_handle_ending(ChMessage *msg,SOCKET fd)
1637 {  
1638   int i;
1639   req_ending++;
1640
1641 #ifndef _FAULT_MLOG_    
1642         if (req_ending == nodetab_size)
1643 #else
1644         if(req_ending == arg_requested_pes)
1645 #endif
1646   {
1647     for (i=0;i<req_nClients;i++)
1648       skt_close(req_clients[i]);
1649     if (arg_verbose) printf("Charmrun> Graceful exit.\n");
1650     exit(0);
1651   }
1652   return REQ_OK;
1653 }
1654
1655
1656 int req_handle_abort(ChMessage *msg,SOCKET fd)
1657 {
1658   /*fprintf(stderr,"req_handle_abort called \n");*/
1659   if (msg->len==0) 
1660     fprintf(stderr,"Aborting!\n");
1661   else
1662     fprintf(stderr, "%s\n", msg->data);
1663   exit(1);
1664 }
1665
1666 int req_handle_scanf(ChMessage *msg,SOCKET fd)
1667 {
1668   char *fmt, *res, *p;
1669
1670   fmt = msg->data;
1671   fmt[msg->len-1]=0;
1672   res = input_scanf_chars(fmt);
1673   p = res; while (*p) { if (*p=='\n') *p=' '; p++; }
1674   req_reply(fd, "scanf-data", res, strlen(res)+1);
1675   free(res);
1676   return REQ_OK;
1677 }
1678
1679 #ifdef __FAULT__        
1680 void restart_node(int crashed_node);
1681 void reconnect_crashed_client(int socket_index,int crashed_node);
1682 void anounce_crash(int socket_index,int crashed_node);
1683
1684 static int _last_crash = 0;                     /* last crashed pe number */
1685 static int _crash_socket_index = 0;             /* last restart socket */
1686
1687 #ifdef _FAULT_MLOG_
1688 static int numCrashes=0;  /*number of crashes*/
1689 static SOCKET last_crashed_fd=-1;
1690 #endif
1691
1692 int req_handle_crashack(ChMessage *msg,SOCKET fd)
1693 {
1694   static int count = 0;
1695   count ++;
1696   if (count == req_nClients-1) {
1697     /* only after everybody else update its nodetab, can this
1698        restarted process continue */
1699     printf("Charmrun> continue node: %d\n", _last_crash);
1700     req_handle_initnodetab(NULL,req_clients[_crash_socket_index]);
1701     _last_crash = 0;
1702     count = 0;
1703 #ifdef _FAULT_MLOG_
1704         last_crashed_fd=-1;
1705 #endif
1706   }
1707 }
1708 #endif
1709
1710 #ifdef __FAULT__
1711 void error_in_req_serve_client(SOCKET fd){
1712         SOCKET * new_req_clients=(SOCKET *)malloc((req_nClients-1)*sizeof(SOCKET));
1713         int count=0,i;
1714         int crashed_node,crashed_pe,node_index,socket_index;
1715         fprintf(stdout,"Socket %d failed \n",fd);
1716         for(i=0;i<nodetab_max;i++){
1717                 if(nodetab_ctrlfd(i) == fd){
1718                         break;
1719                 }
1720         }
1721         fflush(stdout);
1722 #ifndef _FAULT_MLOG_
1723         skt_close(fd);
1724 #endif
1725         crashed_pe = i;
1726         node_index = i-nodetab_rank(crashed_pe);
1727         for(i=0;i<nodetab_rank0_size;i++){
1728                 if(node_index == nodetab_rank0_table[i]){
1729                         break;
1730                 }
1731         }
1732         crashed_node = i;
1733         /** should also send a message to all the other processors telling them that this guy has crashed*/
1734         /*anounce_crash(socket_index,crashed_node);*/
1735         restart_node(crashed_node);
1736         
1737         fprintf(stdout,"charmrun says Processor %d failed Node %d\n",crashed_pe,crashed_node);
1738         /** after the crashed processor has been recreated 
1739          it connects to charmrun. That data must now be filled 
1740          into the req_nClients array and the nodetab_table*/
1741
1742         for(i=0;i<req_nClients;i++){
1743                 if(req_clients[i] == fd){
1744                         break;
1745                 }
1746         }       
1747         socket_index = i;
1748         reconnect_crashed_client(socket_index,crashed_node);
1749 #ifdef _FAULT_MLOG_
1750         skt_close(fd);
1751 #endif
1752 }
1753 #endif
1754
1755 int req_handler_dispatch(ChMessage *msg,SOCKET replyFd)
1756 {
1757   char *cmd=msg->header.type;
1758   int recv_status;
1759   DEBUGF(("Got request '%s'\n",cmd,replyFd));
1760 #if CMK_CCS_AVAILABLE   /* CCS *doesn't* want data yet, for faster forwarding */
1761   if (strcmp(cmd,"reply_fw")==0)   return req_ccs_reply_fw(msg,replyFd);
1762 #endif
1763
1764   /* grab request data */
1765   recv_status = ChMessageData_recv(replyFd,msg);
1766 #ifdef __FAULT__
1767 #ifdef _FAULT_MLOG_
1768  if(recv_status < 0){
1769         if(replyFd == last_crashed_fd){
1770             return REQ_OK;
1771         }
1772         DEBUGF(("recv_status %d on socket %d \n",recv_status,replyFd));
1773         error_in_req_serve_client(replyFd);
1774     }
1775 #else   
1776   if(recv_status < 0)  error_in_req_serve_client(replyFd);
1777 #endif
1778 #endif
1779
1780        if (strcmp(cmd,"ping")==0)       return REQ_OK;
1781   else if (strcmp(cmd,"print")==0)      return req_handle_print(msg,replyFd);
1782   else if (strcmp(cmd,"printerr")==0)   return req_handle_printerr(msg,replyFd);
1783   else if (strcmp(cmd,"printsyn")==0)  return req_handle_printsyn(msg,replyFd);
1784   else if (strcmp(cmd,"printerrsyn")==0) return req_handle_printerrsyn(msg,replyFd);
1785   else if (strcmp(cmd,"scanf")==0)      return req_handle_scanf(msg,replyFd);
1786   else if (strcmp(cmd,"ending")==0)     return req_handle_ending(msg,replyFd);
1787   else if (strcmp(cmd,"abort")==0)      return req_handle_abort(msg,replyFd);
1788 #ifdef __FAULT__        
1789   else if (strcmp(cmd,"crash_ack")==0)   return req_handle_crashack(msg,replyFd);
1790 #endif
1791   else {
1792 #ifndef __FAULT__       
1793         fprintf(stderr,"Charmrun> Bad control socket request '%s'\n",cmd); 
1794         abort();
1795         return REQ_OK;
1796 #endif                          
1797   }
1798   return REQ_OK;
1799 }
1800
1801 void req_serve_client(SOCKET fd)
1802 {
1803   int recv_status;
1804   int status;
1805   ChMessage msg;
1806   DEBUGF(("Getting message from client...\n"));
1807   recv_status = ChMessageHeader_recv(fd,&msg);
1808 #ifdef __FAULT__        
1809   if(recv_status < 0) error_in_req_serve_client(fd);
1810 #endif
1811         
1812   DEBUGF(("Message is '%s'\n",msg.header.type));
1813   status = req_handler_dispatch(&msg,fd);
1814   switch (status) 
1815   {
1816     case REQ_OK: break;
1817     case REQ_FAILED: 
1818         fprintf(stderr,"Charmrun> Error processing control socket request %s\n",msg.header.type); 
1819         abort();
1820         break;
1821   }
1822   ChMessage_free(&msg);
1823 }
1824
1825
1826 int ignore_socket_errors(int c,const char *m)
1827 {  /*Abandon on further socket errors during error shutdown*/
1828   
1829 #ifndef __FAULT__       
1830   exit(2);
1831 #endif  
1832         return -1;
1833 }
1834
1835 /*A socket went bad somewhere!  Immediately disconnect,
1836 which kills everybody.
1837 */
1838 int socket_error_in_poll(int code,const char *msg)
1839 {
1840 /*commenting it for fault tolerance*/
1841 /*ifdef it*/
1842
1843         int i;
1844         skt_set_abort(ignore_socket_errors);
1845         fprintf(stderr,"Charmrun: error on request socket--\n"
1846                         "%s\n",msg);
1847 #ifndef __FAULT__                       
1848         for (i=0;i<req_nClients;i++)
1849                 skt_close(req_clients[i]);
1850         exit(1);
1851 #endif  
1852         ftTimer = GetClock();
1853         return -1;
1854 }
1855
1856 /*
1857 Wait for incoming requests on all client sockets,
1858 and the CCS socket (if present).
1859 */
1860 void req_poll()
1861 {
1862   int status,i;
1863   fd_set  rfds;
1864   struct timeval tmo;
1865   int readcount;
1866
1867   skt_set_abort(socket_error_in_poll);
1868
1869   tmo.tv_sec = 1;
1870   tmo.tv_usec = 0;
1871   FD_ZERO(&rfds);
1872   for (i=0;i<req_nClients;i++)
1873         FD_SET(req_clients[i],&rfds);
1874   if (CcsServer_fd()!=INVALID_SOCKET) FD_SET(CcsServer_fd(),&rfds);
1875   if (arg_charmdebug) {
1876     FD_SET(0, &rfds);
1877     FD_SET(gdb_info_std[1], &rfds);
1878     FD_SET(gdb_info_std[2], &rfds);
1879   }
1880   DEBUGF(("Req_poll: Calling select...\n"));
1881   status=select(FD_SETSIZE, &rfds, 0, 0, &tmo);
1882   DEBUGF(("Req_poll: Select returned %d...\n",status));
1883
1884   if (status==0) return;/*Nothing to do-- timeout*/
1885
1886   if (status<0){ 
1887                 fflush(stdout);
1888                 fflush(stderr);
1889                 socket_error_in_poll(1359,"Node program terminated unexpectedly!\n");
1890         }
1891   for (i=0;i<req_nClients;i++)
1892         if (FD_ISSET(req_clients[i],&rfds))
1893           {
1894             readcount=10;   /*number of successive reads we serve per socket*/
1895             /*This client is ready to read*/
1896             do { req_serve_client(req_clients[i]); readcount--;}
1897             while (1==skt_select1(req_clients[i],0) && readcount>0);
1898           }
1899
1900   if (CcsServer_fd()!=INVALID_SOCKET)
1901          if (FD_ISSET(CcsServer_fd(),&rfds)) {
1902                   DEBUGF(("Activity on CCS server port...\n"));
1903                   req_ccs_connect();
1904          }
1905
1906   if (arg_charmdebug) {
1907     char buf[2048];
1908     if (FD_ISSET(0, &rfds)) {
1909       int indata = read(0, buf, 5);
1910       buf[indata] = 0;
1911       if (indata < 5) fprintf(stderr,"Error reading command (%s)\n",buf);
1912       if (strncmp(buf,"info:",5)==0) {
1913         /* Found info command, forward data to gdb info program */
1914         char c;
1915         int num=0;
1916         //printf("Command to be forwarded\n");
1917         while (read(0, &c, 1)!=-1) {
1918           buf[num++]=c;
1919           if (c=='\n' || num >= 2045) {
1920             write(gdb_info_std[0], buf, num);
1921             if (c=='\n') break;
1922           }
1923         }
1924       }
1925       //printf("Command from charmdebug: %d(%s)\n",indata,buf);
1926     }
1927     /* All streams from gdb are forwarded to the stderr stream through the FILE
1928        gdb_stream which has been duplicated from stderr */
1929     /* NOTE: gdb_info_std[2] must be flushed before gdb_info_std[1] because the
1930        latter contains the string "(gdb) " ending the synchronization. Also the
1931        std[1] should be read with the else statement. It will not work without. */
1932     if (FD_ISSET(gdb_info_std[2], &rfds)) {
1933       int indata = read(gdb_info_std[2], buf, 100);
1934       /*printf("read data from gdb info stderr %d\n",indata);*/
1935       if (indata > 0) {
1936         buf[indata] = 0;
1937         //printf("printing %s\n",buf);
1938         //fflush(stdout);
1939         //fprintf(gdb_stream,"%s",buf);
1940         fflush(gdb_stream);
1941       }
1942     } else if (FD_ISSET(gdb_info_std[1], &rfds)) {
1943       int indata = read(gdb_info_std[1], buf, 100);
1944       /*printf("read data from gdb info stdout %d\n",indata);*/
1945       if (indata > 0) {
1946         buf[indata] = 0;
1947         //printf("printing %s\n",buf);
1948         //fflush(stdout);
1949         fprintf(gdb_stream,"%s",buf);
1950         fflush(gdb_stream);
1951       }
1952     }
1953   }
1954 }
1955
1956
1957
1958 static unsigned int server_port;
1959 static char server_addr[1024];/* IP address or hostname of charmrun*/
1960 static SOCKET server_fd;
1961
1962 int client_connect_problem(int code,const char *msg)
1963 {/*Called when something goes wrong during a client connect*/
1964
1965         fprintf(stderr,"Charmrun> error %d attaching to node:\n"
1966                 "%s\n",code,msg);
1967         exit(1);
1968         return -1;
1969 }
1970
1971 /** return 1 if connection is openned succesfully with client**/
1972 int errorcheck_one_client_connect(int client){
1973         unsigned int clientPort;/*These are actually ignored*/
1974         skt_ip_t clientIP;
1975         if (arg_verbose) printf("Charmrun> Waiting for %d-th client to connect.\n",client);
1976         if (0==skt_select1(server_fd,arg_timeout*1000))
1977                 client_connect_problem(client,"Timeout waiting for node-program to connect");
1978
1979                 
1980         req_clients[client]=skt_accept(server_fd,&clientIP,&clientPort);
1981
1982         
1983         if (req_clients[client]==SOCKET_ERROR) 
1984                 client_connect_problem(client,"Failure in node accept");
1985
1986         return 1;
1987 };
1988
1989
1990 #if CMK_C_INLINE
1991 inline static
1992 #endif
1993 void read_initnode_one_client(int client){
1994                 ChMessage msg;
1995                 if (!skt_select1(req_clients[client],arg_timeout*1000))
1996                    client_connect_problem(client,"Timeout on IP request");
1997                 ChMessage_recv(req_clients[client],&msg);
1998                 req_handle_initnode(&msg,req_clients[client]);
1999                 ChMessage_free(&msg);
2000 }
2001
2002
2003 #if CMK_IBVERBS_FAST_START
2004 void req_one_client_partinit(int client){
2005    ChMessage partStartMsg;
2006          int clientNode;
2007                 
2008          if(errorcheck_one_client_connect(client)){
2009            if (!skt_select1(req_clients[client],arg_timeout*1000))
2010                    client_connect_problem(client,"Timeout on partial init request");
2011                          
2012            ChMessage_recv(req_clients[client],&partStartMsg);
2013            clientNode =            ChMessageInt(*(ChMessageInt_t*)partStartMsg.data);
2014            assert(strncmp(partStartMsg.header.type,"partinit",8) == 0);
2015            ChMessage_free(&partStartMsg);
2016          } 
2017         
2018 };
2019 #endif
2020
2021 void req_set_client_connect(int start,int end) {
2022         fd_set sockset;
2023         ChMessage msg;
2024         int client,i;
2025         int done,maxdesc;
2026         int *finished;
2027         int curclient,curclientend,curclientstart;
2028         
2029         curclient=curclientend=curclientstart=start;
2030
2031         finished=malloc((end-start)*sizeof(int));
2032         for(i=0;i<(end-start);i++)
2033                 finished[i]=0;
2034
2035         done=0;
2036         while(!done) {
2037                 /* check server socket for messages */
2038                 while(curclientstart==curclientend||skt_select1(server_fd,1)!=0) {
2039                         errorcheck_one_client_connect(curclientend++);
2040                 }
2041                 /* check appropriate clients for messages */
2042                 for(client=curclientstart;client<curclientend;client++)
2043                         if(req_clients[client]>0) {
2044                                 if(skt_select1(req_clients[client],1)!=0) {
2045                                         ChMessage_recv(req_clients[client],&msg);
2046                                         req_handle_initnode(&msg,req_clients[client]);
2047                                         finished[client-start]=1;
2048                                 }
2049                         }
2050
2051
2052                 /* test if done */
2053                 done=1;
2054                 for(i=curclientstart-start;i<(end-start);i++)
2055                         if(finished[i]==0) {
2056                                 curclientstart=start+i;
2057                                 done=0;
2058                                 break;
2059                         }
2060
2061         }
2062         ChMessage_free(&msg);
2063
2064         free(finished);
2065 }
2066
2067
2068 /* allow one client to connect */
2069 void req_one_client_connect(int client)
2070 {
2071         if(errorcheck_one_client_connect(client))
2072         { /*This client has just connected-- fetch his name and IP*/
2073                 read_initnode_one_client(client);
2074         }
2075 }
2076
2077 #if CMK_USE_IBVERBS
2078 /* Each node has sent the qpn data for all the qpns it has created
2079    This data needs to be sent to all the other nodes
2080          This needs to be done for all nodes
2081 **/
2082 void exchange_qpdata_clients(){
2083         int proc,i;
2084         for( i=0;i<nodetab_rank0_size;i++){
2085                 int nt=nodetab_rank0_table[i];/*Nodetable index for this node*/ 
2086                 nodetab_table[nt]->qpData = malloc(sizeof(ChInfiAddr)*nodetab_rank0_size);
2087         }
2088         for(proc =0;proc< nodetab_rank0_size;proc++){
2089                 int count=0;
2090                 for(i=0;i<nodetab_rank0_size;i++){
2091                         if(i == proc){
2092                         }else{
2093                                 int nt=nodetab_rank0_table[i];/*Nodetable index for this node*/ 
2094                                 nodetab_table[nt]->qpData[proc] =  nodeinfo_arr[proc].qpList[count];
2095         //                      printf("Charmrun> nt %d proc %d lid 0x%x qpn 0x%x psn 0x%x\n",nt,proc,ChMessageInt(nodetab_table[nt]->qpData[proc].lid),ChMessageInt(nodetab_table[nt]->qpData[proc].qpn),ChMessageInt(nodetab_table[nt]->qpData[proc].psn));
2096                                 count++;
2097                         }
2098                 }
2099                 free(nodeinfo_arr[proc].qpList);
2100         }
2101 };
2102
2103 void    send_clients_nodeinfo_qpdata(){
2104         int node;
2105         int msgSize = sizeof(ChMessageInt_t)+sizeof(ChNodeinfo)*nodetab_rank0_size+sizeof(ChInfiAddr)*nodetab_rank0_size;
2106         for(node=0;node<nodetab_rank0_size;node++){
2107                 int nt=nodetab_rank0_table[node];/*Nodetable index for this node*/
2108 //              printf("Charmrun> Node %d proc %d sending initnodetab \n",node,nt);
2109                 ChMessageHeader hdr;
2110                 ChMessageInt_t nNodes=ChMessageInt_new(nodetab_rank0_size);
2111                 ChMessageHeader_new("initnodetab",msgSize,&hdr);
2112                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&hdr,sizeof(hdr));
2113                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&nNodes,sizeof(nNodes));
2114                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)nodeinfo_arr,sizeof(ChNodeinfo)*nodetab_rank0_size);
2115                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&nodetab_table[nt]->qpData[0],sizeof(ChInfiAddr)*nodetab_rank0_size);                         
2116         }
2117 }
2118 #endif
2119
2120
2121 /*Wait for all the clients to connect to our server port*/
2122 void req_client_connect(void)
2123 {
2124         int client;
2125         nodeinfo_allocate();
2126         req_nClients=nodetab_rank0_size;
2127         req_clients=(SOCKET *)malloc(req_nClients*sizeof(SOCKET));
2128         for(client=0;client<req_nClients;client++)
2129                 req_clients[client]=-1;
2130         
2131         skt_set_abort(client_connect_problem);
2132         
2133 #if CMK_IBVERBS_FAST_START
2134         for (client=0;client<req_nClients;client++){
2135                 req_one_client_partinit(client);
2136         }
2137         for (client=0;client<req_nClients;client++){
2138                 read_initnode_one_client(client);
2139         }
2140 #else
2141         req_set_client_connect(0,req_nClients);
2142 #endif
2143         
2144         if (portOk == 0) exit(1);
2145         if (arg_verbose) printf("Charmrun> All clients connected.\n");
2146 #if CMK_USE_IBVERBS
2147         exchange_qpdata_clients();
2148         send_clients_nodeinfo_qpdata();
2149 #else
2150         for (client=0;client<req_nClients;client++)
2151                 req_handle_initnodetab(NULL,req_clients[client]);
2152 #endif
2153         if (arg_verbose) printf("Charmrun> IP tables sent.\n");
2154 }
2155
2156 #ifndef CMK_BPROC
2157
2158 void start_one_node_rsh(int rank0no);
2159 void finish_one_node(int rank0no);
2160 void finish_set_nodes(int start, int stop);
2161
2162
2163
2164 void req_client_start_and_connect(void)
2165 {
2166         int client, c;
2167         int batch = arg_batch_spawn;        /* fire several at a time */
2168         int clientgroup,clientstart;
2169         int counter;
2170
2171         nodeinfo_allocate();
2172         req_nClients=nodetab_rank0_size;
2173         req_clients=(SOCKET *)malloc(req_nClients*sizeof(SOCKET));
2174         
2175         skt_set_abort(client_connect_problem);
2176
2177         client=0;
2178         while(client<req_nClients) { /* initiate a batch */
2179                 clientstart=client;
2180
2181                 for(counter=0;counter<batch;counter++) { /* initiate batch number of nodes */
2182                         clientgroup=start_set_node_rsh(client);
2183                         client+=clientgroup;
2184                         if(client>=req_nClients) {
2185                                 client=req_nClients;
2186                                 break;
2187                         }
2188                 }
2189                 finish_set_nodes(clientstart,client);
2190
2191 #if CMK_IBVERBS_FAST_START
2192                 for (c=clientstart;c<client;c++) { 
2193                         req_one_client_partinit(c);
2194                 }
2195 #else
2196                 req_set_client_connect(clientstart,client);
2197 #endif                                          
2198         }
2199
2200
2201 #if CMK_IBVERBS_FAST_START
2202         for (client=0;client<req_nClients;client++){
2203                 read_initnode_one_client(client);
2204         }
2205 #endif
2206         if (portOk == 0) exit(1);
2207         if (arg_verbose) printf("Charmrun> All clients connected.\n");
2208         
2209 #if CMK_USE_IBVERBS
2210         exchange_qpdata_clients();      
2211         send_clients_nodeinfo_qpdata();
2212 #else
2213         for (client=0;client<req_nClients;client++) {
2214                 req_handle_initnodetab(NULL,req_clients[client]);
2215         }
2216 #endif    
2217         if (arg_verbose) printf("Charmrun> IP tables sent.\n");
2218         free(rsh_pids); /* done with rsh_pids */
2219 }
2220
2221 #endif
2222
2223 /*Start the server socket the clients will connect to.*/
2224 void req_start_server(void)
2225 {
2226   skt_ip_t ip=skt_innode_my_ip();
2227   if (arg_local)
2228       /* local execution, use localhost always */
2229     strcpy(server_addr, "127.0.0.1");
2230   else if (arg_charmrunip != NULL)
2231       /* user specify the IP at +useip */
2232     strcpy(server_addr, arg_charmrunip);
2233   else if ( (arg_charmrunip = getenv ("CHARMRUN_IP")) != NULL)
2234       /* user specify the env  */
2235     strcpy(server_addr, arg_charmrunip);
2236   else if (skt_ip_match(ip,_skt_invalid_ip)) {
2237       printf("Charmrun> Warning-- cannot find IP address for your hostname.  Using loopback.\n");
2238       strcpy(server_addr, "127.0.0.1");
2239   }
2240   else if (arg_usehostname || skt_ip_match(ip,skt_lookup_ip("127.0.0.1")))
2241       /*Use symbolic host name as charmrun address*/
2242     gethostname(server_addr,sizeof(server_addr));
2243   else 
2244     skt_print_ip(server_addr,ip);
2245
2246   server_port = 0;
2247   server_fd=skt_server(&server_port);
2248
2249   if (arg_verbose) {
2250     printf("Charmrun> Charmrun = %s, port = %d\n", server_addr, server_port);
2251   }
2252   
2253 #if CMK_CCS_AVAILABLE
2254   if(arg_server == 1) CcsServer_new(NULL,&arg_server_port,arg_server_auth);
2255 #endif
2256 }
2257
2258 /****************************************************************************
2259  *
2260  *  The Main Program
2261  *
2262  ****************************************************************************/
2263 void start_nodes_daemon(void);
2264 void start_nodes_rsh(void);
2265 #if CMK_BPROC
2266 void nodetab_init_for_scyld(void);
2267 void start_nodes_scyld(void);
2268 #endif
2269 void start_nodes_local(char **envp);
2270 void kill_nodes(void);
2271 void open_gdb_info(void);
2272 void read_global_segments_size(void);
2273
2274 static void fast_idleFn(void) {sleep(0);}
2275 void finish_nodes(void);
2276
2277 int main(int argc, char **argv, char **envp)
2278 {
2279   srand(time(0));
2280   skt_init();
2281   skt_set_idle(fast_idleFn);
2282   /* CrnSrand((int) time(0)); */
2283   /* notify charm developers that charm is in use */
2284   ping_developers();
2285   /* Compute the values of all constants */
2286   arg_init(argc, argv);
2287   if(arg_verbose) fprintf(stderr, "Charmrun> charmrun started...\n");
2288 #if CMK_BPROC
2289   /* check scyld configuration */
2290   if (arg_nodelist)
2291     nodetab_init();
2292   else
2293     nodetab_init_for_scyld();
2294 #else
2295   /* Initialize the node-table by reading nodesfile */
2296   nodetab_init();
2297 #endif
2298
2299   /* Start the server port */
2300   req_start_server();
2301   
2302   /* Initialize the IO module */
2303   input_init();
2304   
2305   /* start the node processes */
2306   if (0!=getenv("CONV_DAEMON"))
2307     start_nodes_daemon();
2308   else
2309 #if CMK_BPROC
2310     start_nodes_scyld();
2311 #else
2312 #if CMK_USE_IBVERBS
2313                 printf("Charmrun> IBVERBS version of charmrun\n");
2314 #endif
2315     if (!arg_local) {
2316       if (!arg_batch_spawn)
2317         start_nodes_rsh();
2318       else
2319         req_client_start_and_connect();
2320     }
2321     else
2322       start_nodes_local(envp);
2323 #endif
2324
2325   if (arg_charmdebug) {
2326 #if (defined(_WIN32) && !defined(__CYGWIN__)) || CMK_BPROC
2327     /* Gdb stream (and charmdebug) currently valid only with rsh subsystem */
2328     fprintf(stderr, "Charmdebug is supported currently only with the rsh subsystem\n");
2329     abort(); 
2330 #else
2331     /* Open an additional connection to node 0 with a gdb to grab info */
2332     printf("opening connection with node 0 for info gdb\n");
2333     read_global_segments_size();
2334     open_gdb_info();
2335     gdb_stream = fdopen(dup(2), "a");
2336     dup2(1, 2);
2337 #endif
2338   }
2339
2340   if(arg_verbose) fprintf(stderr, "Charmrun> node programs all started\n");
2341
2342   /* Wait for all clients to connect */
2343 #if !CMK_RSH_KILL
2344   if (!arg_batch_spawn) finish_nodes();
2345 #endif
2346   if (!arg_batch_spawn) req_client_connect();
2347 #if CMK_RSH_KILL
2348   kill_nodes();
2349 #endif
2350   if(arg_verbose) fprintf(stderr, "Charmrun> node programs all connected\n");
2351
2352   /* enter request-service mode */
2353   while (1) req_poll();
2354 }
2355
2356 /*This little snippet creates a NETSTART 
2357 environment variable entry for the given node #.
2358 It uses the idiotic "return reference to static buffer"
2359 string return idiom.
2360 */
2361 char *create_netstart(int node)
2362 {
2363   static char dest[1024];
2364   int port=0;
2365   sprintf(dest,"%d %s %d %d %d",node,server_addr,server_port,getpid()&0x7FFF, port);
2366   return dest;
2367 }
2368
2369 /* The remainder of charmrun is only concerned with starting all
2370 the node-programs, also known as charmrun clients.  We have to
2371 start nodetab_rank0_size processes on the remote machines.
2372 */
2373
2374 /*Ask the converse daemon running on each machine to start the node-programs.*/
2375 void start_nodes_daemon(void)
2376 {
2377   taskStruct task;
2378   char argBuffer[5000];/*Buffer to hold assembled program arguments*/
2379   int i,nodeNumber;
2380
2381   /*Set the parts of the task structure that will be the same for all nodes*/
2382   /*Figure out the command line arguments (same for all PEs)*/
2383   argBuffer[0]=0;
2384   for (i=0;arg_argv[i];i++) 
2385   {
2386     if (arg_verbose)
2387       printf("Charmrun> packing arg: %s\n", arg_argv[i]);
2388     strcat(argBuffer," ");
2389     strcat(argBuffer,arg_argv[i]);
2390   }
2391   
2392   task.magic=ChMessageInt_new(DAEMON_MAGIC);
2393
2394 /*Start up the user program, by sending a message
2395   to PE 0 on each node.*/
2396   for (nodeNumber=0;nodeNumber<nodetab_rank0_size;nodeNumber++)
2397   {
2398     char nodeArgBuffer[5000];/*Buffer to hold assembled program arguments*/
2399     char *argBuf;
2400     char* arg_nodeprog_r, *arg_currdir_r;
2401     char statusCode='N';/*Default error code-- network problem*/
2402     int fd;
2403     int pe0=nodetab_rank0_table[nodeNumber];
2404     
2405     arg_currdir_r = pathfix(arg_currdir_a, nodetab_pathfixes(nodeNumber));
2406     strcpy(task.cwd,arg_currdir_r);
2407
2408     arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(nodeNumber), nodetab_ext(nodeNumber));
2409     strcpy(task.pgm,arg_nodeprog_r);
2410
2411     if (arg_verbose)
2412       printf("Charmrun> Starting node program %d on '%s' as %s.\n",nodeNumber,nodetab_name(pe0), arg_nodeprog_r);
2413
2414     sprintf(task.env,"NETSTART=%s",create_netstart(nodeNumber));
2415
2416     if (nodetab_nice(nodeNumber) != -100) {
2417       if(arg_verbose) fprintf(stderr, "Charmrun> +nice %d\n", nodetab_nice(nodeNumber));
2418       sprintf(nodeArgBuffer, "%s +nice %d", argBuffer, nodetab_nice(nodeNumber));
2419       argBuf = nodeArgBuffer;
2420     }
2421     else 
2422       argBuf = argBuffer;
2423     task.argLength=ChMessageInt_new(strlen(argBuf));
2424
2425     /*Send request out to remote node*/
2426     fd = skt_connect(nodetab_ip(pe0),
2427                      DAEMON_IP_PORT,30);
2428     if (fd!=INVALID_SOCKET)
2429     {/*Contact!  Ask the daemon to start the program*/
2430       skt_sendN(fd, (const char *)&task, sizeof(task));
2431       skt_sendN(fd, (const char *)argBuf, strlen(argBuf));
2432       skt_recvN(fd, &statusCode,sizeof(char));
2433     }
2434     if (statusCode!='G')
2435     {/*Something went wrong--*/
2436       fprintf(stderr,"Error '%c' starting remote node program on %s--\n%s\n",
2437                   statusCode,nodetab_name(pe0),daemon_status2msg(statusCode));
2438           exit(1);
2439     } else if (arg_verbose)
2440           printf("Charmrun> Node program %d started.\n",nodeNumber);
2441   }
2442 }
2443
2444 #if defined(_WIN32) && !defined(__CYGWIN__)
2445 /*Sadly, interprocess communication on Win32 is quite
2446   different, so we can't use Rsh on win32 yet.  
2447   Fall back to the daemon.*/
2448 void start_nodes_rsh() {start_nodes_daemon();}
2449 void finish_nodes(void) {}
2450 void start_one_node_rsh(int rank0no) {}
2451 void finish_one_node(int rank0no) {}
2452
2453 int start_set_node_rsh(int client) {}
2454 void finish_set_nodes(int start, int stop) {}
2455
2456 void envCat(char *dest,LPTSTR oldEnv)
2457 {
2458   char *src=oldEnv;
2459   dest+=strlen(dest);//Advance to end of dest
2460   dest++;//Advance past terminating NULL character
2461   while ((*src)!='\0') {
2462     int adv=strlen(src)+1;//Length of newly-copied string plus NULL
2463     strcpy(dest,src);//Copy another environment string
2464     dest+=adv;//Advance past newly-copied string and NULL
2465     src+=adv;//Ditto for src
2466   }
2467   *dest='\0';//Paste on final terminating NULL character
2468   FreeEnvironmentStrings(oldEnv);
2469 }
2470
2471
2472 /* simple version of charmrun that avoids the rshd or charmd,   */
2473 /* it spawn the node program just on local machine using exec. */
2474 void start_nodes_local(char ** env)
2475 {
2476   int ret, i;
2477   PROCESS_INFORMATION pi;     /* process Information for the process spawned */
2478   char **p;
2479
2480   char environment[10000];/*Doubly-null terminated environment strings*/
2481   char cmdLine[10000];/*Program command line, including executable name*/
2482 /*Command line too long.*/
2483 /*
2484   if (strlen(pparam_argv[1])+strlen(args) > 10000) 
2485         return 0; 
2486 */
2487   strcpy(cmdLine,pparam_argv[1]);
2488   p = pparam_argv+2;
2489   while ((*p)!='\0') {
2490     strcat(cmdLine," ");
2491     strcat(cmdLine,*p);
2492     p++;
2493   }
2494
2495   for (i=0; i<arg_requested_pes; i++)
2496   {
2497     STARTUPINFO si={0};         /* startup info for the process spawned */
2498
2499     sprintf(environment, "NETSTART=%s",  create_netstart(i));
2500     /*Paste all system environment strings */
2501     envCat(environment,GetEnvironmentStrings());
2502   
2503     /* Initialise the security attributes for the process 
2504      to be spawned */
2505     si.cb = sizeof(si);   
2506     if (arg_verbose)
2507       printf("Charmrun> start %d node program on localhost.\n", i);
2508
2509     ret = CreateProcess(NULL,   /* application name */
2510                     cmdLine,    /* command line */
2511                     NULL,/*&sa,*/               /* process SA */
2512                     NULL,/*&sa,*/               /* thread SA */
2513                     FALSE,      /* inherit flag */
2514 #if 1
2515                     CREATE_NEW_PROCESS_GROUP|DETACHED_PROCESS, 
2516 #else
2517                     CREATE_NEW_PROCESS_GROUP|CREATE_NEW_CONSOLE,
2518 #endif
2519                         /* creation flags */
2520                     environment,                /* environment block */
2521                     ".",                        /* working directory */
2522                     &si,                        /* startup info */
2523                     &pi);
2524  
2525     if (ret==0)
2526     {
2527       /*Something went wrong!  Look up the Windows error code*/
2528 /*
2529       int error=GetLastError();
2530       char statusCode=daemon_err2status(error);
2531       fprintf(logfile,"******************* ERROR *****************\n"
2532               "Error in creating process!\n"
2533               "Error code = %ld-- %s\n\n\n", error,
2534               daemon_status2msg(statusCode));
2535           fflush(logfile);
2536 */
2537       int error=GetLastError();
2538       printf("startProcess failed to start process \"%s\" with status: %d\n", pparam_argv[1], error);
2539       exit(1) ;
2540     } 
2541   }
2542 }
2543
2544 #elif CMK_BPROC
2545
2546 int bproc_nodeisup(int node)
2547 {
2548     int status = 0;
2549 #if CMK_BPROC_VERSION < 4
2550     if (bproc_nodestatus(node) == bproc_node_up) status = 1;
2551     if (arg_verbose)
2552       printf("Charmrun> node %d status: %s\n", node, status?"up":"down");
2553 #else
2554     char nodestatus[128];
2555     if (node == -1) {           /* master node is always up */
2556       strcpy(nodestatus, "up");
2557       status = 1;
2558     }
2559     if (bproc_nodestatus(node, nodestatus, 128)) {
2560       if (strcmp(nodestatus, "up")==0) status = 1;
2561     }
2562     if (arg_verbose)
2563         printf("Charmrun> node %d status: %s\n", node, nodestatus);
2564 #endif
2565   return status;
2566 }
2567
2568 /**
2569   ++ppn now is supported in both SMP and non SMP version
2570   in SMP, ++ppn specifies number of threads on each node;
2571   in non-SMP, ++ppn specifies number of processes on each node.
2572 */
2573 void nodetab_init_for_scyld()
2574 {
2575   int maxNodes, i, node, npes, rank;
2576   nodetab_host group;
2577   int tablesize;
2578
2579   tablesize = arg_requested_pes;
2580   maxNodes = bproc_numnodes() + 1;
2581   if (arg_endpe < maxNodes) maxNodes=arg_endpe+1;
2582   if (maxNodes > tablesize) tablesize = maxNodes;
2583   nodetab_table=(nodetab_host**)malloc(tablesize*sizeof(nodetab_host*));
2584   nodetab_rank0_table=(int*)malloc(tablesize*sizeof(int));
2585   nodetab_max=tablesize;
2586
2587   nodetab_reset(&group);
2588
2589   if (arg_ppn==0) arg_ppn=1;
2590 /*
2591 #if CMK_SHARED_VARS_UNAVAILABLE
2592   if (arg_ppn > 1) {
2593     fprintf(stderr,"Warning> Invalid ppn %d in nodelist ignored.\n", arg_ppn);
2594     arg_ppn=1;
2595   }
2596 #endif
2597 */
2598   group.cpus = 1;
2599   group.rank = 0;
2600
2601   /* check which slave node is available from frompe to endpe */
2602   npes = 0;
2603   for (i=-1; i<maxNodes && npes < arg_requested_pes; i++) {
2604     char hostname[256];
2605     if (!bproc_nodeisup(i)) continue;
2606     if (i!= -1 && i<arg_startpe) continue;
2607     if (i==-1 && arg_skipmaster) continue;    /* skip master node -1 */
2608     sprintf(hostname, "%d", i);
2609 #if ! CMK_SHARED_VARS_UNAVAILABLE
2610     if (npes + arg_ppn > arg_requested_pes) group.cpus = arg_requested_pes-npes;
2611     else group.cpus = arg_ppn;
2612 #endif
2613     for (rank = 0; rank<arg_ppn; rank++) {
2614 #if ! CMK_SHARED_VARS_UNAVAILABLE
2615       group.rank = rank;
2616 #endif
2617       nodetab_makehost(hostname, &group);
2618       if (++npes == arg_requested_pes) break;
2619     }   
2620   }
2621   if (nodetab_rank0_size == 0) {
2622     fprintf(stderr, "Charmrun> no slave node available!\n");
2623     exit (1);
2624   }
2625   if (arg_verbose)
2626     printf("Charmrun> There are %d slave nodes available.\n", nodetab_rank0_size-(arg_skipmaster?0:1));
2627
2628   /* expand node table to arg_requested_pes */
2629   if (arg_requested_pes > npes) {
2630     int orig_size = npes;
2631     int node;
2632     int startnode = 0;
2633     if (arg_singlemaster && nodetab_rank0_size > 1 && !arg_skipmaster) 
2634         startnode = arg_ppn;      /* skip -1 */
2635     node = startnode; 
2636     while (npes < arg_requested_pes) {
2637 #if ! CMK_SHARED_VARS_UNAVAILABLE
2638       if (npes+arg_ppn > arg_requested_pes) group.cpus = arg_requested_pes-npes;
2639       else group.cpus = arg_ppn;
2640 #endif
2641       for (rank = 0; rank<arg_ppn; rank++) {
2642 #if ! CMK_SHARED_VARS_UNAVAILABLE
2643         group.rank = rank;
2644 #endif
2645         nodetab_makehost(nodetab_name(node), &group);
2646         if (++node == orig_size) node = startnode;
2647         if (++npes == arg_requested_pes) break;
2648       } 
2649     }
2650   }
2651 }
2652
2653 void start_nodes_scyld(void)
2654 {
2655   char *envp[2];
2656   int i;
2657
2658   envp[0] = (char *)malloc(256);
2659   envp[1] = 0;
2660   for (i=0;i<nodetab_rank0_size;i++)
2661   {
2662     int status = 0;
2663     int pid;
2664     int pe=nodetab_rank0_table[i];
2665     int nodeno = atoi(nodetab_name(pe));
2666
2667     if (arg_verbose)
2668       printf("Charmrun> start node program on slave node: %d.\n", nodeno);
2669     sprintf(envp[0], "NETSTART=%s",  create_netstart(i));
2670     pid = 0;
2671     pid = fork();
2672     if (pid < 0) exit(1);
2673     if (pid == 0)
2674     {
2675       int fd, fd1 = dup(1);
2676       if (!(arg_debug || arg_debug_no_pause)) {   /* debug mode */
2677         if (fd = open("/dev/null", O_RDWR)) {
2678           dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
2679         }
2680       }
2681       if (nodeno == -1) {
2682         status = execve(pparam_argv[1], pparam_argv+1, envp);
2683         dup2(fd1, 1);
2684         printf("execve failed to start process \"%s\" with status: %d\n", pparam_argv[1], status);
2685       }
2686       else {
2687         status = bproc_execmove(nodeno, pparam_argv[1], pparam_argv+1, envp);
2688         dup2(fd1, 1);
2689         printf("bproc_execmove failed to start remote process \"%s\" with status: %d\n", pparam_argv[1], status);
2690       }
2691       kill(getppid(), 9);
2692       exit(1);
2693     }
2694   }
2695   free(envp[0]);
2696 }
2697 void finish_nodes(void) {}
2698
2699 #else
2700 /*Unix systems can use Rsh normally*/
2701 /********** RSH-ONLY CODE *****************************************/
2702 /*                                                                          */
2703 /* Rsh_etc                                                                  */
2704 /*                                                                          */
2705 /* this starts all the node programs.  It executes fully in the background. */
2706 /*                                                                          */
2707 /****************************************************************************/
2708 #include <sys/wait.h>
2709
2710 extern char **environ;
2711 void removeEnv(const char *doomedEnv)
2712 { /*Remove a value from the environment list*/
2713       char **oe, **ie;
2714       oe=ie=environ;
2715       while (*ie != NULL) {
2716         if (0!=strncmp(*ie,doomedEnv,strlen(doomedEnv)))
2717           *oe++ = *ie;
2718         ie++;
2719       }
2720       *oe=NULL;/*NULL-terminate list*/
2721 }
2722
2723 int rsh_fork(int nodeno,const char *startScript)
2724 {
2725   char **rshargv;
2726   int pid;
2727   int num=0;
2728   char *s, *e;
2729
2730   /* figure out size and dynamic allocate */
2731   s=nodetab_shell(nodeno); e=skipstuff(s);
2732   while (*s) {
2733     num++;
2734     s = skipblanks(e); e = skipstuff(s);
2735   }
2736   rshargv = (char **)malloc(sizeof(char *)*(num+6));
2737
2738   num = 0;
2739   s=nodetab_shell(nodeno); e=skipstuff(s);
2740   while (*s) {
2741     rshargv[num++]=substr(s, e);
2742     s = skipblanks(e); e = skipstuff(s);
2743   }
2744
2745   rshargv[num++]=nodetab_name(nodeno);
2746   rshargv[num++]="-l";
2747   rshargv[num++]=nodetab_login(nodeno);
2748   rshargv[num++]="/bin/sh -f";
2749   rshargv[num++]=0;
2750   if (arg_verbose) printf("Charmrun> Starting %s %s -l %s %s\n",nodetab_shell(nodeno), nodetab_name(nodeno),nodetab_login(nodeno), rshargv[num-2]);
2751   
2752   pid = fork();
2753   if (pid < 0) 
2754         { perror("ERROR> starting rsh"); exit(1); }
2755   if (pid == 0)
2756   {/*Child process*/
2757       int i;
2758       int fdScript=open(startScript,O_RDONLY);
2759   /**/  unlink(startScript); /**/
2760       dup2(fdScript,0);/*Open script as standard input*/
2761       //removeEnv("DISPLAY="); /*No DISPLAY disables ssh's slow X11 forwarding*/
2762       for(i=3; i<1024; i++) close(i);
2763       execvp(rshargv[0], rshargv);
2764       fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
2765       exit(1);
2766   }
2767   free(rshargv);
2768   if (arg_verbose)
2769     fprintf(stderr,"Charmrun> remote shell (%s:%d) started\n",
2770         nodetab_name(nodeno),nodeno);
2771   return pid;
2772 }
2773
2774 void fprint_arg(FILE *f,char **argv)
2775 {
2776   while (*argv) { 
2777         fprintf(f," %s",*argv); 
2778         argv++; 
2779   }
2780 }
2781 void rsh_Find(FILE *f,const char *program,const char *dest)
2782 {
2783     fprintf(f,"Find %s\n",program);
2784     fprintf(f,"%s=$loc\n",dest);
2785 }
2786 void rsh_script(FILE *f, int nodeno, int rank0no, char **argv)
2787 {
2788   char *netstart;
2789   char *arg_nodeprog_r,*arg_currdir_r;
2790   char *dbg=nodetab_debugger(nodeno);
2791   char *host=nodetab_name(nodeno);
2792 #define CLOSE_ALL " < /dev/null 1> /dev/null 2> /dev/null &"
2793
2794   fprintf(f, /*Echo: prints out status message*/
2795         "Echo() {\n"
2796         "  echo 'Charmrun remote shell(%s.%d)>' $*\n"
2797         "}\n",host,nodeno);
2798   fprintf(f, /*Exit: exits with return code*/
2799         "Exit() {\n"
2800         "  if [ $1 -ne 0 ]\n"
2801         "  then\n"
2802         "    Echo Exiting with error code $1\n"
2803         "  fi\n"
2804 #if CMK_RSH_KILL /*End by killing ourselves*/
2805         "  sleep 5\n" /*Delay until any error messages are flushed*/
2806         "  kill -9 $$\n"
2807 #else /*Exit normally*/
2808         "  exit $1\n"
2809 #endif
2810         "}\n");
2811   fprintf(f, /*Find: locates a binary program in PATH, sets loc*/
2812         "Find() {\n"
2813         "  loc=''\n"
2814         "  for dir in `echo $PATH | sed -e 's/:/ /g'`\n"
2815         "  do\n"
2816         "    test -f \"$dir/$1\" && loc=\"$dir/$1\"\n"
2817         "  done\n"
2818         "  if [ \"x$loc\" = x ]\n"
2819         "  then\n"
2820         "    Echo $1 not found in your PATH \"($PATH)\"--\n"
2821         "    Echo set your path in your ~/.charmrunrc\n"
2822         "    Exit 1\n"
2823         "  fi\n"
2824         "}\n");
2825   
2826   if (arg_verbose) fprintf(f,"Echo 'remote responding...'\n");
2827   
2828   fprintf(f,"test -f \"$HOME/.charmrunrc\" && . \"$HOME/.charmrunrc\"\n");
2829 /* let's leave DISPLAY untouched and rely on X11 forwarding,
2830    changing DISPLAY to charmrun does not always work if X11 forwarding presents 
2831 */
2832   if (arg_display && !arg_ssh_display)
2833     fprintf(f,"DISPLAY='%s';export DISPLAY\n",arg_display);
2834   netstart = create_netstart(rank0no);
2835   fprintf(f,"NETSTART='%s';export NETSTART\n",netstart);
2836   fprintf(f,"CmiMyNode='%d'; export CmiMyNode\n",rank0no);
2837   fprintf(f,"CmiMyNodeSize='%d'; export CmiMyNodeSize\n",nodetab_getnodeinfo(rank0no)->cpus);
2838   fprintf(f,"CmiMyForks='%d'; export CmiMyForks\n",nodetab_getnodeinfo(rank0no)->forks);
2839   fprintf(f,"CmiNumNodes='%d'; export CmiNumNodes\n",nodetab_rank0_size);
2840 #if CONVERSE_VERSION_VMI
2841   /* VMI environment variable */
2842   fprintf (f, "VMI_PROCS='%d'; export VMI_PROCS\n", arg_requested_pes);
2843   fprintf (f, "VMI_KEY='charmrun%d'; export VMI_KEY\n", getpid ());
2844   fprintf (f, "VMI_SPECFILE='%s'; export VMI_SPECFILE\n", arg_vmispecfile);
2845 #endif
2846 #ifdef CMK_G95
2847   fprintf(f,"G95_UNBUFFERED_ALL=TRUE; export G95_UNBUFFERED_ALL\n");
2848 #endif
2849 #ifdef CMK_GFORTRAN
2850   fprintf(f,"GFORTRAN_UNBUFFERED_ALL=YES; export GFORTRAN_UNBUFFERED_ALL\n");
2851 #endif
2852 #if CMK_USE_MX
2853   fprintf(f,"MX_MONOTHREAD=1; export MX_MONOTHREAD\n");
2854   /*fprintf(f,"MX_RCACHE=1; export MX_RCACHE\n");*/
2855 #endif
2856 #if CMK_AIX && CMK_SMP
2857   fprintf(f,"MALLOCMULTIHEAP=1; export MALLOCMULTIHEAP\n");
2858 #endif
2859   
2860   if (arg_verbose) {
2861     printf("Charmrun> Sending \"%s\" to client %d.\n", netstart, rank0no);
2862   }
2863   fprintf(f,"PATH=\"$PATH:/bin:/usr/bin:/usr/X/bin:/usr/X11/bin:/usr/local/bin:"
2864         "/usr/X11R6/bin:/usr/openwin/bin\"\n");
2865   
2866   /* find the node-program */
2867   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(nodeno), nodetab_ext(nodeno));
2868   
2869   /* find the current directory, relative version */
2870   arg_currdir_r = pathfix(arg_currdir_a, nodetab_pathfixes(nodeno));
2871
2872   if (arg_verbose) {
2873     printf("Charmrun> find the node program \"%s\" at \"%s\" for %d.\n", arg_nodeprog_r, arg_currdir_r, nodeno);
2874   }
2875
2876   if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
2877     rsh_Find(f,nodetab_xterm(nodeno),"F_XTERM");
2878     if(!arg_ssh_display)
2879       rsh_Find(f,"xrdb","F_XRDB");
2880     if(arg_verbose) fprintf(f,"Echo 'using xterm' $F_XTERM\n");
2881   }
2882
2883   if (arg_debug || arg_debug_no_pause)
2884   {/*Look through PATH for debugger*/
2885     rsh_Find(f,dbg,"F_DBG");
2886     if (arg_verbose) fprintf(f,"Echo 'using debugger' $F_DBG\n");
2887   }
2888
2889    if (!arg_ssh_display && (arg_debug || arg_debug_no_pause ||
2890       arg_in_xterm)) {
2891      /*    if (arg_debug || arg_debug_no_pause || arg_in_xterm) {*/
2892     fprintf(f,"$F_XRDB -query > /dev/null\n");
2893     fprintf(f,"if test $? != 0\nthen\n");
2894     fprintf(f,"  Echo 'Cannot contact X Server '$DISPLAY'.  You probably'\n");
2895     fprintf(f,"  Echo 'need to run xhost to authorize connections.'\n");
2896     fprintf(f,"  Echo '(See manual for xhost for security issues)'\n");
2897     fprintf(f,"  Echo 'Or try ++batch 1 ++ssh-display to rely on SSH X11 forwarding'\n");
2898     fprintf(f,"  Exit 1\n");
2899     fprintf(f,"fi\n");
2900   }
2901   
2902   fprintf(f,"if test ! -x \"%s\"\nthen\n",arg_nodeprog_r);
2903   fprintf(f,"  Echo 'Cannot locate this node-program: %s'\n",arg_nodeprog_r);
2904   fprintf(f,"  Exit 1\n");
2905   fprintf(f,"fi\n");
2906   
2907   fprintf(f,"cd \"%s\"\n",arg_currdir_r);
2908   fprintf(f,"if test $? = 1\nthen\n");
2909   fprintf(f,"  Echo 'Cannot propagate this current directory:'\n"); 
2910   fprintf(f,"  Echo '%s'\n",arg_currdir_r);
2911   fprintf(f,"  Exit 1\n");
2912   fprintf(f,"fi\n");
2913   
2914   if (strcmp(nodetab_setup(nodeno),"*")) {
2915     fprintf(f,"%s\n",nodetab_setup(nodeno));
2916     fprintf(f,"if test $? = 1\nthen\n");
2917     fprintf(f,"  Echo 'this initialization command failed:'\n");
2918     fprintf(f,"  Echo '\"%s\"'\n",nodetab_setup(nodeno));
2919     fprintf(f,"  Echo 'edit your nodes file to fix it.'\n");
2920     fprintf(f,"  Exit 1\n");
2921     fprintf(f,"fi\n");
2922   }
2923
2924   fprintf(f,"rm -f /tmp/charmrun_err.$$\n");
2925   if(arg_verbose) fprintf(f,"Echo 'starting node-program...'\n");  
2926   /* This is the start of the the run-nodeprogram script */
2927   fprintf(f,"(");
2928   
2929   if (arg_debug || arg_debug_no_pause ) {
2930          if ( strcmp(dbg, "gdb") == 0 || strcmp(dbg, "idb") == 0 ) {
2931            fprintf(f,"cat > /tmp/charmrun_gdb.$$ << END_OF_SCRIPT\n");
2932            if ( strcmp(dbg, "idb") == 0 ) {
2933              fprintf(f,"set \\$cmdset=\"gdb\"\n");
2934            }
2935            fprintf(f,"shell /bin/rm -f /tmp/charmrun_gdb.$$\n");
2936            fprintf(f,"handle SIGPIPE nostop noprint\n");
2937            fprintf(f,"handle SIGWINCH nostop noprint\n");
2938            fprintf(f,"handle SIGWAITING nostop noprint\n");
2939            fprintf(f,"set args");
2940            fprint_arg(f,argv);
2941            fprintf(f,"\n");
2942            if (arg_debug_no_pause) fprintf(f,"run\n");
2943            fprintf(f,"END_OF_SCRIPT\n");
2944            if (arg_runscript)
2945              fprintf(f,"\"%s\" ",arg_runscript);
2946            fprintf(f,"$F_XTERM");
2947            fprintf(f," -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
2948            if ( strcmp(dbg, "idb") == 0 )
2949              fprintf(f," -e $F_DBG %s -c /tmp/charmrun_gdb.$$ \n", arg_nodeprog_r);
2950            else 
2951              fprintf(f," -e $F_DBG %s -x /tmp/charmrun_gdb.$$ \n", arg_nodeprog_r);
2952          } else if ( strcmp(dbg, "dbx") == 0 ) {
2953            fprintf(f,"cat > /tmp/charmrun_dbx.$$ << END_OF_SCRIPT\n");
2954            fprintf(f,"sh /bin/rm -f /tmp/charmrun_dbx.$$\n");
2955            fprintf(f,"dbxenv suppress_startup_message 5.0\n");
2956            fprintf(f,"ignore SIGPOLL\n");
2957            fprintf(f,"ignore SIGPIPE\n");
2958            fprintf(f,"ignore SIGWINCH\n");
2959            fprintf(f,"ignore SIGWAITING\n");
2960            fprintf(f,"END_OF_SCRIPT\n");
2961            if (arg_runscript)
2962              fprintf(f,"\"%s\" ",arg_runscript);
2963            fprintf(f,"$F_XTERM");
2964            fprintf(f," -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
2965            fprintf(f," -e $F_DBG %s ",arg_debug_no_pause?"-r":"");
2966            if(arg_debug) {
2967               fprintf(f,"-c \'runargs ");
2968               fprint_arg(f,argv);
2969               fprintf(f,"\' ");
2970            }
2971            fprintf(f, "-s/tmp/charmrun_dbx.$$ %s",arg_nodeprog_r);
2972            if(arg_debug_no_pause) 
2973               fprint_arg(f,argv);
2974            fprintf(f,"\n");
2975          } else { 
2976           fprintf(stderr, "Unknown debugger: %s.\n Exiting.\n", 
2977             nodetab_debugger(nodeno));
2978          }
2979   } else if (arg_in_xterm) {
2980     if(arg_verbose)
2981       fprintf(stderr, "Charmrun> node %d: xterm is %s\n", 
2982               nodeno, nodetab_xterm(nodeno));
2983     fprintf(f,"cat > /tmp/charmrun_inx.$$ << END_OF_SCRIPT\n");
2984     fprintf(f,"#!/bin/sh\n");
2985     fprintf(f,"/bin/rm -f /tmp/charmrun_inx.$$\n");
2986     fprintf(f,"%s", arg_nodeprog_r);
2987     fprint_arg(f,argv);
2988     fprintf(f,"\n");
2989     fprintf(f,"echo 'program exited with code '\\$?\n");
2990     fprintf(f,"read eoln\n");
2991     fprintf(f,"END_OF_SCRIPT\n");
2992     fprintf(f,"chmod 700 /tmp/charmrun_inx.$$\n");
2993     if (arg_runscript)
2994        fprintf(f,"\"%s\" ",arg_runscript);
2995     fprintf(f,"$F_XTERM -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
2996     fprintf(f," -sl 5000");
2997     fprintf(f," -e /tmp/charmrun_inx.$$\n");
2998   } else {
2999     if (arg_runscript)
3000        fprintf(f,"\"%s\" ",arg_runscript);
3001     fprintf(f,"\"%s\" ",arg_nodeprog_r);
3002     fprint_arg(f,argv);
3003     if (nodetab_nice(nodeno) != -100) {
3004       if(arg_verbose) fprintf(stderr, "Charmrun> nice -n %d\n", nodetab_nice(nodeno));
3005       fprintf(f," +nice %d ",nodetab_nice(nodeno));
3006     }
3007     fprintf(f,"\nres=$?\n");
3008     /* If shared libraries fail to load, the program dies without
3009        calling charmrun back.  Since we *have* to close down stdin/out/err,
3010        we have to smuggle this failure information out via a file,
3011        /tmp/charmrun_err.<pid> */
3012     fprintf(f,
3013         "if [ $res -eq 127 ]\n"
3014         "then\n"
3015         "  ( \n" /* Re-run, spitting out errors from a subshell: */
3016         "    \"%s\" \n"
3017         "    ldd \"%s\"\n"
3018         "  ) > /tmp/charmrun_err.$$ 2>&1 \n"
3019         "fi\n",arg_nodeprog_r,arg_nodeprog_r);
3020   }
3021   
3022   /* End the node-program subshell. To minimize the number 
3023      of open ports on the front-end, we must close down rsh;
3024      to do this, we have to close stdin, stdout, stderr, and 
3025      run the subshell in the background. */
3026   fprintf(f,")");
3027   fprintf(f,CLOSE_ALL "\n");
3028   
3029   if (arg_verbose) fprintf(f,"Echo 'rsh phase successful.'\n");
3030   fprintf(f, /* Check for startup errors: */
3031      "sleep 1\n"
3032      "if [ -r /tmp/charmrun_err.$$ ]\n"
3033      "then\n"
3034      "  cat /tmp/charmrun_err.$$ \n"
3035      "  rm -f /tmp/charmrun_err.$$ \n"
3036      "  Exit 1\n"
3037      "fi\n");
3038   fprintf(f,"Exit 0\n");
3039 }
3040
3041
3042 /* use the command "size" to get information about the position of the ".data"
3043    and ".bss" segments inside the program memory */
3044 void read_global_segments_size() {
3045   char **rshargv;
3046   int childPid;
3047
3048   /* find the node-program */
3049   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(0), nodetab_ext(0));
3050
3051   rshargv = (char **)malloc(sizeof(char *)*6);
3052   rshargv[0]=nodetab_shell(0);
3053   rshargv[1]=nodetab_name(0);
3054   rshargv[2]="-l";
3055   rshargv[3]=nodetab_login(0);
3056   rshargv[4] = (char *)malloc(sizeof(char)*9+strlen(arg_nodeprog_r));
3057   sprintf(rshargv[4],"size -A %s",arg_nodeprog_r);
3058   rshargv[5]=0;
3059
3060   childPid = fork();
3061   if (childPid < 0) {
3062     perror("ERROR> getting the size of the global variables segments"); exit(1);
3063   } else if (childPid == 0) {
3064     /* child process */
3065     dup2(2, 1);
3066     /*printf("executing: \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",rshargv[0],rshargv[1],rshargv[2],rshargv[3],rshargv[4]);*/
3067     execvp(rshargv[0], rshargv);
3068     fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
3069     exit(1);
3070   } else {
3071     /* else we are in the parent */
3072     free(rshargv[4]);
3073     free(rshargv);
3074     waitpid(childPid, NULL, 0);
3075   }
3076 }
3077
3078 /* open a rsh connection with processor 0 and open a gdb session for info */
3079 void open_gdb_info() {
3080   char **rshargv;
3081   int fdin[2];
3082   int fdout[2];
3083   int fderr[2];
3084   int i;
3085
3086   /* find the node-program */
3087   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(0), nodetab_ext(0));
3088
3089   rshargv = (char **)malloc(sizeof(char *)*6);
3090   rshargv[0]=nodetab_shell(0);
3091   rshargv[1]=nodetab_name(0);
3092   rshargv[2]="-l";
3093   rshargv[3]=nodetab_login(0);
3094   rshargv[4] = (char *)malloc(sizeof(char)*8+strlen(arg_nodeprog_r));
3095   sprintf(rshargv[4],"gdb -q %s",arg_nodeprog_r);
3096   rshargv[5]=0;
3097
3098   pipe(fdin);
3099   pipe(fdout);
3100   pipe(fderr);
3101
3102   gdb_info_pid = fork();
3103   if (gdb_info_pid < 0) {
3104     perror("ERROR> starting info gdb"); exit(1);
3105   } else if (gdb_info_pid == 0) {
3106     /* child process */
3107     close(fdin[1]);
3108     close(fdout[0]);
3109     close(fderr[0]);
3110     printf("executing: \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",rshargv[0],rshargv[1],rshargv[2],rshargv[3],rshargv[4]);
3111     dup2(fdin[0],0);
3112     dup2(fdout[1],1);
3113     dup2(fderr[1],2);
3114     for(i=3; i<1024; i++) close(i);
3115     execvp(rshargv[0], rshargv);
3116     fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
3117     exit(1);
3118   }
3119   /* else we are in the parent */
3120   free(rshargv[4]);
3121   free(rshargv);
3122   gdb_info_std[0] = fdin[1];
3123   gdb_info_std[1] = fdout[0];
3124   gdb_info_std[2] = fderr[0];
3125   close(fdin[0]);
3126   close(fdout[1]);
3127   close(fderr[1]);
3128 }
3129
3130 /* returns pid */
3131 void start_one_node_rsh(int rank0no)
3132 {
3133      int pe=nodetab_rank0_table[rank0no];
3134      FILE *f;
3135      char startScript[200];
3136      sprintf(startScript,"/tmp/charmrun.%d.%d",getpid(),pe);
3137      f=fopen(startScript,"w");
3138      if (f==NULL) {
3139        /* now try current directory */
3140        sprintf(startScript,"charmrun.%d.%d",getpid(),pe);
3141        f=fopen(startScript,"w");
3142        if (f==NULL) {
3143          fprintf(stderr,"Charmrun> Can not write file %s!\n", startScript);
3144          exit(1);
3145        }
3146      }
3147      rsh_script(f,pe,rank0no,arg_argv);
3148      fclose(f);
3149      if (!rsh_pids)
3150        rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3151      rsh_pids[rank0no] = rsh_fork(pe,startScript);
3152 }
3153
3154 int start_set_node_rsh(int client) {
3155         /* a search function could be inserted here instead of sequential lookup for more complex node lists (e.g. interleaving) */
3156         int clientgroup;
3157 #if CMK_SMP || defined(_WIN32)
3158         clientgroup=client+1; /* smp already handles this functionality */
3159 #else
3160         if(!arg_scalable_start)
3161                 clientgroup=client+1; /* only launch 1 core per rsh call */
3162         else {
3163                 clientgroup=client;
3164                 do {
3165                         clientgroup++; /* add one more client to group if not greater than nodes and shares the same name as client */
3166                 } while(clientgroup<nodetab_rank0_size&&(!strcmp(nodetab_name(clientgroup),nodetab_name(client))));
3167         }
3168 #endif
3169
3170         nodetab_getnodeinfo(client)->forks=clientgroup-client-1; /* already have 1 process launching */
3171
3172         start_one_node_rsh(client);
3173         return clientgroup-client; /* return number of entries in group */
3174 }
3175
3176 void start_nodes_rsh()
3177 {
3178         int client,clientgroup;
3179         rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3180
3181         client=0;
3182         while(client<nodetab_rank0_size) {
3183                 /* start a group of processes per node */
3184                 clientgroup=start_set_node_rsh(client);
3185                 client+=clientgroup;
3186         }
3187 }
3188
3189 void finish_set_nodes(int start, int stop) {
3190         int status,done,i;
3191         char *host;
3192
3193         if (!rsh_pids) return; /*nothing to do*/
3194
3195         done=0;
3196         while(!done) {
3197                 done=1;
3198                 for(i=start;i<stop;i++) { /* check all nodes */
3199                         if(rsh_pids[i]!=0) {
3200                                 done=0; /* we are not finished yet */
3201                                 status=0;
3202                                 waitpid(rsh_pids[i],&status,0); /* check if the process is finished */
3203                                 if(WIFEXITED(status)) {
3204                                         if (!WEXITSTATUS(status)) { /* good */
3205                                                 rsh_pids[i]=0; /* process is finished */
3206                                         } else {
3207                                                 host=nodetab_name(nodetab_rank0_table[i]);
3208                                                 fprintf(stderr,"Charmrun> Error %d returned from rsh (%s:%d)\n",
3209                                                 WEXITSTATUS(status),host,i);
3210                                                 exit(1);
3211                                         } 
3212                                 }
3213                         }
3214                 }
3215         }
3216 }
3217
3218 void finish_nodes()
3219 {
3220         finish_set_nodes(0,nodetab_rank0_size);
3221         free(rsh_pids);
3222 }
3223
3224 void kill_nodes()
3225 {
3226   int rank0no;
3227   if (!rsh_pids) return; /*nothing to do*/
3228   /*Now wait for all the rsh'es to finish*/
3229   for (rank0no=0;rank0no<nodetab_rank0_size;rank0no++)
3230   {
3231      const char *host=nodetab_name(nodetab_rank0_table[rank0no]);
3232      int status=0;
3233      if (arg_verbose) printf("Charmrun> waiting for rsh (%s:%d), pid %d\n",
3234                 host,rank0no,rsh_pids[rank0no]);
3235      kill(rsh_pids[rank0no],9);
3236      waitpid(rsh_pids[rank0no],&status,0); /*<- no zombies*/
3237   }
3238   free(rsh_pids);
3239 }
3240
3241 /* simple version of charmrun that avoids the rshd or charmd,   */
3242 /* it spawn the node program just on local machine using exec. */
3243 void start_nodes_local(char ** env)
3244 {
3245   char **envp;
3246   int envc, rank0no, i;
3247   int extra = 0;
3248
3249 #if CMK_AIX && CMK_SMP
3250   extra = 1;
3251 #endif
3252
3253   /* copy environ and expanded to hold NETSTART */ 
3254   for (envc=0; env[envc]; envc++);
3255   envp = (char **)malloc((envc+2+extra)*sizeof(void *));
3256   for (i=0; i<envc; i++) envp[i] = env[i];
3257   envp[envc] = (char *)malloc(256);
3258 #if CMK_AIX && CMK_SMP
3259   envp[envc+1] = (char *)malloc(256);
3260   sprintf(envp[envc+1], "MALLOCMULTIHEAP=1");
3261 #endif
3262   envp[envc+1+extra] = 0;
3263
3264   for (rank0no=0;rank0no<nodetab_rank0_size;rank0no++)
3265   {
3266     int status = 0;
3267     int pid;
3268     int pe=nodetab_rank0_table[rank0no];
3269
3270     if (arg_verbose)
3271       printf("Charmrun> start %d node program on localhost.\n", pe);
3272     sprintf(envp[envc], "NETSTART=%s",  create_netstart(rank0no));
3273     pid = 0;
3274     pid = fork();
3275     if (pid < 0) exit(1);
3276     if (pid == 0)
3277     {
3278       int fd, fd1 = dup(1);
3279       if (-1!=(fd = open("/dev/null", O_RDWR))) {
3280         dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
3281       }
3282       status = execve(pparam_argv[1], pparam_argv+1, envp);
3283       dup2(fd1, 1);
3284       printf("execve failed to start process \"%s\" with status: %d\n", pparam_argv[1], status);
3285       kill(getppid(), 9);
3286       exit(1);
3287     }
3288   }
3289   free(envp[envc]);
3290   free(envp);
3291 }
3292
3293 #ifdef __FAULT__
3294
3295 void refill_nodetab_entry(int crashed_node);
3296 nodetab_host *replacement_host(int pe);
3297
3298 void restart_node(int crashed_node){
3299         int pe = nodetab_rank0_table[crashed_node];
3300         FILE *f;
3301         char startScript[200];
3302         int restart_rsh_pid;
3303         char **restart_argv;
3304         int status=0;
3305         int i;
3306         /** write the startScript file to be sent**/
3307         sprintf(startScript,"/tmp/charmrun.%d.%d",getpid(),pe);
3308         f=fopen(startScript,"w");
3309         
3310         /** add an argument to the argv of the new process
3311         so that the restarting processor knows that it 
3312         is a restarting processor */
3313         i=0;
3314         while(arg_argv[i]!= NULL){
3315                 i++;
3316         }
3317         restart_argv = (char **)malloc(sizeof(char *)*(i+2));
3318         i=0;
3319         while(arg_argv[i]!= NULL){
3320                 restart_argv[i] = arg_argv[i];
3321                 i++;
3322         }
3323         restart_argv[i] = "+restartaftercrash";
3324         restart_argv[i+1]=NULL;
3325
3326         rsh_script(f,pe,crashed_node,restart_argv);
3327         fclose(f);
3328         /** change the nodetable entry of the crashed
3329         processor to connect it to a new one**/
3330         refill_nodetab_entry(crashed_node);
3331         /**start the new processor */
3332         restart_rsh_pid =rsh_fork(pe,startScript);
3333         /**wait for the reply from the new process*/
3334         status=0;
3335         if (arg_debug_no_pause || arg_debug) ;
3336         else {
3337         do{
3338                 waitpid(restart_rsh_pid,&status,0);
3339         }while(!WIFEXITED(status));
3340         if (WEXITSTATUS(status)!=0){
3341          fprintf(stderr,"Charmrun> Error %d returned from new attempted rsh \n",
3342          WEXITSTATUS(status));
3343          exit(1);
3344         }     
3345         }
3346         printf("Charmrun finished launching new process in %fs\n", GetClock()-ftTimer);
3347 }
3348
3349
3350
3351 void refill_nodetab_entry(int crashed_node){
3352         int pe =  nodetab_rank0_table[crashed_node];
3353         nodetab_host *h = nodetab_table[pe];
3354         *h = *(replacement_host(pe));
3355 #ifdef _FAULT_MLOG_
3356 fprintf(stderr,"Charmrun>>> New pe %d is on host %s \n",pe,nodetab_name(pe));
3357 #endif
3358 }
3359
3360 #ifdef _FAULT_MLOG_
3361 nodetab_host *replacement_host(int pe){
3362     int x=loaded_max_pe+1;
3363
3364     x = x%arg_read_pes;
3365     loaded_max_pe +=1;
3366 /*  while(x == pe){
3367  *       x = rand()%nodetab_size;    
3368  *           }*/
3369     fprintf(stderr,"Charmrun>>> replacing pe %d with %d host %s with %s \n",pe,x,nodetab_name(pe),nodetab_name(x));
3370     return nodetab_table[x];
3371 }
3372 #else
3373 nodetab_host *replacement_host(int pe){
3374         int x=pe;
3375         while(x == pe){
3376          x = rand()%nodetab_size;        
3377         }
3378         return nodetab_table[x];
3379 }
3380 #endif
3381
3382 void reconnect_crashed_client(int socket_index,int crashed_node){
3383         int i;
3384         unsigned int clientPort;
3385         skt_ip_t clientIP;
3386         ChSingleNodeinfo *in;
3387         if(0==skt_select1(server_fd,arg_timeout*1000)){
3388                         client_connect_problem(socket_index,"Timeout waiting forrestarted node-program to connect");
3389         }
3390         req_clients[socket_index] = skt_accept(server_fd,&clientIP,&clientPort);
3391         if(req_clients[socket_index] == SOCKET_ERROR){
3392                 client_connect_problem(socket_index,"Failure in restarted node accept");
3393         }else{
3394                 ChMessage msg;
3395                 if(!skt_select1(req_clients[socket_index],arg_timeout*1000)){
3396                         client_connect_problem(socket_index,"Timeout on IP request for restarted processor");
3397                 }
3398                 ChMessage_recv(req_clients[socket_index],&msg);
3399                 if(msg.len != sizeof(ChSingleNodeinfo)){
3400                 fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
3401                 fprintf(stderr,"Charmrun: possibly because: %s.\n", msg.data);
3402                 }
3403 fprintf(stdout,"socket_index %d crashed_node %d reconnected fd %d  \n",socket_index,crashed_node,req_clients[socket_index]);
3404                 /** update the nodetab entry corresponding to
3405                 this node, skip the restarted one */
3406                 in = (ChSingleNodeinfo *)msg.data;
3407                 nodeinfo_add(in,req_clients[socket_index]);
3408                 for(i=0;i<req_nClients;i++){
3409                         if(i != socket_index){
3410                                 req_handle_initnodetab(NULL,req_clients[i]);
3411                         }       
3412                 }
3413
3414                 /* tell every one there is a crash */
3415                 anounce_crash(socket_index,crashed_node);
3416                 if (_last_crash != 0) {
3417                   fprintf(stderr, "ERROR> Charmrun detected multiple crashes.\n");
3418                   exit(1);
3419                 }
3420                 _last_crash = crashed_node;
3421                 _crash_socket_index = socket_index;
3422                 /*holds the restarted process until I got ack back from
3423                   everyone in req_handle_crashack
3424                   now the restarted one can only continue until 
3425                   req_handle_crashack calls req_handle_initnodetab(socket_index)
3426                   req_handle_initnodetab(NULL,req_clients[socket_index]); */
3427                 ChMessage_free(&msg);
3428         }       
3429 }
3430
3431 void anounce_crash(int socket_index,int crashed_node){
3432         int i;
3433         ChMessageHeader hdr;
3434         ChMessageInt_t crashNo=ChMessageInt_new(crashed_node);
3435         ChMessageHeader_new("crashnode",sizeof(ChMessageInt_t),&hdr);
3436         for(i=0;i<req_nClients;i++){
3437                 if(i != socket_index){
3438                         skt_sendN(req_clients[i],(const char *)&hdr,sizeof(hdr));
3439                         skt_sendN(req_clients[i],(const char *)&crashNo,sizeof(ChMessageInt_t));
3440                 }
3441         }
3442 }
3443
3444 #endif
3445
3446 #endif /*CMK_USE_RSH*/
3447
3448
3449
3450