]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libdisk/disk.c
MFC to RELENG_6
[FreeBSD/FreeBSD.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 #else
54         IHAVENOIDEA
55 #endif
56         ;
57
58 const char *
59 chunk_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
77 struct disk *
78 Open_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
108 void
109 Debug_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
138 void
139 Free_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
168 void
169 Collapse_Disk(struct disk *d)
170 {
171
172         while (Collapse_Chunk(d, d->chunks))
173                 ;
174 }
175 #endif
176
177 static int
178 qstrcmp(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
186 char **
187 Disk_Names()
188 {
189         int disk_cnt;
190         char **disks;
191         int error;
192         size_t listsize;
193         char *disklist, *disk1, *disk2;
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         disk1 = 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                 disk2 = strsep(&disk1, " ");
222                 if (disk2 == NULL)
223                         break;
224                 disks[disk_cnt] = strdup(disk2);
225                 if (disks[disk_cnt] == NULL) {
226                         for (disk_cnt--; disk_cnt >= 0; disk_cnt--)
227                                 free(disks[disk_cnt]);
228                         free(disklist);
229                         free(disks);
230                         return (NULL);
231                 }
232         }
233         qsort(disks, disk_cnt, sizeof(char*), qstrcmp);
234         free(disklist);
235         return disks;
236 }
237
238 #ifdef PC98
239 void
240 Set_Boot_Mgr(struct disk *d, const u_char *bootipl, const size_t bootipl_size,
241         const u_char *bootmenu, const size_t bootmenu_size)
242 #else
243 void
244 Set_Boot_Mgr(struct disk *d, const u_char *b, const size_t s)
245 #endif
246 {
247 #if !defined(__ia64__)
248 #ifdef PC98
249         if (d->sector_size == 0)
250                 return;
251         if (bootipl_size % d->sector_size != 0)
252                 return;
253         if (d->bootipl)
254                 free(d->bootipl);
255         if (!bootipl) {
256                 d->bootipl = NULL;
257         } else {
258                 d->bootipl_size = bootipl_size;
259                 d->bootipl = malloc(bootipl_size);
260                 if (!d->bootipl)
261                         return;
262                 memcpy(d->bootipl, bootipl, bootipl_size);
263         }
264
265         if (bootmenu_size % d->sector_size != 0)
266                 return;
267         if (d->bootmenu)
268                 free(d->bootmenu);
269         if (!bootmenu) {
270                 d->bootmenu = NULL;
271         } else {
272                 d->bootmenu_size = bootmenu_size;
273                 d->bootmenu = malloc(bootmenu_size);
274                 if (!d->bootmenu)
275                         return;
276                 memcpy(d->bootmenu, bootmenu, bootmenu_size);
277         }
278 #else
279         if (d->sector_size == 0)
280                 return;
281         if (s % d->sector_size != 0)
282                 return;
283         if (d->bootmgr)
284                 free(d->bootmgr);
285         if (!b) {
286                 d->bootmgr = NULL;
287         } else {
288                 d->bootmgr_size = s;
289                 d->bootmgr = malloc(s);
290                 if (!d->bootmgr)
291                         return;
292                 memcpy(d->bootmgr, b, s);
293         }
294 #endif
295 #endif
296 }
297
298 int
299 Set_Boot_Blocks(struct disk *d, const u_char *b1, const u_char *b2)
300 {
301 #if defined(__i386__) || defined(__amd64__)
302         if (d->boot1)
303                 free(d->boot1);
304         d->boot1 = malloc(512);
305         if (!d->boot1)
306                 return -1;
307         memcpy(d->boot1, b1, 512);
308         if (d->boot2)
309                 free(d->boot2);
310         d->boot2 = malloc(15 * 512);
311         if (!d->boot2)
312                 return -1;
313         memcpy(d->boot2, b2, 15 * 512);
314 #elif defined(__alpha__)
315         if (d->boot1)
316                 free(d->boot1);
317         d->boot1 = malloc(15 * 512);
318         if (!d->boot1)
319                 return -1;
320         memcpy(d->boot1, b1, 15 * 512);
321 #elif defined(__sparc64__)
322         if (d->boot1 != NULL)
323                 free(d->boot1);
324         d->boot1 = malloc(16 * 512);
325         if (d->boot1 == NULL)
326                 return (-1);
327         memcpy(d->boot1, b1, 16 * 512);
328 #elif defined(__ia64__)
329         /* nothing */
330 #else
331 /* Should be: #error "Set_Boot_Blocks: unknown arch"; */
332 #endif
333         return 0;
334 }
335
336 const char *
337 slice_type_name( int type, int subtype )
338 {
339
340         switch (type) {
341         case whole:
342                 return "whole";
343         case mbr:
344                 switch (subtype) {
345                 case 1:         return "fat (12-bit)";
346                 case 2:         return "XENIX /";
347                 case 3:         return "XENIX /usr";
348                 case 4:         return "fat (16-bit,<=32Mb)";
349                 case 5:         return "extended DOS";
350                 case 6:         return "fat (16-bit,>32Mb)";
351                 case 7:         return "NTFS/HPFS/QNX";
352                 case 8:         return "AIX bootable";
353                 case 9:         return "AIX data";
354                 case 10:        return "OS/2 bootmgr";
355                 case 11:        return "fat (32-bit)";
356                 case 12:        return "fat (32-bit,LBA)";
357                 case 14:        return "fat (16-bit,>32Mb,LBA)";
358                 case 15:        return "extended DOS, LBA";
359                 case 18:        return "Compaq Diagnostic";
360                 case 57:        return "Plan 9";
361                 case 77:        return "QNX 4.X";
362                 case 78:        return "QNX 4.X 2nd part";
363                 case 79:        return "QNX 4.X 3rd part";
364                 case 84:        return "OnTrack diskmgr";
365                 case 100:       return "Netware 2.x";
366                 case 101:       return "Netware 3.x";
367                 case 115:       return "SCO UnixWare";
368                 case 128:       return "Minix 1.1";
369                 case 129:       return "Minix 1.5";
370                 case 130:       return "linux_swap";
371                 case 131:       return "ext2fs";
372                 case 133:       return "linux extended";
373                 case 166:       return "OpenBSD FFS";   /* 0xA6 */
374                 case 168:       return "Mac OS-X";
375                 case 169:       return "NetBSD FFS";    /* 0xA9 */
376                 case 171:       return "Mac OS-X Boot";
377                 case 182:       return "OpenBSD";       /* dedicated */
378                 case 183:       return "bsd/os";
379                 case 184:       return "bsd/os swap";
380                 case 191:       return "Solaris (new)";
381                 case 238:       return "EFI GPT";
382                 case 239:       return "EFI Sys. Part.";
383                 default:        return "unknown";
384                 }
385         case fat:
386                 return "fat";
387         case freebsd:
388                 switch (subtype) {
389 #ifdef PC98
390                 case 0xc494:    return "freebsd";
391 #else
392                 case 165:       return "freebsd";
393 #endif
394                 default:        return "unknown";
395                 }
396         case extended:
397                 return "extended";
398         case part:
399                 return "part";
400         case efi:
401                 return "efi";
402         case unused:
403                 return "unused";
404         default:
405                 return "unknown";
406         }
407 }