disk.c revision 8156
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$
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/ioctl.h>
21#include <sys/disklabel.h>
22#include <sys/diskslice.h>
23#include "libdisk.h"
24
25#define DOSPTYP_EXTENDED        5
26#define DOSPTYP_ONTRACK         84
27
28struct disk *
29Open_Disk(char *name)
30{
31	return Int_Open_Disk(name,0);
32}
33
34struct disk *
35Int_Open_Disk(char *name, u_long size)
36{
37	int i,fd;
38	struct diskslices ds;
39	char device[64];
40	struct disk *d;
41
42	strcpy(device,"/dev/r");
43	strcat(device,name);
44
45	fd = open(device,O_RDONLY);
46	if (fd < 0) {
47		warn("open(%s) failed",device);
48		return 0;
49	}
50	i = ioctl(fd,DIOCGSLICEINFO,&ds);
51	if (i < 0) {
52		warn("DIOCSLICEINFO(%s) failed",device);
53		close(fd);
54		return 0;
55	}
56
57	d = (struct disk *)malloc(sizeof *d);
58	if(!d) err(1,"malloc failed");
59
60	memset(d,0,sizeof *d);
61
62	d->name = strdup(name);
63
64	if (!size)
65		size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
66
67	Add_Chunk(d, 0, size, name,whole,0,0);
68	Add_Chunk(d, 0, 1, "-",reserved,0,0);
69
70	for(i=2;i<ds.dss_nslices;i++) {
71		char sname[20];
72		chunk_e ce;
73		u_long flags=0;
74		int subtype=0;
75		if (! ds.dss_slices[i].ds_size)
76			continue;
77		sprintf(sname,"%ss%d",name,i-1);
78		switch (ds.dss_slices[i].ds_type) {
79			case 0xa5:
80				ce = freebsd;
81				break;
82			case 0x1:
83			case 0x6:
84				ce = fat;
85				break;
86			case DOSPTYP_EXTENDED:
87				ce = extended;
88				break;
89			default:
90				ce = foo;
91				subtype = -ds.dss_slices[i].ds_type;
92				break;
93		}
94		flags |= CHUNK_ALIGN;
95		Add_Chunk(d,ds.dss_slices[i].ds_offset,
96			ds.dss_slices[i].ds_size, sname,ce,subtype,flags);
97		if (ce == extended)
98			Add_Chunk(d,ds.dss_slices[i].ds_offset,
99				1, "-",reserved, subtype, flags);
100		if (ds.dss_slices[i].ds_type == 0xa5) {
101			struct disklabel *dl;
102			int j;
103
104			dl = read_disklabel(fd,
105				ds.dss_slices[i].ds_offset + LABELSECTOR);
106			if(dl) {
107				for(j=0; j < dl->d_npartitions; j++) {
108					char pname[20];
109					sprintf(pname,"%s%c",sname,j+'a');
110					if (j == 2)
111						continue;
112					if (!dl->d_partitions[j].p_size)
113						continue;
114					Add_Chunk(d,
115						dl->d_partitions[j].p_offset,
116						dl->d_partitions[j].p_size,
117						pname,part,0,0);
118				}
119			}
120			free(dl);
121		}
122	}
123	close(fd);
124	return d;
125}
126
127void
128Debug_Disk(struct disk *d)
129{
130	printf("Debug_Disk(%s)",d->name);
131	printf("  flags=%lx",d->flags);
132	printf("  real_geom=%lu/%lu/%lu",d->real_cyl,d->real_hd,d->real_sect);
133	printf("  bios_geom=%lu/%lu/%lu\n",d->bios_cyl,d->bios_hd,d->bios_sect);
134	Debug_Chunk(d->chunks);
135}
136
137void
138Free_Disk(struct disk *d)
139{
140	if(d->chunks)
141		Free_Chunk(d->chunks);
142	if(d->name)
143		free(d->name);
144	free(d);
145}
146
147struct disk *
148Clone_Disk(struct disk *d)
149{
150	struct disk *d2;
151
152	d2 = (struct disk*) malloc(sizeof *d2);
153	if(!d2) err(1,"malloc failed");
154	*d2 = *d;
155	d2->name = strdup(d2->name);
156	d2->chunks = Clone_Chunk(d2->chunks);
157	return d2;
158}
159
160void
161Collapse_Disk(struct disk *d)
162{
163
164	while(Collapse_Chunk(d,d->chunks))
165		;
166}
167
168int
169Aligned(struct disk *d, u_long offset)
170{
171	if (offset % d->bios_sect)
172		return 0;
173	return 1;
174}
175
176u_long
177Prev_Aligned(struct disk *d, u_long offset)
178{
179	return (offset / d->bios_sect) * d->bios_sect;
180}
181
182u_long
183Next_Aligned(struct disk *d, u_long offset)
184{
185	return Prev_Aligned(d,offset + d->bios_sect);
186}
187