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