xref: /petsc/src/sys/fileio/fretrieve.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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 */
319371c9d4SSatish Balay PETSC_EXTERN PetscMPIInt MPIAPI Petsc_DelTmpShared(MPI_Comm comm, PetscMPIInt keyval, void *count_val, void *extra_state) {
32480cf27aSJed Brown   PetscFunctionBegin;
339566063dSJacob Faibussowitsch   PetscCallMPI(PetscInfo(NULL, "Deleting tmp/shared data in an MPI_Comm %ld\n", (long)comm));
349566063dSJacob Faibussowitsch   PetscCallMPI(PetscFree(count_val));
35480cf27aSJed Brown   PetscFunctionReturn(MPI_SUCCESS);
36480cf27aSJed Brown }
37e5c89e4eSSatish Balay 
38e5c89e4eSSatish Balay /*@C
39e5c89e4eSSatish Balay    PetscGetTmp - Gets the name of the tmp directory
40e5c89e4eSSatish Balay 
41d083f849SBarry Smith    Collective
42e5c89e4eSSatish Balay 
43e5c89e4eSSatish Balay    Input Parameters:
44e5c89e4eSSatish Balay +  comm - MPI_Communicator that may share /tmp
45e5c89e4eSSatish Balay -  len - length of string to hold name
46e5c89e4eSSatish Balay 
47f899ff85SJose E. Roman    Output Parameter:
48e5c89e4eSSatish Balay .  dir - directory name
49e5c89e4eSSatish Balay 
50e5c89e4eSSatish Balay    Options Database Keys:
5110699b91SBarry Smith +    -shared_tmp  - indicates the directory is shared among the MPI ranks
5210699b91SBarry Smith .    -not_shared_tmp - indicates the directory is not shared among the MPI ranks
5310699b91SBarry Smith -    -tmp tmpdir - name of the directory you wish to use as /tmp
54e5c89e4eSSatish Balay 
55e5c89e4eSSatish Balay    Environmental Variables:
5610699b91SBarry Smith +     PETSC_SHARED_TMP - indicates the directory is shared among the MPI ranks
5710699b91SBarry Smith .     PETSC_NOT_SHARED_TMP - indicates the directory is not shared among the MPI ranks
5810699b91SBarry Smith -     PETSC_TMP - name of the directory you wish to use as /tmp
59e5c89e4eSSatish Balay 
60e5c89e4eSSatish Balay    Level: developer
61e5c89e4eSSatish Balay 
62e5c89e4eSSatish Balay @*/
639371c9d4SSatish Balay PetscErrorCode PetscGetTmp(MPI_Comm comm, char dir[], size_t len) {
64ace3abfcSBarry Smith   PetscBool flg;
65e5c89e4eSSatish Balay 
66e5c89e4eSSatish Balay   PetscFunctionBegin;
679566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_TMP", dir, len, &flg));
68*48a46eb9SPierre Jolivet   if (!flg) PetscCall(PetscStrncpy(dir, "/tmp", len));
69e5c89e4eSSatish Balay   PetscFunctionReturn(0);
70e5c89e4eSSatish Balay }
71e5c89e4eSSatish Balay 
72e5c89e4eSSatish Balay /*@C
73e5c89e4eSSatish Balay    PetscSharedTmp - Determines if all processors in a communicator share a
74e5c89e4eSSatish Balay          /tmp or have different ones.
75e5c89e4eSSatish Balay 
76d083f849SBarry Smith    Collective
77e5c89e4eSSatish Balay 
78e5c89e4eSSatish Balay    Input Parameters:
79e5c89e4eSSatish Balay .  comm - MPI_Communicator that may share /tmp
80e5c89e4eSSatish Balay 
81e5c89e4eSSatish Balay    Output Parameters:
82e5c89e4eSSatish Balay .  shared - PETSC_TRUE or PETSC_FALSE
83e5c89e4eSSatish Balay 
84e5c89e4eSSatish Balay    Options Database Keys:
8510699b91SBarry Smith +    -shared_tmp  - indicates the directory is shared among the MPI ranks
8610699b91SBarry Smith .    -not_shared_tmp - indicates the directory is not shared among the MPI ranks
8710699b91SBarry Smith -    -tmp tmpdir - name of the directory you wish to use as /tmp
88e5c89e4eSSatish Balay 
89e5c89e4eSSatish Balay    Environmental Variables:
9010699b91SBarry Smith +     PETSC_SHARED_TMP  - indicates the directory is shared among the MPI ranks
9110699b91SBarry Smith .     PETSC_NOT_SHARED_TMP - indicates the directory is not shared among the MPI ranks
9210699b91SBarry Smith -     PETSC_TMP - name of the directory you wish to use as /tmp
93e5c89e4eSSatish Balay 
94e5c89e4eSSatish Balay    Level: developer
95e5c89e4eSSatish Balay 
96e5c89e4eSSatish Balay    Notes:
97e5c89e4eSSatish Balay    Stores the status as a MPI attribute so it does not have
98e5c89e4eSSatish Balay     to be redetermined each time.
99e5c89e4eSSatish Balay 
100e5c89e4eSSatish Balay       Assumes that all processors in a communicator either
101e5c89e4eSSatish Balay        1) have a common /tmp or
102a8c7a070SBarry Smith        2) each has a separate /tmp
103e5c89e4eSSatish Balay       eventually we can write a fancier one that determines which processors
104e5c89e4eSSatish Balay       share a common /tmp.
105e5c89e4eSSatish Balay 
106e5c89e4eSSatish Balay    This will be very slow on runs with a large number of processors since
107e5c89e4eSSatish Balay    it requires O(p*p) file opens.
108e5c89e4eSSatish Balay 
109e5c89e4eSSatish Balay    If the environmental variable PETSC_TMP is set it will use this directory
110e5c89e4eSSatish Balay   as the "/tmp" directory.
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay @*/
1139371c9d4SSatish Balay PetscErrorCode PetscSharedTmp(MPI_Comm comm, PetscBool *shared) {
114e5c89e4eSSatish Balay   PetscMPIInt        size, rank, *tagvalp, sum, cnt, i;
115ace3abfcSBarry Smith   PetscBool          flg, iflg;
116e5c89e4eSSatish Balay   FILE              *fd;
117e5c89e4eSSatish Balay   static PetscMPIInt Petsc_Tmp_keyval = MPI_KEYVAL_INVALID;
118ed9cf6e9SBarry Smith   int                err;
119e5c89e4eSSatish Balay 
120e5c89e4eSSatish Balay   PetscFunctionBegin;
1219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
122e5c89e4eSSatish Balay   if (size == 1) {
123e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
124e5c89e4eSSatish Balay     PetscFunctionReturn(0);
125e5c89e4eSSatish Balay   }
126e5c89e4eSSatish Balay 
1279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_SHARED_TMP", NULL, 0, &flg));
128e5c89e4eSSatish Balay   if (flg) {
129e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
130e5c89e4eSSatish Balay     PetscFunctionReturn(0);
131e5c89e4eSSatish Balay   }
132e5c89e4eSSatish Balay 
1339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_NOT_SHARED_TMP", NULL, 0, &flg));
134e5c89e4eSSatish Balay   if (flg) {
135e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
136e5c89e4eSSatish Balay     PetscFunctionReturn(0);
137e5c89e4eSSatish Balay   }
138e5c89e4eSSatish Balay 
139*48a46eb9SPierre Jolivet   if (Petsc_Tmp_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelTmpShared, &Petsc_Tmp_keyval, NULL));
140e5c89e4eSSatish Balay 
1419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_Tmp_keyval, (void **)&tagvalp, (int *)&iflg));
142e5c89e4eSSatish Balay   if (!iflg) {
143e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN], tmpname[PETSC_MAX_PATH_LEN];
144e5c89e4eSSatish Balay 
145e5c89e4eSSatish Balay     /* This communicator does not yet have a shared tmp attribute */
1469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &tagvalp));
1479566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_Tmp_keyval, tagvalp));
148e5c89e4eSSatish Balay 
1499566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetenv(comm, "PETSC_TMP", tmpname, 238, &iflg));
150e5c89e4eSSatish Balay     if (!iflg) {
1519566063dSJacob Faibussowitsch       PetscCall(PetscStrcpy(filename, "/tmp"));
152e5c89e4eSSatish Balay     } else {
1539566063dSJacob Faibussowitsch       PetscCall(PetscStrcpy(filename, tmpname));
154e5c89e4eSSatish Balay     }
155e5c89e4eSSatish Balay 
1569566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(filename, "/petsctestshared"));
1579566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
158e5c89e4eSSatish Balay 
159e5c89e4eSSatish Balay     /* each processor creates a /tmp file and all the later ones check */
160e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
161e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
162e5c89e4eSSatish Balay     for (i = 0; i < size - 1; i++) {
163e5c89e4eSSatish Balay       if (rank == i) {
164e5c89e4eSSatish Balay         fd = fopen(filename, "w");
16528b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open test file %s", filename);
166ed9cf6e9SBarry Smith         err = fclose(fd);
16728b400f6SJacob Faibussowitsch         PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
168e5c89e4eSSatish Balay       }
1699566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(comm));
170e5c89e4eSSatish Balay       if (rank >= i) {
171e5c89e4eSSatish Balay         fd = fopen(filename, "r");
172a297a907SKarl Rupp         if (fd) cnt = 1;
173a297a907SKarl Rupp         else cnt = 0;
174e5c89e4eSSatish Balay         if (fd) {
175ed9cf6e9SBarry Smith           err = fclose(fd);
17628b400f6SJacob Faibussowitsch           PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
177e5c89e4eSSatish Balay         }
178a297a907SKarl Rupp       } else cnt = 0;
179a297a907SKarl Rupp 
1801c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&cnt, &sum, 1, MPI_INT, MPI_SUM, comm));
181a297a907SKarl Rupp       if (rank == i) unlink(filename);
182e5c89e4eSSatish Balay 
183e5c89e4eSSatish Balay       if (sum == size) {
184e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
185e5c89e4eSSatish Balay         break;
18608401ef6SPierre Jolivet       } else PetscCheck(sum == 1, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Subset of processes share /tmp ");
187e5c89e4eSSatish Balay     }
188e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
1899566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "processors %s %s\n", (*shared) ? "share" : "do NOT share", (iflg ? tmpname : "/tmp")));
190a297a907SKarl Rupp   } else *shared = (PetscBool)*tagvalp;
191e5c89e4eSSatish Balay   PetscFunctionReturn(0);
192e5c89e4eSSatish Balay }
193e5c89e4eSSatish Balay 
194e5c89e4eSSatish Balay /*@C
195f1a722f8SMatthew G. Knepley   PetscSharedWorkingDirectory - Determines if all processors in a communicator share a working directory or have different ones.
196e5c89e4eSSatish Balay 
197d083f849SBarry Smith   Collective
198e5c89e4eSSatish Balay 
1996b867d5aSJose E. Roman   Input Parameter:
200e5c89e4eSSatish Balay . comm - MPI_Communicator that may share working directory
201e5c89e4eSSatish Balay 
2026b867d5aSJose E. Roman   Output Parameter:
203e5c89e4eSSatish Balay . shared - PETSC_TRUE or PETSC_FALSE
204e5c89e4eSSatish Balay 
205e5c89e4eSSatish Balay   Options Database Keys:
20610699b91SBarry Smith + -shared_working_directory - indicates the directory is shared among the MPI ranks
20710699b91SBarry Smith - -not_shared_working_directory - indicates the directory is shared among the MPI ranks
208e5c89e4eSSatish Balay 
209e5c89e4eSSatish Balay   Environmental Variables:
21010699b91SBarry Smith + PETSC_SHARED_WORKING_DIRECTORY - indicates the directory is shared among the MPI ranks
2113222ab0cSSatish Balay - PETSC_NOT_SHARED_WORKING_DIRECTORY - indicates the directory is shared among the MPI ranks
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay   Level: developer
214e5c89e4eSSatish Balay 
215e5c89e4eSSatish Balay   Notes:
216f1a722f8SMatthew G. Knepley   Stores the status as a MPI attribute so it does not have to be redetermined each time.
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay   Assumes that all processors in a communicator either
219f1a722f8SMatthew G. Knepley $   1) have a common working directory or
220f1a722f8SMatthew G. Knepley $   2) each has a separate working directory
221f1a722f8SMatthew G. Knepley   eventually we can write a fancier one that determines which processors share a common working directory.
222e5c89e4eSSatish Balay 
223f1a722f8SMatthew G. Knepley   This will be very slow on runs with a large number of processors since it requires O(p*p) file opens.
224e5c89e4eSSatish Balay @*/
2259371c9d4SSatish Balay PetscErrorCode PetscSharedWorkingDirectory(MPI_Comm comm, PetscBool *shared) {
226e5c89e4eSSatish Balay   PetscMPIInt        size, rank, *tagvalp, sum, cnt, i;
227ace3abfcSBarry Smith   PetscBool          flg, iflg;
228e5c89e4eSSatish Balay   FILE              *fd;
229e5c89e4eSSatish Balay   static PetscMPIInt Petsc_WD_keyval = MPI_KEYVAL_INVALID;
230ed9cf6e9SBarry Smith   int                err;
231e5c89e4eSSatish Balay 
232e5c89e4eSSatish Balay   PetscFunctionBegin;
2339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
234e5c89e4eSSatish Balay   if (size == 1) {
235e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
236e5c89e4eSSatish Balay     PetscFunctionReturn(0);
237e5c89e4eSSatish Balay   }
238e5c89e4eSSatish Balay 
2399566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_SHARED_WORKING_DIRECTORY", NULL, 0, &flg));
240e5c89e4eSSatish Balay   if (flg) {
241e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
242e5c89e4eSSatish Balay     PetscFunctionReturn(0);
243e5c89e4eSSatish Balay   }
244e5c89e4eSSatish Balay 
2459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_NOT_SHARED_WORKING_DIRECTORY", NULL, 0, &flg));
246e5c89e4eSSatish Balay   if (flg) {
247e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
248e5c89e4eSSatish Balay     PetscFunctionReturn(0);
249e5c89e4eSSatish Balay   }
250e5c89e4eSSatish Balay 
251*48a46eb9SPierre Jolivet   if (Petsc_WD_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelTmpShared, &Petsc_WD_keyval, NULL));
252e5c89e4eSSatish Balay 
2539566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_WD_keyval, (void **)&tagvalp, (int *)&iflg));
254e5c89e4eSSatish Balay   if (!iflg) {
255e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN];
256e5c89e4eSSatish Balay 
257e5c89e4eSSatish Balay     /* This communicator does not yet have a shared  attribute */
2589566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &tagvalp));
2599566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_WD_keyval, tagvalp));
260e5c89e4eSSatish Balay 
2619566063dSJacob Faibussowitsch     PetscCall(PetscGetWorkingDirectory(filename, 240));
2629566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(filename, "/petsctestshared"));
2639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
264e5c89e4eSSatish Balay 
265e5c89e4eSSatish Balay     /* each processor creates a  file and all the later ones check */
266e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
267e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
268e5c89e4eSSatish Balay     for (i = 0; i < size - 1; i++) {
269e5c89e4eSSatish Balay       if (rank == i) {
270e5c89e4eSSatish Balay         fd = fopen(filename, "w");
27128b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open test file %s", filename);
272ed9cf6e9SBarry Smith         err = fclose(fd);
27328b400f6SJacob Faibussowitsch         PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
274e5c89e4eSSatish Balay       }
2759566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(comm));
276e5c89e4eSSatish Balay       if (rank >= i) {
277e5c89e4eSSatish Balay         fd = fopen(filename, "r");
278a297a907SKarl Rupp         if (fd) cnt = 1;
279a297a907SKarl Rupp         else cnt = 0;
280e5c89e4eSSatish Balay         if (fd) {
281ed9cf6e9SBarry Smith           err = fclose(fd);
28228b400f6SJacob Faibussowitsch           PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
283e5c89e4eSSatish Balay         }
284a297a907SKarl Rupp       } else cnt = 0;
285a297a907SKarl Rupp 
2861c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&cnt, &sum, 1, MPI_INT, MPI_SUM, comm));
287a297a907SKarl Rupp       if (rank == i) unlink(filename);
288e5c89e4eSSatish Balay 
289e5c89e4eSSatish Balay       if (sum == size) {
290e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
291e5c89e4eSSatish Balay         break;
29208401ef6SPierre Jolivet       } else PetscCheck(sum == 1, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Subset of processes share working directory");
293e5c89e4eSSatish Balay     }
294e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
295a297a907SKarl Rupp   } else *shared = (PetscBool)*tagvalp;
2969566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "processors %s working directory\n", (*shared) ? "shared" : "do NOT share"));
297e5c89e4eSSatish Balay   PetscFunctionReturn(0);
298e5c89e4eSSatish Balay }
299e5c89e4eSSatish Balay 
300e5c89e4eSSatish Balay /*@C
3010c4f890aSBarry Smith     PetscFileRetrieve - Obtains a file from a URL or compressed
302e5c89e4eSSatish Balay         and copies into local disk space as uncompressed.
303e5c89e4eSSatish Balay 
304d083f849SBarry Smith     Collective
305e5c89e4eSSatish Balay 
306d8d19677SJose E. Roman     Input Parameters:
3070c4f890aSBarry Smith +   comm     - processors accessing the file
3080c4f890aSBarry Smith .   url      - name of file, including entire URL (with or without .gz)
3090c4f890aSBarry Smith -   llen     - length of localname
310e5c89e4eSSatish Balay 
311d8d19677SJose E. Roman     Output Parameters:
31208fb59bfSBarry Smith +   localname - name of local copy of file - valid on only process zero
31308fb59bfSBarry Smith -   found - if found or retrieved the file - valid on all processes
314e5c89e4eSSatish Balay 
31595452b02SPatrick Sanan     Notes:
31695452b02SPatrick Sanan     if the file already exists local this function just returns without downloading it.
317e5c89e4eSSatish Balay 
3180c4f890aSBarry Smith     Level: intermediate
319e5c89e4eSSatish Balay @*/
3209371c9d4SSatish Balay PetscErrorCode PetscFileRetrieve(MPI_Comm comm, const char url[], char localname[], size_t llen, PetscBool *found) {
32108fb59bfSBarry Smith   char        buffer[PETSC_MAX_PATH_LEN], *par, *tlocalname, name[PETSC_MAX_PATH_LEN];
322e5c89e4eSSatish Balay   FILE       *fp;
323e5c89e4eSSatish Balay   PetscMPIInt rank;
324e5c89e4eSSatish Balay   size_t      len = 0;
32508fb59bfSBarry Smith   PetscBool   flg1, flg2, flg3, flg4, download, compressed = PETSC_FALSE;
326e5c89e4eSSatish Balay 
327e5c89e4eSSatish Balay   PetscFunctionBegin;
3289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
329dd400576SPatrick Sanan   if (rank == 0) {
330e5c89e4eSSatish Balay     *found = PETSC_FALSE;
331e5c89e4eSSatish Balay 
3329566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(url, ".gz", &par));
33308fb59bfSBarry Smith     if (par) {
3349566063dSJacob Faibussowitsch       PetscCall(PetscStrlen(par, &len));
33508fb59bfSBarry Smith       if (len == 3) compressed = PETSC_TRUE;
33608fb59bfSBarry Smith     }
337e5c89e4eSSatish Balay 
3389566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "ftp://", 6, &flg1));
3399566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "http://", 7, &flg2));
3409566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "file://", 7, &flg3));
3419566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "https://", 8, &flg4));
342a4772d12SBarry Smith     download = (PetscBool)(flg1 || flg2 || flg3 || flg4);
34308fb59bfSBarry Smith 
34408fb59bfSBarry Smith     if (!download && !compressed) {
3459566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
3469566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(url, 'r', found));
347487e5849SBarry Smith       if (*found) {
3489566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Found file %s\n", url));
349487e5849SBarry Smith       } else {
3509566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Did not find file %s\n", url));
351487e5849SBarry Smith       }
35208fb59bfSBarry Smith       goto done;
353734f99bcSBarry Smith     }
354734f99bcSBarry Smith 
35505698389SBarry Smith     /* look for uncompressed file in requested directory */
35605698389SBarry Smith     if (compressed) {
3579566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
3589566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(localname, ".gz", &par));
35905698389SBarry Smith       *par = 0; /* remove .gz extension */
3609566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
36105698389SBarry Smith       if (*found) goto done;
36205698389SBarry Smith     }
36305698389SBarry Smith 
36405698389SBarry Smith     /* look for file in current directory */
3659566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(url, '/', &tlocalname));
3669566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(localname, tlocalname, llen));
36708fb59bfSBarry Smith     if (compressed) {
3689566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(localname, ".gz", &par));
36908fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
37008fb59bfSBarry Smith     }
3719566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(localname, 'r', found));
37208fb59bfSBarry Smith     if (*found) goto done;
373e5c89e4eSSatish Balay 
37408fb59bfSBarry Smith     if (download) {
37508fb59bfSBarry Smith       /* local file is not already here so use curl to get it */
3769566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, tlocalname, llen));
3779566063dSJacob Faibussowitsch       PetscCall(PetscStrcpy(buffer, "curl --fail --silent --show-error "));
3789566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(buffer, url));
3799566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(buffer, " > "));
3809566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(buffer, localname));
381e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN)
3829566063dSJacob Faibussowitsch       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, buffer, "r", &fp));
3839566063dSJacob Faibussowitsch       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
384e5c89e4eSSatish Balay #else
385e32f2f54SBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
386e5c89e4eSSatish Balay #endif
3879566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
3886e3a5469SBarry Smith       if (*found) {
3896e3a5469SBarry Smith         FILE *fd;
3906e3a5469SBarry Smith         char  buf[1024], *str, *substring;
3916e3a5469SBarry Smith 
3926e3a5469SBarry Smith         /* check if the file didn't exist so it downloaded an HTML message instead */
3936e3a5469SBarry Smith         fd = fopen(localname, "r");
39428b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscTestFile() indicates %s exists but fopen() cannot open it", localname);
3956e3a5469SBarry Smith         str = fgets(buf, sizeof(buf) - 1, fd);
3966e3a5469SBarry Smith         while (str) {
3979566063dSJacob Faibussowitsch           PetscCall(PetscStrstr(buf, "<!DOCTYPE html>", &substring));
39828b400f6SJacob Faibussowitsch           PetscCheck(!substring, 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);
3999566063dSJacob Faibussowitsch           PetscCall(PetscStrstr(buf, "Not Found", &substring));
40028b400f6SJacob Faibussowitsch           PetscCheck(!substring, 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);
4016e3a5469SBarry Smith           str = fgets(buf, sizeof(buf) - 1, fd);
4026e3a5469SBarry Smith         }
4036e3a5469SBarry Smith         fclose(fd);
4046e3a5469SBarry Smith       }
40508fb59bfSBarry Smith     } else if (compressed) {
4069566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(url, 'r', found));
40708fb59bfSBarry Smith       if (!*found) goto done;
4089566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
40908fb59bfSBarry Smith     }
41008fb59bfSBarry Smith     if (compressed) {
4119566063dSJacob Faibussowitsch       PetscCall(PetscStrrchr(localname, '/', &tlocalname));
4129566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(name, tlocalname, PETSC_MAX_PATH_LEN));
4139566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(name, ".gz", &par));
41408fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
41508fb59bfSBarry Smith       /* uncompress file */
4169566063dSJacob Faibussowitsch       PetscCall(PetscStrcpy(buffer, "gzip -c -d "));
4179566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(buffer, localname));
4189566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(buffer, " > "));
4199566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(buffer, name));
42008fb59bfSBarry Smith #if defined(PETSC_HAVE_POPEN)
4219566063dSJacob Faibussowitsch       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, buffer, "r", &fp));
4229566063dSJacob Faibussowitsch       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
42308fb59bfSBarry Smith #else
42408fb59bfSBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
42508fb59bfSBarry Smith #endif
4269566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, name, llen));
4279566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
428e5c89e4eSSatish Balay     }
429e5c89e4eSSatish Balay   }
430955d42a0SBarry Smith done:
4319566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(found, 1, MPIU_BOOL, 0, comm));
4329566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(localname, llen, MPI_CHAR, 0, comm));
433e5c89e4eSSatish Balay   PetscFunctionReturn(0);
434e5c89e4eSSatish Balay }
435