disk.c revision 8228
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 * $Id: disk.c,v 1.11 1995/05/02 19:52:27 jkh Exp $
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
29struct disk *
30Open_Disk(char *name)
31{
32	return Int_Open_Disk(name,0);
33}
34
35struct disk *
36Int_Open_Disk(char *name, u_long size)
37{
38	int i,fd;
39	struct diskslices ds;
40	struct disklabel dl;
41	char device[64];
42	struct disk *d;
43	struct dos_partition *dp;
44	void *p;
45
46	strcpy(device,"/dev/r");
47	strcat(device,name);
48
49	d = (struct disk *)malloc(sizeof *d);
50	if(!d) err(1,"malloc failed");
51	memset(d,0,sizeof *d);
52
53	fd = open(device,O_RDONLY);
54	if (fd < 0) {
55		warn("open(%s) failed",device);
56		return 0;
57	}
58
59	memset(&dl,0,sizeof dl);
60	ioctl(fd,DIOCGDINFO,&dl);
61	i = ioctl(fd,DIOCGSLICEINFO,&ds);
62	if (i < 0) {
63		warn("DIOCGSLICEINFO(%s) failed",device);
64		close(fd);
65		return 0;
66	}
67
68#if 0
69	for(i=0;i<ds.dss_nslices;i++)
70		if(ds.dss_slices[i].ds_openmask)
71			printf("  open(%d)=0x%2x",
72				i,ds.dss_slices[i].ds_openmask);
73	printf("\n");
74#endif
75
76	if (!size)
77		size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
78
79	p = read_block(fd,0);
80	dp = (struct dos_partition*)(p+DOSPARTOFF);
81	for(i=0;i<NDOSPART;i++) {
82		if (dp->dp_start >= size) continue;
83		if (dp->dp_start+dp->dp_size >= size) continue;
84		if (!dp->dp_size) continue;
85
86		if (dp->dp_typ == DOSPTYP_ONTRACK)
87			d->flags |= DISK_ON_TRACK;
88
89	}
90	free(p);
91
92	d->bios_sect = dl.d_nsectors;
93	d->bios_hd = dl.d_ntracks;
94
95	d->name = strdup(name);
96
97
98	if (dl.d_ntracks && dl.d_nsectors)
99		d->bios_cyl = size/(dl.d_ntracks*dl.d_nsectors);
100
101	if (Add_Chunk(d, 0, size, name,whole,0,0))
102		warn("Failed to add 'whole' chunk");
103
104	for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
105		char sname[20];
106		chunk_e ce;
107		u_long flags=0;
108		int subtype=0;
109		if (! ds.dss_slices[i].ds_size)
110			continue;
111		sprintf(sname,"%ss%d",name,i-1);
112		subtype = ds.dss_slices[i].ds_type;
113		switch (ds.dss_slices[i].ds_type) {
114			case 0xa5:
115				ce = freebsd;
116				break;
117			case 0x1:
118			case 0x4:
119				ce = fat;
120				break;
121			case DOSPTYP_EXTENDED:
122				ce = extended;
123				break;
124			default:
125				ce = unknown;
126				break;
127		}
128		flags |= CHUNK_ALIGN;
129		if (Add_Chunk(d,ds.dss_slices[i].ds_offset,
130			ds.dss_slices[i].ds_size, sname,ce,subtype,flags))
131			warn("failed to add chunk for slice %d",i - 1);
132
133		if (ds.dss_slices[i].ds_type != 0xa5)
134			continue;
135		{
136		struct disklabel dl;
137		char pname[20];
138		int j,k;
139
140		strcpy(pname,"/dev/r");
141		strcat(pname,sname);
142		j = open(pname,O_RDONLY);
143		if (j < 0) {
144			warn("open(%s)",pname);
145			continue;
146		}
147		k = ioctl(j,DIOCGDINFO,&dl);
148		if (k < 0) {
149			warn("ioctl(%s,DIOCGDINFO)",pname);
150			close(j);
151			continue;
152		}
153		close(j);
154
155		for(j=0; j <= dl.d_npartitions; j++) {
156			if (j == RAW_PART)
157				continue;
158			if (j == 3)
159				continue;
160			if (j == dl.d_npartitions) {
161				j = 3;
162				dl.d_npartitions=0;
163			}
164			if (!dl.d_partitions[j].p_size)
165				continue;
166			if (dl.d_partitions[j].p_size +
167			    dl.d_partitions[j].p_offset >
168			    ds.dss_slices[i].ds_size)
169				continue;
170			sprintf(pname,"%s%c",sname,j+'a');
171			if (Add_Chunk(d,
172				dl.d_partitions[j].p_offset +
173				ds.dss_slices[i].ds_offset,
174				dl.d_partitions[j].p_size,
175				pname,part,
176				dl.d_partitions[j].p_fstype,
177				0) && j != 3)
178				warn(
179			"Failed to add chunk for partition %c [%lu,%lu]",
180			j + 'a',dl.d_partitions[j].p_offset,
181			dl.d_partitions[j].p_size);
182		}
183		}
184	}
185	close(fd);
186	return d;
187}
188
189void
190Debug_Disk(struct disk *d)
191{
192	printf("Debug_Disk(%s)",d->name);
193	printf("  flags=%lx",d->flags);
194	printf("  real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect);
195	printf("  bios_geom=%lu/%lu/%lu\n",d->bios_cyl,d->bios_hd,d->bios_sect);
196	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
197		d->boot1,d->boot2,d->bootmgr);
198	Debug_Chunk(d->chunks);
199}
200
201void
202Free_Disk(struct disk *d)
203{
204	if(d->chunks) Free_Chunk(d->chunks);
205	if(d->name) free(d->name);
206	if(d->bootmgr) free(d->bootmgr);
207	if(d->boot1) free(d->boot1);
208	if(d->boot2) free(d->boot2);
209	free(d);
210}
211
212struct disk *
213Clone_Disk(struct disk *d)
214{
215	struct disk *d2;
216
217	d2 = (struct disk*) malloc(sizeof *d2);
218	if(!d2) err(1,"malloc failed");
219	*d2 = *d;
220	d2->name = strdup(d2->name);
221	d2->chunks = Clone_Chunk(d2->chunks);
222	if(d2->bootmgr) {
223		d2->bootmgr = malloc(DOSPARTOFF);
224		memcpy(d2->bootmgr,d->bootmgr,DOSPARTOFF);
225	}
226	if(d2->boot1) {
227		d2->boot1 = malloc(512);
228		memcpy(d2->boot1,d->boot1,512);
229	}
230	if(d2->boot2) {
231		d2->boot2 = malloc(512*15);
232		memcpy(d2->boot2,d->boot2,512*15);
233	}
234	return d2;
235}
236
237void
238Collapse_Disk(struct disk *d)
239{
240
241	while(Collapse_Chunk(d,d->chunks))
242		;
243}
244
245static char * device_list[] = {"wd","sd",0};
246
247char **
248Disk_Names()
249{
250    int i,j,k;
251    char disk[25];
252    char diskname[25];
253    struct stat st;
254    struct diskslices ds;
255    int fd;
256    static char **disks;
257
258    disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
259    memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
260    k = 0;
261	for (j = 0; device_list[j]; j++) {
262		for (i = 0; i < 10; i++) {
263			sprintf(diskname, "%s%d", device_list[j], i);
264			sprintf(disk, "/dev/r%s", diskname);
265			if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
266				continue;
267			if ((fd = open(disk, O_RDWR)) == -1)
268				continue;
269			if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
270				close(fd);
271				continue;
272			}
273			disks[k++] = strdup(diskname);
274			if(k == MAX_NO_DISKS)
275				return disks;
276		}
277	}
278	return disks;
279}
280
281void
282Set_Boot_Mgr(struct disk *d, u_char *b)
283{
284	if (d->bootmgr)
285		free(d->bootmgr);
286	if (!b) {
287		d->bootmgr = 0;
288	} else {
289		d->bootmgr = malloc(DOSPARTOFF);
290		if(!d->bootmgr) err(1,"malloc failed");
291		memcpy(d->bootmgr,b,DOSPARTOFF);
292	}
293}
294
295void
296Set_Boot_Blocks(struct disk *d, u_char *b1, u_char *b2)
297{
298	if (d->boot1) free(d->boot1);
299	d->boot1 = malloc(512);
300	if(!d->boot1) err(1,"malloc failed");
301	memcpy(d->boot1,b1,512);
302	if (d->boot2) free(d->boot2);
303	d->boot2 = malloc(15*512);
304	if(!d->boot2) err(1,"malloc failed");
305	memcpy(d->boot2,b2,15*512);
306}
307