Ticket #2338: use uintmax_t for file system infomation
[midnight-commander.git] / src / filemanager / mountlist.c
blob85ed76d000e567d7050dad3222ce7229aeab08f7
1 /*
2 Return a list of mounted filesystems
4 Copyright (C) 1991, 1992, 2011
5 The Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /** \file mountlist.c
24 * \brief Source: list of mounted filesystems
27 #include <config.h>
29 #include <stdio.h>
30 #include <stdlib.h>
32 #include <sys/types.h>
34 /* This header needs to be included before sys/mount.h on *BSD */
35 #ifdef HAVE_SYS_PARAM_H
36 #include <sys/param.h>
37 #endif
39 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
40 #include <sys/mount.h>
41 #include <sys/fs_types.h>
42 #endif /* MOUNTED_GETFSSTAT */
44 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
45 #include <mntent.h>
46 #if !defined(MOUNTED)
47 #if defined(MNT_MNTTAB) /* HP-UX. */
48 #define MOUNTED MNT_MNTTAB
49 #endif
50 #if defined(MNTTABNAME) /* Dynix. */
51 #define MOUNTED MNTTABNAME
52 #endif
53 #endif
54 #endif
56 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
57 #include <sys/mount.h>
58 #endif
60 #ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */
61 #include <sys/statvfs.h>
62 #define statfs statvfs
63 #endif
65 #ifdef MOUNTED_GETMNT /* Ultrix. */
66 #include <sys/mount.h>
67 #include <sys/fs_types.h>
68 #endif
70 #ifdef MOUNTED_FREAD /* SVR2. */
71 #include <mnttab.h>
72 #endif
74 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
75 #include <mnttab.h>
76 #include <sys/fstyp.h>
77 #include <sys/statfs.h>
78 #endif
80 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
81 #include <sys/mnttab.h>
82 #endif
84 #ifdef MOUNTED_VMOUNT /* AIX. */
85 #include <fshelp.h>
86 #include <sys/vfs.h>
87 #endif
89 #ifdef HAVE_SYS_STATFS_H
90 #include <sys/statfs.h>
91 #endif
93 #ifdef HAVE_INFOMOUNT_QNX
94 #include <sys/disk.h>
95 #include <sys/fsys.h>
96 #endif
98 #ifdef HAVE_SYS_MOUNT_H
99 #include <sys/mount.h>
100 #endif
102 #ifdef HAVE_SYS_VFS_H
103 #include <sys/vfs.h>
104 #endif
106 #ifdef HAVE_SYS_FILSYS_H
107 #include <sys/filsys.h> /* SVR2. */
108 #endif
110 #ifdef HAVE_DUSTAT_H /* AIX PS/2. */
111 #include <sys/dustat.h>
112 #endif
114 #ifdef HAVE_SYS_STATVFS_H /* SVR4. */
115 #include <sys/statvfs.h>
116 #endif
118 #include "lib/global.h"
119 #include "mountlist.h"
121 /*** global variables ****************************************************************************/
123 /*** file scope macro definitions ****************************************************************/
125 #ifdef DOLPHIN
126 /* So special that it's not worth putting this in autoconf. */
127 #undef MOUNTED_FREAD_FSTYP
128 #define MOUNTED_GETMNTTBL
129 #endif
131 #if defined (__QNX__) && !defined(__QNXNTO__) && !defined (HAVE_INFOMOUNT_LIST)
132 #define HAVE_INFOMOUNT_QNX
133 #endif
135 #if defined(HAVE_INFOMOUNT_LIST) || defined(HAVE_INFOMOUNT_QNX)
136 #define HAVE_INFOMOUNT
137 #endif
139 /*** file scope type declarations ****************************************************************/
141 /* A mount table entry. */
142 struct mount_entry
144 char *me_devname; /* Device node pathname, including "/dev/". */
145 char *me_mountdir; /* Mount point directory pathname. */
146 char *me_type; /* "nfs", "4.2", etc. */
147 dev_t me_dev; /* Device number of me_mountdir. */
148 struct mount_entry *me_next;
151 struct fs_usage
153 fsblkcnt_t fsu_blocks; /* Total blocks. */
154 fsblkcnt_t fsu_bfree; /* Free blocks available to superuser. */
155 fsblkcnt_t fsu_bavail; /* Free blocks available to non-superuser. */
156 fsfilcnt_t fsu_files; /* Total file nodes. */
157 fsfilcnt_t fsu_ffree; /* Free file nodes. */
160 /*** file scope variables ************************************************************************/
162 #ifdef HAVE_INFOMOUNT_LIST
163 static struct mount_entry *mount_list = NULL;
164 #endif /* HAVE_INFOMOUNT_LIST */
166 /*** file scope functions ************************************************************************/
167 /* --------------------------------------------------------------------------------------------- */
169 #ifdef HAVE_INFOMOUNT_LIST
170 static void
171 free_mount_entry (struct mount_entry *me)
173 if (!me)
174 return;
175 if (me->me_devname)
176 free (me->me_devname);
177 if (me->me_mountdir)
178 free (me->me_mountdir);
179 if (me->me_type)
180 free (me->me_type);
181 free (me);
184 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
186 /* --------------------------------------------------------------------------------------------- */
187 /* Return the value of the hexadecimal number represented by CP.
188 No prefix (like '0x') or suffix (like 'h') is expected to be
189 part of CP. */
191 static int
192 xatoi (const char *cp)
194 int val;
196 val = 0;
197 while (*cp)
199 if (*cp >= 'a' && *cp <= 'f')
200 val = val * 16 + *cp - 'a' + 10;
201 else if (*cp >= 'A' && *cp <= 'F')
202 val = val * 16 + *cp - 'A' + 10;
203 else if (*cp >= '0' && *cp <= '9')
204 val = val * 16 + *cp - '0';
205 else
206 break;
207 cp++;
209 return val;
211 #endif /* MOUNTED_GETMNTENT1 */
213 #ifdef MOUNTED_GETMNTINFO
215 /* --------------------------------------------------------------------------------------------- */
217 #ifndef HAVE_STRUCT_STATFS_F_FSTYPENAME
218 static char *
219 fstype_to_string (short t)
221 switch (t)
223 #ifdef MOUNT_PC
224 case MOUNT_PC:
225 return "pc";
226 #endif
227 #ifdef MOUNT_MFS
228 case MOUNT_MFS:
229 return "mfs";
230 #endif
231 #ifdef MOUNT_LO
232 case MOUNT_LO:
233 return "lo";
234 #endif
235 #ifdef MOUNT_TFS
236 case MOUNT_TFS:
237 return "tfs";
238 #endif
239 #ifdef MOUNT_TMP
240 case MOUNT_TMP:
241 return "tmp";
242 #endif
243 #ifdef MOUNT_UFS
244 case MOUNT_UFS:
245 return "ufs";
246 #endif
247 #ifdef MOUNT_NFS
248 case MOUNT_NFS:
249 return "nfs";
250 #endif
251 #ifdef MOUNT_MSDOS
252 case MOUNT_MSDOS:
253 return "msdos";
254 #endif
255 #ifdef MOUNT_LFS
256 case MOUNT_LFS:
257 return "lfs";
258 #endif
259 #ifdef MOUNT_LOFS
260 case MOUNT_LOFS:
261 return "lofs";
262 #endif
263 #ifdef MOUNT_FDESC
264 case MOUNT_FDESC:
265 return "fdesc";
266 #endif
267 #ifdef MOUNT_PORTAL
268 case MOUNT_PORTAL:
269 return "portal";
270 #endif
271 #ifdef MOUNT_NULL
272 case MOUNT_NULL:
273 return "null";
274 #endif
275 #ifdef MOUNT_UMAP
276 case MOUNT_UMAP:
277 return "umap";
278 #endif
279 #ifdef MOUNT_KERNFS
280 case MOUNT_KERNFS:
281 return "kernfs";
282 #endif
283 #ifdef MOUNT_PROCFS
284 case MOUNT_PROCFS:
285 return "procfs";
286 #endif
287 #ifdef MOUNT_AFS
288 case MOUNT_AFS:
289 return "afs";
290 #endif
291 #ifdef MOUNT_CD9660
292 case MOUNT_CD9660:
293 return "cd9660";
294 #endif
295 #ifdef MOUNT_UNION
296 case MOUNT_UNION:
297 return "union";
298 #endif
299 #ifdef MOUNT_DEVFS
300 case MOUNT_DEVFS:
301 return "devfs";
302 #endif
303 #ifdef MOUNT_EXT2FS
304 case MOUNT_EXT2FS:
305 return "ext2fs";
306 #endif
307 default:
308 return "?";
311 #endif /* ! HAVE_STRUCT_STATFS_F_FSTYPENAME */
313 #endif /* MOUNTED_GETMNTINFO */
315 /* --------------------------------------------------------------------------------------------- */
317 #ifdef MOUNTED_VMOUNT /* AIX. */
318 static char *
319 fstype_to_string (int t)
321 struct vfs_ent *e;
323 e = getvfsbytype (t);
324 if (!e || !e->vfsent_name)
325 return "none";
326 else
327 return e->vfsent_name;
329 #endif /* MOUNTED_VMOUNT */
331 /* --------------------------------------------------------------------------------------------- */
332 /** Return a list of the currently mounted filesystems, or NULL on error.
333 Add each entry to the tail of the list so that they stay in order.
334 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
335 the returned list are valid. Otherwise, they might not be.
336 If ALL_FS is zero, do not return entries for filesystems that
337 are automounter (dummy) entries. */
339 static struct mount_entry *
340 read_filesystem_list (int need_fs_type, int all_fs)
342 struct mount_entry *mlist;
343 struct mount_entry *me;
344 struct mount_entry *mtail;
346 (void) need_fs_type;
347 (void) all_fs;
349 /* Start the list off with a dummy entry. */
350 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
351 me->me_next = NULL;
352 mlist = mtail = me;
354 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
355 #ifdef MOUNTED
357 struct mntent *mnt;
358 FILE *fp;
359 const char *devopt;
361 fp = setmntent (MOUNTED, "r");
362 if (fp == NULL)
363 return NULL;
365 while ((mnt = getmntent (fp)))
367 if (!all_fs && (!strcmp (mnt->mnt_type, "ignore") || !strcmp (mnt->mnt_type, "auto")))
368 continue;
370 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
371 me->me_devname = strdup (mnt->mnt_fsname);
372 me->me_mountdir = strdup (mnt->mnt_dir);
373 me->me_type = strdup (mnt->mnt_type);
374 devopt = strstr (mnt->mnt_opts, "dev=");
375 if (devopt)
377 if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
378 me->me_dev = xatoi (devopt + 6);
379 else
380 me->me_dev = xatoi (devopt + 4);
382 else
383 me->me_dev = -1; /* Magic; means not known yet. */
384 me->me_next = NULL;
386 /* Add to the linked list. */
387 mtail->me_next = me;
388 mtail = me;
391 if (endmntent (fp) == 0)
392 return NULL;
394 #endif /* MOUNTED */
395 #endif /* MOUNTED_GETMNTENT1 */
397 #if defined(MOUNTED_GETMNTINFO) || defined(MOUNTED_GETMNTINFO2) /* 4.4BSD and NetBSD >= 3 */
399 struct statfs *fsp;
400 int entries;
402 entries = getmntinfo (&fsp, MNT_NOWAIT);
403 if (entries < 0)
404 return NULL;
405 while (entries-- > 0)
407 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
408 me->me_devname = strdup (fsp->f_mntfromname);
409 me->me_mountdir = strdup (fsp->f_mntonname);
410 #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || defined(MOUNTED_GETMNTINFO2)
411 me->me_type = strdup (fsp->f_fstypename);
412 #else
413 me->me_type = fstype_to_string (fsp->f_type);
414 #endif
415 me->me_dev = -1; /* Magic; means not known yet. */
416 me->me_next = NULL;
418 /* Add to the linked list. */
419 mtail->me_next = me;
420 mtail = me;
421 fsp++;
424 #endif /* MOUNTED_GETMNTINFO || MOUNTED_GETMNTINFO2 */
426 #ifdef MOUNTED_GETMNT /* Ultrix. */
428 int offset = 0;
429 int val;
430 struct fs_data fsd;
432 while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, NULL)) > 0)
434 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
435 me->me_devname = strdup (fsd.fd_req.devname);
436 me->me_mountdir = strdup (fsd.fd_req.path);
437 me->me_type = gt_names[fsd.fd_req.fstype];
438 me->me_dev = fsd.fd_req.dev;
439 me->me_next = NULL;
441 /* Add to the linked list. */
442 mtail->me_next = me;
443 mtail = me;
445 if (val < 0)
446 return NULL;
448 #endif /* MOUNTED_GETMNT */
450 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
452 int numsys, counter, bufsize;
453 struct statfs *stats;
455 numsys = getfsstat ((struct statfs *) 0, 0L, MNT_WAIT);
456 if (numsys < 0)
457 return (NULL);
459 bufsize = (1 + numsys) * sizeof (struct statfs);
460 stats = (struct statfs *) malloc (bufsize);
461 numsys = getfsstat (stats, bufsize, MNT_WAIT);
463 if (numsys < 0)
465 free (stats);
466 return (NULL);
468 for (counter = 0; counter < numsys; counter++)
470 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
471 me->me_devname = strdup (stats[counter].f_mntfromname);
472 me->me_mountdir = strdup (stats[counter].f_mntonname);
473 me->me_type = mnt_names[stats[counter].f_type];
474 me->me_dev = -1; /* Magic; means not known yet. */
475 me->me_next = NULL;
477 /* Add to the linked list. */
478 mtail->me_next = me;
479 mtail = me;
482 free (stats);
484 #endif /* MOUNTED_GETFSSTAT */
486 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
488 struct mnttab mnt;
489 char *table = "/etc/mnttab";
490 FILE *fp;
492 fp = fopen (table, "r");
493 if (fp == NULL)
494 return NULL;
496 while (fread (&mnt, sizeof mnt, 1, fp) > 0)
498 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
499 #ifdef GETFSTYP /* SVR3. */
500 me->me_devname = strdup (mnt.mt_dev);
501 #else
502 me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
503 strcpy (me->me_devname, "/dev/");
504 strcpy (me->me_devname + 5, mnt.mt_dev);
505 #endif
506 me->me_mountdir = strdup (mnt.mt_filsys);
507 me->me_dev = -1; /* Magic; means not known yet. */
508 me->me_type = "";
509 #ifdef GETFSTYP /* SVR3. */
510 if (need_fs_type)
512 struct statfs fsd;
513 char typebuf[FSTYPSZ];
515 if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
516 && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
517 me->me_type = strdup (typebuf);
519 #endif
520 me->me_next = NULL;
522 /* Add to the linked list. */
523 mtail->me_next = me;
524 mtail = me;
527 if (fclose (fp) == EOF)
528 return NULL;
530 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP */
532 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
534 struct mntent **mnttbl = getmnttbl (), **ent;
535 for (ent = mnttbl; *ent; ent++)
537 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
538 me->me_devname = strdup ((*ent)->mt_resource);
539 me->me_mountdir = strdup ((*ent)->mt_directory);
540 me->me_type = strdup ((*ent)->mt_fstype);
541 me->me_dev = -1; /* Magic; means not known yet. */
542 me->me_next = NULL;
544 /* Add to the linked list. */
545 mtail->me_next = me;
546 mtail = me;
548 endmnttbl ();
550 #endif /* MOUNTED_GETMNTTBL */
552 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
554 struct mnttab mnt;
555 const char *table = MNTTAB;
556 FILE *fp;
557 int ret;
559 fp = fopen (table, "r");
560 if (fp == NULL)
561 return NULL;
563 while ((ret = getmntent (fp, &mnt)) == 0)
565 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
566 me->me_devname = strdup (mnt.mnt_special);
567 me->me_mountdir = strdup (mnt.mnt_mountp);
568 me->me_type = strdup (mnt.mnt_fstype);
569 me->me_dev = -1; /* Magic; means not known yet. */
570 me->me_next = NULL;
571 /* Add to the linked list. */
572 mtail->me_next = me;
573 mtail = me;
576 if (ret > 0)
577 return NULL;
578 if (fclose (fp) == EOF)
579 return NULL;
581 #endif /* MOUNTED_GETMNTENT2 */
583 #ifdef MOUNTED_VMOUNT /* AIX. */
585 int bufsize;
586 char *entries, *thisent;
587 struct vmount *vmp;
589 /* Ask how many bytes to allocate for the mounted filesystem info. */
590 mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
591 entries = malloc (bufsize);
593 /* Get the list of mounted filesystems. */
594 mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
596 for (thisent = entries; thisent < entries + bufsize; thisent += vmp->vmt_length)
598 vmp = (struct vmount *) thisent;
599 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
600 if (vmp->vmt_flags & MNT_REMOTE)
602 char *host, *path;
604 /* Prepend the remote pathname. */
605 host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
606 path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
607 me->me_devname = malloc (strlen (host) + strlen (path) + 2);
608 strcpy (me->me_devname, host);
609 strcat (me->me_devname, ":");
610 strcat (me->me_devname, path);
612 else
614 me->me_devname = strdup (thisent + vmp->vmt_data[VMT_OBJECT].vmt_off);
616 me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
617 me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
618 me->me_dev = -1; /* vmt_fsid might be the info we want. */
619 me->me_next = NULL;
621 /* Add to the linked list. */
622 mtail->me_next = me;
623 mtail = me;
625 free (entries);
627 #endif /* MOUNTED_VMOUNT */
629 /* Free the dummy head. */
630 me = mlist;
631 mlist = mlist->me_next;
632 free (me);
633 return mlist;
635 #endif /* HAVE_INFOMOUNT_LIST */
637 /* --------------------------------------------------------------------------------------------- */
639 #ifdef HAVE_INFOMOUNT_QNX
641 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
642 ** this via the following code.
643 ** Note that, as this is based on CWD, it only fills one mount_entry
644 ** structure. See my_statfs() in utilunix.c for the "other side" of
645 ** this hack.
648 static struct mount_entry *
649 read_filesystem_list (int need_fs_type, int all_fs)
651 struct _disk_entry de;
652 struct statfs fs;
653 int i, fd;
654 char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
656 static struct mount_entry *me = NULL;
658 if (me)
660 if (me->me_devname)
661 free (me->me_devname);
662 if (me->me_mountdir)
663 free (me->me_mountdir);
664 if (me->me_type)
665 free (me->me_type);
667 else
668 me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
670 if (!getcwd (dir, _POSIX_PATH_MAX))
671 return (NULL);
673 fd = open (dir, O_RDONLY);
674 if (fd == -1)
675 return (NULL);
677 i = disk_get_entry (fd, &de);
679 close (fd);
681 if (i == -1)
682 return (NULL);
684 switch (de.disk_type)
686 case _UNMOUNTED:
687 tp = "unmounted";
688 break;
689 case _FLOPPY:
690 tp = "Floppy";
691 break;
692 case _HARD:
693 tp = "Hard";
694 break;
695 case _RAMDISK:
696 tp = "Ram";
697 break;
698 case _REMOVABLE:
699 tp = "Removable";
700 break;
701 case _TAPE:
702 tp = "Tape";
703 break;
704 case _CDROM:
705 tp = "CDROM";
706 break;
707 default:
708 tp = "unknown";
711 if (fsys_get_mount_dev (dir, &dev) == -1)
712 return (NULL);
714 if (fsys_get_mount_pt (dev, &dir) == -1)
715 return (NULL);
717 me->me_devname = strdup (dev);
718 me->me_mountdir = strdup (dir);
719 me->me_type = strdup (tp);
720 me->me_dev = de.disk_type;
722 #ifdef DEBUG
723 fprintf (stderr,
724 "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
725 de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
726 fprintf (stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
727 fprintf (stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
728 #endif /* DEBUG */
730 return (me);
732 #endif /* HAVE_INFOMOUNT_QNX */
734 #ifdef HAVE_INFOMOUNT
735 /** Return the number of TOSIZE-byte blocks used by
736 BLOCKS FROMSIZE-byte blocks, rounding away from zero.
737 TOSIZE must be positive. Return -1 if FROMSIZE is not positive. */
739 static fsblkcnt_t
740 fs_adjust_blocks (fsblkcnt_t blocks, int fromsize, int tosize)
742 if (tosize <= 0)
743 abort ();
744 if (fromsize <= 0)
745 return -1;
747 if (fromsize == tosize) /* E.g., from 512 to 512. */
748 return blocks;
749 else if (fromsize > tosize) /* E.g., from 2048 to 512. */
750 return blocks * (fromsize / tosize);
751 else /* E.g., from 256 to 512. */
752 return blocks / (tosize / fromsize);
755 /* --------------------------------------------------------------------------------------------- */
756 #if defined(_AIX) && defined(_I386)
757 /* AIX PS/2 does not supply statfs. */
758 static int
759 aix_statfs (char *path, struct statfs *fsb)
761 struct stat stats;
762 struct dustat fsd;
764 if (stat (path, &stats))
765 return -1;
766 if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
767 return -1;
768 fsb->f_type = 0;
769 fsb->f_bsize = fsd.du_bsize;
770 fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
771 fsb->f_bfree = fsd.du_tfree;
772 fsb->f_bavail = fsd.du_tfree;
773 fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
774 fsb->f_ffree = fsd.du_tinode;
775 fsb->f_fsid.val[0] = fsd.du_site;
776 fsb->f_fsid.val[1] = fsd.du_pckno;
777 return 0;
780 #define statfs(path,fsb) aix_statfs(path,fsb)
781 #endif /* _AIX && _I386 */
783 /* Fill in the fields of FSP with information about space usage for
784 the filesystem on which PATH resides.
785 Return 0 if successful, -1 if not. */
787 /* --------------------------------------------------------------------------------------------- */
788 static int
789 get_fs_usage (char *path, struct fs_usage *fsp)
791 #ifdef STAT_STATFS3_OSF1
792 struct statfs fsd;
794 if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
795 return -1;
796 #define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_fsize, 512)
797 #endif /* STAT_STATFS3_OSF1 */
799 #ifdef STAT_STATFS2_FS_DATA /* Ultrix. */
800 struct fs_data fsd;
802 if (statfs (path, &fsd) != 1)
803 return -1;
804 #define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), 1024, 512)
805 fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot);
806 fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree);
807 fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen);
808 fsp->fsu_files = fsd.fd_req.gtot;
809 fsp->fsu_ffree = fsd.fd_req.gfree;
810 #endif
812 #ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
813 struct statfs fsd;
815 if (statfs (path, &fsd) < 0)
816 return -1;
817 #define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_bsize, 512)
818 #endif
820 #ifdef STAT_STATFS2_FSIZE /* 4.4BSD. */
821 struct statfs fsd;
823 if (statfs (path, &fsd) < 0)
824 return -1;
825 #define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_fsize, 512)
826 #endif
828 #ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX. */
829 struct statfs fsd;
831 if (statfs (path, &fsd, sizeof fsd, 0) < 0)
832 return -1;
833 /* Empirically, the block counts on most SVR3 and SVR3-derived
834 systems seem to always be in terms of 512-byte blocks,
835 no matter what value f_bsize has. */
836 #if _AIX
837 #define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_bsize, 512)
838 #else
839 #define CONVERT_BLOCKS(b) (b)
840 #ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
841 #ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
842 #define f_bavail f_bfree
843 #endif
844 #endif
845 #endif
846 #endif
848 #ifdef STAT_STATVFS /* SVR4. */
849 struct statvfs fsd;
851 if (statvfs (path, &fsd) < 0)
852 return -1;
853 /* f_frsize isn't guaranteed to be supported. */
854 #define CONVERT_BLOCKS(b) \
855 fs_adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
856 #endif
858 #if defined(CONVERT_BLOCKS) && !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS) /* !Ultrix && !SVR2. */
859 fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks);
860 fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree);
861 fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail);
862 fsp->fsu_files = fsd.f_files;
863 fsp->fsu_ffree = fsd.f_ffree;
864 #endif
866 return 0;
869 #endif /* HAVE_INFOMOUNT */
871 /* --------------------------------------------------------------------------------------------- */
872 /*** public functions ****************************************************************************/
873 /* --------------------------------------------------------------------------------------------- */
875 void
876 free_my_statfs (void)
878 #ifdef HAVE_INFOMOUNT_LIST
879 while (mount_list)
881 struct mount_entry *next = mount_list->me_next;
882 free_mount_entry (mount_list);
883 mount_list = next;
885 mount_list = NULL;
886 #endif /* HAVE_INFOMOUNT_LIST */
889 /* --------------------------------------------------------------------------------------------- */
891 void
892 init_my_statfs (void)
894 #ifdef HAVE_INFOMOUNT_LIST
895 free_my_statfs ();
896 mount_list = read_filesystem_list (1, 1);
897 #endif /* HAVE_INFOMOUNT_LIST */
900 /* --------------------------------------------------------------------------------------------- */
902 void
903 my_statfs (struct my_statfs *myfs_stats, const char *path)
905 #ifdef HAVE_INFOMOUNT_LIST
906 size_t i, len = 0;
907 struct mount_entry *entry = NULL;
908 struct mount_entry *temp = mount_list;
909 struct fs_usage fs_use;
911 while (temp)
913 i = strlen (temp->me_mountdir);
914 if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
915 if (!entry || (path[i] == PATH_SEP || path[i] == '\0'))
917 len = i;
918 entry = temp;
920 temp = temp->me_next;
923 if (entry)
925 memset (&fs_use, 0, sizeof (struct fs_usage));
926 get_fs_usage (entry->me_mountdir, &fs_use);
928 myfs_stats->type = entry->me_dev;
929 myfs_stats->typename = entry->me_type;
930 myfs_stats->mpoint = entry->me_mountdir;
931 myfs_stats->device = entry->me_devname;
932 myfs_stats->avail = (uintmax_t) (getuid () ? fs_use.fsu_bavail : fs_use.fsu_bfree) / 2;
933 myfs_stats->total = (uintmax_t) fs_use.fsu_blocks / 2;
934 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
935 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
937 else
938 #endif /* HAVE_INFOMOUNT_LIST */
940 #ifdef HAVE_INFOMOUNT_QNX
942 ** This is the "other side" of the hack to read_filesystem_list() in
943 ** mountlist.c.
944 ** It's not the most efficient approach, but consumes less memory. It
945 ** also accomodates QNX's ability to mount filesystems on the fly.
947 struct mount_entry *entry;
948 struct fs_usage fs_use;
950 entry = read_filesystem_list (0, 0);
951 if (entry != NULL)
953 get_fs_usage (entry->me_mountdir, &fs_use);
955 myfs_stats->type = entry->me_dev;
956 myfs_stats->typename = entry->me_type;
957 myfs_stats->mpoint = entry->me_mountdir;
958 myfs_stats->device = entry->me_devname;
960 myfs_stats->avail = (uintmax_t) fs_use.fsu_bfree / 2;
961 myfs_stats->total = (uintmax_t) fs_use.fsu_blocks / 2;
962 myfs_stats->nfree = (uintmax_t) fs_use.fsu_ffree;
963 myfs_stats->nodes = (uintmax_t) fs_use.fsu_files;
965 else
966 #endif /* HAVE_INFOMOUNT_QNX */
968 myfs_stats->type = 0;
969 myfs_stats->mpoint = "unknown";
970 myfs_stats->device = "unknown";
971 myfs_stats->avail = 0;
972 myfs_stats->total = 0;
973 myfs_stats->nfree = 0;
974 myfs_stats->nodes = 0;
978 /* --------------------------------------------------------------------------------------------- */