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 <petsc/private/logimpl.h>
6: #include <errno.h>
8: /*@
9: PetscFOpen - Has the first process in the MPI communicator open a file;
10: all others do nothing.
12: Logically Collective
14: Input Parameters:
15: + comm - the MPI communicator
16: . name - the filename
17: - mode - the mode for `fopen()`, usually "w"
19: Output Parameter:
20: . fp - the file pointer
22: Level: developer
24: Note:
25: `NULL`, "stderr" or "stdout" may be passed in as the filename
27: .seealso: `PetscFClose()`, `PetscSynchronizedFGets()`, `PetscSynchronizedPrintf()`, `PetscSynchronizedFlush()`,
28: `PetscFPrintf()`
29: @*/
30: PetscErrorCode PetscFOpen(MPI_Comm comm, const char name[], const char mode[], FILE **fp)
31: {
32: PetscMPIInt rank;
33: FILE *fd;
34: char fname[PETSC_MAX_PATH_LEN], tname[PETSC_MAX_PATH_LEN];
36: PetscFunctionBegin;
37: PetscCallMPI(MPI_Comm_rank(comm, &rank));
38: if (rank == 0) {
39: PetscBool isstdout, isstderr;
40: PetscCall(PetscStrcmp(name, "stdout", &isstdout));
41: PetscCall(PetscStrcmp(name, "stderr", &isstderr));
42: if (isstdout || !name) fd = PETSC_STDOUT;
43: else if (isstderr) fd = PETSC_STDERR;
44: else {
45: PetscBool devnull = PETSC_FALSE;
46: PetscCall(PetscStrreplace(PETSC_COMM_SELF, name, tname, PETSC_MAX_PATH_LEN));
47: PetscCall(PetscFixFilename(tname, fname));
48: PetscCall(PetscStrbeginswith(fname, "/dev/null", &devnull));
49: if (devnull) PetscCall(PetscStrncpy(fname, "/dev/null", sizeof(fname)));
50: PetscCall(PetscInfo(0, "Opening file %s\n", fname));
51: fd = fopen(fname, mode);
52: PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open file %s", fname);
53: }
54: } else fd = NULL;
55: *fp = fd;
56: PetscFunctionReturn(PETSC_SUCCESS);
57: }
59: /*@
60: PetscFClose - Has MPI rank 0 in the communicator close a
61: file (usually obtained with `PetscFOpen()`; all others do nothing.
63: Logically Collective
65: Input Parameters:
66: + comm - the MPI communicator
67: - fd - the file, opened with `PetscFOpen()`
69: Level: developer
71: .seealso: `PetscFOpen()`
72: @*/
73: PetscErrorCode PetscFClose(MPI_Comm comm, FILE *fd)
74: {
75: PetscMPIInt rank;
76: int err;
78: PetscFunctionBegin;
79: PetscCallMPI(MPI_Comm_rank(comm, &rank));
80: if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) {
81: err = fclose(fd);
82: PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
83: }
84: PetscFunctionReturn(PETSC_SUCCESS);
85: }
87: static char PetscPOpenMachine[128] = "";
89: /*@
90: PetscPClose - Closes (ends) a program on MPI rank 0 run with `PetscPOpen()`
92: Collective, but only MPI rank 0 does anything
94: Input Parameters:
95: + comm - MPI communicator, only rank 0 performs the close
96: - fd - the file pointer where program input or output may be read or `NULL` if don't care
98: Level: intermediate
100: Note:
101: Does not work under Microsoft Windows
103: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()`
104: @*/
105: PetscErrorCode PetscPClose(MPI_Comm comm, FILE *fd)
106: {
107: #if PetscDefined(HAVE_POPEN)
108: PetscMPIInt rank;
109: #endif
111: PetscFunctionBegin;
112: #if PetscDefined(HAVE_POPEN)
113: PetscCallMPI(MPI_Comm_rank(comm, &rank));
114: if (rank == 0) {
115: char buf[1024];
116: while (fgets(buf, 1024, fd)); /* wait till it prints everything */
117: (void)pclose(fd);
118: }
119: #else
120: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "pclose() - routine is unavailable.");
121: #endif
122: PetscFunctionReturn(PETSC_SUCCESS);
123: }
125: /*@
126: PetscPOpen - Runs a program on MPI rank 0 and sends either its input or output to
127: a file.
129: Logically Collective, but only MPI rank 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 a 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 results are not needed
140: Level: intermediate
142: Notes:
143: Use `PetscPClose()` to close the file pointer when you are finished with it
145: Does not work under Microsoft Windows
147: If machine is not provided will use the value set with `PetscPOpenSetMachine()` if that was provided, otherwise
148: will use the machine running MPI rank 0 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: #if PetscDefined(HAVE_POPEN)
158: PetscMPIInt rank;
159: size_t i, len, cnt;
160: char commandt[PETSC_MAX_PATH_LEN], command[PETSC_MAX_PATH_LEN];
161: FILE *fd;
162: #endif
164: PetscFunctionBegin;
165: #if PetscDefined(HAVE_POPEN)
166: /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */
167: if (PetscPOpenMachine[0] || (machine && machine[0])) {
168: PetscCall(PetscStrncpy(command, "ssh ", sizeof(command)));
169: if (PetscPOpenMachine[0]) {
170: PetscCall(PetscStrlcat(command, PetscPOpenMachine, sizeof(command)));
171: } else {
172: PetscCall(PetscStrlcat(command, machine, sizeof(command)));
173: }
174: PetscCall(PetscStrlcat(command, " \" export DISPLAY=${DISPLAY}; ", sizeof(command)));
175: /*
176: Copy program into command but protect the " with a \ in front of it
177: */
178: PetscCall(PetscStrlen(command, &cnt));
179: PetscCall(PetscStrlen(program, &len));
180: for (i = 0; i < len; i++) {
181: if (program[i] == '\"') command[cnt++] = '\\';
182: command[cnt++] = program[i];
183: }
184: command[cnt] = 0;
186: PetscCall(PetscStrlcat(command, "\"", sizeof(command)));
187: } else {
188: PetscCall(PetscStrncpy(command, program, sizeof(command)));
189: }
191: PetscCall(PetscStrreplace(comm, command, commandt, 1024));
193: PetscCallMPI(MPI_Comm_rank(comm, &rank));
194: if (rank == 0) {
195: PetscCall(PetscInfo(NULL, "Running command :%s\n", commandt));
196: PetscCheck(fd = popen(commandt, mode), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot run command %s", commandt);
197: if (fp) *fp = fd;
198: }
199: #else
200: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "popen() - system routine is unavailable.");
201: #endif
202: PetscFunctionReturn(PETSC_SUCCESS);
203: }
205: /*@
206: PetscPOpenSetMachine - Sets the name of the default machine to run `PetscPOpen()` calls on
208: Logically Collective, but only the MPI process with rank 0 runs the command
210: Input Parameter:
211: . machine - machine to run command on or `NULL` for the current machine
213: Options Database Key:
214: . -popen_machine machine - run the process on this machine
216: Level: intermediate
218: .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()`
219: @*/
220: PetscErrorCode PetscPOpenSetMachine(const char machine[])
221: {
222: PetscFunctionBegin;
223: if (machine) {
224: PetscCall(PetscStrncpy(PetscPOpenMachine, machine, sizeof(PetscPOpenMachine)));
225: } else {
226: PetscPOpenMachine[0] = 0;
227: }
228: PetscFunctionReturn(PETSC_SUCCESS);
229: }