disk.c revision 158033
114239Sbde/*
266830Sobrien * ----------------------------------------------------------------------------
366830Sobrien * "THE BEER-WARE LICENSE" (Revision 42):
466830Sobrien * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
566830Sobrien * can do whatever you want with this stuff. If we meet some day, and you think
666830Sobrien * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
766830Sobrien * ----------------------------------------------------------------------------
866830Sobrien */
966830Sobrien
1066830Sobrien#include <sys/cdefs.h>
1166830Sobrien__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 158033 2006-04-25 20:42:15Z maxim $");
1266830Sobrien
1366830Sobrien#include <stdio.h>
1466830Sobrien#include <stdlib.h>
1566830Sobrien#include <unistd.h>
1666830Sobrien#include <fcntl.h>
1766830Sobrien#include <string.h>
1866830Sobrien#include <inttypes.h>
1966830Sobrien#include <err.h>
2066830Sobrien#include <sys/sysctl.h>
2166830Sobrien#include <sys/stdint.h>
2266830Sobrien#include <sys/types.h>
2366830Sobrien#include <sys/stat.h>
2466830Sobrien#include <sys/ioctl.h>
2566830Sobrien#include <sys/disklabel.h>
2666830Sobrien#include <sys/uuid.h>
2750472Speter#include <sys/gpt.h>
2866830Sobrien#include <paths.h>
2914239Sbde#include "libdisk.h"
30100280Sgordon
31100280Sgordon#include <ctype.h>
32100280Sgordon#include <errno.h>
33100280Sgordon#include <assert.h>
3413798Smpp#include <uuid.h>
351675Sache
367708Srgrimesconst enum platform platform =
371675Sache#if defined (P_DEBUG)
381675Sache	P_DEBUG
391675Sache#elif defined (PC98)
401675Sache	p_pc98
411675Sache#elif defined(__i386__)
421675Sache	p_i386
431675Sache#elif defined(__alpha__)
441675Sache	p_alpha
451675Sache#elif defined(__sparc64__)
461675Sache	p_sparc64
4714239Sbde#elif defined(__ia64__)
4814239Sbde	p_ia64
4914239Sbde#elif defined(__ppc__)
5014239Sbde	p_ppc
511675Sache#elif defined(__amd64__)
521675Sache	p_amd64
5395305Ssobomax#elif defined(__arm__)
5450454Ssheldonh	p_arm
5550357Ssheldonh#else
5650454Ssheldonh	IHAVENOIDEA
5750357Ssheldonh#endif
581675Sache	;
591675Sache
601675Sacheconst char *
611675Sachechunk_name(chunk_e type)
621675Sache{
6314239Sbde	switch(type) {
6414239Sbde	case unused:	return ("unused");
6514239Sbde	case mbr:	return ("mbr");
6614239Sbde	case part:	return ("part");
671675Sache	case gpt:	return ("gpt");
681675Sache	case pc98:	return ("pc98");
691675Sache	case sun:	return ("sun");
7050357Ssheldonh	case freebsd:	return ("freebsd");
7150357Ssheldonh	case fat:	return ("fat");
721675Sache	case spare:	return ("spare");
7350357Ssheldonh	case efi:	return ("efi");
741675Sache	case apple:     return ("apple");
751675Sache	default:	return ("??");
7650357Ssheldonh	}
7750357Ssheldonh}
781675Sache
791675Sachestruct disk *
801675SacheOpen_Disk(const char *name)
811675Sache{
821675Sache	struct disk *d;
8314239Sbde	char *conftxt;
8414239Sbde	size_t txtsize;
8514239Sbde	int error;
8614239Sbde
871675Sache	error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0);
881675Sache	if (error) {
897708Srgrimes		warn("kern.geom.conftxt sysctl not available, giving up!");
9050357Ssheldonh		return (NULL);
911675Sache	}
921675Sache	conftxt = malloc(txtsize+1);
9350357Ssheldonh	if (conftxt == NULL) {
9450357Ssheldonh		warn("cannot malloc memory for conftxt");
9550357Ssheldonh		return (NULL);
9650357Ssheldonh	}
971675Sache	error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0);
981675Sache	if (error) {
991675Sache		warn("error reading kern.geom.conftxt from the system");
1001675Sache		free(conftxt);
1011675Sache		return (NULL);
10214239Sbde	}
10314239Sbde	conftxt[txtsize] = '\0';	/* in case kernel bug is still there */
10414239Sbde	d = Int_Open_Disk(name, conftxt);
10514239Sbde	free(conftxt);
1061675Sache
1071675Sache	return (d);
1081675Sache}
1091675Sache
11050357Ssheldonhvoid
11150357SsheldonhDebug_Disk(struct disk *d)
11250357Ssheldonh{
11350357Ssheldonh
1141675Sache	printf("Debug_Disk(%s)", d->name);
1151675Sache
1161675Sache#ifndef __ia64__
1171675Sache	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
1181675Sache		d->bios_cyl, d->bios_hd, d->bios_sect,
1191675Sache		d->bios_cyl * d->bios_hd * d->bios_sect);
1201675Sache#if defined(PC98)
1211675Sache	printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
1221675Sache		d->boot1, d->boot2, d->bootipl, d->bootmenu);
1231675Sache#elif defined(__i386__) || defined(__amd64__)
12414239Sbde	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
12514239Sbde		d->boot1, d->boot2, d->bootmgr);
12614239Sbde#elif defined(__alpha__)
12714239Sbde	printf("  boot1=%p, bootmgr=%p\n",
12850357Ssheldonh		d->boot1, d->bootmgr);
1291675Sache#else
1301675Sache/* Should be: error "Debug_Disk: unknown arch"; */
13150357Ssheldonh#endif
13250357Ssheldonh#else	/* __ia64__ */
13350357Ssheldonh	printf("  media size=%lu, sector size=%lu\n", d->media_size,
1341675Sache	    d->sector_size);
1351675Sache#endif
1361675Sache
1371675Sache	Debug_Chunk(d->chunks);
1381675Sache}
13914239Sbde
1401675Sachevoid
14114239SbdeFree_Disk(struct disk *d)
14214239Sbde{
14314239Sbde	if (d->chunks)
14414239Sbde		Free_Chunk(d->chunks);
14514239Sbde	if (d->name)
14614239Sbde		free(d->name);
14714239Sbde#ifdef PC98
14814239Sbde	if (d->bootipl)
14914239Sbde		free(d->bootipl);
15014239Sbde	if (d->bootmenu)
15134561Sdanny		free(d->bootmenu);
15214239Sbde#else
15314239Sbde#if !defined(__ia64__)
15434561Sdanny	if (d->bootmgr)
15514239Sbde		free(d->bootmgr);
15614239Sbde#endif
15723607Sbde#endif
158#if !defined(__ia64__)
159	if (d->boot1)
160		free(d->boot1);
161#endif
162#if defined(__i386__) || defined(__amd64__)
163	if (d->boot2)
164		free(d->boot2);
165#endif
166	free(d);
167}
168
169#if 0
170void
171Collapse_Disk(struct disk *d)
172{
173
174	while (Collapse_Chunk(d, d->chunks))
175		;
176}
177#endif
178
179static int
180qstrcmp(const void* a, const void* b)
181{
182	const char *str1 = *(char* const*)a;
183	const char *str2 = *(char* const*)b;
184
185	return strcmp(str1, str2);
186}
187
188char **
189Disk_Names()
190{
191	int disk_cnt;
192	static char **disks;
193	int error;
194	size_t listsize;
195	char *disklist;
196
197	error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
198	if (error) {
199		warn("kern.disks sysctl not available");
200		return NULL;
201	}
202
203	if (listsize == 0)
204		return (NULL);
205
206	disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
207	if (disks == NULL)
208		return NULL;
209	disklist = (char *)malloc(listsize + 1);
210	if (disklist == NULL) {
211		free(disks);
212		return NULL;
213	}
214	memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
215	memset(disklist, 0, listsize + 1);
216	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
217	if (error || disklist[0] == 0) {
218		free(disklist);
219		free(disks);
220		return NULL;
221	}
222	for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
223		disks[disk_cnt] = strsep(&disklist, " ");
224		if (disks[disk_cnt] == NULL)
225			break;
226	}
227	qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
228	return disks;
229}
230
231#ifdef PC98
232void
233Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
234	const u_char *bootmenu, const size_t bootmenu_size)
235#else
236void
237Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
238#endif
239{
240#if !defined(__ia64__)
241#ifdef PC98
242	if (d->sector_size == 0)
243		return;
244	if (bootipl_size % d->sector_size != 0)
245		return;
246	if (d->bootipl)
247		free(d->bootipl);
248	if (!bootipl) {
249		d->bootipl = NULL;
250	} else {
251		d->bootipl_size = bootipl_size;
252		d->bootipl = malloc(bootipl_size);
253		if (!d->bootipl)
254			return;
255		memcpy(d->bootipl, bootipl, bootipl_size);
256	}
257
258	if (bootmenu_size % d->sector_size != 0)
259		return;
260	if (d->bootmenu)
261		free(d->bootmenu);
262	if (!bootmenu) {
263		d->bootmenu = NULL;
264	} else {
265		d->bootmenu_size = bootmenu_size;
266		d->bootmenu = malloc(bootmenu_size);
267		if (!d->bootmenu)
268			return;
269		memcpy(d->bootmenu, bootmenu, bootmenu_size);
270	}
271#else
272	if (d->sector_size == 0)
273		return;
274	if (s % d->sector_size != 0)
275		return;
276	if (d->bootmgr)
277		free(d->bootmgr);
278	if (!b) {
279		d->bootmgr = NULL;
280	} else {
281		d->bootmgr_size = s;
282		d->bootmgr = malloc(s);
283		if (!d->bootmgr)
284			return;
285		memcpy(d->bootmgr, b, s);
286	}
287#endif
288#endif
289}
290
291int
292Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
293{
294#if defined(__i386__) || defined(__amd64__)
295	if (d->boot1)
296		free(d->boot1);
297	d->boot1 = malloc(512);
298	if (!d->boot1)
299		return -1;
300	memcpy(d->boot1, b1, 512);
301	if (d->boot2)
302		free(d->boot2);
303	d->boot2 = malloc(15 * 512);
304	if (!d->boot2)
305		return -1;
306	memcpy(d->boot2, b2, 15 * 512);
307#elif defined(__alpha__)
308	if (d->boot1)
309		free(d->boot1);
310	d->boot1 = malloc(15 * 512);
311	if (!d->boot1)
312		return -1;
313	memcpy(d->boot1, b1, 15 * 512);
314#elif defined(__sparc64__)
315	if (d->boot1 != NULL)
316		free(d->boot1);
317	d->boot1 = malloc(16 * 512);
318	if (d->boot1 == NULL)
319		return (-1);
320	memcpy(d->boot1, b1, 16 * 512);
321#elif defined(__ia64__)
322	/* nothing */
323#else
324/* Should be: #error "Set_Boot_Blocks: unknown arch"; */
325#endif
326	return 0;
327}
328
329const char *
330slice_type_name( int type, int subtype )
331{
332
333	switch (type) {
334	case whole:
335		return "whole";
336	case mbr:
337		switch (subtype) {
338		case 1:		return "fat (12-bit)";
339		case 2:		return "XENIX /";
340		case 3:		return "XENIX /usr";
341		case 4:         return "fat (16-bit,<=32Mb)";
342		case 5:		return "extended DOS";
343		case 6:         return "fat (16-bit,>32Mb)";
344		case 7:         return "NTFS/HPFS/QNX";
345		case 8:         return "AIX bootable";
346		case 9:         return "AIX data";
347		case 10:	return "OS/2 bootmgr";
348		case 11:        return "fat (32-bit)";
349		case 12:        return "fat (32-bit,LBA)";
350		case 14:        return "fat (16-bit,>32Mb,LBA)";
351		case 15:        return "extended DOS, LBA";
352		case 18:        return "Compaq Diagnostic";
353		case 57:	return "Plan 9";
354		case 77:	return "QNX 4.X";
355		case 78:	return "QNX 4.X 2nd part";
356		case 79:	return "QNX 4.X 3rd part";
357		case 84:	return "OnTrack diskmgr";
358		case 100:	return "Netware 2.x";
359		case 101:	return "Netware 3.x";
360		case 115:	return "SCO UnixWare";
361		case 128:	return "Minix 1.1";
362		case 129:	return "Minix 1.5";
363		case 130:	return "linux_swap";
364		case 131:	return "ext2fs";
365		case 133:	return "linux extended";
366		case 166:	return "OpenBSD FFS";	/* 0xA6 */
367		case 168:	return "Mac OS-X";
368		case 169:	return "NetBSD FFS";	/* 0xA9 */
369		case 171:	return "Mac OS-X Boot";
370		case 182:	return "OpenBSD";	/* dedicated */
371		case 183:	return "bsd/os";
372		case 184:	return "bsd/os swap";
373		case 191:	return "Solaris (new)";
374		case 238:	return "EFI GPT";
375		case 239:	return "EFI Sys. Part.";
376		default:	return "unknown";
377		}
378	case fat:
379		return "fat";
380	case freebsd:
381		switch (subtype) {
382#ifdef PC98
383		case 0xc494:	return "freebsd";
384#else
385		case 165:	return "freebsd";
386#endif
387		default:	return "unknown";
388		}
389	case extended:
390		return "extended";
391	case part:
392		return "part";
393	case efi:
394		return "efi";
395	case unused:
396		return "unused";
397	default:
398		return "unknown";
399	}
400}
401