1 #include <petscsys.h>
2 #include <errno.h>
3 #if defined(PETSC_HAVE_PWD_H)
4 #include <pwd.h>
5 #endif
6 #include <ctype.h>
7 #include <sys/stat.h>
8 #if defined(PETSC_HAVE_UNISTD_H)
9 #include <unistd.h>
10 #endif
11 #if defined(PETSC_HAVE_SYS_UTSNAME_H)
12 #include <sys/utsname.h>
13 #endif
14 #if defined(PETSC_HAVE_IO_H)
15 #include <io.h>
16 #endif
17 #if defined(PETSC_HAVE_SYS_SYSTEMINFO_H)
18 #include <sys/systeminfo.h>
19 #endif
20
21 #if defined(PETSC_HAVE__ACCESS) || defined(PETSC_HAVE_ACCESS)
22
23 #include <errno.h>
PetscTestOwnership(const char fname[],char mode,uid_t fuid,gid_t fgid,int fmode,PetscBool * flg)24 static PetscErrorCode PetscTestOwnership(const char fname[], char mode, uid_t fuid, gid_t fgid, int fmode, PetscBool *flg)
25 {
26 int m = R_OK;
27
28 PetscFunctionBegin;
29 if (mode == 'r') m = R_OK;
30 else if (mode == 'w') m = W_OK;
31 else if (mode == 'x') m = X_OK;
32 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mode must be one of r, w, or x");
33 #if defined(PETSC_HAVE_ACCESS)
34 if (!access(fname, m)) {
35 PetscCall(PetscInfo(NULL, "System call access() succeeded on file %s\n", fname));
36 *flg = PETSC_TRUE;
37 } else {
38 PetscCall(PetscInfo(NULL, "System call access() failed on file %s due to \"%s\"\n", fname, strerror(errno)));
39 *flg = PETSC_FALSE;
40 }
41 #else
42 PetscCheck(m != X_OK, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unable to check execute permission for file %s", fname);
43 if (!_access(fname, m)) *flg = PETSC_TRUE;
44 #endif
45 PetscFunctionReturn(PETSC_SUCCESS);
46 }
47
48 #else /* PETSC_HAVE_ACCESS or PETSC_HAVE__ACCESS */
49
PetscTestOwnership(const char fname[],char mode,uid_t fuid,gid_t fgid,int fmode,PetscBool * flg)50 static PetscErrorCode PetscTestOwnership(const char fname[], char mode, uid_t fuid, gid_t fgid, int fmode, PetscBool *flg)
51 {
52 uid_t uid;
53 gid_t *gid = NULL;
54 int numGroups;
55 int rbit = S_IROTH;
56 int wbit = S_IWOTH;
57 int ebit = S_IXOTH;
58 #if !defined(PETSC_MISSING_GETGROUPS)
59 int err;
60 #endif
61
62 PetscFunctionBegin;
63 /* Get the number of supplementary group IDs */
64 #if !defined(PETSC_MISSING_GETGROUPS)
65 numGroups = getgroups(0, gid);
66 PetscCheck(numGroups >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to count supplementary group IDs due to \"%s\"", strerror(errno));
67 PetscCall(PetscMalloc1(numGroups + 1, &gid));
68 #else
69 numGroups = 0;
70 #endif
71
72 /* Get the (effective) user and group of the caller */
73 uid = geteuid();
74 gid[0] = getegid();
75
76 /* Get supplementary group IDs */
77 #if !defined(PETSC_MISSING_GETGROUPS)
78 err = getgroups(numGroups, gid + 1);
79 PetscCheck(err >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to obtain supplementary group IDs due to \"%s\"", strerror(errno));
80 #endif
81
82 /* Test for accessibility */
83 if (fuid == uid) {
84 rbit = S_IRUSR;
85 wbit = S_IWUSR;
86 ebit = S_IXUSR;
87 } else {
88 int g;
89
90 for (g = 0; g <= numGroups; g++) {
91 if (fgid == gid[g]) {
92 rbit = S_IRGRP;
93 wbit = S_IWGRP;
94 ebit = S_IXGRP;
95 break;
96 }
97 }
98 }
99 PetscCall(PetscFree(gid));
100
101 if (mode == 'r') {
102 if (fmode & rbit) *flg = PETSC_TRUE;
103 } else if (mode == 'w') {
104 if (fmode & wbit) *flg = PETSC_TRUE;
105 } else if (mode == 'x') {
106 if (fmode & ebit) *flg = PETSC_TRUE;
107 }
108 PetscFunctionReturn(PETSC_SUCCESS);
109 }
110
111 #endif /* PETSC_HAVE_ACCESS */
112
PetscGetFileStat(const char fname[],uid_t * fileUid,gid_t * fileGid,int * fileMode,PetscBool * exists)113 static PetscErrorCode PetscGetFileStat(const char fname[], uid_t *fileUid, gid_t *fileGid, int *fileMode, PetscBool *exists)
114 {
115 struct stat statbuf;
116 int ierr;
117
118 PetscFunctionBegin;
119 *fileMode = 0;
120 *exists = PETSC_FALSE;
121 #if defined(PETSC_HAVE_STAT_NO_CONST)
122 ierr = stat((char *)fname, &statbuf);
123 #else
124 ierr = stat(fname, &statbuf);
125 #endif
126 if (ierr) {
127 #if defined(EOVERFLOW)
128 PetscCheck(errno != EOVERFLOW, PETSC_COMM_SELF, PETSC_ERR_SYS, "EOVERFLOW in stat(), configure PETSc --with-large-file-io=1 to support files larger than 2GiB");
129 #endif
130 PetscCall(PetscInfo(NULL, "System call stat() failed on file %s due to \"%s\"\n", fname, strerror(errno)));
131 *exists = PETSC_FALSE;
132 } else {
133 PetscCall(PetscInfo(NULL, "System call stat() succeeded on file %s\n", fname));
134 *exists = PETSC_TRUE;
135 *fileUid = statbuf.st_uid;
136 *fileGid = statbuf.st_gid;
137 *fileMode = statbuf.st_mode;
138 }
139 PetscFunctionReturn(PETSC_SUCCESS);
140 }
141
142 /*@
143 PetscTestFile - checks for the existence of a file
144
145 Not Collective
146
147 Input Parameters:
148 + fname - the filename
149 - mode - either 'r', 'w', 'x' or '\0'
150
151 Output Parameter:
152 . flg - the file exists and satisfies the mode
153
154 Level: intermediate
155
156 Note:
157 If mode is '\0', no permissions checks are performed
158
159 .seealso: `PetscTestDirectory()`, `PetscLs()`
160 @*/
PetscTestFile(const char fname[],char mode,PetscBool * flg)161 PetscErrorCode PetscTestFile(const char fname[], char mode, PetscBool *flg)
162 {
163 uid_t fuid;
164 gid_t fgid;
165 int fmode;
166 PetscBool exists;
167
168 PetscFunctionBegin;
169 *flg = PETSC_FALSE;
170 if (!fname) PetscFunctionReturn(PETSC_SUCCESS);
171
172 PetscCall(PetscGetFileStat(fname, &fuid, &fgid, &fmode, &exists));
173 if (!exists) PetscFunctionReturn(PETSC_SUCCESS);
174 /* Except for systems that have this broken stat macros (rare), this is the correct way to check for a regular file */
175 if (!S_ISREG(fmode)) PetscFunctionReturn(PETSC_SUCCESS);
176 /* return if asked to check for existence only */
177 if (mode == '\0') {
178 *flg = exists;
179 PetscFunctionReturn(PETSC_SUCCESS);
180 }
181 PetscCall(PetscTestOwnership(fname, mode, fuid, fgid, fmode, flg));
182 PetscFunctionReturn(PETSC_SUCCESS);
183 }
184
185 /*@
186 PetscTestDirectory - checks for the existence of a directory
187
188 Not Collective
189
190 Input Parameters:
191 + dirname - the directory name
192 - mode - either 'r', 'w', or 'x'
193
194 Output Parameter:
195 . flg - the directory exists and satisfies the mode
196
197 Level: intermediate
198
199 .seealso: `PetscTestFile()`, `PetscLs()`, `PetscRMTree()`
200 @*/
PetscTestDirectory(const char dirname[],char mode,PetscBool * flg)201 PetscErrorCode PetscTestDirectory(const char dirname[], char mode, PetscBool *flg)
202 {
203 uid_t fuid;
204 gid_t fgid;
205 int fmode;
206 PetscBool exists;
207
208 PetscFunctionBegin;
209 *flg = PETSC_FALSE;
210 if (!dirname) PetscFunctionReturn(PETSC_SUCCESS);
211
212 PetscCall(PetscGetFileStat(dirname, &fuid, &fgid, &fmode, &exists));
213 if (!exists) PetscFunctionReturn(PETSC_SUCCESS);
214 /* Except for systems that have this broken stat macros (rare), this
215 is the correct way to check for a directory */
216 if (!S_ISDIR(fmode)) PetscFunctionReturn(PETSC_SUCCESS);
217
218 PetscCall(PetscTestOwnership(dirname, mode, fuid, fgid, fmode, flg));
219 PetscFunctionReturn(PETSC_SUCCESS);
220 }
221
222 /*@C
223 PetscLs - produce a listing of the files in a directory
224
225 Collective
226
227 Input Parameters:
228 + comm - the MPI communicator
229 . dirname - the directory name
230 - tlen - the length of the buffer `found`
231
232 Output Parameters:
233 + found - listing of files
234 - flg - the directory exists
235
236 Level: intermediate
237
238 .seealso: `PetscTestFile()`, `PetscRMTree()`, `PetscTestDirectory()`
239 @*/
PetscLs(MPI_Comm comm,const char dirname[],char found[],size_t tlen,PetscBool * flg)240 PetscErrorCode PetscLs(MPI_Comm comm, const char dirname[], char found[], size_t tlen, PetscBool *flg)
241 {
242 size_t len;
243 char *f, program[PETSC_MAX_PATH_LEN];
244 FILE *fp;
245
246 PetscFunctionBegin;
247 PetscCall(PetscStrncpy(program, "ls ", sizeof(program)));
248 PetscCall(PetscStrlcat(program, dirname, sizeof(program)));
249 #if defined(PETSC_HAVE_POPEN)
250 PetscCall(PetscPOpen(comm, NULL, program, "r", &fp));
251 #else
252 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
253 #endif
254 f = fgets(found, (int)tlen, fp);
255 if (f) *flg = PETSC_TRUE;
256 else *flg = PETSC_FALSE;
257 while (f) {
258 PetscCall(PetscStrlen(found, &len));
259 f = fgets(found + len, (int)(tlen - len), fp);
260 }
261 if (*flg) PetscCall(PetscInfo(NULL, "ls on %s gives \n%s\n", dirname, found));
262 #if defined(PETSC_HAVE_POPEN)
263 PetscCall(PetscPClose(comm, fp));
264 #else
265 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
266 #endif
267 PetscFunctionReturn(PETSC_SUCCESS);
268 }
269