xref: /freebsd/sys/geom/label/g_label_swaplinux.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  */
4 
5 #include <sys/param.h>
6 #include <sys/systm.h>
7 #include <sys/kernel.h>
8 #include <sys/malloc.h>
9 
10 #include <geom/geom.h>
11 #include <geom/geom_dbg.h>
12 #include <geom/label/g_label.h>
13 
14 /*
15  * Taken from
16  * https://github.com/util-linux/util-linux/blob/master/include/swapheader.h
17  */
18 
19 #define SWAP_VERSION 1
20 #define SWAP_UUID_LENGTH 16
21 #define SWAP_LABEL_LENGTH 16
22 #define SWAP_SIGNATURE "SWAPSPACE2"
23 #define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1)
24 
25 struct swap_header_v1_2 {
26 	char	      bootbits[1024];    /* Space for disklabel etc. */
27 	uint32_t      version;
28 	uint32_t      last_page;
29 	uint32_t      nr_badpages;
30 	unsigned char uuid[SWAP_UUID_LENGTH];
31 	char	      volume_name[SWAP_LABEL_LENGTH];
32 	uint32_t      padding[117];
33 	uint32_t      badpages[1];
34 };
35 
36 typedef union {
37 	struct swap_header_v1_2	header;
38 	struct {
39 		uint8_t reserved[PAGE_SIZE - SWAP_SIGNATURE_SZ];
40 		char	signature[SWAP_SIGNATURE_SZ];
41 	} tail;
42 } swhdr_t;
43 
44 #define sw_version	header.version
45 #define sw_volume_name	header.volume_name
46 #define sw_signature	tail.signature
47 
48 static void
49 g_label_swaplinux_taste(struct g_consumer *cp, char *label, size_t size)
50 {
51 	struct g_provider *pp;
52 	swhdr_t *hdr;
53 
54 	g_topology_assert_not();
55 	pp = cp->provider;
56 	label[0] = '\0';
57 
58 	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize"));
59 	if ((PAGE_SIZE % pp->sectorsize) != 0)
60 		return;
61 
62 	hdr = (swhdr_t *)g_read_data(cp, 0, PAGE_SIZE, NULL);
63 	if (hdr == NULL)
64 		return;
65 
66 	/* Check version and magic string */
67 	if (hdr->sw_version == SWAP_VERSION &&
68 	    !memcmp(hdr->sw_signature, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ))
69 		G_LABEL_DEBUG(1, "linux swap detected on %s.", pp->name);
70 	else
71 		goto exit_free;
72 
73 	/* Check for volume label */
74 	if (hdr->sw_volume_name[0] == '\0')
75 		goto exit_free;
76 
77 	/* Terminate label */
78 	hdr->sw_volume_name[sizeof(hdr->sw_volume_name) - 1] = '\0';
79 	strlcpy(label, hdr->sw_volume_name, size);
80 
81 exit_free:
82 	g_free(hdr);
83 }
84 
85 struct g_label_desc g_label_swaplinux = {
86 	.ld_taste = g_label_swaplinux_taste,
87 	.ld_dirprefix = "swaplinux/",
88 	.ld_enabled = 1
89 };
90 
91 G_LABEL_INIT(swaplinux, g_label_swaplinux, "Create device nodes for Linux swap");
92