sunlabel.c revision 113824
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 113824 2003-04-21 20:38:15Z 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 int parse_size(struct sun_disklabel *sl, int part, char *size); 108static int parse_offset(struct sun_disklabel *sl, int part, char *offset); 109 110static void usage(void); 111 112extern char *__progname; 113 114/* 115 * Disk label editor for sun disklabels. 116 */ 117int 118main(int ac, char **av) 119{ 120 struct sun_disklabel sl; 121 const char *bootpath; 122 const char *proto; 123 const char *disk; 124 int ch; 125 126 bootpath = _PATH_BOOT; 127 while ((ch = getopt(ac, av, "b:BenrRw")) != -1) 128 switch (ch) { 129 case 'b': 130 bflag = 1; 131 bootpath = optarg; 132 break; 133 case 'B': 134 Bflag = 1; 135 break; 136 case 'e': 137 eflag = 1; 138 break; 139 case 'n': 140 nflag = 1; 141 break; 142 case 'r': 143 rflag = 1; 144 break; 145 case 'R': 146 Rflag = 1; 147 break; 148 case 'w': 149 wflag = 1; 150 break; 151 default: 152 usage(); 153 break; 154 } 155 if (bflag && !Bflag) 156 usage(); 157 if (nflag && !(Bflag || eflag || Rflag || wflag)) 158 usage(); 159 if (eflag && (Rflag || wflag)) 160 usage(); 161 ac -= optind; 162 av += optind; 163 if (ac == 0) 164 usage(); 165 bzero(&sl, sizeof(sl)); 166 disk = av[0]; 167 if (wflag) { 168 if (ac != 2 || strcmp(av[1], "auto") != 0) 169 usage(); 170 read_label(&sl, disk); 171 bzero(sl.sl_part, sizeof(sl.sl_part)); 172 sl.sl_part[SUN_RAWPART].sdkp_cyloffset = 0; 173 sl.sl_part[SUN_RAWPART].sdkp_nsectors = sl.sl_ncylinders * 174 sl.sl_ntracks * sl.sl_nsectors; 175 write_label(&sl, disk, bootpath); 176 } else if (eflag) { 177 if (ac != 1) 178 usage(); 179 read_label(&sl, disk); 180 if (sl.sl_magic != SUN_DKMAGIC) 181 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 182 while (edit_label(&sl, disk, bootpath) != 0) 183 ; 184 } else if (Rflag) { 185 if (ac != 2) 186 usage(); 187 proto = av[1]; 188 read_label(&sl, disk); 189 if (parse_label(&sl, proto) != 0) 190 errx(1, "%s: invalid label", proto); 191 write_label(&sl, disk, bootpath); 192 } else if (Bflag) { 193 read_label(&sl, disk); 194 if (sl.sl_magic != SUN_DKMAGIC) 195 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 196 write_label(&sl, disk, bootpath); 197 } else { 198 read_label(&sl, disk); 199 if (sl.sl_magic != SUN_DKMAGIC) 200 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 201 print_label(&sl, disk, stdout); 202 } 203 return (0); 204} 205 206static int 207check_label(struct sun_disklabel *sl) 208{ 209 uint64_t nsectors; 210 uint64_t ostart; 211 uint64_t start; 212 uint64_t oend; 213 uint64_t end; 214 int i; 215 int j; 216 217 nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors; 218 if (sl->sl_part[SUN_RAWPART].sdkp_cyloffset != 0 || 219 sl->sl_part[SUN_RAWPART].sdkp_nsectors != nsectors) { 220 warnx("partition c is incorrect, must start at 0 and cover " 221 "whole disk"); 222 return (1); 223 } 224 for (i = 0; i < SUN_NPART; i++) { 225 if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0) 226 continue; 227 start = (uint64_t)sl->sl_part[i].sdkp_cyloffset * 228 sl->sl_ntracks * sl->sl_nsectors; 229 end = start + sl->sl_part[i].sdkp_nsectors; 230 if (end > nsectors) { 231 warnx("partition %c extends past end of disk", 232 'a' + i); 233 return (1); 234 } 235 for (j = 0; j < SUN_NPART; j++) { 236 if (j == 2 || j == i || 237 sl->sl_part[j].sdkp_nsectors == 0) 238 continue; 239 ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset * 240 sl->sl_ntracks * sl->sl_nsectors; 241 oend = ostart + sl->sl_part[j].sdkp_nsectors; 242 if ((start <= ostart && end >= oend) || 243 (start > ostart && start < oend) || 244 (end > ostart && end < oend)) { 245 warnx("partition %c overlaps partition %c", 246 'a' + i, 'a' + j); 247 return (1); 248 } 249 } 250 } 251 return (0); 252} 253 254static void 255read_label(struct sun_disklabel *sl, const char *disk) 256{ 257 char path[MAXPATHLEN]; 258 uint32_t sectorsize; 259 uint32_t fwsectors; 260 uint32_t fwheads; 261 off_t mediasize; 262 char buf[SUN_SIZE]; 263 int fd, error; 264 265 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); 266 if ((fd = open(path, O_RDONLY)) < 0) 267 err(1, "open %s", path); 268 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 269 err(1, "read"); 270 error = sunlabel_dec(buf, sl); 271 if (error) { 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[SUN_RAWPART].sdkp_cyloffset = 0; 297 sl->sl_part[SUN_RAWPART].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 char buf[SUN_SIZE]; 323 off_t off; 324 int bfd; 325 int fd; 326 int i; 327 328 sl->sl_magic = SUN_DKMAGIC; 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 < SUN_NPART; 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 bzero(buf, sizeof(buf)); 360 sunlabel_enc(buf, sl); 361 362 if (write(fd, buf, sizeof(buf)) != sizeof(buf)) 363 err(1, "write"); 364 close(fd); 365 } else 366 err(1, "implement!"); 367} 368 369static int 370edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 371{ 372 char tmpfil[] = _PATH_TMPFILE; 373 const char *editor; 374 int status; 375 FILE *fp; 376 pid_t pid; 377 pid_t r; 378 int fd; 379 int c; 380 381 if ((fd = mkstemp(tmpfil)) < 0) 382 err(1, "mkstemp"); 383 if ((fp = fdopen(fd, "w")) == NULL) 384 err(1, "fdopen"); 385 print_label(sl, disk, fp); 386 fflush(fp); 387 if ((pid = fork()) < 0) 388 err(1, "fork"); 389 if (pid == 0) { 390 if ((editor = getenv("EDITOR")) == NULL) 391 editor = _PATH_VI; 392 execlp(editor, editor, tmpfil, NULL); 393 err(1, "execlp %s", editor); 394 } 395 status = 0; 396 while ((r = wait(&status)) > 0 && r != pid) 397 ; 398 if (WIFEXITED(status)) { 399 if (parse_label(sl, tmpfil) == 0) { 400 fclose(fp); 401 unlink(tmpfil); 402 write_label(sl, disk, bootpath); 403 return (0); 404 } 405 printf("re-edit the label? [y]: "); 406 fflush(stdout); 407 c = getchar(); 408 if (c != EOF && c != '\n') 409 while (getchar() != '\n') 410 ; 411 if (c == 'n') { 412 fclose(fp); 413 unlink(tmpfil); 414 return (0); 415 } 416 } 417 fclose(fp); 418 unlink(tmpfil); 419 return (1); 420} 421 422static int 423parse_label(struct sun_disklabel *sl, const char *file) 424{ 425 char offset[32]; 426 char size[32]; 427 char buf[128]; 428 uint8_t part; 429 FILE *fp; 430 int line; 431 432 line = 0; 433 if ((fp = fopen(file, "r")) == NULL) 434 err(1, "fopen"); 435 bzero(sl->sl_part, sizeof(sl->sl_part)); 436 while (fgets(buf, sizeof(buf), fp) != NULL) { 437 if (buf[0] != ' ' || buf[1] != ' ') 438 continue; 439 if (sscanf(buf, " %c: %s %s\n", &part, size, offset) != 3 || 440 parse_size(sl, part - 'a', size) || 441 parse_offset(sl, part - 'a', offset)) { 442 warnx("%s: syntex error on line %d", 443 file, line); 444 fclose(fp); 445 return (1); 446 } 447 line++; 448 } 449 fclose(fp); 450 return (check_label(sl)); 451} 452 453static int 454parse_size(struct sun_disklabel *sl, int part, char *size) 455{ 456 uintmax_t nsectors; 457 uintmax_t total; 458 uintmax_t n; 459 char *p; 460 int i; 461 462 nsectors = 0; 463 n = strtoumax(size, &p, 10); 464 if (*p != '\0') { 465 if (strcmp(size, "*") == 0) { 466 total = sl->sl_ncylinders * sl->sl_ntracks * 467 sl->sl_nsectors; 468 for (i = 0; i < part; i++) { 469 if (i == 2) 470 continue; 471 nsectors += sl->sl_part[i].sdkp_nsectors; 472 } 473 n = total - nsectors; 474 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) { 475 n = roundup((n * 1024) / 512, 476 sl->sl_ntracks * sl->sl_nsectors); 477 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) { 478 n = roundup((n * 1024 * 1024) / 512, 479 sl->sl_ntracks * sl->sl_nsectors); 480 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) { 481 n = roundup((n * 1024 * 1024 * 1024) / 512, 482 sl->sl_ntracks * sl->sl_nsectors); 483 } else 484 return (-1); 485 } 486 sl->sl_part[part].sdkp_nsectors = n; 487 return (0); 488} 489 490static int 491parse_offset(struct sun_disklabel *sl, int part, char *offset) 492{ 493 uintmax_t nsectors; 494 uintmax_t n; 495 char *p; 496 int i; 497 498 nsectors = 0; 499 n = strtoumax(offset, &p, 10); 500 if (*p != '\0') { 501 if (strcmp(offset, "*") == 0) { 502 for (i = 0; i < part; i++) { 503 if (i == 2) 504 continue; 505 nsectors += sl->sl_part[i].sdkp_nsectors; 506 } 507 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks); 508 } else 509 return (-1); 510 } 511 sl->sl_part[part].sdkp_cyloffset = n; 512 return (0); 513} 514 515static void 516print_label(struct sun_disklabel *sl, const char *disk, FILE *out) 517{ 518 int i; 519 520 fprintf(out, 521"# /dev/%s:\n" 522"text: %s\n" 523"bytes/sectors: 512\n" 524"sectors/cylinder: %d\n" 525"sectors/unit: %d\n" 526"\n" 527"%d partitions:\n" 528"#\n" 529"# Size is in sectors, use %%dK, %%dM or %%dG to specify in kilobytes,\n" 530"# megabytes or gigabytes respectively, or '*' to specify rest of disk.\n" 531"# Offset is in cylinders, use '*' to calculate offsets automatically.\n" 532"#\n" 533"# size offset\n" 534"# ---------- ----------\n", 535 disk, 536 sl->sl_text, 537 sl->sl_nsectors * sl->sl_ntracks, 538 sl->sl_nsectors * sl->sl_ntracks * sl->sl_ncylinders, 539 SUN_NPART); 540 for (i = 0; i < SUN_NPART; i++) { 541 if (sl->sl_part[i].sdkp_nsectors == 0) 542 continue; 543 fprintf(out, " %c: %10u %10u\n", 544 'a' + i, 545 sl->sl_part[i].sdkp_nsectors, 546 sl->sl_part[i].sdkp_cyloffset); 547 } 548} 549 550static void 551usage(void) 552{ 553 554 fprintf(stderr, "usage:" 555"\t%s [-r] disk\n" 556"\t\t(to read label)\n" 557"\t%s -B [-b boot1] [-n] disk\n" 558"\t\t(to install boot program only)\n" 559"\t%s -R [-B [-b boot1]] [-r] [-n] disk protofile\n" 560"\t\t(to restore label)\n" 561"\t%s -e [-B [-b boot1]] [-r] [-n] disk\n" 562"\t\t(to edit label)\n" 563"\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n" 564"\t\t(to write default label)\n", 565 __progname, 566 __progname, 567 __progname, 568 __progname, 569 __progname); 570 exit(1); 571} 572