summaryrefslogtreecommitdiff
path: root/lib/pttype.c
blob: c2294f13d585cd060b985fb6eca5422cc939aa05 (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
 * Based on libdisk from xfsprogs and Linux fdisk.
 *
 * Copyright (c) 2000-2001 Silicon Graphics, Inc.
 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
 */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>

#include "blkdev.h"

/* we need to read two sectors, beacuse BSD label offset is 512 */
#define PTTYPE_BUFSIZ	(2 * DEFAULT_SECTOR_SIZE)	/* 1024 */

/*
 * SGI
 */
struct sgi_device_parameter { /* 48 bytes */
	unsigned char  skew;
	unsigned char  gap1;
	unsigned char  gap2;
	unsigned char  sparecyl;
	unsigned short pcylcount;
	unsigned short head_vol0;
	unsigned short ntrks;	/* tracks in cyl 0 or vol 0 */
	unsigned char  cmd_tag_queue_depth;
	unsigned char  unused0;
	unsigned short unused1;
	unsigned short nsect;	/* sectors/tracks in cyl 0 or vol 0 */
	unsigned short bytes;
	unsigned short ilfact;
	unsigned int   flags;		/* controller flags */
	unsigned int   datarate;
	unsigned int   retries_on_error;
	unsigned int   ms_per_word;
	unsigned short xylogics_gap1;
	unsigned short xylogics_syncdelay;
	unsigned short xylogics_readdelay;
	unsigned short xylogics_gap2;
	unsigned short xylogics_readgate;
	unsigned short xylogics_writecont;
};

#define	SGI_VOLHDR	0x00
/* 1 and 2 were used for drive types no longer supported by SGI */
#define	SGI_SWAP	0x03
/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
#define	SGI_VOLUME	0x06
#define	SGI_EFS		0x07
#define	SGI_LVOL	0x08
#define	SGI_RLVOL	0x09
#define	SGI_XFS		0x0a
#define	SGI_XFSLOG	0x0b
#define	SGI_XLV		0x0c
#define	SGI_XVM		0x0d
#define	ENTIRE_DISK	SGI_VOLUME
/*
 * controller flags
 */
#define	SECTOR_SLIP	0x01
#define	SECTOR_FWD	0x02
#define	TRACK_FWD	0x04
#define	TRACK_MULTIVOL	0x08
#define	IGNORE_ERRORS	0x10
#define	RESEEK		0x20
#define	CMDTAGQ_ENABLE	0x40

struct sgi_volume_header {
	unsigned int   magic;		 /* expect SGI_LABEL_MAGIC */
	unsigned short boot_part;        /* active boot partition */
	unsigned short swap_part;        /* active swap partition */
	unsigned char  boot_file[16];    /* name of the bootfile */
	struct sgi_device_parameter devparam;	/*  1 * 48 bytes */
	struct volume_directory {		/* 15 * 16 bytes */
		unsigned char vol_file_name[8];	/* a character array */
		unsigned int  vol_file_start;	/* number of logical block */
		unsigned int  vol_file_size;	/* number of bytes */
	} directory[15];
	struct sgi_partition {			/* 16 * 12 bytes */
		unsigned int num_sectors;	/* number of blocks */
		unsigned int start_sector;	/* must be cylinder aligned */
		unsigned int id;
	} partitions[16];
	unsigned int   csum;
	unsigned int   fillbytes;
};

#define	SGI_LABEL_MAGIC		0x0be5a941

static uint32_t
twos_complement_32bit_sum(u_int32_t *base, int size)
{
	int i;
	u_int32_t sum = 0;

	size = size / sizeof(u_int32_t);
	for (i = 0; i < size; i++)
		sum = sum - ntohl(base[i]);
	return sum;
}

static int
sgi_parttable(unsigned char *base)
{
	u_int32_t csum;
	struct sgi_volume_header *vh = (struct sgi_volume_header *) base;

	if (ntohl(vh->magic) != SGI_LABEL_MAGIC)
		return 0;
	csum = twos_complement_32bit_sum((uint32_t *)vh,
				sizeof(struct sgi_volume_header));
	return !csum;
}

/*
 * DOS
 */
static int
dos_parttable(unsigned char *base)
{
	return (base[510] == 0x55 && base[511] == 0xaa);
}

/*
 * AIX
 */
typedef struct {
	unsigned int   magic;        /* expect AIX_LABEL_MAGIC */
	/* ... */
} aix_partition;

#define	AIX_LABEL_MAGIC		0xc9c2d4c1
#define	AIX_LABEL_MAGIC_SWAPPED	0xc1d4c2c9
#define aixlabel(x) ((aix_partition *)x)

static int
aix_parttable(unsigned char *base)
{
	return (aixlabel(base)->magic == AIX_LABEL_MAGIC ||
		aixlabel(base)->magic == AIX_LABEL_MAGIC_SWAPPED);
}

/*
 * SUN
 */
typedef struct {
	unsigned char info[128];   /* Informative text string */
	unsigned char spare0[14];
	struct sun_info {
		unsigned char spare1;
		unsigned char id;
		unsigned char spare2;
		unsigned char flags;
	} infos[8];
	unsigned char spare1[246]; /* Boot information etc. */
	unsigned short rspeed;     /* Disk rotational speed */
	unsigned short pcylcount;  /* Physical cylinder count */
	unsigned short sparecyl;   /* extra sects per cylinder */
	unsigned char spare2[4];   /* More magic... */
	unsigned short ilfact;     /* Interleave factor */
	unsigned short ncyl;       /* Data cylinder count */
	unsigned short nacyl;      /* Alt. cylinder count */
	unsigned short ntrks;      /* Tracks per cylinder */
	unsigned short nsect;      /* Sectors per track */
	unsigned char spare3[4];   /* Even more magic... */
	struct sun_partition {
		u_int32_t start_cylinder;
		u_int32_t num_sectors;
	} partitions[8];
	unsigned short magic;      /* Magic number */
	unsigned short csum;       /* Label xor'd checksum */
} sun_partition;

#define SUN_LABEL_MAGIC          0xDABE
#define SUN_LABEL_MAGIC_SWAPPED  0xBEDA
#define sunlabel(x) ((sun_partition *)x)

static int
sun_parttable(unsigned char *base)
{
	unsigned short *ush;
	int csum = 0;

	if (sunlabel(base)->magic != SUN_LABEL_MAGIC &&
	    sunlabel(base)->magic != SUN_LABEL_MAGIC_SWAPPED)
		return csum;
	ush = ((unsigned short *) (sunlabel(base) + 1)) - 1;
	while (ush >= (unsigned short *)sunlabel(base))
		csum ^= *ush--;
	return !csum;
}

/*
 * MAC
 */
typedef struct {
	unsigned short magic;
	/* ... */
} mac_partition;

#define MAC_LABEL_MAGIC		0x4552
#define MAC_PARTITION_MAGIC	0x504d
#define MAC_OLD_PARTITION_MAGIC	0x5453
#define maclabel(x) ((mac_partition *)x)

static int
mac_parttable(unsigned char *base)
{
	return (ntohs(maclabel(base)->magic) == MAC_LABEL_MAGIC ||
		ntohs(maclabel(base)->magic) == MAC_PARTITION_MAGIC ||
		ntohs(maclabel(base)->magic) == MAC_OLD_PARTITION_MAGIC);
}

/*
 * BSD subpartitions listed in a disklabel, under a dos-like partition.
 */
#define BSD_DISKMAGIC		0x82564557UL		/* The disk magic number */
#define BSD_DISKMAGIC_SWAPED	0x57455682UL
struct bsd_disklabel {
	uint32_t	magic;		/* the magic number */
	/* ... */
};

static int
bsd_parttable(unsigned char *base)
{
	struct bsd_disklabel *l = (struct bsd_disklabel *)
					(base + (DEFAULT_SECTOR_SIZE * 1));

	return (l->magic == BSD_DISKMAGIC || l->magic == BSD_DISKMAGIC_SWAPED);
}

const char *
get_pt_type_fd(int fd)
{
	char	*type = NULL;
	unsigned char	buf[PTTYPE_BUFSIZ];

	if (read(fd, buf, PTTYPE_BUFSIZ) != PTTYPE_BUFSIZ)
		;
	else {
		if (sgi_parttable(buf))
			type = "SGI";
		else if (sun_parttable(buf))
			type = "Sun";
		else if (aix_parttable(buf))
			type = "AIX";
		else if (dos_parttable(buf))
			type = "DOS";
		else if (mac_parttable(buf))
			type = "Mac";
		else if (bsd_parttable(buf))
			type = "BSD";
	}
	return type;
}

const char *
get_pt_type(const char *device)
{
	int fd;
	const char *type;

	fd = open(device, O_RDONLY);
	if (fd == -1)
		return NULL;
	type = get_pt_type_fd(fd);
	close(fd);
	return type;
}

#ifdef TEST_PROGRAM
int
main(int argc, char **argv)
{
	const char *type;

	if (argc < 2) {
		fprintf(stderr, "usage: %s <device>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	type = get_pt_type(argv[1]);
	if (type)
		printf("Partition type: %s\n", type);
	exit(EXIT_SUCCESS);
}
#endif