1 /* $OpenBSD: cmd.c,v 1.98 2017/11/13 21:00:32 krw Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Tobias Weingartner 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/disklabel.h> 21 22 #include <err.h> 23 #include <signal.h> 24 #include <stdint.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <uuid.h> 29 30 #include "disk.h" 31 #include "misc.h" 32 #include "part.h" 33 #include "mbr.h" 34 #include "gpt.h" 35 #include "user.h" 36 #include "cmd.h" 37 38 int reinited; 39 40 /* Some helper functions for GPT handling. */ 41 int Xgedit(char *); 42 int Xgsetpid(char *); 43 44 int 45 Xreinit(char *args, struct mbr *mbr) 46 { 47 struct dos_mbr dos_mbr; 48 int dogpt; 49 50 if (strncasecmp(args, "gpt", 3) == 0) 51 dogpt = 1; 52 else if (strncasecmp(args, "mbr", 3) == 0) 53 dogpt = 0; 54 else if (strlen(args) > 0) { 55 printf("Unrecognized modifier '%s'\n", args); 56 return (CMD_CONT); 57 } else if (MBR_protective_mbr(mbr) == 0) 58 dogpt = 1; 59 else 60 dogpt = 0; 61 62 MBR_make(&initial_mbr, &dos_mbr); 63 MBR_parse(&dos_mbr, mbr->offset, mbr->reloffset, mbr); 64 65 if (dogpt) { 66 MBR_init_GPT(mbr); 67 GPT_init(); 68 GPT_print("s", 0); 69 } else { 70 MBR_init(mbr); 71 MBR_print(mbr, "s"); 72 } 73 reinited = 1; 74 75 printf("Use 'write' to update disk.\n"); 76 77 return (CMD_DIRTY); 78 } 79 80 int 81 Xdisk(char *args, struct mbr *mbr) 82 { 83 int maxcyl = 1024; 84 int maxhead = 256; 85 int maxsec = 63; 86 87 /* Print out disk info */ 88 DISK_printgeometry(args); 89 90 #if defined (__powerpc__) || defined (__mips__) 91 maxcyl = 9999999; 92 maxhead = 9999999; 93 maxsec = 9999999; 94 #endif 95 96 /* Ask for new info */ 97 if (ask_yn("Change disk geometry?")) { 98 disk.cylinders = ask_num("BIOS Cylinders", 99 disk.cylinders, 1, maxcyl); 100 disk.heads = ask_num("BIOS Heads", 101 disk.heads, 1, maxhead); 102 disk.sectors = ask_num("BIOS Sectors", 103 disk.sectors, 1, maxsec); 104 105 disk.size = disk.cylinders * disk.heads * disk.sectors; 106 } 107 108 return (CMD_CONT); 109 } 110 111 int 112 Xswap(char *args, struct mbr *mbr) 113 { 114 const char *errstr; 115 char *from, *to; 116 int pf, pt, maxpn; 117 struct prt pp; 118 struct gpt_partition gg; 119 120 to = args; 121 from = strsep(&to, " \t"); 122 123 if (to == NULL) { 124 printf("partition number is invalid:\n"); 125 return (CMD_CONT); 126 } 127 128 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 129 maxpn = NGPTPARTITIONS - 1; 130 else 131 maxpn = NDOSPART - 1; 132 133 pf = strtonum(from, 0, maxpn, &errstr); 134 if (errstr) { 135 printf("partition number is %s: %s\n", errstr, from); 136 return (CMD_CONT); 137 } 138 pt = strtonum(to, 0, maxpn, &errstr); 139 if (errstr) { 140 printf("partition number is %s: %s\n", errstr, to); 141 return (CMD_CONT); 142 } 143 144 if (pt == pf) { 145 printf("%d same partition as %d, doing nothing.\n", pt, pf); 146 return (CMD_CONT); 147 } 148 149 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 150 gg = gp[pt]; 151 gp[pt] = gp[pf]; 152 gp[pf] = gg; 153 } else { 154 pp = mbr->part[pt]; 155 mbr->part[pt] = mbr->part[pf]; 156 mbr->part[pf] = pp; 157 } 158 159 return (CMD_DIRTY); 160 } 161 162 int 163 Xgedit(char *args) 164 { 165 struct gpt_partition oldpart; 166 const char *errstr; 167 struct gpt_partition *gg; 168 char *name; 169 u_int16_t *utf; 170 u_int64_t bs, ns; 171 int i, pn; 172 173 pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr); 174 if (errstr) { 175 printf("partition number is %s: %s\n", errstr, args); 176 return (CMD_CONT); 177 } 178 gg = &gp[pn]; 179 oldpart = *gg; 180 181 Xgsetpid(args); 182 if (uuid_is_nil(&gg->gp_type, NULL)) { 183 if (uuid_is_nil(&oldpart.gp_type, NULL) == 0) { 184 memset(gg, 0, sizeof(struct gpt_partition)); 185 printf("Partition %d is disabled.\n", pn); 186 } 187 goto done; 188 } 189 190 bs = getuint64("Partition offset", letoh64(gg->gp_lba_start), 191 letoh64(gh.gh_lba_start), letoh64(gh.gh_lba_end)); 192 ns = getuint64("Partition size", letoh64(gg->gp_lba_end) - bs + 1, 193 1, letoh64(gh.gh_lba_end) - bs + 1); 194 195 gg->gp_lba_start = htole64(bs); 196 gg->gp_lba_end = htole64(bs + ns - 1); 197 198 name = ask_string("Partition name", utf16le_to_string(gg->gp_name)); 199 if (strlen(name) >= GPTPARTNAMESIZE) { 200 printf("partition name must be < %d characters\n", 201 GPTPARTNAMESIZE); 202 goto done; 203 } 204 /* 205 * N.B.: simple memcpy() could copy trash from static buf! This 206 * would create false positives for the partition having changed. 207 */ 208 utf = string_to_utf16le(name); 209 for (i = 0; i < GPTPARTNAMESIZE; i++) { 210 gg->gp_name[i] = utf[i]; 211 if (utf[i] == 0) 212 break; 213 } 214 215 done: 216 if (memcmp(gg, &oldpart, sizeof(*gg))) 217 return (CMD_DIRTY); 218 else 219 return (CMD_CONT); 220 } 221 222 int 223 Xedit(char *args, struct mbr *mbr) 224 { 225 struct prt oldpart; 226 const char *errstr; 227 struct prt *pp; 228 int pn; 229 230 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 231 return (Xgedit(args)); 232 233 pn = strtonum(args, 0, 3, &errstr); 234 if (errstr) { 235 printf("partition number is %s: %s\n", errstr, args); 236 return (CMD_CONT); 237 } 238 pp = &mbr->part[pn]; 239 oldpart = *pp; 240 241 Xsetpid(args, mbr); 242 if (pp->id == DOSPTYP_UNUSED) { 243 if (oldpart.id != DOSPTYP_UNUSED) { 244 memset(pp, 0, sizeof(*pp)); 245 printf("Partition %d is disabled.\n", pn); 246 } 247 goto done; 248 } 249 250 if (ask_yn("Do you wish to edit in CHS mode?")) { 251 pp->scyl = ask_num("BIOS Starting cylinder", pp->scyl, 0, 252 disk.cylinders - 1); 253 pp->shead = ask_num("BIOS Starting head", pp->shead, 0, 254 disk.heads - 1); 255 pp->ssect = ask_num("BIOS Starting sector", pp->ssect, 1, 256 disk.sectors); 257 258 pp->ecyl = ask_num("BIOS Ending cylinder", pp->ecyl, 259 pp->scyl, disk.cylinders - 1); 260 pp->ehead = ask_num("BIOS Ending head", pp->ehead, 261 (pp->scyl == pp->ecyl) ? pp->shead : 0, disk.heads - 1); 262 pp->esect = ask_num("BIOS Ending sector", pp->esect, 263 (pp->scyl == pp->ecyl && pp->shead == pp->ehead) ? pp->ssect 264 : 1, disk.sectors); 265 266 /* Fix up off/size values */ 267 PRT_fix_BN(pp, pn); 268 /* Fix up CHS values for LBA */ 269 PRT_fix_CHS(pp); 270 } else { 271 pp->bs = getuint64("Partition offset", pp->bs, 0, disk.size - 1); 272 pp->ns = getuint64("Partition size", pp->ns, 1, 273 disk.size - pp->bs); 274 275 /* Fix up CHS values */ 276 PRT_fix_CHS(pp); 277 } 278 279 done: 280 if (memcmp(pp, &oldpart, sizeof(*pp))) 281 return (CMD_DIRTY); 282 else 283 return (CMD_CONT); 284 } 285 286 int 287 Xgsetpid(char *args) 288 { 289 const char *errstr; 290 struct uuid guid; 291 struct gpt_partition *gg; 292 int pn, num, status; 293 294 pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr); 295 if (errstr) { 296 printf("partition number is %s: %s\n", errstr, args); 297 return (CMD_CONT); 298 } 299 gg = &gp[pn]; 300 301 /* Print out current table entry */ 302 GPT_print_parthdr(0); 303 GPT_print_part(pn, "s", 0); 304 305 /* Ask for partition type or GUID. */ 306 uuid_dec_le(&gg->gp_type, &guid); 307 num = ask_pid(PRT_uuid_to_type(&guid), &guid); 308 if (num <= 0xff) 309 guid = *(PRT_type_to_uuid(num)); 310 uuid_enc_le(&gg->gp_type, &guid); 311 312 if (uuid_is_nil(&gg->gp_guid, NULL)) { 313 uuid_create(&guid, &status); 314 if (status != uuid_s_ok) { 315 printf("could not create guid for partition\n"); 316 return (CMD_CONT); 317 } 318 uuid_enc_le(&gg->gp_guid, &guid); 319 } 320 321 return (CMD_DIRTY); 322 } 323 324 int 325 Xsetpid(char *args, struct mbr *mbr) 326 { 327 const char *errstr; 328 int pn, num; 329 struct prt *pp; 330 331 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 332 return (Xgsetpid(args)); 333 334 pn = strtonum(args, 0, 3, &errstr); 335 if (errstr) { 336 printf("partition number is %s: %s\n", errstr, args); 337 return (CMD_CONT); 338 } 339 pp = &mbr->part[pn]; 340 341 /* Print out current table entry */ 342 PRT_print(0, NULL, NULL); 343 PRT_print(pn, pp, NULL); 344 345 /* Ask for MBR partition type */ 346 num = ask_pid(pp->id, NULL); 347 if (num == pp->id) 348 return (CMD_CONT); 349 350 pp->id = num; 351 352 return (CMD_DIRTY); 353 } 354 355 int 356 Xselect(char *args, struct mbr *mbr) 357 { 358 const char *errstr; 359 static off_t firstoff = 0; 360 off_t off; 361 int pn; 362 363 pn = strtonum(args, 0, 3, &errstr); 364 if (errstr) { 365 printf("partition number is %s: %s\n", errstr, args); 366 return (CMD_CONT); 367 } 368 369 off = mbr->part[pn].bs; 370 371 /* Sanity checks */ 372 if ((mbr->part[pn].id != DOSPTYP_EXTEND) && 373 (mbr->part[pn].id != DOSPTYP_EXTENDL)) { 374 printf("Partition %d is not an extended partition.\n", pn); 375 return (CMD_CONT); 376 } 377 378 if (firstoff == 0) 379 firstoff = off; 380 381 if (!off) { 382 printf("Loop to offset 0! Not selected.\n"); 383 return (CMD_CONT); 384 } else { 385 printf("Selected extended partition %d\n", pn); 386 printf("New MBR at offset %lld.\n", (long long)off); 387 } 388 389 /* Recursion is beautiful! */ 390 USER_edit(off, firstoff); 391 392 return (CMD_CONT); 393 } 394 395 int 396 Xprint(char *args, struct mbr *mbr) 397 { 398 399 if (MBR_protective_mbr(mbr) == 0 && letoh64(gh.gh_sig) == GPTSIGNATURE) 400 GPT_print(args, 1); 401 else 402 MBR_print(mbr, args); 403 404 return (CMD_CONT); 405 } 406 407 int 408 Xwrite(char *args, struct mbr *mbr) 409 { 410 struct dos_mbr dos_mbr; 411 int i, n; 412 413 for (i = 0, n = 0; i < NDOSPART; i++) 414 if (mbr->part[i].id == 0xA6) 415 n++; 416 if (n >= 2) { 417 warnx("MBR contains more than one OpenBSD partition!"); 418 if (!ask_yn("Write MBR anyway?")) 419 return (CMD_CONT); 420 } 421 422 MBR_make(mbr, &dos_mbr); 423 424 printf("Writing MBR at offset %lld.\n", (long long)mbr->offset); 425 if (MBR_write(mbr->offset, &dos_mbr) == -1) { 426 warn("error writing MBR"); 427 return (CMD_CONT); 428 } 429 430 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 431 printf("Writing GPT.\n"); 432 if (GPT_write() == -1) { 433 warn("error writing GPT"); 434 return (CMD_CONT); 435 } 436 } else if (reinited) { 437 /* Make sure GPT doesn't get in the way. */ 438 MBR_zapgpt(&dos_mbr, DL_GETDSIZE(&dl) - 1); 439 } 440 441 /* Refresh in memory copy to reflect what was just written. */ 442 MBR_parse(&dos_mbr, mbr->offset, mbr->reloffset, mbr); 443 444 return (CMD_CLEAN); 445 } 446 447 int 448 Xquit(char *args, struct mbr *mbr) 449 { 450 return (CMD_SAVE); 451 } 452 453 int 454 Xabort(char *args, struct mbr *mbr) 455 { 456 exit(0); 457 } 458 459 int 460 Xexit(char *args, struct mbr *mbr) 461 { 462 return (CMD_EXIT); 463 } 464 465 int 466 Xhelp(char *args, struct mbr *mbr) 467 { 468 char help[80]; 469 char *mbrstr; 470 int i; 471 472 for (i = 0; cmd_table[i].cmd != NULL; i++) { 473 strlcpy(help, cmd_table[i].help, sizeof(help)); 474 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 475 if (cmd_table[i].gpt == 0) 476 continue; 477 mbrstr = strstr(help, "MBR"); 478 if (mbrstr) 479 memcpy(mbrstr, "GPT", 3); 480 } 481 printf("\t%s\t\t%s\n", cmd_table[i].cmd, help); 482 } 483 484 return (CMD_CONT); 485 } 486 487 int 488 Xupdate(char *args, struct mbr *mbr) 489 { 490 /* Update code */ 491 memcpy(mbr->code, initial_mbr.code, sizeof(mbr->code)); 492 mbr->signature = DOSMBR_SIGNATURE; 493 printf("Machine code updated.\n"); 494 return (CMD_DIRTY); 495 } 496 497 int 498 Xflag(char *args, struct mbr *mbr) 499 { 500 const char *errstr; 501 int i, maxpn, pn = -1; 502 long long val = -1; 503 char *part, *flag; 504 505 flag = args; 506 part = strsep(&flag, " \t"); 507 508 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 509 maxpn = NGPTPARTITIONS - 1; 510 else 511 maxpn = NDOSPART - 1; 512 513 pn = strtonum(part, 0, maxpn, &errstr); 514 if (errstr) { 515 printf("partition number is %s: %s.\n", errstr, part); 516 return (CMD_CONT); 517 } 518 519 if (flag != NULL) { 520 /* Set flag to value provided. */ 521 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 522 val = strtonum(flag, 0, INT64_MAX, &errstr); 523 else 524 val = strtonum(flag, 0, 0xff, &errstr); 525 if (errstr) { 526 printf("flag value is %s: %s.\n", errstr, flag); 527 return (CMD_CONT); 528 } 529 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 530 gp[pn].gp_attrs = htole64(val); 531 else 532 mbr->part[pn].flag = val; 533 printf("Partition %d flag value set to 0x%llx.\n", pn, val); 534 } else { 535 /* Set active flag */ 536 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 537 for (i = 0; i < NGPTPARTITIONS; i++) { 538 if (i == pn) 539 gp[i].gp_attrs = htole64(GPTDOSACTIVE); 540 else 541 gp[i].gp_attrs = htole64(0); 542 } 543 } else { 544 for (i = 0; i < NDOSPART; i++) { 545 if (i == pn) 546 mbr->part[i].flag = DOSACTIVE; 547 else 548 mbr->part[i].flag = 0x00; 549 } 550 } 551 printf("Partition %d marked active.\n", pn); 552 } 553 554 return (CMD_DIRTY); 555 } 556 557 int 558 Xmanual(char *args, struct mbr *mbr) 559 { 560 char *pager = "/usr/bin/less"; 561 char *p; 562 sig_t opipe; 563 extern const unsigned char manpage[]; 564 extern const int manpage_sz; 565 FILE *f; 566 567 opipe = signal(SIGPIPE, SIG_IGN); 568 if ((p = getenv("PAGER")) != NULL && (*p != '\0')) 569 pager = p; 570 if (asprintf(&p, "gunzip -qc|%s", pager) != -1) { 571 f = popen(p, "w"); 572 if (f) { 573 fwrite(manpage, manpage_sz, 1, f); 574 pclose(f); 575 } 576 free(p); 577 } 578 579 signal(SIGPIPE, opipe); 580 581 return (CMD_CONT); 582 } 583