summaryrefslogtreecommitdiffstats
path: root/partx/sun.c
blob: 30cbd9fb8c6d5e1281fafc9fbb6b946fad5444de (plain) (blame)
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
/*
 * Lifted from kpartx's sun.c
 *
 * Copyrights of the original file apply
 * Copyright (c) 2007 Hannes Reinecke
 *
 * Integrated to partx (utils-linux-ng)
 *       Davidlohr Bueso <dave@gnu.org>
 */

#include <stdio.h>
#include <sys/types.h>

#include "bitops.h"
#include "partx.h"

#define SUN_DISK_MAGIC		0xDABE	/* Disk magic number */
#define SUN_DISK_MAXPARTITIONS	8

struct __attribute__ ((packed)) sun_raw_part {
	u_int32_t	start_cylinder; /* where the part starts... */
	u_int32_t	num_sectors;	/* ...and it's length */
};

struct __attribute__ ((packed)) sun_part_info {
	u_int8_t	spare1;
	u_int8_t	id;		/* Partition type */
	u_int8_t	spare2;
	u_int8_t	flags;		/* Partition flags */
};

struct __attribute__ ((packed)) sun_disk_label {
	char		info[128];	/* Informative text string */
	u_int8_t	spare0[14];
	struct sun_part_info infos[SUN_DISK_MAXPARTITIONS];
	u_int8_t	spare1[246];	/* Boot information etc. */
	u_int16_t	rspeed;		/* Disk rotational speed */
	u_int16_t	pcylcount;	/* Physical cylinder count */
	u_int16_t	sparecyl;	/* extra sects per cylinder */
	u_int8_t	spare2[4];	/* More magic... */
	u_int16_t	ilfact;		/* Interleave factor */
	u_int16_t	ncyl;		/* Data cylinder count */
	u_int16_t	nacyl;		/* Alt. cylinder count */
	u_int16_t	ntrks;		/* Tracks per cylinder */
	u_int16_t	nsect;		/* Sectors per track */
	u_int8_t	spare3[4];	/* Even more magic... */
	struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS];
	u_int16_t	magic;		/* Magic number */
	u_int16_t	csum;		/* Label xor'd checksum */
};

/* Checksum Verification */
static int
sun_verify_checksum (struct sun_disk_label *label)
{
	u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
	u_int16_t csum = 0;

	while (ush >= (u_int16_t *)label)
		csum ^= *ush--;

	return !csum;
}

int
read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
	struct sun_disk_label *l;
	struct sun_raw_part *s;
	unsigned int offset = all.start, end;
	int i, j, n;
	unsigned char *bp;

	bp = getblock(fd, offset);
	if (bp == NULL)
		return -1;

	l = (struct sun_disk_label *) bp;
	if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC)
		return -1;

	if (!sun_verify_checksum(l)) {
		fprintf(stderr, "Corrupted Sun disk label\n");
		return -1;
	}

	for(i=0, n=0; i<SUN_DISK_MAXPARTITIONS; i++) {
		s = &l->partitions[i];

		if (s->num_sectors == 0)
			continue;
		if (n < ns) {
			sp[n].start = offset +
				be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks);
			sp[n].size = be32_to_cpu(s->num_sectors);
			n++;
		} else {
			fprintf(stderr,
				"sun_disklabel: too many slices\n");
			break;
		}
	}
	/*
	 * Convention has it that the SUN disklabel will always have
	 * the 'c' partition spanning the entire disk.
	 * So we have to check for contained slices.
	 */
	for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
		if (sp[i].size == 0)
			continue;

		end = sp[i].start + sp[i].size;
		for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) {
			if ( i == j )
				continue;
			if (sp[j].size == 0)
				continue;

			if (sp[i].start < sp[j].start) {
				if (end > sp[j].start &&
				    end < sp[j].start + sp[j].size) {
					/* Invalid slice */
					fprintf(stderr,
						"sun_disklabel: slice %d overlaps with %d\n", i , j);
					sp[i].size = 0;
				}
			}
		}
	}
	return n;
}