added a new feature to charmrun so that it works with mpiexec now.
[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     if (pe==-nodetab_size) fprintf(stderr,"Invalid processor index in CCS request: are you trying to do a broadcast instead?");
1406     else fprintf(stderr,"Invalid processor index in CCS request.");
1407     CcsServer_sendReply(&h.hdr,0,0);
1408     free(reqData);
1409     return;
1410   }
1411   else if (pe == -1) {
1412     /*Treat -1 as broadcast and sent to 0 as root of the spanning tree*/
1413     pe = 0;
1414   }
1415   else if (pe < -1) {
1416     /*Treat negative values as multicast to a number of processors specified by -pe.
1417       The pes to multicast to follows sits at the beginning of reqData*/
1418     reqBytes -= pe * sizeof(ChMessageInt_t);
1419     pe = ChMessageInt(*(ChMessageInt_t*)reqData);
1420   }
1421   
1422   if (! check_stdio_header(&h.hdr)) {
1423
1424 #define LOOPBACK 0
1425 #if LOOPBACK /*Immediately reply "there's nothing!" (for performance testing)*/
1426     CcsServer_sendReply(&h.hdr,0,0);
1427 #else
1428     /*Fill out the charmrun header & forward the CCS request*/
1429     ChMessageHeader_new("req_fw",sizeof(h.hdr)+reqBytes,&h.ch);  
1430
1431     bufs[0]=&h; lens[0]=sizeof(h);
1432     bufs[1]=reqData; lens[1]=reqBytes;
1433     skt_sendV(nodetab_ctrlfd(pe),2,bufs,lens);
1434
1435 #endif
1436   }
1437   free(reqData);
1438 }
1439
1440 /*
1441 Forward the CCS reply (if any) from this client back to the 
1442 original network requestor, on the original request socket.
1443  */
1444 int req_ccs_reply_fw(ChMessage *msg,SOCKET srcFd) {
1445   int len=msg->len; /* bytes of data remaining to receive */
1446   
1447   /* First pull down the CCS header sent by the client. */
1448   CcsImplHeader hdr;
1449   skt_recvN(srcFd,&hdr,sizeof(hdr)); len-=sizeof(hdr);
1450   
1451 #define m (4*1024) /* packets of message to recv/send at once */
1452   if (len<m || hdr.attr.auth) 
1453   { /* short or authenticated message: grab the whole thing first */
1454      void *data=malloc(len);
1455      skt_recvN(srcFd,data,len);
1456      CcsServer_sendReply(&hdr,len,data);
1457      free(data);
1458   } 
1459   else 
1460   { /* long messages: packetize (for pipelined sending; a 2x bandwidth improvement!) */
1461     ChMessageInt_t outLen;
1462     int destFd; /* destination for data */
1463     skt_abortFn old=skt_set_abort(reply_abortFn);
1464     int destErrs=0;
1465     
1466     destFd=ChMessageInt(hdr.replyFd);
1467     outLen=ChMessageInt_new(len);
1468     skt_sendN(destFd,&outLen,sizeof(outLen)); /* first comes the length */
1469     while(len>0) {
1470        char buf[m];
1471        int r=m; if (r>len) r=len;
1472        skt_recvN(srcFd,buf,r);
1473        if (0==destErrs) /* don't keep sending to dead clients, but *do* clean out srcFd */
1474           destErrs|=skt_sendN(destFd,buf,r);
1475        len-=m;
1476 #undef m
1477     }
1478     skt_close(destFd);
1479   
1480     skt_set_abort(old); 
1481   }
1482   return 0;
1483 }
1484
1485 #else
1486 int req_ccs_reply_fw(ChMessage *msg,SOCKET srcFd) {
1487   
1488 }
1489 #endif /*CMK_CCS_AVAILABLE*/
1490
1491 /****************************************************************************
1492  *
1493  * REQUEST SERVICER
1494  *
1495  * The request servicer accepts connections on a TCP port.  The client
1496  * sends a sequence of commands (each is one line).  It then closes the
1497  * connection.  The server must then contact the client, sending replies.
1498  *
1499  ****************************************************************************/
1500  /** Macro to switch on the case when charmrun stays up even if
1501  one of the processor crashes*/
1502 /*#define __FAULT__*/
1503
1504 SOCKET *req_clients; /*TCP request sockets for each node*/
1505 int  req_nClients;/*Number of entries in above list (==nodetab_rank0_size)*/
1506 int             req_ending=0;
1507
1508 /* socket and std streams for the gdb info program */
1509 int gdb_info_pid=0;
1510 int gdb_info_std[3];
1511 FILE *gdb_stream=NULL;
1512
1513 #define REQ_OK 0
1514 #define REQ_FAILED -1
1515
1516 /* This is the only place where charmrun talks back to anyone. 
1517 */
1518 int req_reply(SOCKET fd, char *type, 
1519               const char *data, int dataLen)
1520 {
1521   ChMessageHeader msg;
1522   if (fd == INVALID_SOCKET) return REQ_FAILED;
1523   ChMessageHeader_new(type,dataLen,&msg);
1524   skt_sendN(fd,(const char *)&msg,sizeof(msg));
1525   skt_sendN(fd,data,dataLen);
1526   return REQ_OK;
1527 }
1528
1529 /* Request handlers:
1530 When a client asks us to do something, these are the
1531 routines that actually respond to the request.
1532 */
1533 /*Stash this new node's control and data ports.
1534  */
1535 int req_handle_initnode(ChMessage *msg,SOCKET fd)
1536 {
1537 #if CMK_USE_IBVERBS
1538         int i;
1539         ChSingleNodeinfo *nodeInfo = (ChSingleNodeinfo *)msg->data;
1540 //      printf("Charmrun> msg->len %d sizeof(ChSingleNodeinfo) %d sizeof(ChInfiAddr) %d \n",msg->len,sizeof(ChSingleNodeinfo),sizeof(ChInfiAddr));
1541         if(msg->len != sizeof(ChSingleNodeinfo) + (nodetab_rank0_size-1)*sizeof(ChInfiAddr)){
1542     fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
1543                 exit(1);
1544         }
1545         nodeInfo->info.qpList = malloc(sizeof(ChInfiAddr)*(nodetab_rank0_size-1));
1546         memcpy((char *)nodeInfo->info.qpList,&msg->data[sizeof(ChSingleNodeinfo)],sizeof(ChInfiAddr)*(nodetab_rank0_size-1));
1547 /*      for(i=0;i<nodetab_rank0_size-1;i++){
1548                 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));
1549         }*/
1550 #else
1551   if (msg->len!=sizeof(ChSingleNodeinfo)) {
1552     fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
1553     fprintf(stderr,"Charmrun: possibly because: %s.\n", msg->data);
1554     exit(1);
1555   }
1556 #endif  
1557   nodeinfo_add((ChSingleNodeinfo *)msg->data,fd);
1558   return REQ_OK;
1559 }
1560
1561 /*Get the array of node numbers, IPs, and ports.
1562 This is used by the node-programs to talk to one another.
1563 */
1564 int req_handle_initnodetab(ChMessage *msg,SOCKET fd)
1565 {
1566         ChMessageHeader hdr;
1567         ChMessageInt_t nNodes=ChMessageInt_new(nodetab_rank0_size);
1568         ChMessageHeader_new("initnodetab",sizeof(ChMessageInt_t)+
1569                             sizeof(ChNodeinfo)*nodetab_rank0_size,&hdr);
1570         skt_sendN(fd,(const char *)&hdr,sizeof(hdr));
1571         skt_sendN(fd,(const char *)&nNodes,sizeof(nNodes));
1572         skt_sendN(fd,(const char *)nodeinfo_arr,
1573                   sizeof(ChNodeinfo)*nodetab_rank0_size);
1574                         
1575         return REQ_OK;
1576 }
1577
1578 /* Check this return code from "printf". */
1579 static void checkPrintfError(int err) {
1580   if (err<0) {
1581     static int warned=0;
1582     if (!warned) {
1583       perror("charmrun WARNING> error in printf");
1584       warned=1;
1585     }
1586   }
1587 }
1588
1589 int req_handle_print(ChMessage *msg,SOCKET fd)
1590 {
1591   checkPrintfError(printf("%s",msg->data));
1592   checkPrintfError(fflush(stdout));
1593   write_stdio_duplicate(msg->data);
1594   return REQ_OK;
1595 }
1596
1597
1598 int req_handle_printerr(ChMessage *msg,SOCKET fd)
1599 {
1600   fprintf(stderr,"%s",msg->data);
1601   fflush(stderr);
1602   write_stdio_duplicate(msg->data);
1603   return REQ_OK;
1604 }
1605
1606
1607 int req_handle_printsyn(ChMessage *msg,SOCKET fd)
1608 {
1609   checkPrintfError(printf("%s",msg->data));
1610   checkPrintfError(fflush(stdout));
1611   write_stdio_duplicate(msg->data);
1612   req_reply(fd, "printdone", "", 1);
1613   return REQ_OK;
1614 }
1615
1616
1617 int req_handle_printerrsyn(ChMessage *msg,SOCKET fd)
1618 {
1619   fprintf(stderr,"%s",msg->data);
1620   fflush(stderr);
1621   write_stdio_duplicate(msg->data);
1622   req_reply(fd, "printdone", "", 1);
1623   return REQ_OK;
1624 }
1625
1626
1627 int req_handle_ending(ChMessage *msg,SOCKET fd)
1628 {  
1629   int i;
1630   req_ending++;
1631
1632 #if (!defined(_FAULT_MLOG_) && !defined(_FAULT_CAUSAL_))    
1633         if (req_ending == nodetab_size)
1634 #else
1635         if(req_ending == arg_requested_pes)
1636 #endif
1637   {
1638     for (i=0;i<req_nClients;i++)
1639       skt_close(req_clients[i]);
1640     if (arg_verbose) printf("Charmrun> Graceful exit.\n");
1641     exit(0);
1642   }
1643   return REQ_OK;
1644 }
1645
1646 int req_handle_barrier(ChMessage *msg,SOCKET fd)
1647 {
1648   int i;
1649   static int barrier_count = 0;
1650   static int barrier_phase = 0;
1651   barrier_count ++;
1652   if (barrier_count == req_nClients) {
1653     barrier_count = 0;
1654     barrier_phase ++;
1655     for (i=0;i<req_nClients;i++)
1656       if (REQ_OK != req_reply(req_clients[i], "barrier", "", 1))
1657       {
1658         fprintf(stderr, "req_handle_barrier socket error: %d\n", i);
1659         abort();
1660       }
1661   }
1662   return REQ_OK;
1663 }
1664
1665 int req_handle_barrier0(ChMessage *msg,SOCKET fd)
1666 {
1667   int i;
1668   static int count = 0;
1669   static SOCKET fd0;
1670   int pe = atoi(msg->data);
1671   if (pe == 0) fd0 = fd;
1672   count ++;
1673   if (count == req_nClients) {
1674     req_reply(fd0, "barrier0", "", 1);     /* only send to node 0 */
1675     count = 0;
1676   }
1677   return REQ_OK;
1678 }
1679
1680
1681 int req_handle_abort(ChMessage *msg,SOCKET fd)
1682 {
1683   /*fprintf(stderr,"req_handle_abort called \n");*/
1684   if (msg->len==0) 
1685     fprintf(stderr,"Aborting!\n");
1686   else
1687     fprintf(stderr, "%s\n", msg->data);
1688   exit(1);
1689 }
1690
1691 int req_handle_scanf(ChMessage *msg,SOCKET fd)
1692 {
1693   char *fmt, *res, *p;
1694
1695   fmt = msg->data;
1696   fmt[msg->len-1]=0;
1697   res = input_scanf_chars(fmt);
1698   p = res; while (*p) { if (*p=='\n') *p=' '; p++; }
1699   req_reply(fd, "scanf-data", res, strlen(res)+1);
1700   free(res);
1701   return REQ_OK;
1702 }
1703
1704 #ifdef __FAULT__        
1705 void restart_node(int crashed_node);
1706 void reconnect_crashed_client(int socket_index,int crashed_node);
1707 void anounce_crash(int socket_index,int crashed_node);
1708
1709 static int _last_crash = 0;                     /* last crashed pe number */
1710 static int _crash_socket_index = 0;             /* last restart socket */
1711
1712 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1713 static int numCrashes=0;  /*number of crashes*/
1714 static SOCKET last_crashed_fd=-1;
1715 #endif
1716
1717 int req_handle_crashack(ChMessage *msg,SOCKET fd)
1718 {
1719   static int count = 0;
1720   count ++;
1721   if (count == req_nClients-1) {
1722     /* only after everybody else update its nodetab, can this
1723        restarted process continue */
1724     printf("Charmrun> continue node: %d\n", _last_crash);
1725     req_handle_initnodetab(NULL,req_clients[_crash_socket_index]);
1726     _last_crash = 0;
1727     count = 0;
1728 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1729         last_crashed_fd=-1;
1730 #endif
1731   }
1732 }
1733 #endif
1734
1735 #ifdef __FAULT__
1736 void error_in_req_serve_client(SOCKET fd){
1737         SOCKET * new_req_clients=(SOCKET *)malloc((req_nClients-1)*sizeof(SOCKET));
1738         int count=0,i;
1739         int crashed_node,crashed_pe,node_index,socket_index;
1740         fprintf(stdout,"Socket %d failed \n",fd);
1741         for(i=0;i<nodetab_max;i++){
1742                 if(nodetab_ctrlfd(i) == fd){
1743                         break;
1744                 }
1745         }
1746         fflush(stdout);
1747 #if (!defined(_FAULT_MLOG_) && !defined(_FAULT_CAUSAL_))
1748         skt_close(fd);
1749 #endif
1750         crashed_pe = i;
1751         node_index = i-nodetab_rank(crashed_pe);
1752         for(i=0;i<nodetab_rank0_size;i++){
1753                 if(node_index == nodetab_rank0_table[i]){
1754                         break;
1755                 }
1756         }
1757         crashed_node = i;
1758         /** should also send a message to all the other processors telling them that this guy has crashed*/
1759         /*anounce_crash(socket_index,crashed_node);*/
1760         restart_node(crashed_node);
1761         
1762         fprintf(stdout,"charmrun says Processor %d failed on Node %d\n",crashed_pe,crashed_node);
1763         /** after the crashed processor has been recreated 
1764          it connects to charmrun. That data must now be filled 
1765          into the req_nClients array and the nodetab_table*/
1766
1767         for(i=0;i<req_nClients;i++){
1768                 if(req_clients[i] == fd){
1769                         break;
1770                 }
1771         }       
1772         socket_index = i;
1773         reconnect_crashed_client(socket_index,crashed_node);
1774 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1775         skt_close(fd);
1776 #endif
1777 }
1778 #endif
1779
1780 int req_handler_dispatch(ChMessage *msg,SOCKET replyFd)
1781 {
1782   char *cmd=msg->header.type;
1783   int recv_status;
1784   DEBUGF(("Got request '%s'\n",cmd,replyFd));
1785 #if CMK_CCS_AVAILABLE   /* CCS *doesn't* want data yet, for faster forwarding */
1786   if (strcmp(cmd,"reply_fw")==0)   return req_ccs_reply_fw(msg,replyFd);
1787 #endif
1788
1789   /* grab request data */
1790   recv_status = ChMessageData_recv(replyFd,msg);
1791 #ifdef __FAULT__
1792 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1793  if(recv_status < 0){
1794         if(replyFd == last_crashed_fd){
1795             return REQ_OK;
1796         }
1797         DEBUGF(("recv_status %d on socket %d \n",recv_status,replyFd));
1798         error_in_req_serve_client(replyFd);
1799     }
1800 #else   
1801   if(recv_status < 0)  error_in_req_serve_client(replyFd);
1802 #endif
1803 #endif
1804
1805        if (strcmp(cmd,"ping")==0)       return REQ_OK;
1806   else if (strcmp(cmd,"print")==0)      return req_handle_print(msg,replyFd);
1807   else if (strcmp(cmd,"printerr")==0)   return req_handle_printerr(msg,replyFd);
1808   else if (strcmp(cmd,"printsyn")==0)  return req_handle_printsyn(msg,replyFd);
1809   else if (strcmp(cmd,"printerrsyn")==0) return req_handle_printerrsyn(msg,replyFd);
1810   else if (strcmp(cmd,"scanf")==0)      return req_handle_scanf(msg,replyFd);
1811   else if (strcmp(cmd,"barrier")==0)    return req_handle_barrier(msg,replyFd);
1812   else if (strcmp(cmd,"barrier0")==0)   return req_handle_barrier0(msg,replyFd);
1813   else if (strcmp(cmd,"ending")==0)     return req_handle_ending(msg,replyFd);
1814   else if (strcmp(cmd,"abort")==0)      return req_handle_abort(msg,replyFd);
1815 #ifdef __FAULT__        
1816   else if (strcmp(cmd,"crash_ack")==0)   return req_handle_crashack(msg,replyFd);
1817 #endif
1818   else {
1819 #ifndef __FAULT__       
1820         fprintf(stderr,"Charmrun> Bad control socket request '%s'\n",cmd); 
1821         abort();
1822         return REQ_OK;
1823 #endif                          
1824   }
1825   return REQ_OK;
1826 }
1827
1828 void req_serve_client(SOCKET fd)
1829 {
1830   int recv_status;
1831   int status;
1832   ChMessage msg;
1833   DEBUGF(("Getting message from client...\n"));
1834   recv_status = ChMessageHeader_recv(fd,&msg);
1835 #ifdef __FAULT__        
1836   if(recv_status < 0) error_in_req_serve_client(fd);
1837 #endif
1838         
1839   DEBUGF(("Message is '%s'\n",msg.header.type));
1840   status = req_handler_dispatch(&msg,fd);
1841   switch (status) 
1842   {
1843     case REQ_OK: break;
1844     case REQ_FAILED: 
1845         fprintf(stderr,"Charmrun> Error processing control socket request %s\n",msg.header.type); 
1846         abort();
1847         break;
1848   }
1849   ChMessage_free(&msg);
1850 }
1851
1852
1853 int ignore_socket_errors(int c,const char *m)
1854 {  /*Abandon on further socket errors during error shutdown*/
1855   
1856 #ifndef __FAULT__       
1857   exit(2);
1858 #endif  
1859         return -1;
1860 }
1861
1862 /*A socket went bad somewhere!  Immediately disconnect,
1863 which kills everybody.
1864 */
1865 int socket_error_in_poll(int code,const char *msg)
1866 {
1867 /*commenting it for fault tolerance*/
1868 /*ifdef it*/
1869
1870         int i;
1871         skt_set_abort(ignore_socket_errors);
1872         fprintf(stderr,"Charmrun: error on request socket--\n"
1873                         "%s\n",msg);
1874 #ifndef __FAULT__                       
1875         for (i=0;i<req_nClients;i++)
1876                 skt_close(req_clients[i]);
1877         exit(1);
1878 #endif  
1879         ftTimer = GetClock();
1880         return -1;
1881 }
1882
1883 #if CMK_USE_POLL /*poll() version*/
1884 # define CMK_PIPE_DECL(maxn,delayMs) \
1885         static struct pollfd *fds = NULL; \
1886         int nFds_sto=0; int *nFds=&nFds_sto; \
1887         int pollDelayMs=delayMs; \
1888         if (fds == NULL) fds = (struct pollfd *)malloc((maxn) * sizeof(struct pollfd));
1889 # define CMK_PIPE_SUB fds,nFds
1890 # define CMK_PIPE_CALL() poll(fds, *nFds, pollDelayMs); *nFds=0
1891
1892 # define CMK_PIPE_PARAM struct pollfd *fds,int *nFds
1893 # define CMK_PIPE_ADDREAD(rd_fd) \
1894         do {fds[*nFds].fd=rd_fd; fds[*nFds].events=POLLIN; (*nFds)++;} while(0)
1895 # define CMK_PIPE_ADDWRITE(wr_fd) \
1896         do {fds[*nFds].fd=wr_fd; fds[*nFds].events=POLLOUT; (*nFds)++;} while(0)
1897 # define CMK_PIPE_CHECKREAD(rd_fd) fds[(*nFds)++].revents&POLLIN
1898 # define CMK_PIPE_CHECKWRITE(wr_fd) fds[(*nFds)++].revents&POLLOUT
1899
1900 #else /*select() version*/
1901
1902 # define CMK_PIPE_DECL(maxn, delayMs) \
1903         fd_set rfds_sto,wfds_sto;\
1904         int nFds=0;  \
1905         fd_set *rfds=&rfds_sto,*wfds=&wfds_sto; struct timeval tmo; \
1906         FD_ZERO(rfds); FD_ZERO(wfds); \
1907         tmo.tv_sec=delayMs/1000; tmo.tv_usec=1000*(delayMs%1000);
1908 # define CMK_PIPE_SUB rfds,wfds
1909 # define CMK_PIPE_CALL() select(FD_SETSIZE, rfds, 0, 0, &tmo)
1910
1911 # define CMK_PIPE_PARAM fd_set *rfds,fd_set *wfds
1912 # define CMK_PIPE_ADDREAD(rd_fd) { assert(nFds<FD_SETSIZE);FD_SET(rd_fd,rfds); nFds++; }
1913 # define CMK_PIPE_ADDWRITE(wr_fd) FD_SET(wr_fd,wfds)
1914 # define CMK_PIPE_CHECKREAD(rd_fd) FD_ISSET(rd_fd,rfds)
1915 # define CMK_PIPE_CHECKWRITE(wr_fd) FD_ISSET(wr_fd,wfds)
1916 #endif
1917
1918 /*
1919 Wait for incoming requests on all client sockets,
1920 and the CCS socket (if present).
1921 */
1922 void req_poll()
1923 {
1924   int status,i;
1925   int readcount;
1926
1927   CMK_PIPE_DECL(req_nClients+5, 1000);
1928   for (i=0;i<req_nClients;i++)
1929         CMK_PIPE_ADDREAD(req_clients[i]);
1930   if (CcsServer_fd()!=INVALID_SOCKET) CMK_PIPE_ADDREAD(CcsServer_fd());
1931   if (arg_charmdebug) {
1932     CMK_PIPE_ADDREAD(0);
1933     CMK_PIPE_ADDREAD(gdb_info_std[1]);
1934     CMK_PIPE_ADDREAD(gdb_info_std[2]);
1935   }
1936
1937   skt_set_abort(socket_error_in_poll);
1938
1939   DEBUGF(("Req_poll: Calling select...\n"));
1940   status=CMK_PIPE_CALL();
1941   DEBUGF(("Req_poll: Select returned %d...\n",status));
1942
1943   if (status==0) return;/*Nothing to do-- timeout*/
1944
1945   if (status<0){ 
1946                 fflush(stdout);
1947                 fflush(stderr);
1948                 socket_error_in_poll(1359,"Node program terminated unexpectedly!\n");
1949         }
1950   for (i=0;i<req_nClients;i++)
1951         if (CMK_PIPE_CHECKREAD(req_clients[i]))
1952           {
1953             readcount=10;   /*number of successive reads we serve per socket*/
1954             /*This client is ready to read*/
1955             do { req_serve_client(req_clients[i]); readcount--;}
1956             while (1==skt_select1(req_clients[i],0) && readcount>0);
1957           }
1958
1959   if (CcsServer_fd()!=INVALID_SOCKET)
1960          if (CMK_PIPE_CHECKREAD(CcsServer_fd())) {
1961                   DEBUGF(("Activity on CCS server port...\n"));
1962                   req_ccs_connect();
1963          }
1964
1965   if (arg_charmdebug) {
1966     char buf[2048];
1967     if (CMK_PIPE_CHECKREAD(0)) {
1968       int indata = read(0, buf, 5);
1969       buf[indata] = 0;
1970       if (indata < 5) fprintf(stderr,"Error reading command (%s)\n",buf);
1971       if (strncmp(buf,"info:",5)==0) {
1972         /* Found info command, forward data to gdb info program */
1973         char c;
1974         int num=0;
1975         //printf("Command to be forwarded\n");
1976         while (read(0, &c, 1)!=-1) {
1977           buf[num++]=c;
1978           if (c=='\n' || num >= 2045) {
1979             write(gdb_info_std[0], buf, num);
1980             if (c=='\n') break;
1981           }
1982         }
1983       }
1984       //printf("Command from charmdebug: %d(%s)\n",indata,buf);
1985     }
1986     /* All streams from gdb are forwarded to the stderr stream through the FILE
1987        gdb_stream which has been duplicated from stderr */
1988     /* NOTE: gdb_info_std[2] must be flushed before gdb_info_std[1] because the
1989        latter contains the string "(gdb) " ending the synchronization. Also the
1990        std[1] should be read with the else statement. It will not work without. */
1991     if (CMK_PIPE_CHECKREAD(gdb_info_std[2])) {
1992       int indata = read(gdb_info_std[2], buf, 100);
1993       /*printf("read data from gdb info stderr %d\n",indata);*/
1994       if (indata > 0) {
1995         buf[indata] = 0;
1996         //printf("printing %s\n",buf);
1997         //fflush(stdout);
1998         //fprintf(gdb_stream,"%s",buf);
1999         fflush(gdb_stream);
2000       }
2001     } else if (CMK_PIPE_CHECKREAD(gdb_info_std[1])) {
2002       int indata = read(gdb_info_std[1], buf, 100);
2003       /*printf("read data from gdb info stdout %d\n",indata);*/
2004       if (indata > 0) {
2005         buf[indata] = 0;
2006         //printf("printing %s\n",buf);
2007         //fflush(stdout);
2008         fprintf(gdb_stream,"%s",buf);
2009         fflush(gdb_stream);
2010       }
2011     }
2012   }
2013 }
2014
2015
2016
2017 static unsigned int server_port;
2018 static char server_addr[1024];/* IP address or hostname of charmrun*/
2019 static SOCKET server_fd;
2020
2021 int client_connect_problem(int code,const char *msg)
2022 {/*Called when something goes wrong during a client connect*/
2023
2024         fprintf(stderr,"Charmrun> error %d attaching to node:\n"
2025                 "%s\n",code,msg);
2026         exit(1);
2027         return -1;
2028 }
2029
2030 /** return 1 if connection is openned succesfully with client**/
2031 int errorcheck_one_client_connect(int client){
2032         unsigned int clientPort;/*These are actually ignored*/
2033         skt_ip_t clientIP;
2034         if (arg_verbose) printf("Charmrun> Waiting for %d-th client to connect.\n",client);
2035         if (0==skt_select1(server_fd,arg_timeout*1000))
2036                 client_connect_problem(client,"Timeout waiting for node-program to connect");
2037
2038                 
2039         req_clients[client]=skt_accept(server_fd,&clientIP,&clientPort);
2040
2041         if (req_clients[client]==SOCKET_ERROR) 
2042                 client_connect_problem(client,"Failure in node accept");
2043
2044         skt_tcp_no_nagle(req_clients[client]);
2045
2046         return 1;
2047 };
2048
2049
2050 #if CMK_C_INLINE
2051 inline static
2052 #endif
2053 void read_initnode_one_client(int client){
2054                 ChMessage msg;
2055                 if (!skt_select1(req_clients[client],arg_timeout*1000))
2056                    client_connect_problem(client,"Timeout on IP request");
2057                 ChMessage_recv(req_clients[client],&msg);
2058                 req_handle_initnode(&msg,req_clients[client]);
2059                 ChMessage_free(&msg);
2060 }
2061
2062
2063 #if CMK_IBVERBS_FAST_START
2064 void req_one_client_partinit(int client){
2065    ChMessage partStartMsg;
2066          int clientNode;
2067                 
2068          if(errorcheck_one_client_connect(client)){
2069            if (!skt_select1(req_clients[client],arg_timeout*1000))
2070                    client_connect_problem(client,"Timeout on partial init request");
2071                          
2072            ChMessage_recv(req_clients[client],&partStartMsg);
2073            clientNode =            ChMessageInt(*(ChMessageInt_t*)partStartMsg.data);
2074            assert(strncmp(partStartMsg.header.type,"partinit",8) == 0);
2075            ChMessage_free(&partStartMsg);
2076          } 
2077         
2078 };
2079 #endif
2080
2081 void req_set_client_connect(int start,int end) {
2082         fd_set sockset;
2083         ChMessage msg;
2084         int client,i;
2085         int done,maxdesc;
2086         int *finished;
2087         int curclient,curclientend,curclientstart;
2088         
2089         curclient=curclientend=curclientstart=start;
2090
2091         finished=malloc((end-start)*sizeof(int));
2092         for(i=0;i<(end-start);i++)
2093                 finished[i]=0;
2094
2095 #if CMK_USE_IBVERBS && !CMK_IBVERBS_FAST_START
2096         for (i=start;i<end;i++) {
2097                 errorcheck_one_client_connect(curclientend++);
2098         }        
2099         if (req_nClients > 1) {
2100                 /*  a barrier to make sure infiniband device gets initialized */
2101                 for (i=start;i<end;i++) 
2102                         ChMessage_recv(req_clients[i],&msg);
2103                 for (i=start;i<end;i++)
2104                         req_reply(req_clients[i], "barrier", "", 1);
2105         }
2106 #endif
2107
2108         done=0;
2109         while(!done) {
2110                 /* check server socket for messages */
2111 #if ! CMK_USE_IBVERBS || CMK_IBVERBS_FAST_START
2112                 while(curclientstart==curclientend||skt_select1(server_fd,1)!=0) {
2113                         errorcheck_one_client_connect(curclientend++);
2114                 }
2115 #endif
2116                 /* check appropriate clients for messages */
2117                 for(client=curclientstart;client<curclientend;client++)
2118                         if(req_clients[client]>0) {
2119                                 if(skt_select1(req_clients[client],1)!=0) {
2120                                         ChMessage_recv(req_clients[client],&msg);
2121                                         req_handle_initnode(&msg,req_clients[client]);
2122                                         finished[client-start]=1;
2123                                 }
2124                         }
2125
2126
2127                 /* test if done */
2128                 done=1;
2129                 for(i=curclientstart-start;i<(end-start);i++)
2130                         if(finished[i]==0) {
2131                                 curclientstart=start+i;
2132                                 done=0;
2133                                 break;
2134                         }
2135
2136         }
2137         ChMessage_free(&msg);
2138
2139         free(finished);
2140 }
2141
2142
2143 /* allow one client to connect */
2144 void req_one_client_connect(int client)
2145 {
2146         if(errorcheck_one_client_connect(client))
2147         { /*This client has just connected-- fetch his name and IP*/
2148                 read_initnode_one_client(client);
2149         }
2150 }
2151
2152 #if CMK_USE_IBVERBS
2153 /* Each node has sent the qpn data for all the qpns it has created
2154    This data needs to be sent to all the other nodes
2155          This needs to be done for all nodes
2156 **/
2157 void exchange_qpdata_clients(){
2158         int proc,i;
2159         for( i=0;i<nodetab_rank0_size;i++){
2160                 int nt=nodetab_rank0_table[i];/*Nodetable index for this node*/ 
2161                 nodetab_table[nt]->qpData = malloc(sizeof(ChInfiAddr)*nodetab_rank0_size);
2162         }
2163         for(proc =0;proc< nodetab_rank0_size;proc++){
2164                 int count=0;
2165                 for(i=0;i<nodetab_rank0_size;i++){
2166                         if(i == proc){
2167                         }else{
2168                                 int nt=nodetab_rank0_table[i];/*Nodetable index for this node*/ 
2169                                 nodetab_table[nt]->qpData[proc] =  nodeinfo_arr[proc].qpList[count];
2170         //                      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));
2171                                 count++;
2172                         }
2173                 }
2174                 free(nodeinfo_arr[proc].qpList);
2175         }
2176 };
2177
2178 void    send_clients_nodeinfo_qpdata(){
2179         int node;
2180         int msgSize = sizeof(ChMessageInt_t)+sizeof(ChNodeinfo)*nodetab_rank0_size+sizeof(ChInfiAddr)*nodetab_rank0_size;
2181         for(node=0;node<nodetab_rank0_size;node++){
2182                 int nt=nodetab_rank0_table[node];/*Nodetable index for this node*/
2183 //              printf("Charmrun> Node %d proc %d sending initnodetab \n",node,nt);
2184                 ChMessageHeader hdr;
2185                 ChMessageInt_t nNodes=ChMessageInt_new(nodetab_rank0_size);
2186                 ChMessageHeader_new("initnodetab",msgSize,&hdr);
2187                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&hdr,sizeof(hdr));
2188                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&nNodes,sizeof(nNodes));
2189                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)nodeinfo_arr,sizeof(ChNodeinfo)*nodetab_rank0_size);
2190                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&nodetab_table[nt]->qpData[0],sizeof(ChInfiAddr)*nodetab_rank0_size);                         
2191         }
2192 }
2193 #endif
2194
2195
2196 /*Wait for all the clients to connect to our server port*/
2197 void req_client_connect(void)
2198 {
2199         int client;
2200         nodeinfo_allocate();
2201         req_nClients=nodetab_rank0_size;
2202         req_clients=(SOCKET *)malloc(req_nClients*sizeof(SOCKET));
2203         for(client=0;client<req_nClients;client++)
2204                 req_clients[client]=-1;
2205         
2206         skt_set_abort(client_connect_problem);
2207         
2208 #if CMK_IBVERBS_FAST_START
2209         for (client=0;client<req_nClients;client++){
2210                 req_one_client_partinit(client);
2211         }
2212         for (client=0;client<req_nClients;client++){
2213                 read_initnode_one_client(client);
2214         }
2215 #else
2216         req_set_client_connect(0,req_nClients);
2217 #endif
2218         
2219         if (portOk == 0) exit(1);
2220         if (arg_verbose) printf("Charmrun> All clients connected.\n");
2221 #if CMK_USE_IBVERBS
2222         exchange_qpdata_clients();
2223         send_clients_nodeinfo_qpdata();
2224 #else
2225         for (client=0;client<req_nClients;client++)
2226                 req_handle_initnodetab(NULL,req_clients[client]);
2227 #endif
2228         if (arg_verbose) printf("Charmrun> IP tables sent.\n");
2229 }
2230
2231 #ifndef CMK_BPROC
2232
2233 void start_one_node_rsh(int rank0no);
2234 void finish_one_node(int rank0no);
2235 void finish_set_nodes(int start, int stop);
2236
2237
2238
2239 void req_client_start_and_connect(void)
2240 {
2241         int client, c;
2242         int batch = arg_batch_spawn;        /* fire several at a time */
2243         int clientgroup,clientstart;
2244         int counter;
2245
2246         nodeinfo_allocate();
2247         req_nClients=nodetab_rank0_size;
2248         req_clients=(SOCKET *)malloc(req_nClients*sizeof(SOCKET));
2249         
2250         skt_set_abort(client_connect_problem);
2251
2252         client=0;
2253         while(client<req_nClients) { /* initiate a batch */
2254                 clientstart=client;
2255
2256                 for(counter=0;counter<batch;counter++) { /* initiate batch number of nodes */
2257                         clientgroup=start_set_node_rsh(client);
2258                         client+=clientgroup;
2259                         if(client>=req_nClients) {
2260                                 client=req_nClients;
2261                                 break;
2262                         }
2263                 }
2264                 finish_set_nodes(clientstart,client);
2265
2266 #if CMK_IBVERBS_FAST_START
2267                 for (c=clientstart;c<client;c++) { 
2268                         req_one_client_partinit(c);
2269                 }
2270 #else
2271                 req_set_client_connect(clientstart,client);
2272 #endif                                          
2273         }
2274
2275
2276 #if CMK_IBVERBS_FAST_START
2277         for (client=0;client<req_nClients;client++){
2278                 read_initnode_one_client(client);
2279         }
2280 #endif
2281         if (portOk == 0) exit(1);
2282         if (arg_verbose) printf("Charmrun> All clients connected.\n");
2283         
2284 #if CMK_USE_IBVERBS
2285         exchange_qpdata_clients();      
2286         send_clients_nodeinfo_qpdata();
2287 #else
2288         for (client=0;client<req_nClients;client++) {
2289                 req_handle_initnodetab(NULL,req_clients[client]);
2290         }
2291 #endif    
2292         if (arg_verbose) printf("Charmrun> IP tables sent.\n");
2293         free(rsh_pids); /* done with rsh_pids */
2294 }
2295
2296 #endif
2297
2298 /*Start the server socket the clients will connect to.*/
2299 void req_start_server(void)
2300 {
2301   skt_ip_t ip=skt_innode_my_ip();
2302   if (arg_local)
2303       /* local execution, use localhost always */
2304     strcpy(server_addr, "127.0.0.1");
2305   else if (arg_charmrunip != NULL)
2306       /* user specify the IP at +useip */
2307     strcpy(server_addr, arg_charmrunip);
2308   else if ( (arg_charmrunip = getenv ("CHARMRUN_IP")) != NULL)
2309       /* user specify the env  */
2310     strcpy(server_addr, arg_charmrunip);
2311   else if (skt_ip_match(ip,_skt_invalid_ip)) {
2312       printf("Charmrun> Warning-- cannot find IP address for your hostname.  Using loopback.\n");
2313       strcpy(server_addr, "127.0.0.1");
2314   }
2315   else if (arg_usehostname || skt_ip_match(ip,skt_lookup_ip("127.0.0.1")))
2316       /*Use symbolic host name as charmrun address*/
2317     gethostname(server_addr,sizeof(server_addr));
2318   else 
2319     skt_print_ip(server_addr,ip);
2320
2321   server_port = 0;
2322   server_fd=skt_server(&server_port);
2323
2324   if (arg_verbose) {
2325     printf("Charmrun> Charmrun = %s, port = %d\n", server_addr, server_port);
2326   }
2327   
2328 #if CMK_CCS_AVAILABLE
2329   if(arg_server == 1) CcsServer_new(NULL,&arg_server_port,arg_server_auth);
2330 #endif
2331 }
2332
2333 /****************************************************************************
2334  *
2335  *  The Main Program
2336  *
2337  ****************************************************************************/
2338 void start_nodes_daemon(void);
2339 void start_nodes_rsh(void);
2340 void start_nodes_mpiexec();
2341 #if CMK_BPROC
2342 void nodetab_init_for_scyld(void);
2343 void start_nodes_scyld(void);
2344 #endif
2345 void start_nodes_local(char **envp);
2346 void kill_nodes(void);
2347 void open_gdb_info(void);
2348 void read_global_segments_size(void);
2349
2350 static void fast_idleFn(void) {sleep(0);}
2351 void finish_nodes(void);
2352
2353 int main(int argc, char **argv, char **envp)
2354 {
2355   srand(time(0));
2356   skt_init();
2357   skt_set_idle(fast_idleFn);
2358   /* CrnSrand((int) time(0)); */
2359   /* notify charm developers that charm is in use */
2360   ping_developers();
2361   /* Compute the values of all constants */
2362   arg_init(argc, argv);
2363   if(arg_verbose) fprintf(stderr, "Charmrun> charmrun started...\n");
2364   start_timer = GetClock();
2365 #if CMK_BPROC
2366   /* check scyld configuration */
2367   if (arg_nodelist)
2368     nodetab_init();
2369   else
2370     nodetab_init_for_scyld();
2371 #else
2372   /* Initialize the node-table by reading nodesfile */
2373   nodetab_init();
2374 #endif
2375
2376   /* Start the server port */
2377   req_start_server();
2378   
2379   /* Initialize the IO module */
2380   input_init();
2381   
2382   /* start the node processes */
2383   if (0!=getenv("CONV_DAEMON"))
2384     start_nodes_daemon();
2385   else
2386 #if CMK_BPROC
2387     start_nodes_scyld();
2388 #else
2389 #if CMK_USE_IBVERBS
2390                 printf("Charmrun> IBVERBS version of charmrun\n");
2391 #endif
2392     if (!arg_local) {
2393       if (!arg_batch_spawn) {
2394         if (arg_mpiexec)
2395           start_nodes_mpiexec();
2396         else
2397           start_nodes_rsh();
2398       }
2399       else
2400         req_client_start_and_connect();
2401     }
2402     else
2403       start_nodes_local(envp);
2404 #endif
2405
2406   if (arg_charmdebug) {
2407 #if (defined(_WIN32) && !defined(__CYGWIN__)) || CMK_BPROC
2408     /* Gdb stream (and charmdebug) currently valid only with rsh subsystem */
2409     fprintf(stderr, "Charmdebug is supported currently only with the rsh subsystem\n");
2410     abort(); 
2411 #else
2412     /* Open an additional connection to node 0 with a gdb to grab info */
2413     printf("opening connection with node 0 for info gdb\n");
2414     read_global_segments_size();
2415     open_gdb_info();
2416     gdb_stream = fdopen(dup(2), "a");
2417     dup2(1, 2);
2418 #endif
2419   }
2420
2421   if(arg_verbose) fprintf(stderr, "Charmrun> node programs all started\n");
2422
2423   /* Wait for all clients to connect */
2424 #if !CMK_RSH_KILL
2425   if (!arg_batch_spawn) finish_nodes();
2426 #endif
2427   if (!arg_batch_spawn) req_client_connect();
2428 #if CMK_RSH_KILL
2429   kill_nodes();
2430 #endif
2431   if(arg_verbose) fprintf(stderr, "Charmrun> node programs all connected\n");
2432     /* report time */
2433   fprintf(stderr, "Charmrun> started all node programs in %.3f seconds.\n", GetClock()-start_timer);
2434
2435   /* enter request-service mode */
2436   while (1) req_poll();
2437 }
2438
2439 /*This little snippet creates a NETSTART 
2440 environment variable entry for the given node #.
2441 It uses the idiotic "return reference to static buffer"
2442 string return idiom.
2443 */
2444 char *create_netstart(int node)
2445 {
2446   static char dest[1024];
2447   int port=0;
2448   if (arg_mpiexec)
2449     sprintf(dest,"$OMPI_COMM_WORLD_RANK %s %d %d %d",server_addr,server_port,getpid()&0x7FFF, port);
2450   else
2451     sprintf(dest,"%d %s %d %d %d",node,server_addr,server_port,getpid()&0x7FFF, port);
2452   return dest;
2453 }
2454
2455 /* The remainder of charmrun is only concerned with starting all
2456 the node-programs, also known as charmrun clients.  We have to
2457 start nodetab_rank0_size processes on the remote machines.
2458 */
2459
2460 /*Ask the converse daemon running on each machine to start the node-programs.*/
2461 void start_nodes_daemon(void)
2462 {
2463   taskStruct task;
2464   char argBuffer[5000];/*Buffer to hold assembled program arguments*/
2465   int i,nodeNumber;
2466
2467   /*Set the parts of the task structure that will be the same for all nodes*/
2468   /*Figure out the command line arguments (same for all PEs)*/
2469   argBuffer[0]=0;
2470   for (i=0;arg_argv[i];i++) 
2471   {
2472     if (arg_verbose)
2473       printf("Charmrun> packing arg: %s\n", arg_argv[i]);
2474     strcat(argBuffer," ");
2475     strcat(argBuffer,arg_argv[i]);
2476   }
2477   
2478   task.magic=ChMessageInt_new(DAEMON_MAGIC);
2479
2480 /*Start up the user program, by sending a message
2481   to PE 0 on each node.*/
2482   for (nodeNumber=0;nodeNumber<nodetab_rank0_size;nodeNumber++)
2483   {
2484     char nodeArgBuffer[5000];/*Buffer to hold assembled program arguments*/
2485     char *argBuf;
2486     char* arg_nodeprog_r, *arg_currdir_r;
2487     char statusCode='N';/*Default error code-- network problem*/
2488     int fd;
2489     int pe0=nodetab_rank0_table[nodeNumber];
2490     
2491     arg_currdir_r = pathfix(arg_currdir_a, nodetab_pathfixes(nodeNumber));
2492     strcpy(task.cwd,arg_currdir_r);
2493
2494     arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(nodeNumber), nodetab_ext(nodeNumber));
2495     strcpy(task.pgm,arg_nodeprog_r);
2496
2497     if (arg_verbose)
2498       printf("Charmrun> Starting node program %d on '%s' as %s.\n",nodeNumber,nodetab_name(pe0), arg_nodeprog_r);
2499
2500     sprintf(task.env,"NETSTART=%s",create_netstart(nodeNumber));
2501
2502     if (nodetab_nice(nodeNumber) != -100) {
2503       if(arg_verbose) fprintf(stderr, "Charmrun> +nice %d\n", nodetab_nice(nodeNumber));
2504       sprintf(nodeArgBuffer, "%s +nice %d", argBuffer, nodetab_nice(nodeNumber));
2505       argBuf = nodeArgBuffer;
2506     }
2507     else 
2508       argBuf = argBuffer;
2509     task.argLength=ChMessageInt_new(strlen(argBuf));
2510
2511     /*Send request out to remote node*/
2512     fd = skt_connect(nodetab_ip(pe0),
2513                      DAEMON_IP_PORT,30);
2514     if (fd!=INVALID_SOCKET)
2515     {/*Contact!  Ask the daemon to start the program*/
2516       skt_sendN(fd, (const char *)&task, sizeof(task));
2517       skt_sendN(fd, (const char *)argBuf, strlen(argBuf));
2518       skt_recvN(fd, &statusCode,sizeof(char));
2519     }
2520     if (statusCode!='G')
2521     {/*Something went wrong--*/
2522       fprintf(stderr,"Error '%c' starting remote node program on %s--\n%s\n",
2523                   statusCode,nodetab_name(pe0),daemon_status2msg(statusCode));
2524           exit(1);
2525     } else if (arg_verbose)
2526           printf("Charmrun> Node program %d started.\n",nodeNumber);
2527   }
2528 }
2529
2530 #if defined(_WIN32) && !defined(__CYGWIN__)
2531 /*Sadly, interprocess communication on Win32 is quite
2532   different, so we can't use Rsh on win32 yet.  
2533   Fall back to the daemon.*/
2534 void start_nodes_rsh() {start_nodes_daemon();}
2535 void finish_nodes(void) {}
2536 void start_one_node_rsh(int rank0no) {}
2537 void finish_one_node(int rank0no) {}
2538
2539 int start_set_node_rsh(int client) {}
2540 void finish_set_nodes(int start, int stop) {}
2541
2542 void envCat(char *dest,LPTSTR oldEnv)
2543 {
2544   char *src=oldEnv;
2545   dest+=strlen(dest);//Advance to end of dest
2546   dest++;//Advance past terminating NULL character
2547   while ((*src)!='\0') {
2548     int adv=strlen(src)+1;//Length of newly-copied string plus NULL
2549     strcpy(dest,src);//Copy another environment string
2550     dest+=adv;//Advance past newly-copied string and NULL
2551     src+=adv;//Ditto for src
2552   }
2553   *dest='\0';//Paste on final terminating NULL character
2554   FreeEnvironmentStrings(oldEnv);
2555 }
2556
2557
2558 /* simple version of charmrun that avoids the rshd or charmd,   */
2559 /* it spawn the node program just on local machine using exec. */
2560 void start_nodes_local(char ** env)
2561 {
2562   int ret, i;
2563   PROCESS_INFORMATION pi;     /* process Information for the process spawned */
2564   char **p;
2565
2566   char environment[10000];/*Doubly-null terminated environment strings*/
2567   char cmdLine[10000];/*Program command line, including executable name*/
2568 /*Command line too long.*/
2569 /*
2570   if (strlen(pparam_argv[1])+strlen(args) > 10000) 
2571         return 0; 
2572 */
2573   strcpy(cmdLine,pparam_argv[1]);
2574   p = pparam_argv+2;
2575   while ((*p)!='\0') {
2576     strcat(cmdLine," ");
2577     strcat(cmdLine,*p);
2578     p++;
2579   }
2580
2581   for (i=0; i<arg_requested_pes; i++)
2582   {
2583     STARTUPINFO si={0};         /* startup info for the process spawned */
2584
2585     sprintf(environment, "NETSTART=%s",  create_netstart(i));
2586     /*Paste all system environment strings */
2587     envCat(environment,GetEnvironmentStrings());
2588   
2589     /* Initialise the security attributes for the process 
2590      to be spawned */
2591     si.cb = sizeof(si);   
2592     if (arg_verbose)
2593       printf("Charmrun> start %d node program on localhost.\n", i);
2594
2595     ret = CreateProcess(NULL,   /* application name */
2596                     cmdLine,    /* command line */
2597                     NULL,/*&sa,*/               /* process SA */
2598                     NULL,/*&sa,*/               /* thread SA */
2599                     FALSE,      /* inherit flag */
2600 #if 1
2601                     CREATE_NEW_PROCESS_GROUP|DETACHED_PROCESS, 
2602 #else
2603                     CREATE_NEW_PROCESS_GROUP|CREATE_NEW_CONSOLE,
2604 #endif
2605                         /* creation flags */
2606                     environment,                /* environment block */
2607                     ".",                        /* working directory */
2608                     &si,                        /* startup info */
2609                     &pi);
2610  
2611     if (ret==0)
2612     {
2613       /*Something went wrong!  Look up the Windows error code*/
2614 /*
2615       int error=GetLastError();
2616       char statusCode=daemon_err2status(error);
2617       fprintf(logfile,"******************* ERROR *****************\n"
2618               "Error in creating process!\n"
2619               "Error code = %ld-- %s\n\n\n", error,
2620               daemon_status2msg(statusCode));
2621           fflush(logfile);
2622 */
2623       int error=GetLastError();
2624       printf("startProcess failed to start process \"%s\" with status: %d\n", pparam_argv[1], error);
2625       exit(1) ;
2626     } 
2627   }
2628 }
2629
2630 #elif CMK_BPROC
2631
2632 int bproc_nodeisup(int node)
2633 {
2634     int status = 0;
2635 #if CMK_BPROC_VERSION < 4
2636     if (bproc_nodestatus(node) == bproc_node_up) status = 1;
2637     if (arg_verbose)
2638       printf("Charmrun> node %d status: %s\n", node, status?"up":"down");
2639 #else
2640     char nodestatus[128];
2641     if (node == -1) {           /* master node is always up */
2642       strcpy(nodestatus, "up");
2643       status = 1;
2644     }
2645     if (bproc_nodestatus(node, nodestatus, 128)) {
2646       if (strcmp(nodestatus, "up")==0) status = 1;
2647     }
2648     if (arg_verbose)
2649         printf("Charmrun> node %d status: %s\n", node, nodestatus);
2650 #endif
2651   return status;
2652 }
2653
2654 /**
2655   ++ppn now is supported in both SMP and non SMP version
2656   in SMP, ++ppn specifies number of threads on each node;
2657   in non-SMP, ++ppn specifies number of processes on each node.
2658 */
2659 void nodetab_init_for_scyld()
2660 {
2661   int maxNodes, i, node, npes, rank;
2662   nodetab_host group;
2663   int tablesize;
2664
2665   tablesize = arg_requested_pes;
2666   maxNodes = bproc_numnodes() + 1;
2667   if (arg_endpe < maxNodes) maxNodes=arg_endpe+1;
2668   if (maxNodes > tablesize) tablesize = maxNodes;
2669   nodetab_table=(nodetab_host**)malloc(tablesize*sizeof(nodetab_host*));
2670   nodetab_rank0_table=(int*)malloc(tablesize*sizeof(int));
2671   nodetab_max=tablesize;
2672
2673   nodetab_reset(&group);
2674
2675   if (arg_ppn==0) arg_ppn=1;
2676 /*
2677 #if CMK_SHARED_VARS_UNAVAILABLE
2678   if (arg_ppn > 1) {
2679     fprintf(stderr,"Warning> Invalid ppn %d in nodelist ignored.\n", arg_ppn);
2680     arg_ppn=1;
2681   }
2682 #endif
2683 */
2684   group.cpus = 1;
2685   group.rank = 0;
2686
2687   /* check which slave node is available from frompe to endpe */
2688   npes = 0;
2689   for (i=-1; i<maxNodes && npes < arg_requested_pes; i++) {
2690     char hostname[256];
2691     if (!bproc_nodeisup(i)) continue;
2692     if (i!= -1 && i<arg_startpe) continue;
2693     if (i==-1 && arg_skipmaster) continue;    /* skip master node -1 */
2694     sprintf(hostname, "%d", i);
2695 #if ! CMK_SHARED_VARS_UNAVAILABLE
2696     if (npes + arg_ppn > arg_requested_pes) group.cpus = arg_requested_pes-npes;
2697     else group.cpus = arg_ppn;
2698 #endif
2699     for (rank = 0; rank<arg_ppn; rank++) {
2700 #if ! CMK_SHARED_VARS_UNAVAILABLE
2701       group.rank = rank;
2702 #endif
2703       nodetab_makehost(hostname, &group);
2704       if (++npes == arg_requested_pes) break;
2705     }   
2706   }
2707   if (nodetab_rank0_size == 0) {
2708     fprintf(stderr, "Charmrun> no slave node available!\n");
2709     exit (1);
2710   }
2711   if (arg_verbose)
2712     printf("Charmrun> There are %d slave nodes available.\n", nodetab_rank0_size-(arg_skipmaster?0:1));
2713
2714   /* expand node table to arg_requested_pes */
2715   if (arg_requested_pes > npes) {
2716     int orig_size = npes;
2717     int node;
2718     int startnode = 0;
2719     if (arg_singlemaster && nodetab_rank0_size > 1 && !arg_skipmaster) 
2720         startnode = arg_ppn;      /* skip -1 */
2721     node = startnode; 
2722     while (npes < arg_requested_pes) {
2723 #if ! CMK_SHARED_VARS_UNAVAILABLE
2724       if (npes+arg_ppn > arg_requested_pes) group.cpus = arg_requested_pes-npes;
2725       else group.cpus = arg_ppn;
2726 #endif
2727       for (rank = 0; rank<arg_ppn; rank++) {
2728 #if ! CMK_SHARED_VARS_UNAVAILABLE
2729         group.rank = rank;
2730 #endif
2731         nodetab_makehost(nodetab_name(node), &group);
2732         if (++node == orig_size) node = startnode;
2733         if (++npes == arg_requested_pes) break;
2734       } 
2735     }
2736   }
2737 }
2738
2739 void start_nodes_scyld(void)
2740 {
2741   char *envp[2];
2742   int i;
2743
2744   envp[0] = (char *)malloc(256);
2745   envp[1] = 0;
2746   for (i=0;i<nodetab_rank0_size;i++)
2747   {
2748     int status = 0;
2749     int pid;
2750     int pe=nodetab_rank0_table[i];
2751     int nodeno = atoi(nodetab_name(pe));
2752
2753     if (arg_verbose)
2754       printf("Charmrun> start node program on slave node: %d.\n", nodeno);
2755     sprintf(envp[0], "NETSTART=%s",  create_netstart(i));
2756     pid = 0;
2757     pid = fork();
2758     if (pid < 0) exit(1);
2759     if (pid == 0)
2760     {
2761       int fd, fd1 = dup(1);
2762       if (!(arg_debug || arg_debug_no_pause)) {   /* debug mode */
2763         if (fd = open("/dev/null", O_RDWR)) {
2764           dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
2765         }
2766       }
2767       if (nodeno == -1) {
2768         status = execve(pparam_argv[1], pparam_argv+1, envp);
2769         dup2(fd1, 1);
2770         printf("execve failed to start process \"%s\" with status: %d\n", pparam_argv[1], status);
2771       }
2772       else {
2773         status = bproc_execmove(nodeno, pparam_argv[1], pparam_argv+1, envp);
2774         dup2(fd1, 1);
2775         printf("bproc_execmove failed to start remote process \"%s\" with status: %d\n", pparam_argv[1], status);
2776       }
2777       kill(getppid(), 9);
2778       exit(1);
2779     }
2780   }
2781   free(envp[0]);
2782 }
2783 void finish_nodes(void) {}
2784
2785 #else
2786 /*Unix systems can use Rsh normally*/
2787 /********** RSH-ONLY CODE *****************************************/
2788 /*                                                                          */
2789 /* Rsh_etc                                                                  */
2790 /*                                                                          */
2791 /* this starts all the node programs.  It executes fully in the background. */
2792 /*                                                                          */
2793 /****************************************************************************/
2794 #include <sys/wait.h>
2795
2796 extern char **environ;
2797 void removeEnv(const char *doomedEnv)
2798 { /*Remove a value from the environment list*/
2799       char **oe, **ie;
2800       oe=ie=environ;
2801       while (*ie != NULL) {
2802         if (0!=strncmp(*ie,doomedEnv,strlen(doomedEnv)))
2803           *oe++ = *ie;
2804         ie++;
2805       }
2806       *oe=NULL;/*NULL-terminate list*/
2807 }
2808
2809 int rsh_fork(int nodeno,const char *startScript)
2810 {
2811   char **rshargv;
2812   int pid;
2813   int num=0;
2814   char *s, *e;
2815
2816   /* figure out size and dynamic allocate */
2817   s=nodetab_shell(nodeno); e=skipstuff(s);
2818   while (*s) {
2819     num++;
2820     s = skipblanks(e); e = skipstuff(s);
2821   }
2822   rshargv = (char **)malloc(sizeof(char *)*(num+6));
2823
2824   num = 0;
2825   s=nodetab_shell(nodeno); e=skipstuff(s);
2826   while (*s) {
2827     rshargv[num++]=substr(s, e);
2828     s = skipblanks(e); e = skipstuff(s);
2829   }
2830
2831   rshargv[num++]=nodetab_name(nodeno);
2832   rshargv[num++]="-l";
2833   rshargv[num++]=nodetab_login(nodeno);
2834   rshargv[num++]="/bin/sh -f";
2835   rshargv[num++]=0;
2836   if (arg_verbose) printf("Charmrun> Starting %s %s -l %s %s\n",nodetab_shell(nodeno), nodetab_name(nodeno),nodetab_login(nodeno), rshargv[num-2]);
2837   
2838   pid = fork();
2839   if (pid < 0) 
2840         { perror("ERROR> starting rsh"); exit(1); }
2841   if (pid == 0)
2842   {/*Child process*/
2843       int i;
2844       int fdScript=open(startScript,O_RDONLY);
2845   /**/  unlink(startScript); /**/
2846       dup2(fdScript,0);/*Open script as standard input*/
2847       //removeEnv("DISPLAY="); /*No DISPLAY disables ssh's slow X11 forwarding*/
2848       for(i=3; i<1024; i++) close(i);
2849       execvp(rshargv[0], rshargv);
2850       fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
2851       exit(1);
2852   }
2853   free(rshargv);
2854   if (arg_verbose)
2855     fprintf(stderr,"Charmrun> remote shell (%s:%d) started\n",
2856         nodetab_name(nodeno),nodeno);
2857   return pid;
2858 }
2859
2860 void fprint_arg(FILE *f,char **argv)
2861 {
2862   while (*argv) { 
2863         fprintf(f," %s",*argv); 
2864         argv++; 
2865   }
2866 }
2867 void rsh_Find(FILE *f,const char *program,const char *dest)
2868 {
2869     fprintf(f,"Find %s\n",program);
2870     fprintf(f,"%s=$loc\n",dest);
2871 }
2872 void rsh_script(FILE *f, int nodeno, int rank0no, char **argv, int restart)
2873 {
2874   char *netstart;
2875   char *arg_nodeprog_r,*arg_currdir_r;
2876   char *dbg=nodetab_debugger(nodeno);
2877   char *host=nodetab_name(nodeno);
2878 #define CLOSE_ALL " < /dev/null 1> /dev/null 2> /dev/null &"
2879
2880   if (arg_mpiexec)
2881         fprintf(f, "#!/bin/sh\n");
2882   fprintf(f, /*Echo: prints out status message*/
2883         "Echo() {\n"
2884         "  echo 'Charmrun remote shell(%s.%d)>' $*\n"
2885         "}\n",host,nodeno);
2886   fprintf(f, /*Exit: exits with return code*/
2887         "Exit() {\n"
2888         "  if [ $1 -ne 0 ]\n"
2889         "  then\n"
2890         "    Echo Exiting with error code $1\n"
2891         "  fi\n"
2892 #if CMK_RSH_KILL /*End by killing ourselves*/
2893         "  sleep 5\n" /*Delay until any error messages are flushed*/
2894         "  kill -9 $$\n"
2895 #else /*Exit normally*/
2896         "  exit $1\n"
2897 #endif
2898         "}\n");
2899   fprintf(f, /*Find: locates a binary program in PATH, sets loc*/
2900         "Find() {\n"
2901         "  loc=''\n"
2902         "  for dir in `echo $PATH | sed -e 's/:/ /g'`\n"
2903         "  do\n"
2904         "    test -f \"$dir/$1\" && loc=\"$dir/$1\"\n"
2905         "  done\n"
2906         "  if [ \"x$loc\" = x ]\n"
2907         "  then\n"
2908         "    Echo $1 not found in your PATH \"($PATH)\"--\n"
2909         "    Echo set your path in your ~/.charmrunrc\n"
2910         "    Exit 1\n"
2911         "  fi\n"
2912         "}\n");
2913   
2914   if (arg_verbose) fprintf(f,"Echo 'remote responding...'\n");
2915   
2916   fprintf(f,"test -f \"$HOME/.charmrunrc\" && . \"$HOME/.charmrunrc\"\n");
2917 /* let's leave DISPLAY untouched and rely on X11 forwarding,
2918    changing DISPLAY to charmrun does not always work if X11 forwarding presents 
2919 */
2920   if (arg_display && !arg_ssh_display)
2921     fprintf(f,"DISPLAY='%s';export DISPLAY\n",arg_display);
2922   netstart = create_netstart(rank0no);
2923   fprintf(f,"NETSTART=\"%s\";export NETSTART\n",netstart);
2924   if (arg_mpiexec)
2925     fprintf(f,"CmiMyNode=$OMPI_COMM_WORLD_RANK; export CmiMyNode\n");
2926   else
2927     fprintf(f,"CmiMyNode='%d'; export CmiMyNode\n",rank0no);
2928   fprintf(f,"CmiMyNodeSize='%d'; export CmiMyNodeSize\n",nodetab_getnodeinfo(rank0no)->cpus);
2929   if (restart || arg_mpiexec)    /* skip fork */
2930     fprintf(f,"CmiMyForks='%d'; export CmiMyForks\n",0);
2931   else
2932     fprintf(f,"CmiMyForks='%d'; export CmiMyForks\n",nodetab_getnodeinfo(rank0no)->forks);
2933   if (arg_mpiexec)
2934     fprintf(f,"CmiNumNodes=$OMPI_COMM_WORLD_SIZE; export CmiNumNodes\n");
2935   else
2936     fprintf(f,"CmiNumNodes='%d'; export CmiNumNodes\n",nodetab_rank0_size);
2937 #if CONVERSE_VERSION_VMI
2938   /* VMI environment variable */
2939   fprintf (f, "VMI_PROCS='%d'; export VMI_PROCS\n", arg_requested_pes);
2940   fprintf (f, "VMI_KEY='charmrun%d'; export VMI_KEY\n", getpid ());
2941   fprintf (f, "VMI_SPECFILE='%s'; export VMI_SPECFILE\n", arg_vmispecfile);
2942 #endif
2943 #ifdef CMK_G95
2944   fprintf(f,"G95_UNBUFFERED_ALL=TRUE; export G95_UNBUFFERED_ALL\n");
2945 #endif
2946 #ifdef CMK_GFORTRAN
2947   fprintf(f,"GFORTRAN_UNBUFFERED_ALL=YES; export GFORTRAN_UNBUFFERED_ALL\n");
2948 #endif
2949 #if CMK_USE_MX
2950   fprintf(f,"MX_MONOTHREAD=1; export MX_MONOTHREAD\n");
2951   /*fprintf(f,"MX_RCACHE=1; export MX_RCACHE\n");*/
2952 #endif
2953 #if CMK_AIX && CMK_SMP
2954   fprintf(f,"MALLOCMULTIHEAP=1; export MALLOCMULTIHEAP\n");
2955 #endif
2956   
2957   if (arg_verbose) {
2958     printf("Charmrun> Sending \"%s\" to client %d.\n", netstart, rank0no);
2959   }
2960   fprintf(f,"PATH=\"$PATH:/bin:/usr/bin:/usr/X/bin:/usr/X11/bin:/usr/local/bin:"
2961         "/usr/X11R6/bin:/usr/openwin/bin\"\n");
2962   
2963   /* find the node-program */
2964   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(nodeno), nodetab_ext(nodeno));
2965   
2966   /* find the current directory, relative version */
2967   arg_currdir_r = pathfix(arg_currdir_a, nodetab_pathfixes(nodeno));
2968
2969   if (arg_verbose) {
2970     printf("Charmrun> find the node program \"%s\" at \"%s\" for %d.\n", arg_nodeprog_r, arg_currdir_r, nodeno);
2971   }
2972
2973   if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
2974     rsh_Find(f,nodetab_xterm(nodeno),"F_XTERM");
2975     if(!arg_ssh_display && !arg_debug_no_xrdb)
2976       rsh_Find(f,"xrdb","F_XRDB");
2977     if(arg_verbose) fprintf(f,"Echo 'using xterm' $F_XTERM\n");
2978   }
2979
2980   if (arg_debug || arg_debug_no_pause)
2981   {/*Look through PATH for debugger*/
2982     rsh_Find(f,dbg,"F_DBG");
2983     if (arg_verbose) fprintf(f,"Echo 'using debugger' $F_DBG\n");
2984   }
2985
2986    if (!arg_ssh_display && !arg_debug_no_xrdb && 
2987        (arg_debug || arg_debug_no_pause || arg_in_xterm)) {
2988      /*    if (arg_debug || arg_debug_no_pause || arg_in_xterm) {*/
2989     fprintf(f,"$F_XRDB -query > /dev/null\n");
2990     fprintf(f,"if test $? != 0\nthen\n");
2991     fprintf(f,"  Echo 'Cannot contact X Server '$DISPLAY'.  You probably'\n");
2992     fprintf(f,"  Echo 'need to run xhost to authorize connections.'\n");
2993     fprintf(f,"  Echo '(See manual for xhost for security issues)'\n");
2994     fprintf(f,"  Echo 'Or try ++batch 1 ++ssh-display to rely on SSH X11 forwarding'\n");
2995     fprintf(f,"  Exit 1\n");
2996     fprintf(f,"fi\n");
2997   }
2998   
2999   fprintf(f,"if test ! -x \"%s\"\nthen\n",arg_nodeprog_r);
3000   fprintf(f,"  Echo 'Cannot locate this node-program: %s'\n",arg_nodeprog_r);
3001   fprintf(f,"  Exit 1\n");
3002   fprintf(f,"fi\n");
3003   
3004   fprintf(f,"cd \"%s\"\n",arg_currdir_r);
3005   fprintf(f,"if test $? = 1\nthen\n");
3006   fprintf(f,"  Echo 'Cannot propagate this current directory:'\n"); 
3007   fprintf(f,"  Echo '%s'\n",arg_currdir_r);
3008   fprintf(f,"  Exit 1\n");
3009   fprintf(f,"fi\n");
3010   
3011   if (strcmp(nodetab_setup(nodeno),"*")) {
3012     fprintf(f,"%s\n",nodetab_setup(nodeno));
3013     fprintf(f,"if test $? = 1\nthen\n");
3014     fprintf(f,"  Echo 'this initialization command failed:'\n");
3015     fprintf(f,"  Echo '\"%s\"'\n",nodetab_setup(nodeno));
3016     fprintf(f,"  Echo 'edit your nodes file to fix it.'\n");
3017     fprintf(f,"  Exit 1\n");
3018     fprintf(f,"fi\n");
3019   }
3020
3021   fprintf(f,"rm -f /tmp/charmrun_err.$$\n");
3022   if(arg_verbose) fprintf(f,"Echo 'starting node-program...'\n");  
3023   /* This is the start of the the run-nodeprogram script */
3024   fprintf(f,"(");
3025   
3026   if (arg_debug || arg_debug_no_pause ) {
3027          if ( strcmp(dbg, "gdb") == 0 || strcmp(dbg, "idb") == 0 ) {
3028            fprintf(f,"cat > /tmp/charmrun_gdb.$$ << END_OF_SCRIPT\n");
3029            if ( strcmp(dbg, "idb") == 0 ) {
3030              fprintf(f,"set \\$cmdset=\"gdb\"\n");
3031            }
3032            fprintf(f,"shell /bin/rm -f /tmp/charmrun_gdb.$$\n");
3033            fprintf(f,"handle SIGPIPE nostop noprint\n");
3034            fprintf(f,"handle SIGWINCH nostop noprint\n");
3035            fprintf(f,"handle SIGWAITING nostop noprint\n");
3036            if(arg_debug_commands)
3037              fprintf(f,"%s\n", arg_debug_commands);
3038            fprintf(f,"set args");
3039            fprint_arg(f,argv);
3040            fprintf(f,"\n");
3041            if (arg_debug_no_pause) fprintf(f,"run\n");
3042            fprintf(f,"END_OF_SCRIPT\n");
3043            if (arg_runscript)
3044              fprintf(f,"\"%s\" ",arg_runscript);
3045            fprintf(f,"$F_XTERM");
3046            fprintf(f," -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
3047            if ( strcmp(dbg, "idb") == 0 )
3048              fprintf(f," -e $F_DBG %s -c /tmp/charmrun_gdb.$$ \n", arg_nodeprog_r);
3049            else 
3050              fprintf(f," -e $F_DBG %s -x /tmp/charmrun_gdb.$$ \n", arg_nodeprog_r);
3051          } else if ( strcmp(dbg, "dbx") == 0 ) {
3052            fprintf(f,"cat > /tmp/charmrun_dbx.$$ << END_OF_SCRIPT\n");
3053            fprintf(f,"sh /bin/rm -f /tmp/charmrun_dbx.$$\n");
3054            fprintf(f,"dbxenv suppress_startup_message 5.0\n");
3055            fprintf(f,"ignore SIGPOLL\n");
3056            fprintf(f,"ignore SIGPIPE\n");
3057            fprintf(f,"ignore SIGWINCH\n");
3058            fprintf(f,"ignore SIGWAITING\n");
3059            if(arg_debug_commands)
3060              fprintf(f,"%s\n", arg_debug_commands);
3061            fprintf(f,"END_OF_SCRIPT\n");
3062            if (arg_runscript)
3063              fprintf(f,"\"%s\" ",arg_runscript);
3064            fprintf(f,"$F_XTERM");
3065            fprintf(f," -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
3066            fprintf(f," -e $F_DBG %s ",arg_debug_no_pause?"-r":"");
3067            if(arg_debug) {
3068               fprintf(f,"-c \'runargs ");
3069               fprint_arg(f,argv);
3070               fprintf(f,"\' ");
3071            }
3072            fprintf(f, "-s/tmp/charmrun_dbx.$$ %s",arg_nodeprog_r);
3073            if(arg_debug_no_pause) 
3074               fprint_arg(f,argv);
3075            fprintf(f,"\n");
3076          } else { 
3077           fprintf(stderr, "Unknown debugger: %s.\n Exiting.\n", 
3078             nodetab_debugger(nodeno));
3079          }
3080   } else if (arg_in_xterm) {
3081     if(arg_verbose)
3082       fprintf(stderr, "Charmrun> node %d: xterm is %s\n", 
3083               nodeno, nodetab_xterm(nodeno));
3084     fprintf(f,"cat > /tmp/charmrun_inx.$$ << END_OF_SCRIPT\n");
3085     fprintf(f,"#!/bin/sh\n");
3086     fprintf(f,"/bin/rm -f /tmp/charmrun_inx.$$\n");
3087     fprintf(f,"%s", arg_nodeprog_r);
3088     fprint_arg(f,argv);
3089     fprintf(f,"\n");
3090     fprintf(f,"echo 'program exited with code '\\$?\n");
3091     fprintf(f,"read eoln\n");
3092     fprintf(f,"END_OF_SCRIPT\n");
3093     fprintf(f,"chmod 700 /tmp/charmrun_inx.$$\n");
3094     if (arg_runscript)
3095        fprintf(f,"\"%s\" ",arg_runscript);
3096     fprintf(f,"$F_XTERM -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
3097     fprintf(f," -sl 5000");
3098     fprintf(f," -e /tmp/charmrun_inx.$$\n");
3099   } else {
3100     if (arg_runscript)
3101        fprintf(f,"\"%s\" ",arg_runscript);
3102     if (arg_no_va_rand) {
3103       if(arg_verbose) fprintf(stderr, "Charmrun> setarch -R is used.\n");
3104       fprintf(f,"setarch `uname -m` -R ");
3105     }
3106     fprintf(f,"\"%s\" ",arg_nodeprog_r);
3107     fprint_arg(f,argv);
3108     if (nodetab_nice(nodeno) != -100) {
3109       if(arg_verbose) fprintf(stderr, "Charmrun> nice -n %d\n", nodetab_nice(nodeno));
3110       fprintf(f," +nice %d ",nodetab_nice(nodeno));
3111     }
3112     fprintf(f,"\nres=$?\n");
3113     /* If shared libraries fail to load, the program dies without
3114        calling charmrun back.  Since we *have* to close down stdin/out/err,
3115        we have to smuggle this failure information out via a file,
3116        /tmp/charmrun_err.<pid> */
3117     fprintf(f,
3118         "if [ $res -eq 127 ]\n"
3119         "then\n"
3120         "  ( \n" /* Re-run, spitting out errors from a subshell: */
3121         "    \"%s\" \n"
3122         "    ldd \"%s\"\n"
3123         "  ) > /tmp/charmrun_err.$$ 2>&1 \n"
3124         "fi\n",arg_nodeprog_r,arg_nodeprog_r);
3125   }
3126   
3127   /* End the node-program subshell. To minimize the number 
3128      of open ports on the front-end, we must close down rsh;
3129      to do this, we have to close stdin, stdout, stderr, and 
3130      run the subshell in the background. */
3131   fprintf(f,")");
3132   fprintf(f,CLOSE_ALL "\n");
3133   
3134   if (arg_verbose) fprintf(f,"Echo 'rsh phase successful.'\n");
3135   fprintf(f, /* Check for startup errors: */
3136      "sleep 1\n"
3137      "if [ -r /tmp/charmrun_err.$$ ]\n"
3138      "then\n"
3139      "  cat /tmp/charmrun_err.$$ \n"
3140      "  rm -f /tmp/charmrun_err.$$ \n"
3141      "  Exit 1\n"
3142      "fi\n");
3143   fprintf(f,"Exit 0\n");
3144 }
3145
3146
3147 /* use the command "size" to get information about the position of the ".data"
3148    and ".bss" segments inside the program memory */
3149 void read_global_segments_size() {
3150   char **rshargv;
3151   int childPid;
3152
3153   /* find the node-program */
3154   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(0), nodetab_ext(0));
3155
3156   rshargv = (char **)malloc(sizeof(char *)*6);
3157   rshargv[0]=nodetab_shell(0);
3158   rshargv[1]=nodetab_name(0);
3159   rshargv[2]="-l";
3160   rshargv[3]=nodetab_login(0);
3161   rshargv[4] = (char *)malloc(sizeof(char)*9+strlen(arg_nodeprog_r));
3162   sprintf(rshargv[4],"size -A %s",arg_nodeprog_r);
3163   rshargv[5]=0;
3164
3165   childPid = fork();
3166   if (childPid < 0) {
3167     perror("ERROR> getting the size of the global variables segments"); exit(1);
3168   } else if (childPid == 0) {
3169     /* child process */
3170     dup2(2, 1);
3171     /*printf("executing: \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",rshargv[0],rshargv[1],rshargv[2],rshargv[3],rshargv[4]);*/
3172     execvp(rshargv[0], rshargv);
3173     fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
3174     exit(1);
3175   } else {
3176     /* else we are in the parent */
3177     free(rshargv[4]);
3178     free(rshargv);
3179     waitpid(childPid, NULL, 0);
3180   }
3181 }
3182
3183 /* open a rsh connection with processor 0 and open a gdb session for info */
3184 void open_gdb_info() {
3185   char **rshargv;
3186   int fdin[2];
3187   int fdout[2];
3188   int fderr[2];
3189   int i;
3190
3191   /* find the node-program */
3192   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(0), nodetab_ext(0));
3193
3194   rshargv = (char **)malloc(sizeof(char *)*6);
3195   rshargv[0]=nodetab_shell(0);
3196   rshargv[1]=nodetab_name(0);
3197   rshargv[2]="-l";
3198   rshargv[3]=nodetab_login(0);
3199   rshargv[4] = (char *)malloc(sizeof(char)*8+strlen(arg_nodeprog_r));
3200   sprintf(rshargv[4],"gdb -q %s",arg_nodeprog_r);
3201   rshargv[5]=0;
3202
3203   pipe(fdin);
3204   pipe(fdout);
3205   pipe(fderr);
3206
3207   gdb_info_pid = fork();
3208   if (gdb_info_pid < 0) {
3209     perror("ERROR> starting info gdb"); exit(1);
3210   } else if (gdb_info_pid == 0) {
3211     /* child process */
3212     close(fdin[1]);
3213     close(fdout[0]);
3214     close(fderr[0]);
3215     printf("executing: \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",rshargv[0],rshargv[1],rshargv[2],rshargv[3],rshargv[4]);
3216     dup2(fdin[0],0);
3217     dup2(fdout[1],1);
3218     dup2(fderr[1],2);
3219     for(i=3; i<1024; i++) close(i);
3220     execvp(rshargv[0], rshargv);
3221     fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
3222     exit(1);
3223   }
3224   /* else we are in the parent */
3225   free(rshargv[4]);
3226   free(rshargv);
3227   gdb_info_std[0] = fdin[1];
3228   gdb_info_std[1] = fdout[0];
3229   gdb_info_std[2] = fderr[0];
3230   close(fdin[0]);
3231   close(fdout[1]);
3232   close(fderr[1]);
3233 }
3234
3235 /* returns pid */
3236 void start_one_node_rsh(int rank0no)
3237 {
3238      int pe=nodetab_rank0_table[rank0no];
3239      FILE *f;
3240      char startScript[200];
3241      sprintf(startScript,"/tmp/charmrun.%d.%d",getpid(),pe);
3242      f=fopen(startScript,"w");
3243      if (f==NULL) {
3244        /* now try current directory */
3245        sprintf(startScript,"charmrun.%d.%d",getpid(),pe);
3246        f=fopen(startScript,"w");
3247        if (f==NULL) {
3248          fprintf(stderr,"Charmrun> Can not write file %s!\n", startScript);
3249          exit(1);
3250        }
3251      }
3252      rsh_script(f,pe,rank0no,arg_argv,0);
3253      fclose(f);
3254      if (!rsh_pids)
3255        rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3256      rsh_pids[rank0no] = rsh_fork(pe,startScript);
3257 }
3258
3259 int start_set_node_rsh(int client) {
3260         /* a search function could be inserted here instead of sequential lookup for more complex node lists (e.g. interleaving) */
3261         int clientgroup;
3262 #if CMK_SMP || defined(_WIN32)
3263         clientgroup=client+1; /* smp already handles this functionality */
3264 #else
3265         if(!arg_scalable_start)
3266                 clientgroup=client+1; /* only launch 1 core per rsh call */
3267         else {
3268                 clientgroup=client;
3269                 do {
3270                         clientgroup++; /* add one more client to group if not greater than nodes and shares the same name as client */
3271                 } while(clientgroup<nodetab_rank0_size&&(!strcmp(nodetab_name(clientgroup),nodetab_name(client))));
3272         }
3273 #endif
3274
3275         nodetab_getnodeinfo(client)->forks=clientgroup-client-1; /* already have 1 process launching */
3276
3277         start_one_node_rsh(client);
3278         return clientgroup-client; /* return number of entries in group */
3279 }
3280
3281 void start_nodes_rsh()
3282 {
3283         int client,clientgroup;
3284         rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3285
3286         client=0;
3287         while(client<nodetab_rank0_size) {
3288                 /* start a group of processes per node */
3289                 clientgroup=start_set_node_rsh(client);
3290                 client+=clientgroup;
3291         }
3292 }
3293
3294 /* for mpiexec, for once calling mpiexec to start on all nodes  */
3295 int rsh_fork_one(const char *startScript)
3296 {
3297   char **rshargv;
3298   int pid;
3299   int num=0;
3300   char npes[128];
3301   char *s, *e;
3302
3303   /* figure out size and dynamic allocate */
3304   s=nodetab_shell(0); e=skipstuff(s);
3305   while (*s) {
3306     num++;
3307     s = skipblanks(e); e = skipstuff(s);
3308   }
3309   rshargv = (char **)malloc(sizeof(char *)*(num+8));
3310
3311   num = 0;
3312   s=nodetab_shell(0); e=skipstuff(s);
3313   while (*s) {
3314     rshargv[num++]=substr(s, e);
3315     s = skipblanks(e); e = skipstuff(s);
3316   }
3317
3318   rshargv[num++]="-np";
3319   sprintf(npes, "%d", nodetab_rank0_size);
3320   rshargv[num++]=npes;
3321   rshargv[num++]=(char*)startScript;
3322   rshargv[num++]=0;
3323   if (arg_verbose) printf("Charmrun> Starting %s %s \n", nodetab_shell(0), startScript);
3324   
3325   pid = fork();
3326   if (pid < 0) 
3327         { perror("ERROR> starting mpiexec"); exit(1); }
3328   if (pid == 0)
3329   {/*Child process*/
3330       int i;
3331   /*  unlink(startScript); */
3332       //removeEnv("DISPLAY="); /*No DISPLAY disables ssh's slow X11 forwarding*/
3333       for(i=3; i<1024; i++) close(i);
3334       execvp(rshargv[0], rshargv);
3335       fprintf(stderr,"Charmrun> Couldn't find mpiexec program '%s'!\n",rshargv[0]);
3336       exit(1);
3337   }
3338   free(rshargv);
3339   if (arg_verbose)
3340     fprintf(stderr,"Charmrun> mpiexec started\n");
3341   return pid;
3342 }
3343
3344 void start_nodes_mpiexec()
3345 {
3346      int i;
3347
3348      FILE *f;
3349      char startScript[200];
3350      sprintf(startScript,"./charmrun.%d",getpid());
3351      f=fopen(startScript,"w");
3352      chmod(startScript, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IROTH);
3353      if (f==NULL) {
3354        /* now try current directory */
3355        sprintf(startScript,"./charmrun.%d",getpid());
3356        f=fopen(startScript,"w");
3357        if (f==NULL) {
3358          fprintf(stderr,"Charmrun> Can not write file %s!\n", startScript);
3359          exit(1);
3360        }
3361      }
3362      rsh_script(f,0,0,arg_argv,0);
3363      fclose(f);
3364      rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3365      rsh_pids[0]=rsh_fork_one(startScript);
3366      for (i=0; i<nodetab_rank0_size; i++)
3367        rsh_pids[i] = 0;   /* skip finish_nodes */
3368 }
3369
3370 void finish_set_nodes(int start, int stop) {
3371         int status,done,i;
3372         char *host;
3373
3374         if (!rsh_pids) return; /*nothing to do*/
3375
3376         done=0;
3377         while(!done) {
3378                 done=1;
3379                 for(i=start;i<stop;i++) { /* check all nodes */
3380                         if(rsh_pids[i]!=0) {
3381                                 done=0; /* we are not finished yet */
3382                                 status=0;
3383                                 waitpid(rsh_pids[i],&status,0); /* check if the process is finished */
3384                                 if(WIFEXITED(status)) {
3385                                         if (!WEXITSTATUS(status)) { /* good */
3386                                                 rsh_pids[i]=0; /* process is finished */
3387                                         } else {
3388                                                 host=nodetab_name(nodetab_rank0_table[i]);
3389                                                 fprintf(stderr,"Charmrun> Error %d returned from rsh (%s:%d)\n",
3390                                                 WEXITSTATUS(status),host,i);
3391                                                 exit(1);
3392                                         } 
3393                                 }
3394                         }
3395                 }
3396         }
3397 }
3398
3399 void finish_nodes()
3400 {
3401         finish_set_nodes(0,nodetab_rank0_size);
3402         free(rsh_pids);
3403 }
3404
3405 void kill_nodes()
3406 {
3407   int rank0no;
3408   if (!rsh_pids) return; /*nothing to do*/
3409   /*Now wait for all the rsh'es to finish*/
3410   for (rank0no=0;rank0no<nodetab_rank0_size;rank0no++)
3411   {
3412      const char *host=nodetab_name(nodetab_rank0_table[rank0no]);
3413      int status=0;
3414      if (arg_verbose) printf("Charmrun> waiting for rsh (%s:%d), pid %d\n",
3415                 host,rank0no,rsh_pids[rank0no]);
3416      kill(rsh_pids[rank0no],9);
3417      waitpid(rsh_pids[rank0no],&status,0); /*<- no zombies*/
3418   }
3419   free(rsh_pids);
3420 }
3421
3422 /* simple version of charmrun that avoids the rshd or charmd,   */
3423 /* it spawn the node program just on local machine using exec. */
3424 void start_nodes_local(char ** env)
3425 {
3426   char **envp;
3427   int envc, rank0no, i;
3428   int extra = 0;
3429
3430 #if CMK_AIX && CMK_SMP
3431   extra = 1;
3432 #endif
3433
3434   /* copy environ and expanded to hold NETSTART */ 
3435   for (envc=0; env[envc]; envc++);
3436   envp = (char **)malloc((envc+2+extra)*sizeof(void *));
3437   for (i=0; i<envc; i++) envp[i] = env[i];
3438   envp[envc] = (char *)malloc(256);
3439 #if CMK_AIX && CMK_SMP
3440   envp[envc+1] = (char *)malloc(256);
3441   sprintf(envp[envc+1], "MALLOCMULTIHEAP=1");
3442 #endif
3443   envp[envc+1+extra] = 0;
3444
3445   for (rank0no=0;rank0no<nodetab_rank0_size;rank0no++)
3446   {
3447     int status = 0;
3448     int pid;
3449     int pe=nodetab_rank0_table[rank0no];
3450
3451     if (arg_verbose)
3452       printf("Charmrun> start %d node program on localhost.\n", pe);
3453     sprintf(envp[envc], "NETSTART=%s",  create_netstart(rank0no));
3454     pid = 0;
3455     pid = fork();
3456     if (pid < 0) exit(1);
3457     if (pid == 0)
3458     {
3459       int fd, fd1 = dup(1);
3460       if (-1!=(fd = open("/dev/null", O_RDWR))) {
3461         dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
3462       }
3463       status = execve(pparam_argv[1], pparam_argv+1, envp);
3464       dup2(fd1, 1);
3465       printf("execve failed to start process \"%s\" with status: %d\n", pparam_argv[1], status);
3466       kill(getppid(), 9);
3467       exit(1);
3468     }
3469   }
3470   free(envp[envc]);
3471   free(envp);
3472 }
3473
3474 #ifdef __FAULT__
3475
3476 int cur_restart_phase = 1;
3477
3478 void refill_nodetab_entry(int crashed_node);
3479 nodetab_host *replacement_host(int pe);
3480
3481 void restart_node(int crashed_node){
3482         int pe = nodetab_rank0_table[crashed_node];
3483         FILE *f;
3484         char startScript[200];
3485         int restart_rsh_pid;
3486         char **restart_argv;
3487         int status=0;
3488         char phase_str[10];
3489         int i;
3490         /** write the startScript file to be sent**/
3491         sprintf(startScript,"/tmp/charmrun.%d.%d",getpid(),pe);
3492         f=fopen(startScript,"w");
3493         
3494         /** add an argument to the argv of the new process
3495         so that the restarting processor knows that it 
3496         is a restarting processor */
3497         i=0;
3498         while(arg_argv[i]!= NULL){
3499                 i++;
3500         }
3501         restart_argv = (char **)malloc(sizeof(char *)*(i+3));
3502         i=0;
3503         while(arg_argv[i]!= NULL){
3504                 restart_argv[i] = arg_argv[i];
3505                 i++;
3506         }
3507         restart_argv[i] = "+restartaftercrash";
3508         sprintf(phase_str,"%d", ++cur_restart_phase);
3509         restart_argv[i+1]=phase_str;
3510         restart_argv[i+2]=NULL;
3511
3512         rsh_script(f,pe,crashed_node,restart_argv,1);
3513         fclose(f);
3514         /** change the nodetable entry of the crashed
3515         processor to connect it to a new one**/
3516         refill_nodetab_entry(crashed_node);
3517         /**start the new processor */
3518         restart_rsh_pid =rsh_fork(pe,startScript);
3519         /**wait for the reply from the new process*/
3520         status=0;
3521         if (arg_debug_no_pause || arg_debug) ;
3522         else {
3523         do{
3524                 waitpid(restart_rsh_pid,&status,0);
3525         }while(!WIFEXITED(status));
3526         if (WEXITSTATUS(status)!=0){
3527          fprintf(stderr,"Charmrun> Error %d returned from new attempted rsh \n",
3528          WEXITSTATUS(status));
3529          exit(1);
3530         }     
3531         }
3532         printf("Charmrun finished launching new process in %fs\n", GetClock()-ftTimer);
3533 }
3534
3535
3536
3537 void refill_nodetab_entry(int crashed_node){
3538         int pe =  nodetab_rank0_table[crashed_node];
3539         nodetab_host *h = nodetab_table[pe];
3540         *h = *(replacement_host(pe));
3541 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
3542 fprintf(stderr,"Charmrun>>> New pe %d is on host %s \n",pe,nodetab_name(pe));
3543 #endif
3544 }
3545
3546 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
3547 nodetab_host *replacement_host(int pe){