7 #include <rpm/rpmlib.h> /* rpmGetFilesystem*() prototypes */
8 #include <rpm/rpmfileutil.h> /* for rpmGetPath */
9 #include <rpm/rpmlog.h>
15 char * mntPoint; /*!< path to mount point. */
16 dev_t dev; /*!< devno for mount point. */
17 int rdonly; /*!< is mount point read only? */
20 static struct fsinfo * filesystems = NULL;
21 static const char ** fsnames = NULL;
22 static int numFilesystems = 0;
24 void rpmFreeFilesystems(void)
29 for (i = 0; i < numFilesystems; i++)
30 filesystems[i].mntPoint = _free(filesystems[i].mntPoint);
32 filesystems = _free(filesystems);
33 fsnames = _free(fsnames);
39 /* modeled after sample code from Till Bubeck */
41 #include <sys/mntctl.h>
42 #include <sys/vmount.h>
45 * There is NO mntctl prototype in any header file of AIX 3.2.5!
46 * So we have to declare it by ourself...
48 int mntctl(int command, int size, char *buffer);
51 * Get information for mounted file systems.
52 * @todo determine rdonly for non-linux file systems.
53 * @return 0 on success, 1 on error
55 static int getFilesystemList(void)
65 int rc = 1; /* assume failure */
67 num = mntctl(MCTL_QUERY, sizeof(size), (char *) &size);
69 rpmlog(RPMLOG_ERR, _("mntctl() failed to return size: %s\n"),
75 * Double the needed size, so that even when the user mounts a
76 * filesystem between the previous and the next call to mntctl
77 * the buffer still is large enough.
82 num = mntctl(MCTL_QUERY, size, buf);
84 rpmlog(RPMLOG_ERR, _("mntctl() failed to return mount points: %s\n"),
91 filesystems = xcalloc((numFilesystems + 1), sizeof(*filesystems));
92 fsnames = xcalloc((numFilesystems + 1), sizeof(char *));
94 for (vm = buf, i = 0; i < num; i++) {
96 fsnameLength = vm->vmt_data[VMT_STUB].vmt_size;
97 fsn = xmalloc(fsnameLength + 1);
98 strncpy(fsn, (char *)vm + vm->vmt_data[VMT_STUB].vmt_off,
100 fsn[fsnameLength] = '\0';
102 filesystems[i].mntPoint = fsnames[i] = fsn;
104 if (stat(filesystems[i].mntPoint, &sb)) {
106 case EACCES: /* fuse mount */
110 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), fsnames[i],
113 rpmFreeFilesystems();
118 filesystems[i].dev = sb.st_dev;
119 filesystems[i].rdonly = rdonly;
121 /* goto the next vmount structure: */
122 vm = (struct vmount *)((char *)vm + vm->vmt_length);
125 filesystems[i].mntPoint = NULL;
135 #else /* HAVE_MNTCTL */
138 * Get information for mounted file systems.
139 * @todo determine rdonly for non-linux file systems.
140 * @return 0 on success, 1 on error
142 static int getFilesystemList(void)
150 # if GETMNTENT_ONE || GETMNTENT_TWO
154 mtab = fopen(MOUNTED, "r");
156 rpmlog(RPMLOG_ERR, _("failed to open %s: %s\n"), MOUNTED,
160 # elif HAVE_GETMNTINFO_R
162 struct statfs * mounts = NULL;
163 int mntCount = 0, bufSize = 0, flags = MNT_NOWAIT;
166 getmntinfo_r(&mounts, flags, &mntCount, &bufSize);
167 # elif HAVE_GETMNTINFO
168 /* This is Mac OS X */
169 struct statfs * mounts = NULL;
170 int mntCount = 0, flags = MNT_NOWAIT;
173 /* XXX 0 on error, errno set */
174 mntCount = getmntinfo(&mounts, flags);
177 filesystems = xcalloc((numAlloced + 1), sizeof(*filesystems)); /* XXX memory leak */
183 our_mntent * itemptr = getmntent(mtab);
185 item = *itemptr; /* structure assignment */
186 mntdir = item.our_mntdir;
187 #if defined(MNTOPT_RO)
188 if (hasmntopt(itemptr, MNTOPT_RO) != NULL)
192 /* Solaris, maybe others */
193 if (getmntent(mtab, &item)) break;
194 mntdir = item.our_mntdir;
195 # elif HAVE_GETMNTINFO_R
197 if (nextMount == mntCount) break;
198 mntdir = mounts[nextMount++].f_mntonname;
199 # elif HAVE_GETMNTINFO
200 /* This is Mac OS X */
201 if (nextMount == mntCount) break;
202 mntdir = mounts[nextMount++].f_mntonname;
205 if (stat(mntdir, &sb)) {
211 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), mntdir,
213 rpmFreeFilesystems();
218 if ((numFilesystems + 2) == numAlloced) {
220 filesystems = xrealloc(filesystems,
221 sizeof(*filesystems) * (numAlloced + 1));
224 filesystems[numFilesystems].dev = sb.st_dev;
225 filesystems[numFilesystems].mntPoint = xstrdup(mntdir);
226 filesystems[numFilesystems].rdonly = rdonly;
228 rpmlog(RPMLOG_DEBUG, "%5d 0x%04x %s %s\n",
230 (unsigned) filesystems[numFilesystems].dev,
231 (filesystems[numFilesystems].rdonly ? "ro" : "rw"),
232 filesystems[numFilesystems].mntPoint);
237 # if GETMNTENT_ONE || GETMNTENT_TWO
239 # elif HAVE_GETMNTINFO_R
240 mounts = _free(mounts);
243 filesystems[numFilesystems].dev = 0;
244 filesystems[numFilesystems].mntPoint = NULL;
245 filesystems[numFilesystems].rdonly = 0;
247 fsnames = xcalloc((numFilesystems + 1), sizeof(*fsnames));
248 for (i = 0; i < numFilesystems; i++)
249 fsnames[i] = filesystems[i].mntPoint;
250 fsnames[numFilesystems] = NULL;
252 /* FIX: fsnames[] may be NULL */
255 #endif /* HAVE_MNTCTL */
257 int rpmGetFilesystemList(const char *** listptr, unsigned int * num)
260 if (getFilesystemList())
263 if (listptr) *listptr = fsnames;
264 if (num) *num = numFilesystems;
269 int rpmGetFilesystemUsage(const char ** fileList, rpm_loff_t * fssizes,
270 unsigned int numFiles,
271 rpm_loff_t ** usagesPtr, int flags)
275 char * buf, * dirName;
281 int lastDev = -1; /* I hope nobody uses -1 for a st_dev */
286 if (getFilesystemList())
289 usages = xcalloc(numFilesystems, sizeof(usages));
291 sourceDir = rpmGetPath("%{_sourcedir}", NULL);
293 maxLen = strlen(sourceDir);
294 for (i = 0; i < numFiles; i++) {
295 len = strlen(fileList[i]);
296 if (maxLen < len) maxLen = len;
299 buf = xmalloc(maxLen + 1);
300 lastDir = xmalloc(maxLen + 1);
301 dirName = xmalloc(maxLen + 1);
304 /* cut off last filename */
305 for (i = 0; i < numFiles; i++) {
306 if (*fileList[i] == '/') {
307 strcpy(buf, fileList[i]);
308 chptr = buf + strlen(buf) - 1;
309 while (*chptr != '/') chptr--;
315 /* this should only happen for source packages (gulp) */
316 strcpy(buf, sourceDir);
319 if (!rstreq(lastDir, buf)) {
320 strcpy(dirName, buf);
321 chptr = dirName + strlen(dirName) - 1;
322 while (stat(dirName, &sb)) {
323 if (errno != ENOENT) {
324 rpmlog(RPMLOG_ERR, _("failed to stat %s: %s\n"), buf,
329 /* cut off last directory part, because it was not found. */
330 while (*chptr != '/') chptr--;
332 if (chptr == dirName)
338 if (lastDev != sb.st_dev) {
339 for (j = 0; j < numFilesystems; j++)
340 if (filesystems && filesystems[j].dev == sb.st_dev)
343 if (j == numFilesystems) {
345 _("file %s is on an unknown device\n"), buf);
354 strcpy(lastDir, buf);
355 usages[lastfs] += fssizes[i];