xref: /petsc/src/sys/fileio/mpiuopen.c (revision f97672e55eacc8688507b9471cd7ec2664d7f203)
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>
8 
9 /*@C
10     PetscFOpen - Has the first process in the communicator open a file;
11     all others do nothing.
12 
13     Logically Collective
14 
15     Input Parameters:
16 +   comm - the communicator
17 .   name - the filename
18 -   mode - the mode for fopen(), usually "w"
19 
20     Output Parameter:
21 .   fp - the file pointer
22 
23     Level: developer
24 
25     Notes:
26        NULL (0), "stderr" or "stdout" may be passed in as the filename
27 
28     Fortran Note:
29     This routine is not supported in Fortran.
30 
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];
39 
40   PetscFunctionBegin;
41   PetscCallMPI(MPI_Comm_rank(comm,&rank));
42   if (rank == 0) {
43     PetscBool isstdout,isstderr;
44     PetscCall(PetscStrcmp(name,"stdout",&isstdout));
45     PetscCall(PetscStrcmp(name,"stderr",&isstderr));
46     if (isstdout || !name) fd = PETSC_STDOUT;
47     else if (isstderr) fd = PETSC_STDERR;
48     else {
49       PetscBool devnull;
50       PetscCall(PetscStrreplace(PETSC_COMM_SELF,name,tname,PETSC_MAX_PATH_LEN));
51       PetscCall(PetscFixFilename(tname,fname));
52       PetscCall(PetscStrbeginswith(fname,"/dev/null",&devnull));
53       if (devnull) {
54         PetscCall(PetscStrcpy(fname,"/dev/null"));
55       }
56       PetscCall(PetscInfo(0,"Opening file %s\n",fname));
57       fd   = fopen(fname,mode);
58       PetscCheck(fd,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open file %s",fname);
59     }
60   } else fd = NULL;
61   *fp = fd;
62   PetscFunctionReturn(0);
63 }
64 
65 /*@C
66     PetscFClose - Has the first processor in the communicator close a
67     file; all others do nothing.
68 
69     Logically Collective
70 
71     Input Parameters:
72 +   comm - the communicator
73 -   fd - the file, opened with PetscFOpen()
74 
75    Level: developer
76 
77     Fortran Note:
78     This routine is not supported in Fortran.
79 
80 .seealso: `PetscFOpen()`
81 @*/
82 PetscErrorCode  PetscFClose(MPI_Comm comm,FILE *fd)
83 {
84   PetscMPIInt    rank;
85   int            err;
86 
87   PetscFunctionBegin;
88   PetscCallMPI(MPI_Comm_rank(comm,&rank));
89   if (rank == 0 && fd != PETSC_STDOUT && fd != PETSC_STDERR) {
90     err = fclose(fd);
91     PetscCheck(!err,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
92   }
93   PetscFunctionReturn(0);
94 }
95 
96 #if defined(PETSC_HAVE_POPEN)
97 static char PetscPOpenMachine[128] = "";
98 
99 /*@C
100       PetscPClose - Closes (ends) a program on processor zero run with PetscPOpen()
101 
102      Collective, but only process 0 runs the command
103 
104    Input Parameters:
105 +   comm - MPI communicator, only processor zero runs the program
106 -   fp - the file pointer where program input or output may be read or NULL if don't care
107 
108    Level: intermediate
109 
110    Notes:
111        Does not work under Windows
112 
113 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPOpen()`
114 
115 @*/
116 PetscErrorCode PetscPClose(MPI_Comm comm,FILE *fd)
117 {
118   PetscMPIInt    rank;
119 
120   PetscFunctionBegin;
121   PetscCallMPI(MPI_Comm_rank(comm,&rank));
122   if (rank == 0) {
123     char buf[1024];
124     while (fgets(buf,1024,fd)) ; /* wait till it prints everything */
125     (void) pclose(fd);
126   }
127   PetscFunctionReturn(0);
128 }
129 
130 /*@C
131       PetscPOpen - Runs a program on processor zero and sends either its input or output to
132           a file.
133 
134      Logically Collective, but only process 0 runs the command
135 
136    Input Parameters:
137 +   comm - MPI communicator, only processor zero runs the program
138 .   machine - machine to run command on or NULL, or string with 0 in first location
139 .   program - name of program to run
140 -   mode - either r or w
141 
142    Output Parameter:
143 .   fp - the file pointer where program input or output may be read or NULL if don't care
144 
145    Level: intermediate
146 
147    Notes:
148        Use PetscPClose() to close the file pointer when you are finished with it
149        Does not work under Windows
150 
151        If machine is not provided will use the value set with PetsPOpenSetMachine() if that was provided, otherwise
152        will use the machine running node zero of the communicator
153 
154        The program string may contain ${DISPLAY}, ${HOMEDIRECTORY} or ${WORKINGDIRECTORY}; these
155     will be replaced with relevant values.
156 
157 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpenSetMachine()`
158 
159 @*/
160 PetscErrorCode  PetscPOpen(MPI_Comm comm,const char machine[],const char program[],const char mode[],FILE **fp)
161 {
162   PetscMPIInt    rank;
163   size_t         i,len,cnt;
164   char           commandt[PETSC_MAX_PATH_LEN],command[PETSC_MAX_PATH_LEN];
165   FILE           *fd;
166 
167   PetscFunctionBegin;
168   /* all processors have to do the string manipulation because PetscStrreplace() is a collective operation */
169   if (PetscPOpenMachine[0] || (machine && machine[0])) {
170     PetscCall(PetscStrcpy(command,"ssh "));
171     if (PetscPOpenMachine[0]) {
172       PetscCall(PetscStrcat(command,PetscPOpenMachine));
173     } else {
174       PetscCall(PetscStrcat(command,machine));
175     }
176     PetscCall(PetscStrcat(command," \" export DISPLAY=${DISPLAY}; "));
177     /*
178         Copy program into command but protect the " with a \ in front of it
179     */
180     PetscCall(PetscStrlen(command,&cnt));
181     PetscCall(PetscStrlen(program,&len));
182     for (i=0; i<len; i++) {
183       if (program[i] == '\"') command[cnt++] = '\\';
184       command[cnt++] = program[i];
185     }
186     command[cnt] = 0;
187 
188     PetscCall(PetscStrcat(command,"\""));
189   } else {
190     PetscCall(PetscStrcpy(command,program));
191   }
192 
193   PetscCall(PetscStrreplace(comm,command,commandt,1024));
194 
195   PetscCallMPI(MPI_Comm_rank(comm,&rank));
196   if (rank == 0) {
197     PetscCall(PetscInfo(NULL,"Running command :%s\n",commandt));
198     PetscCheck((fd = popen(commandt,mode)),PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot run command %s",commandt);
199     if (fp) *fp = fd;
200   }
201   PetscFunctionReturn(0);
202 }
203 
204 /*@C
205       PetscPOpenSetMachine - Sets the name of the default machine to run PetscPOpen() calls on
206 
207      Logically Collective, but only process 0 runs the command
208 
209    Input Parameter:
210 .   machine - machine to run command on or NULL for the current machine
211 
212    Options Database:
213 .   -popen_machine <machine> - run the process on this machine
214 
215    Level: intermediate
216 
217 .seealso: `PetscFOpen()`, `PetscFClose()`, `PetscPClose()`, `PetscPOpen()`
218 @*/
219 PetscErrorCode  PetscPOpenSetMachine(const char machine[])
220 {
221   PetscFunctionBegin;
222   if (machine) {
223     PetscCall(PetscStrcpy(PetscPOpenMachine,machine));
224   } else {
225     PetscPOpenMachine[0] = 0;
226   }
227   PetscFunctionReturn(0);
228 }
229 
230 #endif
231