1 /* mountlist.c -- return a list of mounted filesystems
2 Copyright (C) 1991, 1992 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22 #include <sys/types.h>
29 void free (void *ptr
);
31 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
41 #ifdef HAVE_SYS_PARAM_H
42 #include <sys/param.h>
45 #if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
46 #include <sys/mount.h>
47 #include <sys/fs_types.h>
48 #endif /* MOUNTED_GETFSSTAT */
50 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
53 #if defined(MNT_MNTTAB) /* HP-UX. */
54 #define MOUNTED MNT_MNTTAB
56 #if defined(MNTTABNAME) /* Dynix. */
57 #define MOUNTED MNTTABNAME
62 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
63 #include <sys/mount.h>
66 #ifdef MOUNTED_GETMNT /* Ultrix. */
67 #include <sys/mount.h>
68 #include <sys/fs_types.h>
71 #ifdef MOUNTED_FREAD /* SVR2. */
75 #ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
77 #include <sys/fstyp.h>
78 #include <sys/statfs.h>
81 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
82 #include <sys/mnttab.h>
85 #ifdef MOUNTED_VMOUNT /* AIX. */
90 #ifdef HAVE_SYS_STATFS_H
91 #include <sys/statfs.h>
94 #ifdef HAVE_INFOMOUNT_QNX
100 #include "mountlist.h"
104 /* void error (void); FIXME -- needed? */
107 /* So special that it's not worth putting this in autoconf. */
108 #undef MOUNTED_FREAD_FSTYP
109 #define MOUNTED_GETMNTTBL
112 /* A mount table entry. */
115 char *me_devname
; /* Device node pathname, including "/dev/". */
116 char *me_mountdir
; /* Mount point directory pathname. */
117 char *me_type
; /* "nfs", "4.2", etc. */
118 dev_t me_dev
; /* Device number of me_mountdir. */
119 struct mount_entry
*me_next
;
122 #ifdef HAVE_INFOMOUNT_LIST
124 static struct mount_entry
*mount_list
= NULL
;
126 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
127 /* Return the value of the hexadecimal number represented by CP.
128 No prefix (like '0x') or suffix (like 'h') is expected to be
131 static int xatoi (char *cp
)
137 if (*cp
>= 'a' && *cp
<= 'f')
138 val
= val
* 16 + *cp
- 'a' + 10;
139 else if (*cp
>= 'A' && *cp
<= 'F')
140 val
= val
* 16 + *cp
- 'A' + 10;
141 else if (*cp
>= '0' && *cp
<= '9')
142 val
= val
* 16 + *cp
- '0';
149 #endif /* MOUNTED_GETMNTENT1 */
151 #if defined (MOUNTED_GETMNTINFO) && !defined (HAVE_F_FSTYPENAME)
152 static char *fstype_to_string (short t
)
183 #endif /* MOUNTED_GETMNTINFO && !HAVE_F_FSTYPENAME */
185 #ifdef MOUNTED_VMOUNT /* AIX. */
187 fstype_to_string (int t
)
191 e
= getvfsbytype (t
);
192 if (!e
|| !e
->vfsent_name
)
195 return e
->vfsent_name
;
197 #endif /* MOUNTED_VMOUNT */
199 /* Return a list of the currently mounted filesystems, or NULL on error.
200 Add each entry to the tail of the list so that they stay in order.
201 If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
202 the returned list are valid. Otherwise, they might not be.
203 If ALL_FS is zero, do not return entries for filesystems that
204 are automounter (dummy) entries. */
206 static struct mount_entry
*
207 read_filesystem_list (int need_fs_type
, int all_fs
)
209 struct mount_entry
*mlist
;
210 struct mount_entry
*me
;
211 struct mount_entry
*mtail
;
213 /* Start the list off with a dummy entry. */
214 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
218 #ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
221 char *table
= MOUNTED
;
225 fp
= setmntent (table
, "r");
229 while ((mnt
= getmntent (fp
))) {
230 if (!all_fs
&& (!strcmp (mnt
->mnt_type
, "ignore")
231 || !strcmp (mnt
->mnt_type
, "auto")))
234 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
235 me
->me_devname
= strdup (mnt
->mnt_fsname
);
236 me
->me_mountdir
= strdup (mnt
->mnt_dir
);
237 me
->me_type
= strdup (mnt
->mnt_type
);
238 devopt
= strstr (mnt
->mnt_opts
, "dev=");
240 if (devopt
[4] == '0' && (devopt
[5] == 'x' || devopt
[5] == 'X'))
241 me
->me_dev
= xatoi (devopt
+ 6);
243 me
->me_dev
= xatoi (devopt
+ 4);
245 me
->me_dev
= -1; /* Magic; means not known yet. */
248 /* Add to the linked list. */
253 if (endmntent (fp
) == 0)
256 #endif /* MOUNTED_GETMNTENT1 */
258 #ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
263 entries
= getmntinfo (&fsp
, MNT_NOWAIT
);
266 while (entries
-- > 0) {
267 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
268 me
->me_devname
= strdup (fsp
->f_mntfromname
);
269 me
->me_mountdir
= strdup (fsp
->f_mntonname
);
270 #ifdef HAVE_F_FSTYPENAME
271 me
->me_type
= strdup (fsp
->f_fstypename
);
273 me
->me_type
= fstype_to_string (fsp
->f_type
);
275 me
->me_dev
= -1; /* Magic; means not known yet. */
278 /* Add to the linked list. */
284 #endif /* MOUNTED_GETMNTINFO */
286 #ifdef MOUNTED_GETMNT /* Ultrix. */
292 while ((val
= getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
,
294 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
295 me
->me_devname
= strdup (fsd
.fd_req
.devname
);
296 me
->me_mountdir
= strdup (fsd
.fd_req
.path
);
297 me
->me_type
= gt_names
[fsd
.fd_req
.fstype
];
298 me
->me_dev
= fsd
.fd_req
.dev
;
301 /* Add to the linked list. */
308 #endif /* MOUNTED_GETMNT */
310 #ifdef MOUNTED_GETFSSTAT /* __alpha running OSF_1 */
312 int numsys
, counter
, bufsize
;
313 struct statfs
*stats
;
315 numsys
= getfsstat ((struct statfs
*) 0, 0L, MNT_WAIT
);
319 bufsize
= (1 + numsys
) * sizeof (struct statfs
);
320 stats
= (struct statfs
*) malloc (bufsize
);
321 numsys
= getfsstat (stats
, bufsize
, MNT_WAIT
);
327 for (counter
= 0; counter
< numsys
; counter
++) {
328 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
329 me
->me_devname
= strdup (stats
[counter
].f_mntfromname
);
330 me
->me_mountdir
= strdup (stats
[counter
].f_mntonname
);
331 me
->me_type
= mnt_names
[stats
[counter
].f_type
];
332 me
->me_dev
= -1; /* Magic; means not known yet. */
335 /* Add to the linked list. */
342 #endif /* MOUNTED_GETFSSTAT */
344 #if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
347 char *table
= "/etc/mnttab";
350 fp
= fopen (table
, "r");
354 while (fread (&mnt
, sizeof mnt
, 1, fp
) > 0) {
355 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
356 #ifdef GETFSTYP /* SVR3. */
357 me
->me_devname
= strdup (mnt
.mt_dev
);
359 me
->me_devname
= malloc (strlen (mnt
.mt_dev
) + 6);
360 strcpy (me
->me_devname
, "/dev/");
361 strcpy (me
->me_devname
+ 5, mnt
.mt_dev
);
363 me
->me_mountdir
= strdup (mnt
.mt_filsys
);
364 me
->me_dev
= -1; /* Magic; means not known yet. */
366 #ifdef GETFSTYP /* SVR3. */
369 char typebuf
[FSTYPSZ
];
371 if (statfs (me
->me_mountdir
, &fsd
, sizeof fsd
, 0) != -1
372 && sysfs (GETFSTYP
, fsd
.f_fstyp
, typebuf
) != -1)
373 me
->me_type
= strdup (typebuf
);
378 /* Add to the linked list. */
383 if (fclose (fp
) == EOF
)
386 #endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP */
388 #ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
390 struct mntent
**mnttbl
= getmnttbl (), **ent
;
391 for (ent
= mnttbl
; *ent
; ent
++) {
392 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
393 me
->me_devname
= strdup ((*ent
)->mt_resource
);
394 me
->me_mountdir
= strdup ((*ent
)->mt_directory
);
395 me
->me_type
= strdup ((*ent
)->mt_fstype
);
396 me
->me_dev
= -1; /* Magic; means not known yet. */
399 /* Add to the linked list. */
405 #endif /* MOUNTED_GETMNTTBL */
407 #ifdef MOUNTED_GETMNTENT2 /* SVR4. */
410 char *table
= MNTTAB
;
414 fp
= fopen (table
, "r");
418 while ((ret
= getmntent (fp
, &mnt
)) == 0) {
419 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
420 me
->me_devname
= strdup (mnt
.mnt_special
);
421 me
->me_mountdir
= strdup (mnt
.mnt_mountp
);
422 me
->me_type
= strdup (mnt
.mnt_fstype
);
423 me
->me_dev
= -1; /* Magic; means not known yet. */
425 /* Add to the linked list. */
432 if (fclose (fp
) == EOF
)
435 #endif /* MOUNTED_GETMNTENT2 */
437 #ifdef MOUNTED_VMOUNT /* AIX. */
440 char *entries
, *thisent
;
443 /* Ask how many bytes to allocate for the mounted filesystem info. */
444 mntctl (MCTL_QUERY
, sizeof bufsize
, (struct vmount
*) &bufsize
);
445 entries
= malloc (bufsize
);
447 /* Get the list of mounted filesystems. */
448 mntctl (MCTL_QUERY
, bufsize
, (struct vmount
*) entries
);
450 for (thisent
= entries
; thisent
< entries
+ bufsize
;
451 thisent
+= vmp
->vmt_length
) {
452 vmp
= (struct vmount
*) thisent
;
453 me
= (struct mount_entry
*) malloc (sizeof (struct mount_entry
));
454 if (vmp
->vmt_flags
& MNT_REMOTE
) {
457 /* Prepend the remote pathname. */
458 host
= thisent
+ vmp
->vmt_data
[VMT_HOSTNAME
].vmt_off
;
459 path
= thisent
+ vmp
->vmt_data
[VMT_OBJECT
].vmt_off
;
460 me
->me_devname
= malloc (strlen (host
) + strlen (path
) + 2);
461 strcpy (me
->me_devname
, host
);
462 strcat (me
->me_devname
, ":");
463 strcat (me
->me_devname
, path
);
465 me
->me_devname
= strdup (thisent
+
466 vmp
->vmt_data
[VMT_OBJECT
].vmt_off
);
468 me
->me_mountdir
= strdup (thisent
+ vmp
->vmt_data
[VMT_STUB
].vmt_off
);
469 me
->me_type
= strdup (fstype_to_string (vmp
->vmt_gfstype
));
470 me
->me_dev
= -1; /* vmt_fsid might be the info we want. */
473 /* Add to the linked list. */
479 #endif /* MOUNTED_VMOUNT */
481 /* Free the dummy head. */
483 mlist
= mlist
->me_next
;
487 #endif /* HAVE_INFOMOUNT_LIST */
489 #ifdef HAVE_INFOMOUNT_QNX
491 ** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
492 ** this via the following code.
493 ** Note that, as this is based on CWD, it only fills one mount_entry
494 ** structure. See my_statfs() in utilunix.c for the "other side" of
498 static struct mount_entry
*
499 read_filesystem_list(int need_fs_type
, int all_fs
)
501 struct _disk_entry de
;
504 char *tp
, dev
[_POSIX_NAME_MAX
], dir
[_POSIX_PATH_MAX
];
506 static struct mount_entry
*me
= NULL
;
510 if (me
->me_devname
) free(me
->me_devname
);
511 if (me
->me_mountdir
) free(me
->me_mountdir
);
512 if (me
->me_type
) free(me
->me_type
);
515 me
= (struct mount_entry
*)malloc(sizeof(struct mount_entry
));
517 if (!getcwd(dir
, _POSIX_PATH_MAX
)) return (NULL
);
519 if ((fd
= open(dir
, O_RDONLY
)) == -1) return (NULL
);
521 i
= disk_get_entry(fd
, &de
);
525 if (i
== -1) return (NULL
);
527 switch (de
.disk_type
)
529 case _UNMOUNTED
: tp
= "unmounted"; break;
530 case _FLOPPY
: tp
= "Floppy"; break;
531 case _HARD
: tp
= "Hard"; break;
532 case _RAMDISK
: tp
= "Ram"; break;
533 case _REMOVABLE
: tp
= "Removable"; break;
534 case _TAPE
: tp
= "Tape"; break;
535 case _CDROM
: tp
= "CDROM"; break;
536 default: tp
= "unknown";
539 if (fsys_get_mount_dev(dir
, &dev
) == -1) return (NULL
);
541 if (fsys_get_mount_pt(dev
, &dir
) == -1) return (NULL
);
543 me
->me_devname
= strdup(dev
);
544 me
->me_mountdir
= strdup(dir
);
545 me
->me_type
= strdup(tp
);
546 me
->me_dev
= de
.disk_type
;
549 fprintf(stderr
, "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
550 de
.disk_type
, tp
, _DRIVER_NAME_LEN
, _DRIVER_NAME_LEN
, de
.driver_name
, de
.disk_drv
);
551 fprintf(stderr
, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev
);
552 fprintf(stderr
, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir
);
557 #endif /* HAVE_INFOMOUNT_QNX */
560 init_my_statfs (void)
562 #ifdef HAVE_INFOMOUNT_LIST
563 mount_list
= read_filesystem_list (1, 1);
564 #endif /* HAVE_INFOMOUNT_LIST */
568 my_statfs (struct my_statfs
*myfs_stats
, char *path
)
570 #ifdef HAVE_INFOMOUNT_LIST
572 struct mount_entry
*entry
= NULL
;
573 struct mount_entry
*temp
= mount_list
;
574 struct fs_usage fs_use
;
577 i
= strlen (temp
->me_mountdir
);
578 if (i
> len
&& (strncmp (path
, temp
->me_mountdir
, i
) == 0))
579 if (!entry
|| (path
[i
] == PATH_SEP
|| path
[i
] == 0)){
583 temp
= temp
->me_next
;
587 get_fs_usage (entry
->me_mountdir
, &fs_use
);
589 myfs_stats
->type
= entry
->me_dev
;
590 myfs_stats
->typename
= entry
->me_type
;
591 myfs_stats
->mpoint
= entry
->me_mountdir
;
592 myfs_stats
->device
= entry
->me_devname
;
593 myfs_stats
->avail
= getuid () ? fs_use
.fsu_bavail
/2 : fs_use
.fsu_bfree
/2;
594 myfs_stats
->total
= fs_use
.fsu_blocks
/2;
595 myfs_stats
->nfree
= fs_use
.fsu_ffree
;
596 myfs_stats
->nodes
= fs_use
.fsu_files
;
598 #endif /* HAVE_INFOMOUNT_LIST */
600 #ifdef HAVE_INFOMOUNT_QNX
602 ** This is the "other side" of the hack to read_filesystem_list() in
604 ** It's not the most efficient approach, but consumes less memory. It
605 ** also accomodates QNX's ability to mount filesystems on the fly.
607 struct mount_entry
*entry
;
608 struct fs_usage fs_use
;
610 if ((entry
= read_filesystem_list(0, 0)) != NULL
)
612 get_fs_usage(entry
->me_mountdir
, &fs_use
);
614 myfs_stats
->type
= entry
->me_dev
;
615 myfs_stats
->typename
= entry
->me_type
;
616 myfs_stats
->mpoint
= entry
->me_mountdir
;
617 myfs_stats
->device
= entry
->me_devname
;
619 myfs_stats
->avail
= fs_use
.fsu_bfree
/ 2;
620 myfs_stats
->total
= fs_use
.fsu_blocks
/ 2;
621 myfs_stats
->nfree
= fs_use
.fsu_ffree
;
622 myfs_stats
->nodes
= fs_use
.fsu_files
;
625 #endif /* HAVE_INFOMOUNT_QNX */
627 myfs_stats
->type
= 0;
628 myfs_stats
->mpoint
= "unknown";
629 myfs_stats
->device
= "unknown";
630 myfs_stats
->avail
= 0;
631 myfs_stats
->total
= 0;
632 myfs_stats
->nfree
= 0;
633 myfs_stats
->nodes
= 0;