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_TYPES_H
27 #include <sys/types.h>
34 #ifdef HAVE_SYS_MNTIO_H
38 #include <sys/mntio.h>
40 #ifdef HAVE_SYS_MKDEV_H
41 #include <sys/mkdev.h>
44 #if defined(MNTIOC_NMNTS) && defined(MNTIOC_GETDEVLIST)
45 #define USE_MNTIOC_GETDEVLIST 1
47 #undef USE_MNTIOC_GETDEVLIST
58 #include "../gnulib/lib/dirname.h"
62 /* Need declaration of function `xstrtoumax' */
63 #include "../gnulib/lib/xstrtol.h"
65 #include "extendbuf.h"
70 # define _(Text) gettext (Text)
75 # define N_(String) gettext_noop (String)
77 /* See locate.c for explanation as to why not use (String) */
78 # define N_(String) String
81 static char *filesystem_type_uncached
PARAMS((const char *path
, const char *relpath
, const struct stat
*statp
));
83 #if defined(FSTYPE_MNTENT) || defined(HAVE_GETMNTENT) || defined(HAVE_SYS_MNTTAB_H) /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
91 # include <sys/mnttab.h>
94 #if HAVE_STRUCT_MNTTAB_MNT_MOUNTP
95 #define mnt_dir mnt_mountp
100 # if defined(MNT_MNTTAB) /* HP-UX. */
101 # define MOUNTED MNT_MNTTAB
103 # if defined(MNTTABNAME) /* Dynix. */
104 # define MOUNTED MNTTABNAME
106 # if defined(MNTTAB) /* Solaris. */
107 # define MOUNTED MNTTAB
111 #if !defined(MOUNTED) /* last resort. */
112 # define MOUNTED "/etc/mtab"
117 #define SETMNTENT(name,mode) setmntent(name,mode)
119 #define SETMNTENT(name,mode) fopen(name,mode)
123 #define ENDMNTENT(fp) (0 != endmntent(fp))
125 #define ENDMNTENT(fp) (0 == fclose(fp))
129 #ifdef FSTYPE_GETMNT /* Ultrix. */
130 #include <sys/param.h>
131 #include <sys/mount.h>
132 #include <sys/fs_types.h>
135 #ifdef FSTYPE_USG_STATFS /* SVR3. */
136 #include <sys/statfs.h>
137 #include <sys/fstyp.h>
140 #ifdef FSTYPE_STATVFS /* SVR4. */
141 #include <sys/statvfs.h>
142 #include <sys/fstyp.h>
145 #ifdef FSTYPE_STATFS /* 4.4BSD. */
146 #include <sys/param.h> /* NetBSD needs this. */
147 #include <sys/mount.h>
150 #include "xstrtol.h" /* for xstrtoumax(). */
153 #ifndef HAVE_F_FSTYPENAME_IN_STATFS
154 #ifndef MFSNAMELEN /* NetBSD defines this. */
159 #ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
160 static char *mn
[] = INITMOUNTNAMES
;
161 if (t
>= 0 && t
<= MOUNT_MAXTYPE
)
165 #else /* !INITMOUNTNAMES */
203 #endif /* !INITMOUNTNAMES */
205 #endif /* !MFSNAMELEN */
206 #endif /* !HAVE_F_FSTYPENAME_IN_STATFS */
207 #endif /* FSTYPE_STATFS */
209 #ifdef FSTYPE_AIX_STATFS /* AIX. */
210 #include <sys/vmount.h>
211 #include <sys/statfs.h>
213 #define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
214 #define f_type f_vfstype
223 #if 0 /* NFS filesystems are actually MNT_AIX. */
236 #endif /* FSTYPE_AIX_STATFS */
239 #include <netinet/in.h>
240 #include <afs/venus.h>
242 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
244 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
247 /* AFS on Solaris 2.3 doesn't get this definition. */
248 #include <sys/ioccom.h>
255 static char space
[2048];
259 vi
.out_size
= sizeof (space
);
262 if (pioctl (path
, VIOC_FILE_CELL_NAME
, &vi
, 1)
263 && (errno
== EINVAL
|| errno
== ENOENT
))
269 /* Nonzero if the current filesystem's type is known. */
270 static int fstype_known
= 0;
272 /* Return a static string naming the type of filesystem that the file PATH,
273 described by STATP, is on.
274 RELPATH is the file name relative to the current directory.
275 Return "unknown" if its filesystem type is unknown. */
278 filesystem_type (const char *path
, const char *relpath
, const struct stat
*statp
)
280 static char *current_fstype
= NULL
;
281 static dev_t current_dev
;
283 if (current_fstype
!= NULL
)
285 if (fstype_known
&& statp
->st_dev
== current_dev
)
286 return current_fstype
; /* Cached value. */
287 free (current_fstype
);
289 current_dev
= statp
->st_dev
;
290 current_fstype
= filesystem_type_uncached (path
, relpath
, statp
);
291 return current_fstype
;
294 /* Return a newly allocated string naming the type of filesystem that the
295 file PATH, described by STATP, is on.
296 RELPATH is the file name relative to the current directory.
297 Return "unknown" if its filesystem type is unknown. */
300 filesystem_type_uncached (const char *path
, const char *relpath
, const struct stat
*statp
)
304 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
305 char *table
= MOUNTED
;
312 mfp
= SETMNTENT (table
, "r");
314 error (1, errno
, "%s", table
);
316 /* Find the entry with the same device number as STATP, and return
317 that entry's fstype. */
318 while (type
== NULL
&& (mnt
= getmntent (mfp
)))
322 struct stat disk_stats
;
324 #ifdef MNTTYPE_IGNORE
325 if (!strcmp (mnt
->mnt_type
, MNTTYPE_IGNORE
))
329 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
330 in the options string. For older systems, we need to stat the
331 directory that the filesystem is mounted on to get it.
333 Unfortunately, the HPUX 9.x mnttab entries created by automountq
334 contain a dev= option but the option value does not match the
335 st_dev value of the file (maybe the lower 16 bits match?). */
337 #if !defined(hpux) && !defined(__hpux__)
338 devopt
= strstr (mnt
->mnt_opts
, "dev=");
343 if (devopt
[0] == '0' && (devopt
[1] == 'x' || devopt
[1] == 'X'))
345 xstrtoumax (devopt
, NULL
, 16, &u
, NULL
);
349 #endif /* not hpux */
351 if (stat (mnt
-> mnt_dir
, &disk_stats
) == -1) {
355 error (1, errno
, _("error in %s: %s"), table
, mnt
-> mnt_dir
);
357 dev
= disk_stats
.st_dev
;
360 if (dev
== statp
->st_dev
)
361 type
= mnt
->mnt_type
;
364 if (ENDMNTENT (mfp
) == 0)
365 error (0, errno
, "%s", table
);
368 #ifdef FSTYPE_GETMNT /* Ultrix. */
373 && getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, 0) > 0)
375 if (fsd
.fd_req
.dev
== statp
->st_dev
)
376 type
= gt_names
[fsd
.fd_req
.fstype
];
380 #ifdef FSTYPE_USG_STATFS /* SVR3. */
382 char typebuf
[FSTYPSZ
];
384 if (statfs (relpath
, &fss
, sizeof (struct statfs
), 0) == -1)
386 /* Don't die if a file was just removed. */
388 error (1, errno
, "%s", path
);
390 else if (!sysfs (GETFSTYP
, fss
.f_fstyp
, typebuf
))
394 #ifdef FSTYPE_STATVFS /* SVR4. */
397 if (statvfs (relpath
, &fss
) == -1)
399 /* Don't die if a file was just removed. */
401 error (1, errno
, "%s", path
);
404 type
= fss
.f_basetype
;
407 #ifdef FSTYPE_STATFS /* 4.4BSD. */
411 if (S_ISLNK (statp
->st_mode
))
412 p
= dir_name (relpath
);
416 if (statfs (p
, &fss
) == -1)
418 /* Don't die if symlink to nonexisting file, or a file that was
421 error (1, errno
, "%s", path
);
425 #ifdef HAVE_F_FSTYPENAME_IN_STATFS
426 type
= xstrdup (fss
.f_fstypename
);
428 type
= fstype_to_string (fss
.f_type
);
436 if ((!type
|| !strcmp (type
, "xx")) && in_afs (relpath
))
440 /* An unknown value can be caused by an ENOENT error condition.
441 Don't cache those values. */
442 fstype_known
= (type
!= NULL
);
444 return xstrdup (type
? type
: _("unknown"));
451 #ifdef HAVE_GETMNTENT
453 #if HAVE_STRUCT_MNTTAB
454 typedef struct mnttab MountPointEntry
;
455 #elif HAVE_STRUCT_MNTENT
456 typedef struct mntent MountPointEntry
;
459 #if GETMNTENT_RETURNS_STRUCT
460 static MountPointEntry
*
461 next_mount_point(FILE *fp
)
463 return getmntent(fp
);
466 #elif GETMNTENT_RETURNS_INT && GETMNTENT_REQUIRES_STRUCT_PTR
467 static MountPointEntry current_mount_point
;
469 static MountPointEntry
*
470 next_mount_point(FILE *fp
)
472 int rv
= getmntent(fp
, ¤t_mount_point
);
477 return ¤t_mount_point
; /* success */
479 case -1: /* EOF - this is normal.*/
483 error(0, 0, _("Line too long in `%s'"), MOUNTED
);
488 _("One of the lines in `%s' has too many fields"),
494 _("One of the lines in `%s' has too few fields"),
500 _("Failed to parse an entry in `%s'"),
506 static MountPointEntry
*
507 next_mount_point(FILE *fp
)
511 error(0, 0, _("Don't know how to use getmntent() to read `%s'. This is a bug."));
519 get_mounted_filesystems (void)
521 char *table
= MOUNTED
;
523 #if HAVE_STRUCT_MNTTAB
525 #elif HAVE_STRUCT_MNTENT
529 size_t alloc_size
= 0u;
532 mfp
= SETMNTENT(table
, "r");
534 error (1, errno
, "%s", table
);
536 while (NULL
!= (mnt
= next_mount_point (mfp
)))
540 #ifdef MNTTYPE_IGNORE
541 if (!strcmp (mnt
->mnt_type
, MNTTYPE_IGNORE
))
545 len
= strlen(mnt
-> mnt_dir
) + 1;
546 result
= extendbuf(result
, used
+len
, &alloc_size
);
547 strcpy(&result
[used
], mnt
->mnt_dir
);
548 used
+= len
; /* len already includes one for the \0 */
550 if (ENDMNTENT(mfp
) == 0)
551 error (0, errno
, "%s", table
);
555 /* Add the extra terminating \0 */
556 result
= extendbuf(result
, used
+1, &alloc_size
);
561 assert(NULL
== result
); /* Postcondition. */
567 get_mounted_filesystems (void)
569 return NULL
; /* No getmntent(). */
573 #ifdef USE_MNTIOC_GETDEVLIST
576 get_mounted_devices (size_t *n
)
578 dev_t
*result
= NULL
;
581 /* Yes, we really are issuing an ioctl() against a vanilla file in order to
582 * find out what's in it.
584 if ( (fd
= open(MOUNTED
, O_RDONLY
)) >= 0)
587 if (0 == ioctl(fd
, MNTIOC_NMNTS
, &nmnts
))
589 uint32_t * devlist
= (uint32_t*) xcalloc(2 * nmnts
, sizeof(uint32_t));
590 result
= xcalloc(nmnts
, sizeof(dev_t
));
592 if (0 == ioctl(fd
, MNTIOC_GETDEVLIST
, devlist
))
594 for (i
= 0; i
< nmnts
; ++i
)
596 result
[i
] = makedev(devlist
[2*i
], devlist
[2*i
+1]);
605 error (1, errno
, "%s", MOUNTED
);
612 get_mounted_devices (size_t *n
)
614 char *mountpoints
= get_mounted_filesystems();
616 size_t alloc_size
= 0u;
623 const char *mountpoint
= mountpoints
;
627 if (0 == lstat(mountpoint
, &st
))
629 result
= extendbuf(result
, sizeof(dev_t
)*(used
+1), &alloc_size
);
630 result
[used
] = st
.st_dev
;
635 if (errno
== ENOENT
|| errno
== EACCES
)
637 /* ignore, carry on with the next. */
641 error (1, errno
, "%s", mountpoint
);
644 mountpoint
+= strlen(mountpoint
);
645 ++mountpoint
; /* skip the terminating NUL to find next entry. */
649 result
= xrealloc(result
, sizeof(dev_t
)*used
);