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