open_disk.c revision 188408
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: head/lib/libdisk/open_disk.c 188408 2009-02-09 21:34:06Z lulf $"); 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 42struct disk * 43Int_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} 312