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