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