]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libdisk/open_disk.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libdisk / open_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/gpt.h>
27 #include <paths.h>
28 #include "libdisk.h"
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <assert.h>
33
34 #ifdef DEBUG
35 #define DPRINT(x)       warn x
36 #define DPRINTX(x)      warnx x
37 #else
38 #define DPRINT(x)
39 #define DPRINTX(x)
40 #endif
41
42 struct disk *
43 Int_Open_Disk(const char *name, char *conftxt)
44 {
45         struct disk *d;
46         int i, line = 1;
47         char *p, *q, *r, *a, *b, *n, *t, *sn;
48         daddr_t o, len, off;
49         u_int l, s, ty, sc, hd, alt;
50         daddr_t lo[10];
51
52         /*
53          * Locate the disk (by name) in our sysctl output
54          */
55         for (p = conftxt; p != NULL && *p; p = strchr(p, '\n'), line++) {
56                 if (*p == '\n')
57                         p++;
58                 a = strsep(&p, " ");
59                 /* Skip anything not with index 0 */
60                 if (strcmp(a, "0"))
61                         continue;
62
63                 /* Skip anything not a disk */
64                 a = strsep(&p, " ");
65                 if (strcmp(a, "DISK"))
66                         continue;
67
68                 a = strsep(&p, " ");
69                 if (strcmp(a, name))
70                         continue;
71                 break;
72         }
73
74         q = strchr(p, '\n');
75         if (q != NULL)
76                 *q++ = '\0';
77
78         d = (struct disk *)calloc(sizeof *d, 1);
79         if(d == NULL)
80                 return NULL;
81
82         d->name = strdup(name);
83
84         a = strsep(&p, " ");    /* length in bytes */
85         len = strtoimax(a, &r, 0);
86         if (*r) {
87                 printf("libdisk: Int_Open_Disk(%s): can't parse length in line %d (r='%s')\n",
88                         name, line, r);
89                 return NULL;
90         }
91
92         a = strsep(&p, " ");    /* sectorsize */
93         s = strtoul(a, &r, 0);
94         if (*r) {
95                 printf("libdisk: Int_Open_Disk(%s): can't parse sector size in line %d (r='%s')\n",
96                         name, line, r);
97                 return NULL;
98         }
99
100         if (s == 0)
101                 return (NULL);
102         d->sector_size = s;
103         len /= s;       /* media size in number of sectors. */
104
105         if (Add_Chunk(d, 0, len, name, whole, 0, 0, "-")) {
106                 DPRINT(("Failed to add 'whole' chunk"));
107         }
108
109         /* Try to parse any fields after the sector size in the DISK entry line */
110         for (;;) {
111                 a = strsep(&p, " ");
112                 if (a == NULL)
113                         break;
114                 b = strsep(&p, " ");
115                 o = strtoimax(b, &r, 0);
116                 if (*r) {
117                         printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n",
118                                 name, a, line, r);
119                         return NULL;
120                 }
121                 if (!strcmp(a, "hd"))
122                         d->bios_hd = o;
123                 else if (!strcmp(a, "sc"))
124                         d->bios_sect = o;
125                 else
126                         printf("libdisk: Int_Open_Disk(%s): unknown parameter '%s' with value '%s' in line %d, ignored\n",
127                                 name, a, b, line);
128         }
129
130         /* Sanitize the parameters. */
131         Sanitize_Bios_Geom(d);
132
133         /*
134          * Calculate the number of cylinders this disk must have. If we have
135          * an obvious insanity, we set the number of cylinders to zero.
136          */
137         o = d->bios_hd * d->bios_sect;
138         d->bios_cyl = (o != 0) ? len / o : 0;
139
140         p = q; line++; /* p is now the start of the line _after_ the DISK entry */
141         lo[0] = 0;
142
143         for (; p != NULL && *p; p = q, line++) {
144                 sn = NULL;
145                 q = strchr(p, '\n');
146                 if (q != NULL)
147                         *q++ = '\0';
148                 a = strsep(&p, " ");    /* Index */
149                 /*
150                  * If we find index 0 again, this means we've encountered another disk, so it's safe to assume this disk
151                  * has been processed.
152                  */
153                 if (!strcmp(a, "0"))
154                         break;
155                 l = strtoimax(a, &r, 0);
156                 if (*r) {
157                         printf("libdisk: Int_Open_Disk(%s): can't parse depth '%s' in line %d (r='%s')\n",
158                                 name, a, line, r);
159                         return NULL;
160
161                 }
162                 t = strsep(&p, " ");    /* Type {SUN, BSD, MBR, PC98, GPT} */
163                 n = strsep(&p, " ");    /* name */
164                 a = strsep(&p, " ");    /* len */
165                 len = strtoimax(a, &r, 0);
166                 if (*r) {
167                         printf("libdisk: Int_Open_Disk(%s): can't parse length '%s' in line %d (r='%s')\n",
168                                 name, a, line, r);
169                         continue;
170                 }
171                 a = strsep(&p, " ");    /* secsize */
172                 s = strtoimax(a, &r, 0);
173                 if (*r) {
174                         printf("libdisk: Int_Open_Disk(%s): can't parse sector size '%s' in line %d (r='%s')\n",
175                                 name, a, line, r);
176                         continue;
177                 }
178                 for (;;) {
179                         a = strsep(&p, " ");
180                         if (a == NULL)
181                                 break;
182                         /* XXX: Slice name may include a space. */
183                         if (!strcmp(a, "sn")) {
184                                 sn = p;
185                                 break;
186                         }
187                         b = strsep(&p, " ");
188                         o = strtoimax(b, &r, 0);
189                         /* APPLE have ty as a string */
190                         if ((*r) && strcmp(t, "APPLE") &&
191                             strcmp(t, "GPT") && strcmp(t, "PART")) {
192                                 printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n",
193                                         name, a, line, r);
194                                 break;
195                         }
196                         if (!strcmp(a, "o"))
197                                 off = o;
198                         else if (!strcmp(a, "i"))
199                                 i = (!strcmp(t, "PART")) ? o - 1 : o;
200                         else if (!strcmp(a, "ty"))
201                                 ty = o;
202                         else if (!strcmp(a, "sc"))
203                                 sc = o;
204                         else if (!strcmp(a, "hd"))
205                                 hd = o;
206                         else if (!strcmp(a, "alt"))
207                                 alt = o;
208                         else if (!strcmp(a, "xs"))
209                                 t = b;
210                         else if (!strcmp(a, "xt")) {
211                                 if (*r)
212                                         sn = b;
213                                 else
214                                         ty = o;
215                         }
216                 }
217
218                 /* PLATFORM POLICY BEGIN ----------------------------------- */
219                 if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2)
220                         continue;
221                 if (platform == p_sparc64 && !strcmp(t, "SUN") &&
222                     d->chunks->part->part == NULL) {
223                         d->bios_hd = hd;
224                         d->bios_sect = sc;
225                         o = d->chunks->size / (hd * sc);
226                         o *= (hd * sc);
227                         o -= alt * hd * sc;
228                         if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
229                                 DPRINT(("Failed to add 'freebsd' chunk"));
230                         }
231                 }
232                 if (platform == p_alpha && !strcmp(t, "BSD") &&
233                     d->chunks->part->part == NULL) {
234                         if (Add_Chunk(d, 0, d->chunks->size, name, freebsd,
235                                       0, 0, "-")) {
236                                 DPRINT(("Failed to add 'freebsd' chunk"));
237                         }
238                 }
239                 if (!strcmp(t, "BSD") && i == RAW_PART)
240                         continue;
241                 /* PLATFORM POLICY END ------------------------------------- */
242
243                 off /= s;
244                 len /= s;
245                 off += lo[l - 1];
246                 lo[l] = off;
247                 if (!strcmp(t, "SUN"))
248                         i = Add_Chunk(d, off, len, n, part, 0, 0, 0);
249                 else if (!strncmp(t, "MBR", 3)) {
250                         switch (ty) {
251                         case 0xa5:
252                                 i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0);
253                                 break;
254                         case 0x01:
255                         case 0x04:
256                         case 0x06:
257                         case 0x0b:
258                         case 0x0c:
259                         case 0x0e:
260                                 i = Add_Chunk(d, off, len, n, fat, ty, 0, 0);
261                                 break;
262                         case 0xef:      /* EFI */
263                                 i = Add_Chunk(d, off, len, n, efi, ty, 0, 0);
264                                 break;
265                         default:
266                                 i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0);
267                                 break;
268                         }
269                 } else if (!strcmp(t, "BSD"))
270                         i = Add_Chunk(d, off, len, n, part, ty, 0, 0);
271                 else if (!strcmp(t, "PC98")) {
272                         switch (ty & 0x7f) {
273                         case 0x14:
274                                 i = Add_Chunk(d, off, len, n, freebsd, ty, 0,
275                                               sn);
276                                 break;
277                         case 0x20:
278                         case 0x21:
279                         case 0x22:
280                         case 0x23:
281                         case 0x24:
282                                 i = Add_Chunk(d, off, len, n, fat, ty, 0, sn);
283                                 break;
284                         default:
285                                 i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn);
286                                 break;
287                         }
288                 } else if (!strcmp(t, "GPT"))
289                         i = Add_Chunk(d, off, len, n, gpt, 0, 0, b);
290                 else if (!strcmp(t, "APPLE"))
291                         i = Add_Chunk(d, off, len, n, apple, 0, 0, sn);
292                 else
293                         ; /* Ignore unknown classes. */
294         }
295         /* PLATFORM POLICY BEGIN ------------------------------------- */
296         /* We have a chance to do things on a blank disk here */
297         if (platform == p_sparc64 && d->chunks->part->part == NULL) {
298                 hd = d->bios_hd;
299                 sc = d->bios_sect;
300                 o = d->chunks->size / (hd * sc);
301                 o *= (hd * sc);
302                 o -= 2 * hd * sc;
303                 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) {
304                         DPRINT(("Failed to add 'freebsd' chunk"));
305                 }
306         }
307         /* PLATFORM POLICY END --------------------------------------- */
308
309         return (d);
310         i = 0;
311 }