xref: /petsc/src/sys/fileio/fretrieve.c (revision 8112c1cbf372cb53bf7c5aca994a84a6a303db4d)
1e5c89e4eSSatish Balay /*
2e5c89e4eSSatish Balay       Code for opening and closing files.
3e5c89e4eSSatish Balay */
4c6db04a5SJed Brown #include <petscsys.h>
5e5c89e4eSSatish Balay #if defined(PETSC_HAVE_PWD_H)
6e5c89e4eSSatish Balay   #include <pwd.h>
7e5c89e4eSSatish Balay #endif
8e5c89e4eSSatish Balay #include <ctype.h>
9e5c89e4eSSatish Balay #include <sys/stat.h>
10e5c89e4eSSatish Balay #if defined(PETSC_HAVE_UNISTD_H)
11e5c89e4eSSatish Balay   #include <unistd.h>
12e5c89e4eSSatish Balay #endif
13e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SYS_UTSNAME_H)
14e5c89e4eSSatish Balay   #include <sys/utsname.h>
15e5c89e4eSSatish Balay #endif
16e5c89e4eSSatish Balay #include <fcntl.h>
17e5c89e4eSSatish Balay #include <time.h>
18e5c89e4eSSatish Balay #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
19e5c89e4eSSatish Balay   #include <sys/systeminfo.h>
20e5c89e4eSSatish Balay #endif
215ea2b939SDuncan Campbell #include <petsc/private/petscimpl.h>
22e5c89e4eSSatish Balay 
23480cf27aSJed Brown /*
24480cf27aSJed Brown    Private routine to delete tmp/shared storage
25480cf27aSJed Brown 
2621532e8aSBarry Smith    This is called by MPI, not by users, when communicator attributes are deleted
27480cf27aSJed Brown 
28480cf27aSJed Brown */
Petsc_DelTmpShared(MPI_Comm comm,PetscMPIInt keyval,void * count_val,void * extra_state)29d6acfc2dSPierre Jolivet static PetscMPIInt MPIAPI Petsc_DelTmpShared(MPI_Comm comm, PetscMPIInt keyval, void *count_val, void *extra_state)
30d71ae5a4SJacob Faibussowitsch {
31480cf27aSJed Brown   PetscFunctionBegin;
327c5b2466SBarry Smith   PetscCallReturnMPI(PetscInfo(NULL, "Deleting tmp/shared data in an MPI_Comm %ld\n", (long)comm));
337c5b2466SBarry Smith   PetscCallReturnMPI(PetscFree(count_val));
34480cf27aSJed Brown   PetscFunctionReturn(MPI_SUCCESS);
35480cf27aSJed Brown }
36e5c89e4eSSatish Balay 
3710450e9eSJacob Faibussowitsch // "Unknown section 'Environmental Variables'"
3810450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
39e5c89e4eSSatish Balay /*@C
4021532e8aSBarry Smith   PetscGetTmp - Gets the name of the "tmp" directory, often this is `/tmp`
41e5c89e4eSSatish Balay 
42d083f849SBarry Smith   Collective
43e5c89e4eSSatish Balay 
44e5c89e4eSSatish Balay   Input Parameters:
4521532e8aSBarry Smith + comm - MPI_Communicator that may share tmp
46e5c89e4eSSatish Balay - len  - length of string to hold name
47e5c89e4eSSatish Balay 
48f899ff85SJose E. Roman   Output Parameter:
49e5c89e4eSSatish Balay . dir - directory name
50e5c89e4eSSatish Balay 
51e5c89e4eSSatish Balay   Options Database Keys:
5221532e8aSBarry Smith + -shared_tmp     - indicates the directory is known to be shared among the MPI processes
5321532e8aSBarry Smith . -not_shared_tmp - indicates the directory is known to be not shared among the MPI processes
5421532e8aSBarry Smith - -tmp tmpdir     - name of the directory you wish to use as tmp
55e5c89e4eSSatish Balay 
56e5c89e4eSSatish Balay   Environmental Variables:
5721532e8aSBarry Smith + `PETSC_SHARED_TMP`     - indicates the directory is known to be shared among the MPI processes
5821532e8aSBarry Smith . `PETSC_NOT_SHARED_TMP` - indicates the directory is known to be not shared among the MPI processes
5921532e8aSBarry Smith - `PETSC_TMP`            - name of the directory you wish to use as tmp
60e5c89e4eSSatish Balay 
61e5c89e4eSSatish Balay   Level: developer
62e5c89e4eSSatish Balay 
63811af0c4SBarry Smith .seealso: `PetscSharedTmp()`, `PetscSharedWorkingDirectory()`, `PetscGetWorkingDirectory()`, `PetscGetHomeDirectory()`
64e5c89e4eSSatish Balay @*/
PetscGetTmp(MPI_Comm comm,char dir[],size_t len)65d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGetTmp(MPI_Comm comm, char dir[], size_t len)
66d71ae5a4SJacob Faibussowitsch {
67ace3abfcSBarry Smith   PetscBool flg;
68e5c89e4eSSatish Balay 
69e5c89e4eSSatish Balay   PetscFunctionBegin;
709566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_TMP", dir, len, &flg));
7148a46eb9SPierre Jolivet   if (!flg) PetscCall(PetscStrncpy(dir, "/tmp", len));
723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
73e5c89e4eSSatish Balay }
74e5c89e4eSSatish Balay 
7510450e9eSJacob Faibussowitsch // "Unknown section 'Environmental Variables'"
7610450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
77cc4c1da9SBarry Smith /*@
78e5c89e4eSSatish Balay   PetscSharedTmp - Determines if all processors in a communicator share a
7921532e8aSBarry Smith   tmp directory or have different ones.
80e5c89e4eSSatish Balay 
81d083f849SBarry Smith   Collective
82e5c89e4eSSatish Balay 
83811af0c4SBarry Smith   Input Parameter:
8421532e8aSBarry Smith . comm - MPI_Communicator that may share tmp
85e5c89e4eSSatish Balay 
86811af0c4SBarry Smith   Output Parameter:
87811af0c4SBarry Smith . shared - `PETSC_TRUE` or `PETSC_FALSE`
88e5c89e4eSSatish Balay 
89e5c89e4eSSatish Balay   Options Database Keys:
9021532e8aSBarry Smith + -shared_tmp     - indicates the directory is known to be shared among the MPI processes
9121532e8aSBarry Smith . -not_shared_tmp - indicates the directory is known to be not shared among the MPI processes
9221532e8aSBarry Smith - -tmp tmpdir     - name of the directory you wish to use as tmp
93e5c89e4eSSatish Balay 
94e5c89e4eSSatish Balay   Environmental Variables:
9521532e8aSBarry Smith + `PETSC_SHARED_TMP`     - indicates the directory is known to be shared among the MPI processes
9621532e8aSBarry Smith . `PETSC_NOT_SHARED_TMP` - indicates the directory is known to be not shared among the MPI processes
9721532e8aSBarry Smith - `PETSC_TMP`            - name of the directory you wish to use as tmp
98e5c89e4eSSatish Balay 
99e5c89e4eSSatish Balay   Level: developer
100e5c89e4eSSatish Balay 
101e5c89e4eSSatish Balay   Notes:
102e5c89e4eSSatish Balay   Stores the status as a MPI attribute so it does not have
103e5c89e4eSSatish Balay   to be redetermined each time.
104e5c89e4eSSatish Balay 
105e5c89e4eSSatish Balay   Assumes that all processors in a communicator either
10621532e8aSBarry Smith   1) have a common tmp or
10721532e8aSBarry Smith   2) each has a separate tmp
108e5c89e4eSSatish Balay   eventually we can write a fancier one that determines which processors
10921532e8aSBarry Smith   share a common tmp.
110e5c89e4eSSatish Balay 
111e5c89e4eSSatish Balay   This will be very slow on runs with a large number of processors since
112e5c89e4eSSatish Balay   it requires O(p*p) file opens.
113e5c89e4eSSatish Balay 
114bfbbc7b7SBarry Smith   If the environmental variable `PETSC_TMP` is set it will use this directory
11521532e8aSBarry Smith   as the "tmp" directory.
116e5c89e4eSSatish Balay 
117811af0c4SBarry Smith .seealso: `PetscGetTmp()`, `PetscSharedWorkingDirectory()`, `PetscGetWorkingDirectory()`, `PetscGetHomeDirectory()`
118e5c89e4eSSatish Balay @*/
PetscSharedTmp(MPI_Comm comm,PetscBool * shared)119d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSharedTmp(MPI_Comm comm, PetscBool *shared)
120d71ae5a4SJacob Faibussowitsch {
121e5c89e4eSSatish Balay   PetscMPIInt size, rank, *tagvalp, sum, cnt, i;
122b8b5be36SMartin Diehl   PetscBool   flg;
123b8b5be36SMartin Diehl   PetscMPIInt iflg;
124e5c89e4eSSatish Balay   FILE       *fd;
125ed9cf6e9SBarry Smith   int         err;
126e5c89e4eSSatish Balay 
127e5c89e4eSSatish Balay   PetscFunctionBegin;
1289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
129e5c89e4eSSatish Balay   if (size == 1) {
130e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
1313ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
132e5c89e4eSSatish Balay   }
133e5c89e4eSSatish Balay 
1349566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_SHARED_TMP", NULL, 0, &flg));
135e5c89e4eSSatish Balay   if (flg) {
136e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
1373ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
138e5c89e4eSSatish Balay   }
139e5c89e4eSSatish Balay 
1409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_NOT_SHARED_TMP", NULL, 0, &flg));
141e5c89e4eSSatish Balay   if (flg) {
142e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
1433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
144e5c89e4eSSatish Balay   }
145e5c89e4eSSatish Balay 
1465ea2b939SDuncan Campbell   if (Petsc_SharedTmp_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelTmpShared, &Petsc_SharedTmp_keyval, NULL));
147e5c89e4eSSatish Balay 
148b8b5be36SMartin Diehl   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_SharedTmp_keyval, (void **)&tagvalp, &iflg));
149e5c89e4eSSatish Balay   if (!iflg) {
150e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN], tmpname[PETSC_MAX_PATH_LEN];
151e5c89e4eSSatish Balay 
152e5c89e4eSSatish Balay     /* This communicator does not yet have a shared tmp attribute */
1539566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &tagvalp));
1545ea2b939SDuncan Campbell     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_SharedTmp_keyval, tagvalp));
155e5c89e4eSSatish Balay 
156b8b5be36SMartin Diehl     PetscCall(PetscOptionsGetenv(comm, "PETSC_TMP", tmpname, 238, &flg));
157b8b5be36SMartin Diehl     if (!flg) {
158c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(filename, "/tmp", sizeof(filename)));
159e5c89e4eSSatish Balay     } else {
160c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(filename, tmpname, sizeof(filename)));
161e5c89e4eSSatish Balay     }
162e5c89e4eSSatish Balay 
163c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(filename, "/petsctestshared", sizeof(filename)));
1649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
165e5c89e4eSSatish Balay 
166e5c89e4eSSatish Balay     /* each processor creates a /tmp file and all the later ones check */
167e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
168e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
169e5c89e4eSSatish Balay     for (i = 0; i < size - 1; i++) {
170e5c89e4eSSatish Balay       if (rank == i) {
171e5c89e4eSSatish Balay         fd = fopen(filename, "w");
17228b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open test file %s", filename);
173ed9cf6e9SBarry Smith         err = fclose(fd);
17428b400f6SJacob Faibussowitsch         PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
175e5c89e4eSSatish Balay       }
1769566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(comm));
177e5c89e4eSSatish Balay       if (rank >= i) {
178e5c89e4eSSatish Balay         fd = fopen(filename, "r");
179a297a907SKarl Rupp         if (fd) cnt = 1;
180a297a907SKarl Rupp         else cnt = 0;
181e5c89e4eSSatish Balay         if (fd) {
182ed9cf6e9SBarry Smith           err = fclose(fd);
18328b400f6SJacob Faibussowitsch           PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
184e5c89e4eSSatish Balay         }
185a297a907SKarl Rupp       } else cnt = 0;
186a297a907SKarl Rupp 
187462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&cnt, &sum, 1, MPI_INT, MPI_SUM, comm));
188a297a907SKarl Rupp       if (rank == i) unlink(filename);
189e5c89e4eSSatish Balay 
190e5c89e4eSSatish Balay       if (sum == size) {
191e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
192e5c89e4eSSatish Balay         break;
19308401ef6SPierre Jolivet       } else PetscCheck(sum == 1, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Subset of processes share /tmp ");
194e5c89e4eSSatish Balay     }
195e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
196b8b5be36SMartin Diehl     PetscCall(PetscInfo(NULL, "processors %s %s\n", *shared ? "share" : "do NOT share", flg ? tmpname : "/tmp"));
197a297a907SKarl Rupp   } else *shared = (PetscBool)*tagvalp;
1983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
199e5c89e4eSSatish Balay }
200e5c89e4eSSatish Balay 
20110450e9eSJacob Faibussowitsch // "Unknown section 'Environmental Variables'"
20210450e9eSJacob Faibussowitsch // PetscClangLinter pragma disable: -fdoc-section-header-unknown
203cc4c1da9SBarry Smith /*@
204f1a722f8SMatthew G. Knepley   PetscSharedWorkingDirectory - Determines if all processors in a communicator share a working directory or have different ones.
205e5c89e4eSSatish Balay 
206d083f849SBarry Smith   Collective
207e5c89e4eSSatish Balay 
2086b867d5aSJose E. Roman   Input Parameter:
209e5c89e4eSSatish Balay . comm - MPI_Communicator that may share working directory
210e5c89e4eSSatish Balay 
2116b867d5aSJose E. Roman   Output Parameter:
212811af0c4SBarry Smith . shared - `PETSC_TRUE` or `PETSC_FALSE`
213e5c89e4eSSatish Balay 
214e5c89e4eSSatish Balay   Options Database Keys:
21521532e8aSBarry Smith + -shared_working_directory     - indicates the directory is known to be shared among the MPI processes
21621532e8aSBarry Smith - -not_shared_working_directory - indicates the directory is known to be not shared among the MPI processes
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay   Environmental Variables:
21921532e8aSBarry Smith + `PETSC_SHARED_WORKING_DIRECTORY`     - indicates the directory is known to be shared among the MPI processes
22021532e8aSBarry Smith - `PETSC_NOT_SHARED_WORKING_DIRECTORY` - indicates the directory is known to be not shared among the MPI processes
221e5c89e4eSSatish Balay 
222e5c89e4eSSatish Balay   Level: developer
223e5c89e4eSSatish Balay 
224e5c89e4eSSatish Balay   Notes:
225f1a722f8SMatthew G. Knepley   Stores the status as a MPI attribute so it does not have to be redetermined each time.
226e5c89e4eSSatish Balay 
227e5c89e4eSSatish Balay   Assumes that all processors in a communicator either
228bfbbc7b7SBarry Smith .vb
229bfbbc7b7SBarry Smith    1) have a common working directory or
230bfbbc7b7SBarry Smith    2) each has a separate working directory
231bfbbc7b7SBarry Smith .ve
232f1a722f8SMatthew G. Knepley   eventually we can write a fancier one that determines which processors share a common working directory.
233e5c89e4eSSatish Balay 
234f1a722f8SMatthew G. Knepley   This will be very slow on runs with a large number of processors since it requires O(p*p) file opens.
235811af0c4SBarry Smith 
236811af0c4SBarry Smith .seealso: `PetscGetTmp()`, `PetscSharedTmp()`, `PetscGetWorkingDirectory()`, `PetscGetHomeDirectory()`
237e5c89e4eSSatish Balay @*/
PetscSharedWorkingDirectory(MPI_Comm comm,PetscBool * shared)238d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSharedWorkingDirectory(MPI_Comm comm, PetscBool *shared)
239d71ae5a4SJacob Faibussowitsch {
240e5c89e4eSSatish Balay   PetscMPIInt size, rank, *tagvalp, sum, cnt, i;
241b8b5be36SMartin Diehl   PetscBool   flg;
242b8b5be36SMartin Diehl   PetscMPIInt iflg;
243e5c89e4eSSatish Balay   FILE       *fd;
244ed9cf6e9SBarry Smith   int         err;
245e5c89e4eSSatish Balay 
246e5c89e4eSSatish Balay   PetscFunctionBegin;
2479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
248e5c89e4eSSatish Balay   if (size == 1) {
249e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
2503ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
251e5c89e4eSSatish Balay   }
252e5c89e4eSSatish Balay 
2539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_SHARED_WORKING_DIRECTORY", NULL, 0, &flg));
254e5c89e4eSSatish Balay   if (flg) {
255e5c89e4eSSatish Balay     *shared = PETSC_TRUE;
2563ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
257e5c89e4eSSatish Balay   }
258e5c89e4eSSatish Balay 
2599566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetenv(comm, "PETSC_NOT_SHARED_WORKING_DIRECTORY", NULL, 0, &flg));
260e5c89e4eSSatish Balay   if (flg) {
261e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
2623ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
263e5c89e4eSSatish Balay   }
264e5c89e4eSSatish Balay 
2655ea2b939SDuncan Campbell   if (Petsc_SharedWD_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelTmpShared, &Petsc_SharedWD_keyval, NULL));
266e5c89e4eSSatish Balay 
267b8b5be36SMartin Diehl   PetscCallMPI(MPI_Comm_get_attr(comm, Petsc_SharedWD_keyval, (void **)&tagvalp, &iflg));
268e5c89e4eSSatish Balay   if (!iflg) {
269e5c89e4eSSatish Balay     char filename[PETSC_MAX_PATH_LEN];
270e5c89e4eSSatish Balay 
271e5c89e4eSSatish Balay     /* This communicator does not yet have a shared  attribute */
2729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &tagvalp));
2735ea2b939SDuncan Campbell     PetscCallMPI(MPI_Comm_set_attr(comm, Petsc_SharedWD_keyval, tagvalp));
274e5c89e4eSSatish Balay 
275bf31d2d3SBarry Smith     PetscCall(PetscGetWorkingDirectory(filename, sizeof(filename) - 16));
276c6a7a370SJeremy L Thompson     PetscCall(PetscStrlcat(filename, "/petsctestshared", sizeof(filename)));
2779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(comm, &rank));
278e5c89e4eSSatish Balay 
279e5c89e4eSSatish Balay     /* each processor creates a  file and all the later ones check */
280e5c89e4eSSatish Balay     /* this makes sure no subset of processors is shared */
281e5c89e4eSSatish Balay     *shared = PETSC_FALSE;
282e5c89e4eSSatish Balay     for (i = 0; i < size - 1; i++) {
283e5c89e4eSSatish Balay       if (rank == i) {
284e5c89e4eSSatish Balay         fd = fopen(filename, "w");
28528b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to open test file %s", filename);
286ed9cf6e9SBarry Smith         err = fclose(fd);
28728b400f6SJacob Faibussowitsch         PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
288e5c89e4eSSatish Balay       }
2899566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(comm));
290e5c89e4eSSatish Balay       if (rank >= i) {
291e5c89e4eSSatish Balay         fd = fopen(filename, "r");
292a297a907SKarl Rupp         if (fd) cnt = 1;
293a297a907SKarl Rupp         else cnt = 0;
294e5c89e4eSSatish Balay         if (fd) {
295ed9cf6e9SBarry Smith           err = fclose(fd);
29628b400f6SJacob Faibussowitsch           PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
297e5c89e4eSSatish Balay         }
298a297a907SKarl Rupp       } else cnt = 0;
299a297a907SKarl Rupp 
300462c564dSBarry Smith       PetscCallMPI(MPIU_Allreduce(&cnt, &sum, 1, MPI_INT, MPI_SUM, comm));
301a297a907SKarl Rupp       if (rank == i) unlink(filename);
302e5c89e4eSSatish Balay 
303e5c89e4eSSatish Balay       if (sum == size) {
304e5c89e4eSSatish Balay         *shared = PETSC_TRUE;
305e5c89e4eSSatish Balay         break;
30608401ef6SPierre Jolivet       } else PetscCheck(sum == 1, PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Subset of processes share working directory");
307e5c89e4eSSatish Balay     }
308e5c89e4eSSatish Balay     *tagvalp = (int)*shared;
309a297a907SKarl Rupp   } else *shared = (PetscBool)*tagvalp;
3109566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "processors %s working directory\n", (*shared) ? "shared" : "do NOT share"));
3113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
312e5c89e4eSSatish Balay }
313e5c89e4eSSatish Balay 
314e5c89e4eSSatish Balay /*@C
315bfbbc7b7SBarry Smith   PetscFileRetrieve - Obtains a file from a URL or a compressed file
316e5c89e4eSSatish Balay   and copies into local disk space as uncompressed.
317e5c89e4eSSatish Balay 
318d083f849SBarry Smith   Collective
319e5c89e4eSSatish Balay 
320d8d19677SJose E. Roman   Input Parameters:
3210c4f890aSBarry Smith + comm - processors accessing the file
3220c4f890aSBarry Smith . url  - name of file, including entire URL (with or without .gz)
32321532e8aSBarry Smith - llen - length of `localname`
324e5c89e4eSSatish Balay 
325d8d19677SJose E. Roman   Output Parameters:
32608fb59bfSBarry Smith + localname - name of local copy of file - valid on only process zero
32708fb59bfSBarry Smith - found     - if found or retrieved the file - valid on all processes
328e5c89e4eSSatish Balay 
32921532e8aSBarry Smith   Level: developer
3302fe279fdSBarry Smith 
331811af0c4SBarry Smith   Note:
33221532e8aSBarry Smith   if the file already exists locally this function just returns without downloading it.
333e5c89e4eSSatish Balay 
33410450e9eSJacob Faibussowitsch .seealso: `PetscDLLibraryRetrieve()`
335e5c89e4eSSatish Balay @*/
PetscFileRetrieve(MPI_Comm comm,const char url[],char localname[],size_t llen,PetscBool * found)336d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFileRetrieve(MPI_Comm comm, const char url[], char localname[], size_t llen, PetscBool *found)
337d71ae5a4SJacob Faibussowitsch {
338bbcf679cSJacob Faibussowitsch   char        buffer[PETSC_MAX_PATH_LEN], *par = NULL, *tlocalname = NULL, name[PETSC_MAX_PATH_LEN];
339e5c89e4eSSatish Balay   FILE       *fp;
340e5c89e4eSSatish Balay   PetscMPIInt rank;
341e5c89e4eSSatish Balay   size_t      len = 0;
34208fb59bfSBarry Smith   PetscBool   flg1, flg2, flg3, flg4, download, compressed = PETSC_FALSE;
343e5c89e4eSSatish Balay 
344e5c89e4eSSatish Balay   PetscFunctionBegin;
3459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
346dd400576SPatrick Sanan   if (rank == 0) {
347e5c89e4eSSatish Balay     *found = PETSC_FALSE;
348e5c89e4eSSatish Balay 
3499566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(url, ".gz", &par));
35008fb59bfSBarry Smith     if (par) {
3519566063dSJacob Faibussowitsch       PetscCall(PetscStrlen(par, &len));
35208fb59bfSBarry Smith       if (len == 3) compressed = PETSC_TRUE;
35308fb59bfSBarry Smith     }
354e5c89e4eSSatish Balay 
3559566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "ftp://", 6, &flg1));
3569566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "http://", 7, &flg2));
3579566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "file://", 7, &flg3));
3589566063dSJacob Faibussowitsch     PetscCall(PetscStrncmp(url, "https://", 8, &flg4));
359a4772d12SBarry Smith     download = (PetscBool)(flg1 || flg2 || flg3 || flg4);
36008fb59bfSBarry Smith 
36108fb59bfSBarry Smith     if (!download && !compressed) {
3629566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
3639566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(url, 'r', found));
364487e5849SBarry Smith       if (*found) {
3659566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Found file %s\n", url));
366487e5849SBarry Smith       } else {
3679566063dSJacob Faibussowitsch         PetscCall(PetscInfo(NULL, "Did not find file %s\n", url));
368487e5849SBarry Smith       }
36908fb59bfSBarry Smith       goto done;
370734f99bcSBarry Smith     }
371734f99bcSBarry Smith 
37205698389SBarry Smith     /* look for uncompressed file in requested directory */
37305698389SBarry Smith     if (compressed) {
3749566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
3759566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(localname, ".gz", &par));
37605698389SBarry Smith       *par = 0; /* remove .gz extension */
3779566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
37805698389SBarry Smith       if (*found) goto done;
37905698389SBarry Smith     }
38005698389SBarry Smith 
38105698389SBarry Smith     /* look for file in current directory */
3829566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(url, '/', &tlocalname));
3839566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(localname, tlocalname, llen));
38408fb59bfSBarry Smith     if (compressed) {
3859566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(localname, ".gz", &par));
38608fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
38708fb59bfSBarry Smith     }
3889566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(localname, 'r', found));
38908fb59bfSBarry Smith     if (*found) goto done;
390e5c89e4eSSatish Balay 
39108fb59bfSBarry Smith     if (download) {
39208fb59bfSBarry Smith       /* local file is not already here so use curl to get it */
3939566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, tlocalname, llen));
394c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(buffer, "curl --fail --silent --show-error ", sizeof(buffer)));
395c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, url, sizeof(buffer)));
396c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, " > ", sizeof(buffer)));
397c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, localname, sizeof(buffer)));
398e5c89e4eSSatish Balay #if defined(PETSC_HAVE_POPEN)
3999566063dSJacob Faibussowitsch       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, buffer, "r", &fp));
4009566063dSJacob Faibussowitsch       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
401e5c89e4eSSatish Balay #else
402e32f2f54SBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
403e5c89e4eSSatish Balay #endif
4049566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
4056e3a5469SBarry Smith       if (*found) {
4066e3a5469SBarry Smith         FILE *fd;
4076e3a5469SBarry Smith         char  buf[1024], *str, *substring;
4086e3a5469SBarry Smith 
4096e3a5469SBarry Smith         /* check if the file didn't exist so it downloaded an HTML message instead */
4106e3a5469SBarry Smith         fd = fopen(localname, "r");
41128b400f6SJacob Faibussowitsch         PetscCheck(fd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscTestFile() indicates %s exists but fopen() cannot open it", localname);
4126e3a5469SBarry Smith         str = fgets(buf, sizeof(buf) - 1, fd);
4136e3a5469SBarry Smith         while (str) {
4149566063dSJacob Faibussowitsch           PetscCall(PetscStrstr(buf, "<!DOCTYPE html>", &substring));
41528b400f6SJacob 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);
4169566063dSJacob Faibussowitsch           PetscCall(PetscStrstr(buf, "Not Found", &substring));
41728b400f6SJacob 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);
4186e3a5469SBarry Smith           str = fgets(buf, sizeof(buf) - 1, fd);
4196e3a5469SBarry Smith         }
4206e3a5469SBarry Smith         fclose(fd);
4216e3a5469SBarry Smith       }
42208fb59bfSBarry Smith     } else if (compressed) {
4239566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(url, 'r', found));
42408fb59bfSBarry Smith       if (!*found) goto done;
4259566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, url, llen));
42608fb59bfSBarry Smith     }
42708fb59bfSBarry Smith     if (compressed) {
4289566063dSJacob Faibussowitsch       PetscCall(PetscStrrchr(localname, '/', &tlocalname));
4299566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(name, tlocalname, PETSC_MAX_PATH_LEN));
4309566063dSJacob Faibussowitsch       PetscCall(PetscStrstr(name, ".gz", &par));
43108fb59bfSBarry Smith       *par = 0; /* remove .gz extension */
43208fb59bfSBarry Smith       /* uncompress file */
433c6a7a370SJeremy L Thompson       PetscCall(PetscStrncpy(buffer, "gzip -c -d ", sizeof(buffer)));
434c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, localname, sizeof(buffer)));
435c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, " > ", sizeof(buffer)));
436c6a7a370SJeremy L Thompson       PetscCall(PetscStrlcat(buffer, name, sizeof(buffer)));
43708fb59bfSBarry Smith #if defined(PETSC_HAVE_POPEN)
4389566063dSJacob Faibussowitsch       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, buffer, "r", &fp));
4399566063dSJacob Faibussowitsch       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
44008fb59bfSBarry Smith #else
44108fb59bfSBarry Smith       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
44208fb59bfSBarry Smith #endif
4439566063dSJacob Faibussowitsch       PetscCall(PetscStrncpy(localname, name, llen));
4449566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(localname, 'r', found));
445e5c89e4eSSatish Balay     }
446e5c89e4eSSatish Balay   }
447955d42a0SBarry Smith done:
448*5440e5dcSBarry Smith   PetscCallMPI(MPI_Bcast(found, 1, MPI_C_BOOL, 0, comm));
4496497c311SBarry Smith   PetscCallMPI(MPI_Bcast(localname, (PetscMPIInt)llen, MPI_CHAR, 0, comm));
4503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
451e5c89e4eSSatish Balay }
452