]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/fstype.c
4fc4f2669bcfd3ac2dedf8fcf4dbe6d273138a1c
[bacula/bacula] / bacula / src / findlib / fstype.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 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
295 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
296 {
297    /* Solaris has the filesystem type name in the lstat packet */
298    bstrncpy(fs, ff_pkt->statp.st_fstype, fslen);
299    return true;
300 }
301  
302 #elif defined (__digital__) && defined (__unix__)  /* Tru64 */
303 /* Tru64 */
304 #include <sys/stat.h>
305 #include <sys/mount.h>
306  
307 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
308 {
309    char *fname = ff_pkt->fname;
310    struct statfs st;
311    if (statfs((char *)fname, &st) == 0) {
312       switch (st.f_type) {
313       /* Known good values */
314       case 0xa:         bstrncpy(fs, "advfs", fslen); return true;        /* Tru64 AdvFS */
315       case 0xe:         bstrncpy(fs, "nfs", fslen); return true;          /* Tru64 NFS   */
316       default:
317          Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".\n", st.f_type,
318                fname);
319          return false;
320       }
321    }
322    Dmsg1(50, "statfs() failed for \"%s\"\n", fname);
323    return false;
324 }
325 /* Tru64 */
326
327 #else    /* No recognised OS */
328
329 bool fstype(FF_PKT *ff_pkt, char *fs, int fslen)
330 {
331    char *fname = ff_pkt->fname;
332    Dmsg0(10, "!!! fstype() not implemented for this OS. !!!\n");
333    return false;
334 }
335 #endif
336
337 /* Read mtab entries  */
338 bool read_mtab(mtab_handler_t *mtab_handler, void *user_ctx)
339
340 /* Debian stretch GNU/KFreeBSD has both getmntinfo and getmntent, but
341    only the first seems to work, so ordering is important here */
342 #ifdef HAVE_GETMNTINFO
343    struct stat st;
344 #if defined(ST_NOWAIT)
345    int flags = ST_NOWAIT;
346 #elif defined(MNT_NOWAIT)
347    int flags = MNT_NOWAIT;
348 #else
349    int flags = 0;
350 #endif
351 #if defined(HAVE_NETBSD_OS)
352    struct statvfs *mntinfo;
353 #else
354    struct statfs *mntinfo;
355 #endif
356    int nument;
357
358    P(mutex);
359    if ((nument = getmntinfo(&mntinfo, flags)) > 0) {
360       while (nument-- > 0) {
361          if (is_rootfs(mntinfo->f_fstypename)) {
362             continue;
363          }
364          if (stat(mntinfo->f_mntonname, &st) < 0) {
365             continue;
366          }
367          mtab_handler(user_ctx, &st, mntinfo->f_mntfromname,
368             mntinfo->f_mntonname, mntinfo->f_fstypename, NULL);
369          mntinfo++;
370       }
371    }
372    V(mutex);
373 /* HAVE_GETMNTINFO */
374 #elif defined(HAVE_GETMNTENT)
375    FILE *mntfp;
376    struct stat st;
377  
378 #ifdef HAVE_LINUX_OS
379    struct mntent *mnt;
380    P(mutex);
381    if ((mntfp = setmntent("/proc/mounts", "r")) == NULL) {
382       if ((mntfp = setmntent(_PATH_MOUNTED, "r")) == NULL) {
383          V(mutex);
384          return false;
385       }
386    } 
387    while ((mnt = getmntent(mntfp)) != NULL) {
388       if (is_rootfs(mnt->mnt_type)) {
389          continue;
390       }
391
392       if (stat(mnt->mnt_dir, &st) < 0) {
393          continue;
394       }
395       mtab_handler(user_ctx, &st, mnt->mnt_type, mnt->mnt_dir,
396          mnt->mnt_opts, mnt->mnt_fsname);
397    }
398    endmntent(mntfp);
399    V(mutex);
400 #endif
401
402 #ifdef HAVE_SUN_OS
403    struct mnttab mnt;
404
405    P(mutex);
406    if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
407       V(mutex);
408       return false;
409    }
410
411    while (getmntent(mntfp, &mnt) == 0) {
412       if (is_rootfs(mnt.mnt_fstype)) {
413          continue;
414       }
415       if (stat(mnt.mnt_mountp, &st) < 0) {
416          continue;
417       }
418       mtab_handler(user_ctx, &st, mnt.mnt_fstype, mnt.mnt_mountp,
419          mnt.mnt_mntopts, mnt.mnt_special);
420    }
421    fclose(mntfp);
422    V(mutex);
423 #endif
424
425 #endif /* HAVE_GETMNTENT */
426    return true;
427
428  
429 #ifdef TEST_PROGRAM
430 int main(int argc, char **argv)
431 {
432    char *p;
433    char fs[1000];
434    int status = 0;
435
436    if (argc < 2) {
437       p = (argc < 1) ? "fstype" : argv[0];
438       printf("usage:\t%s path ...\n"
439             "\t%s prints the file system type and pathname of the paths.\n",
440             p, p);
441       return EXIT_FAILURE;
442    }
443    while (*++argv) {
444       if (!fstype(*argv, fs, sizeof(fs))) {
445          status = EXIT_FAILURE;
446       } else {
447          printf("%s\t%s\n", fs, *argv);
448       }
449    }
450    return status;
451 }
452 #endif