1 /* $OpenBSD: cmd.c,v 1.99 2021/01/30 18:16:36 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 int i, pn; 171 172 pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr); 173 if (errstr) { 174 printf("partition number is %s: %s\n", errstr, args); 175 return (CMD_CONT); 176 } 177 gg = &gp[pn]; 178 oldpart = *gg; 179 180 Xgsetpid(args); 181 if (uuid_is_nil(&gg->gp_type, NULL)) { 182 if (uuid_is_nil(&oldpart.gp_type, NULL) == 0) { 183 memset(gg, 0, sizeof(struct gpt_partition)); 184 printf("Partition %d is disabled.\n", pn); 185 } 186 goto done; 187 } 188 189 if (GPT_get_lba_start(pn) == -1 || 190 GPT_get_lba_end(pn) == -1) { 191 *gg = oldpart; 192 goto done; 193 } 194 195 name = ask_string("Partition name", utf16le_to_string(gg->gp_name)); 196 if (strlen(name) >= GPTPARTNAMESIZE) { 197 printf("partition name must be < %d characters\n", 198 GPTPARTNAMESIZE); 199 goto done; 200 } 201 /* 202 * N.B.: simple memcpy() could copy trash from static buf! This 203 * would create false positives for the partition having changed. 204 */ 205 utf = string_to_utf16le(name); 206 for (i = 0; i < GPTPARTNAMESIZE; i++) { 207 gg->gp_name[i] = utf[i]; 208 if (utf[i] == 0) 209 break; 210 } 211 212 done: 213 if (memcmp(gg, &oldpart, sizeof(*gg))) 214 return (CMD_DIRTY); 215 else 216 return (CMD_CONT); 217 } 218 219 int 220 Xedit(char *args, struct mbr *mbr) 221 { 222 struct prt oldpart; 223 const char *errstr; 224 struct prt *pp; 225 int pn; 226 227 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 228 return (Xgedit(args)); 229 230 pn = strtonum(args, 0, 3, &errstr); 231 if (errstr) { 232 printf("partition number is %s: %s\n", errstr, args); 233 return (CMD_CONT); 234 } 235 pp = &mbr->part[pn]; 236 oldpart = *pp; 237 238 Xsetpid(args, mbr); 239 if (pp->id == DOSPTYP_UNUSED) { 240 if (oldpart.id != DOSPTYP_UNUSED) { 241 memset(pp, 0, sizeof(*pp)); 242 printf("Partition %d is disabled.\n", pn); 243 } 244 goto done; 245 } 246 247 if (ask_yn("Do you wish to edit in CHS mode?")) { 248 pp->scyl = ask_num("BIOS Starting cylinder", pp->scyl, 0, 249 disk.cylinders - 1); 250 pp->shead = ask_num("BIOS Starting head", pp->shead, 0, 251 disk.heads - 1); 252 pp->ssect = ask_num("BIOS Starting sector", pp->ssect, 1, 253 disk.sectors); 254 255 pp->ecyl = ask_num("BIOS Ending cylinder", pp->ecyl, 256 pp->scyl, disk.cylinders - 1); 257 pp->ehead = ask_num("BIOS Ending head", pp->ehead, 258 (pp->scyl == pp->ecyl) ? pp->shead : 0, disk.heads - 1); 259 pp->esect = ask_num("BIOS Ending sector", pp->esect, 260 (pp->scyl == pp->ecyl && pp->shead == pp->ehead) ? pp->ssect 261 : 1, disk.sectors); 262 263 /* Fix up off/size values */ 264 PRT_fix_BN(pp, pn); 265 /* Fix up CHS values for LBA */ 266 PRT_fix_CHS(pp); 267 } else { 268 pp->bs = getuint64("Partition offset", pp->bs, 0, disk.size - 1); 269 pp->ns = getuint64("Partition size", pp->ns, 1, 270 disk.size - pp->bs); 271 272 /* Fix up CHS values */ 273 PRT_fix_CHS(pp); 274 } 275 276 done: 277 if (memcmp(pp, &oldpart, sizeof(*pp))) 278 return (CMD_DIRTY); 279 else 280 return (CMD_CONT); 281 } 282 283 int 284 Xgsetpid(char *args) 285 { 286 const char *errstr; 287 struct uuid guid; 288 struct gpt_partition *gg; 289 int pn, num, status; 290 291 pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr); 292 if (errstr) { 293 printf("partition number is %s: %s\n", errstr, args); 294 return (CMD_CONT); 295 } 296 gg = &gp[pn]; 297 298 /* Print out current table entry */ 299 GPT_print_parthdr(0); 300 GPT_print_part(pn, "s", 0); 301 302 /* Ask for partition type or GUID. */ 303 uuid_dec_le(&gg->gp_type, &guid); 304 num = ask_pid(PRT_uuid_to_type(&guid), &guid); 305 if (num <= 0xff) 306 guid = *(PRT_type_to_uuid(num)); 307 uuid_enc_le(&gg->gp_type, &guid); 308 309 if (uuid_is_nil(&gg->gp_guid, NULL)) { 310 uuid_create(&guid, &status); 311 if (status != uuid_s_ok) { 312 printf("could not create guid for partition\n"); 313 return (CMD_CONT); 314 } 315 uuid_enc_le(&gg->gp_guid, &guid); 316 } 317 318 return (CMD_DIRTY); 319 } 320 321 int 322 Xsetpid(char *args, struct mbr *mbr) 323 { 324 const char *errstr; 325 int pn, num; 326 struct prt *pp; 327 328 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 329 return (Xgsetpid(args)); 330 331 pn = strtonum(args, 0, 3, &errstr); 332 if (errstr) { 333 printf("partition number is %s: %s\n", errstr, args); 334 return (CMD_CONT); 335 } 336 pp = &mbr->part[pn]; 337 338 /* Print out current table entry */ 339 PRT_print(0, NULL, NULL); 340 PRT_print(pn, pp, NULL); 341 342 /* Ask for MBR partition type */ 343 num = ask_pid(pp->id, NULL); 344 if (num == pp->id) 345 return (CMD_CONT); 346 347 pp->id = num; 348 349 return (CMD_DIRTY); 350 } 351 352 int 353 Xselect(char *args, struct mbr *mbr) 354 { 355 const char *errstr; 356 static off_t firstoff = 0; 357 off_t off; 358 int pn; 359 360 pn = strtonum(args, 0, 3, &errstr); 361 if (errstr) { 362 printf("partition number is %s: %s\n", errstr, args); 363 return (CMD_CONT); 364 } 365 366 off = mbr->part[pn].bs; 367 368 /* Sanity checks */ 369 if ((mbr->part[pn].id != DOSPTYP_EXTEND) && 370 (mbr->part[pn].id != DOSPTYP_EXTENDL)) { 371 printf("Partition %d is not an extended partition.\n", pn); 372 return (CMD_CONT); 373 } 374 375 if (firstoff == 0) 376 firstoff = off; 377 378 if (!off) { 379 printf("Loop to offset 0! Not selected.\n"); 380 return (CMD_CONT); 381 } else { 382 printf("Selected extended partition %d\n", pn); 383 printf("New MBR at offset %lld.\n", (long long)off); 384 } 385 386 /* Recursion is beautiful! */ 387 USER_edit(off, firstoff); 388 389 return (CMD_CONT); 390 } 391 392 int 393 Xprint(char *args, struct mbr *mbr) 394 { 395 396 if (MBR_protective_mbr(mbr) == 0 && letoh64(gh.gh_sig) == GPTSIGNATURE) 397 GPT_print(args, 1); 398 else 399 MBR_print(mbr, args); 400 401 return (CMD_CONT); 402 } 403 404 int 405 Xwrite(char *args, struct mbr *mbr) 406 { 407 struct dos_mbr dos_mbr; 408 int i, n; 409 410 for (i = 0, n = 0; i < NDOSPART; i++) 411 if (mbr->part[i].id == 0xA6) 412 n++; 413 if (n >= 2) { 414 warnx("MBR contains more than one OpenBSD partition!"); 415 if (!ask_yn("Write MBR anyway?")) 416 return (CMD_CONT); 417 } 418 419 MBR_make(mbr, &dos_mbr); 420 421 printf("Writing MBR at offset %lld.\n", (long long)mbr->offset); 422 if (MBR_write(mbr->offset, &dos_mbr) == -1) { 423 warn("error writing MBR"); 424 return (CMD_CONT); 425 } 426 427 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 428 printf("Writing GPT.\n"); 429 if (GPT_write() == -1) { 430 warn("error writing GPT"); 431 return (CMD_CONT); 432 } 433 } else if (reinited) { 434 /* Make sure GPT doesn't get in the way. */ 435 MBR_zapgpt(&dos_mbr, DL_GETDSIZE(&dl) - 1); 436 } 437 438 /* Refresh in memory copy to reflect what was just written. */ 439 MBR_parse(&dos_mbr, mbr->offset, mbr->reloffset, mbr); 440 441 return (CMD_CLEAN); 442 } 443 444 int 445 Xquit(char *args, struct mbr *mbr) 446 { 447 return (CMD_SAVE); 448 } 449 450 int 451 Xabort(char *args, struct mbr *mbr) 452 { 453 exit(0); 454 } 455 456 int 457 Xexit(char *args, struct mbr *mbr) 458 { 459 return (CMD_EXIT); 460 } 461 462 int 463 Xhelp(char *args, struct mbr *mbr) 464 { 465 char help[80]; 466 char *mbrstr; 467 int i; 468 469 for (i = 0; cmd_table[i].cmd != NULL; i++) { 470 strlcpy(help, cmd_table[i].help, sizeof(help)); 471 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 472 if (cmd_table[i].gpt == 0) 473 continue; 474 mbrstr = strstr(help, "MBR"); 475 if (mbrstr) 476 memcpy(mbrstr, "GPT", 3); 477 } 478 printf("\t%s\t\t%s\n", cmd_table[i].cmd, help); 479 } 480 481 return (CMD_CONT); 482 } 483 484 int 485 Xupdate(char *args, struct mbr *mbr) 486 { 487 /* Update code */ 488 memcpy(mbr->code, initial_mbr.code, sizeof(mbr->code)); 489 mbr->signature = DOSMBR_SIGNATURE; 490 printf("Machine code updated.\n"); 491 return (CMD_DIRTY); 492 } 493 494 int 495 Xflag(char *args, struct mbr *mbr) 496 { 497 const char *errstr; 498 int i, maxpn, pn = -1; 499 long long val = -1; 500 char *part, *flag; 501 502 flag = args; 503 part = strsep(&flag, " \t"); 504 505 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 506 maxpn = NGPTPARTITIONS - 1; 507 else 508 maxpn = NDOSPART - 1; 509 510 pn = strtonum(part, 0, maxpn, &errstr); 511 if (errstr) { 512 printf("partition number is %s: %s.\n", errstr, part); 513 return (CMD_CONT); 514 } 515 516 if (flag != NULL) { 517 /* Set flag to value provided. */ 518 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 519 val = strtonum(flag, 0, INT64_MAX, &errstr); 520 else 521 val = strtonum(flag, 0, 0xff, &errstr); 522 if (errstr) { 523 printf("flag value is %s: %s.\n", errstr, flag); 524 return (CMD_CONT); 525 } 526 if (letoh64(gh.gh_sig) == GPTSIGNATURE) 527 gp[pn].gp_attrs = htole64(val); 528 else 529 mbr->part[pn].flag = val; 530 printf("Partition %d flag value set to 0x%llx.\n", pn, val); 531 } else { 532 /* Set active flag */ 533 if (letoh64(gh.gh_sig) == GPTSIGNATURE) { 534 for (i = 0; i < NGPTPARTITIONS; i++) { 535 if (i == pn) 536 gp[i].gp_attrs = htole64(GPTDOSACTIVE); 537 else 538 gp[i].gp_attrs = htole64(0); 539 } 540 } else { 541 for (i = 0; i < NDOSPART; i++) { 542 if (i == pn) 543 mbr->part[i].flag = DOSACTIVE; 544 else 545 mbr->part[i].flag = 0x00; 546 } 547 } 548 printf("Partition %d marked active.\n", pn); 549 } 550 551 return (CMD_DIRTY); 552 } 553 554 int 555 Xmanual(char *args, struct mbr *mbr) 556 { 557 char *pager = "/usr/bin/less"; 558 char *p; 559 sig_t opipe; 560 extern const unsigned char manpage[]; 561 extern const int manpage_sz; 562 FILE *f; 563 564 opipe = signal(SIGPIPE, SIG_IGN); 565 if ((p = getenv("PAGER")) != NULL && (*p != '\0')) 566 pager = p; 567 if (asprintf(&p, "gunzip -qc|%s", pager) != -1) { 568 f = popen(p, "w"); 569 if (f) { 570 fwrite(manpage, manpage_sz, 1, f); 571 pclose(f); 572 } 573 free(p); 574 } 575 576 signal(SIGPIPE, opipe); 577 578 return (CMD_CONT); 579 } 580