/src/util-linux/libblkid/src/superblocks/swap.c
Line | Count | Source |
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 | 861 | #define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c" |
37 | 539 | #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 | 14 | { |
43 | 14 | enum blkid_endianness endianness = le32_to_cpu(hdr->version) == 1 ? |
44 | 10 | BLKID_ENDIANNESS_LITTLE : BLKID_ENDIANNESS_BIG; |
45 | 14 | blkid_probe_set_fsendianness(pr, endianness); |
46 | | |
47 | 14 | uint32_t pagesize = mag->sboff + mag->len; |
48 | 14 | blkid_probe_set_fsblocksize(pr, pagesize); |
49 | | |
50 | | /* note that "lastpage" in swap header means number of pages used by |
51 | | * swap, see mkswap */ |
52 | 14 | uint32_t lastpage = endianness == BLKID_ENDIANNESS_LITTLE ? |
53 | 10 | le32_to_cpu(hdr->lastpage) : be32_to_cpu(hdr->lastpage); |
54 | 14 | blkid_probe_set_fssize(pr, (uint64_t) pagesize * lastpage); |
55 | 14 | blkid_probe_set_fslastblock(pr, lastpage + 1); |
56 | 14 | } |
57 | | |
58 | | static int swap_set_info(blkid_probe pr, const struct blkid_idmag *mag, |
59 | | const char *version) |
60 | 416 | { |
61 | 416 | struct swap_header_v1_2 *hdr; |
62 | | |
63 | | /* Swap header always located at offset of 1024 bytes */ |
64 | 416 | hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024, |
65 | 416 | sizeof(struct swap_header_v1_2)); |
66 | 416 | if (!hdr) |
67 | 0 | return errno ? -errno : 1; |
68 | | |
69 | | /* SWAPSPACE2 - check for wrong version or zeroed pagecount */ |
70 | 416 | if (strcmp(version, "1") == 0) { |
71 | 203 | if (hdr->version != 1 && swab32(hdr->version) != 1) { |
72 | 182 | DBG(LOWPROBE, ul_debug("incorrect swap version")); |
73 | 182 | return 1; |
74 | 182 | } |
75 | 21 | if (hdr->lastpage == 0) { |
76 | 7 | DBG(LOWPROBE, ul_debug("not set last swap page")); |
77 | 7 | return 1; |
78 | 7 | } |
79 | 14 | swap_set_info_swap1(pr, mag, hdr); |
80 | 14 | } |
81 | | |
82 | | /* arbitrary sanity check.. is there any garbage down there? */ |
83 | 227 | if (hdr->padding[32] == 0 && hdr->padding[33] == 0) { |
84 | 62 | if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume, |
85 | 34 | sizeof(hdr->volume)) < 0) |
86 | 0 | return 1; |
87 | 62 | if (blkid_probe_set_uuid(pr, hdr->uuid) < 0) |
88 | 0 | return 1; |
89 | 62 | } |
90 | | |
91 | 227 | blkid_probe_set_version(pr, version); |
92 | 227 | return 0; |
93 | 227 | } |
94 | | |
95 | | static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag) |
96 | 217 | { |
97 | 217 | const unsigned char *buf; |
98 | | |
99 | 217 | if (!mag) |
100 | 0 | return 1; |
101 | | |
102 | | /* TuxOnIce keeps valid swap header at the end of the 1st page */ |
103 | 217 | buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN); |
104 | 217 | if (!buf) |
105 | 0 | return errno ? -errno : 1; |
106 | | |
107 | 217 | if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0) |
108 | 3 | return 1; /* Ignore swap signature, it's TuxOnIce */ |
109 | | |
110 | 214 | if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) { |
111 | | /* swap v0 doesn't support LABEL or UUID */ |
112 | 11 | blkid_probe_set_version(pr, "0"); |
113 | 11 | return 0; |
114 | | |
115 | 11 | } |
116 | | |
117 | 203 | if (!memcmp(mag->magic, "SWAPSPACE2", mag->len)) |
118 | 203 | return swap_set_info(pr, mag, "1"); |
119 | | |
120 | 0 | return 1; |
121 | 203 | } |
122 | | |
123 | | static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag) |
124 | 213 | { |
125 | 213 | if (!mag) |
126 | 0 | return 1; |
127 | 213 | if (!memcmp(mag->magic, "S1SUSPEND", mag->len)) |
128 | 23 | return swap_set_info(pr, mag, "s1suspend"); |
129 | 190 | if (!memcmp(mag->magic, "S2SUSPEND", mag->len)) |
130 | 45 | return swap_set_info(pr, mag, "s2suspend"); |
131 | 145 | if (!memcmp(mag->magic, "ULSUSPEND", mag->len)) |
132 | 40 | return swap_set_info(pr, mag, "ulsuspend"); |
133 | 105 | if (!memcmp(mag->magic, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN)) |
134 | 28 | return swap_set_info(pr, mag, "tuxonice"); |
135 | 77 | if (!memcmp(mag->magic, "LINHIB0001", mag->len)) |
136 | 77 | return swap_set_info(pr, mag, "linhib0001"); |
137 | | |
138 | 0 | return 1; /* no signature detected */ |
139 | 77 | } |
140 | | |
141 | | const struct blkid_idinfo swap_idinfo = |
142 | | { |
143 | | .name = "swap", |
144 | | .usage = BLKID_USAGE_OTHER, |
145 | | .probefunc = probe_swap, |
146 | | .minsz = 10 * 4096, /* 10 pages */ |
147 | | .magics = |
148 | | { |
149 | | { .magic = "SWAP-SPACE", .len = 10, .sboff = 0xff6 }, |
150 | | { .magic = "SWAPSPACE2", .len = 10, .sboff = 0xff6 }, |
151 | | { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x1ff6 }, |
152 | | { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x1ff6 }, |
153 | | { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x3ff6 }, |
154 | | { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x3ff6 }, |
155 | | { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x7ff6 }, |
156 | | { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x7ff6 }, |
157 | | { .magic = "SWAP-SPACE", .len = 10, .sboff = 0xfff6 }, |
158 | | { .magic = "SWAPSPACE2", .len = 10, .sboff = 0xfff6 }, |
159 | | { NULL } |
160 | | } |
161 | | }; |
162 | | |
163 | | |
164 | | const struct blkid_idinfo swsuspend_idinfo = |
165 | | { |
166 | | .name = "swsuspend", |
167 | | .usage = BLKID_USAGE_OTHER, |
168 | | .probefunc = probe_swsuspend, |
169 | | .minsz = 10 * 4096, /* 10 pages */ |
170 | | .magics = |
171 | | { |
172 | | { .magic = TOI_MAGIC_STRING, .len = TOI_MAGIC_STRLEN }, |
173 | | { .magic = "S1SUSPEND", .len = 9, .sboff = 0xff6 }, |
174 | | { .magic = "S2SUSPEND", .len = 9, .sboff = 0xff6 }, |
175 | | { .magic = "ULSUSPEND", .len = 9, .sboff = 0xff6 }, |
176 | | { .magic = "LINHIB0001", .len = 10, .sboff = 0xff6 }, |
177 | | |
178 | | { .magic = "S1SUSPEND", .len = 9, .sboff = 0x1ff6 }, |
179 | | { .magic = "S2SUSPEND", .len = 9, .sboff = 0x1ff6 }, |
180 | | { .magic = "ULSUSPEND", .len = 9, .sboff = 0x1ff6 }, |
181 | | { .magic = "LINHIB0001", .len = 10, .sboff = 0x1ff6 }, |
182 | | |
183 | | { .magic = "S1SUSPEND", .len = 9, .sboff = 0x3ff6 }, |
184 | | { .magic = "S2SUSPEND", .len = 9, .sboff = 0x3ff6 }, |
185 | | { .magic = "ULSUSPEND", .len = 9, .sboff = 0x3ff6 }, |
186 | | { .magic = "LINHIB0001", .len = 10, .sboff = 0x3ff6 }, |
187 | | |
188 | | { .magic = "S1SUSPEND", .len = 9, .sboff = 0x7ff6 }, |
189 | | { .magic = "S2SUSPEND", .len = 9, .sboff = 0x7ff6 }, |
190 | | { .magic = "ULSUSPEND", .len = 9, .sboff = 0x7ff6 }, |
191 | | { .magic = "LINHIB0001", .len = 10, .sboff = 0x7ff6 }, |
192 | | |
193 | | { .magic = "S1SUSPEND", .len = 9, .sboff = 0xfff6 }, |
194 | | { .magic = "S2SUSPEND", .len = 9, .sboff = 0xfff6 }, |
195 | | { .magic = "ULSUSPEND", .len = 9, .sboff = 0xfff6 }, |
196 | | { .magic = "LINHIB0001", .len = 10, .sboff = 0xfff6 }, |
197 | | { NULL } |
198 | | } |
199 | | }; |