/src/util-linux/libblkid/src/superblocks/swap.c
Line | Count | Source (jump to first uncovered line) |
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 | 1.10k | #define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c" |
37 | 686 | #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 | 7 | { |
43 | 7 | enum blkid_endianness endianness = le32_to_cpu(hdr->version) == 1 ? |
44 | 4 | BLKID_ENDIANNESS_LITTLE : BLKID_ENDIANNESS_BIG; |
45 | 7 | blkid_probe_set_fsendianness(pr, endianness); |
46 | | |
47 | 7 | uint32_t pagesize = mag->sboff + mag->len; |
48 | 7 | blkid_probe_set_fsblocksize(pr, pagesize); |
49 | | |
50 | 7 | uint32_t lastpage = endianness == BLKID_ENDIANNESS_LITTLE ? |
51 | 4 | le32_to_cpu(hdr->lastpage) : be32_to_cpu(hdr->lastpage); |
52 | 7 | blkid_probe_set_fssize(pr, (uint64_t) pagesize * lastpage); |
53 | 7 | } |
54 | | |
55 | | static int swap_set_info(blkid_probe pr, const struct blkid_idmag *mag, |
56 | | const char *version) |
57 | 596 | { |
58 | 596 | struct swap_header_v1_2 *hdr; |
59 | | |
60 | | /* Swap header always located at offset of 1024 bytes */ |
61 | 596 | hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024, |
62 | 596 | sizeof(struct swap_header_v1_2)); |
63 | 596 | if (!hdr) |
64 | 0 | return errno ? -errno : 1; |
65 | | |
66 | | /* SWAPSPACE2 - check for wrong version or zeroed pagecount */ |
67 | 596 | if (strcmp(version, "1") == 0) { |
68 | 263 | if (hdr->version != 1 && swab32(hdr->version) != 1) { |
69 | 248 | DBG(LOWPROBE, ul_debug("incorrect swap version")); |
70 | 248 | return 1; |
71 | 248 | } |
72 | 15 | if (hdr->lastpage == 0) { |
73 | 8 | DBG(LOWPROBE, ul_debug("not set last swap page")); |
74 | 8 | return 1; |
75 | 8 | } |
76 | 7 | swap_set_info_swap1(pr, mag, hdr); |
77 | 7 | } |
78 | | |
79 | | /* arbitrary sanity check.. is there any garbage down there? */ |
80 | 340 | if (hdr->padding[32] == 0 && hdr->padding[33] == 0) { |
81 | 105 | if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume, |
82 | 50 | sizeof(hdr->volume)) < 0) |
83 | 0 | return 1; |
84 | 105 | if (blkid_probe_set_uuid(pr, hdr->uuid) < 0) |
85 | 0 | return 1; |
86 | 105 | } |
87 | | |
88 | 340 | blkid_probe_set_version(pr, version); |
89 | 340 | return 0; |
90 | 340 | } |
91 | | |
92 | | static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag) |
93 | 269 | { |
94 | 269 | const unsigned char *buf; |
95 | | |
96 | 269 | if (!mag) |
97 | 0 | return 1; |
98 | | |
99 | | /* TuxOnIce keeps valid swap header at the end of the 1st page */ |
100 | 269 | buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN); |
101 | 269 | if (!buf) |
102 | 0 | return errno ? -errno : 1; |
103 | | |
104 | 269 | if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0) |
105 | 4 | return 1; /* Ignore swap signature, it's TuxOnIce */ |
106 | | |
107 | 265 | if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) { |
108 | | /* swap v0 doesn't support LABEL or UUID */ |
109 | 2 | blkid_probe_set_version(pr, "0"); |
110 | 2 | return 0; |
111 | | |
112 | 2 | } |
113 | | |
114 | 263 | if (!memcmp(mag->magic, "SWAPSPACE2", mag->len)) |
115 | 263 | return swap_set_info(pr, mag, "1"); |
116 | | |
117 | 0 | return 1; |
118 | 263 | } |
119 | | |
120 | | static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag) |
121 | 333 | { |
122 | 333 | if (!mag) |
123 | 0 | return 1; |
124 | 333 | if (!memcmp(mag->magic, "S1SUSPEND", mag->len)) |
125 | 23 | return swap_set_info(pr, mag, "s1suspend"); |
126 | 310 | if (!memcmp(mag->magic, "S2SUSPEND", mag->len)) |
127 | 48 | return swap_set_info(pr, mag, "s2suspend"); |
128 | 262 | if (!memcmp(mag->magic, "ULSUSPEND", mag->len)) |
129 | 114 | return swap_set_info(pr, mag, "ulsuspend"); |
130 | 148 | if (!memcmp(mag->magic, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN)) |
131 | 49 | return swap_set_info(pr, mag, "tuxonice"); |
132 | 99 | if (!memcmp(mag->magic, "LINHIB0001", mag->len)) |
133 | 99 | return swap_set_info(pr, mag, "linhib0001"); |
134 | | |
135 | 0 | return 1; /* no signature detected */ |
136 | 99 | } |
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 | | }; |