1/*
2 * QNX support routines for PhysicsFS.
3 *
4 * Please see the file LICENSE.txt in the source's root directory.
5 *
6 * This file written by Ryan C. Gordon.
7 */
8
9/* This is tested against QNX 7 at the moment. */
10
11#define __PHYSICSFS_INTERNAL__
12#include "physfs_platforms.h"
13
14#ifdef PHYSFS_PLATFORM_QNX
15
16#include <fcntl.h>
17#include <unistd.h>
18#include <sys/types.h>
19#include <limits.h>
20
21#include "physfs_internal.h"
22
23int __PHYSFS_platformInit(void)
24{
25 return 1; /* always succeed. */
26} /* __PHYSFS_platformInit */
27
28
29void __PHYSFS_platformDeinit(void)
30{
31 /* no-op */
32} /* __PHYSFS_platformDeinit */
33
34
35char *__PHYSFS_platformCalcBaseDir(const char *argv0)
36{
37 char *retval = (char *) allocator.Malloc(PATH_MAX+1);
38 if (retval == NULL)
39 BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
40 else
41 {
42 const int fd = open("/proc/self/exefile", O_RDONLY);
43 const ssize_t br = (fd == -1) ? -1 : read(fd, retval, PATH_MAX);
44 char *ptr;
45
46 if (fd != -1)
47 close(fd);
48
49 if ((br < 0) || (br > PATH_MAX))
50 {
51 allocator.Free(retval);
52 BAIL(PHYSFS_ERR_OS_ERROR, NULL);
53 } /* if */
54
55 retval[br] = '\0';
56 ptr = strrchr(retval, '/');
57 if (ptr == NULL) /* uhoh! */
58 {
59 allocator.Free(retval);
60 BAIL(PHYSFS_ERR_OS_ERROR, NULL);
61 } /* if */
62
63 ptr[1] = '\0'; /* chop off filename, leave dirs and '/' */
64
65 ptr = (char *) allocator.Realloc(retval, (ptr - retval) + 2);
66 if (ptr != NULL) /* just shrinking buffer; don't care if it failed. */
67 retval = ptr;
68 } /* else */
69
70 return retval;
71} /* __PHYSFS_platformCalcBaseDir */
72
73
74char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
75{
76 /* !!! FIXME: this might be wrong; I don't know if there's a better method
77 on QNX, or if it follows XDG specs, etc. */
78 char *retval = NULL;
79 const char *home = __PHYSFS_getUserDir();
80 if (home)
81 {
82 const size_t len = strlen(home) + strlen(app) + 3;
83 retval = (char *) allocator.Malloc(len);
84 BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
85 snprintf(retval, len, "%s.%s/", home, app);
86 } /* if */
87 return retval;
88} /* __PHYSFS_platformCalcPrefDir */
89
90
91#if !PHYSFS_NO_CDROM_SUPPORT
92#include <devctl.h>
93#include <sys/dcmd_blk.h>
94#include <dirent.h>
95#include <sys/stat.h>
96#include <sys/statvfs.h>
97
98static void checkPathForCD(const char *path, PHYSFS_StringCallback cb, void *d)
99{
100 struct stat statbuf;
101 int fd;
102
103 /* The devctl() thing is QNX-specific. In this case, we query what is
104 probably the mountpoint for the device. statvfs() on that mountpoint
105 will tell use its filesystem type. */
106
107 if ( (stat(path, &statbuf) == 0) &&
108 (S_ISBLK(statbuf.st_mode)) &&
109 ((fd = open(path, O_RDONLY | O_NONBLOCK)) != -1) )
110 {
111 char mnt[256] = { 0 };
112 const int rc = devctl(fd, DCMD_FSYS_MOUNTED_BY, mnt, sizeof (mnt), 0);
113 close(fd);
114 if ( (rc == EOK) && (mnt[0]) )
115 {
116 struct statvfs statvfsbuf;
117 if (statvfs(mnt, &statvfsbuf) == 0)
118 {
119 /* I don't know if this is a complete or accurate list. */
120 const char *fstype = statvfsbuf.f_basetype;
121 const int iscd = ( (strcmp(fstype, "cd") == 0) ||
122 (strcmp(fstype, "udf") == 0) );
123 if (iscd)
124 cb(d, mnt);
125 } /* if */
126 } /* if */
127 } /* if */
128} /* checkPathForCD */
129
130static void checkDevForCD(const char *dev, PHYSFS_StringCallback cb, void *d)
131{
132 size_t len;
133 char *path;
134
135 if (dev[0] == '.') /* ignore "." and ".." */
136 {
137 if ((dev[1] == '\0') || ((dev[1] == '.') && (dev[2] == '\0')))
138 return;
139 } /* if */
140
141 len = strlen(dev) + 6;
142 path = (char *) __PHYSFS_smallAlloc(len);
143 if (!path)
144 return; /* oh well. */
145
146 snprintf(path, len, "/dev/%s", dev);
147 checkPathForCD(path, cb, d);
148 __PHYSFS_smallFree(path);
149} /* checkDevForCD */
150#endif /* !PHYSFS_NO_CDROM_SUPPORT */
151
152void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
153{
154#if !PHYSFS_NO_CDROM_SUPPORT
155 DIR *dirp = opendir("/dev");
156 if (dirp)
157 {
158 struct dirent *dent;
159 while ((dent = readdir(dirp)) != NULL)
160 checkDevForCD(dent->d_name, cb, data);
161 closedir(dirp);
162 } /* if */
163#endif
164} /* __PHYSFS_platformDetectAvailableCDs */
165
166#endif /* PHYSFS_PLATFORM_QNX */
167
168/* end of physfs_platform_qnx.c ... */
169
170