xref: /petsc/src/sys/fileio/mpiuopen.c (revision 57508ece14a6b1339c0bbf016ecd72f673a062b0)
10039db0dSBarry Smith #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for popen() */
2e5c89e4eSSatish Balay /*
34c500f23SPierre Jolivet       Some PETSc utility routines to add simple parallel IO capabilities
4e5c89e4eSSatish Balay */
5c6db04a5SJed Brown #include <petscsys.h>
6cc4c1da9SBarry Smith #include <petsc/private/logimpl.h> /*I   "petscsys.h"    I*/
7d0286d30SJed Brown #include <errno.h>
8d0286d30SJed Brown 
9e5c89e4eSSatish Balay /*@C
1021532e8aSBarry Smith   PetscFOpen - Has the first process in the MPI communicator open a file;
11e5c89e4eSSatish Balay   all others do nothing.
12e5c89e4eSSatish Balay 
13cc4c1da9SBarry Smith   Logically Collective
14e5c89e4eSSatish Balay 
15e5c89e4eSSatish Balay   Input Parameters:
1621532e8aSBarry Smith + comm - the MPI communicator
17e5c89e4eSSatish Balay . name - the filename
18bfbbc7b7SBarry Smith - mode - the mode for `fopen()`, usually "w"
19e5c89e4eSSatish Balay 
20e5c89e4eSSatish Balay   Output Parameter:
21e5c89e4eSSatish Balay . fp - the file pointer
22e5c89e4eSSatish Balay 
23e5c89e4eSSatish Balay   Level: developer
24e5c89e4eSSatish Balay 
25811af0c4SBarry Smith   Note:
26bfbbc7b7SBarry Smith   `NULL`, "stderr" or "stdout" may be passed in as the filename
27e5c89e4eSSatish Balay 
28db781477SPatrick Sanan .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`,
29db781477SPatrick Sanan           `PetscFPrintf()`
30e5c89e4eSSatish Balay @*/
31d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp)
32d71ae5a4SJacob Faibussowitsch {
33e5c89e4eSSatish Balay   PetscMPIInt rank;
34e5c89e4eSSatish Balay   FILE       *fd;
35e5c89e4eSSatish Balay   char        fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN];
36e5c89e4eSSatish Balay 
37e5c89e4eSSatish Balay   PetscFunctionBegin;
389566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
39dd400576SPatrick Sanan   if (rank == 0) {
40ace3abfcSBarry Smith     PetscBool isstdout, isstderr;
419566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
429566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
43a297a907SKarl Rupp     if (isstdout || !name) fd = PETSC_STDOUT;
44a297a907SKarl Rupp     else if (isstderr) fd = PETSC_STDERR;
45a297a907SKarl Rupp     else {
46bbcf679cSJacob Faibussowitsch       PetscBool devnull = PETSC_FALSE;
479566063dSJacob Faibussowitsch       PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN));
489566063dSJacob Faibussowitsch       PetscCall(PetscFixFilename(tname, fname));
499566063dSJacob Faibussowitsch       PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull));
50c6a7a370SJeremy L Thompson       if (devnull) PetscCall(PetscStrncpy(fname, "/dev/null", sizeof(fname)));
519566063dSJacob Faibussowitsch       PetscCall(PetscInfo(0, "Opening file %s\n", fname));
52e5c89e4eSSatish Balay       fd = fopen(fname, mode);
5328b400f6SJacob Faibussowitsch       PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname);
54e5c89e4eSSatish Balay     }
5502c9f0b5SLisandro Dalcin   } else fd = NULL;
56e5c89e4eSSatish Balay   *fp = fd;
573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58e5c89e4eSSatish Balay }
59e5c89e4eSSatish Balay 
60e8976759SBarry Smith /*@C
6121532e8aSBarry Smith   PetscFClose - Has MPI rank 0 in the communicator close a
6221532e8aSBarry Smith   file (usually obtained with `PetscFOpen()`; all others do nothing.
63e5c89e4eSSatish Balay 
64cc4c1da9SBarry Smith   Logically Collective
65e5c89e4eSSatish Balay 
66e5c89e4eSSatish Balay   Input Parameters:
6721532e8aSBarry Smith + comm - the MPI communicator
6821532e8aSBarry Smith - fd   - the file, opened with `PetscFOpen()`
69e5c89e4eSSatish Balay 
70e5c89e4eSSatish Balay   Level: developer
71e5c89e4eSSatish Balay 
72db781477SPatrick Sanan .seealso: `PetscFOpen()`
73e5c89e4eSSatish Balay @*/
74d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd)
75d71ae5a4SJacob Faibussowitsch {
76e5c89e4eSSatish Balay   PetscMPIInt rank;
77ed9cf6e9SBarry Smith   int         err;
78e5c89e4eSSatish Balay 
79e5c89e4eSSatish Balay   PetscFunctionBegin;
809566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
81dd400576SPatrick Sanan   if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) {
82ed9cf6e9SBarry Smith     err = fclose(fd);
8328b400f6SJacob Faibussowitsch     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
84ed9cf6e9SBarry Smith   }
853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
86e5c89e4eSSatish Balay }
87e5c89e4eSSatish Balay 
8874ba8654SBarry Smith static char PetscPOpenMachine[128] = "";
89e5c89e4eSSatish Balay 
90e5c89e4eSSatish Balay /*@C
9121532e8aSBarry Smith   PetscPClose - Closes (ends) a program on MPI rank 0 run with `PetscPOpen()`
92e5c89e4eSSatish Balay 
9321532e8aSBarry Smith   Collective, but only MPI rank 0 does anything
94e5c89e4eSSatish Balay 
95e5c89e4eSSatish Balay   Input Parameters:
9621532e8aSBarry Smith + comm - MPI communicator, only rank 0 performs the close
9721532e8aSBarry Smith - fd   - the file pointer where program input or output may be read or `NULL` if don't care
98e5c89e4eSSatish Balay 
99e5c89e4eSSatish Balay   Level: intermediate
100e5c89e4eSSatish Balay 
101811af0c4SBarry Smith   Note:
102bfbbc7b7SBarry Smith   Does not work under Microsoft Windows
103e5c89e4eSSatish Balay 
104db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()`
105e5c89e4eSSatish Balay @*/
106d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd)
107d71ae5a4SJacob Faibussowitsch {
108cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN)
109e5c89e4eSSatish Balay   PetscMPIInt rank;
110cc4c1da9SBarry Smith #endif
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay   PetscFunctionBegin;
113cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN)
1149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
115dd400576SPatrick Sanan   if (rank == 0) {
116e5c89e4eSSatish Balay     char buf[1024];
117fbccb6d4SPierre Jolivet     while (fgets(buf, 1024, fd)); /* wait till it prints everything */
118016831caSBarry Smith     (void)pclose(fd);
119e5c89e4eSSatish Balay   }
120cc4c1da9SBarry Smith #else
121cc4c1da9SBarry Smith   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "pclose() - routine is unavailable.");
122cc4c1da9SBarry Smith #endif
1233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
124e5c89e4eSSatish Balay }
125e5c89e4eSSatish Balay 
126e5c89e4eSSatish Balay /*@C
12721532e8aSBarry Smith   PetscPOpen - Runs a program on MPI rank 0 and sends either its input or output to
128e5c89e4eSSatish Balay   a file.
129e5c89e4eSSatish Balay 
130bfbbc7b7SBarry Smith   Logically Collective, but only MPI rank 0 runs the command
131e5c89e4eSSatish Balay 
132e5c89e4eSSatish Balay   Input Parameters:
133e5c89e4eSSatish Balay + comm    - MPI communicator, only processor zero runs the program
13421532e8aSBarry Smith . machine - machine to run command on or `NULL`, or a string with 0 in first location
135e5c89e4eSSatish Balay . program - name of program to run
136bfbbc7b7SBarry Smith - mode    - either "r" or "w"
137e5c89e4eSSatish Balay 
138e5c89e4eSSatish Balay   Output Parameter:
13921532e8aSBarry Smith . fp - the file pointer where program input or output may be read or `NULL` if results are not needed
140e5c89e4eSSatish Balay 
141e5c89e4eSSatish Balay   Level: intermediate
142e5c89e4eSSatish Balay 
143e5c89e4eSSatish Balay   Notes:
144811af0c4SBarry Smith   Use `PetscPClose()` to close the file pointer when you are finished with it
145811af0c4SBarry Smith 
146bfbbc7b7SBarry Smith   Does not work under Microsoft Windows
147e5c89e4eSSatish Balay 
148811af0c4SBarry Smith   If machine is not provided will use the value set with `PetsPOpenSetMachine()` if that was provided, otherwise
14921532e8aSBarry Smith   will use the machine running MPI rank 0 of the communicator
15074ba8654SBarry Smith 
151e5c89e4eSSatish Balay   The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these
152a5b23f4aSJose E. Roman   will be replaced with relevant values.
153e5c89e4eSSatish Balay 
154db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()`
155e5c89e4eSSatish Balay @*/
156d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpen(MPI_Comm comm, const char machine[], const char program[], const char mode[], FILE **fp)
157d71ae5a4SJacob Faibussowitsch {
158cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN)
159e5c89e4eSSatish Balay   PetscMPIInt rank;
160e5c89e4eSSatish Balay   size_t      i, len, cnt;
161e5c89e4eSSatish Balay   char        commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN];
162e5c89e4eSSatish Balay   FILE       *fd;
163cc4c1da9SBarry Smith #endif
164e5c89e4eSSatish Balay 
165e5c89e4eSSatish Balay   PetscFunctionBegin;
166cc4c1da9SBarry Smith #if defined(PETSC_HAVE_POPEN)
167e5c89e4eSSatish Balay   /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */
16874ba8654SBarry Smith   if (PetscPOpenMachine[0] || (machine && machine[0])) {
169c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(command, "ssh ", sizeof(command)));
17074ba8654SBarry Smith     if (PetscPOpenMachine[0]) {
171c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command)));
17274ba8654SBarry Smith     } else {
173c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(command, machine, sizeof(command)));
17474ba8654SBarry Smith     }
175c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command)));
176e5c89e4eSSatish Balay     /*
177e5c89e4eSSatish Balay         Copy program into command but protect the " with a \ in front of it
178e5c89e4eSSatish Balay     */
1799566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(command, &cnt));
1809566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(program, &len));
181e5c89e4eSSatish Balay     for (i = 0; i < len; i++) {
182a297a907SKarl Rupp       if (program[i] == '\"') command[cnt++] = '\\';
183e5c89e4eSSatish Balay       command[cnt++] = program[i];
184e5c89e4eSSatish Balay     }
185e5c89e4eSSatish Balay     command[cnt] = 0;
186a297a907SKarl Rupp 
187c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(command, "\"", sizeof(command)));
188e5c89e4eSSatish Balay   } else {
189c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(command, program, sizeof(command)));
190e5c89e4eSSatish Balay   }
191e5c89e4eSSatish Balay 
1929566063dSJacob Faibussowitsch   PetscCall(PetscStrreplace(comm, command, commandt, 1024));
193e5c89e4eSSatish Balay 
1949566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
195dd400576SPatrick Sanan   if (rank == 0) {
1969566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt));
197*57508eceSPierre Jolivet     PetscCheck(fd = popen(commandt, mode), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt);
198e5c89e4eSSatish Balay     if (fp) *fp = fd;
199e5c89e4eSSatish Balay   }
200cc4c1da9SBarry Smith #else
201cc4c1da9SBarry Smith   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "popen() - system routine is unavailable.");
202cc4c1da9SBarry Smith #endif
2033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
204e5c89e4eSSatish Balay }
205e5c89e4eSSatish Balay 
206cc4c1da9SBarry Smith /*@
207811af0c4SBarry Smith   PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on
20874ba8654SBarry Smith 
209a3b724e8SBarry Smith   Logically Collective, but only the MPI process with rank 0 runs the command
21074ba8654SBarry Smith 
21174ba8654SBarry Smith   Input Parameter:
212bfbbc7b7SBarry Smith . machine - machine to run command on or `NULL` for the current machine
21374ba8654SBarry Smith 
214811af0c4SBarry Smith   Options Database Key:
21510699b91SBarry Smith . -popen_machine <machine> - run the process on this machine
21674ba8654SBarry Smith 
21774ba8654SBarry Smith   Level: intermediate
21874ba8654SBarry Smith 
219db781477SPatrick Sanan .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()`
22074ba8654SBarry Smith @*/
221d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscPOpenSetMachine(const char machine[])
222d71ae5a4SJacob Faibussowitsch {
22374ba8654SBarry Smith   PetscFunctionBegin;
22474ba8654SBarry Smith   if (machine) {
225c6a7a370SJeremy L Thompson     PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine)));
22674ba8654SBarry Smith   } else {
22774ba8654SBarry Smith     PetscPOpenMachine[0] = 0;
22874ba8654SBarry Smith   }
2293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23074ba8654SBarry Smith }
231