open_disk.c revision 172285
1226584Sdim/* 2226584Sdim * ---------------------------------------------------------------------------- 3226584Sdim * "THE BEER-WARE LICENSE" (Revision 42): 4226584Sdim * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 5226584Sdim * can do whatever you want with this stuff. If we meet some day, and you think 6226584Sdim * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7226584Sdim * ---------------------------------------------------------------------------- 8226584Sdim */ 9226584Sdim 10226584Sdim#include <sys/cdefs.h> 11226584Sdim__FBSDID("$FreeBSD: head/lib/libdisk/open_disk.c 172285 2007-09-21 16:19:50Z marcel $"); 12226584Sdim 13226584Sdim#include <stdio.h> 14226584Sdim#include <stdlib.h> 15226584Sdim#include <unistd.h> 16226584Sdim#include <fcntl.h> 17226584Sdim#include <string.h> 18234353Sdim#include <inttypes.h> 19234353Sdim#include <err.h> 20226584Sdim#include <sys/sysctl.h> 21226584Sdim#include <sys/stdint.h> 22226584Sdim#include <sys/types.h> 23226584Sdim#include <sys/stat.h> 24226584Sdim#include <sys/ioctl.h> 25226584Sdim#include <sys/disklabel.h> 26226584Sdim#include <sys/gpt.h> 27226584Sdim#include <paths.h> 28226584Sdim#include "libdisk.h" 29226584Sdim 30226584Sdim#include <ctype.h> 31226584Sdim#include <errno.h> 32226584Sdim#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 /* 131 * Calculate the number of cylinders this disk must have. If we have 132 * an obvious insanity, we set the number of cylinders to zero. 133 */ 134 o = d->bios_hd * d->bios_sect; 135 d->bios_cyl = (o != 0) ? len / o : 0; 136 137 p = q; line++; /* p is now the start of the line _after_ the DISK entry */ 138 lo[0] = 0; 139 140 for (; p != NULL && *p; p = q, line++) { 141 sn = NULL; 142 q = strchr(p, '\n'); 143 if (q != NULL) 144 *q++ = '\0'; 145 a = strsep(&p, " "); /* Index */ 146 /* 147 * If we find index 0 again, this means we've encountered another disk, so it's safe to assume this disk 148 * has been processed. 149 */ 150 if (!strcmp(a, "0")) 151 break; 152 l = strtoimax(a, &r, 0); 153 if (*r) { 154 printf("libdisk: Int_Open_Disk(%s): can't parse depth '%s' in line %d (r='%s')\n", 155 name, a, line, r); 156 return NULL; 157 158 } 159 t = strsep(&p, " "); /* Type {SUN, BSD, MBR, PC98, GPT} */ 160 n = strsep(&p, " "); /* name */ 161 a = strsep(&p, " "); /* len */ 162 len = strtoimax(a, &r, 0); 163 if (*r) { 164 printf("libdisk: Int_Open_Disk(%s): can't parse length '%s' in line %d (r='%s')\n", 165 name, a, line, r); 166 continue; 167 } 168 a = strsep(&p, " "); /* secsize */ 169 s = strtoimax(a, &r, 0); 170 if (*r) { 171 printf("libdisk: Int_Open_Disk(%s): can't parse sector size '%s' in line %d (r='%s')\n", 172 name, a, line, r); 173 continue; 174 } 175 for (;;) { 176 a = strsep(&p, " "); 177 if (a == NULL) 178 break; 179 /* XXX: Slice name may include a space. */ 180 if (!strcmp(a, "sn")) { 181 sn = p; 182 break; 183 } 184 b = strsep(&p, " "); 185 o = strtoimax(b, &r, 0); 186 /* APPLE have ty as a string */ 187 if ((*r) && strcmp(t, "APPLE") && 188 strcmp(t, "GPT") && strcmp(t, "PART")) { 189 printf("libdisk: Int_Open_Disk(%s): can't parse parameter '%s' in line %d (r='%s')\n", 190 name, a, line, r); 191 break; 192 } 193 if (!strcmp(a, "o")) 194 off = o; 195 else if (!strcmp(a, "i")) 196 i = o; 197 else if (!strcmp(a, "ty")) 198 ty = o; 199 else if (!strcmp(a, "sc")) 200 sc = o; 201 else if (!strcmp(a, "hd")) 202 hd = o; 203 else if (!strcmp(a, "alt")) 204 alt = o; 205 } 206 207 /* PLATFORM POLICY BEGIN ----------------------------------- */ 208 if (platform == p_sparc64 && !strcmp(t, "SUN") && i == 2) 209 continue; 210 if (platform == p_sparc64 && !strcmp(t, "SUN") && 211 d->chunks->part->part == NULL) { 212 d->bios_hd = hd; 213 d->bios_sect = sc; 214 o = d->chunks->size / (hd * sc); 215 o *= (hd * sc); 216 o -= alt * hd * sc; 217 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) { 218 DPRINT(("Failed to add 'freebsd' chunk")); 219 } 220 } 221 if (platform == p_alpha && !strcmp(t, "BSD") && 222 d->chunks->part->part == NULL) { 223 if (Add_Chunk(d, 0, d->chunks->size, name, freebsd, 224 0, 0, "-")) { 225 DPRINT(("Failed to add 'freebsd' chunk")); 226 } 227 } 228 if (!strcmp(t, "BSD") && i == RAW_PART) 229 continue; 230 /* PLATFORM POLICY END ------------------------------------- */ 231 232 off /= s; 233 len /= s; 234 off += lo[l - 1]; 235 lo[l] = off; 236 if (!strcmp(t, "SUN")) 237 i = Add_Chunk(d, off, len, n, part, 0, 0, 0); 238 else if (!strncmp(t, "MBR", 3)) { 239 switch (ty) { 240 case 0xa5: 241 i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 0); 242 break; 243 case 0x01: 244 case 0x04: 245 case 0x06: 246 case 0x0b: 247 case 0x0c: 248 case 0x0e: 249 i = Add_Chunk(d, off, len, n, fat, ty, 0, 0); 250 break; 251 case 0xef: /* EFI */ 252 i = Add_Chunk(d, off, len, n, efi, ty, 0, 0); 253 break; 254 default: 255 i = Add_Chunk(d, off, len, n, mbr, ty, 0, 0); 256 break; 257 } 258 } else if (!strcmp(t, "BSD")) 259 i = Add_Chunk(d, off, len, n, part, ty, 0, 0); 260 else if (!strcmp(t, "PC98")) { 261 switch (ty & 0x7f) { 262 case 0x14: 263 i = Add_Chunk(d, off, len, n, freebsd, ty, 0, 264 sn); 265 break; 266 case 0x20: 267 case 0x21: 268 case 0x22: 269 case 0x23: 270 case 0x24: 271 i = Add_Chunk(d, off, len, n, fat, ty, 0, sn); 272 break; 273 default: 274 i = Add_Chunk(d, off, len, n, pc98, ty, 0, sn); 275 break; 276 } 277 } else if (!strcmp(t, "GPT")) 278 i = Add_Chunk(d, off, len, n, gpt, 0, 0, b); 279 else if (!strcmp(t, "APPLE")) 280 i = Add_Chunk(d, off, len, n, apple, 0, 0, sn); 281 else if (!strcmp(t, "PART")) { 282#ifdef __powerpc__ 283 i = Add_Chunk(d, off, len, n, apple, 0, 0, sn); 284#endif 285 } else 286 ; /* Ignore unknown classes. */ 287 } 288 /* PLATFORM POLICY BEGIN ------------------------------------- */ 289 /* We have a chance to do things on a blank disk here */ 290 if (platform == p_sparc64 && d->chunks->part->part == NULL) { 291 hd = d->bios_hd; 292 sc = d->bios_sect; 293 o = d->chunks->size / (hd * sc); 294 o *= (hd * sc); 295 o -= 2 * hd * sc; 296 if (Add_Chunk(d, 0, o, name, freebsd, 0, 0, "-")) { 297 DPRINT(("Failed to add 'freebsd' chunk")); 298 } 299 } 300 /* PLATFORM POLICY END --------------------------------------- */ 301 302 return (d); 303 i = 0; 304} 305