summaryrefslogtreecommitdiffstats
path: root/libblkid/src/partitions/solaris_x86.c
blob: df1def57adda76bcff0ca8045b36ddeec5e24fdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * Solaris x86 partition parsing code
 *
 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
 *
 * This file may be redistributed under the terms of the
 * GNU Lesser General Public License.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include "partitions.h"

/*
 * Solaris-x86 is always within primary dos partition (nested PT table).  The
 * solaris-x86 vtoc can be used to split the entire partition to "slices". The
 * offset (start) of the slice is always relatively to the primary dos
 * partition.
 *
 * Note that Solaris-SPARC uses entire disk with a different partitioning
 * scheme.
 */

/* some other implementation than Linux kernel assume 8 partitions only */
#define SOLARIS_MAXPARTITIONS	16

/* disklabel (vtoc) location  */
#define SOLARIS_SECTOR		1			/* in 512-sectors */
#define SOLARIS_OFFSET		(SOLARIS_SECTOR << 9)	/* in bytes */
#define SOLARIS_MAGICOFFSET	(SOLARIS_OFFSET + 12)	/* v_sanity offset in bytes */

/* slice tags */
#define SOLARIS_TAG_WHOLEDISK	5

struct solaris_slice {
	uint16_t s_tag;      /* ID tag of partition */
	uint16_t s_flag;     /* permission flags */
	uint32_t s_start;    /* start sector no of partition */
	uint32_t s_size;     /* # of blocks in partition */
} __attribute__((packed));

struct solaris_vtoc {
	unsigned int v_bootinfo[3];     /* info needed by mboot (unsupported) */

	uint32_t     v_sanity;          /* to verify vtoc sanity */
	uint32_t     v_version;         /* layout version */
	char         v_volume[8];       /* volume name */
	uint16_t     v_sectorsz;        /* sector size in bytes */
	uint16_t     v_nparts;          /* number of partitions */
	unsigned int v_reserved[10];    /* free space */

	struct solaris_slice v_slice[SOLARIS_MAXPARTITIONS]; /* slices */

	unsigned int timestamp[SOLARIS_MAXPARTITIONS]; /* timestamp (unsupported) */
	char         v_asciilabel[128];	/* for compatibility */
} __attribute__((packed));

static int probe_solaris_pt(blkid_probe pr,
		const struct blkid_idmag *mag __attribute__((__unused__)))
{
	struct solaris_vtoc *l;	/* disk label */
	struct solaris_slice *p;	/* partition */
	blkid_parttable tab = NULL;
	blkid_partition parent;
	blkid_partlist ls;
	int i;
	uint16_t nparts;

	l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR);
	if (!l) {
		if (errno)
			return -errno;
		goto nothing;
	}

	if (le32_to_cpu(l->v_version) != 1) {
		DBG(LOWPROBE, ul_debug(
			"WARNING: unsupported solaris x86 version %d, ignore",
			le32_to_cpu(l->v_version)));
		goto nothing;
	}

	if (blkid_partitions_need_typeonly(pr))
		/* caller does not ask for details about partitions */
		return BLKID_PROBE_OK;

	ls = blkid_probe_get_partlist(pr);
	if (!ls)
		goto nothing;

	parent = blkid_partlist_get_parent(ls);

	tab = blkid_partlist_new_parttable(ls, "solaris", SOLARIS_OFFSET);
	if (!tab)
		goto err;

	nparts = le16_to_cpu(l->v_nparts);
	if (nparts > SOLARIS_MAXPARTITIONS)
		nparts = SOLARIS_MAXPARTITIONS;

	for (i = 1, p = &l->v_slice[0];	i < nparts; i++, p++) {

		uint32_t start = le32_to_cpu(p->s_start);
		uint32_t size = le32_to_cpu(p->s_size);
		blkid_partition par;

		if (size == 0 || le16_to_cpu(p->s_tag) == SOLARIS_TAG_WHOLEDISK)
			continue;

		if (parent)
			/* Solaris slices are relative to the parent (primary
			 * DOS partition) */
			start += blkid_partition_get_start(parent);

		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
			DBG(LOWPROBE, ul_debug(
				"WARNING: solaris partition (%d) overflow "
				"detected, ignore", i));
			continue;
		}

		par = blkid_partlist_add_partition(ls, tab, start, size);
		if (!par)
			goto err;

		blkid_partition_set_type(par, le16_to_cpu(p->s_tag));
		blkid_partition_set_flags(par, le16_to_cpu(p->s_flag));
	}

	return BLKID_PROBE_OK;

nothing:
	return BLKID_PROBE_NONE;
err:
	return -ENOMEM;
}

const struct blkid_idinfo solaris_x86_pt_idinfo =
{
	.name		= "solaris",
	.probefunc	= probe_solaris_pt,
	.magics		=
	{
		{
		  .magic = "\xEE\xDE\x0D\x60",	/* little-endian magic string */
		  .len = 4,			/* v_sanity size in bytes */
		  .sboff = SOLARIS_MAGICOFFSET	/* offset of v_sanity */
		},
		{ NULL }
	}
};