Actual source code: mpiuopen.c

      1: #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for popen() */
      2: /*
      3:       Some PETSc utility routines to add simple parallel IO capabilities
      4: */
      5: #include <petscsys.h>
      6: #include <petsc/private/logimpl.h>
      7: #include <errno.h>

      9: /*@C
     10:   PetscFOpen - Has the first process in the MPI communicator open a file;
     11:   all others do nothing.

     13:   Logically Collective

     15:   Input Parameters:
     16: + comm - the MPI communicator
     17: . name - the filename
     18: - mode - the mode for `fopen()`, usually "w"

     20:   Output Parameter:
     21: . fp - the file pointer

     23:   Level: developer

     25:   Note:
     26:   `NULL`, "stderr" or "stdout" may be passed in as the filename

     28: .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`,
     29:           `PetscFPrintf()`
     30: @*/
     31: PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp)
     32: {
     33:   PetscMPIInt rank;
     34:   FILE       *fd;
     35:   char        fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN];

     37:   PetscFunctionBegin;
     38:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
     39:   if (rank == 0) {
     40:     PetscBool isstdout, isstderr;
     41:     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
     42:     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
     43:     if (isstdout || !name) fd = PETSC_STDOUT;
     44:     else if (isstderr) fd = PETSC_STDERR;
     45:     else {
     46:       PetscBool devnull = PETSC_FALSE;
     47:       PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN));
     48:       PetscCall(PetscFixFilename(tname, fname));
     49:       PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull));
     50:       if (devnull) PetscCall(PetscStrncpy(fname, "/dev/null", sizeof(fname)));
     51:       PetscCall(PetscInfo(0, "Opening file %s\n", fname));
     52:       fd = fopen(fname, mode);
     53:       PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname);
     54:     }
     55:   } else fd = NULL;
     56:   *fp = fd;
     57:   PetscFunctionReturn(PETSC_SUCCESS);
     58: }

     60: /*@C
     61:   PetscFClose - Has MPI rank 0 in the communicator close a
     62:   file (usually obtained with `PetscFOpen()`; all others do nothing.

     64:   Logically Collective

     66:   Input Parameters:
     67: + comm - the MPI communicator
     68: - fd   - the file, opened with `PetscFOpen()`

     70:   Level: developer

     72: .seealso: `PetscFOpen()`
     73: @*/
     74: PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd)
     75: {
     76:   PetscMPIInt rank;
     77:   int         err;

     79:   PetscFunctionBegin;
     80:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
     81:   if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) {
     82:     err = fclose(fd);
     83:     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
     84:   }
     85:   PetscFunctionReturn(PETSC_SUCCESS);
     86: }

     88: static char PetscPOpenMachine[128] = "";

     90: /*@C
     91:   PetscPClose - Closes (ends) a program on MPI rank 0 run with `PetscPOpen()`

     93:   Collective, but only MPI rank 0 does anything

     95:   Input Parameters:
     96: + comm - MPI communicator, only rank 0 performs the close
     97: - fd   - the file pointer where program input or output may be read or `NULL` if don't care

     99:   Level: intermediate

    101:   Note:
    102:   Does not work under Microsoft Windows

    104: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()`
    105: @*/
    106: PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd)
    107: {
    108: #if defined(PETSC_HAVE_POPEN)
    109:   PetscMPIInt rank;
    110: #endif

    112:   PetscFunctionBegin;
    113: #if defined(PETSC_HAVE_POPEN)
    114:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
    115:   if (rank == 0) {
    116:     char buf[1024];
    117:     while (fgets(buf, 1024, fd)); /* wait till it prints everything */
    118:     (void)pclose(fd);
    119:   }
    120: #else
    121:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "pclose() - routine is unavailable.");
    122: #endif
    123:   PetscFunctionReturn(PETSC_SUCCESS);
    124: }

    126: /*@C
    127:   PetscPOpen - Runs a program on MPI rank 0 and sends either its input or output to
    128:   a file.

    130:   Logically Collective, but only MPI rank 0 runs the command

    132:   Input Parameters:
    133: + comm    - MPI communicator, only processor zero runs the program
    134: . machine - machine to run command on or `NULL`, or a string with 0 in first location
    135: . program - name of program to run
    136: - mode    - either "r" or "w"

    138:   Output Parameter:
    139: . fp - the file pointer where program input or output may be read or `NULL` if results are not needed

    141:   Level: intermediate

    143:   Notes:
    144:   Use `PetscPClose()` to close the file pointer when you are finished with it

    146:   Does not work under Microsoft Windows

    148:   If machine is not provided will use the value set with `PetscPOpenSetMachine()` if that was provided, otherwise
    149:   will use the machine running MPI rank 0 of the communicator

    151:   The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these
    152:   will be replaced with relevant values.

    154: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()`
    155: @*/
    156: PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp)
    157: {
    158: #if defined(PETSC_HAVE_POPEN)
    159:   PetscMPIInt rank;
    160:   size_t      i, len, cnt;
    161:   char        commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN];
    162:   FILE       *fd;
    163: #endif

    165:   PetscFunctionBegin;
    166: #if defined(PETSC_HAVE_POPEN)
    167:   /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */
    168:   if (PetscPOpenMachine[0] || (machine && machine[0])) {
    169:     PetscCall(PetscStrncpy(command, "ssh ", sizeof(command)));
    170:     if (PetscPOpenMachine[0]) {
    171:       PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command)));
    172:     } else {
    173:       PetscCall(PetscStrlcat(command, machine, sizeof(command)));
    174:     }
    175:     PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command)));
    176:     /*
    177:         Copy program into command but protect the " with a \ in front of it
    178:     */
    179:     PetscCall(PetscStrlen(command, &cnt));
    180:     PetscCall(PetscStrlen(program, &len));
    181:     for (i = 0; i < len; i++) {
    182:       if (program[i] == '\"') command[cnt++] = '\\';
    183:       command[cnt++] = program[i];
    184:     }
    185:     command[cnt] = 0;

    187:     PetscCall(PetscStrlcat(command, "\"", sizeof(command)));
    188:   } else {
    189:     PetscCall(PetscStrncpy(command, program, sizeof(command)));
    190:   }

    192:   PetscCall(PetscStrreplace(comm, command, commandt, 1024));

    194:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
    195:   if (rank == 0) {
    196:     PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt));
    197:     PetscCheck(fd = popen(commandt, mode), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt);
    198:     if (fp) *fp = fd;
    199:   }
    200: #else
    201:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "popen() - system routine is unavailable.");
    202: #endif
    203:   PetscFunctionReturn(PETSC_SUCCESS);
    204: }

    206: /*@
    207:   PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on

    209:   Logically Collective, but only the MPI process with rank 0 runs the command

    211:   Input Parameter:
    212: . machine - machine to run command on or `NULL` for the current machine

    214:   Options Database Key:
    215: . -popen_machine <machine> - run the process on this machine

    217:   Level: intermediate

    219: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()`
    220: @*/
    221: PetscErrorCode PetscPOpenSetMachine(const char machine[])
    222: {
    223:   PetscFunctionBegin;
    224:   if (machine) {
    225:     PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine)));
    226:   } else {
    227:     PetscPOpenMachine[0] = 0;
    228:   }
    229:   PetscFunctionReturn(PETSC_SUCCESS);
    230: }