Regen
[dragonfly.git] / lib / libdisk / disk.c
blobcd9d8888d0d74aca838724d14aa76349cbd9e58c
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 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/lib/libdisk/disk.c,v 1.50.2.15 2001/12/30 09:56:12 phk Exp $
10 * $DragonFly: src/lib/libdisk/Attic/disk.c,v 1.4 2005/03/13 15:10:03 swildner Exp $
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <err.h>
20 #include <sys/sysctl.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24 #include <sys/disklabel.h>
25 #include <sys/diskslice.h>
26 #include <sys/diskmbr.h>
27 #include <paths.h>
28 #include "libdisk.h"
30 #define DOSPTYP_EXTENDED 5
31 #define DOSPTYP_ONTRACK 84
33 const char *chunk_n[] = {
34 "whole",
35 "unknown",
36 "fat",
37 "freebsd",
38 "extended",
39 "part",
40 "unused",
41 NULL
44 struct disk *
45 Open_Disk(const char *name)
47 return Int_Open_Disk(name, 0);
50 static u_int32_t
51 Read_Int32(u_int32_t *p)
53 u_int8_t *bp = (u_int8_t *)p;
54 return bp[0] | (bp[1] << 8) | (bp[2] << 16) | (bp[3] << 24);
57 struct disk *
58 Int_Open_Disk(const char *name, u_long size)
60 int i,fd;
61 struct diskslices ds;
62 struct disklabel dl;
63 char device[64], *buf;
64 struct disk *d;
65 u_long sector_size;
66 struct dos_partition *dp;
67 void *p;
68 u_long offset = 0;
70 strcpy(device, _PATH_DEV);
71 strcat(device, name);
73 d = (struct disk *)malloc(sizeof *d);
74 if(!d) return NULL;
75 memset(d, 0, sizeof *d);
77 fd = open(device, O_RDONLY);
78 if (fd < 0) {
79 #ifdef DEBUG
80 warn("open(%s) failed", device);
81 #endif
82 return 0;
85 memset(&dl, 0, sizeof dl);
86 ioctl(fd, DIOCGDINFO, &dl);
87 i = ioctl(fd, DIOCGSLICEINFO, &ds);
88 if (i < 0) {
89 #ifdef DEBUG
90 warn("DIOCGSLICEINFO(%s) failed", device);
91 #endif
92 close(fd);
93 return 0;
96 #ifdef DEBUG
97 for(i = 0; i < ds.dss_nslices; i++)
98 if(ds.dss_slices[i].ds_openmask)
99 printf(" open(%d)=0x%2x",
100 i, ds.dss_slices[i].ds_openmask);
101 printf("\n");
102 #endif
104 /* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
105 if (!size)
106 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
108 /* determine media sector size */
109 if ((buf = malloc(MAX_SEC_SIZE)) == NULL)
110 return NULL;
111 for (sector_size = MIN_SEC_SIZE; sector_size <= MAX_SEC_SIZE; sector_size *= 2) {
112 if (read(fd, buf, sector_size) == sector_size) {
113 d->sector_size = sector_size;
114 break;
117 free (buf);
118 if (sector_size > MAX_SEC_SIZE)
119 return NULL; /* could not determine sector size */
121 p = read_block(fd, 0, sector_size);
122 dp = (struct dos_partition*)(p + DOSPARTOFF);
123 for (i = 0; i < NDOSPART; i++) {
124 if (Read_Int32(&dp->dp_start) >= size)
125 continue;
126 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
127 continue;
128 if (!Read_Int32(&dp->dp_size))
129 continue;
131 if (dp->dp_typ == DOSPTYP_ONTRACK) {
132 d->flags |= DISK_ON_TRACK;
133 offset = 63;
137 free(p);
139 d->bios_sect = dl.d_nsectors;
140 d->bios_hd = dl.d_ntracks;
142 d->name = strdup(name);
145 if (dl.d_ntracks && dl.d_nsectors)
146 d->bios_cyl = size / (dl.d_ntracks * dl.d_nsectors);
148 if (Add_Chunk(d, -offset, size, name, whole, 0, 0))
149 #ifdef DEBUG
150 warn("Failed to add 'whole' chunk");
151 #else
153 #endif
155 #ifdef __i386__
156 for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
157 char sname[20];
158 chunk_e ce;
159 u_long flags=0;
160 int subtype=0;
162 if (! ds.dss_slices[i].ds_size)
163 continue;
164 ds.dss_slices[i].ds_offset -= offset;
165 sprintf(sname, "%ss%d", name, i - 1);
166 subtype = ds.dss_slices[i].ds_type;
167 switch (ds.dss_slices[i].ds_type) {
168 case 0xa5:
169 ce = freebsd;
170 break;
171 case 0x1:
172 case 0x6:
173 case 0x4:
174 case 0xb:
175 case 0xc:
176 case 0xe:
177 ce = fat;
178 break;
179 case DOSPTYP_EXTENDED:
180 case 0xf:
181 ce = extended;
182 break;
183 default:
184 ce = unknown;
185 break;
187 if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
188 ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
189 #ifdef DEBUG
190 warn("failed to add chunk for slice %d", i - 1);
191 #else
193 #endif
195 if (ds.dss_slices[i].ds_type != 0xa5)
196 continue;
198 struct disklabel dl;
199 char pname[20];
200 int j, k;
202 strcpy(pname, _PATH_DEV);
203 strcat(pname, sname);
204 j = open(pname, O_RDONLY);
205 if (j < 0) {
206 #ifdef DEBUG
207 warn("open(%s)", pname);
208 #endif
209 continue;
211 k = ioctl(j, DIOCGDINFO, &dl);
212 if (k < 0) {
213 #ifdef DEBUG
214 warn("ioctl(%s, DIOCGDINFO)", pname);
215 #endif
216 close(j);
217 continue;
219 close(j);
221 for(j = 0; j <= dl.d_npartitions; j++) {
222 if (j == RAW_PART)
223 continue;
224 if (j == 3)
225 continue;
226 if (j == dl.d_npartitions) {
227 j = 3;
228 dl.d_npartitions = 0;
230 if (!dl.d_partitions[j].p_size)
231 continue;
232 if (dl.d_partitions[j].p_size +
233 dl.d_partitions[j].p_offset >
234 ds.dss_slices[i].ds_size)
235 continue;
236 sprintf(pname, "%s%c", sname, j + 'a');
237 if (Add_Chunk(d,
238 dl.d_partitions[j].p_offset +
239 ds.dss_slices[i].ds_offset,
240 dl.d_partitions[j].p_size,
241 pname,part,
242 dl.d_partitions[j].p_fstype,
243 0) && j != 3)
244 #ifdef DEBUG
245 warn(
246 "Failed to add chunk for partition %c [%lu,%lu]",
247 j + 'a', dl.d_partitions[j].p_offset,
248 dl.d_partitions[j].p_size);
249 #else
251 #endif
255 #endif /* __i386__ */
256 close(fd);
257 Fixup_Names(d);
258 return d;
261 void
262 Debug_Disk(struct disk *d)
264 printf("Debug_Disk(%s)", d->name);
265 printf(" flags=%lx", d->flags);
266 #if 0
267 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
268 #endif
269 printf(" bios_geom=%lu/%lu/%lu = %lu\n",
270 d->bios_cyl, d->bios_hd, d->bios_sect,
271 d->bios_cyl * d->bios_hd * d->bios_sect);
272 #if defined(__i386__)
273 printf(" boot1=%p, boot2=%p, bootmgr=%p\n",
274 d->boot1, d->boot2, d->bootmgr);
275 #endif
276 Debug_Chunk(d->chunks);
279 void
280 Free_Disk(struct disk *d)
282 if(d->chunks) Free_Chunk(d->chunks);
283 if(d->name) free(d->name);
284 if(d->bootmgr) free(d->bootmgr);
285 if(d->boot1) free(d->boot1);
286 #if defined(__i386__)
287 if(d->boot2) free(d->boot2);
288 #endif
289 free(d);
292 struct disk *
293 Clone_Disk(struct disk *d)
295 struct disk *d2;
297 d2 = (struct disk*) malloc(sizeof *d2);
298 if(!d2) return NULL;
299 *d2 = *d;
300 d2->name = strdup(d2->name);
301 d2->chunks = Clone_Chunk(d2->chunks);
302 if(d2->bootmgr) {
303 d2->bootmgr = malloc(d2->bootmgr_size);
304 memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size);
306 #if defined(__i386__)
307 if(d2->boot1) {
308 d2->boot1 = malloc(512);
309 memcpy(d2->boot1, d->boot1, 512);
311 if(d2->boot2) {
312 d2->boot2 = malloc(512 * 15);
313 memcpy(d2->boot2, d->boot2, 512 * 15);
315 #endif
316 return d2;
319 #if 0
320 void
321 Collapse_Disk(struct disk *d)
324 while(Collapse_Chunk(d, d->chunks))
327 #endif
329 static char * device_list[] = {"aacd", "ad", "da", "afd", "fla", "idad", "mlxd", "amrd", "twed", "ar", "fd", 0};
331 int qstrcmp(const void* a, const void* b) {
333 char *str1 = *(char**)a;
334 char *str2 = *(char**)b;
335 return strcmp(str1, str2);
339 char **
340 Disk_Names()
342 int i,j,disk_cnt;
343 char disk[25];
344 char diskname[25];
345 struct stat st;
346 struct diskslices ds;
347 int fd;
348 static char **disks;
349 int error;
350 size_t listsize;
351 char *disklist, **dp;
353 disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
354 memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
355 #if !defined(KERN_DISKS_BROKEN)
356 error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
357 if (!error) {
358 disklist = (char *)malloc(listsize);
359 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
360 if (error)
361 return NULL;
362 disk_cnt = 0;
363 for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) &&
364 disk_cnt < MAX_NO_DISKS; disk_cnt++, dp++);
365 } else {
366 warn("kern.disks sysctl not available");
367 #endif
368 disk_cnt = 0;
369 for (j = 0; device_list[j]; j++) {
370 if(disk_cnt >= MAX_NO_DISKS)
371 break;
372 for (i = 0; i < MAX_NO_DISKS; i++) {
373 sprintf(diskname, "%s%d", device_list[j], i);
374 sprintf(disk, _PATH_DEV"%s", diskname);
375 if (stat(disk, &st) || !(st.st_mode & S_IFCHR))
376 continue;
377 if ((fd = open(disk, O_RDWR)) == -1)
378 continue;
379 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
380 #ifdef DEBUG
381 warn("DIOCGSLICEINFO %s", disk);
382 #endif
383 close(fd);
384 continue;
386 close(fd);
387 disks[disk_cnt++] = strdup(diskname);
388 if(disk_cnt >= MAX_NO_DISKS)
389 break;
392 #if !defined(KERN_DISKS_BROKEN)
394 #endif
395 qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
397 return disks;
400 void
401 Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
403 if (s % d->sector_size != 0)
404 return;
405 if (d->bootmgr)
406 free(d->bootmgr);
407 if (!b) {
408 d->bootmgr = NULL;
409 } else {
410 d->bootmgr_size = s;
411 d->bootmgr = malloc(s);
412 if(!d->bootmgr) return;
413 memcpy(d->bootmgr, b, s);
418 Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
420 #if defined(__i386__)
421 if (d->boot1) free(d->boot1);
422 d->boot1 = malloc(512);
423 if(!d->boot1) return -1;
424 memcpy(d->boot1, b1, 512);
425 if (d->boot2) free(d->boot2);
426 d->boot2 = malloc(15 * 512);
427 if(!d->boot2) return -1;
428 memcpy(d->boot2, b2, 15 * 512);
429 #endif
430 return 0;
433 const char *
434 slice_type_name( int type, int subtype )
436 switch (type) {
437 case 0: return "whole";
438 case 1: switch (subtype) {
439 case 1: return "fat (12-bit)";
440 case 2: return "XENIX /";
441 case 3: return "XENIX /usr";
442 case 4: return "fat (16-bit,<=32Mb)";
443 case 5: return "extended DOS";
444 case 6: return "fat (16-bit,>32Mb)";
445 case 7: return "NTFS/HPFS/QNX";
446 case 8: return "AIX bootable";
447 case 9: return "AIX data";
448 case 10: return "OS/2 bootmgr";
449 case 11: return "fat (32-bit)";
450 case 12: return "fat (32-bit,LBA)";
451 case 14: return "fat (16-bit,>32Mb,LBA)";
452 case 15: return "extended DOS, LBA";
453 case 18: return "Compaq Diagnostic";
454 case 84: return "OnTrack diskmgr";
455 case 100: return "Netware 2.x";
456 case 101: return "Netware 3.x";
457 case 115: return "SCO UnixWare";
458 case 128: return "Minix 1.1";
459 case 129: return "Minix 1.5";
460 case 130: return "linux_swap";
461 case 131: return "ext2fs";
462 case 166: return "OpenBSD FFS"; /* 0xA6 */
463 case 169: return "NetBSD FFS"; /* 0xA9 */
464 case 182: return "OpenBSD"; /* dedicated */
465 case 183: return "bsd/os";
466 case 184: return "bsd/os swap";
467 default: return "unknown";
469 case 2: return "fat";
470 case 3: switch (subtype) {
471 case 165: return "freebsd";
472 default: return "unknown";
474 case 4: return "extended";
475 case 5: return "part";
476 case 6: return "unused";
477 default: return "unknown";