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