sunlabel.c revision 113688
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 113688 2003-04-18 20:27:16Z phk $"); 70 71#include <sys/types.h> 72#include <sys/param.h> 73#include <sys/disk.h> 74#include <sys/ioctl.h> 75#include <sys/sun_disklabel.h> 76#include <sys/wait.h> 77 78#include <err.h> 79#include <fcntl.h> 80#include <inttypes.h> 81#include <paths.h> 82#include <stdio.h> 83#include <stdlib.h> 84#include <string.h> 85#include <unistd.h> 86 87#define _PATH_TMPFILE "/tmp/EdDk.XXXXXXXXXX" 88#define _PATH_BOOT "/boot/boot1" 89 90static int bflag; 91static int Bflag; 92static int eflag; 93static int nflag; 94static int rflag = 1; 95static int Rflag; 96static int wflag; 97 98static int check_label(struct sun_disklabel *sl); 99static void read_label(struct sun_disklabel *sl, const char *disk); 100static void write_label(struct sun_disklabel *sl, const char *disk, 101 const char *bootpath); 102static int edit_label(struct sun_disklabel *sl, const char *disk, 103 const char *bootpath); 104static int parse_label(struct sun_disklabel *sl, const char *file); 105static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out); 106 107static uint16_t checksum(struct sun_disklabel *sl); 108 109static int parse_size(struct sun_disklabel *sl, int part, char *size); 110static int parse_offset(struct sun_disklabel *sl, int part, char *offset); 111 112static void usage(void); 113 114extern char *__progname; 115 116/* 117 * Disk label editor for sun disklabels. 118 */ 119int 120main(int ac, char **av) 121{ 122 struct sun_disklabel sl; 123 const char *bootpath; 124 const char *proto; 125 const char *disk; 126 int ch; 127 128 bootpath = _PATH_BOOT; 129 while ((ch = getopt(ac, av, "b:BenrRw")) != -1) 130 switch (ch) { 131 case 'b': 132 bflag = 1; 133 bootpath = optarg; 134 break; 135 case 'B': 136 Bflag = 1; 137 break; 138 case 'e': 139 eflag = 1; 140 break; 141 case 'n': 142 nflag = 1; 143 break; 144 case 'r': 145 rflag = 1; 146 break; 147 case 'R': 148 Rflag = 1; 149 break; 150 case 'w': 151 wflag = 1; 152 break; 153 default: 154 usage(); 155 break; 156 } 157 if (bflag && !Bflag) 158 usage(); 159 if (nflag && !(Bflag || eflag || Rflag || wflag)) 160 usage(); 161 if (eflag && (Rflag || wflag)) 162 usage(); 163 ac -= optind; 164 av += optind; 165 if (ac == 0) 166 usage(); 167 bzero(&sl, sizeof(sl)); 168 disk = av[0]; 169 if (wflag) { 170 if (ac != 2 || strcmp(av[1], "auto") != 0) 171 usage(); 172 read_label(&sl, disk); 173 bzero(sl.sl_part, sizeof(sl.sl_part)); 174 sl.sl_part[2].sdkp_cyloffset = 0; 175 sl.sl_part[2].sdkp_nsectors = sl.sl_ncylinders * 176 sl.sl_ntracks * sl.sl_nsectors; 177 write_label(&sl, disk, bootpath); 178 } else if (eflag) { 179 if (ac != 1) 180 usage(); 181 read_label(&sl, disk); 182 if (sl.sl_magic != SUN_DKMAGIC) 183 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 184 while (edit_label(&sl, disk, bootpath) != 0) 185 ; 186 } else if (Rflag) { 187 if (ac != 2) 188 usage(); 189 proto = av[1]; 190 read_label(&sl, disk); 191 if (parse_label(&sl, proto) != 0) 192 errx(1, "%s: invalid label", proto); 193 write_label(&sl, disk, bootpath); 194 } else if (Bflag) { 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 write_label(&sl, disk, bootpath); 199 } else { 200 read_label(&sl, disk); 201 if (sl.sl_magic != SUN_DKMAGIC) 202 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 203 print_label(&sl, disk, stdout); 204 } 205 return (0); 206} 207 208static int 209check_label(struct sun_disklabel *sl) 210{ 211 uint64_t nsectors; 212 uint64_t ostart; 213 uint64_t start; 214 uint64_t oend; 215 uint64_t end; 216 int i; 217 int j; 218 219 nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors; 220 if (sl->sl_part[2].sdkp_cyloffset != 0 || 221 sl->sl_part[2].sdkp_nsectors != nsectors) { 222 warnx("partition c is incorrect, must start at 0 and cover " 223 "whole disk"); 224 return (1); 225 } 226 for (i = 0; i < 8; i++) { 227 if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0) 228 continue; 229 start = (uint64_t)sl->sl_part[i].sdkp_cyloffset * 230 sl->sl_ntracks * sl->sl_nsectors; 231 end = start + sl->sl_part[i].sdkp_nsectors; 232 if (end > nsectors) { 233 warnx("partition %c extends past end of disk", 234 'a' + i); 235 return (1); 236 } 237 for (j = 0; j < 8; j++) { 238 if (j == 2 || j == i || 239 sl->sl_part[j].sdkp_nsectors == 0) 240 continue; 241 ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset * 242 sl->sl_ntracks * sl->sl_nsectors; 243 oend = ostart + sl->sl_part[j].sdkp_nsectors; 244 if ((start <= ostart && end >= oend) || 245 (start > ostart && start < oend) || 246 (end > ostart && end < oend)) { 247 warnx("partition %c overlaps partition %c", 248 'a' + i, 'a' + j); 249 return (1); 250 } 251 } 252 } 253 return (0); 254} 255 256static void 257read_label(struct sun_disklabel *sl, const char *disk) 258{ 259 char path[MAXPATHLEN]; 260 uint32_t sectorsize; 261 uint32_t fwsectors; 262 uint32_t fwheads; 263 off_t mediasize; 264 int fd; 265 266 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); 267 if ((fd = open(path, O_RDONLY)) < 0) 268 err(1, "open %s", path); 269 if (read(fd, sl, sizeof(*sl)) != sizeof(*sl)) 270 err(1, "read"); 271 if (sl->sl_magic != SUN_DKMAGIC || checksum(sl) != sl->sl_cksum) { 272 bzero(sl, sizeof(*sl)); 273 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) 274 err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk); 275 if (ioctl(fd, DIOCGSECTORSIZE, §orsize) != 0) 276 err(1, "%s: DIOCGSECTORSIZE failed", disk); 277 if (ioctl(fd, DIOCGFWSECTORS, &fwsectors) != 0) 278 fwsectors = 63; 279 if (ioctl(fd, DIOCGFWHEADS, &fwheads) != 0) { 280 if (mediasize <= 63 * 1024 * sectorsize) 281 fwheads = 1; 282 else if (mediasize <= 63 * 16 * 1024 * sectorsize) 283 fwheads = 16; 284 else 285 fwheads = 255; 286 } 287 sl->sl_rpm = 3600; 288 sl->sl_pcylinders = mediasize / (fwsectors * fwheads * 289 sectorsize); 290 sl->sl_sparespercyl = 0; 291 sl->sl_interleave = 1; 292 sl->sl_ncylinders = sl->sl_pcylinders - 2; 293 sl->sl_acylinders = 2; 294 sl->sl_nsectors = fwsectors; 295 sl->sl_ntracks = fwheads; 296 sl->sl_part[2].sdkp_cyloffset = 0; 297 sl->sl_part[2].sdkp_nsectors = sl->sl_ncylinders * 298 sl->sl_ntracks * sl->sl_nsectors; 299 if (mediasize > (off_t)4999L * 1024L * 1024L) { 300 sprintf(sl->sl_text, 301 "FreeBSD%jdG cyl %u alt %u hd %u sec %u", 302 (intmax_t)(mediasize + 512 * 1024 * 1024) / 303 (1024 * 1024 * 1024), 304 sl->sl_ncylinders, sl->sl_acylinders, 305 sl->sl_ntracks, sl->sl_nsectors); 306 } else { 307 sprintf(sl->sl_text, 308 "FreeBSD%jdM cyl %u alt %u hd %u sec %u", 309 (intmax_t)(mediasize + 512 * 1024) / (1024 * 1024), 310 sl->sl_ncylinders, sl->sl_acylinders, 311 sl->sl_ntracks, sl->sl_nsectors); 312 } 313 } 314 close(fd); 315} 316 317static void 318write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 319{ 320 char path[MAXPATHLEN]; 321 char boot[16 * 512]; 322 off_t off; 323 int bfd; 324 int fd; 325 int i; 326 327 sl->sl_magic = SUN_DKMAGIC; 328 sl->sl_cksum = checksum(sl); 329 330 if (check_label(sl) != 0) 331 errx(1, "invalid label"); 332 333 if (nflag) { 334 print_label(sl, disk, stdout); 335 } else if (rflag) { 336 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); 337 if ((fd = open(path, O_RDWR)) < 0) 338 err(1, "open %s", path); 339 if (Bflag) { 340 if ((bfd = open(bootpath, O_RDONLY)) < 0) 341 err(1, "open %s", bootpath); 342 if (read(bfd, boot, sizeof(boot)) != sizeof(boot)) 343 err(1, "read"); 344 close(bfd); 345 for (i = 0; i < 8; i++) { 346 if (sl->sl_part[i].sdkp_nsectors == 0) 347 continue; 348 off = sl->sl_part[i].sdkp_cyloffset * 349 sl->sl_ntracks * sl->sl_nsectors * 512; 350 if (lseek(fd, off, SEEK_SET) < 0) 351 err(1, "lseek"); 352 if (write(fd, boot, sizeof(boot)) != 353 sizeof(boot)) 354 err(1, "write"); 355 } 356 } 357 if (lseek(fd, 0, SEEK_SET) < 0) 358 err(1, "lseek"); 359 if (write(fd, sl, sizeof(*sl)) != sizeof(*sl)) 360 err(1, "write"); 361 close(fd); 362 } else 363 err(1, "implement!"); 364} 365 366static int 367edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 368{ 369 char tmpfil[] = _PATH_TMPFILE; 370 const char *editor; 371 int status; 372 FILE *fp; 373 pid_t pid; 374 pid_t r; 375 int fd; 376 int c; 377 378 if ((fd = mkstemp(tmpfil)) < 0) 379 err(1, "mkstemp"); 380 if ((fp = fdopen(fd, "w")) == NULL) 381 err(1, "fdopen"); 382 print_label(sl, disk, fp); 383 fflush(fp); 384 if ((pid = fork()) < 0) 385 err(1, "fork"); 386 if (pid == 0) { 387 if ((editor = getenv("EDITOR")) == NULL) 388 editor = _PATH_VI; 389 execlp(editor, editor, tmpfil, NULL); 390 err(1, "execlp %s", editor); 391 } 392 status = 0; 393 while ((r = wait(&status)) > 0 && r != pid) 394 ; 395 if (WIFEXITED(status)) { 396 if (parse_label(sl, tmpfil) == 0) { 397 fclose(fp); 398 unlink(tmpfil); 399 write_label(sl, disk, bootpath); 400 return (0); 401 } 402 printf("re-edit the label? [y]: "); 403 fflush(stdout); 404 c = getchar(); 405 if (c != EOF && c != '\n') 406 while (getchar() != '\n') 407 ; 408 if (c == 'n') { 409 fclose(fp); 410 unlink(tmpfil); 411 return (0); 412 } 413 } 414 fclose(fp); 415 unlink(tmpfil); 416 return (1); 417} 418 419static int 420parse_label(struct sun_disklabel *sl, const char *file) 421{ 422 char offset[32]; 423 char size[32]; 424 char buf[128]; 425 uint8_t part; 426 FILE *fp; 427 int line; 428 429 line = 0; 430 if ((fp = fopen(file, "r")) == NULL) 431 err(1, "fopen"); 432 bzero(sl->sl_part, sizeof(sl->sl_part)); 433 while (fgets(buf, sizeof(buf), fp) != NULL) { 434 if (buf[0] != ' ' || buf[1] != ' ') 435 continue; 436 if (sscanf(buf, " %c: %s %s\n", &part, size, offset) != 3 || 437 parse_size(sl, part - 'a', size) || 438 parse_offset(sl, part - 'a', offset)) { 439 warnx("%s: syntex error on line %d", 440 file, line); 441 fclose(fp); 442 return (1); 443 } 444 line++; 445 } 446 fclose(fp); 447 return (check_label(sl)); 448} 449 450static int 451parse_size(struct sun_disklabel *sl, int part, char *size) 452{ 453 uintmax_t nsectors; 454 uintmax_t total; 455 uintmax_t n; 456 char *p; 457 int i; 458 459 nsectors = 0; 460 n = strtoumax(size, &p, 10); 461 if (*p != '\0') { 462 if (strcmp(size, "*") == 0) { 463 total = sl->sl_ncylinders * sl->sl_ntracks * 464 sl->sl_nsectors; 465 for (i = 0; i < part; i++) { 466 if (i == 2) 467 continue; 468 nsectors += sl->sl_part[i].sdkp_nsectors; 469 } 470 n = total - nsectors; 471 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) { 472 n = roundup((n * 1024) / 512, 473 sl->sl_ntracks * sl->sl_nsectors); 474 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) { 475 n = roundup((n * 1024 * 1024) / 512, 476 sl->sl_ntracks * sl->sl_nsectors); 477 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) { 478 n = roundup((n * 1024 * 1024 * 1024) / 512, 479 sl->sl_ntracks * sl->sl_nsectors); 480 } else 481 return (-1); 482 } 483 sl->sl_part[part].sdkp_nsectors = n; 484 return (0); 485} 486 487static uint16_t 488checksum(struct sun_disklabel *sl) 489{ 490 uint16_t cksum; 491 uint16_t *sp1; 492 uint16_t *sp2; 493 494 sp1 = (u_short *)sl; 495 sp2 = (u_short *)(sl + 1) - 1; 496 cksum = 0; 497 while (sp1 < sp2) 498 cksum ^= *sp1++; 499 return (cksum); 500} 501 502static int 503parse_offset(struct sun_disklabel *sl, int part, char *offset) 504{ 505 uintmax_t nsectors; 506 uintmax_t n; 507 char *p; 508 int i; 509 510 nsectors = 0; 511 n = strtoumax(offset, &p, 10); 512 if (*p != '\0') { 513 if (strcmp(offset, "*") == 0) { 514 for (i = 0; i < part; i++) { 515 if (i == 2) 516 continue; 517 nsectors += sl->sl_part[i].sdkp_nsectors; 518 } 519 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks); 520 } else 521 return (-1); 522 } 523 sl->sl_part[part].sdkp_cyloffset = n; 524 return (0); 525} 526 527static void 528print_label(struct sun_disklabel *sl, const char *disk, FILE *out) 529{ 530 int i; 531 532 fprintf(out, 533"# /dev/%s:\n" 534"text: %s\n" 535"bytes/sectors: 512\n" 536"sectors/cylinder: %d\n" 537"sectors/unit: %d\n" 538"\n" 539"8 partitions:\n" 540"#\n" 541"# Size is in sectors, use %%dK, %%dM or %%dG to specify in kilobytes,\n" 542"# megabytes or gigabytes respectively, or '*' to specify rest of disk.\n" 543"# Offset is in cylinders, use '*' to calculate offsets automatically.\n" 544"#\n" 545"# size offset\n" 546"# ---------- ----------\n", 547 disk, 548 sl->sl_text, 549 sl->sl_nsectors * sl->sl_ntracks, 550 sl->sl_nsectors * sl->sl_ntracks * sl->sl_ncylinders); 551 for (i = 0; i < 8; i++) { 552 if (sl->sl_part[i].sdkp_nsectors == 0) 553 continue; 554 fprintf(out, " %c: %10u %10u\n", 555 'a' + i, 556 sl->sl_part[i].sdkp_nsectors, 557 sl->sl_part[i].sdkp_cyloffset); 558 } 559} 560 561static void 562usage(void) 563{ 564 565 fprintf(stderr, "usage:" 566"\t%s [-r] disk\n" 567"\t\t(to read label)\n" 568"\t%s -B [-b boot1] [-n] disk\n" 569"\t\t(to install boot program only)\n" 570"\t%s -R [-B [-b boot1]] [-r] [-n] disk protofile\n" 571"\t\t(to restore label)\n" 572"\t%s -e [-B [-b boot1]] [-r] [-n] disk\n" 573"\t\t(to edit label)\n" 574"\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n" 575"\t\t(to write default label)\n", 576 __progname, 577 __progname, 578 __progname, 579 __progname, 580 __progname); 581 exit(1); 582} 583