diff options
Diffstat (limited to 'sys/geom/label/g_label_swaplinux.c')
| -rw-r--r-- | sys/geom/label/g_label_swaplinux.c | 91 | 
1 files changed, 91 insertions, 0 deletions
| diff --git a/sys/geom/label/g_label_swaplinux.c b/sys/geom/label/g_label_swaplinux.c new file mode 100644 index 000000000000..5994ad93fd6f --- /dev/null +++ b/sys/geom/label/g_label_swaplinux.c @@ -0,0 +1,91 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/label/g_label.h> + +/* + * Taken from + * https://github.com/util-linux/util-linux/blob/master/include/swapheader.h + */ + +#define SWAP_VERSION 1 +#define SWAP_UUID_LENGTH 16 +#define SWAP_LABEL_LENGTH 16 +#define SWAP_SIGNATURE "SWAPSPACE2" +#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1) + +struct swap_header_v1_2 { +	char	      bootbits[1024];    /* Space for disklabel etc. */ +	uint32_t      version; +	uint32_t      last_page; +	uint32_t      nr_badpages; +	unsigned char uuid[SWAP_UUID_LENGTH]; +	char	      volume_name[SWAP_LABEL_LENGTH]; +	uint32_t      padding[117]; +	uint32_t      badpages[1]; +}; + +typedef union { +	struct swap_header_v1_2	header; +	struct { +		uint8_t reserved[PAGE_SIZE - SWAP_SIGNATURE_SZ]; +		char	signature[SWAP_SIGNATURE_SZ]; +	} tail; +} swhdr_t; + +#define sw_version	header.version +#define sw_volume_name	header.volume_name +#define sw_signature	tail.signature + +static void +g_label_swaplinux_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	swhdr_t *hdr; + +	g_topology_assert_not(); +	pp = cp->provider; +	label[0] = '\0'; + +	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize")); +	if ((PAGE_SIZE % pp->sectorsize) != 0) +		return; + +	hdr = (swhdr_t *)g_read_data(cp, 0, PAGE_SIZE, NULL); +	if (hdr == NULL) +		return; + +	/* Check version and magic string */ +	if (hdr->sw_version == SWAP_VERSION && +	    !memcmp(hdr->sw_signature, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ)) +		G_LABEL_DEBUG(1, "linux swap detected on %s.", pp->name); +	else +		goto exit_free; + +	/* Check for volume label */ +	if (hdr->sw_volume_name[0] == '\0') +		goto exit_free; + +	/* Terminate label */ +	hdr->sw_volume_name[sizeof(hdr->sw_volume_name) - 1] = '\0'; +	strlcpy(label, hdr->sw_volume_name, size); + +exit_free: +	g_free(hdr); +} + +struct g_label_desc g_label_swaplinux = { +	.ld_taste = g_label_swaplinux_taste, +	.ld_dirprefix = "swaplinux/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(swaplinux, g_label_swaplinux, "Create device nodes for Linux swap"); | 
