diff options
Diffstat (limited to 'extras/volume_id/lib')
-rw-r--r-- | extras/volume_id/lib/Makefile | 3 | ||||
-rw-r--r-- | extras/volume_id/lib/exported_symbols | 2 | ||||
-rw-r--r-- | extras/volume_id/lib/gfs.c | 120 | ||||
-rw-r--r-- | extras/volume_id/lib/libvolume_id.h | 2 | ||||
-rw-r--r-- | extras/volume_id/lib/volume_id.c | 6 |
5 files changed, 132 insertions, 1 deletions
diff --git a/extras/volume_id/lib/Makefile b/extras/volume_id/lib/Makefile index 8d8710d09a..90cd63e745 100644 --- a/extras/volume_id/lib/Makefile +++ b/extras/volume_id/lib/Makefile @@ -13,7 +13,7 @@ INSTALL_DATA = ${INSTALL} -m 644 INSTALL_LIB = ${INSTALL} -m 755 SHLIB_CUR = 0 -SHLIB_REV = 65 +SHLIB_REV = 66 SHLIB_AGE = 0 SHLIB = libvolume_id.so.$(SHLIB_CUR).$(SHLIB_REV).$(SHLIB_AGE) @@ -45,6 +45,7 @@ OBJS= \ romfs.o \ sysv.o \ minix.o \ + gfs.o \ luks.o \ ocfs.o \ vxfs.o \ diff --git a/extras/volume_id/lib/exported_symbols b/extras/volume_id/lib/exported_symbols index df5f9f05c9..3f10ec0c78 100644 --- a/extras/volume_id/lib/exported_symbols +++ b/extras/volume_id/lib/exported_symbols @@ -27,6 +27,8 @@ volume_id_probe_xfs; volume_id_probe_squashfs; volume_id_probe_netware; + volume_id_probe_gfs; + volume_id_probe_gfs2; volume_id_probe_linux_raid; volume_id_probe_lvm1; diff --git a/extras/volume_id/lib/gfs.c b/extras/volume_id/lib/gfs.c new file mode 100644 index 0000000000..40a4493b32 --- /dev/null +++ b/extras/volume_id/lib/gfs.c @@ -0,0 +1,120 @@ +/* + * volume_id - reads filesystem label and uuid + * + * Copyright (C) 2006 Red Hat, Inc. <redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> + +#include "libvolume_id.h" +#include "util.h" + +/* Common gfs/gfs2 constants: */ +#define GFS_MAGIC 0x01161970 +#define GFS_DEFAULT_BSIZE 4096 +#define GFS_SUPERBLOCK_OFFSET (0x10 * GFS_DEFAULT_BSIZE) +#define GFS_METATYPE_SB 1 +#define GFS_FORMAT_SB 100 +#define GFS_LOCKNAME_LEN 64 + +/* gfs1 constants: */ +#define GFS_FORMAT_FS 1309 +#define GFS_FORMAT_MULTI 1401 +/* gfs2 constants: */ +#define GFS2_FORMAT_FS 1801 +#define GFS2_FORMAT_MULTI 1900 + +struct gfs2_meta_header { + uint32_t mh_magic; + uint32_t mh_type; + uint64_t __pad0; /* Was generation number in gfs1 */ + uint32_t mh_format; + uint32_t __pad1; /* Was incarnation number in gfs1 */ +}; + +struct gfs2_inum { + uint64_t no_formal_ino; + uint64_t no_addr; +}; + +struct gfs2_sb { + struct gfs2_meta_header sb_header; + + uint32_t sb_fs_format; + uint32_t sb_multihost_format; + uint32_t __pad0; /* Was superblock flags in gfs1 */ + + uint32_t sb_bsize; + uint32_t sb_bsize_shift; + uint32_t __pad1; /* Was journal segment size in gfs1 */ + + struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */ + struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */ + struct gfs2_inum sb_root_dir; + + char sb_lockproto[GFS_LOCKNAME_LEN]; + char sb_locktable[GFS_LOCKNAME_LEN]; + /* In gfs1, quota and license dinodes followed */ +} PACKED; + +static int volume_id_probe_gfs_generic(struct volume_id *id, uint64_t off, int vers) +{ + struct gfs2_sb *sbd; + + info("probing at offset 0x%llx", (unsigned long long) off); + + sbd = (struct gfs2_sb *) + volume_id_get_buffer(id, off + GFS_SUPERBLOCK_OFFSET, sizeof(struct gfs2_sb)); + if (sbd == NULL) + return -1; + + if (be32_to_cpu(sbd->sb_header.mh_magic) == GFS_MAGIC && + be32_to_cpu(sbd->sb_header.mh_type) == GFS_METATYPE_SB && + be32_to_cpu(sbd->sb_header.mh_format) == GFS_FORMAT_SB) { + if (vers == 1) { + if (be32_to_cpu(sbd->sb_fs_format) != GFS_FORMAT_FS || + be32_to_cpu(sbd->sb_multihost_format) != GFS_FORMAT_MULTI) + return -1; /* not gfs1 */ + id->type = "gfs"; + } + else if (vers == 2) { + if (be32_to_cpu(sbd->sb_fs_format) != GFS2_FORMAT_FS || + be32_to_cpu(sbd->sb_multihost_format) != GFS2_FORMAT_MULTI) + return -1; /* not gfs2 */ + id->type = "gfs2"; + } + else + return -1; + strcpy(id->type_version, "1"); + volume_id_set_usage(id, VOLUME_ID_FILESYSTEM); + return 0; + } + return -1; +} + +int volume_id_probe_gfs(struct volume_id *id, uint64_t off) +{ + return volume_id_probe_gfs_generic(id, off, 1); +} + +int volume_id_probe_gfs2(struct volume_id *id, uint64_t off) +{ + return volume_id_probe_gfs_generic(id, off, 2); +} diff --git a/extras/volume_id/lib/libvolume_id.h b/extras/volume_id/lib/libvolume_id.h index df9fcd9891..e34f4679e7 100644 --- a/extras/volume_id/lib/libvolume_id.h +++ b/extras/volume_id/lib/libvolume_id.h @@ -89,6 +89,8 @@ extern int volume_id_probe_vxfs(struct volume_id *id, uint64_t off); extern int volume_id_probe_xfs(struct volume_id *id, uint64_t off); extern int volume_id_probe_squashfs(struct volume_id *id, uint64_t off); extern int volume_id_probe_netware(struct volume_id *id, uint64_t off); +extern int volume_id_probe_gfs(struct volume_id *id, uint64_t off); +extern int volume_id_probe_gfs2(struct volume_id *id, uint64_t off); /* special formats */ extern int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off); diff --git a/extras/volume_id/lib/volume_id.c b/extras/volume_id/lib/volume_id.c index fd95e7d3b0..bcdbe2feaa 100644 --- a/extras/volume_id/lib/volume_id.c +++ b/extras/volume_id/lib/volume_id.c @@ -171,6 +171,12 @@ int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size if (volume_id_probe_netware(id, off) == 0) goto found; + if (volume_id_probe_gfs(id, off) == 0) + goto found; + + if (volume_id_probe_gfs2(id, off) == 0) + goto found; + return -1; found: |