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 @*/
PetscFOpen(MPI_Comm comm,const char name[],const char mode[],FILE ** fp)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 @*/
PetscFClose(MPI_Comm comm,FILE * fd)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 @*/
PetscPClose(MPI_Comm comm,FILE * fd)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
148*54c05997SPierre Jolivet If machine is not provided will use the value set with `PetscPOpenSetMachine()` 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 @*/
PetscPOpen(MPI_Comm comm,const char machine[],const char program[],const char mode[],FILE ** fp)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));
19757508eceSPierre 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 @*/
PetscPOpenSetMachine(const char machine[])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