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