Migrated from GPL version 2 to GPL version 3
[findutils.git] / find / fstype.c
blobe448e9ed2c9731a71227f40c5b42c406ffcef1c8
1 /* fstype.c -- determine type of file systems that files are on
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2004 Free Software Foundation, Inc.
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 /* Written by David MacKenzie <djm@gnu.org>.
19 * Converted to use gnulib's read_file_system_list()
20 * by James Youngman <jay@gnu.org> (which saves a lot
21 * of manual hacking of configure.in).
25 #include <config.h>
26 #include <errno.h>
27 #include <stdbool.h>
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #include <sys/stat.h>
34 /* The presence of unistd.h is assumed by gnulib these days, so we
35 * might as well assume it too.
37 #include <unistd.h>
39 #ifdef HAVE_SYS_MNTIO_H
40 #ifdef HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43 #include <sys/mntio.h>
44 #endif
45 #ifdef HAVE_SYS_MKDEV_H
46 #include <sys/mkdev.h>
47 #endif
49 #ifdef STDC_HEADERS
50 #include <stdlib.h>
51 #else
52 extern int errno;
53 #endif
55 #include "defs.h"
56 #include "../gnulib/lib/dirname.h"
57 #include "xalloc.h"
58 #include "modetype.h"
60 /* Need declaration of function `xstrtoumax' */
61 #include "../gnulib/lib/xstrtol.h"
63 #include "extendbuf.h"
64 #include "mountlist.h"
65 #include "error.h"
69 #if ENABLE_NLS
70 # include <libintl.h>
71 # define _(Text) gettext (Text)
72 #else
73 # define _(Text) Text
74 #endif
75 #ifdef gettext_noop
76 # define N_(String) gettext_noop (String)
77 #else
78 /* See locate.c for explanation as to why not use (String) */
79 # define N_(String) String
80 #endif
82 static char *file_system_type_uncached PARAMS((const struct stat *statp, const char *path));
85 /* Get MNTTYPE_IGNORE if it is available. */
86 #if HAVE_MNTENT_H
87 # include <mntent.h>
88 #endif
89 #if HAVE_SYS_MNTTAB_H
90 # include <stdio.h>
91 # include <sys/mnttab.h>
92 #endif
98 static void
99 free_file_system_list(struct mount_entry *p)
101 while (p)
103 struct mount_entry *pnext = p->me_next;
105 free(p->me_devname);
106 free(p->me_mountdir);
108 if(p->me_type_malloced)
109 free(p->me_type);
110 p->me_next = NULL;
111 free(p);
112 p = pnext;
119 #ifdef AFS
120 #include <netinet/in.h>
121 #include <afs/venus.h>
122 #if __STDC__
123 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
124 #undef _VICEIOCTL
125 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
126 #endif
127 #ifndef _IOW
128 /* AFS on Solaris 2.3 doesn't get this definition. */
129 #include <sys/ioccom.h>
130 #endif
132 static int
133 in_afs (char *path)
135 static char space[2048];
136 struct ViceIoctl vi;
138 vi.in_size = 0;
139 vi.out_size = sizeof (space);
140 vi.out = space;
142 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
143 && (errno == EINVAL || errno == ENOENT))
144 return 0;
145 return 1;
147 #endif /* AFS */
149 /* Nonzero if the current file system's type is known. */
150 static int fstype_known = 0;
152 /* Return a static string naming the type of file system that the file PATH,
153 described by STATP, is on.
154 RELPATH is the file name relative to the current directory.
155 Return "unknown" if its file system type is unknown. */
157 char *
158 filesystem_type (const struct stat *statp, const char *path)
160 static char *current_fstype = NULL;
161 static dev_t current_dev;
163 if (current_fstype != NULL)
165 if (fstype_known && statp->st_dev == current_dev)
166 return current_fstype; /* Cached value. */
167 free (current_fstype);
169 current_dev = statp->st_dev;
170 current_fstype = file_system_type_uncached (statp, path);
171 return current_fstype;
174 static int
175 set_fstype_devno(struct mount_entry *p)
177 struct stat stbuf;
179 if (p->me_dev == (dev_t)-1)
181 set_stat_placeholders(&stbuf);
182 if (0 == (options.xstat)(p->me_mountdir, &stbuf))
184 p->me_dev = stbuf.st_dev;
185 return 0;
187 else
189 return -1;
192 return 0; /* not needed */
195 static struct mount_entry *
196 must_read_fs_list(bool need_fs_type)
198 struct mount_entry *entries = read_file_system_list(need_fs_type);
199 if (NULL == entries)
201 /* We cannot determine for sure which file we were trying to
202 * use because gnulib has extracted all that stuff away.
203 * Hence we cannot issue a specific error message here.
205 error(1, 0, "Cannot read mounted file system list");
207 return entries;
212 /* Return a newly allocated string naming the type of file system that the
213 file PATH, described by STATP, is on.
214 RELPATH is the file name relative to the current directory.
215 Return "unknown" if its file system type is unknown. */
217 static char *
218 file_system_type_uncached (const struct stat *statp, const char *path)
220 struct mount_entry *entries, *entry;
221 char *type;
223 (void) path;
225 #ifdef AFS
226 if (in_afs(path))
228 fstype_known = 1;
229 return xstrdup("afs");
231 #endif
233 entries = must_read_fs_list(true);
234 for (type=NULL, entry=entries; entry; entry=entry->me_next)
236 #ifdef MNTTYPE_IGNORE
237 if (!strcmp (entry->me_type, MNTTYPE_IGNORE))
238 continue;
239 #endif
240 set_fstype_devno(entry);
241 if (entry->me_dev == statp->st_dev)
243 type = xstrdup(entry->me_type);
244 break;
247 free_file_system_list(entries);
249 /* Don't cache unknown values. */
250 fstype_known = (type != NULL);
252 return type ? type : xstrdup(_("unknown"));
256 char *
257 get_mounted_filesystems (void)
259 char *result = NULL;
260 size_t alloc_size = 0u;
261 size_t used = 0u;
262 struct mount_entry *entries, *entry;
264 entries = must_read_fs_list(false);
265 for (entry=entries; entry; entry=entry->me_next)
267 size_t len;
269 #ifdef MNTTYPE_IGNORE
270 if (!strcmp (entry->me_type, MNTTYPE_IGNORE))
271 continue;
272 #endif
273 set_fstype_devno(entry);
275 len = strlen(entry->me_mountdir) + 1;
276 result = extendbuf(result, used+len, &alloc_size);
277 strcpy(&result[used], entry->me_mountdir);
278 used += len; /* len already includes one for the \0 */
281 free_file_system_list(entries);
282 return result;
286 dev_t *
287 get_mounted_devices (size_t *n)
289 size_t alloc_size = 0u;
290 size_t used = 0u;
291 struct mount_entry *entries, *entry;
292 dev_t *result = NULL;
294 /* Use read_file_system_list() rather than must_read_fs_list()
295 * because on some system this is always called at startup,
296 * and find should only exit fatally if it needs to use the
297 * result of this operation. If we can't get the fs list
298 * but we never need the information, there is no need to fail.
300 for (entry = entries = read_file_system_list(false);
301 entry;
302 entry = entry->me_next)
304 result = extendbuf(result, sizeof(dev_t)*(used+1), &alloc_size);
305 set_fstype_devno(entry);
306 result[used] = entry->me_dev;
307 ++used;
309 free_file_system_list(entries);
310 *n = used;
311 return result;