2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2018 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Implement routines to determine file system types.
22 * Written by Preben 'Peppe' Guldberg, December MMIV
23 * Updated by Kern Sibbald, April MMXV
31 #include <sys/types.h>
34 #include <sys/mnttab.h>
36 #else /* Set up for testing a stand alone program */
41 #define bstrncpy strncpy
42 #define Dmsg0(n,s) fprintf(stderr, s)
43 #define Dmsg1(n,s,a1) fprintf(stderr, s, a1)
44 #define Dmsg2(n,s,a1,a2) fprintf(stderr, s, a1, a2)
47 #define is_rootfs(x) bstrcmp("rootfs", x)
49 #if defined(HAVE_GETMNTINFO) || defined(HAVE_GETMNTENT)
50 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
59 /* Compare two device types */
60 static int compare_mtab_items(void *item1, void *item2)
62 mtab_item *mtab1, *mtab2;
63 mtab1 = (mtab_item *)item1;
64 mtab2 = (mtab_item *)item2;
65 if (mtab1->dev < mtab2->dev) return -1;
66 if (mtab1->dev > mtab2->dev) return 1;
70 void add_mtab_item(void *user_ctx, struct stat *st, const char *fstype,
71 const char *mountpoint, const char *mntopts,
74 rblist *mtab_list = (rblist *)user_ctx;
75 mtab_item *item, *ritem;
76 int len = strlen(fstype) + 1;
78 item = (mtab_item *)malloc(sizeof(mtab_item) + len);
79 item->dev = (uint64_t)st->st_dev;
80 bstrncpy(item->fstype, fstype, len);
81 ritem = (mtab_item *)mtab_list->insert((void *)item, compare_mtab_items);
83 /* Item already inserted, so we discard this one */
90 * These functions should be implemented for each OS
92 * bool fstype(FF_PKT *ff_pkt, char *fs, int fslen);
94 #if defined(HAVE_DARWIN_OS) \
95 || defined(HAVE_FREEBSD_OS ) \
96 || defined(HAVE_KFREEBSD_OS ) \
97 || defined(HAVE_OPENBSD_OS)
99 #include <sys/param.h>
100 #include <sys/mount.h>
102 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
104 char *fname = ff_pkt->fname;
107 if (statfs(fname, &st) == 0) {
108 bstrncpy(fs, st.f_fstypename, fslen);
111 Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
114 #elif defined(HAVE_NETBSD_OS)
115 #include <sys/param.h>
116 #include <sys/mount.h>
117 #ifdef HAVE_SYS_STATVFS_H
118 #include <sys/statvfs.h>
120 #define statvfs statfs
123 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
125 char *fname = ff_pkt->fname;
127 if (statvfs(fname, &st) == 0) {
128 bstrncpy(fs, st.f_fstypename, fslen);
131 Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
134 #elif defined(HAVE_HPUX_OS) \
135 || defined(HAVE_IRIX_OS)
137 #include <sys/types.h>
138 #include <sys/statvfs.h>
140 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
142 char *fname = ff_pkt->fname;
144 if (statvfs(fname, &st) == 0) {
145 bstrncpy(fs, st.f_basetype, fslen);
148 Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
152 #elif defined(HAVE_LINUX_OS)
158 * Linux statfs() does not return the filesystem name type. It
159 * only returns a binary fstype, so we must look up the type name
162 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
164 char *fname = ff_pkt->fname;
168 if (statfs(fname, &st) == 0) {
169 mtab_item *item, search_item;
170 if (*ff_pkt->last_fstypename && ff_pkt->last_fstype == (uint64_t)st.f_type) {
171 bstrncpy(fs, ff_pkt->last_fstypename, fslen);
174 if (!ff_pkt->mtab_list) {
175 ff_pkt->mtab_list = New(rblist());
176 read_mtab(add_mtab_item, ff_pkt->mtab_list);
178 search_item.dev = st.f_type;
179 item = (mtab_item *)ff_pkt->mtab_list->search((void *)&search_item, compare_mtab_items);
181 ff_pkt->last_fstype = st.f_type;
182 bstrncpy(ff_pkt->last_fstypename, item->fstype, sizeof(ff_pkt->last_fstypename));
183 bstrncpy(fs, ff_pkt->last_fstypename, fslen);
187 * Values obtained from statfs(2), testing and
189 * $ grep -r SUPER_MAGIC /usr/include/linux
192 /* Known good values */
193 /* ext2, ext3, and ext4 have the same code */
194 case 0xef53: fstype = "ext2"; break; /* EXT2_SUPER_MAGIC */
195 case 0x3153464a: fstype = "jfs"; break; /* JFS_SUPER_MAGIC */
196 case 0x5346544e: fstype = "ntfs"; break; /* NTFS_SB_MAGIC */
197 case 0x9fa0: fstype = "proc"; break; /* PROC_SUPER_MAGIC */
198 case 0x52654973: fstype = "reiserfs"; break; /* REISERFS_SUPER_MAGIC */
199 case 0x58465342: fstype = "xfs"; break; /* XFS_SB_MAGIC */
200 case 0x9fa2: fstype = "usbdevfs"; break; /* USBDEVICE_SUPER_MAGIC */
201 case 0x62656572: fstype = "sysfs"; break; /* SYSFS_MAGIC */
202 case 0x517B: fstype = "smbfs"; break; /* SMB_SUPER_MAGIC */
203 case 0x9660: fstype = "iso9660"; break; /* ISOFS_SUPER_MAGIC */
204 case 0xadf5: fstype = "adfs"; break; /* ADFS_SUPER_MAGIC */
205 case 0xadff: fstype = "affs"; break; /* AFFS_SUPER_MAGIC */
206 case 0x42465331: fstype = "befs"; break; /* BEFS_SUPER_MAGIC */
207 case 0xFF534D42: fstype = "cifs"; break; /* CIFS_MAGIC_NUMBER */
208 case 0x73757245: fstype = "coda"; break; /* CODA_SUPER_MAGIC */
209 case 0x012ff7b7: fstype = "coherent"; break; /* COH_SUPER_MAGIC */
210 case 0x28cd3d45: fstype = "cramfs"; break; /* CRAMFS_MAGIC */
211 case 0x1373: fstype = "devfs"; break; /* DEVFS_SUPER_MAGIC */
212 case 0x414A53: fstype = "efs"; break; /* EFS_SUPER_MAGIC */
213 case 0x137d: fstype = "ext"; break; /* EXT_SUPER_MAGIC */
214 case 0xef51: fstype = "oldext2"; break; /* EXT2_OLD_SUPER_MAGIC */
215 case 0x4244: fstype = "hfs"; break; /* EXT2_OLD_SUPER_MAGIC */
216 case 0xf995e849: fstype = "hpfs"; break; /* HPFS_SUPER_MAGIC */
217 case 0x958458f6: fstype = "hugetlbfs"; break; /* HUGETLBFS_MAGIC */
218 case 0x72b6: fstype = "jffs2"; break; /* JFFS2_SUPER_MAGIC */
219 case 0x2468: fstype = "minix"; break; /* MINIX2_SUPER_MAGIC */
220 case 0x2478: fstype = "minix"; break; /* MINIX2_SUPER_MAGIC2 */
221 case 0x137f: fstype = "minix"; break; /* MINIX_SUPER_MAGIC */
222 case 0x138f: fstype = "minix"; break; /* MINIX_SUPER_MAGIC2 */
223 case 0x4d44: fstype = "msdos"; break; /* MSDOS_SUPER_MAGIC */
224 case 0x564c: fstype = "ncpfs"; break; /* NCP_SUPER_MAGIC */
225 case 0x6969: fstype = "nfs"; break; /* NFS_SUPER_MAGIC */
226 case 0x9fa1: fstype = "openpromfs"; break; /* OPENPROM_SUPER_MAGIC */
227 case 0x002f: fstype = "qnx4"; break; /* QNX4_SUPER_MAGIC */
228 case 0x7275: fstype = "romfs"; break; /* QNX4_SUPER_MAGIC */
229 case 0x012ff7b6: fstype = "sysv2"; break;
230 case 0x012ff7b5: fstype = "sysv4"; break;
231 case 0x01021994: fstype = "tmpfs"; break;
232 case 0x15013346: fstype = "udf"; break;
233 case 0x00011954: fstype = "ufs"; break;
234 case 0xa501FCF5: fstype = "vxfs"; break;
235 case 0x012FF7B4: fstype = "xenix"; break;
236 case 0x012FD16D: fstype = "xiafs"; break;
237 case 0x9123683e: fstype = "btrfs"; break;
239 #if 0 /* These need confirmation */
240 case 0x6B414653: fstype = "afs"; break; /* AFS_FS_MAGIC */
241 case 0x0187: fstype = "autofs"; break; /* AUTOFS_SUPER_MAGIC */
242 case 0x62646576: fstype = "bdev"; break; /* ??? */
243 case 0x1BADFACE: fstype = "bfs"; break; /* BFS_MAGIC */
244 case 0x42494e4d: fstype = "binfmt_misc"; break; /* ??? */
245 case (('C'<<8)|'N'): fstype = "capifs"; break; /* CAPIFS_SUPER_MAGIC */
246 case 0x1cd1: fstype = "devpts"; break; /* ??? */
247 case 0x03111965: fstype = "eventpollfs"; break; /* EVENTPOLLFS_MAGIC */
248 case 0xBAD1DEA: fstype = "futexfs"; break; /* ??? */
249 case 0xaee71ee7: fstype = "gadgetfs"; break; /* GADGETFS_MAGIC */
250 case 0x00c0ffee: fstype = "hostfs"; break; /* HOSTFS_SUPER_MAGIC */
251 case 0xb00000ee: fstype = "hppfs"; break; /* HPPFS_SUPER_MAGIC */
252 case 0x12061983: fstype = "hwgfs"; break; /* HWGFS_MAGIC */
253 case 0x66726f67: fstype = "ibmasmfs"; break; /* IBMASMFS_MAGIC */
254 case 0x19800202: fstype = "mqueue"; break; /* MQUEUE_MAGIC */
255 case 0x6f70726f: fstype = "oprofilefs"; break; /* OPROFILEFS_MAGIC */
256 case 0xa0b4d889: fstype = "pfmfs"; break; /* PFMFS_MAGIC */
257 case 0x50495045: fstype = "pipfs"; break; /* PIPEFS_MAGIC */
258 case 0x858458f6: fstype = "ramfs"; break; /* RAMFS_MAGIC */
259 case 0x7275: fstype = "romfs"; break; /* ROMFS_MAGIC */
260 case 0x858458f6: fstype = "rootfs"; break; /* RAMFS_MAGIC */
261 case 0x67596969: fstype = "rpc_pipefs"; break; /* RPCAUTH_GSSMAGIC */
262 case 0x534F434B: fstype = "sockfs"; break; /* SOCKFS_MAGIC */
263 case 0x858458f6: fstype = "tmpfs"; break; /* RAMFS_MAGIC */
264 case 0x01021994: fstype = "tmpfs"; break; /* TMPFS_MAGIC */
268 Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".\n", st.f_type,
272 ff_pkt->last_fstype = st.f_type;
273 bstrncpy(ff_pkt->last_fstypename, fstype, sizeof(ff_pkt->last_fstypename));
274 bstrncpy(fs, fstype, fslen);
277 Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
281 #elif defined(HAVE_SUN_OS)
283 #include <sys/types.h>
284 #include <sys/stat.h>
286 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
288 /* Solaris has the filesystem type name in the lstat packet */
289 bstrncpy(fs, ff_pkt->statp.st_fstype, fslen);
293 #elif defined (__digital__) && defined (__unix__) /* Tru64 */
295 #include <sys/stat.h>
296 #include <sys/mount.h>
297 #include <sys/mnttab.h>
299 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
301 char *fname = ff_pkt->fname;
303 if (statfs((char *)fname, &st) == 0) {
305 /* Known good values */
306 case 0xa: bstrncpy(fs, "advfs", fslen); return true; /* Tru64 AdvFS */
307 case 0xe: bstrncpy(fs, "nfs", fslen); return true; /* Tru64 NFS */
309 Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".\n", st.f_type,
314 Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
319 #elif defined (HAVE_WIN32)
321 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
323 char *fname = ff_pkt->fname;
324 DWORD componentlength;
330 /* Copy Drive Letter, colon, and backslash to rootpath */
331 bstrncpy(rootpath, fname, sizeof(rootpath));
333 /* We don't want any popups if there isn't any media in the drive */
334 oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);
335 result = GetVolumeInformation(rootpath, NULL, 0, NULL, &componentlength, &fsflags, fs, fslen);
336 SetErrorMode(oldmode);
339 /* Windows returns NTFS, FAT, etc. Make it lowercase to be consistent with other OSes */
342 Dmsg2(10, "GetVolumeInformation() failed for \"%s\", Error = %d.\n", rootpath, GetLastError());
348 #else /* No recognised OS */
350 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
352 char *fname = ff_pkt->fname;
353 Dmsg0(10, "!!! fstype() not implemented for this OS. !!!\n");
358 /* Read mtab entries */
359 bool read_mtab(mtab_handler_t *mtab_handler, void *user_ctx)
361 /* Debian stretch GNU/KFreeBSD has both getmntinfo and getmntent, but
362 only the first seems to work, so we skip over getmntent in this case */
363 #ifndef HAVE_KFREEBSD_OS
364 #ifdef HAVE_GETMNTENT
371 if ((mntfp = setmntent("/proc/mounts", "r")) == NULL) {
372 if ((mntfp = setmntent(_PATH_MOUNTED, "r")) == NULL) {
377 while ((mnt = getmntent(mntfp)) != NULL) {
378 if (is_rootfs(mnt->mnt_type)) {
382 if (stat(mnt->mnt_dir, &st) < 0) {
385 mtab_handler(user_ctx, &st, mnt->mnt_type, mnt->mnt_dir,
386 mnt->mnt_opts, mnt->mnt_fsname);
396 if ((mntfp = bfopen(MNTTAB, "r")) == NULL) {
401 while (getmntent(mntfp, &mnt) == 0) {
402 if (is_rootfs(mnt.mnt_fstype)) {
405 if (stat(mnt.mnt_mountp, &st) < 0) {
408 mtab_handler(user_ctx, &st, mnt.mnt_fstype, mnt.mnt_mountp,
409 mnt.mnt_mntopts, mnt.mnt_special);
415 #endif /* HAVE_GETMNTENT */
416 #endif /* HAVE_KFREEBSD_OS */
418 #ifdef HAVE_GETMNTINFO
420 #if defined(ST_NOWAIT)
421 int flags = ST_NOWAIT;
422 #elif defined(MNT_NOWAIT)
423 int flags = MNT_NOWAIT;
427 #if defined(HAVE_NETBSD_OS)
428 struct statvfs *mntinfo;
430 struct statfs *mntinfo;
435 if ((nument = getmntinfo(&mntinfo, flags)) > 0) {
436 while (nument-- > 0) {
437 if (is_rootfs(mntinfo->f_fstypename)) {
440 if (stat(mntinfo->f_mntonname, &st) < 0) {
443 mtab_handler(user_ctx, &st, mntinfo->f_mntfromname,
444 mntinfo->f_mntonname, mntinfo->f_fstypename, NULL);
449 #endif /* HAVE_GETMNTINFO */
454 int main(int argc, char **argv)
461 p = (argc < 1) ? "fstype" : argv[0];
462 printf("usage:\t%s path ...\n"
463 "\t%s prints the file system type and pathname of the paths.\n",
468 if (!fstype(*argv, fs, sizeof(fs))) {
469 status = EXIT_FAILURE;
471 printf("%s\t%s\n", fs, *argv);