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