summaryrefslogtreecommitdiffstats
path: root/libblkid/src/superblocks/swap.c
diff options
context:
space:
mode:
Diffstat (limited to 'libblkid/src/superblocks/swap.c')
-rw-r--r--libblkid/src/superblocks/swap.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/libblkid/src/superblocks/swap.c b/libblkid/src/superblocks/swap.c
new file mode 100644
index 0000000..fcdb13b
--- /dev/null
+++ b/libblkid/src/superblocks/swap.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 1999 by Andries Brouwer
+ * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
+ * Copyright (C) 2001 by Andreas Dilger
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdint.h>
+
+#include "superblocks.h"
+
+/* linux-2.6/include/linux/swap.h */
+struct swap_header_v1_2 {
+ /* char bootbits[1024]; */ /* Space for disklabel etc. */
+ uint32_t version;
+ uint32_t lastpage;
+ uint32_t nr_badpages;
+ unsigned char uuid[16];
+ unsigned char volume[16];
+ uint32_t padding[117];
+ uint32_t badpages[1];
+} __attribute__((packed));
+
+#define PAGESIZE_MIN 0xff6 /* 4086 (arm, i386, ...) */
+#define PAGESIZE_MAX 0xfff6 /* 65526 (ia64) */
+
+#define TOI_MAGIC_STRING "\xed\xc3\x02\xe9\x98\x56\xe5\x0c"
+#define TOI_MAGIC_STRLEN (sizeof(TOI_MAGIC_STRING) - 1)
+
+static int swap_set_info(blkid_probe pr, const char *version)
+{
+ struct swap_header_v1_2 *hdr;
+
+ /* Swap header always located at offset of 1024 bytes */
+ hdr = (struct swap_header_v1_2 *) blkid_probe_get_buffer(pr, 1024,
+ sizeof(struct swap_header_v1_2));
+ if (!hdr)
+ return errno ? -errno : 1;
+
+ /* SWAPSPACE2 - check for wrong version or zeroed pagecount */
+ if (strcmp(version, "1") == 0) {
+ if (hdr->version != 1 && swab32(hdr->version) != 1) {
+ DBG(LOWPROBE, ul_debug("incorrect swap version"));
+ return 1;
+ }
+ if (hdr->lastpage == 0) {
+ DBG(LOWPROBE, ul_debug("not set last swap page"));
+ return 1;
+ }
+ }
+
+ /* arbitrary sanity check.. is there any garbage down there? */
+ if (hdr->padding[32] == 0 && hdr->padding[33] == 0) {
+ if (hdr->volume[0] && blkid_probe_set_label(pr, hdr->volume,
+ sizeof(hdr->volume)) < 0)
+ return 1;
+ if (blkid_probe_set_uuid(pr, hdr->uuid) < 0)
+ return 1;
+ }
+
+ blkid_probe_set_version(pr, version);
+ return 0;
+}
+
+static int probe_swap(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ unsigned char *buf;
+
+ if (!mag)
+ return 1;
+
+ /* TuxOnIce keeps valid swap header at the end of the 1st page */
+ buf = blkid_probe_get_buffer(pr, 0, TOI_MAGIC_STRLEN);
+ if (!buf)
+ return errno ? -errno : 1;
+
+ if (memcmp(buf, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN) == 0)
+ return 1; /* Ignore swap signature, it's TuxOnIce */
+
+ if (!memcmp(mag->magic, "SWAP-SPACE", mag->len)) {
+ /* swap v0 doesn't support LABEL or UUID */
+ blkid_probe_set_version(pr, "0");
+ return 0;
+
+ }
+
+ if (!memcmp(mag->magic, "SWAPSPACE2", mag->len))
+ return swap_set_info(pr, "1");
+
+ return 1;
+}
+
+static int probe_swsuspend(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ if (!mag)
+ return 1;
+ if (!memcmp(mag->magic, "S1SUSPEND", mag->len))
+ return swap_set_info(pr, "s1suspend");
+ if (!memcmp(mag->magic, "S2SUSPEND", mag->len))
+ return swap_set_info(pr, "s2suspend");
+ if (!memcmp(mag->magic, "ULSUSPEND", mag->len))
+ return swap_set_info(pr, "ulsuspend");
+ if (!memcmp(mag->magic, TOI_MAGIC_STRING, TOI_MAGIC_STRLEN))
+ return swap_set_info(pr, "tuxonice");
+ if (!memcmp(mag->magic, "LINHIB0001", mag->len))
+ return swap_set_info(pr, "linhib0001");
+
+ return 1; /* no signature detected */
+}
+
+const struct blkid_idinfo swap_idinfo =
+{
+ .name = "swap",
+ .usage = BLKID_USAGE_OTHER,
+ .probefunc = probe_swap,
+ .minsz = 10 * 4096, /* 10 pages */
+ .magics =
+ {
+ { .magic = "SWAP-SPACE", .len = 10, .sboff = 0xff6 },
+ { .magic = "SWAPSPACE2", .len = 10, .sboff = 0xff6 },
+ { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x1ff6 },
+ { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x1ff6 },
+ { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x3ff6 },
+ { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x3ff6 },
+ { .magic = "SWAP-SPACE", .len = 10, .sboff = 0x7ff6 },
+ { .magic = "SWAPSPACE2", .len = 10, .sboff = 0x7ff6 },
+ { .magic = "SWAP-SPACE", .len = 10, .sboff = 0xfff6 },
+ { .magic = "SWAPSPACE2", .len = 10, .sboff = 0xfff6 },
+ { NULL }
+ }
+};
+
+
+const struct blkid_idinfo swsuspend_idinfo =
+{
+ .name = "swsuspend",
+ .usage = BLKID_USAGE_OTHER,
+ .probefunc = probe_swsuspend,
+ .minsz = 10 * 4096, /* 10 pages */
+ .magics =
+ {
+ { .magic = TOI_MAGIC_STRING, .len = TOI_MAGIC_STRLEN },
+ { .magic = "S1SUSPEND", .len = 9, .sboff = 0xff6 },
+ { .magic = "S2SUSPEND", .len = 9, .sboff = 0xff6 },
+ { .magic = "ULSUSPEND", .len = 9, .sboff = 0xff6 },
+ { .magic = "LINHIB0001", .len = 10, .sboff = 0xff6 },
+
+ { .magic = "S1SUSPEND", .len = 9, .sboff = 0x1ff6 },
+ { .magic = "S2SUSPEND", .len = 9, .sboff = 0x1ff6 },
+ { .magic = "ULSUSPEND", .len = 9, .sboff = 0x1ff6 },
+ { .magic = "LINHIB0001", .len = 10, .sboff = 0x1ff6 },
+
+ { .magic = "S1SUSPEND", .len = 9, .sboff = 0x3ff6 },
+ { .magic = "S2SUSPEND", .len = 9, .sboff = 0x3ff6 },
+ { .magic = "ULSUSPEND", .len = 9, .sboff = 0x3ff6 },
+ { .magic = "LINHIB0001", .len = 10, .sboff = 0x3ff6 },
+
+ { .magic = "S1SUSPEND", .len = 9, .sboff = 0x7ff6 },
+ { .magic = "S2SUSPEND", .len = 9, .sboff = 0x7ff6 },
+ { .magic = "ULSUSPEND", .len = 9, .sboff = 0x7ff6 },
+ { .magic = "LINHIB0001", .len = 10, .sboff = 0x7ff6 },
+
+ { .magic = "S1SUSPEND", .len = 9, .sboff = 0xfff6 },
+ { .magic = "S2SUSPEND", .len = 9, .sboff = 0xfff6 },
+ { .magic = "ULSUSPEND", .len = 9, .sboff = 0xfff6 },
+ { .magic = "LINHIB0001", .len = 10, .sboff = 0xfff6 },
+ { NULL }
+ }
+};