1 /*
2 * Copyright (C) 1999 by Andries Brouwer
3 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4 * Copyright (C) 2001 by Andreas Dilger
5 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
7 *
8 * This file may be redistributed under the terms of the
9 * GNU Lesser General Public License.
10 */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <ctype.h>
17 #include <stdint.h>
18
19 #include "superblocks.h"
20
21 /* linux-2.6/include/linux/swap.h */
22 struct swap_header_v1_2 {
23 /* char bootbits[1024]; */ /* Space for disklabel etc. */
24 uint32_t version;
25 uint32_t lastpage;
26 uint32_t nr_badpages;
27 unsigned char uuid[16];
28 unsigned char volume[16];
29 uint32_t padding[117];
30 uint32_t badpages[1];
31 } __attribute__((packed));
32
33 #define PAGESIZE_MIN 0xff6 /* 4086 (arm, i386, ...) */
34 #define PAGESIZE_MAX 0xfff6 /* 65526 (ia64) */
35
36 #define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c"
37 #define TOI_MAGIC_STRLEN (sizeof(TOI_MAGIC_STRING) - 1)
38
39 static void swap_set_info_swap1(blkid_probe pr,
40 const struct blkid_idmag *mag,
41 const struct swap_header_v1_2 *hdr)
42 {
43 enum BLKID_ENDIANNESS endianness = le32_to_cpu(hdr->version) == 1 ?
44 BLKID_ENDIANNESS_LITTLE : BLKID_ENDIANNESS_BIG;
45 blkid_probe_set_fsendianness(pr, endianness);
46
47 uint32_t pagesize = mag->sboff + mag->len;
48 blkid_probe_set_fsblocksize(pr, pagesize);
49
50 uint32_t lastpage = endianness == BLKID_ENDIANNESS_LITTLE ?
51 le32_to_cpu(hdr->lastpage) : be32_to_cpu(hdr->lastpage);
52 blkid_probe_set_fssize(pr, (uint64_t) pagesize * lastpage);
53 }
54
55 static int swap_set_info(blkid_probe pr, const struct blkid_idmag *mag,
56 const char *version)
57 {
58 struct swap_header_v1_2 *hdr;
59
60 /* Swap header always located at offset of 1024 bytes */
61 hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
62 sizeof(struct swap_header_v1_2));
63 if (!hdr)
64 return errno ? -errno : 1;
65
66 /* SWAPSPACE2 - check for wrong version or zeroed pagecount */
67 if (strcmp(version, "1") == 0) {
68 if (hdr->version != 1 && swab32(hdr->version) != 1) {
69 DBG(LOWPROBE, ul_debug("incorrect swap version"));
70 return 1;
71 }
72 if (hdr->lastpage == 0) {
73 DBG(LOWPROBE, ul_debug("not set last swap page"));
74 return 1;
75 }
76 swap_set_info_swap1(pr, mag, hdr);
77 }
78
79 /* arbitrary sanity check.. is there any garbage down there? */
80 if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
81 if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
82 sizeof(hdr->volume)) < 0)
83 return 1;
84 if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
85 return 1;
86 }
87
88 blkid_probe_set_version(pr, version);
89 return 0;
90 }
91
92 static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag)
93 {
94 unsigned char *buf;
95
96 if (!mag)
97 return 1;
98
99 /* TuxOnIce keeps valid swap header at the end of the 1st page */
100 buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
101 if (!buf)
102 return errno ? -errno : 1;
103
104 if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
105 return 1; /* Ignore swap signature, it's TuxOnIce */
106
107 if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) {
108 /* swap v0 doesn't support LABEL or UUID */
109 blkid_probe_set_version(pr, "0");
110 return 0;
111
112 }
113
114 if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
115 return swap_set_info(pr, mag, "1");
116
117 return 1;
118 }
119
120 static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
121 {
122 if (!mag)
123 return 1;
124 if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
125 return swap_set_info(pr, mag, "s1suspend");
126 if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
127 return swap_set_info(pr, mag, "s2suspend");
128 if (!memcmp(mag->magic, "ULSUSPEND", mag->len))
129 return swap_set_info(pr, mag, "ulsuspend");
130 if (!memcmp(mag->magic, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN))
131 return swap_set_info(pr, mag, "tuxonice");
132 if (!memcmp(mag->magic, "LINHIB0001", mag->len))
133 return swap_set_info(pr, mag, "linhib0001");
134
135 return 1; /* no signature detected */
136 }
137
138 const struct blkid_idinfo swap_idinfo =
139 {
140 .name = "swap",
141 .usage = BLKID_USAGE_OTHER,
142 .probefunc = probe_swap,
143 .minsz = 10 * 4096, /* 10 pages */
144 .magics =
145 {
146 { .magic = "SWAP-SPACE", .len = 10, .sboff = 0xff6 },
147 { .magic = "SWAPSPACE2", .len = 10, .sboff = 0xff6 },
148 { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x1ff6 },
149 { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x1ff6 },
150 { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x3ff6 },
151 { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x3ff6 },
152 { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x7ff6 },
153 { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x7ff6 },
154 { .magic = "SWAP-SPACE", .len = 10, .sboff = 0xfff6 },
155 { .magic = "SWAPSPACE2", .len = 10, .sboff = 0xfff6 },
156 { NULL }
157 }
158 };
159
160
161 const struct blkid_idinfo swsuspend_idinfo =
162 {
163 .name = "swsuspend",
164 .usage = BLKID_USAGE_OTHER,
165 .probefunc = probe_swsuspend,
166 .minsz = 10 * 4096, /* 10 pages */
167 .magics =
168 {
169 { .magic = TOI_MAGIC_STRING, .len = TOI_MAGIC_STRLEN },
170 { .magic = "S1SUSPEND", .len = 9, .sboff = 0xff6 },
171 { .magic = "S2SUSPEND", .len = 9, .sboff = 0xff6 },
172 { .magic = "ULSUSPEND", .len = 9, .sboff = 0xff6 },
173 { .magic = "LINHIB0001", .len = 10, .sboff = 0xff6 },
174
175 { .magic = "S1SUSPEND", .len = 9, .sboff = 0x1ff6 },
176 { .magic = "S2SUSPEND", .len = 9, .sboff = 0x1ff6 },
177 { .magic = "ULSUSPEND", .len = 9, .sboff = 0x1ff6 },
178 { .magic = "LINHIB0001", .len = 10, .sboff = 0x1ff6 },
179
180 { .magic = "S1SUSPEND", .len = 9, .sboff = 0x3ff6 },
181 { .magic = "S2SUSPEND", .len = 9, .sboff = 0x3ff6 },
182 { .magic = "ULSUSPEND", .len = 9, .sboff = 0x3ff6 },
183 { .magic = "LINHIB0001", .len = 10, .sboff = 0x3ff6 },
184
185 { .magic = "S1SUSPEND", .len = 9, .sboff = 0x7ff6 },
186 { .magic = "S2SUSPEND", .len = 9, .sboff = 0x7ff6 },
187 { .magic = "ULSUSPEND", .len = 9, .sboff = 0x7ff6 },
188 { .magic = "LINHIB0001", .len = 10, .sboff = 0x7ff6 },
189
190 { .magic = "S1SUSPEND", .len = 9, .sboff = 0xfff6 },
191 { .magic = "S2SUSPEND", .len = 9, .sboff = 0xfff6 },
192 { .magic = "ULSUSPEND", .len = 9, .sboff = 0xfff6 },
193 { .magic = "LINHIB0001", .len = 10, .sboff = 0xfff6 },
194 { NULL }
195 }
196 };