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