Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <ctype.h>
5
#include <disk.h>
6
 
7
static Disk*
8
mkwidth(Disk *disk)
9
{
10
	char buf[40];
11
 
12
	snprint(buf, sizeof buf, "%lld", disk->size);
13
	disk->width = strlen(buf);
14
	return disk;
15
}
16
 
17
/*
18
 * Discover the disk geometry by various sleazeful means.
19
 * 
20
 * First, if there is a partition table in sector 0,
21
 * see if all the partitions have the same end head
22
 * and sector; if so, we'll assume that that's the 
23
 * right count.
24
 * 
25
 * If that fails, we'll try looking at the geometry that the ATA
26
 * driver supplied, if any, and translate that as a
27
 * BIOS might. 
28
 * 
29
 * If that too fails, which should only happen on a SCSI
30
 * disk with no currently defined partitions, we'll try
31
 * various common (h, s) pairs used by BIOSes when faking
32
 * the geometries.
33
 */
34
typedef struct Table  Table;
35
typedef struct Tentry Tentry;
36
struct Tentry {
37
	uchar	active;			/* active flag */
38
	uchar	starth;			/* starting head */
39
	uchar	starts;			/* starting sector */
40
	uchar	startc;			/* starting cylinder */
41
	uchar	type;			/* partition type */
42
	uchar	endh;			/* ending head */
43
	uchar	ends;			/* ending sector */
44
	uchar	endc;			/* ending cylinder */
45
	uchar	xlba[4];			/* starting LBA from beginning of disc */
46
	uchar	xsize[4];		/* size in sectors */
47
};
48
enum {
49
	Toffset		= 446,		/* offset of partition table in sector */
50
	Magic0		= 0x55,
51
	Magic1		= 0xAA,
52
	NTentry		= 4,
53
};
54
struct Table {
55
	Tentry	entry[NTentry];
56
	uchar	magic[2];
57
};
58
static int
59
partitiongeometry(Disk *disk)
60
{
61
	char *rawname;
62
	int i, h, rawfd, s;
63
	uchar buf[512];
64
	Table *t;
65
 
66
	if(disk->c == 0 || disk->h == 0 || disk->s == 0)
67
		return -1;
68
 
69
	t = (Table*)(buf + Toffset);
70
 
71
	/*
72
	 * look for an MBR first in the /dev/sdXX/data partition, otherwise
73
	 * attempt to fall back on the current partition.
74
	 */
75
	rawname = malloc(strlen(disk->prefix) + 5);	/* prefix + "data" + nul */
76
	if(rawname == nil)
77
		return -1;
78
 
79
	strcpy(rawname, disk->prefix);
80
	strcat(rawname, "data");
81
	rawfd = open(rawname, OREAD);
82
	free(rawname);
83
	if(rawfd >= 0
84
	&& seek(rawfd, 0, 0) >= 0
85
	&& readn(rawfd, buf, 512) == 512
86
	&& t->magic[0] == Magic0
87
	&& t->magic[1] == Magic1) {
88
		close(rawfd);
89
	} else {
90
		if(rawfd >= 0)
91
			close(rawfd);
92
		if(seek(disk->fd, 0, 0) < 0
93
		|| readn(disk->fd, buf, 512) != 512
94
		|| t->magic[0] != Magic0
95
		|| t->magic[1] != Magic1) {
96
			return -1;
97
		}
98
	}
99
 
100
	h = s = -1;
101
	for(i=0; i<NTentry; i++) {
102
		if(t->entry[i].type == 0)
103
			continue;
104
 
105
		t->entry[i].ends &= 63;
106
		if(h == -1) {
107
			h = t->entry[i].endh;
108
			s = t->entry[i].ends;
109
		} else {
110
			/*
111
			 * Only accept the partition info if every
112
			 * partition is consistent.
113
			 */
114
			if(h != t->entry[i].endh || s != t->entry[i].ends)
115
				return -1;
116
		}
117
	}
118
 
119
	if(h == -1)
120
		return -1;
121
 
122
	disk->h = h+1;	/* heads count from 0 */
123
	disk->s = s;	/* sectors count from 1 */
124
	disk->c = disk->secs / (disk->h*disk->s);
125
	disk->chssrc = Gpart;
126
	return 0;
127
}
128
 
129
/*
130
 * If there is ATA geometry, use it, perhaps massaged.
131
 */
132
static int
133
drivergeometry(Disk *disk)
134
{
135
	int m;
136
 
137
	if(disk->c == 0 || disk->h == 0 || disk->s == 0)
138
		return -1;
139
 
140
	disk->chssrc = Gdisk;
141
	if(disk->c < 1024)
142
		return 0;
143
 
144
	switch(disk->h) {
145
	case 15:
146
		disk->h = 255;
147
		disk->c /= 17;
148
		return 0;
149
 
150
	default:
151
		for(m = 2; m*disk->h < 256; m *= 2) {
152
			if(disk->c/m < 1024) {
153
				disk->c /= m;
154
				disk->h *= m;
155
				return 0;
156
			}
157
		}
158
 
159
		/* set to 255, 63 and be done with it */
160
		disk->h = 255;
161
		disk->s = 63;
162
		disk->c = disk->secs / (disk->h * disk->s);
163
		return 0;
164
	}
165
}
166
 
167
/*
168
 * There's no ATA geometry and no partitions.
169
 * Our guess is as good as anyone's.
170
 */
