sunlabel.c revision 110130
1/*- 2 * Copyright (c) 2003 Jake Burkholder. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26/* 27 * Copyright (c) 1994, 1995 Gordon W. Ross 28 * Copyright (c) 1994 Theo de Raadt 29 * All rights reserved. 30 * Copyright (c) 1987, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * Symmetric Computer Systems. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * This product includes software developed by Theo de Raadt. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $ 66 */ 67 68#include <sys/cdefs.h> 69__FBSDID("$FreeBSD: head/sbin/sunlabel/sunlabel.c 110130 2003-01-31 07:03:25Z jake $"); 70 71#include <sys/types.h> 72#include <sys/param.h> 73#include <sys/sysctl.h> 74#include <sys/sun_disklabel.h> 75#include <sys/wait.h> 76 77#include <err.h> 78#include <fcntl.h> 79#include <inttypes.h> 80#include <paths.h> 81#include <stdio.h> 82#include <stdlib.h> 83#include <string.h> 84#include <unistd.h> 85 86#define _PATH_TMPFILE "/tmp/EdDk.XXXXXXXXXX" 87#define _PATH_BOOT "/boot/boot1" 88 89static int bflag; 90static int Bflag; 91static int eflag; 92static int nflag; 93static int rflag = 1; 94static int Rflag; 95static int wflag; 96 97static int check_label(struct sun_disklabel *sl); 98static void read_label(struct sun_disklabel *sl, const char *disk); 99static void write_label(struct sun_disklabel *sl, const char *disk, 100 const char *bootpath); 101static int edit_label(struct sun_disklabel *sl, const char *disk, 102 const char *bootpath); 103static int parse_label(struct sun_disklabel *sl, const char *file); 104static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out); 105 106static int parse_size(struct sun_disklabel *sl, int part, char *size); 107static int parse_offset(struct sun_disklabel *sl, int part, char *offset); 108 109static void usage(void); 110 111extern char *__progname; 112 113/* 114 * Disk label editor for sun disklabels. 115 */ 116int 117main(int ac, char **av) 118{ 119 struct sun_disklabel sl; 120 const char *bootpath; 121 const char *proto; 122 const char *disk; 123 int ch; 124 125 bootpath = _PATH_BOOT; 126 while ((ch = getopt(ac, av, "b:BenrRw")) != -1) 127 switch (ch) { 128 case 'b': 129 bflag = 1; 130 bootpath = optarg; 131 break; 132 case 'B': 133 Bflag = 1; 134 break; 135 case 'e': 136 eflag = 1; 137 break; 138 case 'n': 139 nflag = 1; 140 break; 141 case 'r': 142 rflag = 1; 143 break; 144 case 'R': 145 Rflag = 1; 146 break; 147 case 'w': 148 wflag = 1; 149 break; 150 default: 151 usage(); 152 break; 153 } 154 if (bflag && !Bflag) 155 usage(); 156 if (nflag && !(Bflag || eflag || Rflag || wflag)) 157 usage(); 158 if (eflag && (Rflag || wflag)) 159 usage(); 160 ac -= optind; 161 av += optind; 162 if (ac == 0) 163 usage(); 164 bzero(&sl, sizeof(sl)); 165 disk = av[0]; 166 if (wflag) { 167 if (ac != 2 || strcmp(av[1], "auto") != 0) 168 usage(); 169 read_label(&sl, disk); 170 bzero(sl.sl_part, sizeof(sl.sl_part)); 171 sl.sl_part[2].sdkp_cyloffset = 0; 172 sl.sl_part[2].sdkp_nsectors = sl.sl_ncylinders * 173 sl.sl_ntracks * sl.sl_nsectors; 174 write_label(&sl, disk, bootpath); 175 } else if (eflag) { 176 if (ac != 1) 177 usage(); 178 read_label(&sl, disk); 179 if (sl.sl_magic != SUN_DKMAGIC) 180 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 181 while (edit_label(&sl, disk, bootpath) != 0) 182 ; 183 } else if (Rflag) { 184 if (ac != 2) 185 usage(); 186 proto = av[1]; 187 read_label(&sl, disk); 188 write_label(&sl, disk, bootpath); 189 } else if (Bflag) { 190 read_label(&sl, disk); 191 if (sl.sl_magic != SUN_DKMAGIC) 192 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 193 write_label(&sl, disk, bootpath); 194 } else { 195 read_label(&sl, disk); 196 if (sl.sl_magic != SUN_DKMAGIC) 197 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 198 print_label(&sl, disk, stdout); 199 } 200 return (0); 201} 202 203static int 204check_label(struct sun_disklabel *sl) 205{ 206 uint64_t nsectors; 207 uint64_t ostart; 208 uint64_t start; 209 uint64_t oend; 210 uint64_t end; 211 int i; 212 int j; 213 214 nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors; 215 for (i = 0; i < 8; i++) { 216 if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0) 217 continue; 218 start = (uint64_t)sl->sl_part[i].sdkp_cyloffset * 219 sl->sl_ntracks * sl->sl_nsectors; 220 end = start + sl->sl_part[i].sdkp_nsectors; 221 if (end > nsectors) { 222 warnx("partition %c extends past end of disk", 223 'a' + i); 224 return (1); 225 } 226 for (j = 0; j < 8; j++) { 227 if (j == 2 || j == i || 228 sl->sl_part[j].sdkp_nsectors == 0) 229 continue; 230 ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset * 231 sl->sl_ntracks * sl->sl_nsectors; 232 oend = ostart + sl->sl_part[j].sdkp_nsectors; 233 if ((start <= ostart && end >= oend) || 234 (start > ostart && start < oend) || 235 (end > ostart && end < oend)) { 236 warnx("partition %c overlaps partition %c", 237 'a' + i, 'a' + j); 238 return (1); 239 } 240 } 241 } 242 return (0); 243} 244 245static void 246read_label(struct sun_disklabel *sl, const char *disk) 247{ 248 uint32_t bytepercyl; 249 uint32_t bytepersec; 250 uint32_t acylinders; 251 uint32_t nsectors; 252 uint32_t ntracks; 253 uintmax_t offset; 254 uintmax_t size; 255 char name[64]; 256 char *text; 257 char *p, *s; 258 size_t len; 259 int i; 260 int n; 261 262 if (sysctlbyname("kern.geom.conftxt", NULL, &len, NULL, 0) < 0) 263 err(1, "sysctlbyname"); 264 if ((text = malloc(len)) == NULL) 265 err(1, "malloc"); 266 if (sysctlbyname("kern.geom.conftxt", text, &len, NULL, 0) < 0) 267 err(1, "sysctlbyname"); 268 bytepercyl = 0; 269 for (p = text; (s = strsep(&p, "\n")) != NULL;) { 270 n = sscanf(s, "%*u DISK %s %ju %u hd %u sc %u\n", name, &size, 271 &bytepersec, &ntracks, &nsectors); 272 if (n == 5) { 273 if (strncmp(name, disk, strlen(disk)) != 0) 274 continue; 275 bytepercyl = ntracks * nsectors * bytepersec; 276 sl->sl_pcylinders = size / bytepercyl; 277 sl->sl_acylinders = 2; 278 sl->sl_nsectors = nsectors; 279 sl->sl_ntracks = ntracks; 280 continue; 281 } 282 n = sscanf(s, 283 "%*u SUN %s %ju %*u i %u o %ju sc %*u hd %*u alt %u", 284 name, &size, &i, &offset, &acylinders); 285 if (n == 5) { 286 if (strncmp(name, disk, strlen(disk)) != 0) 287 continue; 288 sl->sl_acylinders = acylinders; 289 sl->sl_part[i].sdkp_cyloffset = offset / bytepercyl; 290 sl->sl_part[i].sdkp_nsectors = size / bytepersec; 291 sl->sl_magic = SUN_DKMAGIC; 292 continue; 293 } 294 } 295 if (bytepercyl == 0) 296 errx(1, "disk %s not found", disk); 297 sl->sl_ncylinders = sl->sl_pcylinders - 298 sl->sl_acylinders; 299 sl->sl_interleave = 1; 300 sl->sl_sparespercyl = 0; 301 sl->sl_rpm = 3600; 302 size = (uint64_t)sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors; 303 if (size > 4999 * 1024 * 2) { 304 sprintf(sl->sl_text, "FreeBSD%luG cyl %u alt %u hd %u sec %u", 305 (size + 1024 * 1024) / (2 * 1024 * 1024), 306 sl->sl_ncylinders, sl->sl_acylinders, 307 sl->sl_ntracks, sl->sl_nsectors); 308 } else { 309 sprintf(sl->sl_text, "FreeBSD%luM cyl %u alt %u hd %u sec %u", 310 (size + 1024) / (2 * 1024), 311 sl->sl_ncylinders, sl->sl_acylinders, 312 sl->sl_ntracks, sl->sl_nsectors); 313 } 314} 315 316static void 317write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 318{ 319 char path[MAXPATHLEN]; 320 char boot[16 * 512]; 321 uint16_t cksum; 322 uint16_t *sp1; 323 uint16_t *sp2; 324 off_t off; 325 int bfd; 326 int fd; 327 int i; 328 329 sl->sl_magic = SUN_DKMAGIC; 330 331 sp1 = (u_short *)sl; 332 sp2 = (u_short *)(sl + 1); 333 cksum = 0; 334 while (sp1 < sp2) 335 cksum ^= *sp1++; 336 sl->sl_cksum = cksum; 337 338 if (check_label(sl) != 0) 339 errx(1, "invalid label"); 340 341 if (nflag) { 342 print_label(sl, disk, stdout); 343 } else if (rflag) { 344 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); 345 if ((fd = open(path, O_RDWR)) < 0) 346 err(1, "open %s", path); 347 if (Bflag) { 348 if ((bfd = open(bootpath, O_RDONLY)) < 0) 349 err(1, "open %s", bootpath); 350 if (read(bfd, boot, sizeof(boot)) != sizeof(boot)) 351 err(1, "read"); 352 close(bfd); 353 for (i = 0; i < 8; i++) { 354 if (sl->sl_part[i].sdkp_nsectors == 0) 355 continue; 356 off = sl->sl_part[i].sdkp_cyloffset * 357 sl->sl_ntracks * sl->sl_nsectors * 512; 358 if (lseek(fd, off, SEEK_SET) < 0) 359 err(1, "lseek"); 360 if (write(fd, boot, sizeof(boot)) != 361 sizeof(boot)) 362 err(1, "write"); 363 } 364 } 365 if (lseek(fd, 0, SEEK_SET) < 0) 366 err(1, "lseek"); 367 if (write(fd, sl, sizeof(*sl)) != sizeof(*sl)) 368 err(1, "write"); 369 close(fd); 370 } else 371 err(1, "implement!"); 372} 373 374static int 375edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 376{ 377 char tmpfil[] = _PATH_TMPFILE; 378 const char *editor; 379 int status; 380 FILE *fp; 381 pid_t pid; 382 pid_t r; 383 int fd; 384 int c; 385 386 if ((fd = mkstemp(tmpfil)) < 0) 387 err(1, "mkstemp"); 388 if ((fp = fdopen(fd, "w")) == NULL) 389 err(1, "fdopen"); 390 print_label(sl, disk, fp); 391 fflush(fp); 392 if ((pid = fork()) < 0) 393 err(1, "fork"); 394 if (pid == 0) { 395 if ((editor = getenv("EDITOR")) == NULL) 396 editor = _PATH_VI; 397 execlp(editor, editor, tmpfil, NULL); 398 err(1, "execlp %s", editor); 399 } 400 status = 0; 401 while ((r = wait(&status)) > 0 && r != pid) 402 ; 403 if (WIFEXITED(status)) { 404 if (parse_label(sl, tmpfil) == 0) { 405 fclose(fp); 406 unlink(tmpfil); 407 write_label(sl, disk, bootpath); 408 return (0); 409 } 410 printf("re-edit the label? [y]: "); 411 fflush(stdout); 412 c = getchar(); 413 if (c != EOF && c != '\n') 414 while (getchar() != '\n') 415 ; 416 if (c == 'n') { 417 fclose(fp); 418 unlink(tmpfil); 419 return (0); 420 } 421 } 422 fclose(fp); 423 unlink(tmpfil); 424 return (1); 425} 426 427static int 428parse_label(struct sun_disklabel *sl, const char *file) 429{ 430 char offset[32]; 431 char size[32]; 432 char buf[128]; 433 uint8_t part; 434 FILE *fp; 435 int line; 436 437 line = 0; 438 if ((fp = fopen(file, "r")) == NULL) 439 err(1, "fopen"); 440 bzero(sl->sl_part, sizeof(sl->sl_part)); 441 while (fgets(buf, sizeof(buf), fp) != NULL) { 442 if (buf[0] != ' ' || buf[1] != ' ') 443 continue; 444 if (sscanf(buf, " %c: %s %s\n", &part, size, offset) != 3 || 445 parse_size(sl, part - 'a', size) || 446 parse_offset(sl, part - 'a', offset)) { 447 warnx("%s: syntex error on line %d", 448 file, line); 449 fclose(fp); 450 return (1); 451 } 452 line++; 453 } 454 fclose(fp); 455 sl->sl_part[2].sdkp_cyloffset = 0; 456 sl->sl_part[2].sdkp_nsectors = sl->sl_ncylinders * 457 sl->sl_ntracks * sl->sl_nsectors; 458 return (check_label(sl)); 459} 460 461static int 462parse_size(struct sun_disklabel *sl, int part, char *size) 463{ 464 uintmax_t nsectors; 465 uintmax_t total; 466 uintmax_t n; 467 char *p; 468 int i; 469 470 nsectors = 0; 471 n = strtoumax(size, &p, 10); 472 if (*p != '\0') { 473 if (strcmp(size, "*") == 0) { 474 total = sl->sl_ncylinders * sl->sl_ntracks * 475 sl->sl_nsectors; 476 for (i = 0; i < part; i++) { 477 if (i == 2) 478 continue; 479 nsectors += sl->sl_part[i].sdkp_nsectors; 480 } 481 n = total - nsectors; 482 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) { 483 n = roundup((n * 1024) / 512, 484 sl->sl_ntracks * sl->sl_nsectors); 485 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) { 486 n = roundup((n * 1024 * 1024) / 512, 487 sl->sl_ntracks * sl->sl_nsectors); 488 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) { 489 n = roundup((n * 1024 * 1024 * 1024) / 512, 490 sl->sl_ntracks * sl->sl_nsectors); 491 } else 492 return (-1); 493 } 494 sl->sl_part[part].sdkp_nsectors = n; 495 return (0); 496} 497 498static int 499parse_offset(struct sun_disklabel *sl, int part, char *offset) 500{ 501 uintmax_t nsectors; 502 uintmax_t n; 503 char *p; 504 int i; 505 506 nsectors = 0; 507 n = strtoumax(offset, &p, 10); 508 if (*p != '\0') { 509 if (strcmp(offset, "*") == 0) { 510 for (i = 0; i < part; i++) { 511 if (i == 2) 512 continue; 513 nsectors += sl->sl_part[i].sdkp_nsectors; 514 } 515 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks); 516 } else 517 return (-1); 518 } 519 sl->sl_part[part].sdkp_cyloffset = n; 520 return (0); 521} 522 523static void 524print_label(struct sun_disklabel *sl, const char *disk, FILE *out) 525{ 526 int i; 527 528 fprintf(out, 529"# /dev/%s:\n" 530"text: %s\n" 531"bytes/sectors: 512\n" 532"sectors/cylinder: %d\n" 533"sectors/unit: %d\n" 534"\n" 535"8 partitions:\n" 536"#\n" 537"# Size is in sectors, use %%dK, %%dM or %%dG to specify in kilobytes,\n" 538"# megabytes or gigabytes respectively, or '*' to specify rest of disk.\n" 539"# Offset is in cylinders, use '*' to calculate offsets automatically.\n" 540"#\n" 541"# size offset\n" 542"# ---------- ----------\n", 543 disk, 544 sl->sl_text, 545 sl->sl_nsectors * sl->sl_ntracks, 546 sl->sl_nsectors * sl->sl_ntracks * sl->sl_ncylinders); 547 for (i = 0; i < 8; i++) { 548 if (sl->sl_part[i].sdkp_nsectors == 0) 549 continue; 550 fprintf(out, " %c: %10u %10u\n", 551 'a' + i, 552 sl->sl_part[i].sdkp_nsectors, 553 sl->sl_part[i].sdkp_cyloffset); 554 } 555} 556 557static void 558usage(void) 559{ 560 561 fprintf(stderr, "usage:" 562"\t%s [-r] disk\n" 563"\t\t(to read label)\n" 564"\t%s -B [-b boot1] [-n] disk\n" 565"\t\t(to install boot program only)\n" 566"\t%s -R [-B [-b boot1]] [-r] [-n] disk protofile\n" 567"\t\t(to restore label)\n" 568"\t%s -e [-B [-b boot1]] [-r] [-n] disk\n" 569"\t\t(to edit label)\n" 570"\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n" 571"\t\t(to write default label)\n", 572 __progname, 573 __progname, 574 __progname, 575 __progname, 576 __progname); 577 exit(1); 578} 579