xref: /petsc/src/sys/fileio/fretrieve.c (revision bfbbc7b7132e4b411f537ad2e2bd0dcaa87bca64)
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
225ea2b939SDuncan Campbell #include <petsc/private/petscimpl.h>
23e5c89e4eSSatish Balay 
24480cf27aSJed Brown /*
25480cf27aSJed Brown    Private routine to delete tmp/shared storage
26480cf27aSJed Brown 
27480cf27aSJed Brown    This is called by MPI, not by users.
28480cf27aSJed Brown 
2912801b39SBarry Smith    Note: this is declared extern "C" because it is passed to MPI_Comm_create_keyval()
30480cf27aSJed Brown 
31480cf27aSJed Brown */
32d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscMPIInt MPIAPI Petsc_DelTmpShared(MPI_Comm comm, PetscMPIInt keyval, void *count_val, void *extra_state)
33d71ae5a4SJacob Faibussowitsch {
34480cf27aSJed Brown   PetscFunctionBegin;
359566063dSJacob Faibussowitsch   PetscCallMPI(PetscInfo(NULL, "Deleting tmp/shared data in an MPI_Comm %ld\n", (long)comm));
369566063dSJacob Faibussowitsch   PetscCallMPI(PetscFree(count_val));
37480cf27aSJed Brown   PetscFunctionReturn(MPI_SUCCESS);
38480cf27aSJed Brown }
39e5c89e4eSSatish Balay 
40e5c89e4eSSatish Balay /*@C
41e5c89e4eSSatish Balay    PetscGetTmp - Gets the name of the tmp directory
42e5c89e4eSSatish Balay 
43d083f849SBarry Smith    Collective
44e5c89e4eSSatish Balay 
45e5c89e4eSSatish Balay    Input Parameters:
46e5c89e4eSSatish Balay +  comm - MPI_Communicator that may share /tmp
47e5c89e4eSSatish Balay -  len - length of string to hold name
48e5c89e4eSSatish Balay 
49f899ff85SJose E. Roman    Output Parameter:
50e5c89e4eSSatish Balay .  dir - directory name
51e5c89e4eSSatish Balay 
52e5c89e4eSSatish Balay    Options Database Keys:
5310699b91SBarry Smith +    -shared_tmp  - indicates the directory is shared among the MPI ranks
5410699b91SBarry Smith .    -not_shared_tmp - indicates the directory is not shared among the MPI ranks
5510699b91SBarry Smith -    -tmp tmpdir - name of the directory you wish to use as /tmp
56e5c89e4eSSatish Balay 
57e5c89e4eSSatish Balay    Environmental Variables:
58811af0c4SBarry Smith +     `PETSC_SHARED_TMP` - indicates the directory is shared among the MPI ranks
59811af0c4SBarry Smith .     `PETSC_NOT_SHARED_TMP` - indicates the directory is not shared among the MPI ranks
60811af0c4SBarry Smith -     `PETSC_TMP` - name of the directory you wish to use as /tmp
61e5c89e4eSSatish Balay 
62e5c89e4eSSatish Balay    Level: developer
63e5c89e4eSSatish Balay 
64811af0c4SBarry Smith .seealso: `PetscSharedTmp()`, `PetscSharedWorkingDirectory()`, `PetscGetWorkingDirectory()`, `PetscGetHomeDirectory()`
65e5c89e4eSSatish Balay @*/
66d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGetTmp(MPI_Comm comm, char dir[], size_t len)
67d71ae5a4SJacob Faibussowitsch {
68ace3abfcSBarry Smith   PetscBool flg;
69e5c89e4eSSatish Balay 
70e5c89e4eSSatish Balay   PetscFunctionBegin;
719566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_TMP", dir, len, &flg));
7248a46eb9SPierre Jolivet   if (!flg) PetscCall(PetscStrncpy(dir, "/tmp", len));
733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
74e5c89e4eSSatish Balay }
75e5c89e4eSSatish Balay 
76e5c89e4eSSatish Balay /*@C
77e5c89e4eSSatish Balay    PetscSharedTmp - Determines if all processors in a communicator share a
78e5c89e4eSSatish Balay          /tmp or have different ones.
79e5c89e4eSSatish Balay 
80d083f849SBarry Smith    Collective
81e5c89e4eSSatish Balay 
82811af0c4SBarry Smith    Input Parameter:
83e5c89e4eSSatish Balay .  comm - MPI_Communicator that may share /tmp
84e5c89e4eSSatish Balay 
85811af0c4SBarry Smith    Output Parameter:
86811af0c4SBarry Smith .  shared - `PETSC_TRUE` or `PETSC_FALSE`
87e5c89e4eSSatish Balay 
88e5c89e4eSSatish Balay    Options Database Keys:
8910699b91SBarry Smith +    -shared_tmp  - indicates the directory is shared among the MPI ranks
9010699b91SBarry Smith .    -not_shared_tmp - indicates the directory is not shared among the MPI ranks
9110699b91SBarry Smith -    -tmp tmpdir - name of the directory you wish to use as /tmp
92e5c89e4eSSatish Balay 
93e5c89e4eSSatish Balay    Environmental Variables:
94811af0c4SBarry Smith +     `PETSC_SHARED_TMP`  - indicates the directory is shared among the MPI ranks
95811af0c4SBarry Smith .     `PETSC_NOT_SHARED_TMP` - indicates the directory is not shared among the MPI ranks
96811af0c4SBarry Smith -     `PETSC_TMP` - name of the directory you wish to use as /tmp
97e5c89e4eSSatish Balay 
98e5c89e4eSSatish Balay    Level: developer
99e5c89e4eSSatish Balay 
100e5c89e4eSSatish Balay    Notes:
101e5c89e4eSSatish Balay    Stores the status as a MPI attribute so it does not have
102e5c89e4eSSatish Balay     to be redetermined each time.
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay       Assumes that all processors in a communicator either
105e5c89e4eSSatish Balay        1) have a common /tmp or
106a8c7a070SBarry Smith        2) each has a separate /tmp
107e5c89e4eSSatish Balay       eventually we can write a fancier one that determines which processors
108e5c89e4eSSatish Balay       share a common /tmp.
109e5c89e4eSSatish Balay 
110e5c89e4eSSatish Balay    This will be very slow on runs with a large number of processors since
111e5c89e4eSSatish Balay    it requires O(p*p) file opens.
112e5c89e4eSSatish Balay 
113*bfbbc7b7SBarry Smith    If the environmental variable `PETSC_TMP` is set it will use this directory
114e5c89e4eSSatish Balay   as the "/tmp" directory.
115e5c89e4eSSatish Balay 
116811af0c4SBarry Smith .seealso: `PetscGetTmp()`, `PetscSharedWorkingDirectory()`, `PetscGetWorkingDirectory()`, `PetscGetHomeDirectory()`
117e5c89e4eSSatish Balay @*/
118d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSharedTmp(MPI_Comm comm, PetscBool *shared)
119d71ae5a4SJacob Faibussowitsch {
120e5c89e4eSSatish Balay   PetscMPIInt size, rank, *tagvalp, sum, cnt, i;
121ace3abfcSBarry Smith   PetscBool   flg, iflg;
122e5c89e4eSSatish Balay   FILE       *fd;
123ed9cf6e9SBarry Smith   int         err;
124e5c89e4eSSatish Balay 
125e5c89e4eSSatish Balay   PetscFunctionBegin;
1269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
127e5c89e4eSSatish Balay   if (size == 1) {
128e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
1293ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
130e5c89e4eSSatish Balay   }
131e5c89e4eSSatish Balay 
1329566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_SHARED_TMP", NULL, 0, &flg));
133e5c89e4eSSatish Balay   if (flg) {
134e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
1353ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
136e5c89e4eSSatish Balay   }
137e5c89e4eSSatish Balay 
1389566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_NOT_SHARED_TMP", NULL, 0, &flg));
139e5c89e4eSSatish Balay   if (flg) {
140e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
1413ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
142e5c89e4eSSatish Balay   }
143e5c89e4eSSatish Balay 
1445ea2b939SDuncan Campbell   if (Petsc_SharedTmp_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelTmpShared, &Petsc_SharedTmp_keyval, NULL));
145e5c89e4eSSatish Balay 
1465ea2b939SDuncan Campbell   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_SharedTmp_keyval, (void **)&tagvalp, (int *)&iflg));
147e5c89e4eSSatish Balay   if (!iflg) {
148e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN], tmpname[PETSC_MAX_PATH_LEN];
149e5c89e4eSSatish Balay 
150e5c89e4eSSatish Balay     /* This communicator does not yet have a shared tmp attribute */
1519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &tagvalp));
1525ea2b939SDuncan Campbell     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_SharedTmp_keyval, tagvalp));
153e5c89e4eSSatish Balay 
1549566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetenv(comm, "PETSC_TMP", tmpname, 238, &iflg));
155e5c89e4eSSatish Balay     if (!iflg) {
156c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(filename, "/tmp", sizeof(filename)));
157e5c89e4eSSatish Balay     } else {
158c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(filename, tmpname, sizeof(filename)));
159e5c89e4eSSatish Balay     }
160e5c89e4eSSatish Balay 
161c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(filename, "/petsctestshared", sizeof(filename)));
1629566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
163e5c89e4eSSatish Balay 
164e5c89e4eSSatish Balay     /* each processor creates a /tmp file and all the later ones check */
165e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
166e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
167e5c89e4eSSatish Balay     for (i = 0; i < size - 1; i++) {
168e5c89e4eSSatish Balay       if (rank == i) {
169e5c89e4eSSatish Balay         fd = fopen(filename, "w");
17028b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open test file %s", filename);
171ed9cf6e9SBarry Smith         err = fclose(fd);
17228b400f6SJacob Faibussowitsch         PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
173e5c89e4eSSatish Balay       }
1749566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(comm));
175e5c89e4eSSatish Balay       if (rank >= i) {
176e5c89e4eSSatish Balay         fd = fopen(filename, "r");
177a297a907SKarl Rupp         if (fd) cnt = 1;
178a297a907SKarl Rupp         else cnt = 0;
179e5c89e4eSSatish Balay         if (fd) {
180ed9cf6e9SBarry Smith           err = fclose(fd);
18128b400f6SJacob Faibussowitsch           PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
182e5c89e4eSSatish Balay         }
183a297a907SKarl Rupp       } else cnt = 0;
184a297a907SKarl Rupp 
1851c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&cnt, &sum, 1, MPI_INT, MPI_SUM, comm));
186a297a907SKarl Rupp       if (rank == i) unlink(filename);
187e5c89e4eSSatish Balay 
188e5c89e4eSSatish Balay       if (sum == size) {
189e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
190e5c89e4eSSatish Balay         break;
19108401ef6SPierre Jolivet       } else PetscCheck(sum == 1, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Subset of processes share /tmp ");
192e5c89e4eSSatish Balay     }
193e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
1949566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL, "processors %s %s\n", (*shared) ? "share" : "do NOT share", (iflg ? tmpname : "/tmp")));
195a297a907SKarl Rupp   } else *shared = (PetscBool)*tagvalp;
1963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
197e5c89e4eSSatish Balay }
198e5c89e4eSSatish Balay 
199e5c89e4eSSatish Balay /*@C
200f1a722f8SMatthew G. Knepley   PetscSharedWorkingDirectory - Determines if all processors in a communicator share a working directory or have different ones.
201e5c89e4eSSatish Balay 
202d083f849SBarry Smith   Collective
203e5c89e4eSSatish Balay 
2046b867d5aSJose E. Roman   Input Parameter:
205e5c89e4eSSatish Balay . comm - MPI_Communicator that may share working directory
206e5c89e4eSSatish Balay 
2076b867d5aSJose E. Roman   Output Parameter:
208811af0c4SBarry Smith . shared - `PETSC_TRUE` or `PETSC_FALSE`
209e5c89e4eSSatish Balay 
210e5c89e4eSSatish Balay   Options Database Keys:
21110699b91SBarry Smith + -shared_working_directory - indicates the directory is shared among the MPI ranks
21210699b91SBarry Smith - -not_shared_working_directory - indicates the directory is shared among the MPI ranks
213e5c89e4eSSatish Balay 
214e5c89e4eSSatish Balay   Environmental Variables:
215811af0c4SBarry Smith + `PETSC_SHARED_WORKING_DIRECTORY` - indicates the directory is shared among the MPI ranks
216811af0c4SBarry Smith - `PETSC_NOT_SHARED_WORKING_DIRECTORY` - indicates the directory is shared among the MPI ranks
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay   Level: developer
219e5c89e4eSSatish Balay 
220e5c89e4eSSatish Balay   Notes:
221f1a722f8SMatthew G. Knepley   Stores the status as a MPI attribute so it does not have to be redetermined each time.
222e5c89e4eSSatish Balay 
223e5c89e4eSSatish Balay   Assumes that all processors in a communicator either
224*bfbbc7b7SBarry Smith .vb
225*bfbbc7b7SBarry Smith    1) have a common working directory or
226*bfbbc7b7SBarry Smith    2) each has a separate working directory
227*bfbbc7b7SBarry Smith .ve
228f1a722f8SMatthew G. Knepley   eventually we can write a fancier one that determines which processors share a common working directory.
229e5c89e4eSSatish Balay 
230f1a722f8SMatthew G. Knepley   This will be very slow on runs with a large number of processors since it requires O(p*p) file opens.
231811af0c4SBarry Smith 
232811af0c4SBarry Smith .seealso: `PetscGetTmp()`, `PetscSharedTmp()`, `PetscGetWorkingDirectory()`, `PetscGetHomeDirectory()`
233e5c89e4eSSatish Balay @*/
234d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSharedWorkingDirectory(MPI_Comm comm, PetscBool *shared)
235d71ae5a4SJacob Faibussowitsch {
236e5c89e4eSSatish Balay   PetscMPIInt size, rank, *tagvalp, sum, cnt, i;
237ace3abfcSBarry Smith   PetscBool   flg, iflg;
238e5c89e4eSSatish Balay   FILE       *fd;
239ed9cf6e9SBarry Smith   int         err;
240e5c89e4eSSatish Balay 
241e5c89e4eSSatish Balay   PetscFunctionBegin;
2429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
243e5c89e4eSSatish Balay   if (size == 1) {
244e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
2453ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
246e5c89e4eSSatish Balay   }
247e5c89e4eSSatish Balay 
2489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_SHARED_WORKING_DIRECTORY", NULL, 0, &flg));
249e5c89e4eSSatish Balay   if (flg) {
250e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
2513ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
252e5c89e4eSSatish Balay   }
253e5c89e4eSSatish Balay 
2549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_NOT_SHARED_WORKING_DIRECTORY", NULL, 0, &flg));
255e5c89e4eSSatish Balay   if (flg) {
256e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
2573ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
258e5c89e4eSSatish Balay   }
259e5c89e4eSSatish Balay 
2605ea2b939SDuncan Campbell   if (Petsc_SharedWD_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelTmpShared, &Petsc_SharedWD_keyval, NULL));
261e5c89e4eSSatish Balay 
2625ea2b939SDuncan Campbell   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_SharedWD_keyval, (void **)&tagvalp, (int *)&iflg));
263e5c89e4eSSatish Balay   if (!iflg) {
264e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN];
265e5c89e4eSSatish Balay 
266e5c89e4eSSatish Balay     /* This communicator does not yet have a shared  attribute */
2679566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &tagvalp));
2685ea2b939SDuncan Campbell     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_SharedWD_keyval, tagvalp));
269e5c89e4eSSatish Balay 
2709566063dSJacob Faibussowitsch     PetscCall(PetscGetWorkingDirectory(filename, 240));
271c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(filename, "/petsctestshared", sizeof(filename)));
2729566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
273e5c89e4eSSatish Balay 
274e5c89e4eSSatish Balay     /* each processor creates a  file and all the later ones check */
275e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
276e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
277e5c89e4eSSatish Balay     for (i = 0; i < size - 1; i++) {
278e5c89e4eSSatish Balay       if (rank == i) {
279e5c89e4eSSatish Balay         fd = fopen(filename, "w");
28028b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open test file %s", filename);
281ed9cf6e9SBarry Smith         err = fclose(fd);
28228b400f6SJacob Faibussowitsch         PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
283e5c89e4eSSatish Balay       }
2849566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(comm));
285e5c89e4eSSatish Balay       if (rank >= i) {
286e5c89e4eSSatish Balay         fd = fopen(filename, "r");
287a297a907SKarl Rupp         if (fd) cnt = 1;
288a297a907SKarl Rupp         else cnt = 0;
289e5c89e4eSSatish Balay         if (fd) {
290ed9cf6e9SBarry Smith           err = fclose(fd);
29128b400f6SJacob Faibussowitsch           PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
292e5c89e4eSSatish Balay         }
293a297a907SKarl Rupp       } else cnt = 0;
294a297a907SKarl Rupp 
2951c2dc1cbSBarry Smith       PetscCall(MPIU_Allreduce(&cnt, &sum, 1, MPI_INT, MPI_SUM, comm));
296a297a907SKarl Rupp       if (rank == i) unlink(filename);
297e5c89e4eSSatish Balay 
298e5c89e4eSSatish Balay       if (sum == size) {
299e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
300e5c89e4eSSatish Balay         break;
30108401ef6SPierre Jolivet       } else PetscCheck(sum == 1, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Subset of processes share working directory");
302e5c89e4eSSatish Balay     }
303e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
304a297a907SKarl Rupp   } else *shared = (PetscBool)*tagvalp;
3059566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "processors %s working directory\n", (*shared) ? "shared" : "do NOT share"));
3063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
307e5c89e4eSSatish Balay }
308e5c89e4eSSatish Balay 
309e5c89e4eSSatish Balay /*@C
310*bfbbc7b7SBarry Smith     PetscFileRetrieve - Obtains a file from a URL or a compressed file
311e5c89e4eSSatish Balay         and copies into local disk space as uncompressed.
312e5c89e4eSSatish Balay 
313d083f849SBarry Smith     Collective
314e5c89e4eSSatish Balay 
315d8d19677SJose E. Roman     Input Parameters:
3160c4f890aSBarry Smith +   comm     - processors accessing the file
3170c4f890aSBarry Smith .   url      - name of file, including entire URL (with or without .gz)
3180c4f890aSBarry Smith -   llen     - length of localname
319e5c89e4eSSatish Balay 
320d8d19677SJose E. Roman     Output Parameters:
32108fb59bfSBarry Smith +   localname - name of local copy of file - valid on only process zero
32208fb59bfSBarry Smith -   found - if found or retrieved the file - valid on all processes
323e5c89e4eSSatish Balay 
3242fe279fdSBarry Smith     Level: intermediate
3252fe279fdSBarry Smith 
326811af0c4SBarry Smith     Note:
32795452b02SPatrick Sanan     if the file already exists local this function just returns without downloading it.
328e5c89e4eSSatish Balay 
329e5c89e4eSSatish Balay @*/
330d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFileRetrieve(MPI_Comm comm, const char url[], char localname[], size_t llen, PetscBool *found)
331d71ae5a4SJacob Faibussowitsch {
332bbcf679cSJacob Faibussowitsch   char        buffer[PETSC_MAX_PATH_LEN], *par = NULL, *tlocalname = NULL, name[PETSC_MAX_PATH_LEN];
333e5c89e4eSSatish Balay   FILE       *fp;
334e5c89e4eSSatish Balay   PetscMPIInt rank;
335e5c89e4eSSatish Balay   size_t      len = 0;
33608fb59bfSBarry Smith   PetscBool   flg1, flg2, flg3, flg4, download, compressed = PETSC_FALSE;
337e5c89e4eSSatish Balay 
338e5c89e4eSSatish Balay   PetscFunctionBegin;
3399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
340dd400576SPatrick Sanan   if (rank == 0) {
341e5c89e4eSSatish Balay     *found = PETSC_FALSE;
342e5c89e4eSSatish Balay 
3439566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(url, ".gz", &par));
34408fb59bfSBarry Smith     if (par) {
3459566063dSJacob Faibussowitsch       PetscCall(PetscStrlen(par, &len));
34608fb59bfSBarry Smith       if (len == 3) compressed = PETSC_TRUE;
34708fb59bfSBarry Smith     }
348e5c89e4eSSatish Balay 
3499566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "ftp://", 6, &flg1));
3509566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "http://", 7, &flg2));
3519566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "file://", 7, &flg3));
3529566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "https://", 8, &flg4));
353a4772d12SBarry Smith     download = (PetscBool)(flg1 || flg2 || flg3 || flg4);
35408fb59bfSBarry Smith 
35508fb59bfSBarry Smith     if (!download && !compressed) {
3569566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
3579566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(url, 'r', found));
358487e5849SBarry Smith       if (*found) {
3599566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Found file %s\n", url));
360487e5849SBarry Smith       } else {
3619566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Did not find file %s\n", url));
362487e5849SBarry Smith       }
36308fb59bfSBarry Smith       goto done;
364734f99bcSBarry Smith     }
365734f99bcSBarry Smith 
36605698389SBarry Smith     /* look for uncompressed file in requested directory */
36705698389SBarry Smith     if (compressed) {
3689566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
3699566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(localname, ".gz", &par));
37005698389SBarry Smith       *par = 0; /* remove .gz extension */
3719566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
37205698389SBarry Smith       if (*found) goto done;
37305698389SBarry Smith     }
37405698389SBarry Smith 
37505698389SBarry Smith     /* look for file in current directory */
3769566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(url, '/', &tlocalname));
3779566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(localname, tlocalname, llen));
37808fb59bfSBarry Smith     if (compressed) {
3799566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(localname, ".gz", &par));
38008fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
38108fb59bfSBarry Smith     }
3829566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(localname, 'r', found));
38308fb59bfSBarry Smith     if (*found) goto done;
384e5c89e4eSSatish Balay 
38508fb59bfSBarry Smith     if (download) {
38608fb59bfSBarry Smith       /* local file is not already here so use curl to get it */
3879566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, tlocalname, llen));
388c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(buffer, "curl --fail --silent --show-error ", sizeof(buffer)));
389c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, url, sizeof(buffer)));
390c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, " > ", sizeof(buffer)));
391c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, localname, sizeof(buffer)));
392e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN)
3939566063dSJacob Faibussowitsch       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, buffer, "r", &fp));
3949566063dSJacob Faibussowitsch       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
395e5c89e4eSSatish Balay #else
396e32f2f54SBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
397e5c89e4eSSatish Balay #endif
3989566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
3996e3a5469SBarry Smith       if (*found) {
4006e3a5469SBarry Smith         FILE *fd;
4016e3a5469SBarry Smith         char  buf[1024], *str, *substring;
4026e3a5469SBarry Smith 
4036e3a5469SBarry Smith         /* check if the file didn't exist so it downloaded an HTML message instead */
4046e3a5469SBarry Smith         fd = fopen(localname, "r");
40528b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscTestFile() indicates %s exists but fopen() cannot open it", localname);
4066e3a5469SBarry Smith         str = fgets(buf, sizeof(buf) - 1, fd);
4076e3a5469SBarry Smith         while (str) {
4089566063dSJacob Faibussowitsch           PetscCall(PetscStrstr(buf, "<!DOCTYPE html>", &substring));
40928b400f6SJacob 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);
4109566063dSJacob Faibussowitsch           PetscCall(PetscStrstr(buf, "Not Found", &substring));
41128b400f6SJacob 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);
4126e3a5469SBarry Smith           str = fgets(buf, sizeof(buf) - 1, fd);
4136e3a5469SBarry Smith         }
4146e3a5469SBarry Smith         fclose(fd);
4156e3a5469SBarry Smith       }
41608fb59bfSBarry Smith     } else if (compressed) {
4179566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(url, 'r', found));
41808fb59bfSBarry Smith       if (!*found) goto done;
4199566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
42008fb59bfSBarry Smith     }
42108fb59bfSBarry Smith     if (compressed) {
4229566063dSJacob Faibussowitsch       PetscCall(PetscStrrchr(localname, '/', &tlocalname));
4239566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(name, tlocalname, PETSC_MAX_PATH_LEN));
4249566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(name, ".gz", &par));
42508fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
42608fb59bfSBarry Smith       /* uncompress file */
427c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(buffer, "gzip -c -d ", sizeof(buffer)));
428c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, localname, sizeof(buffer)));
429c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, " > ", sizeof(buffer)));
430c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, name, sizeof(buffer)));
43108fb59bfSBarry Smith #if defined(PETSC_HAVE_POPEN)
4329566063dSJacob Faibussowitsch       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, buffer, "r", &fp));
4339566063dSJacob Faibussowitsch       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
43408fb59bfSBarry Smith #else
43508fb59bfSBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
43608fb59bfSBarry Smith #endif
4379566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, name, llen));
4389566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
439e5c89e4eSSatish Balay     }
440e5c89e4eSSatish Balay   }
441955d42a0SBarry Smith done:
4429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(found, 1, MPIU_BOOL, 0, comm));
4439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(localname, llen, MPI_CHAR, 0, comm));
4443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
445e5c89e4eSSatish Balay }
446