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 $
20 #include <sys/sysctl.h>
21 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/disklabel.h>
25 #include <sys/diskslice.h>
26 #include <sys/diskmbr.h>
30 #define DOSPTYP_EXTENDED 5
31 #define DOSPTYP_ONTRACK 84
33 const char *chunk_n[] = {
45 Open_Disk(const char *name)
47 return Int_Open_Disk(name, 0);
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);
58 Int_Open_Disk(const char *name, u_long size)
63 char device[64], *buf;
66 struct dos_partition *dp;
70 strcpy(device, _PATH_DEV);
73 d = (struct disk *)malloc(sizeof *d);
75 memset(d, 0, sizeof *d);
77 fd = open(device, O_RDONLY);
80 warn("open(%s) failed", device);
85 memset(&dl, 0, sizeof dl);
86 ioctl(fd, DIOCGDINFO, &dl);
87 i = ioctl(fd, DIOCGSLICEINFO, &ds);
90 warn("DIOCGSLICEINFO(%s) failed", device);
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);
104 /* XXX --- ds.dss_slice[WHOLE_DISK_SLICE].ds.size of MO disk is wrong!!! */
106 size = ds.dss_slices[WHOLE_DISK_SLICE].ds_size;
108 /* determine media sector size */
109 if ((buf = malloc(MAX_SEC_SIZE)) == 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;
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)
126 if (Read_Int32(&dp->dp_start) + Read_Int32(&dp->dp_size) >= size)
128 if (!Read_Int32(&dp->dp_size))
131 if (dp->dp_typ == DOSPTYP_ONTRACK) {
132 d->flags |= DISK_ON_TRACK;
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))
150 warn("Failed to add 'whole' chunk");
156 for(i=BASE_SLICE;i<ds.dss_nslices;i++) {
162 if (! ds.dss_slices[i].ds_size)
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) {
179 case DOSPTYP_EXTENDED:
187 if (Add_Chunk(d, ds.dss_slices[i].ds_offset,
188 ds.dss_slices[i].ds_size, sname, ce, subtype, flags))
190 warn("failed to add chunk for slice %d", i - 1);
195 if (ds.dss_slices[i].ds_type != 0xa5)
202 strcpy(pname, _PATH_DEV);
203 strcat(pname, sname);
204 j = open(pname, O_RDONLY);
207 warn("open(%s)", pname);
211 k = ioctl(j, DIOCGDINFO, &dl);
214 warn("ioctl(%s, DIOCGDINFO)", pname);
221 for(j = 0; j <= dl.d_npartitions; j++) {
226 if (j == dl.d_npartitions) {
228 dl.d_npartitions = 0;
230 if (!dl.d_partitions[j].p_size)
232 if (dl.d_partitions[j].p_size +
233 dl.d_partitions[j].p_offset >
234 ds.dss_slices[i].ds_size)
236 sprintf(pname, "%s%c", sname, j + 'a');
238 dl.d_partitions[j].p_offset +
239 ds.dss_slices[i].ds_offset,
240 dl.d_partitions[j].p_size,
242 dl.d_partitions[j].p_fstype,
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);
255 #endif /* __i386__ */
262 Debug_Disk(struct disk *d)
264 printf("Debug_Disk(%s)", d->name);
265 printf(" flags=%lx", d->flags);
267 printf(" real_geom=%lu/%lu/%lu", d->real_cyl, d->real_hd, d->real_sect);
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);
276 Debug_Chunk(d->chunks);
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);
293 Clone_Disk(struct disk *d)
297 d2 = (struct disk*) malloc(sizeof *d2);
300 d2->name = strdup(d2->name);
301 d2->chunks = Clone_Chunk(d2->chunks);
303 d2->bootmgr = malloc(d2->bootmgr_size);
304 memcpy(d2->bootmgr, d->bootmgr, d2->bootmgr_size);
306 #if defined(__i386__)
308 d2->boot1 = malloc(512);
309 memcpy(d2->boot1, d->boot1, 512);
312 d2->boot2 = malloc(512 * 15);
313 memcpy(d2->boot2, d->boot2, 512 * 15);
321 Collapse_Disk(struct disk *d)
324 while(Collapse_Chunk(d, d->chunks))
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);
346 struct diskslices ds;
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);
358 disklist = (char *)malloc(listsize);
359 error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
363 for (dp = disks; ((*dp = strsep(&disklist, " ")) != NULL) &&
364 disk_cnt < MAX_NO_DISKS; disk_cnt++, dp++);
366 warn("kern.disks sysctl not available");
369 for (j = 0; device_list[j]; j++) {
370 if(disk_cnt >= MAX_NO_DISKS)
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))
377 if ((fd = open(disk, O_RDWR)) == -1)
379 if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
381 warn("DIOCGSLICEINFO %s", disk);
387 disks[disk_cnt++] = strdup(diskname);
388 if(disk_cnt >= MAX_NO_DISKS)
392 #if !defined(KERN_DISKS_BROKEN)
395 qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
401 Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
403 if (s % d->sector_size != 0)
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);
434 slice_type_name( int type, int subtype )
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";