Skip to content

Latest commit

 

History

History
375 lines (302 loc) · 9.96 KB

platform_unix.c

File metadata and controls

375 lines (302 loc) · 9.96 KB
 
Jul 7, 2001
Jul 7, 2001
1
2
3
/*
* Unix support routines for PhysicsFS.
*
Mar 11, 2007
Mar 11, 2007
4
* Please see the file LICENSE.txt in the source's root directory.
Jul 7, 2001
Jul 7, 2001
5
6
7
8
*
* This file written by Ryan C. Gordon.
*/
Mar 11, 2007
Mar 11, 2007
9
10
11
12
#define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h"
#ifdef PHYSFS_PLATFORM_UNIX
Jun 29, 2002
Jun 29, 2002
13
Jul 8, 2001
Jul 8, 2001
14
15
#include <ctype.h>
#include <unistd.h>
Aug 24, 2013
Aug 24, 2013
16
#include <stdlib.h>
Jul 8, 2001
Jul 8, 2001
17
18
19
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
Jul 16, 2001
Jul 16, 2001
20
#include <sys/param.h>
Jul 8, 2001
Jul 8, 2001
21
22
23
#include <dirent.h>
#include <time.h>
#include <errno.h>
Aug 24, 2013
Aug 24, 2013
24
#include <limits.h>
Mar 5, 2002
Mar 5, 2002
25
Mar 20, 2012
Mar 20, 2012
26
27
28
29
30
31
32
33
#if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H)
#define PHYSFS_HAVE_MNTENT_H 1
#elif PHYSFS_PLATFORM_SOLARIS && !defined(PHYSFS_HAVE_SYS_MNTTAB_H)
#define PHYSFS_HAVE_SYS_MNTTAB_H 1
#elif PHYSFS_PLATFORM_BSD && !defined(PHYSFS_HAVE_SYS_UCRED_H)
#define PHYSFS_HAVE_SYS_UCRED_H 1
#endif
Jul 20, 2002
Jul 20, 2002
34
35
36
37
#ifdef PHYSFS_HAVE_SYS_UCRED_H
# ifdef PHYSFS_HAVE_MNTENT_H
# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
# endif
May 3, 2009
May 3, 2009
38
# include <sys/mount.h>
Jul 20, 2002
Jul 20, 2002
39
# include <sys/ucred.h>
Mar 5, 2002
Mar 5, 2002
40
#endif
Jul 7, 2001
Jul 7, 2001
41
Jul 20, 2002
Jul 20, 2002
42
43
44
#ifdef PHYSFS_HAVE_MNTENT_H
#include <mntent.h>
#endif
Apr 6, 2002
Apr 6, 2002
45
Apr 13, 2009
Apr 13, 2009
46
47
48
49
#ifdef PHYSFS_HAVE_SYS_MNTTAB_H
#include <sys/mnttab.h>
#endif
Jul 9, 2017
Jul 9, 2017
50
51
52
53
#if PHYSFS_PLATFORM_FREEBSD
#include <sys/sysctl.h>
#endif
Jul 7, 2001
Jul 7, 2001
54
55
#include "physfs_internal.h"
Mar 24, 2002
Mar 24, 2002
56
57
int __PHYSFS_platformInit(void)
{
Jan 28, 2010
Jan 28, 2010
58
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
59
60
61
62
63
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
Jan 28, 2010
Jan 28, 2010
64
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
65
66
67
} /* __PHYSFS_platformDeinit */
Jul 25, 2002
Jul 25, 2002
68
/* Stub version for platforms without CD-ROM support. */
Sep 29, 2004
Sep 29, 2004
69
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Jul 25, 2002
Jul 25, 2002
70
{
Apr 13, 2009
Apr 13, 2009
71
72
#if (defined PHYSFS_NO_CDROM_SUPPORT)
/* no-op. */
Jul 25, 2002
Jul 25, 2002
73
May 24, 2003
May 24, 2003
74
#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
Jul 25, 2002
Jul 25, 2002
75
int i;
Sep 29, 2004
Sep 29, 2004
76
77
struct statfs *mntbufp = NULL;
int mounts = getmntinfo(&mntbufp, MNT_WAIT);
Mar 5, 2002
Mar 5, 2002
78
Jul 25, 2002
Jul 25, 2002
79
80
for (i = 0; i < mounts; i++)
{
Mar 5, 2002
Mar 5, 2002
81
82
int add_it = 0;
Jul 25, 2002
Jul 25, 2002
83
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
Mar 5, 2002
Mar 5, 2002
84
add_it = 1;
Jul 25, 2002
Jul 25, 2002
85
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
Apr 6, 2002
Apr 6, 2002
86
add_it = 1;
May 21, 2002
May 21, 2002
87
88
/* add other mount types here */
Mar 5, 2002
Mar 5, 2002
89
90
if (add_it)
Sep 29, 2004
Sep 29, 2004
91
cb(data, mntbufp[i].f_mntonname);
Jul 25, 2002
Jul 25, 2002
92
} /* for */
Mar 5, 2002
Mar 5, 2002
93
May 24, 2003
May 24, 2003
94
#elif (defined PHYSFS_HAVE_MNTENT_H)
Aug 7, 2001
Aug 7, 2001
95
96
97
98
FILE *mounts = NULL;
struct mntent *ent = NULL;
mounts = setmntent("/etc/mtab", "r");
Jul 6, 2017
Jul 6, 2017
99
BAIL_IF(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
Aug 7, 2001
Aug 7, 2001
100
101
102
103
104
105
while ( (ent = getmntent(mounts)) != NULL )
{
int add_it = 0;
if (strcmp(ent->mnt_type, "iso9660") == 0)
add_it = 1;
Mar 22, 2010
Mar 22, 2010
106
107
108
109
110
111
112
113
else if (strcmp(ent->mnt_type, "udf") == 0)
add_it = 1;
/* !!! FIXME: these might pick up floppy drives, right? */
else if (strcmp(ent->mnt_type, "auto") == 0)
add_it = 1;
else if (strcmp(ent->mnt_type, "supermount") == 0)
add_it = 1;
May 21, 2002
May 21, 2002
114
Mar 1, 2010
Mar 1, 2010
115
116
/* !!! FIXME: udf? automount? */
May 21, 2002
May 21, 2002
117
/* add other mount types here */
Aug 7, 2001
Aug 7, 2001
118
119
if (add_it)
Sep 29, 2004
Sep 29, 2004
120
cb(data, ent->mnt_dir);
Aug 7, 2001
Aug 7, 2001
121
122
123
} /* while */
endmntent(mounts);
Apr 13, 2009
Apr 13, 2009
124
125
126
127
128
#elif (defined PHYSFS_HAVE_SYS_MNTTAB_H)
FILE *mounts = fopen(MNTTAB, "r");
struct mnttab ent;
Jul 6, 2017
Jul 6, 2017
129
BAIL_IF(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
Apr 13, 2009
Apr 13, 2009
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
while (getmntent(mounts, &ent) == 0)
{
int add_it = 0;
if (strcmp(ent.mnt_fstype, "hsfs") == 0)
add_it = 1;
/* add other mount types here */
if (add_it)
cb(data, ent.mnt_mountp);
} /* while */
fclose(mounts);
#else
#error Unknown platform. Should have defined PHYSFS_NO_CDROM_SUPPORT, perhaps.
Mar 5, 2002
Mar 5, 2002
146
#endif
Apr 13, 2009
Apr 13, 2009
147
} /* __PHYSFS_platformDetectAvailableCDs */
Jul 7, 2001
Jul 7, 2001
148
149
May 21, 2002
May 21, 2002
150
151
152
153
154
155
/*
* See where program (bin) resides in the $PATH specified by (envr).
* returns a copy of the first element in envr that contains it, or NULL
* if it doesn't exist or there were other problems. PHYSFS_SetError() is
* called if we have a problem.
*
Mar 14, 2005
Mar 14, 2005
156
* (envr) will be scribbled over, and you are expected to allocator.Free() the
May 21, 2002
May 21, 2002
157
158
159
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
Jul 8, 2001
Jul 8, 2001
160
{
May 21, 2002
May 21, 2002
161
162
163
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
Jul 8, 2001
Jul 8, 2001
164
165
char *ptr;
Mar 20, 2012
Mar 20, 2012
166
167
assert(bin != NULL);
assert(envr != NULL);
Jul 8, 2001
Jul 8, 2001
168
169
170
do
{
May 21, 2002
May 21, 2002
171
size_t size;
Mar 23, 2012
Mar 23, 2012
172
173
size_t binlen;
May 21, 2002
May 21, 2002
174
ptr = strchr(start, ':'); /* find next $PATH separator. */
Jul 8, 2001
Jul 8, 2001
175
176
177
if (ptr)
*ptr = '\0';
Mar 23, 2012
Mar 23, 2012
178
179
binlen = strlen(bin);
size = strlen(start) + binlen + 2;
Aug 19, 2014
Aug 19, 2014
180
if (size >= alloc_size)
Jul 8, 2001
Jul 8, 2001
181
{
Mar 14, 2005
Mar 14, 2005
182
char *x = (char *) allocator.Realloc(exe, size);
Mar 20, 2012
Mar 20, 2012
183
if (!x)
May 21, 2002
May 21, 2002
184
185
{
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
186
allocator.Free(exe);
Jul 6, 2017
Jul 6, 2017
187
BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
May 21, 2002
May 21, 2002
188
189
190
191
} /* if */
alloc_size = size;
exe = x;
Jul 8, 2001
Jul 8, 2001
192
} /* if */
May 21, 2002
May 21, 2002
193
194
/* build full binary path... */
Jul 8, 2001
Jul 8, 2001
195
strcpy(exe, start);
Nov 30, 2002
Nov 30, 2002
196
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
Aug 29, 2001
Aug 29, 2001
197
strcat(exe, "/");
May 21, 2002
May 21, 2002
198
199
200
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
Jul 8, 2001
Jul 8, 2001
201
{
Jul 16, 2013
Jul 16, 2013
202
exe[(size - binlen) - 1] = '\0'; /* chop off filename, leave '/' */
Jan 28, 2010
Jan 28, 2010
203
return exe;
May 21, 2002
May 21, 2002
204
} /* if */
Jul 8, 2001
Jul 8, 2001
205
May 21, 2002
May 21, 2002
206
start = ptr + 1; /* start points to beginning of next element. */
Jul 8, 2001
Jul 8, 2001
207
208
} while (ptr != NULL);
May 21, 2002
May 21, 2002
209
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
210
allocator.Free(exe);
May 21, 2002
May 21, 2002
211
Jan 28, 2010
Jan 28, 2010
212
return NULL; /* doesn't exist in path. */
May 21, 2002
May 21, 2002
213
214
215
} /* findBinaryInPath */
Jul 8, 2009
Jul 8, 2009
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
static char *readSymLink(const char *path)
{
ssize_t len = 64;
ssize_t rc = -1;
char *retval = NULL;
while (1)
{
char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
if (ptr == NULL)
break; /* out of memory. */
retval = ptr;
rc = readlink(path, retval, len);
if (rc == -1)
break; /* not a symlink, i/o error, etc. */
else if (rc < len)
{
retval[rc] = '\0'; /* readlink doesn't null-terminate. */
return retval; /* we're good to go. */
} /* else if */
len *= 2; /* grow buffer, try again. */
} /* while */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* readSymLink */
May 21, 2002
May 21, 2002
248
249
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
Mar 19, 2007
Mar 19, 2007
250
char *retval = NULL;
Mar 24, 2012
Mar 24, 2012
251
const char *envr = NULL;
Mar 19, 2007
Mar 19, 2007
252
Aug 24, 2013
Aug 24, 2013
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/* Try to avoid using argv0 unless forced to. Try system-specific stuff. */
#if PHYSFS_PLATFORM_FREEBSD
{
char fullpath[PATH_MAX];
size_t buflen = sizeof (fullpath);
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1)
retval = __PHYSFS_strdup(fullpath);
}
#elif PHYSFS_PLATFORM_SOLARIS
{
const char *path = getexecname();
if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */
retval = __PHYSFS_strdup(path);
}
#endif
if (retval)
return retval; /* already got it. */
/* If there's a Linux-like /proc filesystem, you can get the full path to
* the current process from a symlink in there.
Mar 19, 2007
Mar 19, 2007
276
*/
Aug 24, 2013
Aug 24, 2013
277
278
if (access("/proc", F_OK) == 0)
Jul 8, 2009
Jul 8, 2009
279
{
Aug 24, 2013
Aug 24, 2013
280
281
282
283
284
285
286
287
288
289
290
291
retval = readSymLink("/proc/self/exe");
if (!retval) retval = readSymLink("/proc/curproc/file");
if (!retval) retval = readSymLink("/proc/curproc/exe");
if (retval == NULL)
{
/* older kernels don't have /proc/self ... try PID version... */
const unsigned long long pid = (unsigned long long) getpid();
char path[64];
const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
if ( (rc > 0) && (rc < sizeof(path)) )
retval = readSymLink(path);
} /* if */
Jul 8, 2009
Jul 8, 2009
292
293
} /* if */
Jul 8, 2009
Jul 8, 2009
294
if (retval != NULL) /* chop off filename. */
Mar 19, 2007
Mar 19, 2007
295
{
Jul 8, 2009
Jul 8, 2009
296
297
char *ptr = strrchr(retval, '/');
if (ptr != NULL)
Mar 23, 2012
Mar 23, 2012
298
*(ptr+1) = '\0';
Mar 24, 2012
Mar 24, 2012
299
300
301
302
303
else /* shouldn't happen, but just in case... */
{
allocator.Free(retval);
retval = NULL;
} /* else */
Mar 19, 2007
Mar 19, 2007
304
} /* if */
May 21, 2002
May 21, 2002
305
Aug 24, 2013
Aug 24, 2013
306
/* No /proc/self/exe, etc, but we have an argv[0] we can parse? */
Mar 19, 2007
Mar 19, 2007
307
308
if ((retval == NULL) && (argv0 != NULL))
{
Mar 23, 2012
Mar 23, 2012
309
310
311
312
/* fast path: default behaviour can handle this. */
if (strchr(argv0, '/') != NULL)
return NULL; /* higher level parses out real path from argv0. */
Mar 19, 2007
Mar 19, 2007
313
/* If there's no dirsep on argv0, then look through $PATH for it. */
Mar 24, 2012
Mar 24, 2012
314
315
316
317
envr = getenv("PATH");
if (envr != NULL)
{
char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1);
Jul 6, 2017
Jul 6, 2017
318
BAIL_IF(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Mar 24, 2012
Mar 24, 2012
319
320
321
322
strcpy(path, envr);
retval = findBinaryInPath(argv0, path);
__PHYSFS_smallFree(path);
} /* if */
Mar 19, 2007
Mar 19, 2007
323
} /* if */
May 21, 2002
May 21, 2002
324
Jul 8, 2009
Jul 8, 2009
325
326
327
328
329
330
331
332
if (retval != NULL)
{
/* try to shrink buffer... */
char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
if (ptr != NULL)
retval = ptr; /* oh well if it failed. */
} /* if */
Jan 28, 2010
Jan 28, 2010
333
return retval;
Jul 8, 2001
Jul 8, 2001
334
335
336
} /* __PHYSFS_platformCalcBaseDir */
Mar 22, 2012
Mar 22, 2012
337
338
339
340
341
342
343
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
{
/*
* We use XDG's base directory spec, even if you're not on Linux.
* This isn't strictly correct, but the results are relatively sane
* in any case.
*
Feb 25, 2016
Feb 25, 2016
344
* https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
Mar 22, 2012
Mar 22, 2012
345
346
347
348
349
350
351
352
353
354
*/
const char *envr = getenv("XDG_DATA_HOME");
const char *append = "/";
char *retval = NULL;
size_t len = 0;
if (!envr)
{
/* You end up with "$HOME/.local/share/Game Name 2" */
envr = __PHYSFS_getUserDir();
Jul 6, 2017
Jul 6, 2017
355
BAIL_IF_ERRPASS(!envr, NULL); /* oh well. */
Mar 22, 2012
Mar 22, 2012
356
357
358
append = ".local/share/";
} /* if */
Mar 22, 2012
Mar 22, 2012
359
len = strlen(envr) + strlen(append) + strlen(app) + 2;
Mar 22, 2012
Mar 22, 2012
360
retval = (char *) allocator.Malloc(len);
Jul 6, 2017
Jul 6, 2017
361
BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Mar 22, 2012
Mar 22, 2012
362
snprintf(retval, len, "%s%s%s/", envr, append, app);
Mar 22, 2012
Mar 22, 2012
363
364
365
366
return retval;
} /* __PHYSFS_platformCalcPrefDir */
Mar 20, 2007
Mar 20, 2007
367
368
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
Jan 28, 2010
Jan 28, 2010
369
return 0; /* just use malloc() and friends. */
Mar 20, 2007
Mar 20, 2007
370
371
} /* __PHYSFS_platformSetDefaultAllocator */
Mar 11, 2007
Mar 11, 2007
372
#endif /* PHYSFS_PLATFORM_UNIX */
May 24, 2002
May 24, 2002
373
Jul 7, 2001
Jul 7, 2001
374
/* end of unix.c ... */