Use gnulib-tool --import to import the gnulib code, rather than the odd way we were...
[findutils.git] / find / fstype.c
blobc0b7ba20c5823a7d71dbe8ca22a0e70eed31b55b
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., 9 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
33 /* Need declaration of function `xstrtoumax' */
34 #include "../gnulib/lib/xstrtol.h"
36 #if ENABLE_NLS
37 # include <libintl.h>
38 # define _(Text) gettext (Text)
39 #else
40 # define _(Text) Text
41 #endif
42 #ifdef gettext_noop
43 # define N_(String) gettext_noop (String)
44 #else
45 /* See locate.c for explanation as to why not use (String) */
46 # define N_(String) String
47 #endif
49 static char *filesystem_type_uncached PARAMS((char *path, char *relpath, struct stat *statp));
51 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
52 #include <mntent.h>
53 #if !defined(MOUNTED)
54 # if defined(MNT_MNTTAB) /* HP-UX. */
55 # define MOUNTED MNT_MNTTAB
56 # endif
57 # if defined(MNTTABNAME) /* Dynix. */
58 # define MOUNTED MNTTABNAME
59 # endif
60 #endif
61 #endif
63 #ifdef FSTYPE_GETMNT /* Ultrix. */
64 #include <sys/param.h>
65 #include <sys/mount.h>
66 #include <sys/fs_types.h>
67 #endif
69 #ifdef FSTYPE_USG_STATFS /* SVR3. */
70 #include <sys/statfs.h>
71 #include <sys/fstyp.h>
72 #endif
74 #ifdef FSTYPE_STATVFS /* SVR4. */
75 #include <sys/statvfs.h>
76 #include <sys/fstyp.h>
77 #endif
79 #ifdef FSTYPE_STATFS /* 4.4BSD. */
80 #include <sys/param.h> /* NetBSD needs this. */
81 #include <sys/mount.h>
83 #ifndef HAVE_F_FSTYPENAME_IN_STATFS
84 #ifndef MFSNAMELEN /* NetBSD defines this. */
85 static char *
86 fstype_to_string (t)
87 short t;
89 #ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
90 static char *mn[] = INITMOUNTNAMES;
91 if (t >= 0 && t <= MOUNT_MAXTYPE)
92 return mn[t];
93 else
94 return "?";
95 #else /* !INITMOUNTNAMES */
96 switch (t)
98 case MOUNT_UFS:
99 return "ufs";
100 case MOUNT_NFS:
101 return "nfs";
102 #ifdef MOUNT_PC
103 case MOUNT_PC:
104 return "pc";
105 #endif
106 #ifdef MOUNT_MFS
107 case MOUNT_MFS:
108 return "mfs";
109 #endif
110 #ifdef MOUNT_LO
111 case MOUNT_LO:
112 return "lofs";
113 #endif
114 #ifdef MOUNT_TFS
115 case MOUNT_TFS:
116 return "tfs";
117 #endif
118 #ifdef MOUNT_TMP
119 case MOUNT_TMP:
120 return "tmp";
121 #endif
122 #ifdef MOUNT_MSDOS
123 case MOUNT_MSDOS:
124 return "msdos";
125 #endif
126 #ifdef MOUNT_ISO9660
127 case MOUNT_ISO9660:
128 return "iso9660fs";
129 #endif
130 default:
131 return "?";
133 #endif /* !INITMOUNTNAMES */
135 #endif /* !MFSNAMELEN */
136 #endif /* !HAVE_F_FSTYPENAME_IN_STATFS */
137 #endif /* FSTYPE_STATFS */
139 #ifdef FSTYPE_AIX_STATFS /* AIX. */
140 #include <sys/vmount.h>
141 #include <sys/statfs.h>
143 #define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
144 #define f_type f_vfstype
146 static char *
147 fstype_to_string (t)
148 short t;
150 switch (t)
152 case MNT_AIX:
153 #if 0 /* NFS filesystems are actually MNT_AIX. */
154 return "aix";
155 #endif
156 case MNT_NFS:
157 return "nfs";
158 case MNT_JFS:
159 return "jfs";
160 case MNT_CDROM:
161 return "cdrom";
162 default:
163 return "?";
166 #endif /* FSTYPE_AIX_STATFS */
168 #ifdef AFS
169 #include <netinet/in.h>
170 #include <afs/venus.h>
171 #if __STDC__
172 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
173 #undef _VICEIOCTL
174 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
175 #endif
176 #ifndef _IOW
177 /* AFS on Solaris 2.3 doesn't get this definition. */
178 #include <sys/ioccom.h>
179 #endif
181 static int
182 in_afs (path)
183 char *path;
185 static char space[2048];
186 struct ViceIoctl vi;
188 vi.in_size = 0;
189 vi.out_size = sizeof (space);
190 vi.out = space;
192 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
193 && (errno == EINVAL || errno == ENOENT))
194 return 0;
195 return 1;
197 #endif /* AFS */
199 /* Nonzero if the current filesystem's type is known. */
200 static int fstype_known = 0;
202 /* Return a static string naming the type of filesystem that the file PATH,
203 described by STATP, is on.
204 RELPATH is the file name relative to the current directory.
205 Return "unknown" if its filesystem type is unknown. */
207 char *
208 filesystem_type (char *path, char *relpath, struct stat *statp)
210 static char *current_fstype = NULL;
211 static dev_t current_dev;
213 if (current_fstype != NULL)
215 if (fstype_known && statp->st_dev == current_dev)
216 return current_fstype; /* Cached value. */
217 free (current_fstype);
219 current_dev = statp->st_dev;
220 current_fstype = filesystem_type_uncached (path, relpath, statp);
221 return current_fstype;
224 /* Return a newly allocated string naming the type of filesystem that the
225 file PATH, described by STATP, is on.
226 RELPATH is the file name relative to the current directory.
227 Return "unknown" if its filesystem type is unknown. */
229 static char *
230 filesystem_type_uncached (char *path, char *relpath, struct stat *statp)
232 char *type = NULL;
234 #ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
235 char *table = MOUNTED;
236 FILE *mfp;
237 struct mntent *mnt;
239 mfp = setmntent (table, "r");
240 if (mfp == NULL)
241 error (1, errno, "%s", table);
243 /* Find the entry with the same device number as STATP, and return
244 that entry's fstype. */
245 while (type == NULL && (mnt = getmntent (mfp)))
247 char *devopt;
248 dev_t dev;
249 struct stat disk_stats;
251 #ifdef MNTTYPE_IGNORE
252 if (!strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
253 continue;
254 #endif
256 /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
257 in the options string. For older systems, we need to stat the
258 directory that the filesystem is mounted on to get it.
260 Unfortunately, the HPUX 9.x mnttab entries created by automountq
261 contain a dev= option but the option value does not match the
262 st_dev value of the file (maybe the lower 16 bits match?). */
264 #if !defined(hpux) && !defined(__hpux__)
265 devopt = strstr (mnt->mnt_opts, "dev=");
266 if (devopt)
268 uintmax_t u = 0;
269 devopt += 4;
270 if (devopt[0] == '0' && (devopt[1] == 'x' || devopt[1] == 'X'))
271 devopt += 2;
272 xstrtoumax (devopt, NULL, 16, &u, NULL);
273 dev = u;
275 else
276 #endif /* not hpux */
278 if (stat (mnt->mnt_dir, &disk_stats) == -1) {
279 if (errno == EACCES)
280 continue;
281 else
282 error (1, errno, _("error in %s: %s"), table, mnt->mnt_dir);
284 dev = disk_stats.st_dev;
287 if (dev == statp->st_dev)
288 type = mnt->mnt_type;
291 if (endmntent (mfp) == 0)
292 error (0, errno, "%s", table);
293 #endif
295 #ifdef FSTYPE_GETMNT /* Ultrix. */
296 int offset = 0;
297 struct fs_data fsd;
299 while (type == NULL
300 && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
302 if (fsd.fd_req.dev == statp->st_dev)
303 type = gt_names[fsd.fd_req.fstype];
305 #endif
307 #ifdef FSTYPE_USG_STATFS /* SVR3. */
308 struct statfs fss;
309 char typebuf[FSTYPSZ];
311 if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
313 /* Don't die if a file was just removed. */
314 if (errno != ENOENT)
315 error (1, errno, "%s", path);
317 else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
318 type = typebuf;
319 #endif
321 #ifdef FSTYPE_STATVFS /* SVR4. */
322 struct statvfs fss;
324 if (statvfs (relpath, &fss) == -1)
326 /* Don't die if a file was just removed. */
327 if (errno != ENOENT)
328 error (1, errno, "%s", path);
330 else
331 type = fss.f_basetype;
332 #endif
334 #ifdef FSTYPE_STATFS /* 4.4BSD. */
335 struct statfs fss;
336 char *p;
338 if (S_ISLNK (statp->st_mode))
339 p = dir_name (relpath);
340 else
341 p = relpath;
343 if (statfs (p, &fss) == -1)
345 /* Don't die if symlink to nonexisting file, or a file that was
346 just removed. */
347 if (errno != ENOENT)
348 error (1, errno, "%s", path);
350 else
352 #ifdef HAVE_F_FSTYPENAME_IN_STATFS
353 type = xstrdup (fss.f_fstypename);
354 #else
355 type = fstype_to_string (fss.f_type);
356 #endif
358 if (p != relpath)
359 free (p);
360 #endif
362 #ifdef AFS
363 if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
364 type = "afs";
365 #endif
367 /* An unknown value can be caused by an ENOENT error condition.
368 Don't cache those values. */
369 fstype_known = (type != NULL);
371 return xstrdup (type ? type : _("unknown"));