Beispiel #1
0
int AMUDP_SPMDCustomSpawn(int nproc, int argc, char **argv, char **extra_env) {
  int i;
  char *spawn_cmd = NULL;
  char *spawn_servers = NULL;
  char workerservers[1024];
  char workercmd[1024];
  char nproc_str[10];
  char cwd[1024];
  char cmd[1024];
#if PLATFORM_OS_MSWINDOWS || PLATFORM_OS_CYGWIN
  int spawn_use_create_process;
#endif
  int spawn_route_output;
  int pid;

  if (!AMUDP_SPMDSpawnRunning) {
    AMUDP_Err("Spawn functions should never be run directly - only passed to AMUDP_SPMDStartup()"); 
    return FALSE;
  }

  pid = getpid();

  spawn_cmd = AMUDP_getenv_prefixed_withdefault("CSPAWN_CMD","");
  if (!strlen(spawn_cmd)) {
    AMUDP_Err("You must set the " AMUDP_ENV_PREFIX_STR"_CSPAWN_CMD environment variable to use the custom spawn function"); 
    return FALSE;
  }
  spawn_servers = AMUDP_getenv_prefixed_withdefault("CSPAWN_SERVERS","");
  if (!strlen(spawn_servers)) spawn_servers = NULL;
  spawn_route_output = 
    strcmp(AMUDP_getenv_prefixed_withdefault("CSPAWN_ROUTE_OUTPUT","0"),"0");
#if PLATFORM_OS_MSWINDOWS || PLATFORM_OS_CYGWIN
  spawn_use_create_process =
    strcmp(AMUDP_getenv_prefixed_withdefault("CSPAWN_USE_CREATE_PROCESS","0"),"0");
#endif


  if (spawn_servers) { /* build server list */
    char *p = spawn_servers;
    char servername[255];
    char serverDelim[2];
    strcpy(serverDelim," "); /* default to space */
    workerservers[0] = '\0';
    for (i = 0; i < nproc; i++) { /* check we have enough servers & copy the right number */
      char *end;
      while (*p && strchr(SSH_SERVERS_DELIM_CHARS, *p)) p++;
      end = p + strcspn(p, SSH_SERVERS_DELIM_CHARS);
      if (p == end) {
        printf("Not enough machines in environment variable " AMUDP_ENV_PREFIX_STR"_CSPAWN_SERVERS to satisfy request for (%i).\n"
          "Only (%i) machines available: %s\n", nproc, i, spawn_servers);
        return FALSE;
      }
      strncpy(servername, p, end-p);
      servername[end-p] = '\0';
      if (workerservers[0]) strcat(workerservers, serverDelim);
      if (*end) serverDelim[0] = *end;
      strcat(workerservers, servername);
      if (*end) p = end+1;
      else p = end;
    }
  } 

  sprintf(nproc_str, "%i", nproc);

  if (!getcwd(cwd, 1024)) {
    printf("Error calling getcwd()\n");
    return FALSE;
  }

    /* build the worker command */
  { char temp[2048]; // TODO: allocate dynamically
    temp[0] = '\0';
    if (extra_env && extra_env[0]) {
      const char *envcmd = AMUDP_getenv_prefixed_withdefault("ENV_CMD", "env");
      strcat(temp,envcmd);
      strcat(temp," ");
      for (i=0; extra_env[i]; ++i) {
        strcat(temp,"'");
        strcat(temp,extra_env[i]);
        strcat(temp,"' ");
      }
    }
    for (i = 0; i < argc; i++) {
      AMUDP_assert(argv[i] != NULL);
      char *qarg = quote_for_local(argv[i]);
      strcat(temp,qarg);
      strcat(temp," ");
      AMUDP_free(qarg);
    }
    AMUDP_assert(!argv[i]);

  #if PLATFORM_OS_MSWINDOWS || PLATFORM_OS_CYGWIN
    strcpy(workercmd, temp);
  #else
    sprintf(workercmd, "/bin/sh -c \"%s%s\" || ( echo \"spawn failed.\" ; kill %i ) ",
      (AMUDP_SilentMode?"":"echo connected to `uname -n`... ; "),
      temp, pid
    );
  #endif
  }

  strcpy(cmd, spawn_cmd);
  { char tmp[1024];
    char *p = cmd;
    while ((p = strchr(p, '%'))) {
      const char *replacement;
      switch (*(p+1)) {
        case 'M': case 'm': 
          if (!spawn_servers) { /* user failed to provide servers and now is asking for them */
            AMUDP_Err("You must set the " AMUDP_ENV_PREFIX_STR"_CSPAWN_SERVERS environment "
                       "variable to use the %%M option in " AMUDP_ENV_PREFIX_STR"_CSPAWN_CMD");
          }
          replacement = workerservers; 
          break;
        case 'N': case 'n': replacement = nproc_str; break;
        case 'C': case 'c': replacement = workercmd; break;
        case 'D': case 'd': replacement = cwd; break;
        case 'P': case 'p': replacement = argv[0]; break;
        case '%': replacement = "%"; break;
        default: replacement = "";
      }
      strcpy(tmp, cmd);
      tmp[p-cmd] = '\0';
      strcat(tmp, replacement);
      if (*(p+1)) strcat(tmp, p+2);
      p += strlen(replacement);
      strcpy(cmd, tmp);
    }
  }

  AMUDP_SPMDRedirectStdsockets = spawn_route_output; 

  {
  #if !PLATFORM_OS_MSWINDOWS
    int forkRet;
    forkRet = fork(); /* fork a new process to hold cmd master */

    if (forkRet == -1) {
      perror("fork");
      return FALSE;
    }
    else if (forkRet != 0) {
      return TRUE;  
    }
    else 
  #endif
    {  /*  this is the child - exec the new process */
      if (!AMUDP_SilentMode) 
        printf("system(%s)\n", cmd); fflush(stdout);
    #if PLATFORM_OS_MSWINDOWS || PLATFORM_OS_CYGWIN
      if (spawn_use_create_process) {
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        DWORD code;

        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        si.hStdError = GetStdHandle(STD_OUTPUT_HANDLE); 
        si.hStdOutput = GetStdHandle(STD_ERROR_HANDLE); 
        si.dwFlags |= STARTF_USESTDHANDLES;

        if (   TRUE != CreateProcess(0, strdup(cmd), 0, 0, TRUE, 0, 0, 0, &si, &pi)
            || WAIT_FAILED == WaitForSingleObject(pi.hProcess, INFINITE)
            || 0 == GetExitCodeProcess(pi.hProcess, &code)
            || 0 != code)
          AMUDP_FatalErr("Failed while calling CreateProcess() with custom spawn command:\n%s", cmd);
      } else
    #endif
      if (system(cmd) != 0)
         AMUDP_FatalErr("Failed while calling system() with custom spawn command:\n%s", cmd);
      exit(0);
    }
  }

  return TRUE;
}
Beispiel #2
0
/* ------------------------------------------------------------------------------------ 
 *  spawn jobs on local machine
 * ------------------------------------------------------------------------------------ */
