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