Enhancements to format strings in hman-readable messages intended to allow better...
[findutils.git] / find / fstype.c
blobed2946a53b617ded965346699a7aeb8735eb6d30
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 #include <fcntl.h>
40 #ifdef HAVE_SYS_MNTIO_H
41 #include <sys/mntio.h>
42 #endif
43 #ifdef HAVE_SYS_MKDEV_H
44 #include <sys/mkdev.h>
45 #endif
47 #ifdef STDC_HEADERS
48 #include <stdlib.h>
49 #else
50 extern int errno;
51 #endif
53 #include "defs.h"
54 #include "../gnulib/lib/dirname.h"
55 #include "xalloc.h"
56 #include "modetype.h"
58 /* Need declaration of function `xstrtoumax' */
59 #include "../gnulib/lib/xstrtol.h"
61 #include "extendbuf.h"
62 #include "mountlist.h"
63 #include "error.h"
67 #if ENABLE_NLS
68 # include <libintl.h>
69 # define _(Text) gettext (Text)
70 #else
71 # define _(Text) Text
72 #endif
73 #ifdef gettext_noop
74 # define N_(String) gettext_noop (String)
75 #else
76 /* See locate.c for explanation as to why not use (String) */
77 # define N_(String) String
78 #endif
80 static char *file_system_type_uncached PARAMS((const struct stat *statp, const char *path));
83 /* Get MNTTYPE_IGNORE if it is available. */
84 #if HAVE_MNTENT_H
85 # include <mntent.h>
86 #endif
87 #if HAVE_SYS_MNTTAB_H
88 # include <stdio.h>
89 # include <sys/mnttab.h>
90 #endif
96 static void
97 free_file_system_list(struct mount_entry *p)
99 while (p)
101 struct mount_entry *pnext = p->me_next;
103 free(p->me_devname);
104 free(p->me_mountdir);
106 if(p->me_type_malloced)
107 free(p->me_type);
108 p->me_next = NULL;
109 free(p);
110 p = pnext;
117 #ifdef AFS
118 #include <netinet/in.h>
119 #include <afs/venus.h>
120 #if __STDC__
121 /* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
122 #undef _VICEIOCTL
123 #define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
124 #endif
125 #ifndef _IOW
126 /* AFS on Solaris 2.3 doesn't get this definition. */
127 #include <sys/ioccom.h>
128 #endif
130 static int
131 in_afs (char *path)
133 static char space[2048];
134 struct ViceIoctl vi;
136 vi.in_size = 0;
137 vi.out_size = sizeof (space);
138 vi.out = space;
140 if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
141 && (errno == EINVAL || errno == ENOENT))
142 return 0;
143 return 1;
145 #endif /* AFS */
147 /* Nonzero if the current file system's type is known. */
148 static int fstype_known = 0;
150 /* Return a static string naming the type of file system that the file PATH,
151 described by STATP, is on.
152 RELPATH is the file name relative to the current directory.
153 Return "unknown" if its file system type is unknown. */
155 char *
156 filesystem_type (const struct stat *statp, const char *path)
158 static char *current_fstype = NULL;
159 static dev_t current_dev;
161 if (current_fstype != NULL)
163 if (fstype_known && statp->st_dev == current_dev)
164 return current_fstype; /* Cached value. */
165 free (current_fstype);
167 current_dev = statp->st_dev;
168 current_fstype = file_system_type_uncached (statp, path);
169 return current_fstype;
172 static int
173 set_fstype_devno(struct mount_entry *p)
175 struct stat stbuf;
177 if (p->me_dev == (dev_t)-1)
179 set_stat_placeholders(&stbuf);
180 if (0 == (options.xstat)(p->me_mountdir, &stbuf))
182 p->me_dev = stbuf.st_dev;
183 return 0;
185 else
187 return -1;
190 return 0; /* not needed */
193 static struct mount_entry *
194 must_read_fs_list(bool need_fs_type)
196 struct mount_entry *entries = read_file_system_list(need_fs_type);
197 if (NULL == entries)
199 /* We cannot determine for sure which file we were trying to
200 * use because gnulib has extracted all that stuff away.
201 * Hence we cannot issue a specific error message here.
203 error(1, 0, "Cannot read mounted file system list");
205 return entries;
210 /* Return a newly allocated string naming the type of file system that the
211 file PATH, described by STATP, is on.
212 RELPATH is the file name relative to the current directory.
213 Return "unknown" if its file system type is unknown. */
215 static char *
216 file_system_type_uncached (const struct stat *statp, const char *path)
218 struct mount_entry *entries, *entry;
219 char *type;
221 (void) path;
223 #ifdef AFS
224 if (in_afs(path))
226 fstype_known = 1;
227 return xstrdup("afs");
229 #endif
231 entries = must_read_fs_list(true);
232 for (type=NULL, entry=entries; entry; entry=entry->me_next)
234 #ifdef MNTTYPE_IGNORE
235 if (!strcmp (entry->me_type, MNTTYPE_IGNORE))
236 continue;
237 #endif
238 set_fstype_devno(entry);
239 if (entry->me_dev == statp->st_dev)
241 type = xstrdup(entry->me_type);
242 break;
245 free_file_system_list(entries);
247 /* Don't cache unknown values. */
248 fstype_known = (type != NULL);
249 if (type)
250 return type;
251 else
252 return xstrdup(_("unknown"
253 /* TRANSLATORS: this is essentially an abbreviation
254 for "unknown file system type" */));
258 char *
259 get_mounted_filesystems (void)
261 char *result = NULL;
262 size_t alloc_size = 0u;
263 size_t used = 0u;
264 struct mount_entry *entries, *entry;
266 entries = must_read_fs_list(false);
267 for (entry=entries; entry; entry=entry->me_next)
269 size_t len;
271 #ifdef MNTTYPE_IGNORE
272 if (!strcmp (entry->me_type, MNTTYPE_IGNORE))
273 continue;
274 #endif
275 set_fstype_devno(entry);
277 len = strlen(entry->me_mountdir) + 1;
278 result = extendbuf(result, used+len, &alloc_size);
279 strcpy(&result[used], entry->me_mountdir);
280 used += len; /* len already includes one for the \0 */
283 free_file_system_list(entries);
284 return result;
288 dev_t *
289 get_mounted_devices (size_t *n)
291 size_t alloc_size = 0u;
292 size_t used = 0u;
293 struct mount_entry *entries, *entry;
294 dev_t *result = NULL;
296 /* Use read_file_system_list() rather than must_read_fs_list()
297 * because on some system this is always called at startup,
298 * and find should only exit fatally if it needs to use the
299 * result of this operation. If we can't get the fs list
300 * but we never need the information, there is no need to fail.
302 for (entry = entries = read_file_system_list(false);
303 entry;
304 entry = entry->me_next)
306 result = extendbuf(result, sizeof(dev_t)*(used+1), &alloc_size);
307 set_fstype_devno(entry);
308 result[used] = entry->me_dev;
309 ++used;
311 free_file_system_list(entries);
312 *n = used;
313 return result;