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