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>. */
24 #include "../gnulib/lib/dirname.h"
34 /* Need declaration of function `xstrtoumax' */
35 #include "../gnulib/lib/xstrtol.h"
37 #include "extendbuf.h"
42 # define _(Text) gettext (Text)
47 # define N_(String) gettext_noop (String)
49 /* See locate.c for explanation as to why not use (String) */
50 # define N_(String) String
53 static char *filesystem_type_uncached
PARAMS((const char *path
, const char *relpath
, const struct stat
*statp
));
55 #if defined(FSTYPE_MNTENT) || defined(HAVE_GETMNTENT) || defined(HAVE_SYS_MNTTAB_H) /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
63 # include <sys/mnttab.h>
66 #if HAVE_STRUCT_MNTTAB_MNT_MOUNTP
67 #define mnt_dir mnt_mountp
72 # if defined(MNT_MNTTAB) /* HP-UX. */
73 # define MOUNTED MNT_MNTTAB
75 # if defined(MNTTABNAME) /* Dynix. */
76 # define MOUNTED MNTTABNAME
78 # if defined(MNTTAB) /* Solaris. */
79 # define MOUNTED MNTTAB
83 #if !defined(MOUNTED) /* last resort. */
84 # define MOUNTED "/etc/mtab"
89 #define SETMNTENT(name,mode) setmntent(name,mode)
91 #define SETMNTENT(name,mode) fopen(name,mode)
95 #define ENDMNTENT(fp) (0 != endmntent(fp))
97 #define ENDMNTENT(fp) (0 == fclose(fp))
101 #ifdef FSTYPE_GETMNT /* Ultrix. */
102 #include <sys/param.h>
103 #include <sys/mount.h>
104 #include <sys/fs_types.h>
107 #ifdef FSTYPE_USG_STATFS /* SVR3. */
108 #include <sys/statfs.h>
109 #include <sys/fstyp.h>
112 #ifdef FSTYPE_STATVFS /* SVR4. */
113 #include <sys/statvfs.h>
114 #include <sys/fstyp.h>
117 #ifdef FSTYPE_STATFS /* 4.4BSD. */
118 #include <sys/param.h> /* NetBSD needs this. */
119 #include <sys/mount.h>
122 #include "xstrtol.h" /* for xstrtoumax(). */
125 #ifndef HAVE_F_FSTYPENAME_IN_STATFS
126 #ifndef MFSNAMELEN /* NetBSD defines this. */
131 #ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
132 static char *mn
[] = INITMOUNTNAMES
;
133 if (t
>= 0 && t
<= MOUNT_MAXTYPE
)
137 #else /* !INITMOUNTNAMES */
175 #endif /* !INITMOUNTNAMES */
177 #endif /* !MFSNAMELEN */
178 #endif /* !HAVE_F_FSTYPENAME_IN_STATFS */
179 #endif /* FSTYPE_STATFS */
181 #ifdef FSTYPE_AIX_STATFS /* AIX. */
182 #include <sys/vmount.h>
183 #include <sys/statfs.h>
185 #define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
186 #define f_type f_vfstype
195 #if 0 /* NFS filesystems are actually MNT_AIX. */
208 #endif /* FSTYPE_AIX_STATFS */
211 #include <netinet/in.h>
212 #include <afs/venus.h>
214 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
216 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
219 /* AFS on Solaris 2.3 doesn't get this definition. */
220 #include <sys/ioccom.h>
227 static char space
[2048];
231 vi
.out_size
= sizeof (space
);
234 if (pioctl (path
, VIOC_FILE_CELL_NAME
, &vi
, 1)
235 && (errno
== EINVAL
|| errno
== ENOENT
))
241 /* Nonzero if the current filesystem's type is known. */
242 static int fstype_known
= 0;
244 /* Return a static string naming the type of filesystem that the file PATH,
245 described by STATP, is on.
246 RELPATH is the file name relative to the current directory.
247 Return "unknown" if its filesystem type is unknown. */
250 filesystem_type (const char *path
, const char *relpath
, const struct stat
*statp
)
252 static char *current_fstype
= NULL
;
253 static dev_t current_dev
;
255 if (current_fstype
!= NULL
)
257 if (fstype_known
&& statp
->st_dev
== current_dev
)
258 return current_fstype
; /* Cached value. */
259 free (current_fstype
);
261 current_dev
= statp
->st_dev
;
262 current_fstype
= filesystem_type_uncached (path
, relpath
, statp
);
263 return current_fstype
;
266 /* Return a newly allocated string naming the type of filesystem that the
267 file PATH, described by STATP, is on.
268 RELPATH is the file name relative to the current directory.
269 Return "unknown" if its filesystem type is unknown. */
272 filesystem_type_uncached (const char *path
, const char *relpath
, const struct stat
*statp
)
276 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
277 char *table
= MOUNTED
;
284 mfp
= SETMNTENT (table
, "r");
286 error (1, errno
, "%s", table
);
288 /* Find the entry with the same device number as STATP, and return
289 that entry's fstype. */
290 while (type
== NULL
&& (mnt
= getmntent (mfp
)))
294 struct stat disk_stats
;
296 #ifdef MNTTYPE_IGNORE
297 if (!strcmp (mnt
->mnt_type
, MNTTYPE_IGNORE
))
301 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
302 in the options string. For older systems, we need to stat the
303 directory that the filesystem is mounted on to get it.
305 Unfortunately, the HPUX 9.x mnttab entries created by automountq
306 contain a dev= option but the option value does not match the
307 st_dev value of the file (maybe the lower 16 bits match?). */
309 #if !defined(hpux) && !defined(__hpux__)
310 devopt
= strstr (mnt
->mnt_opts
, "dev=");
315 if (devopt
[0] == '0' && (devopt
[1] == 'x' || devopt
[1] == 'X'))
317 xstrtoumax (devopt
, NULL
, 16, &u
, NULL
);
321 #endif /* not hpux */
323 if (stat (mnt
-> mnt_dir
, &disk_stats
) == -1) {
327 error (1, errno
, _("error in %s: %s"), table
, mnt
-> mnt_dir
);
329 dev
= disk_stats
.st_dev
;
332 if (dev
== statp
->st_dev
)
333 type
= mnt
->mnt_type
;
336 if (ENDMNTENT (mfp
) == 0)
337 error (0, errno
, "%s", table
);
340 #ifdef FSTYPE_GETMNT /* Ultrix. */
345 && getmnt (&offset
, &fsd
, sizeof (fsd
), NOSTAT_MANY
, 0) > 0)
347 if (fsd
.fd_req
.dev
== statp
->st_dev
)
348 type
= gt_names
[fsd
.fd_req
.fstype
];
352 #ifdef FSTYPE_USG_STATFS /* SVR3. */
354 char typebuf
[FSTYPSZ
];
356 if (statfs (relpath
, &fss
, sizeof (struct statfs
), 0) == -1)
358 /* Don't die if a file was just removed. */
360 error (1, errno
, "%s", path
);
362 else if (!sysfs (GETFSTYP
, fss
.f_fstyp
, typebuf
))
366 #ifdef FSTYPE_STATVFS /* SVR4. */
369 if (statvfs (relpath
, &fss
) == -1)
371 /* Don't die if a file was just removed. */
373 error (1, errno
, "%s", path
);
376 type
= fss
.f_basetype
;
379 #ifdef FSTYPE_STATFS /* 4.4BSD. */
383 if (S_ISLNK (statp
->st_mode
))
384 p
= dir_name (relpath
);
388 if (statfs (p
, &fss
) == -1)
390 /* Don't die if symlink to nonexisting file, or a file that was
393 error (1, errno
, "%s", path
);
397 #ifdef HAVE_F_FSTYPENAME_IN_STATFS
398 type
= xstrdup (fss
.f_fstypename
);
400 type
= fstype_to_string (fss
.f_type
);
408 if ((!type
|| !strcmp (type
, "xx")) && in_afs (relpath
))
412 /* An unknown value can be caused by an ENOENT error condition.
413 Don't cache those values. */
414 fstype_known
= (type
!= NULL
);
416 return xstrdup (type
? type
: _("unknown"));
423 #ifdef HAVE_GETMNTENT
425 #if HAVE_STRUCT_MNTTAB
426 typedef struct mnttab MountPointEntry
;
427 #elif HAVE_STRUCT_MNTENT
428 typedef struct mntent MountPointEntry
;
431 #if GETMNTENT_RETURNS_STRUCT
432 static MountPointEntry
*
433 next_mount_point(FILE *fp
)
435 return getmntent(fp
);
438 #elif GETMNTENT_RETURNS_INT && GETMNTENT_REQUIRES_STRUCT_PTR
439 static MountPointEntry current_mount_point
;
441 static MountPointEntry
*
442 next_mount_point(FILE *fp
)
444 int rv
= getmntent(fp
, ¤t_mount_point
);
449 return ¤t_mount_point
; /* success */
451 case -1: /* EOF - this is normal.*/
455 error(0, 0, _("Line too long in `%s'"), MOUNTED
);
460 _("One of the lines in `%s' has too many fields"),
466 _("One of the lines in `%s' has too few fields"),
472 _("Failed to parse an entry in `%s'"),
478 static MountPointEntry
*
479 next_mount_point(FILE *fp
)
483 error(0, 0, _("Don't know how to use getmntent() to read `%s'. This is a bug."));
491 get_mounted_filesystems (void)
493 char *table
= MOUNTED
;
495 #if HAVE_STRUCT_MNTTAB
497 #elif HAVE_STRUCT_MNTENT
501 size_t alloc_size
= 0u;
504 mfp
= SETMNTENT(table
, "r");
506 error (1, errno
, "%s", table
);
508 while (NULL
!= (mnt
= next_mount_point (mfp
)))
512 #ifdef MNTTYPE_IGNORE
513 if (!strcmp (mnt
->mnt_type
, MNTTYPE_IGNORE
))
517 len
= strlen(mnt
-> mnt_dir
) + 1;
518 result
= extendbuf(result
, used
+len
, &alloc_size
);
519 strcpy(&result
[used
], mnt
->mnt_dir
);
520 used
+= len
; /* len already includes one for the \0 */
522 if (ENDMNTENT(mfp
) == 0)
523 error (0, errno
, "%s", table
);
527 /* Add the extra terminating \0 */
528 result
= extendbuf(result
, used
+1, &alloc_size
);
533 assert(NULL
== result
); /* Postcondition. */
539 get_mounted_filesystems (void)
541 return NULL
; /* No getmntent(). */