]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/fstype.c
a61886c59fe51f8c9105c235fe885013d2894c74
[bacula/bacula] / bacula / src / findlib / fstype.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Implement routines to determine file system types.
21  *
22  *   Written by Preben 'Peppe' Guldberg, December MMIV
23  *   Updated by Kern Sibbald, April MMXV
24  */
25
26
27 #ifndef TEST_PROGRAM
28
29 #include "bacula.h"
30 #include "find.h"
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #ifdef HAVE_SUN_OS
34   #include <sys/mnttab.h>
35 #endif
36 #else /* Set up for testing a stand alone program */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
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)
45 #endif
46
47 #define is_rootfs(x) bstrcmp("rootfs", x)
48
49 #if defined(HAVE_GETMNTINFO) || defined(HAVE_GETMNTENT)
50 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
51 #endif
52
53 struct mtab_item {
54    rblink link;
55    uint64_t dev;
56    char fstype[1];
57 };
58
59 /* Compare two device types */
60 static int compare_mtab_items(void *item1, void *item2)
61 {
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;
67    return 0;
68 }
69
70 #if defined(HAVE_LINUX_OS)
71 static void add_mtab_item(void *user_ctx, struct stat *st, const char *fstype,
72                const char *mountpoint, const char *mntopts,
73                const char *fsname)
74 {
75    rblist *mtab_list = (rblist *)user_ctx;
76    mtab_item *item, *ritem;
77    int len = strlen(fstype) + 1;
78    
79    item = (mtab_item *)malloc(sizeof(mtab_item) + len);
80    item->dev = (uint64_t)st->st_dev;
81    bstrncpy(item->fstype, fstype, len);
82    ritem = (mtab_item *)mtab_list->insert((void *)item, compare_mtab_items);
83    if (ritem != item) {
84       /* Item already inserted, so we discard this one */
85       free(item);
86    }
87 }
88 #endif
89
90 /* Compare directly the FS from a fname with a string */
91 bool fstype_cmp(FF_PKT *ff_pkt, const char *fsname)
92 {
93    char buf[256];
94    if (fstype(ff_pkt, buf, sizeof(buf))) {
95       return (strcmp(buf, fsname) == 0);
96    }
97    return false;
98 }
99
100 /*
101  * These functions should be implemented for each OS
102  *
103  *       bool fstype(FF_PKT *ff_pkt, char *fs, int fslen);
104  */
105 #if defined(HAVE_DARWIN_OS) \
106    || defined(HAVE_FREEBSD_OS ) \
107    || defined(HAVE_KFREEBSD_OS ) \
108    || defined(HAVE_OPENBSD_OS)
109
110 #include <sys/param.h>
111 #include <sys/mount.h>
112
113 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
114 {
115    char *fname = ff_pkt->fname;
116    struct statfs st;
117  
118    if (statfs(fname, &st) == 0) {
119       bstrncpy(fs, st.f_fstypename, fslen);
120       return true;
121    }
122    Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
123    return false;
124 }
125 #elif defined(HAVE_NETBSD_OS)
126 #include <sys/param.h>
127 #include <sys/mount.h>
128 #ifdef HAVE_SYS_STATVFS_H
129 #include <sys/statvfs.h>
130 #else
131 #define statvfs statfs
132 #endif
133
134 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
135 {
136    char *fname = ff_pkt->fname;
137    struct statvfs st;
138    if (statvfs(fname, &st) == 0) {
139       bstrncpy(fs, st.f_fstypename, fslen);
140       return true;
141    }
142    Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
143    return false;
144 }
145 #elif defined(HAVE_HPUX_OS) \
146    || defined(HAVE_IRIX_OS)
147
148 #include <sys/types.h>
149 #include <sys/statvfs.h>
150
151 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
152 {
153    char *fname = ff_pkt->fname;
154    struct statvfs st;
155    if (statvfs(fname, &st) == 0) {
156       bstrncpy(fs, st.f_basetype, fslen);
157       return true;
158    }
159    Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
160    return false;
161 }
162
163 #elif defined(HAVE_LINUX_OS)
164
165 #include <sys/vfs.h>
166 #include <mntent.h>
167
168 /*
169  * Linux statfs() does not return the filesystem name type.  It
170  *  only returns a binary fstype, so we must look up the type name
171  *  in mtab.
172  */
173 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
174 {
175    char *fname = ff_pkt->fname;
176    struct statfs st;
177    const char *fstype;
178
179    if (statfs(fname, &st) == 0) {
180       mtab_item *item, search_item;
181       if (*ff_pkt->last_fstypename && ff_pkt->last_fstype == (uint64_t)st.f_type) {
182          bstrncpy(fs, ff_pkt->last_fstypename, fslen);
183          return true; 
184       }
185       if (!ff_pkt->mtab_list) {
186          ff_pkt->mtab_list = New(rblist());
187          read_mtab(add_mtab_item, ff_pkt->mtab_list);
188       }
189       search_item.dev = st.f_type;
190       item = (mtab_item *)ff_pkt->mtab_list->search((void *)&search_item, compare_mtab_items);
191       if (item) {
192          ff_pkt->last_fstype = st.f_type;
193          bstrncpy(ff_pkt->last_fstypename, item->fstype, sizeof(ff_pkt->last_fstypename));
194          bstrncpy(fs, ff_pkt->last_fstypename, fslen);
195          return true; 
196       }
197       /*
198        * Values obtained from statfs(2), testing and
199        *
200        *    $ grep -r SUPER_MAGIC /usr/include/linux
201        */
202       switch (st.f_type) {
203       /* Known good values */
204       /* ext2, ext3, and ext4 have the same code */
205       case 0xef53:         fstype = "ext2"; break;          /* EXT2_SUPER_MAGIC */
206       case 0x3153464a:     fstype = "jfs"; break;           /* JFS_SUPER_MAGIC */
207       case 0x5346544e:     fstype = "ntfs"; break;          /* NTFS_SB_MAGIC */
208       case 0x9fa0:         fstype = "proc"; break;          /* PROC_SUPER_MAGIC */
209       case 0x52654973:     fstype = "reiserfs"; break;      /* REISERFS_SUPER_MAGIC */
210       case 0x58465342:     fstype = "xfs"; break;           /* XFS_SB_MAGIC */
211       case 0x9fa2:         fstype = "usbdevfs"; break;      /* USBDEVICE_SUPER_MAGIC */
212       case 0x62656572:     fstype = "sysfs"; break;         /* SYSFS_MAGIC */
213       case 0x517B:         fstype = "smbfs"; break;         /* SMB_SUPER_MAGIC */
214       case 0x9660:         fstype = "iso9660"; break;       /* ISOFS_SUPER_MAGIC */
215       case 0xadf5:         fstype = "adfs"; break;          /* ADFS_SUPER_MAGIC */
216       case 0xadff:         fstype = "affs"; break;          /* AFFS_SUPER_MAGIC */
217       case 0x42465331:     fstype = "befs"; break;          /* BEFS_SUPER_MAGIC */
218       case 0xFF534D42:     fstype = "cifs"; break;          /* CIFS_MAGIC_NUMBER */
219       case 0x73757245:     fstype = "coda"; break;          /* CODA_SUPER_MAGIC */
220       case 0x012ff7b7:     fstype = "coherent"; break;      /* COH_SUPER_MAGIC */
221       case 0x28cd3d45:     fstype = "cramfs"; break;        /* CRAMFS_MAGIC */
222       case 0x1373:         fstype = "devfs"; break;         /* DEVFS_SUPER_MAGIC */
223       case 0x414A53:       fstype = "efs"; break;           /* EFS_SUPER_MAGIC */
224       case 0x137d:         fstype = "ext"; break;           /* EXT_SUPER_MAGIC */
225       case 0xef51:         fstype = "oldext2"; break;          /* EXT2_OLD_SUPER_MAGIC */
226       case 0x4244:         fstype = "hfs"; break;          /* EXT2_OLD_SUPER_MAGIC */
227       case 0xf995e849:     fstype = "hpfs"; break;          /* HPFS_SUPER_MAGIC */
228       case 0x958458f6:     fstype = "hugetlbfs"; break;     /* HUGETLBFS_MAGIC */
229       case 0x72b6:         fstype = "jffs2"; break;         /* JFFS2_SUPER_MAGIC */
230       case 0x2468:         fstype = "minix"; break;         /* MINIX2_SUPER_MAGIC */
231       case 0x2478:         fstype = "minix"; break;         /* MINIX2_SUPER_MAGIC2 */
232       case 0x137f:         fstype = "minix"; break;         /* MINIX_SUPER_MAGIC */
233       case 0x138f:         fstype = "minix"; break;         /* MINIX_SUPER_MAGIC2 */
234       case 0x4d44:         fstype = "msdos"; break;         /* MSDOS_SUPER_MAGIC */
235       case 0x564c:         fstype = "ncpfs"; break;         /* NCP_SUPER_MAGIC */
236       case 0x6969:         fstype = "nfs"; break;           /* NFS_SUPER_MAGIC */
237       case 0x9fa1:         fstype = "openpromfs"; break;    /* OPENPROM_SUPER_MAGIC */
238       case 0x002f:         fstype = "qnx4"; break;          /* QNX4_SUPER_MAGIC */
239       case 0x7275:         fstype = "romfs"; break;          /* QNX4_SUPER_MAGIC */
240       case 0x012ff7b6:     fstype = "sysv2"; break;
241       case 0x012ff7b5:     fstype = "sysv4"; break;
242       case 0x01021994:     fstype = "tmpfs"; break;
243       case 0x15013346:     fstype = "udf"; break;
244       case 0x00011954:     fstype = "ufs"; break;
245       case 0xa501FCF5:     fstype = "vxfs"; break;
246       case 0x012FF7B4:     fstype = "xenix"; break;
247       case 0x012FD16D:     fstype = "xiafs"; break;
248       case 0x9123683e:     fstype = "btrfs"; break;
249
250 #if 0       /* These need confirmation */
251       case 0x6B414653:     fstype = "afs"; break;           /* AFS_FS_MAGIC */
252       case 0x0187:         fstype = "autofs"; break;        /* AUTOFS_SUPER_MAGIC */
253       case 0x62646576:     fstype = "bdev"; break;          /* ??? */
254       case 0x1BADFACE:     fstype = "bfs"; break;           /* BFS_MAGIC */
255       case 0x42494e4d:     fstype = "binfmt_misc"; break;   /* ??? */
256       case (('C'<<8)|'N'): fstype = "capifs"; break;        /* CAPIFS_SUPER_MAGIC */
257       case 0x1cd1:         fstype = "devpts"; break;        /* ??? */
258       case 0x03111965:     fstype = "eventpollfs"; break;   /* EVENTPOLLFS_MAGIC */
259       case 0xBAD1DEA:      fstype = "futexfs"; break;       /* ??? */
260       case 0xaee71ee7:     fstype = "gadgetfs"; break;      /* GADGETFS_MAGIC */
261       case 0x00c0ffee:     fstype = "hostfs"; break;        /* HOSTFS_SUPER_MAGIC */
262       case 0xb00000ee:     fstype = "hppfs"; break;         /* HPPFS_SUPER_MAGIC */
263       case 0x12061983:     fstype = "hwgfs"; break;         /* HWGFS_MAGIC */
264       case 0x66726f67:     fstype = "ibmasmfs"; break;      /* IBMASMFS_MAGIC */
265       case 0x19800202:     fstype = "mqueue"; break;        /* MQUEUE_MAGIC */
266       case 0x6f70726f:     fstype = "oprofilefs"; break;    /* OPROFILEFS_MAGIC */
267       case 0xa0b4d889:     fstype = "pfmfs"; break;         /* PFMFS_MAGIC */
268       case 0x50495045:     fstype = "pipfs"; break;         /* PIPEFS_MAGIC */
269       case 0x858458f6:     fstype = "ramfs"; break;         /* RAMFS_MAGIC */
270       case 0x7275:         fstype = "romfs"; break;         /* ROMFS_MAGIC */
271       case 0x858458f6:     fstype = "rootfs"; break;        /* RAMFS_MAGIC */
272       case 0x67596969:     fstype = "rpc_pipefs"; break;    /* RPCAUTH_GSSMAGIC */
273       case 0x534F434B:     fstype = "sockfs"; break;        /* SOCKFS_MAGIC */
274       case 0x858458f6:     fstype = "tmpfs"; break;         /* RAMFS_MAGIC */
275       case 0x01021994:     fstype = "tmpfs"; break;         /* TMPFS_MAGIC */
276 #endif
277  
278       default:
279          Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".\n", st.f_type,
280                fname);
281          return false;
282       }
283       ff_pkt->last_fstype = st.f_type;
284       bstrncpy(ff_pkt->last_fstypename, fstype, sizeof(ff_pkt->last_fstypename));
285       bstrncpy(fs, fstype, fslen);
286       return true;
287    }
288    Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
289    return false;
290 }
291
292 #elif defined(HAVE_SUN_OS)
293
294 #include <sys/types.h>
295 #include <sys/stat.h>
296 #include <sys/mnttab.h>
297
298 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
299 {
300    /* Solaris has the filesystem type name in the lstat packet */
301    bstrncpy(fs, ff_pkt->statp.st_fstype, fslen);
302    return true;
303 }
304  
305 #elif defined (__digital__) && defined (__unix__)  /* Tru64 */
306 /* Tru64 */
307 #include <sys/stat.h>
308 #include <sys/mount.h>
309  
310 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
311 {
312    char *fname = ff_pkt->fname;
313    struct statfs st;
314    if (statfs((char *)fname, &st) == 0) {
315       switch (st.f_type) {
316       /* Known good values */
317       case 0xa:         bstrncpy(fs, "advfs", fslen); return true;        /* Tru64 AdvFS */
318       case 0xe:         bstrncpy(fs, "nfs", fslen); return true;          /* Tru64 NFS   */
319       default:
320          Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".\n", st.f_type,
321                fname);
322          return false;
323       }
324    }
325    Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
326    return false;
327 }
328 /* Tru64 */
329
330 #else    /* No recognised OS */
331
332 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
333 {
334    char *fname = ff_pkt->fname;
335    Dmsg0(10, "!!! fstype() not implemented for this OS. !!!\n");
336    return false;
337 }
338 #endif
339
340 /* Read mtab entries  */
341 bool read_mtab(mtab_handler_t *mtab_handler, void *user_ctx)
342
343 /* Debian stretch GNU/KFreeBSD has both getmntinfo and getmntent, but
344    only the first seems to work, so ordering is important here */
345 #ifdef HAVE_GETMNTINFO
346    struct stat st;
347 #if defined(ST_NOWAIT)
348    int flags = ST_NOWAIT;
349 #elif defined(MNT_NOWAIT)
350    int flags = MNT_NOWAIT;
351 #else
352    int flags = 0;
353 #endif
354 #if defined(HAVE_NETBSD_OS)
355    struct statvfs *mntinfo;
356 #else
357    struct statfs *mntinfo;
358 #endif
359    int nument;
360
361    P(mutex);
362    if ((nument = getmntinfo(&mntinfo, flags)) > 0) {
363       while (nument-- > 0) {
364          if (is_rootfs(mntinfo->f_fstypename)) {
365             continue;
366          }
367          if (stat(mntinfo->f_mntonname, &st) < 0) {
368             continue;
369          }
370          mtab_handler(user_ctx, &st, mntinfo->f_mntfromname,
371             mntinfo->f_mntonname, mntinfo->f_fstypename, NULL);
372          mntinfo++;
373       }
374    }
375    V(mutex);
376 /* HAVE_GETMNTINFO */
377 #elif defined(HAVE_GETMNTENT)
378    FILE *mntfp;
379    struct stat st;
380  
381 #ifdef HAVE_LINUX_OS
382    struct mntent *mnt;
383    P(mutex);
384    if ((mntfp = setmntent("/proc/mounts", "r")) == NULL) {
385       if ((mntfp = setmntent(_PATH_MOUNTED, "r")) == NULL) {
386          V(mutex);
387          return false;
388       }
389    } 
390    while ((mnt = getmntent(mntfp)) != NULL) {
391       if (is_rootfs(mnt->mnt_type)) {
392          continue;
393       }
394
395       if (stat(mnt->mnt_dir, &st) < 0) {
396          continue;
397       }
398       mtab_handler(user_ctx, &st, mnt->mnt_type, mnt->mnt_dir,
399          mnt->mnt_opts, mnt->mnt_fsname);
400    }
401    endmntent(mntfp);
402    V(mutex);
403 #endif
404
405 #ifdef HAVE_SUN_OS
406    struct mnttab mnt;
407
408    P(mutex);
409    if ((mntfp = bfopen(MNTTAB, "r")) == NULL) {
410       V(mutex);
411       return false;
412    }
413
414    while (getmntent(mntfp, &mnt) == 0) {
415       if (is_rootfs(mnt.mnt_fstype)) {
416          continue;
417       }
418       if (stat(mnt.mnt_mountp, &st) < 0) {
419          continue;
420       }
421       mtab_handler(user_ctx, &st, mnt.mnt_fstype, mnt.mnt_mountp,
422          mnt.mnt_mntopts, mnt.mnt_special);
423    }
424    fclose(mntfp);
425    V(mutex);
426 #endif
427
428 #endif /* HAVE_GETMNTENT */
429    return true;
430
431  
432 #ifdef TEST_PROGRAM
433 int main(int argc, char **argv)
434 {
435    char *p;
436    char fs[1000];
437    int status = 0;
438
439    if (argc < 2) {
440       p = (argc < 1) ? "fstype" : argv[0];
441       printf("usage:\t%s path ...\n"
442             "\t%s prints the file system type and pathname of the paths.\n",
443             p, p);
444       return EXIT_FAILURE;
445    }
446    while (*++argv) {
447       if (!fstype(*argv, fs, sizeof(fs))) {
448          status = EXIT_FAILURE;
449       } else {
450          printf("%s\t%s\n", fs, *argv);
451       }
452    }
453    return status;
454 }
455 #endif