disk.c revision 178765
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> 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
10#include <sys/cdefs.h>
11__FBSDID("$FreeBSD: head/lib/libdisk/disk.c 178765 2008-05-04 22:24:40Z gonzo $");
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <string.h>
18#include <inttypes.h>
19#include <err.h>
20#include <sys/sysctl.h>
21#include <sys/stdint.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <sys/ioctl.h>
25#include <sys/disklabel.h>
26#include <sys/uuid.h>
27#include <sys/gpt.h>
28#include <paths.h>
29#include "libdisk.h"
30
31#include <ctype.h>
32#include <errno.h>
33#include <assert.h>
34#include <uuid.h>
35
36const enum platform platform =
37#if defined (P_DEBUG)
38	P_DEBUG
39#elif defined (PC98)
40	p_pc98
41#elif defined(__i386__)
42	p_i386
43#elif defined(__alpha__)
44	p_alpha
45#elif defined(__sparc64__)
46	p_sparc64
47#elif defined(__ia64__)
48	p_ia64
49#elif defined(__ppc__)
50	p_ppc
51#elif defined(__amd64__)
52	p_amd64
53#elif defined(__arm__)
54	p_arm
55#elif defined(__mips__)
56	p_mips
57#else
58	IHAVENOIDEA
59#endif
60	;
61
62const char *
63chunk_name(chunk_e type)
64{
65	switch(type) {
66	case unused:	return ("unused");
67	case mbr:	return ("mbr");
68	case part:	return ("part");
69	case gpt:	return ("gpt");
70	case pc98:	return ("pc98");
71	case sun:	return ("sun");
72	case freebsd:	return ("freebsd");
73	case fat:	return ("fat");
74	case spare:	return ("spare");
75	case efi:	return ("efi");
76	case apple:     return ("apple");
77	default:	return ("??");
78	}
79}
80
81struct disk *
82Open_Disk(const char *name)
83{
84	struct disk *d;
85	char *conftxt;
86	size_t txtsize;
87	int error;
88
89	error = sysctlbyname("kern.geom.conftxt", NULL, &txtsize, NULL, 0);
90	if (error) {
91		warn("kern.geom.conftxt sysctl not available, giving up!");
92		return (NULL);
93	}
94	conftxt = malloc(txtsize+1);
95	if (conftxt == NULL) {
96		warn("cannot malloc memory for conftxt");
97		return (NULL);
98	}
99	error = sysctlbyname("kern.geom.conftxt", conftxt, &txtsize, NULL, 0);
100	if (error) {
101		warn("error reading kern.geom.conftxt from the system");
102		free(conftxt);
103		return (NULL);
104	}
105	conftxt[txtsize] = '\0';	/* in case kernel bug is still there */
106	d = Int_Open_Disk(name, conftxt);
107	free(conftxt);
108
109	return (d);
110}
111
112void
113Debug_Disk(struct disk *d)
114{
115
116	printf("Debug_Disk(%s)", d->name);
117
118#ifndef __ia64__
119	printf("  bios_geom=%lu/%lu/%lu = %lu\n",
120		d->bios_cyl, d->bios_hd, d->bios_sect,
121		d->bios_cyl * d->bios_hd * d->bios_sect);
122#if defined(PC98)
123	printf("  boot1=%p, boot2=%p, bootipl=%p, bootmenu=%p\n",
124		d->boot1, d->boot2, d->bootipl, d->bootmenu);
125#elif defined(__i386__) || defined(__amd64__)
126	printf("  boot1=%p, boot2=%p, bootmgr=%p\n",
127		d->boot1, d->boot2, d->bootmgr);
128#elif defined(__alpha__)
129	printf("  boot1=%p, bootmgr=%p\n",
130		d->boot1, d->bootmgr);
131#else
132/* Should be: error "Debug_Disk: unknown arch"; */
133#endif
134#else	/* __ia64__ */
135	printf("  media size=%lu, sector size=%lu\n", d->media_size,
136	    d->sector_size);
137#endif
138
139	Debug_Chunk(d->chunks);
140}
141
142void
143Free_Disk(struct disk *d)
144{
145	if (d->chunks)
146		Free_Chunk(d->chunks);
147	if (d->name)
148		free(d->name);
149#ifdef PC98
150	if (d->bootipl)
151		free(d->bootipl);
152	if (d->bootmenu)
153		free(d->bootmenu);
154#else
155#if !defined(__ia64__)
156	if (d->bootmgr)
157		free(d->bootmgr);
158#endif
159#endif
160#if !defined(__ia64__)
161	if (d->boot1)
162		free(d->boot1);
163#endif
164#if defined(__i386__) || defined(__amd64__)
165	if (d->boot2)
166		free(d->boot2);
167#endif
168	free(d);
169}
170
171#if 0
172void
173Collapse_Disk(struct disk *d)
174{
175
176	while (Collapse_Chunk(d, d->chunks))
177		;
178}
179#endif
180
181static int
182qstrcmp(const void* a, const void* b)
183{
184	const char *str1 = *(char* const*)a;
185	const char *str2 = *(char* const*)b;
186
187	return strcmp(str1, str2);
188}
189
190char **
191Disk_Names()
192{
193	int disk_cnt;
194	char **disks;
195	int error;
196	size_t listsize;
197	char *disklist, *disk1, *disk2;
198
199	error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
200	if (error) {
201		warn("kern.disks sysctl not available");
202		return NULL;
203	}
204
205	if (listsize == 0)
206		return (NULL);
207
208	disks = malloc(sizeof *disks * (1 + MAX_NO_DISKS));
209	if (disks == NULL)
210		return NULL;
211	disk1 = disklist = (char *)malloc(listsize + 1);
212	if (disklist == NULL) {
213		free(disks);
214		return NULL;
215	}
216	memset(disks,0,sizeof *disks * (1 + MAX_NO_DISKS));
217	memset(disklist, 0, listsize + 1);
218	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
219	if (error || disklist[0] == 0) {
220		free(disklist);
221		free(disks);
222		return NULL;
223	}
224	for (disk_cnt = 0; disk_cnt < MAX_NO_DISKS; disk_cnt++) {
225		disk2 = strsep(&disk1, " ");
226		if (disk2 == NULL)
227			break;
228		disks[disk_cnt] = strdup(disk2);
229		if (disks[disk_cnt] == NULL) {
230			for (disk_cnt--; disk_cnt >= 0; disk_cnt--)
231				free(disks[disk_cnt]);
232			free(disklist);
233			free(disks);
234			return (NULL);
235		}
236	}
237	qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
238	free(disklist);
239	return disks;
240}
241
242#ifdef PC98
243void
244Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
245	const u_char *bootmenu, const size_t bootmenu_size)
246#else
247void
248Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
249#endif
250{
251#if !defined(__ia64__)
252#ifdef PC98
253	if (d->sector_size == 0)
254		return;
255	if (bootipl_size % d->sector_size != 0)
256		return;
257	if (d->bootipl)
258		free(d->bootipl);
259	if (!bootipl) {
260		d->bootipl = NULL;
261	} else {
262		d->bootipl_size = bootipl_size;
263		d->bootipl = malloc(bootipl_size);
264		if (!d->bootipl)
265			return;
266		memcpy(d->bootipl, bootipl, bootipl_size);
267	}
268
269	if (bootmenu_size % d->sector_size != 0)
270		return;
271	if (d->bootmenu)
272		free(d->bootmenu);
273	if (!bootmenu) {
274		d->bootmenu = NULL;
275	} else {
276		d->bootmenu_size = bootmenu_size;
277		d->bootmenu = malloc(bootmenu_size);
278		if (!d->bootmenu)
279			return;
280		memcpy(d->bootmenu, bootmenu, bootmenu_size);
281	}
282#else
283	if (d->sector_size == 0)
284		return;
285	if (s % d->sector_size != 0)
286		return;
287	if (d->bootmgr)
288		free(d->bootmgr);
289	if (!b) {
290		d->bootmgr = NULL;
291	} else {
292		d->bootmgr_size = s;
293		d->bootmgr = malloc(s);
294		if (!d->bootmgr)
295			return;
296		memcpy(d->bootmgr, b, s);
297	}
298#endif
299#endif
300}
301
302int
303Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
304{
305#if defined(__i386__) || defined(__amd64__)
306	if (d->boot1)
307		free(d->boot1);
308	d->boot1 = malloc(512);
309	if (!d->boot1)
310		return -1;
311	memcpy(d->boot1, b1, 512);
312	if (d->boot2)
313		free(d->boot2);
314	d->boot2 = malloc(15 * 512);
315	if (!d->boot2)
316		return -1;
317	memcpy(d->boot2, b2, 15 * 512);
318#elif defined(__alpha__)
319	if (d->boot1)
320		free(d->boot1);
321	d->boot1 = malloc(15 * 512);
322	if (!d->boot1)
323		return -1;
324	memcpy(d->boot1, b1, 15 * 512);
325#elif defined(__sparc64__)
326	if (d->boot1 != NULL)
327		free(d->boot1);
328	d->boot1 = malloc(16 * 512);
329	if (d->boot1 == NULL)
330		return (-1);
331	memcpy(d->boot1, b1, 16 * 512);
332#elif defined(__ia64__)
333	/* nothing */
334#else
335/* Should be: #error "Set_Boot_Blocks: unknown arch"; */
336#endif
337	return 0;
338}
339
340const char *
341slice_type_name( int type, int subtype )
342{
343
344	switch (type) {
345	case whole:
346		return "whole";
347	case mbr:
348		switch (subtype) {
349		case 1:		return "fat (12-bit)";
350		case 2:		return "XENIX /";
351		case 3:		return "XENIX /usr";
352		case 4:         return "fat (16-bit,<=32Mb)";
353		case 5:		return "extended DOS";
354		case 6:         return "fat (16-bit,>32Mb)";
355		case 7:         return "NTFS/HPFS/QNX";
356		case 8:         return "AIX bootable";
357		case 9:         return "AIX data";
358		case 10:	return "OS/2 bootmgr";
359		case 11:        return "fat (32-bit)";
360		case 12:        return "fat (32-bit,LBA)";
361		case 14:        return "fat (16-bit,>32Mb,LBA)";
362		case 15:        return "extended DOS, LBA";
363		case 18:        return "Compaq Diagnostic";
364		case 57:	return "Plan 9";
365		case 77:	return "QNX 4.X";
366		case 78:	return "QNX 4.X 2nd part";
367		case 79:	return "QNX 4.X 3rd part";
368		case 84:	return "OnTrack diskmgr";
369		case 100:	return "Netware 2.x";
370		case 101:	return "Netware 3.x";
371		case 115:	return "SCO UnixWare";
372		case 128:	return "Minix 1.1";
373		case 129:	return "Minix 1.5";
374		case 130:	return "linux_swap";
375		case 131:	return "ext2fs";
376		case 133:	return "linux extended";
377		case 166:	return "OpenBSD FFS";	/* 0xA6 */
378		case 168:	return "Mac OS-X";
379		case 169:	return "NetBSD FFS";	/* 0xA9 */
380		case 171:	return "Mac OS-X Boot";
381		case 182:	return "OpenBSD";	/* dedicated */
382		case 183:	return "bsd/os";
383		case 184:	return "bsd/os swap";
384		case 191:	return "Solaris (new)";
385		case 238:	return "EFI GPT";
386		case 239:	return "EFI Sys. Part.";
387		default:	return "unknown";
388		}
389	case fat:
390		return "fat";
391	case freebsd:
392		switch (subtype) {
393#ifdef PC98
394		case 0xc494:	return "freebsd";
395#else
396		case 165:	return "freebsd";
397#endif
398		default:	return "unknown";
399		}
400	case extended:
401		return "extended";
402	case part:
403		return "part";
404	case efi:
405		return "efi";
406	case unused:
407		return "unused";
408	default:
409		return "unknown";
410	}
411}
412