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";