get_mounted_filesystems() should use getmntent() if that function is
[findutils.git] / find / fstype.c
blobd7a6be77b83f4a2c4da7c013b653acd812dd6a28
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 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
56 #include <mntent.h>
57 #if !defined(MOUNTED)
58 # if defined(MNT_MNTTAB) /* HP-UX. */
59 # define MOUNTED MNT_MNTTAB
60 # endif
61 # if defined(MNTTABNAME) /* Dynix. */
62 # define MOUNTED MNTTABNAME
63 # endif
64 #endif
65 #endif
67 #ifdef FSTYPE_GETMNT /* Ultrix. */
68 #include <sys/param.h>
69 #include <sys/mount.h>
70 #include <sys/fs_types.h>
71 #endif
73 #ifdef FSTYPE_USG_STATFS /* SVR3. */
74 #include <sys/statfs.h>
75 #include <sys/fstyp.h>
76 #endif
78 #ifdef FSTYPE_STATVFS /* SVR4. */
79 #include <sys/statvfs.h>
80 #include <sys/fstyp.h>
81 #endif
83 #ifdef FSTYPE_STATFS /* 4.4BSD. */
84 #include <sys/param.h> /* NetBSD needs this. */
85 #include <sys/mount.h>
88 #include "xstrtol.h" /* for xstrtoumax(). */
91 #ifndef HAVE_F_FSTYPENAME_IN_STATFS
92 #ifndef MFSNAMELEN /* NetBSD defines this. */
93 static char *
94 fstype_to_string (t)
95 short t;
97 #ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
98 static char *mn[] = INITMOUNTNAMES;
99 if (t >= 0 && t <= MOUNT_MAXTYPE)
100 return mn[t];
101 else
102 return "?";
103 #else /* !INITMOUNTNAMES */
104 switch (t)
106 case MOUNT_UFS:
107 return "ufs";
108 case MOUNT_NFS:
109 return "nfs";
110 #ifdef MOUNT_PC
111 case MOUNT_PC:
112 return "pc";
113 #endif
114 #ifdef MOUNT_MFS
115 case MOUNT_MFS:
116 return "mfs";
117 #endif
118 #ifdef MOUNT_LO
119 case MOUNT_LO:
120 return "lofs";
121 #endif
122 #ifdef MOUNT_TFS
123 case MOUNT_TFS:
124 return "tfs";
125 #endif
126 #ifdef MOUNT_TMP
127 case MOUNT_TMP:
128 return "tmp";
129 #endif
130 #ifdef MOUNT_MSDOS
131 case MOUNT_MSDOS:
132 return "msdos";
133 #endif
134 #ifdef MOUNT_ISO9660
135 case MOUNT_ISO9660:
136 return "iso9660fs";
137 #endif
138 default:
139 return "?";
141 #endif /* !INITMOUNTNAMES */
143 #endif /* !MFSNAMELEN */
144 #endif /* !HAVE_F_FSTYPENAME_IN_STATFS */
145 #endif /* FSTYPE_STATFS */
147 #ifdef FSTYPE_AIX_STATFS /* AIX. */
148 #include <sys/vmount.h>
149 #include <sys/statfs.h>
151 #define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
152 #define f_type f_vfstype
154 static char *
155 fstype_to_string (t)
156 short t;
158 switch (t)
160 case MNT_AIX:
161 #if 0 /* NFS filesystems are actually MNT_AIX. */
162 return "aix";
163 #endif
164 case MNT_NFS:
165 return "nfs";
166 case MNT_JFS:
167 return "jfs";
168 case MNT_CDROM:
169 return "cdrom";
170 default:
171 return "?";
174 #endif /* FSTYPE_AIX_STATFS */
176 #ifdef AFS
177 #include <netinet/in.h>
178 #include <afs/venus.h>
179 #if __STDC__
180 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
181 #undef _VICEIOCTL
182 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
183 #endif
184 #ifndef _IOW
185 /* AFS on Solaris 2.3 doesn't get this definition. */
186 #include <sys/ioccom.h>
187 #endif
189 static int
190 in_afs (path)
191 char *path;
193 static char space[2048];
194 struct ViceIoctl vi;
196 vi.in_size = 0;
197 vi.out_size = sizeof (space);
198 vi.out = space;
200 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
201 && (errno == EINVAL || errno == ENOENT))
202 return 0;
203 return 1;
205 #endif /* AFS */
207 /* Nonzero if the current filesystem's type is known. */
208 static int fstype_known = 0;
210 /* Return a static string naming the type of filesystem that the file PATH,
211 described by STATP, is on.
212 RELPATH is the file name relative to the current directory.
213 Return "unknown" if its filesystem type is unknown. */
215 char *
216 filesystem_type (const char *path, const char *relpath, const struct stat *statp)
218 static char *current_fstype = NULL;
219 static dev_t current_dev;
221 if (current_fstype != NULL)
223 if (fstype_known && statp->st_dev == current_dev)
224 return current_fstype; /* Cached value. */
225 free (current_fstype);
227 current_dev = statp->st_dev;
228 current_fstype = filesystem_type_uncached (path, relpath, statp);
229 return current_fstype;
232 /* Return a newly allocated string naming the type of filesystem that the
233 file PATH, described by STATP, is on.
234 RELPATH is the file name relative to the current directory.
235 Return "unknown" if its filesystem type is unknown. */
237 static char *
238 filesystem_type_uncached (const char *path, const char *relpath, const struct stat *statp)
240 char *type = NULL;
242 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
243 char *table = MOUNTED;
244 FILE *mfp;
245 struct mntent *mnt;
247 (void) &path;
248 (void) &relpath;
250 mfp = setmntent (table, "r");
251 if (mfp == NULL)
252 error (1, errno, "%s", table);
254 /* Find the entry with the same device number as STATP, and return
255 that entry's fstype. */
256 while (type == NULL && (mnt = getmntent (mfp)))
258 char *devopt;
259 dev_t dev;
260 struct stat disk_stats;
262 #ifdef MNTTYPE_IGNORE
263 if (!strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
264 continue;
265 #endif
267 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
268 in the options string. For older systems, we need to stat the
269 directory that the filesystem is mounted on to get it.
271 Unfortunately, the HPUX 9.x mnttab entries created by automountq
272 contain a dev= option but the option value does not match the
273 st_dev value of the file (maybe the lower 16 bits match?). */
275 #if !defined(hpux) && !defined(__hpux__)
276 devopt = strstr (mnt->mnt_opts, "dev=");
277 if (devopt)
279 uintmax_t u = 0;
280 devopt += 4;
281 if (devopt[0] == '0' && (devopt[1] == 'x' || devopt[1] == 'X'))
282 devopt += 2;
283 xstrtoumax (devopt, NULL, 16, &u, NULL);
284 dev = u;
286 else
287 #endif /* not hpux */
289 if (stat (mnt->mnt_dir, &disk_stats) == -1) {
290 if (errno == EACCES)
291 continue;
292 else
293 error (1, errno, _("error in %s: %s"), table, mnt->mnt_dir);
295 dev = disk_stats.st_dev;
298 if (dev == statp->st_dev)
299 type = mnt->mnt_type;
302 if (endmntent (mfp) == 0)
303 error (0, errno, "%s", table);
304 #endif
306 #ifdef FSTYPE_GETMNT /* Ultrix. */
307 int offset = 0;
308 struct fs_data fsd;
310 while (type == NULL
311 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
313 if (fsd.fd_req.dev == statp->st_dev)
314 type = gt_names[fsd.fd_req.fstype];
316 #endif
318 #ifdef FSTYPE_USG_STATFS /* SVR3. */
319 struct statfs fss;
320 char typebuf[FSTYPSZ];
322 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
324 /* Don't die if a file was just removed. */
325 if (errno != ENOENT)
326 error (1, errno, "%s", path);
328 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
329 type = typebuf;
330 #endif
332 #ifdef FSTYPE_STATVFS /* SVR4. */
333 struct statvfs fss;
335 if (statvfs (relpath, &fss) == -1)
337 /* Don't die if a file was just removed. */
338 if (errno != ENOENT)
339 error (1, errno, "%s", path);
341 else
342 type = fss.f_basetype;
343 #endif
345 #ifdef FSTYPE_STATFS /* 4.4BSD. */
346 struct statfs fss;
347 char *p;
349 if (S_ISLNK (statp->st_mode))
350 p = dir_name (relpath);
351 else
352 p = relpath;
354 if (statfs (p, &fss) == -1)
356 /* Don't die if symlink to nonexisting file, or a file that was
357 just removed. */
358 if (errno != ENOENT)
359 error (1, errno, "%s", path);
361 else
363 #ifdef HAVE_F_FSTYPENAME_IN_STATFS
364 type = xstrdup (fss.f_fstypename);
365 #else
366 type = fstype_to_string (fss.f_type);
367 #endif
369 if (p != relpath)
370 free (p);
371 #endif
373 #ifdef AFS
374 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
375 type = "afs";
376 #endif
378 /* An unknown value can be caused by an ENOENT error condition.
379 Don't cache those values. */
380 fstype_known = (type != NULL);
382 return xstrdup (type ? type : _("unknown"));
389 char *
390 get_mounted_filesystems (void)
392 #ifdef HAVE_GETMNTENT
393 char *table = MOUNTED;
394 FILE *mfp;
395 struct mntent *mnt;
396 char *result = NULL;
397 size_t alloc_size = 0u;
398 size_t used = 0u;
401 mfp = setmntent (table, "r");
402 if (mfp == NULL)
403 error (1, errno, "%s", table);
405 while (NULL != (mnt = getmntent (mfp)))
407 size_t len;
409 #ifdef MNTTYPE_IGNORE
410 if (!strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
411 continue;
412 #endif
414 len = strlen(mnt->mnt_dir) + 1;
415 result = extendbuf(result, used+len, &alloc_size);
416 strcpy(&result[used], mnt->mnt_dir);
417 used += len; /* len already includes one for the \0 */
419 if (endmntent (mfp) == 0)
420 error (0, errno, "%s", table);
422 if (used)
424 /* Add the extra terminating \0 */
425 result = extendbuf(result, used+1, &alloc_size);
426 result[used] = 0;
428 else
430 assert(NULL == result); /* Postcondition. */
432 return result;
434 #else
435 /* No getmntent(). */
436 return NULL;
437 #endif