arch/net/charmrun/charmrun.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * $Source: /cvsroot/charm/src/arch/net/charmrun/charmrun.c,v $
00003  * $Author: gzheng $
00004  * $Date: 2008-06-26 05:17:59 $
00005  * $Revision: 1.138 $
00006  *****************************************************************************/
00007 
00008 #include "converse.h"
00009 
00010 #include "../sockRoutines.h"
00011 #include "../sockRoutines.c"
00012 #include "../ccs-auth.h"
00013 #include "../ccs-auth.c"
00014 #include "../ccs-server.h"
00015 #include "../ccs-server.c"
00016 
00017 #include <stdio.h>
00018 #include <string.h>
00019 #include <ctype.h>
00020 #include <errno.h>
00021 #include <setjmp.h>
00022 #include <stdlib.h>
00023 #include <signal.h>
00024 #include <fcntl.h>
00025 #include <time.h>
00026 #include <assert.h>
00027 #if CMK_BPROC
00028 #include <sys/bproc.h>
00029 #endif
00030 
00031 #if defined(_WIN32) && !defined(__CYGWIN__)
00032 /*Win32 has screwy names for the standard UNIX calls:*/
00033 #define getcwd _getcwd
00034 #define strdup _strdup
00035 #define unlink _unlink
00036 #define open _open
00037 #define fdopen _fdopen
00038 #define ftruncate _chsize
00039 #include <winbase.h>
00040 #include <direct.h>
00041 #include <io.h>
00042 #include <sys/timeb.h>
00043 #include <process.h>
00044 #define DIRSEP "\\"
00045 #define SIGBUS -1  /*These signals don't exist in Win32*/
00046 #define SIGKILL -1
00047 #define SIGQUIT -1
00048 
00049 
00050 #else /*UNIX*/
00051 #include <pwd.h>   /*getcwd*/
00052 #include <unistd.h>
00053 #define DIRSEP "/"
00054 #endif
00055 
00056 #if CMK_RSH_NOT_NEEDED /*No RSH-- use daemon to start node-programs*/
00057 #  define CMK_USE_RSH 0
00058 
00059 #else /*Use RSH to start node-programs*/
00060 #  define CMK_USE_RSH 1
00061 #ifdef __MINGW_H
00062 #  include <rpc.h>
00063 #elif !defined(__CYGWIN__)
00064 #  include <rpc/rpc.h>
00065 #else
00066 #  include <w32api/rpc.h>
00067 #endif
00068 #  if CMK_RSH_IS_A_COMMAND
00069 #    define RSH_CMD "rsh"
00070 #  endif
00071 
00072 #  if CMK_RSH_USE_REMSH
00073 #    define RSH_CMD "remsh"
00074 #  endif
00075 #endif
00076 
00077 #include "daemon.h"
00078 
00079 /*#define DEBUGF(x) printf x*/
00080 #define DEBUGF(x) 
00081 
00082 #ifndef MAXPATHLEN
00083 #define MAXPATHLEN 1024
00084 #endif
00085 
00086 static double ftTimer;
00087                                                                                 
00088 double GetClock(void)
00089 {
00090 #if defined(_WIN32) && !defined(__CYGWIN__)
00091   struct _timeb tv;
00092   _ftime(&tv);
00093   return (tv.time * 1.0 + tv.millitm * 1.0E-3);
00094 #else
00095   struct timeval tv; int ok;
00096   ok = gettimeofday(&tv, NULL);
00097   if (ok<0) { perror("gettimeofday"); exit(1); }
00098   return (tv.tv_sec * 1.0 + tv.tv_usec * 1.0E-6);
00099 #endif
00100 }
00101 
00102 
00103 int probefile(path)
00104     char *path;
00105 {
00106         FILE *f=fopen(path,"r");
00107         if (f==NULL) return 0;
00108         fclose(f);
00109         return 1;
00110 }
00111 
00112 char *mylogin(void)
00113 {
00114 #if defined(_WIN32) && !defined(__CYGWIN__)
00115         static char name[100]={'d','u','n','n','o',0};
00116         int len=100;
00117         GetUserName(name,&len);
00118         return name;
00119 #else /*UNIX*/
00120   struct passwd *self;
00121 
00122   self = getpwuid(getuid());
00123   if (self==0) { return "unknown"; }
00124   return self->pw_name;
00125 #endif
00126 } 
00127 
00128 /**************************************************************************
00129  *
00130  * ping_developers
00131  *
00132  * Sends a single UDP packet to the charm developers notifying them
00133  * that charm is in use.
00134  *
00135  **************************************************************************/
00136 
00137 void ping_developers()
00138 {
00139 #ifdef NOTIFY
00140   char               info[1000];
00141   /*This is the resolved IP address of elegance.cs.uiuc.edu */
00142   skt_ip_t destination_ip=skt_lookup_ip("128.174.241.211");
00143   unsigned int destination_port=6571;
00144   struct sockaddr_in addr=skt_build_addr(destination_ip,destination_port);
00145   SOCKET             skt;
00146   
00147   skt = socket(AF_INET, SOCK_DGRAM, 0);
00148   if (skt == INVALID_SOCKET) return;
00149 
00150   sprintf(info,"%s",mylogin());
00151   
00152   sendto(skt, info, strlen(info), 0, (struct sockaddr *)&addr, sizeof(addr));
00153   skt_close(skt);
00154 #endif /* NOTIFY */
00155 }
00156 
00157 /**************************************************************************
00158  *
00159  * Pathfix : alters a path according to a set of rewrite rules
00160  *
00161  *************************************************************************/
00162 
00163 typedef struct pathfixlist {
00164   char *s1;
00165   char *s2;
00166   struct pathfixlist *next;
00167 } *pathfixlist;
00168 
00169 pathfixlist pathfix_append(char *s1, char *s2, pathfixlist l)
00170 {
00171   pathfixlist pf = (pathfixlist)malloc(sizeof(struct pathfixlist));
00172   pf->s1 = s1;
00173   pf->s2 = s2;
00174   pf->next = l;
00175   return pf;
00176 }
00177 
00178 char *pathfix(char *path, pathfixlist fixes)
00179 {
00180   char buffer[MAXPATHLEN]; pathfixlist l; 
00181   char buf2[MAXPATHLEN]; 
00182   char *offs; int mod, len;
00183   strcpy(buffer,path);
00184   mod = 1;
00185   while (mod) {
00186     mod = 0;
00187     for (l=fixes; l; l=l->next) {
00188       len = strlen(l->s1);
00189       offs = strstr(buffer, l->s1);
00190       if (offs) {
00191         offs[0]=0;
00192         sprintf(buf2,"%s%s%s",buffer,l->s2,offs+len);
00193         strcpy(buffer,buf2);
00194         mod = 1;
00195       }
00196     }
00197   }
00198   return strdup(buffer);
00199 }
00200 
00201 char *pathextfix(char *path, pathfixlist fixes, char *ext)
00202 {
00203   char *newpath = pathfix(path, fixes);
00204   char *ret;
00205   if (ext == NULL) return newpath;
00206   ret = (char *)malloc(strlen(newpath)+strlen(ext)+2);
00207   strcpy(ret, newpath);
00208   strcat(ret, ext);
00209   return ret;
00210 }
00211 
00212 /****************************************************************************
00213  *
00214  * Miscellaneous minor routines.
00215  *
00216  ****************************************************************************/
00217 
00218 int is_quote(char c)
00219 {
00220   return (c=='\'' || c == '"');
00221 }
00222 
00223 void zap_newline(char *s)
00224 {
00225   char *p;
00226   p = s + strlen(s)-1;
00227   if (*p == '\n') *p = '\0';
00228   /* in case of DOS ^m */
00229   p--;
00230   if (*p == '\15') *p = '\0';
00231 }
00232 
00233 /* get substring from lo to hi, remove quote chars */
00234 char *substr(char *lo, char *hi)
00235 {
00236   int len;
00237   char *res;
00238   if (is_quote(*lo)) lo++;
00239   if (is_quote(*(hi-1))) hi--;
00240   len = hi-lo;
00241   res = (char *)malloc(1+len);
00242   memcpy(res, lo, len);
00243   res[len]=0;
00244   return res;
00245 }
00246 
00247 int subeqs(char *lo, char *hi, char *str)
00248 {
00249   int len = strlen(str);
00250   if (hi-lo != len) return 0;
00251   if (memcmp(lo, str, len)) return 0;
00252   return 1;
00253 }
00254 
00255 /* advance pointer over blank characters */
00256 char *skipblanks(char *p)
00257 {
00258   while ((*p==' ')||(*p=='\t')) p++;
00259   return p;
00260 }
00261 
00262 /* advance pointer over nonblank characters and a quoted string */
00263 char *skipstuff(char *p)
00264 {
00265   char quote = 0;
00266   if (*p && (*p=='\'' || *p=='"')) { quote=*p; p++; }
00267   if (quote != 0) {
00268     while (*p&&*p!=quote) p++;
00269     if (*p!=quote) {
00270       fprintf(stderr, "ERROR> Unmatched quote in nodelist file.\n");
00271       exit(1);
00272     }
00273     p++;
00274   }
00275   else
00276     while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
00277   return p;
00278 }
00279 
00280 #if CMK_USE_RSH
00281 char *getenv_rsh()
00282 {
00283   char *e;
00284 
00285   e = getenv("CONV_RSH");
00286   return e ? e : RSH_CMD;
00287 }
00288 #endif
00289 
00290 #if !defined(_WIN32) || defined(__CYGWIN__)
00291 char *getenv_display()
00292 {
00293   static char result[100],ipBuf[200];
00294   char *e, *p;
00295   
00296   e = getenv("DISPLAY");
00297   if (e==0) return NULL;
00298   p = strrchr(e, ':');
00299   if (p==0) return NULL;
00300   if ((e[0]==':')||(strncmp(e,"unix:",5)==0)) {
00301     sprintf(result,"%s:%s",skt_print_ip(ipBuf,skt_my_ip()),p+1);
00302   }
00303   else strcpy(result, e);
00304   return result;
00305 }
00306 char *getenv_display_no_tamper()
00307 {
00308   static char result[100],ipBuf[200];
00309   char *e, *p;
00310   
00311   e = getenv("DISPLAY");
00312   if (e==0) return NULL;
00313   p = strrchr(e, ':');
00314   if (p==0) return NULL;
00315   strcpy(result, e);
00316   return result;
00317 }
00318 
00319 #endif
00320 
00321 /*****************************************************************************
00322  *                                                                           *
00323  * PPARAM - obtaining "program parameters" from the user.                    *
00324  *                                                                           *
00325  *****************************************************************************/
00326 
00327 typedef struct ppdef
00328 {
00329   union {
00330       int *i;
00331       double *r;
00332       char **s;
00333       int *f;
00334     } where;/*Where to store result*/
00335   const char *lname; /*Argument name on command line*/
00336   const char *doc;
00337   char  type; /*One of i, r, s, f.*/
00338   struct ppdef *next;
00339 }
00340 *ppdef;
00341 
00342 static ppdef ppdefs;
00343 
00344 static int     pparam_pos;
00345 static char  **pparam_argv;
00346 static char    pparam_optc='-';
00347 char           pparam_error[100];
00348 
00349 static ppdef pparam_find(lname)
00350     const char *lname;
00351 {
00352   ppdef def;
00353   for (def=ppdefs; def; def=def->next)
00354     if (strcmp(def->lname, lname)==0)
00355       return def;
00356   return 0;
00357 }
00358 
00359 static ppdef pparam_cell(lname)
00360     const char *lname;
00361 {
00362   ppdef def = pparam_find(lname);
00363   if (def) return def;
00364   def = (ppdef)malloc(sizeof(struct ppdef));
00365   def->lname = lname;
00366   def->type  = 's';
00367   def->doc   = "(undocumented)";
00368   def->next  = ppdefs;
00369   ppdefs = def;
00370   return def;
00371 }
00372 
00373 
00374 
00375 void pparam_int(int *where,int defValue,
00376                                    const char *arg,const char *doc)
00377 {
00378   ppdef def = pparam_cell(arg);
00379   def->type  = 'i';
00380   def->where.i = where; *where=defValue;
00381   def->lname=arg;
00382   def->doc=doc;
00383 }
00384 
00385 void pparam_flag(int *where,int defValue,
00386                                    const char *arg,const char *doc)
00387 {
00388   ppdef def = pparam_cell(arg);
00389   def->type  = 'f';
00390   def->where.f = where; *where=defValue;
00391   def->lname=arg;
00392   def->doc=doc;
00393 }
00394 
00395 void pparam_real(double *where,double defValue,
00396                                    const char *arg,const char *doc)
00397 {
00398   ppdef def = pparam_cell(arg);
00399   def->type  = 'r';
00400   def->where.r = where; *where=defValue;
00401   def->lname=arg;
00402   def->doc=doc;
00403 }
00404 void pparam_str(char **where,char *defValue,
00405                                    const char *arg,const char *doc)
00406 {
00407   ppdef def = pparam_cell(arg);
00408   def->type  = 's';
00409   def->where.s = where; *where=defValue;
00410   def->lname=arg;
00411   def->doc=doc;
00412 }
00413 
00414 static int pparam_setdef(def, value)
00415     ppdef def; char *value;
00416 {
00417   char *p;
00418   switch(def->type)
00419     {
00420     case 'i' :
00421       *def->where.i = strtol(value, &p, 10);
00422       if (*p) return -1;
00423       return 0;
00424     case 'r' :
00425       *def->where.r = strtod(value, &p);
00426       if (*p) return -1;
00427       return 0;
00428     case 's' :
00429       *def->where.s = strdup(value);
00430       return 0;
00431     case 'f' :
00432       *def->where.f = strtol(value, &p, 10);
00433       if (*p) return -1;
00434       return 0;
00435     }
00436   return -1;
00437 }
00438 
00439 int pparam_set(lname, value)
00440     char *lname; char *value;
00441 {
00442   ppdef def = pparam_cell(lname);
00443   return pparam_setdef(def, value);
00444 }
00445 
00446 char *pparam_getdef(def)
00447     ppdef def;
00448 {
00449   static char result[100];
00450   switch(def->type)
00451     {
00452     case 'i': sprintf(result,"%d", *def->where.i); return result;
00453     case 'r': sprintf(result,"%f",*def->where.r); return result;
00454     case 's': return *def->where.s?*def->where.s:"";
00455     case 'f': sprintf(result,"%d", *def->where.f); return result;
00456     }
00457   return NULL;
00458 }
00459 
00460 void pparam_printdocs()
00461 {
00462   ppdef def; int len, maxname, maxdoc;
00463   maxname = 0;
00464   maxdoc = 0;
00465   for (def=ppdefs; def; def=def->next)
00466     {
00467       len = strlen(def->lname);
00468       if (len>maxname) maxname=len;
00469       len = strlen(def->doc);
00470       if (len>maxdoc) maxdoc=len;
00471     }
00472   fprintf(stderr,"\n");
00473   fprintf(stderr,"Charmrun Command-line Parameters:\n");
00474   for (def=ppdefs; def; def=def->next)
00475     {
00476       fprintf(stderr,"  %c%c%-*s ",pparam_optc,pparam_optc,maxname,def->lname);
00477       fprintf(stderr,"  %-*s [%s]\n",maxdoc,def->doc,pparam_getdef(def));
00478     }
00479   fprintf(stderr,"\n");
00480 }
00481 
00482 void pparam_delarg(i)
00483     int i;
00484 {
00485   int j;
00486   for (j=i; pparam_argv[j]; j++)
00487     pparam_argv[j]=pparam_argv[j+1];
00488 }
00489 
00490 int pparam_countargs(argv)
00491     char **argv;
00492 {
00493   int argc;
00494   for (argc=0; argv[argc]; argc++);
00495   return argc;
00496 }
00497 
00498 int pparam_parseopt()
00499 {
00500   int ok; ppdef def=NULL;
00501   char *opt = pparam_argv[pparam_pos];
00502   /* handle ++ by skipping to end */
00503   if ((opt[1]=='+')&&(opt[2]==0))
00504     {
00505       pparam_delarg(pparam_pos);
00506       while (pparam_argv[pparam_pos]) pparam_pos++;
00507       return 0;
00508     }
00509   /* handle + by itself - an error */
00510   if (opt[1]==0) 
00511     {
00512       sprintf(pparam_error,"Illegal option +\n");
00513       return -1;
00514     }
00515   /* look up option definition */
00516   if (opt[1]=='+') def = pparam_find(opt+2);
00517   else
00518     {
00519       char name[2];
00520       name[0]=opt[1];
00521       name[1]=0;
00522       def = pparam_find(name);
00523     }
00524   if (def==NULL)
00525   {
00526     if (opt[1]=='+')
00527     {
00528        sprintf(pparam_error,"Option %s not recognized.",opt);
00529        return -1;
00530     } else {
00531            /*Unrecognized + option-- skip it.*/
00532            pparam_pos++;
00533            return 0;
00534         }
00535   }
00536   /* handle flag-options */
00537   if ((def->type=='f')&&(opt[1]!='+')&&(opt[2]))
00538     {
00539       sprintf(pparam_error,"Option %s should not include a value",opt);
00540       return -1;
00541     }
00542   if (def->type=='f')
00543     {
00544       *def->where.f = 1;
00545       pparam_delarg(pparam_pos);
00546       return 0;
00547     }
00548   /* handle non-flag options */
00549   if ((opt[1]=='+')||(opt[2]==0))
00550     {
00551       pparam_delarg(pparam_pos);
00552       opt = pparam_argv[pparam_pos];
00553     }
00554   else opt+=2;
00555   if ((opt == 0)||(opt[0] == 0))
00556     {
00557       sprintf(pparam_error,"%s must be followed by a value.",opt);
00558       return -1;
00559     }
00560   ok = pparam_setdef(def, opt);
00561   pparam_delarg(pparam_pos);
00562   if (ok<0)
00563     {
00564       sprintf(pparam_error,"Illegal value for %s",opt);
00565       return -1;
00566     }
00567   return 0;
00568 }
00569 
00570 int pparam_parsecmd(optchr, argv)
00571     char optchr; char **argv;
00572 {
00573   pparam_error[0]=0;
00574   pparam_argv = argv;
00575   pparam_optc = optchr;
00576   pparam_pos  = 0;
00577   while(1)
00578     {
00579       char *opt = pparam_argv[pparam_pos];
00580       if (opt==0) break;
00581       if (opt[0]!=optchr) pparam_pos++;
00582       else if (pparam_parseopt()<0) return -1;
00583     }
00584   return 0;
00585 }
00586 
00587 /****************************************************************************
00588  * 
00589  * ARG
00590  *
00591  * The following module computes a whole bunch of miscellaneous values, which
00592  * are all constant throughout the program.  Naturally, this includes the
00593  * value of the command-line arguments.
00594  *
00595  *****************************************************************************/
00596 
00597 
00598 #define MAX_NODES 1000
00599 #define MAX_LINE_LENGTH 1000
00600 
00601 char **arg_argv;
00602 int    arg_argc;
00603 
00604 int   arg_requested_pes;
00605 int   arg_timeout;
00606 int   arg_verbose;
00607 char *arg_nodelist;
00608 char *arg_nodegroup;
00609 char *arg_runscript; /* script to run the node-program with */
00610 char *arg_charmrunip;
00611 #if CONVERSE_VERSION_VMI
00612 char *arg_vmispecfile;
00613 #endif
00614 
00615 int   arg_debug;
00616 int   arg_debug_no_pause;
00617 int   arg_charmdebug;
00618 
00619 int   arg_local;        /* start node programs directly by exec on localhost */
00620 int   arg_batch_spawn;  /* control starting node programs, several at a time */
00621 
00622 int   arg_help;         /* print help message */
00623 int   arg_ppn;          /* pes per node */
00624 int   arg_usehostname;
00625 
00626 #if CMK_USE_RSH
00627 int   arg_maxrsh;
00628 char *arg_shell;
00629 int   arg_in_xterm;
00630 char *arg_debugger;
00631 char *arg_xterm;
00632 char *arg_display;
00633 int arg_ssh_display;
00634 char *arg_mylogin;
00635 #endif
00636 
00637 char *arg_nodeprog_a;
00638 char *arg_nodeprog_r;
00639 char *arg_currdir_a;
00640 char *arg_currdir_r;
00641 
00642 int   arg_server;
00643 int   arg_server_port=0;
00644 char *arg_server_auth=NULL;
00645 
00646 #if CMK_BPROC
00647 int   arg_startpe;
00648 int   arg_endpe;
00649 int   arg_singlemaster;
00650 int   arg_skipmaster;
00651 #endif
00652 
00653 void arg_init(int argc, char **argv)
00654 {
00655   static char buf[1024];
00656   
00657   int i, local_def=0;
00658 #if CMK_CHARMRUN_LOCAL
00659   local_def=1; /*++local is the default*/
00660 #endif
00661   
00662   pparam_int(&arg_requested_pes, 1, "p",             "number of processes to create");
00663   pparam_int(&arg_timeout,      60, "timeout",       "seconds to wait per host connection");
00664   pparam_flag(&arg_verbose,      0, "verbose",       "Print diagnostic messages");
00665   pparam_str(&arg_nodelist,      0, "nodelist",      "file containing list of nodes");
00666   pparam_str(&arg_nodegroup,"main", "nodegroup",     "which group of nodes to use");
00667 
00668 #if CMK_CCS_AVAILABLE
00669   pparam_flag(&arg_server,       0, "server",        "Enable client-server (CCS) mode");
00670   pparam_int(&arg_server_port,   0, "server-port",   "Port to listen for CCS requests");
00671   pparam_str(&arg_server_auth,   0, "server-auth",   "CCS Authentication file");
00672 #endif
00673   pparam_flag(&arg_local,       local_def, "local", "Start node programs locally without daemon");
00674   pparam_int(&arg_batch_spawn,   0, "batch", "Rsh several node programs at a time, avoiding overloading charmrun pe");
00675   pparam_flag(&arg_usehostname,  0, "usehostname", "Send nodes our symbolic hostname instead of IP address");
00676   pparam_str(&arg_charmrunip,    0, "useip",      "Use IP address provided for charmrun IP");
00677 #if CMK_USE_RSH
00678   pparam_flag(&arg_debug,         0, "debug",         "Run each node under gdb in an xterm window");
00679   pparam_flag(&arg_debug_no_pause,0, "debug-no-pause","Like debug, except doesn't pause at beginning");
00680 
00681   /* When the ++charmdebug flag is used, charmrun listens from its stdin for
00682      commands, and forwards them to the gdb info program (a child), or to the
00683      processor gdbs. The stderr is redirected to the stdout, so the two streams
00684      are mixed together. The channel for stderr is reused to forward the replies
00685      of gdb back to the java debugger. */
00686 #if !defined(_WIN32)
00687   pparam_flag(&arg_charmdebug,    0, "charmdebug",    "Used only when charmrun is started by charmdebug");
00688 #endif
00689 
00690   pparam_int(&arg_maxrsh,        16, "maxrsh",        "Maximum number of rsh's to run at a time");
00691   pparam_str(&arg_shell,          0, "remote-shell",  "which remote shell to use");
00692   pparam_str(&arg_debugger,       0, "debugger",      "which debugger to use");
00693   pparam_str(&arg_display,        0, "display",       "X Display for xterm");
00694   pparam_flag(&arg_ssh_display,   0, "ssh-display",   "use own X Display for each ssh session");
00695   pparam_flag(&arg_in_xterm,      0, "in-xterm",      "Run each node in an xterm window");
00696   pparam_str(&arg_xterm,          0, "xterm",         "which xterm to use");
00697 #endif
00698 #ifdef CMK_BPROC
00699   /* options for Scyld */
00700   pparam_int(&arg_startpe,   0, "startpe",   "first pe to start job(SCYLD)");
00701   pparam_int(&arg_endpe,  1000000, "endpe",   "last pe to start job(SCYLD)");
00702   pparam_flag(&arg_singlemaster, 0, "singlemaster", "Only assign one process to master node(SCYLD)");
00703   pparam_flag(&arg_skipmaster, 0, "skipmaster", "Donot assign any process to master node(SCYLD)");
00704   if (arg_skipmaster && arg_singlemaster) {
00705     printf("Charmrun> 'singlemaster' is ignored due to 'skipmaster'. \n");
00706     arg_singlemaster = 0;
00707   }
00708   pparam_flag(&arg_debug,         0, "debug",         "turn on more verbose debug print");
00709 #endif
00710 #ifdef CONVERSE_VERSION_VMI
00711   pparam_str (&arg_vmispecfile, 0, "specfile", "device specfile to load (VMI)");
00712 #endif
00713   pparam_str(&arg_runscript,    0, "runscript", "script to run node-program with");
00714   pparam_flag(&arg_help,        0, "help", "print help messages");
00715   pparam_int(&arg_ppn,          0, "ppn",             "number of pes per node");
00716 
00717   if (pparam_parsecmd('+', argv) < 0) {
00718     fprintf(stderr,"ERROR> syntax: %s\n",pparam_error);
00719     pparam_printdocs();
00720     exit(1);
00721   }
00722   
00723   /* Check for (but do *not* remove) the "-?", "-h", or "--help" flags */
00724   for (i=0;argv[i];i++) {
00725         if (0==strcmp(argv[i],"-?") ||
00726             0==strcmp(argv[i],"-h") ||
00727             0==strcmp(argv[i],"--help")) 
00728                 arg_help=1;
00729   }
00730   if (arg_help) {
00731     pparam_printdocs();
00732     /*exit(0);*/
00733   }
00734 
00735   arg_argv = argv+1; /*Skip over charmrun (0) here and program name (1) later*/
00736   arg_argc = pparam_countargs(arg_argv);
00737   if (arg_argc<1) {
00738     fprintf(stderr,"ERROR> You must specify a node-program.\n");
00739     pparam_printdocs();
00740     exit(1);
00741   }
00742   arg_argv++; arg_argc--;
00743 
00744   if (arg_server_port || arg_server_auth) arg_server=1;
00745 
00746   if (arg_debug || arg_debug_no_pause) {
00747         arg_verbose=1;
00748         /*Pass ++debug along to program (used by machine.c)*/
00749         arg_argv[arg_argc++]="++debug";
00750   }
00751 
00752 #ifdef CMK_BPROC
00753   if (arg_local) {
00754     fprintf(stderr,"Warning> ++local cannot be used in bproc version, ignored!\n");
00755     arg_local = 0;
00756   }
00757 #endif
00758 
00759 #if CMK_USE_RSH
00760   /* Find the current value of the CONV_RSH variable */
00761   if(!arg_shell) arg_shell = getenv_rsh();
00762 
00763   /* Find the current value of the DISPLAY variable */
00764   if(!arg_display)
00765     arg_display = getenv_display_no_tamper();
00766   if ((arg_debug || arg_debug_no_pause || arg_in_xterm) && (arg_display==0)) {
00767     fprintf(stderr,"ERROR> DISPLAY must be set to use debugging mode\n");
00768     exit(1);
00769   }
00770   if (arg_debug || arg_debug_no_pause) 
00771     arg_timeout=8*60*60; /* Wait 8 hours for ++debug */
00772 
00773   /* default debugger is gdb */
00774   if(!arg_debugger)
00775     arg_debugger = "gdb" ;
00776   /* default xterm is xterm */
00777   if(!arg_xterm)
00778     arg_xterm = "xterm" ;
00779 
00780   arg_mylogin = mylogin();
00781 #endif
00782 
00783 #if CONVERSE_VERSION_VMI
00784   if (!arg_vmispecfile) {
00785     arg_vmispecfile = getenv ("VMI_SPECFILE");
00786   }
00787 
00788   if (!arg_vmispecfile) {
00789     fprintf (stderr, "ERROR> ++specfile not specified and VMI_SPECFILE not given in environment\n");
00790     exit (1);
00791   }
00792 #endif
00793 
00794   /* find the current directory, absolute version */
00795   getcwd(buf, 1023);
00796   arg_currdir_a = strdup(buf);
00797     
00798   /* find the node-program, absolute version */
00799   arg_nodeprog_r = argv[1];
00800 
00801   if (arg_nodeprog_r[0]=='-' || arg_nodeprog_r[0]=='+') 
00802   { /*If it starts with - or +, it ain't a node program.
00803       Chances are, the user screwed up and passed some unknown flag to charmrun*/
00804      printf("Charmrun does not recognize the flag '%s'.\n",arg_nodeprog_r);
00805      if (arg_nodeprog_r[0]=='+')
00806        printf("Charm++'s flags need to be placed *after* the program name.\n");
00807      pparam_printdocs();
00808      exit(1);
00809   }
00810 
00811 
00812 #if defined(_WIN32) && !defined(__CYGWIN__)
00813   if (argv[1][1]==':' || argv[1][0]=='\\' && argv[1][1]=='\\') { /*E.g.: "C:\foo\bar.exe*/
00814 #else
00815   if (argv[1][0]=='/') { /*E.g.: "\foo\bar"*/
00816 #endif
00817           /*Absolute path to node-program*/
00818     arg_nodeprog_a = argv[1];
00819   } else {
00820     sprintf(buf,"%s%s%s",arg_currdir_a,DIRSEP,arg_nodeprog_r);
00821     arg_nodeprog_a = strdup(buf);
00822   }
00823 }
00824 
00825 /****************************************************************************
00826  *                                                                           
00827  * NODETAB:  The nodes file and nodes table.
00828  *
00829  ****************************************************************************/
00830 
00831 static int portOk = 1;
00832 static const char *nodetab_tempName=NULL;
00833 char *nodetab_file_find()
00834 {
00835   char buffer[MAXPATHLEN];
00836 
00837   /* Find a nodes-file as specified by ++nodelist */
00838   if (arg_nodelist) {
00839     char *path = arg_nodelist;
00840     if (probefile(path)) return strdup(path);
00841     fprintf(stderr,"ERROR> No such nodelist file %s\n",path);
00842     exit(1);
00843   }
00844   /* Find a nodes-file as specified by getenv("NODELIST") */
00845   if (getenv("NODELIST")) {
00846     char *path = getenv("NODELIST");        
00847     if (path && probefile(path)) return strdup(path);
00848     fprintf(stderr,"ERROR> Cannot find nodelist file %s\n",path);
00849     exit(1);
00850   }
00851   /* Find a nodes-file by looking under 'nodelist' in the current directory */
00852   if (probefile("./nodelist")) return strdup("./nodelist");
00853 #if defined(_WIN32) && !defined(__CYGWIN__)
00854   tmpnam(buffer);
00855   nodetab_tempName=strdup(buffer);
00856 #else /*UNIX*/
00857   if (getenv("HOME")) {
00858     sprintf(buffer,"%s/.nodelist",getenv("HOME"));
00859   }
00860 #endif
00861   if (!probefile(buffer)) 
00862   {
00863     /*Create a simple nodelist in the user's home*/
00864     FILE *f=fopen(buffer,"w");
00865     if (f==NULL) {
00866       fprintf(stderr,"ERROR> Cannot create a 'nodelist' file.\n");
00867       exit(1);
00868     }
00869     fprintf(f,"group main\nhost localhost\n");
00870     fclose(f);
00871   }
00872   return strdup(buffer);
00873 }
00874 
00875 typedef struct nodetab_host {
00876   char    *name;  /*Host DNS name*/
00877   skt_ip_t ip; /*IP address of host*/
00878   pathfixlist pathfixes;
00879   char    *ext;  /*FIXME: What the heck is this?  OSL 9/8/00*/
00880   int      cpus;  /* # of physical CPUs*/
00881   int      rank;  /*Rank of this CPU*/
00882   double   speed; /*Relative speed of each CPU*/
00883   int      nice;  /* process priority */
00884   /*These fields are set during node-startup*/
00885   int     dataport;/*UDP port number*/
00886   SOCKET  ctrlfd;/*Connection to control port*/
00887 #if CMK_USE_RSH
00888   char    *shell;  /*Rsh to use*/
00889   char    *debugger ; /*Debugger to use*/
00890   char    *xterm ;  /*Xterm to use*/
00891   char    *login;  /*User login name to use*/
00892   char    *passwd;  /*User login password*/
00893   char    *setup;  /*Commands to execute on login*/
00894 #endif
00895 
00896 #if CMK_USE_IBVERBS
00897         ChInfiAddr *qpData;
00898 #endif
00899 
00900 
00901 } nodetab_host;
00902 
00903 nodetab_host **nodetab_table;
00904 int           nodetab_max;
00905 int           nodetab_size;
00906 int          *nodetab_rank0_table;
00907 int           nodetab_rank0_size;
00908 
00909 void nodetab_reset(nodetab_host *h)
00910 {
00911   h->name="SET_H->NAME";
00912   h->ip=_skt_invalid_ip;
00913   h->pathfixes = 0;
00914   h->ext = NULL;
00915   h->speed = 1.0;
00916   h->cpus = 1;
00917   h->rank = 0;
00918   h->nice=-100;
00919   h->dataport=-1;
00920   h->ctrlfd=-1;
00921 #if CMK_USE_RSH
00922   h->shell = arg_shell;
00923   h->debugger = arg_debugger;
00924   h->xterm = arg_xterm;
00925   h->login = arg_mylogin;
00926   h->passwd = "*";
00927   h->setup = "*";
00928 #endif
00929 }
00930 
00931 void nodetab_add(nodetab_host *h)
00932 {
00933   if (h->rank == 0)
00934     nodetab_rank0_table[nodetab_rank0_size++] = nodetab_size;
00935   nodetab_table[nodetab_size] = (nodetab_host *) malloc(sizeof(nodetab_host));
00936 
00937   if (arg_verbose) {
00938     char ips[200];
00939     skt_print_ip(ips,h->ip);
00940     printf("Charmrun> adding client %d: \"%s\", IP:%s\n", nodetab_size, h->name, ips);
00941   }
00942 
00943   *nodetab_table[nodetab_size++] = *h;
00944 }
00945 
00946 void nodetab_makehost(char *name,nodetab_host *h)
00947 {
00948   h->name=strdup(name);
00949   h->ip = skt_innode_lookup_ip(name);
00950   if (skt_ip_match(h->ip,_skt_invalid_ip)) {
00951 #ifdef CMK_BPROC
00952     /* only the master node is used */
00953     if (!(1 == arg_requested_pes && atoi(name)==-1))
00954 #endif
00955     {
00956     fprintf(stderr,"ERROR> Cannot obtain IP address of %s\n", name);
00957     exit(1);
00958     }
00959   }
00960   if (nodetab_size == nodetab_max) return;
00961   nodetab_add(h);
00962 }
00963 
00964 char *nodetab_args(char *args,nodetab_host *h)
00965 {
00966   if (arg_ppn>0) h->cpus = arg_ppn;
00967   while(*args != 0) {
00968     char *b1 = skipblanks(args), *e1 = skipstuff(b1);
00969     char *b2 = skipblanks(e1), *e2 = skipstuff(b2);
00970     while (*b1=='+') b1++;/*Skip over "++" on parameters*/
00971 #if CMK_USE_RSH
00972     if (subeqs(b1,e1,"login")) h->login = substr(b2,e2);
00973     else if (subeqs(b1,e1,"passwd")) h->passwd = substr(b2,e2);
00974     else if (subeqs(b1,e1,"setup")) h->setup = strdup(b2);
00975     else if (subeqs(b1,e1,"shell")) h->shell = substr(b2,e2);
00976     else if (subeqs(b1,e1,"debugger")) h->debugger = substr(b2,e2);
00977     else if (subeqs(b1,e1,"xterm")) h->xterm = substr(b2,e2);
00978     else 
00979 #endif
00980     if (subeqs(b1,e1,"speed")) h->speed = atof(b2);
00981     else if (subeqs(b1,e1,"cpus")) {
00982       if (arg_ppn==0) h->cpus = atol(b2);       /* ignore if there is ++ppn */
00983     }
00984     else if (subeqs(b1,e1,"pathfix")) {
00985       char *b3 = skipblanks(e2), *e3 = skipstuff(b3);
00986       args = skipblanks(e3);
00987       h->pathfixes=pathfix_append(substr(b2,e2),substr(b3,e3),h->pathfixes);
00988       e2 = e3;       /* for the skipblanks at the end */
00989     } 
00990     else if (subeqs(b1,e1,"ext"))  h->ext = substr(b2,e2);
00991     else if (subeqs(b1,e1,"nice"))  h->nice = atoi(b2);
00992     else return args;
00993     args = skipblanks(e2);
00994   }
00995 #if CMK_SHARED_VARS_UNAVAILABLE
00996   if (h->cpus != 1) {
00997     fprintf(stderr,"Warning> Invalid cpus %d in nodelist ignored.\n", h->cpus);
00998     h->cpus = 1;
00999   }
01000 #endif
01001   return args;
01002 }
01003 
01004 /*  setup nodetab as localhost only */
01005 void nodetab_init_for_local()
01006 {
01007   int tablesize, i, done=0;
01008   nodetab_host group;
01009 
01010   tablesize = arg_requested_pes;
01011   nodetab_table=(nodetab_host**)malloc(tablesize*sizeof(nodetab_host*));
01012   nodetab_rank0_table=(int*)malloc(tablesize*sizeof(int));
01013   nodetab_max=tablesize;
01014 
01015   nodetab_reset(&group);
01016   if (arg_ppn==0) arg_ppn=1;
01017 #if CMK_SHARED_VARS_UNAVAILABLE
01018   if (arg_ppn > 1) {
01019     fprintf(stderr,"Warning> Invalid ppn %d in nodelist ignored.\n", arg_ppn);
01020     arg_ppn=1;
01021   }
01022 #endif
01023   group.cpus = arg_ppn;
01024   i = 0;
01025   while (!done) {
01026     char *hostname = "127.0.0.1";
01027     for (group.rank = 0;