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