extern int AMUDP_SPMDLocalSpawn(int nproc, int argc, char **argv, char **extra_env) {
  /* just a simple fork/exec */
  int i;

  if (!AMUDP_SPMDSpawnRunning) {
    AMUDP_Err("Spawn functions should never be run directly - only passed to AMUDP_SPMDStartup()"); 
    return FALSE;
  }

  /* Temporarily assume values from extra_env[] (which we modify in-place) */
  char **save_env = NULL;
  int envc = 0;
  if (extra_env && extra_env[0]) {
    for (envc=0; extra_env[envc]; ++envc) {/*empty*/}
    save_env = (char **)AMUDP_malloc(sizeof(char *)*envc);
    for (i=0;i<envc;++i) {
      char *var = extra_env[i];
      char *delim = strchr(var,'=');
      AMUDP_assert(delim);
      *delim = '\0';
      save_env[i] = getenv(var);
      setenv(var,delim+1,1);
    }
  }

  for (i = 0; i < nproc; i++) {
    #if PLATFORM_OS_MSWINDOWS && !PLATFORM_OS_CYGWIN
      if (_spawnv(_P_NOWAIT, argv[0], argv) == -1)
        AMUDP_FatalErr("failed _spawnv()");
    #elif PLATFORM_ARCH_CRAYX1
      { char **nargv = (char **)AMUDP_malloc(sizeof(char *)*(argc+2));
        nargv[0] = argv[0];
        memcpy(nargv+1,argv,argc*sizeof(char *));
        nargv[argc+1] = NULL;
        if (execsp(nargv, environ, NULL) == -1)
          AMUDP_FatalErr("failed execsp()");
      }
    #else
      int forkRet = fork();
      if (forkRet == -1) {
        perror("fork");
        return FALSE;
      } else if (forkRet != 0) continue;  /*  this is the parent, will go back to the top of the loop */
      else {  /*  this is the child - exec the new process */
        /*  could close some resources here (like AMUDP_SPMDListenSocket) but not strictly necessary */

        #if 0
          /*  put new process in a separate process group */
          if (setsid() == -1) perror("setsid"); 
        #endif

        /*  exec the program, with the given arguments  */
        execv(argv[0], argv);

        /*  if execv returns, an error occurred */
        perror("execv");
        _exit(1); /*  use _exit() to prevent corrupting parent's io buffers */
      } /*  child */
    #endif
  }

  /* Restore saved environment var(s) */
  for (i=0;i<envc;++i) {
    char *name = extra_env[i];
    if (save_env[i]) {
      setenv(name,save_env[i],1);
    } else {
      unsetenv(name);
    }
    /* Revert our in-place modification of extra_env[]: */
    name[strlen(name)] = '=';
  }
  AMUDP_free(save_env);

  return TRUE;
}
Beispiel #3
0
int AMUDP_SPMDSshSpawn(int nproc, int argc, char **argv, char **extra_env) {
  int i;
  const char *ssh_servers;
  const char *ssh_cmd;
  const char *ssh_options;
  const char *ssh_remote_path;
  char cwd[1024];
  const char *p;
  char *cmd1, *cmd2;
  size_t cmd1_sz, cmd2_sz;
  int pid;

  if (!AMUDP_SPMDSpawnRunning) {
    AMUDP_Err("Spawn functions should never be run directly - only passed to AMUDP_SPMDStartup()"); 
    return FALSE;
  }

  pid = getpid();

  ssh_servers = AMUDP_getenv_prefixed_withdefault("SSH_SERVERS","");
  if (!strlen(ssh_servers)) {
    printf("Environment variable SSH_SERVERS is missing.\n");
    return FALSE;
  }


  if (!getcwd(cwd, 1024)) {
    printf("Error calling getcwd()\n");
    return FALSE;
  }
  ssh_remote_path = quote_for_local(AMUDP_getenv_prefixed_withdefault("SSH_REMOTE_PATH", cwd));
  ssh_cmd = AMUDP_getenv_prefixed_withdefault("SSH_CMD", "ssh");

  int isOpenSSH = 0; /* figure out if we're using OpenSSH */
  { char cmdtmp[1024];
    sprintf(cmdtmp,"%s -v 2>&1 | grep OpenSSH", ssh_cmd);
    FILE *pop = popen(cmdtmp,"r");
    while (!feof(pop) && !ferror(pop)) {
      int next = fgetc(pop);
      if (next != EOF && !isspace(next)) {
        isOpenSSH = 1;
        break;
      }
    }
    pclose(pop);
  }

  ssh_options = AMUDP_getenv_prefixed_withdefault("SSH_OPTIONS","");

  p = ssh_servers;
  for (i = 0; i < nproc; i++) { /* check we have enough servers */
    const char *end;
    while (*p && strchr(SSH_SERVERS_DELIM_CHARS, *p)) p++;
    end = p + strcspn(p, SSH_SERVERS_DELIM_CHARS);
    if (p == end) {
      printf("Not enough machines in environment variable SSH_SERVERS to satisfy request for (%i).\n"
       "Only (%i) machines available: %s\n", nproc, i, ssh_servers);
      return FALSE;
    }
    if (*end) p = end+1;
    else p = end;
  } 

  const char *envcmd = AMUDP_getenv_prefixed_withdefault("ENV_CMD", "env");

  cmd1_sz = 1; /* terminating nul */
  if (extra_env && extra_env[0]) {
    cmd1_sz += 1 + strlen(envcmd); // "env "
    for (i=0; extra_env[i]; ++i) {
      cmd1_sz += strlen(extra_env[i]) + 3; // "'%s' "
    }
  }
  char **quoted_args = (char**)AMUDP_malloc(argc * sizeof(char*));
  for (i = 0; i < argc; i++) {
    AMUDP_assert(argv[i]);
    quoted_args[i] = quote_for_local(argv[i]);
    cmd1_sz += strlen(quoted_args[i]) + 1; // +1 for trailing space
  }
  cmd1 = (char *)AMUDP_malloc(cmd1_sz);
  { char *tmp = cmd1;
    if (extra_env && extra_env[0]) {
      tmp += sprintf(tmp, "%s ", envcmd);
      for (i=0; extra_env[i]; ++i) {
        tmp += sprintf(tmp, "'%s' ", extra_env[i]);
      }
    }
    for (i = 0; i < argc; i++) {
      AMUDP_assert(quoted_args[i]);
      tmp += sprintf(tmp, "%s ", quoted_args[i]);
      AMUDP_free(quoted_args[i]);
    }
    AMUDP_free(quoted_args);
    AMUDP_assert(!argv[i]);
    *tmp = '\0';
    AMUDP_assert(strlen(cmd1) == cmd1_sz - 1);
  }
  cmd2_sz = cmd1_sz + strlen(ssh_remote_path) + 1024; /* estimated */
  cmd2 =  (char *)AMUDP_malloc(cmd2_sz);

  p = ssh_servers;
  for (i = 0; i < nproc; i++) {
    char ssh_server[255];
    const char *end;
    while (*p && strchr(SSH_SERVERS_DELIM_CHARS, *p)) p++;
    end = p + strcspn(p, SSH_SERVERS_DELIM_CHARS);
    AMUDP_assert(p != end);

    strncpy(ssh_server, p, (end-p));
    ssh_server[end-p] = '\0'; 

    /* build the ssh command */
    snprintf(cmd2, cmd2_sz, "%s %s %s %s %s %s \" %s cd %s ; %s\" "
      " || ( echo \"connection to %s failed.\" ; kill %i ) "
      "%s", 
      ssh_cmd,

      (isOpenSSH?"-f":""),    /* go into background and nullify stdin */

      #if SSH_SUPRESSNEWKEYPROMPT
        (isOpenSSH?"-o 'StrictHostKeyChecking no'":""),
      #else 
        "",
      #endif

      #if SSH_PREVENTRSHFALLBACK
        (isOpenSSH?"-o 'FallBackToRsh no'":""),
      #else 
        "",
      #endif

      ssh_options, ssh_server, 
      
      (AMUDP_SilentMode?"":"echo connected to \\$HOST... ;"),

      ssh_remote_path, cmd1, ssh_server, pid,

      #if SSH_PARALLELSPAWN
        "&"
      #else
        ""
      #endif
    );

    if (!AMUDP_SilentMode) 
      printf("system(%s)\n", cmd2); fflush(stdout);
    if (system(cmd2) == -1) {
      printf("Failed to call system() to spawn");
      AMUDP_free(cmd1);
      AMUDP_free(cmd2);
      return FALSE;
    }
    if (*end) p = end+1;
    else p = end;
  } 

  AMUDP_free(cmd1);
  AMUDP_free(cmd2);
  return TRUE;
}
Beispiel #4
0
int AMUDP_SPMDSshSpawn(int nproc, int argc, char **argv) {
  int i;
  const char *ssh_servers;
  const char *ssh_cmd;
  const char *ssh_options;
  const char *ssh_remote_path;
  char cwd[1024];
  const char *p;
  char cmd1[1024],cmd2[1024];
  int pid;

  if (!AMUDP_SPMDSpawnRunning) {
    AMUDP_Err("Spawn functions should never be run directly - only passed to AMUDP_SPMDStartup()"); 
    return FALSE;
  }

  pid = getpid();

  ssh_servers = AMUDP_getenv_prefixed_withdefault("SSH_SERVERS","");
  if (!strlen(ssh_servers)) {
    printf("Environment variable SSH_SERVERS is missing.\n");
    return FALSE;
  }


  if (!getcwd(cwd, 1024)) {
    printf("Error calling getcwd()\n");
    return FALSE;
  }
  ssh_remote_path = AMUDP_getenv_prefixed_withdefault("SSH_REMOTE_PATH", cwd);
  ssh_cmd = AMUDP_getenv_prefixed_withdefault("SSH_CMD", "ssh");

  int isOpenSSH = 0; /* figure out if we're using OpenSSH */
  { char cmdtmp[1024];
    sprintf(cmdtmp,"%s -v 2>&1 | grep OpenSSH", ssh_cmd);
    FILE *pop = popen(cmdtmp,"r");
    while (!feof(pop) && !ferror(pop)) {
      int next = fgetc(pop);
      if (next != EOF && !isspace(next)) {
        isOpenSSH = 1;
        break;
      }
    }
    pclose(pop);
  }

  ssh_options = AMUDP_getenv_prefixed_withdefault("SSH_OPTIONS","");

  cmd1[0] = '\0';
  for (i = 0; i < argc; i++) {
    AMUDP_assert(argv[i] != NULL);
    strcat(cmd1,"'");
    strcat(cmd1,argv[i]);
    strcat(cmd1,"' ");
  }
  AMUDP_assert(!argv[i]);

  p = ssh_servers;
  for (i = 0; i < nproc; i++) { /* check we have enough servers */
    const char *end;
    while (*p && strchr(SSH_SERVERS_DELIM_CHARS, *p)) p++;
    end = p + strcspn(p, SSH_SERVERS_DELIM_CHARS);
    if (p == end) {
      printf("Not enough machines in environment variable SSH_SERVERS to satisfy request for (%i).\n"
       "Only (%i) machines available: %s\n", nproc, i, ssh_servers);
      return FALSE;
    }
    if (*end) p = end+1;
    else p = end;
  } 

  p = ssh_servers;
  for (i = 0; i < nproc; i++) {
    char ssh_server[255];
    const char *end;
    while (*p && strchr(SSH_SERVERS_DELIM_CHARS, *p)) p++;
    end = p + strcspn(p, SSH_SERVERS_DELIM_CHARS);
    AMUDP_assert(p != end);

    strncpy(ssh_server, p, (end-p));
    ssh_server[end-p] = '\0'; 

    /* build the ssh command */
    sprintf(cmd2, "%s %s %s %s %s %s \" %s cd '%s' ; %s\" "
      " || ( echo \"connection to %s failed.\" ; kill %i ) "
      "%s", 
      ssh_cmd,

      (isOpenSSH?"-f":""),    /* go into background and nullify stdin */

      #if SSH_SUPRESSNEWKEYPROMPT
        (isOpenSSH?"-o 'StrictHostKeyChecking no'":""),
      #else 
        "",
      #endif

      #if SSH_PREVENTRSHFALLBACK
        (isOpenSSH?"-o 'FallBackToRsh no'":""),
      #else 
        "",
      #endif

      ssh_options, ssh_server, 
      
      (AMUDP_SilentMode?"":"echo connected to \\$HOST... ;"),

      ssh_remote_path, cmd1, ssh_server, pid,

      #if SSH_PARALLELSPAWN
        "&"
      #else
        ""
      #endif
    );

    if (!AMUDP_SilentMode) 
      printf("system(%s)\n", cmd2); fflush(stdout);
    if (system(cmd2) == -1) {
      printf("Failed to call system() to spawn");
      return FALSE;
    }
    if (*end) p = end+1;
    else p = end;
  } 

  return TRUE;
}