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 
swap_set_info(blkid_probe pr,const char * version)39 static int swap_set_info(blkid_probe pr, const char *version)
40 {
41 	struct swap_header_v1_2 *hdr;
42 
43 	/* Swap header always located at offset of 1024 bytes */
44 	hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
45 				sizeof(struct swap_header_v1_2));
46 	if (!hdr)
47 		return errno ? -errno : 1;
48 
49 	/* SWAPSPACE2 - check for wrong version or zeroed pagecount */
50 	if (strcmp(version, "1") == 0) {
51 		if (hdr->version != 1 && swab32(hdr->version) != 1) {
52 			DBG(LOWPROBE, ul_debug("incorrect swap version"));
53 			return 1;
54 		}
55 		if (hdr->lastpage == 0) {
56 			DBG(LOWPROBE, ul_debug("not set last swap page"));
57 			return 1;
58 		}
59 	}
60 
61 	/* arbitrary sanity check.. is there any garbage down there? */
62 	if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
63 		if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
64 				sizeof(hdr->volume)) < 0)
65 			return 1;
66 		if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
67 			return 1;
68 	}
69 
70 	blkid_probe_set_version(pr, version);
71 	return 0;
72 }
73 
probe_swap(blkid_probe pr,const struct blkid_idmag * mag)74 static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag)
75 {
76 	unsigned char *buf;
77 
78 	if (!mag)
79 		return 1;
80 
81 	/* TuxOnIce keeps valid swap header at the end of the 1st page */
82 	buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
83 	if (!buf)
84 		return errno ? -errno : 1;
85 
86 	if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
87 		return 1;	/* Ignore swap signature, it's TuxOnIce */
88 
89 	if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) {
90 		/* swap v0 doesn't support LABEL or UUID */
91 		blkid_probe_set_version(pr, "0");
92 		return 0;
93 
94 	} else if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
95 		return swap_set_info(pr, "1");
96 
97 	return 1;
98 }
99 
probe_swsuspend(blkid_probe pr,const struct blkid_idmag * mag)100 static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
101 {
102 	if (!mag)
103 		return 1;
104 	if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
105 		return swap_set_info(pr, "s1suspend");
106 	if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
107 		return swap_set_info(pr, "s2suspend");
108 	if (!memcmp(mag->magic, "ULSUSPEND", mag->len))
109 		return swap_set_info(pr, "ulsuspend");
110 	if (!memcmp(mag->magic, TOI_MAGIC_STRING, mag->len))
111 		return swap_set_info(pr, "tuxonice");
112 	if (!memcmp(mag->magic, "LINHIB0001", mag->len))
113 		return swap_set_info(pr, "linhib0001");
114 
115 	return 1;	/* no signature detected */
116 }
117 
118 const struct blkid_idinfo swap_idinfo =
119 {
120 	.name		= "swap",
121 	.usage		= BLKID_USAGE_OTHER,
122 	.probefunc	= probe_swap,
123 	.minsz		= 10 * 4096,	/* 10 pages */
124 	.magics		=
125 	{
126 		{ "SWAP-SPACE", 10, 0,  0xff6 },
127 		{ "SWAPSPACE2", 10, 0,  0xff6 },
128 		{ "SWAP-SPACE", 10, 0, 0x1ff6 },
129 		{ "SWAPSPACE2", 10, 0, 0x1ff6 },
130 		{ "SWAP-SPACE", 10, 0, 0x3ff6 },
131 		{ "SWAPSPACE2", 10, 0, 0x3ff6 },
132 		{ "SWAP-SPACE", 10, 0, 0x7ff6 },
133 		{ "SWAPSPACE2", 10, 0, 0x7ff6 },
134 		{ "SWAP-SPACE", 10, 0, 0xfff6 },
135 		{ "SWAPSPACE2", 10, 0, 0xfff6 },
136 		{ NULL }
137 	}
138 };
139 
140 
141 const struct blkid_idinfo swsuspend_idinfo =
142 {
143 	.name		= "swsuspend",
144 	.usage		= BLKID_USAGE_OTHER,
145 	.probefunc	= probe_swsuspend,
146 	.minsz		= 10 * 4096,	/* 10 pages */
147 	.magics		=
148 	{
149 		{ TOI_MAGIC_STRING, TOI_MAGIC_STRLEN, 0, 0 },
150 		{ "S1SUSPEND", 9, 0, 0xff6 },
151 		{ "S2SUSPEND", 9, 0, 0xff6 },
152 		{ "ULSUSPEND", 9, 0, 0xff6 },
153 		{ "LINHIB0001",10,0, 0xff6 },
154 
155 		{ "S1SUSPEND", 9, 0, 0x1ff6 },
156 		{ "S2SUSPEND", 9, 0, 0x1ff6 },
157 		{ "ULSUSPEND", 9, 0, 0x1ff6 },
158 		{ "LINHIB0001",10,0, 0x1ff6 },
159 
160 		{ "S1SUSPEND", 9, 0, 0x3ff6 },
161 		{ "S2SUSPEND", 9, 0, 0x3ff6 },
162 		{ "ULSUSPEND", 9, 0, 0x3ff6 },
163 		{ "LINHIB0001",10,0, 0x3ff6 },
164 
165 		{ "S1SUSPEND", 9, 0, 0x7ff6 },
166 		{ "S2SUSPEND", 9, 0, 0x7ff6 },
167 		{ "ULSUSPEND", 9, 0, 0x7ff6 },
168 		{ "LINHIB0001",10,0, 0x7ff6 },
169 
170 		{ "S1SUSPEND", 9, 0, 0xfff6 },
171 		{ "S2SUSPEND", 9, 0, 0xfff6 },
172 		{ "ULSUSPEND", 9, 0, 0xfff6 },
173 		{ "LINHIB0001",10,0, 0xfff6 },
174 
175 		{ NULL }
176 	}
177 };
178 
179