Enable the 'Warning: filesystem XXX has recently been mounted' check on Solaris,...
[findutils.git] / find / fstype.c
blobdb1cc60c417c5eec9953bac14608f3d04b7230df
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)
7 any later version.
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,
17 USA.
20 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
22 #include "defs.h"
24 #include "../gnulib/lib/dirname.h"
25 #include "modetype.h"
26 #include <errno.h>
27 #ifdef STDC_HEADERS
28 #include <stdlib.h>
29 #else
30 extern int errno;
31 #endif
32 #include <assert.h>
34 /* Need declaration of function `xstrtoumax' */
35 #include "../gnulib/lib/xstrtol.h"
37 #include "extendbuf.h"
40 #if ENABLE_NLS
41 # include <libintl.h>
42 # define _(Text) gettext (Text)
43 #else
44 # define _(Text) Text
45 #endif
46 #ifdef gettext_noop
47 # define N_(String) gettext_noop (String)
48 #else
49 /* See locate.c for explanation as to why not use (String) */
50 # define N_(String) String
51 #endif
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. */
57 #if HAVE_MNTENT_H
58 # include <mntent.h>
59 #endif
61 #if HAVE_SYS_MNTTAB_H
62 # include <stdio.h>
63 # include <sys/mnttab.h>
64 #endif
66 #if HAVE_STRUCT_MNTTAB_MNT_MOUNTP
67 #define mnt_dir mnt_mountp
68 #endif
71 #if !defined(MOUNTED)
72 # if defined(MNT_MNTTAB) /* HP-UX. */
73 # define MOUNTED MNT_MNTTAB
74 # endif
75 # if defined(MNTTABNAME) /* Dynix. */
76 # define MOUNTED MNTTABNAME
77 # endif
78 # if defined(MNTTAB) /* Solaris. */
79 # define MOUNTED MNTTAB
80 # endif
81 #endif
83 #if !defined(MOUNTED) /* last resort. */
84 # define MOUNTED "/etc/mtab"
85 #endif
88 #if HAVE_SETMNTENT
89 #define SETMNTENT(name,mode) setmntent(name,mode)
90 #else
91 #define SETMNTENT(name,mode) fopen(name,mode)
92 #endif
94 #if HAVE_ENDMNTENT
95 #define ENDMNTENT(fp) (0 != endmntent(fp))
96 #else
97 #define ENDMNTENT(fp) (0 == fclose(fp))
98 #endif
99 #endif
101 #ifdef FSTYPE_GETMNT /* Ultrix. */
102 #include <sys/param.h>
103 #include <sys/mount.h>
104 #include <sys/fs_types.h>
105 #endif
107 #ifdef FSTYPE_USG_STATFS /* SVR3. */
108 #include <sys/statfs.h>
109 #include <sys/fstyp.h>
110 #endif
112 #ifdef FSTYPE_STATVFS /* SVR4. */
113 #include <sys/statvfs.h>
114 #include <sys/fstyp.h>
115 #endif
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. */
127 static char *
128 fstype_to_string (t)
129 short t;
131 #ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
132 static char *mn[] = INITMOUNTNAMES;
133 if (t >= 0 && t <= MOUNT_MAXTYPE)
134 return mn[t];
135 else
136 return "?";
137 #else /* !INITMOUNTNAMES */
138 switch (t)
140 case MOUNT_UFS:
141 return "ufs";
142 case MOUNT_NFS:
143 return "nfs";
144 #ifdef MOUNT_PC
145 case MOUNT_PC:
146 return "pc";
147 #endif
148 #ifdef MOUNT_MFS
149 case MOUNT_MFS:
150 return "mfs";
151 #endif
152 #ifdef MOUNT_LO
153 case MOUNT_LO:
154 return "lofs";
155 #endif
156 #ifdef MOUNT_TFS
157 case MOUNT_TFS:
158 return "tfs";
159 #endif
160 #ifdef MOUNT_TMP
161 case MOUNT_TMP:
162 return "tmp";
163 #endif
164 #ifdef MOUNT_MSDOS
165 case MOUNT_MSDOS:
166 return "msdos";
167 #endif
168 #ifdef MOUNT_ISO9660
169 case MOUNT_ISO9660:
170 return "iso9660fs";
171 #endif
172 default:
173 return "?";
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
188 static char *
189 fstype_to_string (t)
190 short t;
192 switch (t)
194 case MNT_AIX:
195 #if 0 /* NFS filesystems are actually MNT_AIX. */
196 return "aix";
197 #endif
198 case MNT_NFS:
199 return "nfs";
200 case MNT_JFS:
201 return "jfs";
202 case MNT_CDROM:
203 return "cdrom";
204 default:
205 return "?";
208 #endif /* FSTYPE_AIX_STATFS */
210 #ifdef AFS
211 #include <netinet/in.h>
212 #include <afs/venus.h>
213 #if __STDC__
214 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
215 #undef _VICEIOCTL
216 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
217 #endif
218 #ifndef _IOW
219 /* AFS on Solaris 2.3 doesn't get this definition. */
220 #include <sys/ioccom.h>
221 #endif
223 static int
224 in_afs (path)
225 char *path;
227 static char space[2048];
228 struct ViceIoctl vi;
230 vi.in_size = 0;
231 vi.out_size = sizeof (space);
232 vi.out = space;
234 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
235 && (errno == EINVAL || errno == ENOENT))
236 return 0;
237 return 1;
239 #endif /* AFS */
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. */
249 char *
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. */
271 static char *
272 filesystem_type_uncached (const char *path, const char *relpath, const struct stat *statp)
274 char *type = NULL;
276 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
277 char *table = MOUNTED;
278 FILE *mfp;
279 struct mntent *mnt;
281 (void) &path;
282 (void) &relpath;
284 mfp = SETMNTENT (table, "r");
285 if (mfp == NULL)
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)))
292 char *devopt;
293 dev_t dev;
294 struct stat disk_stats;
296 #ifdef MNTTYPE_IGNORE
297 if (!strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
298 continue;
299 #endif
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=");
311 if (devopt)
313 uintmax_t u = 0;
314 devopt += 4;
315 if (devopt[0] == '0' && (devopt[1] == 'x' || devopt[1] == 'X'))
316 devopt += 2;
317 xstrtoumax (devopt, NULL, 16, &u, NULL);
318 dev = u;
320 else
321 #endif /* not hpux */
323 if (stat (mnt-> mnt_dir, &disk_stats) == -1) {
324 if (errno == EACCES)
325 continue;
326 else
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);
338 #endif
340 #ifdef FSTYPE_GETMNT /* Ultrix. */
341 int offset = 0;
342 struct fs_data fsd;
344 while (type == NULL
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];
350 #endif
352 #ifdef FSTYPE_USG_STATFS /* SVR3. */
353 struct statfs fss;
354 char typebuf[FSTYPSZ];
356 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
358 /* Don't die if a file was just removed. */
359 if (errno != ENOENT)
360 error (1, errno, "%s", path);
362 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
363 type = typebuf;
364 #endif
366 #ifdef FSTYPE_STATVFS /* SVR4. */
367 struct statvfs fss;
369 if (statvfs (relpath, &fss) == -1)
371 /* Don't die if a file was just removed. */
372 if (errno != ENOENT)
373 error (1, errno, "%s", path);
375 else
376 type = fss.f_basetype;
377 #endif
379 #ifdef FSTYPE_STATFS /* 4.4BSD. */
380 struct statfs fss;
381 char *p;
383 if (S_ISLNK (statp->st_mode))
384 p = dir_name (relpath);
385 else
386 p = relpath;
388 if (statfs (p, &fss) == -1)
390 /* Don't die if symlink to nonexisting file, or a file that was
391 just removed. */
392 if (errno != ENOENT)
393 error (1, errno, "%s", path);
395 else
397 #ifdef HAVE_F_FSTYPENAME_IN_STATFS
398 type = xstrdup (fss.f_fstypename);
399 #else
400 type = fstype_to_string (fss.f_type);
401 #endif
403 if (p != relpath)
404 free (p);
405 #endif
407 #ifdef AFS
408 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
409 type = "afs";
410 #endif
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;
429 #endif
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, &current_mount_point);
446 switch (rv)
448 case 0:
449 return &current_mount_point; /* success */
451 case -1: /* EOF - this is normal.*/
452 return NULL;
454 case MNT_TOOLONG:
455 error(0, 0, _("Line too long in `%s'"), MOUNTED);
456 return NULL;
458 case MNT_TOOMANY:
459 error(0, 0,
460 _("One of the lines in `%s' has too many fields"),
461 MOUNTED);
462 return NULL;
464 case MNT_TOOFEW:
465 error(0, 0,
466 _("One of the lines in `%s' has too few fields"),
467 MOUNTED);
468 return NULL;
470 default:
471 error(0, 0,
472 _("Failed to parse an entry in `%s'"),
473 MOUNTED);
474 return NULL;
477 #else
478 static MountPointEntry*
479 next_mount_point(FILE *fp)
481 if (warnings)
483 error(0, 0, _("Don't know how to use getmntent() to read `%s'. This is a bug."));
485 return NULL;
488 #endif
490 char *
491 get_mounted_filesystems (void)
493 char *table = MOUNTED;
494 FILE *mfp;
495 #if HAVE_STRUCT_MNTTAB
496 struct mnttab *mnt;
497 #elif HAVE_STRUCT_MNTENT
498 struct mntent *mnt;
499 #endif
500 char *result = NULL;
501 size_t alloc_size = 0u;
502 size_t used = 0u;
504 mfp = SETMNTENT(table, "r");
505 if (mfp == NULL)
506 error (1, errno, "%s", table);
508 while (NULL != (mnt = next_mount_point (mfp)))
510 size_t len;
512 #ifdef MNTTYPE_IGNORE
513 if (!strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
514 continue;
515 #endif
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);
525 if (used)
527 /* Add the extra terminating \0 */
528 result = extendbuf(result, used+1, &alloc_size);
529 result[used] = 0;
531 else
533 assert(NULL == result); /* Postcondition. */
535 return result;
537 #else
538 char *
539 get_mounted_filesystems (void)
541 return NULL; /* No getmntent(). */
543 #endif