1 /* fstype.c -- determine type of filesystems that files are on
2 Copyright (C) 1990, 91, 92, 93, 94, 2000 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,
20 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
26 #ifdef HAVE_SYS_MNTIO_H
27 #include <sys/mntio.h>
29 #ifdef HAVE_SYS_MKDEV_H
30 #include <sys/mkdev.h>
33 #if defined(MNTIOC_NMNTS) && defined(MNTIOC_GETDEVLIST)
34 #define USE_MNTIOC_GETDEVLIST 1
45 #include "../gnulib/lib/dirname.h"
48 /* Need declaration of function `xstrtoumax' */
49 #include "../gnulib/lib/xstrtol.h"
51 #include "extendbuf.h"
56 # define _(Text) gettext (Text)
61 # define N_(String) gettext_noop (String)
63 /* See locate.c for explanation as to why not use (String) */
64 # define N_(String) String
67 static char *filesystem_type_uncached
PARAMS((const char *path
, const char *relpath
, const struct stat
*statp
));
69 #if defined(FSTYPE_MNTENT) || defined(HAVE_GETMNTENT) || defined(HAVE_SYS_MNTTAB_H) /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
77 # include <sys/mnttab.h>
80 #if HAVE_STRUCT_MNTTAB_MNT_MOUNTP
81 #define mnt_dir mnt_mountp
86 # if defined(MNT_MNTTAB) /* HP-UX. */
87 # define MOUNTED MNT_MNTTAB
89 # if defined(MNTTABNAME) /* Dynix. */
90 # define MOUNTED MNTTABNAME
92 # if defined(MNTTAB) /* Solaris. */
93 # define MOUNTED MNTTAB
97 #if !defined(MOUNTED) /* last resort. */
98 # define MOUNTED "/etc/mtab"
103 #define SETMNTENT(name,mode) setmntent(name,mode)
105 #define SETMNTENT(name,mode) fopen(name,mode)
109 #define ENDMNTENT(fp) (0 != endmntent(fp))
111 #define ENDMNTENT(fp) (0 == fclose(fp))
115 #ifdef FSTYPE_GETMNT /* Ultrix. */
116 #include <sys/param.h>
117 #include <sys/mount.h>
118 #include <sys/fs_types.h>
121 #ifdef FSTYPE_USG_STATFS /* SVR3. */
122 #include <sys/statfs.h>
123 #include <sys/fstyp.h>
126 #ifdef FSTYPE_STATVFS /* SVR4. */
127 #include <sys/statvfs.h>
128 #include <sys/fstyp.h>
131 #ifdef FSTYPE_STATFS /* 4.4BSD. */
132 #include <sys/param.h> /* NetBSD needs this. */
133 #include <sys/mount.h>
136 #include "xstrtol.h" /* for xstrtoumax(). */
139 #ifndef HAVE_F_FSTYPENAME_IN_STATFS
140 #ifndef MFSNAMELEN /* NetBSD defines this. */
145 #ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
146 static char *mn
[] = INITMOUNTNAMES
;
147 if (t
>= 0 && t
<= MOUNT_MAXTYPE
)
151 #else /* !INITMOUNTNAMES */
189 #endif /* !INITMOUNTNAMES */
191 #endif /* !MFSNAMELEN */
192 #endif /* !HAVE_F_FSTYPENAME_IN_STATFS */
193 #endif /* FSTYPE_STATFS */
195 #ifdef FSTYPE_AIX_STATFS /* AIX. */
196 #include <sys/vmount.h>
197 #include <sys/statfs.h>
199 #define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
200 #define f_type f_vfstype
209 #if 0 /* NFS filesystems are actually MNT_AIX. */
222 #endif /* FSTYPE_AIX_STATFS */
225 #include <netinet/in.h>
226 #include <afs/venus.h>
228 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
230 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
233 /* AFS on Solaris 2.3 doesn't get this definition. */
234 #include <sys/ioccom.h>
241 static char space
[2048];
245 vi
.out_size
= sizeof (space
);
248 if (pioctl (path
, VIOC_FILE_CELL_NAME
, &vi
, 1)
249 && (errno
== EINVAL
|| errno
== ENOENT
))
255 /* Nonzero if the current filesystem's type is known. */
256 static int fstype_known
= 0;
258 /* Return a static string naming the type of filesystem that the file PATH,
259 described by STATP, is on.
260 RELPATH is the file name relative to the current directory.
261 Return "unknown" if its filesystem type is unknown. */
264 filesystem_type (const char *path
, const char *relpath
, const struct stat
*statp
)
266 static char *current_fstype
= NULL
;
267 static dev_t current_dev
;
269 if (current_fstype
!= NULL
)
271 if (fstype_known
&& statp
->st_dev
== current_dev
)
272 return current_fstype
; /* Cached value. */
273 free (current_fstype
);
275 current_dev
= statp
->st_dev
;
276 current_fstype
= filesystem_type_uncached (path
, relpath
, statp
);
277 return current_fstype
;
280 /* Return a newly allocated string naming the type of filesystem that the
281 file PATH, described by STATP, is on.
282 RELPATH is the file name relative to the current directory.
283 Return "unknown" if its filesystem type is unknown. */
286 filesystem_type_uncached (const char *path
, const char *relpath
, const struct stat
*statp
)
290 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
291 char *table
= MOUNTED
;
298 mfp
= SETMNTENT (table
, "r");
300 error (1, errno
, "%s", table
);
302 /* Find the entry with the same device number as STATP, and return
303 that entry's fstype. */
304 while (type
== NULL
&& (mnt
= getmntent (mfp
)))
308 struct stat disk_stats
;
310 #ifdef MNTTYPE_IGNORE
311 if (!strcmp (mnt
->mnt_type
, MNTTYPE_IGNORE
))
315 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
316 in the options string. For older systems, we need to stat the
317 directory that the filesystem is mounted on to get it.
319 Unfortunately, the HPUX 9.x mnttab entries created by automountq
320 contain a dev= option but the option value does not match the
321 st_dev value of the file (maybe the lower 16 bits match?). */
323 #if !defined(hpux) && !defined(__hpux__)
324 devopt
= strstr (mnt
->mnt_opts
, "dev=");
329 if (devopt
[0] == '0' && (devopt
[1] == 'x' || devopt
[1] == 'X'))
331 xstrtoumax (devopt
, NULL
, 16, &u
, NULL
);
335 #endif /* not hpux */
337 if (stat (mnt
-> mnt_dir
, &disk_stats
) == -1) {
341 error (1, errno
, _("error in %s: %s"), table
, mnt
-> mnt_dir
);
343 dev
= disk_stats
.st_dev
;
346 if (dev
== statp
->st_dev
)
347 type
= mnt
->mnt_type
;
350 if (ENDMNTENT (mfp
) == 0)
351 error (0, errno
, "%s", table
);
354 #ifdef FSTYPE_GETMNT /* Ultrix. */
359 && getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, 0) > 0)
361 if (fsd
.fd_req
.dev
== statp
->st_dev
)
362 type
= gt_names
[fsd
.fd_req
.fstype
];
366 #ifdef FSTYPE_USG_STATFS /* SVR3. */
368 char typebuf
[FSTYPSZ
];
370 if (statfs (relpath
, &fss
, sizeof (struct statfs
), 0) == -1)
372 /* Don't die if a file was just removed. */
374 error (1, errno
, "%s", path
);
376 else if (!sysfs (GETFSTYP
, fss
.f_fstyp
, typebuf
))
380 #ifdef FSTYPE_STATVFS /* SVR4. */
383 if (statvfs (relpath
, &fss
) == -1)
385 /* Don't die if a file was just removed. */
387 error (1, errno
, "%s", path
);
390 type
= fss
.f_basetype
;
393 #ifdef FSTYPE_STATFS /* 4.4BSD. */
397 if (S_ISLNK (statp
->st_mode
))
398 p
= dir_name (relpath
);
402 if (statfs (p
, &fss
) == -1)
404 /* Don't die if symlink to nonexisting file, or a file that was
407 error (1, errno
, "%s", path
);
411 #ifdef HAVE_F_FSTYPENAME_IN_STATFS
412 type
= xstrdup (fss
.f_fstypename
);
414 type
= fstype_to_string (fss
.f_type
);
422 if ((!type
|| !strcmp (type
, "xx")) && in_afs (relpath
))
426 /* An unknown value can be caused by an ENOENT error condition.
427 Don't cache those values. */
428 fstype_known
= (type
!= NULL
);
430 return xstrdup (type
? type
: _("unknown"));
437 #ifdef HAVE_GETMNTENT
439 #if HAVE_STRUCT_MNTTAB
440 typedef struct mnttab MountPointEntry
;
441 #elif HAVE_STRUCT_MNTENT
442 typedef struct mntent MountPointEntry
;
445 #if GETMNTENT_RETURNS_STRUCT
446 static MountPointEntry
*
447 next_mount_point(FILE *fp
)
449 return getmntent(fp
);
452 #elif GETMNTENT_RETURNS_INT && GETMNTENT_REQUIRES_STRUCT_PTR
453 static MountPointEntry current_mount_point
;
455 static MountPointEntry
*
456 next_mount_point(FILE *fp
)
458 int rv
= getmntent(fp
, ¤t_mount_point
);
463 return ¤t_mount_point
; /* success */
465 case -1: /* EOF - this is normal.*/
469 error(0, 0, _("Line too long in `%s'"), MOUNTED
);
474 _("One of the lines in `%s' has too many fields"),
480 _("One of the lines in `%s' has too few fields"),
486 _("Failed to parse an entry in `%s'"),
492 static MountPointEntry
*
493 next_mount_point(FILE *fp
)
497 error(0, 0, _("Don't know how to use getmntent() to read `%s'. This is a bug."));
505 get_mounted_filesystems (void)
507 char *table
= MOUNTED
;
509 #if HAVE_STRUCT_MNTTAB
511 #elif HAVE_STRUCT_MNTENT
515 size_t alloc_size
= 0u;
518 mfp
= SETMNTENT(table
, "r");
520 error (1, errno
, "%s", table
);
522 while (NULL
!= (mnt
= next_mount_point (mfp
)))
526 #ifdef MNTTYPE_IGNORE
527 if (!strcmp (mnt
->mnt_type
, MNTTYPE_IGNORE
))
531 len
= strlen(mnt
-> mnt_dir
) + 1;
532 result
= extendbuf(result
, used
+len
, &alloc_size
);
533 strcpy(&result
[used
], mnt
->mnt_dir
);
534 used
+= len
; /* len already includes one for the \0 */
536 if (ENDMNTENT(mfp
) == 0)
537 error (0, errno
, "%s", table
);
541 /* Add the extra terminating \0 */
542 result
= extendbuf(result
, used
+1, &alloc_size
);
547 assert(NULL
== result
); /* Postcondition. */
553 get_mounted_filesystems (void)
555 return NULL
; /* No getmntent(). */
559 #ifdef USE_MNTIOC_GETDEVLIST
562 get_mounted_devices (size_t *n
)
564 dev_t
*result
= NULL
;
567 /* Yes, we really are issuing an ioctl() against a vanilla file in order to
568 * find out what's in it.
570 if ( (fd
= open(MOUNTED
, O_RDONLY
)) >= 0)
573 if (0 == ioctl(fd
, MNTIOC_NMNTS
, &nmnts
))
575 uint32_t * devlist
= (uint32_t*) xcalloc(2 * nmnts
, sizeof(uint32_t));
576 result
= xcalloc(nmnts
, sizeof(dev_t
));
578 if (0 == ioctl(fd
, MNTIOC_GETDEVLIST
, devlist
))
580 printf("fd=%d nmnts=%d\n", fd
, nmnts
);
581 for (i
= 0; i
< nmnts
; ++i
)
583 result
[i
] = makedev(devlist
[2*i
], devlist
[2*i
+1]);
591 error (1, errno
, "%s", MOUNTED
);
598 get_mounted_devices (size_t *n
)
600 char *mountpoints
= get_mounted_filesystems();
602 size_t alloc_size
= 0u;
609 const char *mountpoint
= mountpoints
;
613 if (0 == lstat(mountpoint
, &st
))
615 result
= extendbuf(result
, sizeof(dev_t
)*(used
+1), &alloc_size
);
616 result
[used
] = st
.st_dev
;
621 if (errno
== ENOENT
|| errno
== EACCES
)
623 /* ignore, carry on with the next. */
627 error (1, errno
, "%s", mountpoint
);
630 mountpoint
+= strlen(mountpoint
);
631 ++mountpoint
; /* skip the terminating NUL to find next entry. */
635 result
= xrealloc(result
, sizeof(dev_t
)*used
);