]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libdisk/disk.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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 #elif defined(__mips__)
56         p_mips
57 #else
58         IHAVENOIDEA
59 #endif
60         ;
61
62 const char *
63 chunk_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
81 struct disk *
82 Open_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
112 void
113 Debug_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
142 void
143 Free_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
172 void
173 Collapse_Disk(struct disk *d)
174 {
175
176         while (Collapse_Chunk(d, d->chunks))
177                 ;
178 }
179 #endif
180
181 static int
182 qstrcmp(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
190 char **
191 Disk_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
243 void
244 Set_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
247 void
248 Set_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
302 int
303 Set_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
340 const char *
341 slice_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 }