1/*
2 * volume_id - reads filesystem label and uuid
3 *
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 *	This program is free software; you can redistribute it and/or modify it
7 *	under the terms of the GNU General Public License as published by the
8 *	Free Software Foundation version 2 of the License.
9 */
10
11#ifndef _GNU_SOURCE
12#define _GNU_SOURCE 1
13#endif
14
15#ifdef HAVE_CONFIG_H
16#  include <config.h>
17#endif
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23#include <errno.h>
24#include <ctype.h>
25
26#include "libvolume_id.h"
27#include "util.h"
28
29struct swap_header_v1_2 {
30	uint8_t		bootbits[1024];
31	uint32_t	version;
32	uint32_t	last_page;
33	uint32_t	nr_badpages;
34	uint8_t		uuid[16];
35	uint8_t		volume_name[16];
36} PACKED;
37
38#define LARGEST_PAGESIZE			0x4000
39
40int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size)
41{
42	const uint8_t *buf;
43	unsigned int page;
44	struct swap_header_v1_2 *sw;
45
46	info("probing at offset 0x%llx", (unsigned long long) off);
47
48	/* eek, the swap signature is at the end of the PAGE_SIZE */
49	for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
50			buf = volume_id_get_buffer(id, off + page-10, 10);
51			if (buf == NULL)
52				return -1;
53
54			if (memcmp(buf, "SWAP-SPACE", 10) == 0) {
55				strcpy(id->type_version, "1");
56				goto found;
57			}
58
59			if (memcmp(buf, "SWAPSPACE2", 10) == 0) {
60				id->type = "swap";
61				strcpy(id->type_version, "2");
62				goto found_label;
63			}
64
65			if (memcmp(buf, "S1SUSPEND", 9) == 0) {
66				id->type = "suspend";
67				strcpy(id->type_version, "s1suspend");
68				goto found_label;
69			}
70
71			if (memcmp(buf, "ULSUSPEND", 9) == 0) {
72				id->type = "suspend";
73				strcpy(id->type_version, "ulsuspend");
74				goto found_label;
75			}
76	}
77	return -1;
78
79found_label:
80	sw = (struct swap_header_v1_2 *) volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
81	if (sw != NULL) {
82		volume_id_set_label_raw(id, sw->volume_name, 16);
83		volume_id_set_label_string(id, sw->volume_name, 16);
84		volume_id_set_uuid(id, sw->uuid, 0, UUID_DCE);
85	}
86
87found:
88	volume_id_set_usage(id, VOLUME_ID_OTHER);
89	return 0;
90}
91