xref: /petsc/src/sys/fileio/fretrieve.c (revision 5c6c1daec53e1d9ab0bec9db5309fd8fc7645b8d)
1 
2 /*
3       Code for opening and closing files.
4 */
5 #include <petscsys.h>
6 #if defined(PETSC_HAVE_PWD_H)
7 #include <pwd.h>
8 #endif
9 #include <ctype.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #if defined(PETSC_HAVE_UNISTD_H)
13 #include <unistd.h>
14 #endif
15 #if defined(PETSC_HAVE_STDLIB_H)
16 #include <stdlib.h>
17 #endif
18 #if defined(PETSC_HAVE_SYS_UTSNAME_H)
19 #include <sys/utsname.h>
20 #endif
21 #include <fcntl.h>
22 #include <time.h>
23 #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
24 #include <sys/systeminfo.h>
25 #endif
26 
27 EXTERN_C_BEGIN
28 #undef __FUNCT__
29 #define __FUNCT__ "Petsc_DelTmpShared"
30 /*
31    Private routine to delete tmp/shared storage
32 
33    This is called by MPI, not by users.
34 
35    Note: this is declared extern "C" because it is passed to MPI_Keyval_create()
36 
37 */
38 PetscMPIInt  MPIAPI Petsc_DelTmpShared(MPI_Comm comm,PetscMPIInt keyval,void *count_val,void *extra_state)
39 {
40   PetscErrorCode ierr;
41 
42   PetscFunctionBegin;
43   ierr = PetscInfo1(0,"Deleting tmp/shared data in an MPI_Comm %ld\n",(long)comm);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr);
44   ierr = PetscFree(count_val);if (ierr) PetscFunctionReturn((PetscMPIInt)ierr);
45   PetscFunctionReturn(MPI_SUCCESS);
46 }
47 EXTERN_C_END
48 
49 #undef __FUNCT__
50 #define __FUNCT__ "PetscGetTmp"
51 /*@C
52    PetscGetTmp - Gets the name of the tmp directory
53 
54    Collective on MPI_Comm
55 
56    Input Parameters:
57 +  comm - MPI_Communicator that may share /tmp
58 -  len - length of string to hold name
59 
60    Output Parameters:
61 .  dir - directory name
62 
63    Options Database Keys:
64 +    -shared_tmp
65 .    -not_shared_tmp
66 -    -tmp tmpdir
67 
68    Environmental Variables:
69 +     PETSC_SHARED_TMP
70 .     PETSC_NOT_SHARED_TMP
71 -     PETSC_TMP
72 
73    Level: developer
74 
75 
76    If the environmental variable PETSC_TMP is set it will use this directory
77   as the "/tmp" directory.
78 
79 @*/
80 PetscErrorCode  PetscGetTmp(MPI_Comm comm,char dir[],size_t len)
81 {
82   PetscErrorCode ierr;
83   PetscBool      flg;
84 
85   PetscFunctionBegin;
86   ierr = PetscOptionsGetenv(comm,"PETSC_TMP",dir,len,&flg);CHKERRQ(ierr);
87   if (!flg) {
88     ierr = PetscStrncpy(dir,"/tmp",len);CHKERRQ(ierr);
89   }
90   PetscFunctionReturn(0);
91 }
92 
93 #undef __FUNCT__
94 #define __FUNCT__ "PetscSharedTmp"
95 /*@C
96    PetscSharedTmp - Determines if all processors in a communicator share a
97          /tmp or have different ones.
98 
99    Collective on MPI_Comm
100 
101    Input Parameters:
102 .  comm - MPI_Communicator that may share /tmp
103 
104    Output Parameters:
105 .  shared - PETSC_TRUE or PETSC_FALSE
106 
107    Options Database Keys:
108 +    -shared_tmp
109 .    -not_shared_tmp
110 -    -tmp tmpdir
111 
112    Environmental Variables:
113 +     PETSC_SHARED_TMP
114 .     PETSC_NOT_SHARED_TMP
115 -     PETSC_TMP
116 
117    Level: developer
118 
119    Notes:
120    Stores the status as a MPI attribute so it does not have
121     to be redetermined each time.
122 
123       Assumes that all processors in a communicator either
124        1) have a common /tmp or
125        2) each has a separate /tmp
126       eventually we can write a fancier one that determines which processors
127       share a common /tmp.
128 
129    This will be very slow on runs with a large number of processors since
130    it requires O(p*p) file opens.
131 
132    If the environmental variable PETSC_TMP is set it will use this directory
133   as the "/tmp" directory.
134 
135 @*/
136 PetscErrorCode  PetscSharedTmp(MPI_Comm comm,PetscBool  *shared)
137 {
138   PetscErrorCode     ierr;
139   PetscMPIInt        size,rank,*tagvalp,sum,cnt,i;
140   PetscBool          flg,iflg;
141   FILE               *fd;
142   static PetscMPIInt Petsc_Tmp_keyval = MPI_KEYVAL_INVALID;
143   int                err;
144 
145   PetscFunctionBegin;
146   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
147   if (size == 1) {
148     *shared = PETSC_TRUE;
149     PetscFunctionReturn(0);
150   }
151 
152   ierr = PetscOptionsGetenv(comm,"PETSC_SHARED_TMP",PETSC_NULL,0,&flg);CHKERRQ(ierr);
153   if (flg) {
154     *shared = PETSC_TRUE;
155     PetscFunctionReturn(0);
156   }
157 
158   ierr = PetscOptionsGetenv(comm,"PETSC_NOT_SHARED_TMP",PETSC_NULL,0,&flg);CHKERRQ(ierr);
159   if (flg) {
160     *shared = PETSC_FALSE;
161     PetscFunctionReturn(0);
162   }
163 
164   if (Petsc_Tmp_keyval == MPI_KEYVAL_INVALID) {
165     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTmpShared,&Petsc_Tmp_keyval,0);CHKERRQ(ierr);
166   }
167 
168   ierr = MPI_Attr_get(comm,Petsc_Tmp_keyval,(void**)&tagvalp,(int*)&iflg);CHKERRQ(ierr);
169   if (!iflg) {
170     char       filename[PETSC_MAX_PATH_LEN],tmpname[PETSC_MAX_PATH_LEN];
171 
172     /* This communicator does not yet have a shared tmp attribute */
173     ierr = PetscMalloc(sizeof(PetscMPIInt),&tagvalp);CHKERRQ(ierr);
174     ierr = MPI_Attr_put(comm,Petsc_Tmp_keyval,tagvalp);CHKERRQ(ierr);
175 
176     ierr = PetscOptionsGetenv(comm,"PETSC_TMP",tmpname,238,&iflg);CHKERRQ(ierr);
177     if (!iflg) {
178       ierr = PetscStrcpy(filename,"/tmp");CHKERRQ(ierr);
179     } else {
180       ierr = PetscStrcpy(filename,tmpname);CHKERRQ(ierr);
181     }
182 
183     ierr = PetscStrcat(filename,"/petsctestshared");CHKERRQ(ierr);
184     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
185 
186     /* each processor creates a /tmp file and all the later ones check */
187     /* this makes sure no subset of processors is shared */
188     *shared = PETSC_FALSE;
189     for (i=0; i<size-1; i++) {
190       if (rank == i) {
191         fd = fopen(filename,"w");
192         if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open test file %s",filename);
193         err = fclose(fd);
194         if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
195       }
196       ierr = MPI_Barrier(comm);CHKERRQ(ierr);
197       if (rank >= i) {
198         fd = fopen(filename,"r");
199         if (fd) cnt = 1; else cnt = 0;
200         if (fd) {
201           err = fclose(fd);
202           if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
203         }
204       } else {
205         cnt = 0;
206       }
207       ierr = MPI_Allreduce(&cnt,&sum,1,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
208       if (rank == i) {
209         unlink(filename);
210       }
211 
212       if (sum == size) {
213         *shared = PETSC_TRUE;
214         break;
215       } else if (sum != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Subset of processes share /tmp ");
216     }
217     *tagvalp = (int)*shared;
218     ierr = PetscInfo2(0,"processors %s %s\n",(*shared) ? "share":"do NOT share",(iflg ? tmpname:"/tmp"));CHKERRQ(ierr);
219   } else {
220     *shared = (PetscBool) *tagvalp;
221   }
222   PetscFunctionReturn(0);
223 }
224 
225 #undef __FUNCT__
226 #define __FUNCT__ "PetscSharedWorkingDirectory"
227 /*@C
228    PetscSharedWorkingDirectory - Determines if all processors in a communicator share a
229          working directory or have different ones.
230 
231    Collective on MPI_Comm
232 
233    Input Parameters:
234 .  comm - MPI_Communicator that may share working directory
235 
236    Output Parameters:
237 .  shared - PETSC_TRUE or PETSC_FALSE
238 
239    Options Database Keys:
240 +    -shared_working_directory
241 .    -not_shared_working_directory
242 
243    Environmental Variables:
244 +     PETSC_SHARED_WORKING_DIRECTORY
245 .     PETSC_NOT_SHARED_WORKING_DIRECTORY
246 
247    Level: developer
248 
249    Notes:
250    Stores the status as a MPI attribute so it does not have
251     to be redetermined each time.
252 
253       Assumes that all processors in a communicator either
254        1) have a common working directory or
255        2) each has a separate working directory
256       eventually we can write a fancier one that determines which processors
257       share a common working directory.
258 
259    This will be very slow on runs with a large number of processors since
260    it requires O(p*p) file opens.
261 
262 @*/
263 PetscErrorCode  PetscSharedWorkingDirectory(MPI_Comm comm,PetscBool  *shared)
264 {
265   PetscErrorCode     ierr;
266   PetscMPIInt        size,rank,*tagvalp,sum,cnt,i;
267   PetscBool          flg,iflg;
268   FILE               *fd;
269   static PetscMPIInt Petsc_WD_keyval = MPI_KEYVAL_INVALID;
270   int                err;
271 
272   PetscFunctionBegin;
273   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
274   if (size == 1) {
275     *shared = PETSC_TRUE;
276     PetscFunctionReturn(0);
277   }
278 
279   ierr = PetscOptionsGetenv(comm,"PETSC_SHARED_WORKING_DIRECTORY",PETSC_NULL,0,&flg);CHKERRQ(ierr);
280   if (flg) {
281     *shared = PETSC_TRUE;
282     PetscFunctionReturn(0);
283   }
284 
285   ierr = PetscOptionsGetenv(comm,"PETSC_NOT_SHARED_WORKING_DIRECTORY",PETSC_NULL,0,&flg);CHKERRQ(ierr);
286   if (flg) {
287     *shared = PETSC_FALSE;
288     PetscFunctionReturn(0);
289   }
290 
291   if (Petsc_WD_keyval == MPI_KEYVAL_INVALID) {
292     ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,Petsc_DelTmpShared,&Petsc_WD_keyval,0);CHKERRQ(ierr);
293   }
294 
295   ierr = MPI_Attr_get(comm,Petsc_WD_keyval,(void**)&tagvalp,(int*)&iflg);CHKERRQ(ierr);
296   if (!iflg) {
297     char       filename[PETSC_MAX_PATH_LEN];
298 
299     /* This communicator does not yet have a shared  attribute */
300     ierr = PetscMalloc(sizeof(PetscMPIInt),&tagvalp);CHKERRQ(ierr);
301     ierr = MPI_Attr_put(comm,Petsc_WD_keyval,tagvalp);CHKERRQ(ierr);
302 
303     ierr = PetscGetWorkingDirectory(filename,240);CHKERRQ(ierr);
304     ierr = PetscStrcat(filename,"/petsctestshared");CHKERRQ(ierr);
305     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
306 
307     /* each processor creates a  file and all the later ones check */
308     /* this makes sure no subset of processors is shared */
309     *shared = PETSC_FALSE;
310     for (i=0; i<size-1; i++) {
311       if (rank == i) {
312         fd = fopen(filename,"w");
313         if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open test file %s",filename);
314         err = fclose(fd);
315         if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
316       }
317       ierr = MPI_Barrier(comm);CHKERRQ(ierr);
318       if (rank >= i) {
319         fd = fopen(filename,"r");
320         if (fd) cnt = 1; else cnt = 0;
321         if (fd) {
322           err = fclose(fd);
323           if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
324         }
325       } else {
326         cnt = 0;
327       }
328       ierr = MPI_Allreduce(&cnt,&sum,1,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
329       if (rank == i) {
330         unlink(filename);
331       }
332 
333       if (sum == size) {
334         *shared = PETSC_TRUE;
335         break;
336       } else if (sum != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Subset of processes share working directory");
337     }
338     *tagvalp = (int)*shared;
339   } else {
340     *shared = (PetscBool) *tagvalp;
341   }
342   ierr = PetscInfo1(0,"processors %s working directory\n",(*shared) ? "shared" : "do NOT share");CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 
347 #undef __FUNCT__
348 #define __FUNCT__ "PetscFileRetrieve"
349 /*@C
350     PetscFileRetrieve - Obtains a library from a URL or compressed
351         and copies into local disk space as uncompressed.
352 
353     Collective on MPI_Comm
354 
355     Input Parameter:
356 +   comm     - processors accessing the library
357 .   libname  - name of library, including entire URL (with or without .gz)
358 -   llen     - length of llibname
359 
360     Output Parameter:
361 +   llibname - name of local copy of library
362 -   found - if found and retrieved the file
363 
364     Level: developer
365 
366 @*/
367 PetscErrorCode  PetscFileRetrieve(MPI_Comm comm,const char libname[],char llibname[],size_t llen,PetscBool  *found)
368 {
369   char              buf[1024],tmpdir[PETSC_MAX_PATH_LEN],urlget[PETSC_MAX_PATH_LEN],*par;
370   const char        *pdir;
371   FILE              *fp;
372   PetscErrorCode    ierr;
373   int               i;
374   PetscMPIInt       rank;
375   size_t            len = 0;
376   PetscBool         flg1,flg2,flg3,sharedtmp,exists;
377 #if defined(PETSC_HAVE_POPEN)
378   PetscInt          rval;
379 #endif
380 
381   PetscFunctionBegin;
382   *found = PETSC_FALSE;
383 
384   /* if file does not have an ftp:// or http:// or .gz then need not process file */
385   ierr = PetscStrstr(libname,".gz",&par);CHKERRQ(ierr);
386   if (par) {ierr = PetscStrlen(par,&len);CHKERRQ(ierr);}
387 
388   ierr = PetscStrncmp(libname,"ftp://",6,&flg1);CHKERRQ(ierr);
389   ierr = PetscStrncmp(libname,"http://",7,&flg2);CHKERRQ(ierr);
390   ierr = PetscStrncmp(libname,"file://",7,&flg3);CHKERRQ(ierr);
391   if (!flg1 && !flg2 && !flg3 && (!par || len != 3)) {
392     ierr = PetscStrncpy(llibname,libname,llen);CHKERRQ(ierr);
393     ierr = PetscTestFile(libname,'r',found);CHKERRQ(ierr);
394     if (*found) {
395       ierr = PetscInfo1(PETSC_NULL,"Found file %s\n",libname);
396     } else {
397       ierr = PetscInfo1(PETSC_NULL,"Did not find file %s\n",libname);
398     }
399     PetscFunctionReturn(0);
400   }
401 
402   /* Determine if all processors share a common /tmp */
403   ierr = PetscSharedTmp(comm,&sharedtmp);CHKERRQ(ierr);
404   ierr = PetscOptionsGetenv(comm,"PETSC_TMP",tmpdir,PETSC_MAX_PATH_LEN,&flg1);CHKERRQ(ierr);
405 
406   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
407   if (!rank || !sharedtmp) {
408 
409     /* Construct the script to get URL file */
410     ierr = PetscGetPetscDir(&pdir);CHKERRQ(ierr);
411     ierr = PetscStrcpy(urlget,pdir);CHKERRQ(ierr);
412     ierr = PetscStrcat(urlget,"/bin/urlget");CHKERRQ(ierr);
413     ierr = PetscTestFile(urlget,'r',&exists);CHKERRQ(ierr);
414     if (!exists) {
415       ierr = PetscTestFile("urlget",'r',&exists);CHKERRQ(ierr);
416       if (!exists) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cannot locate PETSc script urlget in %s or current directory",urlget);
417       ierr = PetscStrcpy(urlget,"urlget");CHKERRQ(ierr);
418     }
419     ierr = PetscStrcat(urlget," ");CHKERRQ(ierr);
420 
421     /* are we using an alternative /tmp? */
422     if (flg1) {
423       ierr = PetscStrcat(urlget,"-tmp ");CHKERRQ(ierr);
424       ierr = PetscStrcat(urlget,tmpdir);CHKERRQ(ierr);
425       ierr = PetscStrcat(urlget," ");CHKERRQ(ierr);
426     }
427 
428     ierr = PetscStrcat(urlget,libname);CHKERRQ(ierr);
429     ierr = PetscStrcat(urlget," 2>&1 ");CHKERRQ(ierr);
430 
431 #if defined(PETSC_HAVE_POPEN)
432     ierr = PetscPOpen(PETSC_COMM_SELF,PETSC_NULL,urlget,"r",&fp);CHKERRQ(ierr);
433 #else
434     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Cannot run external programs on this machine");
435 #endif
436     if (!fgets(buf,1024,fp)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"No output from ${PETSC_DIR}/bin/urlget in getting file %s",libname);
437     ierr = PetscInfo1(0,"Message back from urlget: %s\n",buf);CHKERRQ(ierr);
438 
439     ierr = PetscStrncmp(buf,"Error",5,&flg1);CHKERRQ(ierr);
440     ierr = PetscStrncmp(buf,"Traceback",9,&flg2);CHKERRQ(ierr);
441 #if defined(PETSC_HAVE_POPEN)
442     ierr = PetscPClose(PETSC_COMM_SELF,fp,&rval);CHKERRQ(ierr);
443 #endif
444     if (flg1 || flg2) {
445       *found = PETSC_FALSE;
446     } else {
447       *found = PETSC_TRUE;
448 
449       /* Check for \n and make it 0 */
450       for (i=0; i<1024; i++) {
451         if (buf[i] == '\n') {
452           buf[i] = 0;
453           break;
454         }
455       }
456       ierr = PetscStrncpy(llibname,buf,llen);CHKERRQ(ierr);
457     }
458   }
459   if (sharedtmp) { /* send library name to all processors */
460     ierr = MPI_Bcast(found,1,MPI_INT,0,comm);CHKERRQ(ierr);
461     if (*found) {
462       ierr = MPI_Bcast(llibname,llen,MPI_CHAR,0,comm);CHKERRQ(ierr);
463       ierr = MPI_Bcast(found,1,MPI_INT,0,comm);CHKERRQ(ierr);
464     }
465   }
466 
467   PetscFunctionReturn(0);
468 }
469