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 communicator open a file;
 11:     all others do nothing.

 13:     Logically Collective

 15:     Input Parameters:
 16: +   comm - the 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 (0), "stderr" or "stdout" may be passed in as the filename

 28:     Fortran Note:
 29:     This routine is not supported in Fortran.

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

 40:   MPI_Comm_rank(comm, &rank);
 41:   if (rank == 0) {
 42:     PetscBool isstdout, isstderr;
 43:     PetscStrcmp(name, "stdout", &isstdout);
 44:     PetscStrcmp(name, "stderr", &isstderr);
 45:     if (isstdout || !name) fd = PETSC_STDOUT;
 46:     else if (isstderr) fd = PETSC_STDERR;
 47:     else {
 48:       PetscBool devnull;
 49:       PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN);
 50:       PetscFixFilename(tname, fname);
 51:       PetscStrbeginswith(fname, "/dev/null", &devnull);
 52:       if (devnull) PetscStrcpy(fname, "/dev/null");
 53:       PetscInfo(0, "Opening file %s\n", fname);
 54:       fd = fopen(fname, mode);
 56:     }
 57:   } else fd = NULL;
 58:   *fp = fd;
 59:   return 0;
 60: }

 62: /*@C
 63:     PetscFClose - Has the first processor in the communicator close a
 64:     file; all others do nothing.

 66:     Logically Collective

 68:     Input Parameters:
 69: +   comm - the communicator
 70: -   fd - the file, opened with PetscFOpen()

 72:    Level: developer

 74:     Fortran Note:
 75:     This routine is not supported in Fortran.

 77: .seealso: `PetscFOpen()`
 78: @*/
 79: PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd)
 80: {
 81:   PetscMPIInt rank;
 82:   int         err;

 84:   MPI_Comm_rank(comm, &rank);
 85:   if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) {
 86:     err = fclose(fd);
 88:   }
 89:   return 0;
 90: }

 92: #if defined(PETSC_HAVE_POPEN)
 93: static char PetscPOpenMachine[128] = "";

 95: /*@C
 96:       PetscPClose - Closes (ends) a program on processor zero run with `PetscPOpen()`

 98:      Collective, but only process 0 runs the command

100:    Input Parameters:
101: +   comm - MPI communicator, only processor zero runs the program
102: -   fp - the file pointer where program input or output may be read or NULL if don't care

104:    Level: intermediate

106:    Note:
107:        Does not work under Windows

109: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()`
110: @*/
111: PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd)
112: {
113:   PetscMPIInt rank;

115:   MPI_Comm_rank(comm, &rank);
116:   if (rank == 0) {
117:     char buf[1024];
118:     while (fgets(buf, 1024, fd))
119:       ; /* wait till it prints everything */
120:     (void)pclose(fd);
121:   }
122:   return 0;
123: }

125: /*@C
126:       PetscPOpen - Runs a program on processor zero and sends either its input or output to
127:           a file.

129:      Logically Collective, but only process 0 runs the command

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

137:    Output Parameter:
138: .   fp - the file pointer where program input or output may be read or NULL if don't care

140:    Level: intermediate

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

145:        Does not work under Windows

147:        If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise
148:        will use the machine running node zero of the communicator

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

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

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

182:     PetscStrcat(command, "\"");
183:   } else {
184:     PetscStrcpy(command, program);
185:   }

187:   PetscStrreplace(comm, command, commandt, 1024);

189:   MPI_Comm_rank(comm, &rank);
190:   if (rank == 0) {
191:     PetscInfo(NULL, "Running command :%s\n", commandt);
193:     if (fp) *fp = fd;
194:   }
195:   return 0;
196: }

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

201:      Logically Collective, but only process 0 runs the command

203:    Input Parameter:
204: .   machine - machine to run command on or NULL for the current machine

206:    Options Database Key:
207: .   -popen_machine <machine> - run the process on this machine

209:    Level: intermediate

211: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()`
212: @*/
213: PetscErrorCode PetscPOpenSetMachine(const char machine[])
214: {
215:   if (machine) {
216:     PetscStrcpy(PetscPOpenMachine, machine);
217:   } else {
218:     PetscPOpenMachine[0] = 0;
219:   }
220:   return 0;
221: }

223: #endif