disk.c revision 21958
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD: head/lib/libdisk/disk.c 21958 1997-01-23 06:29:01Z obrien $
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <string.h>
18#include <err.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <sys/ioctl.h>
22#include <sys/disklabel.h>
23#include <sys/diskslice.h>
24#include "libdisk.h"
25
26#define DOSPTYP_EXTENDED        5
27#define DOSPTYP_ONTRACK         84
28
29const char *chunk_n[] = {
30	"whole",
31	"unknown",
32	"fat",
33	"freebsd",
34	"extended",
35	"part",
36	"unused",
37	NULL
38};
39
40struct disk *
41Open_Disk(const char *name)
42{
43	return Int_Open_Disk(name,0);
44}
45
46struct disk *
47Int_Open_Disk(const char *name, u_long size)
48{
49	int i,fd;
50	struct diskslices ds;
51	struct disklabel dl;
52	char device[64];
53	struct disk *d;
54	struct dos_partition *dp;
55	void *p;
56	u_long offset = 0;
57
58	strcpy(device,"/dev/r");
59	strcat(device,name);
60
61	d = (struct disk *)malloc(sizeof *d);
62	if(!d) err(1,"malloc failed");
63	memset(d,0,sizeof *d);
64
65	fd = open(device,O_RDONLY);
66	if (fd < 0) {
67#ifdef DEBUG
68		warn("open(%s) failed",device);
69#endif
70		return 0;
71	}
72
73	memset(&dl,0,sizeof dl);
74	ioctl(fd,DIOCGDINFO,&dl);
75	i = ioctl(fd,DIOCGSLICEINFO,&ds);
76	if (i < 0) {
77#ifdef DEBUG
78		warn("DIOCGSLICEINFO(%s) failed",device);
79#endif
80		close(fd);
81		return 0;
82	}
83
84#ifdef DEBUG
85	for(i=0;i<ds.dss_nslices;i++)
86		if(ds.dss_slices[i].ds_openmask)
87			printf("  open(%d)=0x%2x",
88				i,ds.dss_slices[i].ds_openmask);
89	printf("\n");
90#endif
91
92	if (!size)
93		size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
94
95	p = read_block(fd,0);
96	dp = (struct dos_partition*)(p+DOSPARTOFF);
97	for(i=0;i<NDOSPART;i++) {
98		if (dp->dp_start >= size) continue;
99		if (dp->dp_start+dp->dp_size >= size) continue;
100		if (!dp->dp_size) continue;
101
102		if (dp->dp_typ == DOSPTYP_ONTRACK) {
103			d->flags |= DISK_ON_TRACK;
104			offset = 63;
105		}
106
107	}
108	free(p);
109
110	d->bios_sect = dl.d_nsectors;
111	d->bios_hd = dl.d_ntracks;
112
113	d->name = strdup(name);
114
115
116	if (dl.d_ntracks && dl.d_nsectors)
117		d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors);
118
119	if (Add_Chunk(d, -offset, size, name, whole, 0, 0))
120#ifdef DEBUG
121		warn("Failed to add 'whole' chunk");
122#else
123		{}
124#endif
125
126	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
127		char sname[20];
128		chunk_e ce;
129		u_long flags=0;
130		int subtype=0;
131		if (! ds.dss_slices[i].ds_size)
132			continue;
133		ds.dss_slices[i].ds_offset -= offset;
134		sprintf(sname,"%ss%d",name,i-1);
135		subtype = ds.dss_slices[i].ds_type;
136		switch (ds.dss_slices[i].ds_type) {
137			case 0xa5:
138				ce = freebsd;
139				break;
140			case 0x1:
141			case 0x6:
142			case 0x4:
143				ce = fat;
144				break;
145			case DOSPTYP_EXTENDED:
146				ce = extended;
147				break;
148			default:
149				ce = unknown;
150				break;
151		}
152		if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
153			ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
154#ifdef DEBUG
155			warn("failed to add chunk for slice %d", i - 1);
156#else
157			{}
158#endif
159
160		if (ds.dss_slices[i].ds_type != 0xa5)
161			continue;
162		{
163		struct disklabel dl;
164		char pname[20];
165		int j,k;
166
167		strcpy(pname,"/dev/r");
168		strcat(pname,sname);
169		j = open(pname,O_RDONLY);
170		if (j < 0) {
171#ifdef DEBUG
172			warn("open(%s)",pname);
173#endif
174			continue;
175		}
176		k = ioctl(j,DIOCGDINFO,&dl);
177		if (k < 0) {
178#ifdef DEBUG
179			warn("ioctl(%s,DIOCGDINFO)",pname);
180#endif
181			close(j);
182			continue;
183		}
184		close(j);
185
186		for(j=0; j <= dl.d_npartitions; j++) {
187			if (j == RAW_PART)
188				continue;
189			if (j == 3)
190				continue;
191			if (j == dl.d_npartitions) {
192				j = 3;
193				dl.d_npartitions=0;
194			}
195			if (!dl.d_partitions[j].p_size)
196				continue;
197			if (dl.d_partitions[j].p_size +
198			    dl.d_partitions[j].p_offset >
199			    ds.dss_slices[i].ds_size)
200				continue;
201			sprintf(pname,"%s%c",sname,j+'a');
202			if (Add_Chunk(d,
203				dl.d_partitions[j].p_offset +
204				ds.dss_slices[i].ds_offset,
205				dl.d_partitions[j].p_size,
206				pname,part,
207				dl.d_partitions[j].p_fstype,
208				0) && j != 3)
209#ifdef DEBUG
210				warn(
211			"Failed to add chunk for partition %c [%lu,%lu]",
212			j + 'a',dl.d_partitions[j].p_offset,
213			dl.d_partitions[j].p_size);
214#else
215				{}
216#endif
217		}
218		}
219	}
220	close(fd);
221	Fixup_Names(d);
222	Bios_Limit_Chunk(d->chunks,1024*d->bios_hd*d->bios_sect);
223	return d;
224}
225
226void
227Debug_Disk(struct disk *d)
228{
229	printf("Debug_Disk(%s)",d->name);
230	printf("  flags=%lx",d->flags);
231#if 0
232	printf("  real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect);
233#endif
234	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
235		d->bios_cyl,d->bios_hd,d->bios_sect,
236		d->bios_cyl*d->bios_hd*d->bios_sect);
237	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
238		d->boot1,d->boot2,d->bootmgr);
239	Debug_Chunk(d->chunks);
240}
241
242void
243Free_Disk(struct disk *d)
244{
245	if(d->chunks) Free_Chunk(d->chunks);
246	if(d->name) free(d->name);
247	if(d->bootmgr) free(d->bootmgr);
248	if(d->boot1) free(d->boot1);
249	if(d->boot2) free(d->boot2);
250	free(d);
251}
252
253struct disk *
254Clone_Disk(struct disk *d)
255{
256	struct disk *d2;
257
258	d2 = (struct disk*) malloc(sizeof *d2);
259	if(!d2) err(1,"malloc failed");
260	*d2 = *d;
261	d2->name = strdup(d2->name);
262	d2->chunks = Clone_Chunk(d2->chunks);
263	if(d2->bootmgr) {
264		d2->bootmgr = malloc(DOSPARTOFF);
265		memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF);
266	}
267	if(d2->boot1) {
268		d2->boot1 = malloc(512);
269		memcpy(d2->boot1,d->boot1,512);
270	}
271	if(d2->boot2) {
272		d2->boot2 = malloc(512*15);
273		memcpy(d2->boot2,d->boot2,512*15);
274	}
275	return d2;
276}
277
278#if 0
279void
280Collapse_Disk(struct disk *d)
281{
282
283	while(Collapse_Chunk(d,d->chunks))
284		;
285}
286#endif
287
288static char * device_list[] = {"wd","sd","od",0};
289
290char **
291Disk_Names()
292{
293    int i,j,k;
294    char disk[25];
295    char diskname[25];
296    struct stat st;
297    struct diskslices ds;
298    int fd;
299    static char **disks;
300
301    disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
302    memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
303    k = 0;
304	for (j = 0; device_list[j]; j++) {
305		for (i = 0; i < 10; i++) {
306			sprintf(diskname, "%s%d", device_list[j], i);
307			sprintf(disk, "/dev/r%s", diskname);
308			if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
309				continue;
310			if ((fd = open(disk, O_RDWR)) == -1)
311				continue;
312			if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
313				close(fd);
314				continue;
315			}
316			disks[k++] = strdup(diskname);
317			if(k == MAX_NO_DISKS)
318				return disks;
319		}
320	}
321	return disks;
322}
323
324void
325Set_Boot_Mgr(struct disk *d, const u_char *b)
326{
327	if (d->bootmgr)
328		free(d->bootmgr);
329	if (!b) {
330		d->bootmgr = 0;
331	} else {
332		d->bootmgr = malloc(DOSPARTOFF);
333		if(!d->bootmgr) err(1,"malloc failed");
334		memcpy(d->bootmgr,b,DOSPARTOFF);
335	}
336}
337
338void
339Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
340{
341	if (d->boot1) free(d->boot1);
342	d->boot1 = malloc(512);
343	if(!d->boot1) err(1,"malloc failed");
344	memcpy(d->boot1,b1,512);
345	if (d->boot2) free(d->boot2);
346	d->boot2 = malloc(15*512);
347	if(!d->boot2) err(1,"malloc failed");
348	memcpy(d->boot2,b2,15*512);
349}
350
351const char *
352slice_type_name( int type, int subtype )
353{
354	switch (type) {
355		case 0:		return "whole";
356		case 1:		switch (subtype) {
357					case 1:		return "fat (12-bit)";
358					case 2:		return "XENIX /";
359					case 3:		return "XENIX /usr";
360					case 4:		return "fat (16-bit)";
361					case 5:		return "extended DOS";
362					case 6:		return "fat (>32Mb)";
363					case 7:		return "NTFS/HPFS";
364					case 10:	return "OS/2 bootmgr";
365					case 84:	return "OnTrack diskmgr";
366					case 100:	return "Netware 2.x";
367					case 101:	return "Netware 3.x";
368					case 128:	return "Minix 1.1";
369					case 129:	return "Minix 1.5";
370					case 130:	return "linux_swap";
371					case 131:	return "ext2fs";
372					case 183:	return "bsd/os";
373					case 184:	return "bsd/os swap";
374					default:	return "unknown";
375				}
376		case 2:		return "fat";
377		case 3:		switch (subtype) {
378					case 165:	return "freebsd";
379					default:	return "unknown";
380				}
381		case 4:		return "extended";
382		case 5:		return "part";
383		case 6:		return "unused";
384		default:	return "unknown";
385	}
386}
387