xref: /petsc/src/sys/fileio/fretrieve.c (revision 10699b917c2ca523f62b603029bfcc018e13d799)
17d0a6c19SBarry Smith 
2e5c89e4eSSatish Balay /*
3e5c89e4eSSatish Balay       Code for opening and closing files.
4e5c89e4eSSatish Balay */
5c6db04a5SJed Brown #include <petscsys.h>
6e5c89e4eSSatish Balay #if defined(PETSC_HAVE_PWD_H)
7e5c89e4eSSatish Balay #include <pwd.h>
8e5c89e4eSSatish Balay #endif
9e5c89e4eSSatish Balay #include <ctype.h>
10e5c89e4eSSatish Balay #include <sys/stat.h>
11e5c89e4eSSatish Balay #if defined(PETSC_HAVE_UNISTD_H)
12e5c89e4eSSatish Balay #include <unistd.h>
13e5c89e4eSSatish Balay #endif
14e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SYS_UTSNAME_H)
15e5c89e4eSSatish Balay #include <sys/utsname.h>
16e5c89e4eSSatish Balay #endif
17e5c89e4eSSatish Balay #include <fcntl.h>
18e5c89e4eSSatish Balay #include <time.h>
19e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
20e5c89e4eSSatish Balay #include <sys/systeminfo.h>
21e5c89e4eSSatish Balay #endif
22e5c89e4eSSatish Balay 
23480cf27aSJed Brown /*
24480cf27aSJed Brown    Private routine to delete tmp/shared storage
25480cf27aSJed Brown 
26480cf27aSJed Brown    This is called by MPI, not by users.
27480cf27aSJed Brown 
2812801b39SBarry Smith    Note: this is declared extern "C" because it is passed to MPI_Comm_create_keyval()
29480cf27aSJed Brown 
30480cf27aSJed Brown */
318cc058d9SJed Brown PETSC_EXTERN PetscMPIInt MPIAPI Petsc_DelTmpShared(MPI_Comm comm,PetscMPIInt keyval,void *count_val,void *extra_state)
32480cf27aSJed Brown {
33480cf27aSJed Brown   PetscErrorCode ierr;
34480cf27aSJed Brown 
35480cf27aSJed Brown   PetscFunctionBegin;
3602c9f0b5SLisandro Dalcin   ierr = PetscInfo1(NULL,"Deleting tmp/shared data in an MPI_Comm %ld\n",(long)comm);CHKERRMPI(ierr);
3712801b39SBarry Smith   ierr = PetscFree(count_val);CHKERRMPI(ierr);
38480cf27aSJed Brown   PetscFunctionReturn(MPI_SUCCESS);
39480cf27aSJed Brown }
40e5c89e4eSSatish Balay 
41e5c89e4eSSatish Balay /*@C
42e5c89e4eSSatish Balay    PetscGetTmp - Gets the name of the tmp directory
43e5c89e4eSSatish Balay 
44d083f849SBarry Smith    Collective
45e5c89e4eSSatish Balay 
46e5c89e4eSSatish Balay    Input Parameters:
47e5c89e4eSSatish Balay +  comm - MPI_Communicator that may share /tmp
48e5c89e4eSSatish Balay -  len - length of string to hold name
49e5c89e4eSSatish Balay 
50e5c89e4eSSatish Balay    Output Parameters:
51e5c89e4eSSatish Balay .  dir - directory name
52e5c89e4eSSatish Balay 
53e5c89e4eSSatish Balay    Options Database Keys:
54*10699b91SBarry Smith +    -shared_tmp  - indicates the directory is shared among the MPI ranks
55*10699b91SBarry Smith .    -not_shared_tmp - indicates the directory is not shared among the MPI ranks
56*10699b91SBarry Smith -    -tmp tmpdir - name of the directory you wish to use as /tmp
57e5c89e4eSSatish Balay 
58e5c89e4eSSatish Balay    Environmental Variables:
59*10699b91SBarry Smith +     PETSC_SHARED_TMP - indicates the directory is shared among the MPI ranks
60*10699b91SBarry Smith .     PETSC_NOT_SHARED_TMP - indicates the directory is not shared among the MPI ranks
61*10699b91SBarry Smith -     PETSC_TMP - name of the directory you wish to use as /tmp
62e5c89e4eSSatish Balay 
63e5c89e4eSSatish Balay    Level: developer
64e5c89e4eSSatish Balay 
65e5c89e4eSSatish Balay 
66e5c89e4eSSatish Balay @*/
677087cfbeSBarry Smith PetscErrorCode  PetscGetTmp(MPI_Comm comm,char dir[],size_t len)
68e5c89e4eSSatish Balay {
69e5c89e4eSSatish Balay   PetscErrorCode ierr;
70ace3abfcSBarry Smith   PetscBool      flg;
71e5c89e4eSSatish Balay 
72e5c89e4eSSatish Balay   PetscFunctionBegin;
73e5c89e4eSSatish Balay   ierr = PetscOptionsGetenv(comm,"PETSC_TMP",dir,len,&flg);CHKERRQ(ierr);
74e5c89e4eSSatish Balay   if (!flg) {
75e5c89e4eSSatish Balay     ierr = PetscStrncpy(dir,"/tmp",len);CHKERRQ(ierr);
76e5c89e4eSSatish Balay   }
77e5c89e4eSSatish Balay   PetscFunctionReturn(0);
78e5c89e4eSSatish Balay }
79e5c89e4eSSatish Balay 
80e5c89e4eSSatish Balay /*@C
81e5c89e4eSSatish Balay    PetscSharedTmp - Determines if all processors in a communicator share a
82e5c89e4eSSatish Balay          /tmp or have different ones.
83e5c89e4eSSatish Balay 
84d083f849SBarry Smith    Collective
85e5c89e4eSSatish Balay 
86e5c89e4eSSatish Balay    Input Parameters:
87e5c89e4eSSatish Balay .  comm - MPI_Communicator that may share /tmp
88e5c89e4eSSatish Balay 
89e5c89e4eSSatish Balay    Output Parameters:
90e5c89e4eSSatish Balay .  shared - PETSC_TRUE or PETSC_FALSE
91e5c89e4eSSatish Balay 
92e5c89e4eSSatish Balay    Options Database Keys:
93*10699b91SBarry Smith +    -shared_tmp  - indicates the directory is shared among the MPI ranks
94*10699b91SBarry Smith .    -not_shared_tmp - indicates the directory is not shared among the MPI ranks
95*10699b91SBarry Smith -    -tmp tmpdir - name of the directory you wish to use as /tmp
96e5c89e4eSSatish Balay 
97e5c89e4eSSatish Balay    Environmental Variables:
98*10699b91SBarry Smith +     PETSC_SHARED_TMP  - indicates the directory is shared among the MPI ranks
99*10699b91SBarry Smith .     PETSC_NOT_SHARED_TMP - indicates the directory is not shared among the MPI ranks
100*10699b91SBarry Smith -     PETSC_TMP - name of the directory you wish to use as /tmp
101e5c89e4eSSatish Balay 
102e5c89e4eSSatish Balay    Level: developer
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay    Notes:
105e5c89e4eSSatish Balay    Stores the status as a MPI attribute so it does not have
106e5c89e4eSSatish Balay     to be redetermined each time.
107e5c89e4eSSatish Balay 
108e5c89e4eSSatish Balay       Assumes that all processors in a communicator either
109e5c89e4eSSatish Balay        1) have a common /tmp or
110a8c7a070SBarry Smith        2) each has a separate /tmp
111e5c89e4eSSatish Balay       eventually we can write a fancier one that determines which processors
112e5c89e4eSSatish Balay       share a common /tmp.
113e5c89e4eSSatish Balay 
114e5c89e4eSSatish Balay    This will be very slow on runs with a large number of processors since
115e5c89e4eSSatish Balay    it requires O(p*p) file opens.
116e5c89e4eSSatish Balay 
117e5c89e4eSSatish Balay    If the environmental variable PETSC_TMP is set it will use this directory
118e5c89e4eSSatish Balay   as the "/tmp" directory.
119e5c89e4eSSatish Balay 
120e5c89e4eSSatish Balay @*/
1217087cfbeSBarry Smith PetscErrorCode  PetscSharedTmp(MPI_Comm comm,PetscBool  *shared)
122e5c89e4eSSatish Balay {
123e5c89e4eSSatish Balay   PetscErrorCode     ierr;
124e5c89e4eSSatish Balay   PetscMPIInt        size,rank,*tagvalp,sum,cnt,i;
125ace3abfcSBarry Smith   PetscBool          flg,iflg;
126e5c89e4eSSatish Balay   FILE               *fd;
127e5c89e4eSSatish Balay   static PetscMPIInt Petsc_Tmp_keyval = MPI_KEYVAL_INVALID;
128ed9cf6e9SBarry Smith   int                err;
129e5c89e4eSSatish Balay 
130e5c89e4eSSatish Balay   PetscFunctionBegin;
131ffc4695bSBarry Smith   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
132e5c89e4eSSatish Balay   if (size == 1) {
133e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
134e5c89e4eSSatish Balay     PetscFunctionReturn(0);
135e5c89e4eSSatish Balay   }
136e5c89e4eSSatish Balay 
1370298fd71SBarry Smith   ierr = PetscOptionsGetenv(comm,"PETSC_SHARED_TMP",NULL,0,&flg);CHKERRQ(ierr);
138e5c89e4eSSatish Balay   if (flg) {
139e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
140e5c89e4eSSatish Balay     PetscFunctionReturn(0);
141e5c89e4eSSatish Balay   }
142e5c89e4eSSatish Balay 
1430298fd71SBarry Smith   ierr = PetscOptionsGetenv(comm,"PETSC_NOT_SHARED_TMP",NULL,0,&flg);CHKERRQ(ierr);
144e5c89e4eSSatish Balay   if (flg) {
145e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
146e5c89e4eSSatish Balay     PetscFunctionReturn(0);
147e5c89e4eSSatish Balay   }
148e5c89e4eSSatish Balay 
149e5c89e4eSSatish Balay   if (Petsc_Tmp_keyval == MPI_KEYVAL_INVALID) {
150ffc4695bSBarry Smith     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,Petsc_DelTmpShared,&Petsc_Tmp_keyval,NULL);CHKERRMPI(ierr);
151e5c89e4eSSatish Balay   }
152e5c89e4eSSatish Balay 
153ffc4695bSBarry Smith   ierr = MPI_Comm_get_attr(comm,Petsc_Tmp_keyval,(void**)&tagvalp,(int*)&iflg);CHKERRMPI(ierr);
154e5c89e4eSSatish Balay   if (!iflg) {
155e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN],tmpname[PETSC_MAX_PATH_LEN];
156e5c89e4eSSatish Balay 
157e5c89e4eSSatish Balay     /* This communicator does not yet have a shared tmp attribute */
158854ce69bSBarry Smith     ierr = PetscMalloc1(1,&tagvalp);CHKERRQ(ierr);
159ffc4695bSBarry Smith     ierr = MPI_Comm_set_attr(comm,Petsc_Tmp_keyval,tagvalp);CHKERRMPI(ierr);
160e5c89e4eSSatish Balay 
161e5c89e4eSSatish Balay     ierr = PetscOptionsGetenv(comm,"PETSC_TMP",tmpname,238,&iflg);CHKERRQ(ierr);
162e5c89e4eSSatish Balay     if (!iflg) {
163e5c89e4eSSatish Balay       ierr = PetscStrcpy(filename,"/tmp");CHKERRQ(ierr);
164e5c89e4eSSatish Balay     } else {
165e5c89e4eSSatish Balay       ierr = PetscStrcpy(filename,tmpname);CHKERRQ(ierr);
166e5c89e4eSSatish Balay     }
167e5c89e4eSSatish Balay 
168e5c89e4eSSatish Balay     ierr = PetscStrcat(filename,"/petsctestshared");CHKERRQ(ierr);
169ffc4695bSBarry Smith     ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
170e5c89e4eSSatish Balay 
171e5c89e4eSSatish Balay     /* each processor creates a /tmp file and all the later ones check */
172e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
173e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
174e5c89e4eSSatish Balay     for (i=0; i<size-1; i++) {
175e5c89e4eSSatish Balay       if (rank == i) {
176e5c89e4eSSatish Balay         fd = fopen(filename,"w");
177eb3354f8SBarry Smith         if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open test file %s",filename);
178ed9cf6e9SBarry Smith         err = fclose(fd);
179e32f2f54SBarry Smith         if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
180e5c89e4eSSatish Balay       }
181ffc4695bSBarry Smith       ierr = MPI_Barrier(comm);CHKERRMPI(ierr);
182e5c89e4eSSatish Balay       if (rank >= i) {
183e5c89e4eSSatish Balay         fd = fopen(filename,"r");
184a297a907SKarl Rupp         if (fd) cnt = 1;
185a297a907SKarl Rupp         else cnt = 0;
186e5c89e4eSSatish Balay         if (fd) {
187ed9cf6e9SBarry Smith           err = fclose(fd);
188e32f2f54SBarry Smith           if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
189e5c89e4eSSatish Balay         }
190a297a907SKarl Rupp       } else cnt = 0;
191a297a907SKarl Rupp 
192b2566f29SBarry Smith       ierr = MPIU_Allreduce(&cnt,&sum,1,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
193a297a907SKarl Rupp       if (rank == i) unlink(filename);
194e5c89e4eSSatish Balay 
195e5c89e4eSSatish Balay       if (sum == size) {
196e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
197e5c89e4eSSatish Balay         break;
198eb3354f8SBarry Smith       } else if (sum != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Subset of processes share /tmp ");
199e5c89e4eSSatish Balay     }
200e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
20102c9f0b5SLisandro Dalcin     ierr = PetscInfo2(NULL,"processors %s %s\n",(*shared) ? "share":"do NOT share",(iflg ? tmpname:"/tmp"));CHKERRQ(ierr);
202a297a907SKarl Rupp   } else *shared = (PetscBool) *tagvalp;
203e5c89e4eSSatish Balay   PetscFunctionReturn(0);
204e5c89e4eSSatish Balay }
205e5c89e4eSSatish Balay 
206e5c89e4eSSatish Balay /*@C
207e5c89e4eSSatish Balay    PetscSharedWorkingDirectory - Determines if all processors in a communicator share a
208e5c89e4eSSatish Balay          working directory or have different ones.
209e5c89e4eSSatish Balay 
210d083f849SBarry Smith    Collective
211e5c89e4eSSatish Balay 
212e5c89e4eSSatish Balay    Input Parameters:
213e5c89e4eSSatish Balay .  comm - MPI_Communicator that may share working directory
214e5c89e4eSSatish Balay 
215e5c89e4eSSatish Balay    Output Parameters:
216e5c89e4eSSatish Balay .  shared - PETSC_TRUE or PETSC_FALSE
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay    Options Database Keys:
219*10699b91SBarry Smith +    -shared_working_directory - indicates the directory is shared among the MPI ranks
220*10699b91SBarry Smith -    -not_shared_working_directory - indicates the directory is shared among the MPI ranks
221e5c89e4eSSatish Balay 
222e5c89e4eSSatish Balay    Environmental Variables:
223*10699b91SBarry Smith +     PETSC_SHARED_WORKING_DIRECTORY - indicates the directory is shared among the MPI ranks
224*10699b91SBarry Smith .     PETSC_NOT_SHARED_WORKING_DIRECTORY - indicates the directory is shared among the MPI ranks
225e5c89e4eSSatish Balay 
226e5c89e4eSSatish Balay    Level: developer
227e5c89e4eSSatish Balay 
228e5c89e4eSSatish Balay    Notes:
229e5c89e4eSSatish Balay    Stores the status as a MPI attribute so it does not have
230e5c89e4eSSatish Balay     to be redetermined each time.
231e5c89e4eSSatish Balay 
232e5c89e4eSSatish Balay       Assumes that all processors in a communicator either
233e5c89e4eSSatish Balay        1) have a common working directory or
234a8c7a070SBarry Smith        2) each has a separate working directory
235e5c89e4eSSatish Balay       eventually we can write a fancier one that determines which processors
236e5c89e4eSSatish Balay       share a common working directory.
237e5c89e4eSSatish Balay 
238e5c89e4eSSatish Balay    This will be very slow on runs with a large number of processors since
239e5c89e4eSSatish Balay    it requires O(p*p) file opens.
240e5c89e4eSSatish Balay 
241e5c89e4eSSatish Balay @*/
2427087cfbeSBarry Smith PetscErrorCode  PetscSharedWorkingDirectory(MPI_Comm comm,PetscBool  *shared)
243e5c89e4eSSatish Balay {
244e5c89e4eSSatish Balay   PetscErrorCode     ierr;
245e5c89e4eSSatish Balay   PetscMPIInt        size,rank,*tagvalp,sum,cnt,i;
246ace3abfcSBarry Smith   PetscBool          flg,iflg;
247e5c89e4eSSatish Balay   FILE               *fd;
248e5c89e4eSSatish Balay   static PetscMPIInt Petsc_WD_keyval = MPI_KEYVAL_INVALID;
249ed9cf6e9SBarry Smith   int                err;
250e5c89e4eSSatish Balay 
251e5c89e4eSSatish Balay   PetscFunctionBegin;
252ffc4695bSBarry Smith   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
253e5c89e4eSSatish Balay   if (size == 1) {
254e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
255e5c89e4eSSatish Balay     PetscFunctionReturn(0);
256e5c89e4eSSatish Balay   }
257e5c89e4eSSatish Balay 
2580298fd71SBarry Smith   ierr = PetscOptionsGetenv(comm,"PETSC_SHARED_WORKING_DIRECTORY",NULL,0,&flg);CHKERRQ(ierr);
259e5c89e4eSSatish Balay   if (flg) {
260e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
261e5c89e4eSSatish Balay     PetscFunctionReturn(0);
262e5c89e4eSSatish Balay   }
263e5c89e4eSSatish Balay 
2640298fd71SBarry Smith   ierr = PetscOptionsGetenv(comm,"PETSC_NOT_SHARED_WORKING_DIRECTORY",NULL,0,&flg);CHKERRQ(ierr);
265e5c89e4eSSatish Balay   if (flg) {
266e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
267e5c89e4eSSatish Balay     PetscFunctionReturn(0);
268e5c89e4eSSatish Balay   }
269e5c89e4eSSatish Balay 
270e5c89e4eSSatish Balay   if (Petsc_WD_keyval == MPI_KEYVAL_INVALID) {
271ffc4695bSBarry Smith     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,Petsc_DelTmpShared,&Petsc_WD_keyval,NULL);CHKERRMPI(ierr);
272e5c89e4eSSatish Balay   }
273e5c89e4eSSatish Balay 
274ffc4695bSBarry Smith   ierr = MPI_Comm_get_attr(comm,Petsc_WD_keyval,(void**)&tagvalp,(int*)&iflg);CHKERRMPI(ierr);
275e5c89e4eSSatish Balay   if (!iflg) {
276e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN];
277e5c89e4eSSatish Balay 
278e5c89e4eSSatish Balay     /* This communicator does not yet have a shared  attribute */
279854ce69bSBarry Smith     ierr = PetscMalloc1(1,&tagvalp);CHKERRQ(ierr);
280ffc4695bSBarry Smith     ierr = MPI_Comm_set_attr(comm,Petsc_WD_keyval,tagvalp);CHKERRMPI(ierr);
281e5c89e4eSSatish Balay 
282e5c89e4eSSatish Balay     ierr = PetscGetWorkingDirectory(filename,240);CHKERRQ(ierr);
283e5c89e4eSSatish Balay     ierr = PetscStrcat(filename,"/petsctestshared");CHKERRQ(ierr);
284ffc4695bSBarry Smith     ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
285e5c89e4eSSatish Balay 
286e5c89e4eSSatish Balay     /* each processor creates a  file and all the later ones check */
287e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
288e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
289e5c89e4eSSatish Balay     for (i=0; i<size-1; i++) {
290e5c89e4eSSatish Balay       if (rank == i) {
291e5c89e4eSSatish Balay         fd = fopen(filename,"w");
292e32f2f54SBarry Smith         if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to open test file %s",filename);
293ed9cf6e9SBarry Smith         err = fclose(fd);
294e32f2f54SBarry Smith         if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
295e5c89e4eSSatish Balay       }
296ffc4695bSBarry Smith       ierr = MPI_Barrier(comm);CHKERRMPI(ierr);
297e5c89e4eSSatish Balay       if (rank >= i) {
298e5c89e4eSSatish Balay         fd = fopen(filename,"r");
299a297a907SKarl Rupp         if (fd) cnt = 1;
300a297a907SKarl Rupp         else cnt = 0;
301e5c89e4eSSatish Balay         if (fd) {
302ed9cf6e9SBarry Smith           err = fclose(fd);
303e32f2f54SBarry Smith           if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on file");
304e5c89e4eSSatish Balay         }
305a297a907SKarl Rupp       } else cnt = 0;
306a297a907SKarl Rupp 
307b2566f29SBarry Smith       ierr = MPIU_Allreduce(&cnt,&sum,1,MPI_INT,MPI_SUM,comm);CHKERRQ(ierr);
308a297a907SKarl Rupp       if (rank == i) unlink(filename);
309e5c89e4eSSatish Balay 
310e5c89e4eSSatish Balay       if (sum == size) {
311e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
312e5c89e4eSSatish Balay         break;
313eb3354f8SBarry Smith       } else if (sum != 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Subset of processes share working directory");
314e5c89e4eSSatish Balay     }
315e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
316a297a907SKarl Rupp   } else *shared = (PetscBool) *tagvalp;
31702c9f0b5SLisandro Dalcin   ierr = PetscInfo1(NULL,"processors %s working directory\n",(*shared) ? "shared" : "do NOT share");CHKERRQ(ierr);
318e5c89e4eSSatish Balay   PetscFunctionReturn(0);
319e5c89e4eSSatish Balay }
320e5c89e4eSSatish Balay 
321e5c89e4eSSatish Balay 
322e5c89e4eSSatish Balay /*@C
3230c4f890aSBarry Smith     PetscFileRetrieve - Obtains a file from a URL or compressed
324e5c89e4eSSatish Balay         and copies into local disk space as uncompressed.
325e5c89e4eSSatish Balay 
326d083f849SBarry Smith     Collective
327e5c89e4eSSatish Balay 
328e5c89e4eSSatish Balay     Input Parameter:
3290c4f890aSBarry Smith +   comm     - processors accessing the file
3300c4f890aSBarry Smith .   url      - name of file, including entire URL (with or without .gz)
3310c4f890aSBarry Smith -   llen     - length of localname
332e5c89e4eSSatish Balay 
333e5c89e4eSSatish Balay     Output Parameter:
33408fb59bfSBarry Smith +   localname - name of local copy of file - valid on only process zero
33508fb59bfSBarry Smith -   found - if found or retrieved the file - valid on all processes
336e5c89e4eSSatish Balay 
33795452b02SPatrick Sanan     Notes:
33895452b02SPatrick Sanan     if the file already exists local this function just returns without downloading it.
339e5c89e4eSSatish Balay 
3400c4f890aSBarry Smith     Level: intermediate
341e5c89e4eSSatish Balay @*/
3420c4f890aSBarry Smith PetscErrorCode  PetscFileRetrieve(MPI_Comm comm,const char url[],char localname[],size_t llen,PetscBool  *found)
343e5c89e4eSSatish Balay {
34408fb59bfSBarry Smith   char           buffer[PETSC_MAX_PATH_LEN],*par,*tlocalname,name[PETSC_MAX_PATH_LEN];
345e5c89e4eSSatish Balay   FILE           *fp;
346e5c89e4eSSatish Balay   PetscErrorCode ierr;
347e5c89e4eSSatish Balay   PetscMPIInt    rank;
348e5c89e4eSSatish Balay   size_t         len = 0;
34908fb59bfSBarry Smith   PetscBool      flg1,flg2,flg3,flg4,download,compressed = PETSC_FALSE;
350e5c89e4eSSatish Balay 
351e5c89e4eSSatish Balay   PetscFunctionBegin;
352ffc4695bSBarry Smith   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
35308fb59bfSBarry Smith   if (!rank) {
354e5c89e4eSSatish Balay     *found = PETSC_FALSE;
355e5c89e4eSSatish Balay 
3560c4f890aSBarry Smith     ierr = PetscStrstr(url,".gz",&par);CHKERRQ(ierr);
35708fb59bfSBarry Smith     if (par) {
35808fb59bfSBarry Smith       ierr = PetscStrlen(par,&len);CHKERRQ(ierr);
35908fb59bfSBarry Smith       if (len == 3) compressed = PETSC_TRUE;
36008fb59bfSBarry Smith     }
361e5c89e4eSSatish Balay 
3620c4f890aSBarry Smith     ierr = PetscStrncmp(url,"ftp://",6,&flg1);CHKERRQ(ierr);
3630c4f890aSBarry Smith     ierr = PetscStrncmp(url,"http://",7,&flg2);CHKERRQ(ierr);
3640c4f890aSBarry Smith     ierr = PetscStrncmp(url,"file://",7,&flg3);CHKERRQ(ierr);
36508fb59bfSBarry Smith     ierr = PetscStrncmp(url,"https://",8,&flg4);CHKERRQ(ierr);
366a4772d12SBarry Smith     download = (PetscBool) (flg1 || flg2 || flg3 || flg4);
36708fb59bfSBarry Smith 
36808fb59bfSBarry Smith     if (!download && !compressed) {
3690c4f890aSBarry Smith       ierr = PetscStrncpy(localname,url,llen);CHKERRQ(ierr);
3700c4f890aSBarry Smith       ierr = PetscTestFile(url,'r',found);CHKERRQ(ierr);
371487e5849SBarry Smith       if (*found) {
3720c4f890aSBarry Smith         ierr = PetscInfo1(NULL,"Found file %s\n",url);CHKERRQ(ierr);
373487e5849SBarry Smith       } else {
3740c4f890aSBarry Smith         ierr = PetscInfo1(NULL,"Did not find file %s\n",url);CHKERRQ(ierr);
375487e5849SBarry Smith       }
37608fb59bfSBarry Smith       goto done;
377734f99bcSBarry Smith     }
378734f99bcSBarry Smith 
37905698389SBarry Smith     /* look for uncompressed file in requested directory */
38005698389SBarry Smith     if (compressed) {
38105698389SBarry Smith       ierr = PetscStrncpy(localname,url,llen);CHKERRQ(ierr);
38205698389SBarry Smith       ierr = PetscStrstr(localname,".gz",&par);CHKERRQ(ierr);
38305698389SBarry Smith       *par = 0; /* remove .gz extension */
38405698389SBarry Smith       ierr = PetscTestFile(localname,'r',found);CHKERRQ(ierr);
38505698389SBarry Smith       if (*found) goto done;
38605698389SBarry Smith     }
38705698389SBarry Smith 
38805698389SBarry Smith     /* look for file in current directory */
3890c4f890aSBarry Smith     ierr = PetscStrrchr(url,'/',&tlocalname);CHKERRQ(ierr);
3900c4f890aSBarry Smith     ierr = PetscStrncpy(localname,tlocalname,llen);CHKERRQ(ierr);
39108fb59bfSBarry Smith     if (compressed) {
39208fb59bfSBarry Smith       ierr = PetscStrstr(localname,".gz",&par);CHKERRQ(ierr);
39308fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
39408fb59bfSBarry Smith     }
3950c4f890aSBarry Smith     ierr = PetscTestFile(localname,'r',found);CHKERRQ(ierr);
39608fb59bfSBarry Smith     if (*found) goto done;
397e5c89e4eSSatish Balay 
39808fb59bfSBarry Smith     if (download) {
39908fb59bfSBarry Smith       /* local file is not already here so use curl to get it */
40008fb59bfSBarry Smith       ierr = PetscStrncpy(localname,tlocalname,llen);CHKERRQ(ierr);
401e8eec0a8SKarl Rupp       ierr = PetscStrcpy(buffer,"curl --fail --silent --show-error ");CHKERRQ(ierr);
40208fb59bfSBarry Smith       ierr = PetscStrcat(buffer,url);CHKERRQ(ierr);
40308fb59bfSBarry Smith       ierr = PetscStrcat(buffer," > ");CHKERRQ(ierr);
40408fb59bfSBarry Smith       ierr = PetscStrcat(buffer,localname);CHKERRQ(ierr);
405e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN)
40608fb59bfSBarry Smith       ierr = PetscPOpen(PETSC_COMM_SELF,NULL,buffer,"r",&fp);CHKERRQ(ierr);
407016831caSBarry Smith       ierr = PetscPClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr);
408e5c89e4eSSatish Balay #else
409e32f2f54SBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Cannot run external programs on this machine");
410e5c89e4eSSatish Balay #endif
4110c4f890aSBarry Smith       ierr = PetscTestFile(localname,'r',found);CHKERRQ(ierr);
4126e3a5469SBarry Smith       if (*found) {
4136e3a5469SBarry Smith         FILE      *fd;
4146e3a5469SBarry Smith         char      buf[1024],*str,*substring;
4156e3a5469SBarry Smith 
4166e3a5469SBarry Smith         /* check if the file didn't exist so it downloaded an HTML message instead */
4176e3a5469SBarry Smith         fd = fopen(localname,"r");
4186e3a5469SBarry Smith         if (!fd) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"PetscTestFile() indicates %s exists but fopen() cannot open it",localname);
4196e3a5469SBarry Smith         str = fgets(buf,sizeof(buf)-1,fd);
4206e3a5469SBarry Smith         while (str) {
4216e3a5469SBarry Smith           ierr = PetscStrstr(buf,"<!DOCTYPE html>",&substring);CHKERRQ(ierr);
4226e3a5469SBarry Smith           if (substring) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to download %s it does not appear to exist at this URL, dummy HTML file was downloaded",url);
4236e3a5469SBarry Smith           ierr = PetscStrstr(buf,"Not Found",&substring);CHKERRQ(ierr);
4246e3a5469SBarry Smith           if (substring) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to download %s it does not appear to exist at this URL, dummy HTML file was downloaded",url);
4256e3a5469SBarry Smith           str = fgets(buf,sizeof(buf)-1,fd);
4266e3a5469SBarry Smith         }
4276e3a5469SBarry Smith         fclose(fd);
4286e3a5469SBarry Smith       }
42908fb59bfSBarry Smith     } else if (compressed) {
43008fb59bfSBarry Smith       ierr = PetscTestFile(url,'r',found);CHKERRQ(ierr);
43108fb59bfSBarry Smith       if (!*found) goto done;
43208fb59bfSBarry Smith       ierr = PetscStrncpy(localname,url,llen);CHKERRQ(ierr);
43308fb59bfSBarry Smith     }
43408fb59bfSBarry Smith     if (compressed) {
43508fb59bfSBarry Smith       ierr = PetscStrrchr(localname,'/',&tlocalname);CHKERRQ(ierr);
43608fb59bfSBarry Smith       ierr = PetscStrncpy(name,tlocalname,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
43708fb59bfSBarry Smith       ierr = PetscStrstr(name,".gz",&par);CHKERRQ(ierr);
43808fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
43908fb59bfSBarry Smith       /* uncompress file */
44008fb59bfSBarry Smith       ierr = PetscStrcpy(buffer,"gzip -c -d ");CHKERRQ(ierr);
44108fb59bfSBarry Smith       ierr = PetscStrcat(buffer,localname);CHKERRQ(ierr);
44208fb59bfSBarry Smith       ierr = PetscStrcat(buffer," > ");CHKERRQ(ierr);
44308fb59bfSBarry Smith       ierr = PetscStrcat(buffer,name);CHKERRQ(ierr);
44408fb59bfSBarry Smith #if defined(PETSC_HAVE_POPEN)
44508fb59bfSBarry Smith       ierr = PetscPOpen(PETSC_COMM_SELF,NULL,buffer,"r",&fp);CHKERRQ(ierr);
446016831caSBarry Smith       ierr = PetscPClose(PETSC_COMM_SELF,fp);CHKERRQ(ierr);
44708fb59bfSBarry Smith #else
44808fb59bfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"Cannot run external programs on this machine");
44908fb59bfSBarry Smith #endif
45008fb59bfSBarry Smith       ierr = PetscStrncpy(localname,name,llen);CHKERRQ(ierr);
45108fb59bfSBarry Smith       ierr = PetscTestFile(localname,'r',found);CHKERRQ(ierr);
452e5c89e4eSSatish Balay     }
453e5c89e4eSSatish Balay   }
454955d42a0SBarry Smith   done:
455ffc4695bSBarry Smith   ierr = MPI_Bcast(found,1,MPIU_BOOL,0,comm);CHKERRMPI(ierr);
456ffc4695bSBarry Smith   ierr = MPI_Bcast(localname, llen, MPI_CHAR, 0, comm);CHKERRMPI(ierr);
457e5c89e4eSSatish Balay   PetscFunctionReturn(0);
458e5c89e4eSSatish Balay }
459