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
g_label_swaplinux_taste(struct g_consumer * cp,char * label,size_t size)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