171
static struct {
172
	int h;
173
	int s;
174
} guess[] = {
175
	64, 32,
176
	64, 63,
177
	128, 63,
178
	255, 63,
179
};
180
static int
181
guessgeometry(Disk *disk)
182
{
183
	int i;
184
	long c;
185
 
186
	disk->chssrc = Gguess;
187
	c = 1024;
188
	for(i=0; i<nelem(guess); i++)
189
		if(c*guess[i].h*guess[i].s >= disk->secs) {
190
			disk->h = guess[i].h;
191
			disk->s = guess[i].s;
192
			disk->c = disk->secs / (disk->h * disk->s);
193
			return 0;
194
		}
195
 
196
	/* use maximum values */
197
	disk->h = 255;
198
	disk->s = 63;
199
	disk->c = disk->secs / (disk->h * disk->s);
200
	return 0;
201
}
202
 
203
static void
204
findgeometry(Disk *disk)
205
{
206
	if(partitiongeometry(disk) < 0
207
	&& drivergeometry(disk) < 0
208
	&& guessgeometry(disk) < 0) {	/* can't happen */
209
		print("we're completely confused about your disk; sorry\n");
210
		assert(0);
211
	}
212
}
213
 
214
static Disk*
215
openfile(Disk *disk)
216
{
217
	Dir *d;
218
 
219
	if((d = dirfstat(disk->fd)) == nil){
220
		free(disk);
221
		return nil;
222
	}
223
 
224
	disk->secsize = 512;
225
	disk->size = d->length;
226
	disk->secs = disk->size / disk->secsize;
227
	disk->offset = 0;
228
	free(d);
229
 
230
	findgeometry(disk);
231
	return mkwidth(disk);
232
}
233
 
234
static Disk*
235
opensd(Disk *disk)
236
{
237
	Biobuf b;
238
	char *p, *f[10];
239
	int nf;
240
 
241
	Binit(&b, disk->ctlfd, OREAD);
242
	while(p = Brdline(&b, '\n')) {
243
		p[Blinelen(&b)-1] = '\0';
244
		nf = tokenize(p, f, nelem(f));
245
		if(nf >= 3 && strcmp(f[0], "geometry") == 0) {
246
			disk->secsize = strtoll(f[2], 0, 0);
247
			if(nf >= 6) {
248
				disk->c = strtol(f[3], 0, 0);
249
				disk->h = strtol(f[4], 0, 0);
250
				disk->s = strtol(f[5], 0, 0);
251
			}
252
		}
253
		if(nf >= 4 && strcmp(f[0], "part") == 0 && strcmp(f[1], disk->part) == 0) {
254
			disk->offset = strtoll(f[2], 0, 0);
255
			disk->secs = strtoll(f[3], 0, 0) - disk->offset;
256
		}
257
	}
258
 
259
 
260
	disk->size = disk->secs * disk->secsize;
261
	if(disk->size <= 0) {
262
		strcpy(disk->part, "");
263
		disk->type = Tfile;
264
		return openfile(disk);
265
	}
266
 
267
	findgeometry(disk);
268
	return mkwidth(disk);
269
}
270
 
271
Disk*
272
opendisk(char *disk, int rdonly, int noctl)
273
{
274
	char *p, *q;
275
	Disk *d;
276
 
277
	d = mallocz(sizeof(*d), 1);
278
	if(d == nil)
279
		return nil;
280
 
281
	d->fd = d->wfd = d->ctlfd = -1;
282
	d->rdonly = rdonly;
283
 
284
	d->fd = open(disk, OREAD);
285
	if(d->fd < 0) {
286
		werrstr("cannot open disk file");
287
		free(d);
288
		return nil;
289
	}
290
 
291
	if(rdonly == 0) {
292
		d->wfd = open(disk, OWRITE);
293
		if(d->wfd < 0)
294
			d->rdonly = 1;
295
	}
296
 
297
	if(noctl)
298
		return openfile(d);
299
 
300
	p = malloc(strlen(disk) + 4);	/* 4: slop for "ctl\0" */
301
	if(p == nil) {
302
		close(d->wfd);
303
		close(d->fd);
304
		free(d);
305
		return nil;
306
	}
307
	strcpy(p, disk);
308
 
309
	/* check for floppy(3) disk */
310
	if(strlen(p) >= 7) {
311
		q = p+strlen(p)-7;
312
		if(q[0] == 'f' && q[1] == 'd' && isdigit(q[2]) && strcmp(q+3, "disk") == 0) {
313
			strcpy(q+3, "ctl");
314
			if((d->ctlfd = open(p, ORDWR)) >= 0) {
315
				*q = '\0';
316
				d->prefix = p;
317
				d->type = Tfloppy;
318
				return openfile(d);
319
			}
320
		}
321
	}
322
 
323
	/* attempt to find sd(3) disk or partition */
324
	if(q = strrchr(p, '/'))
325
		q++;
326
	else
327
		q = p;
328
 
329
	strcpy(q, "ctl");
330
	if((d->ctlfd = open(p, ORDWR)) >= 0) {
331
		*q = '\0';
332
		d->prefix = p;
333
		d->type = Tsd;
334
		d->part = strdup(disk+(q-p));
335
		if(d->part == nil){
336
			close(d->ctlfd);
337
			close(d->wfd);
338
			close(d->fd);
339
			free(p);
340
			free(d);
341
			return nil;
342
		}
343
		return opensd(d);
344
	}
345
 
346
	*q = '\0';
347
	d->prefix = p;
348
	/* assume we just have a normal file */
349
	d->type = Tfile;
350
	return openfile(d);
351
}