1 /* $OpenBSD: cmd.c,v 1.43 2009/02/08 18:03:18 krw Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Tobias Weingartner 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <err.h> 29 #include <errno.h> 30 #include <stdio.h> 31 #include <ctype.h> 32 #include <memory.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <signal.h> 36 #include <sys/fcntl.h> 37 #include <sys/disklabel.h> 38 #include "disk.h" 39 #include "misc.h" 40 #include "user.h" 41 #include "part.h" 42 #include "cmd.h" 43 #define MAX(a, b) ((a) >= (b) ? (a) : (b)) 44 45 int 46 Xreinit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 47 { 48 char buf[DEV_BSIZE]; 49 50 /* Copy template MBR */ 51 MBR_make(tt, buf); 52 MBR_parse(disk, buf, mbr->offset, mbr->reloffset, mbr); 53 54 MBR_init(disk, mbr); 55 56 /* Tell em we did something */ 57 printf("In memory copy is initialized to:\n"); 58 printf("Offset: %d\t", offset); 59 MBR_print(mbr, cmd->args); 60 printf("Use 'write' to update disk.\n"); 61 62 return (CMD_DIRTY); 63 } 64 65 /* ARGSUSED */ 66 int 67 Xdisk(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 68 { 69 int maxcyl = 1024; 70 int maxhead = 256; 71 int maxsec = 63; 72 73 /* Print out disk info */ 74 DISK_printmetrics(disk, cmd->args); 75 76 #if defined (__powerpc__) || defined (__mips__) 77 maxcyl = 9999999; 78 maxhead = 9999999; 79 maxsec = 9999999; 80 #endif 81 82 /* Ask for new info */ 83 if (ask_yn("Change disk geometry?")) { 84 disk->real->cylinders = ask_num("BIOS Cylinders", ASK_DEC, 85 disk->real->cylinders, 1, maxcyl, NULL); 86 disk->real->heads = ask_num("BIOS Heads", ASK_DEC, 87 disk->real->heads, 1, maxhead, NULL); 88 disk->real->sectors = ask_num("BIOS Sectors", ASK_DEC, 89 disk->real->sectors, 1, maxsec, NULL); 90 91 disk->real->size = disk->real->cylinders * disk->real->heads 92 * disk->real->sectors; 93 } 94 95 return (CMD_CONT); 96 } 97 98 /* ARGSUSED */ 99 int 100 Xswap(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 101 { 102 int pf, pt, ret; 103 prt_t pp; 104 105 ret = CMD_CONT; 106 107 if (!isdigit(cmd->args[0])) { 108 printf("Invalid argument: %s <from partition number>\n", 109 cmd->cmd); 110 return (ret); 111 } 112 113 pf = atoi(cmd->args); 114 if (pf < 0 || pf > 3) { 115 printf("Invalid partition number %d.\n", pf); 116 return (ret); 117 } 118 119 pt = ask_num("Swap with what partition?", ASK_DEC, 120 -1, 0, 3, NULL); 121 if (pt < 0 || pt > 3) { 122 printf("Invalid partition number %d.\n", pt); 123 return (ret); 124 } 125 126 if (pt == pf) { 127 printf("%d same partition as %d, doing nothing.\n", pt, pf); 128 return (ret); 129 } 130 131 pp = mbr->part[pt]; 132 mbr->part[pt] = mbr->part[pf]; 133 mbr->part[pf] = pp; 134 135 ret = CMD_DIRTY; 136 return (ret); 137 } 138 139 140 /* ARGSUSED */ 141 int 142 Xedit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 143 { 144 int pn, num, ret; 145 prt_t *pp; 146 147 ret = CMD_CONT; 148 149 if (!isdigit(cmd->args[0])) { 150 printf("Invalid argument: %s <partition number>\n", cmd->cmd); 151 return (ret); 152 } 153 pn = atoi(cmd->args); 154 155 if (pn < 0 || pn > 3) { 156 printf("Invalid partition number.\n"); 157 return (ret); 158 } 159 160 /* Print out current table entry */ 161 pp = &mbr->part[pn]; 162 PRT_print(0, NULL, NULL); 163 PRT_print(pn, pp, NULL); 164 165 #define EDIT(p, f, v, n, m, h) \ 166 if ((num = ask_num(p, f, v, n, m, h)) != v) \ 167 ret = CMD_DIRTY; \ 168 v = num; 169 170 /* Ask for partition type */ 171 EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall); 172 173 /* Unused, so just zero out */ 174 if (pp->id == DOSPTYP_UNUSED) { 175 memset(pp, 0, sizeof(*pp)); 176 printf("Partition %d is disabled.\n", pn); 177 return (ret); 178 } 179 180 /* Change table entry */ 181 if (ask_yn("Do you wish to edit in CHS mode?")) { 182 int maxcyl, maxhead, maxsect; 183 184 /* Shorter */ 185 maxcyl = disk->real->cylinders - 1; 186 maxhead = disk->real->heads - 1; 187 maxsect = disk->real->sectors; 188 189 /* Get data */ 190 EDIT("BIOS Starting cylinder", ASK_DEC, pp->scyl, 0, maxcyl, NULL); 191 EDIT("BIOS Starting head", ASK_DEC, pp->shead, 0, maxhead, NULL); 192 EDIT("BIOS Starting sector", ASK_DEC, pp->ssect, 1, maxsect, NULL); 193 EDIT("BIOS Ending cylinder", ASK_DEC, pp->ecyl, 0, maxcyl, NULL); 194 EDIT("BIOS Ending head", ASK_DEC, pp->ehead, 0, maxhead, NULL); 195 EDIT("BIOS Ending sector", ASK_DEC, pp->esect, 1, maxsect, NULL); 196 /* Fix up off/size values */ 197 PRT_fix_BN(disk, pp, pn); 198 /* Fix up CHS values for LBA */ 199 PRT_fix_CHS(disk, pp); 200 } else { 201 u_int m; 202 203 /* Get data */ 204 pp->bs = getuint(disk, "offset", 205 "Starting sector for this partition.", pp->bs, 206 disk->real->size, 0, DO_CONVERSIONS | 207 (pp->id == FS_BSDFFS ? DO_ROUNDING : 0)); 208 209 m = MAX(pp->ns, disk->real->size - pp->bs); 210 if ( m > disk->real->size - pp->bs) { 211 /* dont have default value extend beyond end of disk */ 212 m = disk->real->size - pp->bs; 213 } 214 pp->ns = getuint(disk, "size", "Size of the partition.", 215 pp->ns, m, pp->bs , DO_CONVERSIONS | 216 ((pp->id == FS_BSDFFS || pp->id == FS_SWAP) ? 217 DO_ROUNDING : 0)); 218 219 /* Fix up CHS values */ 220 PRT_fix_CHS(disk, pp); 221 } 222 #undef EDIT 223 return (ret); 224 } 225 226 /* ARGSUSED */ 227 int 228 Xsetpid(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 229 { 230 int pn, num, ret; 231 prt_t *pp; 232 233 ret = CMD_CONT; 234 235 if (!isdigit(cmd->args[0])) { 236 printf("Invalid argument: %s <partition number>\n", cmd->cmd); 237 return (ret); 238 } 239 pn = atoi(cmd->args); 240 241 if (pn < 0 || pn > 3) { 242 printf("Invalid partition number.\n"); 243 return (ret); 244 } 245 246 /* Print out current table entry */ 247 pp = &mbr->part[pn]; 248 PRT_print(0, NULL, NULL); 249 PRT_print(pn, pp, NULL); 250 251 #define EDIT(p, f, v, n, m, h) \ 252 if ((num = ask_num(p, f, v, n, m, h)) != v) \ 253 ret = CMD_DIRTY; \ 254 v = num; 255 256 /* Ask for partition type */ 257 EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall); 258 259 #undef EDIT 260 return (ret); 261 } 262 263 /* ARGSUSED */ 264 int 265 Xselect(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 266 { 267 static int firstoff = 0; 268 int off; 269 int pn; 270 271 if (!isdigit(cmd->args[0])) { 272 printf("Invalid argument: %s <partition number>\n", cmd->cmd); 273 return (CMD_CONT); 274 } 275 276 pn = atoi(cmd->args); 277 off = mbr->part[pn].bs; 278 279 /* Sanity checks */ 280 if ((mbr->part[pn].id != DOSPTYP_EXTEND) && 281 (mbr->part[pn].id != DOSPTYP_EXTENDL)) { 282 printf("Partition %d is not an extended partition.\n", pn); 283 return (CMD_CONT); 284 } 285 286 if (firstoff == 0) 287 firstoff = off; 288 289 if (!off) { 290 printf("Loop to offset 0! Not selected.\n"); 291 return (CMD_CONT); 292 } else { 293 printf("Selected extended partition %d\n", pn); 294 printf("New MBR at offset %d.\n", off); 295 } 296 297 /* Recursion is beautifull! */ 298 USER_modify(disk, tt, off, firstoff); 299 return (CMD_CONT); 300 } 301 302 /* ARGSUSED */ 303 int 304 Xprint(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 305 { 306 307 DISK_printmetrics(disk, cmd->args); 308 printf("Offset: %d\t", offset); 309 MBR_print(mbr, cmd->args); 310 311 return (CMD_CONT); 312 } 313 314 /* ARGSUSED */ 315 int 316 Xwrite(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 317 { 318 char mbr_buf[DEV_BSIZE]; 319 int fd; 320 321 fd = DISK_open(disk->name, O_RDWR); 322 MBR_make(mbr, mbr_buf); 323 324 printf("Writing MBR at offset %d.\n", offset); 325 if (MBR_write(fd, offset, mbr_buf) == -1) { 326 int saved_errno = errno; 327 warn("error writing MBR"); 328 close(fd); 329 errno = saved_errno; 330 return (CMD_CONT); 331 } 332 close(fd); 333 334 return (CMD_CLEAN); 335 } 336 337 /* ARGSUSED */ 338 int 339 Xquit(cmd, disk, r, tt, offset) 340 cmd_t *cmd; 341 disk_t *disk; 342 mbr_t *r; 343 mbr_t *tt; 344 int offset; 345 { 346 347 /* Nothing to do here */ 348 return (CMD_SAVE); 349 } 350 351 /* ARGSUSED */ 352 int 353 Xabort(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 354 { 355 exit(0); 356 357 /* NOTREACHED */ 358 return (CMD_CONT); 359 } 360 361 362 /* ARGSUSED */ 363 int 364 Xexit(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 365 { 366 367 /* Nothing to do here */ 368 return (CMD_EXIT); 369 } 370 371 /* ARGSUSED */ 372 int 373 Xhelp(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 374 { 375 cmd_table_t *cmd_table = cmd->table; 376 int i; 377 378 /* Hmm, print out cmd_table here... */ 379 for (i = 0; cmd_table[i].cmd != NULL; i++) 380 printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help); 381 return (CMD_CONT); 382 } 383 384 /* ARGSUSED */ 385 int 386 Xupdate(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 387 { 388 389 /* Update code */ 390 memcpy(mbr->code, tt->code, MBR_CODE_SIZE); 391 mbr->signature = DOSMBR_SIGNATURE; 392 printf("Machine code updated.\n"); 393 return (CMD_DIRTY); 394 } 395 396 /* ARGSUSED */ 397 int 398 Xflag(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 399 { 400 int i, pn = -1, val = -1; 401 char *p; 402 403 /* Parse partition table entry number */ 404 if (!isdigit(cmd->args[0])) { 405 printf("Invalid argument: %s <partition number> [value]\n", 406 cmd->cmd); 407 return (CMD_CONT); 408 } 409 pn = atoi(cmd->args); 410 p = strchr(cmd->args, ' '); 411 if (p != NULL) 412 val = strtol(p + 1, NULL, 0) & 0xff; 413 414 if (pn < 0 || pn > 3) { 415 printf("Invalid partition number.\n"); 416 return (CMD_CONT); 417 } 418 419 if (val == -1) { 420 /* Set active flag */ 421 for (i = 0; i < 4; i++) { 422 if (i == pn) 423 mbr->part[i].flag = DOSACTIVE; 424 else 425 mbr->part[i].flag = 0x00; 426 } 427 printf("Partition %d marked active.\n", pn); 428 } else { 429 mbr->part[pn].flag = val; 430 printf("Partition %d flag value set to 0x%x.\n", pn, val); 431 } 432 return (CMD_DIRTY); 433 } 434 435 /* ARGSUSED */ 436 int 437 Xmanual(cmd_t *cmd, disk_t *disk, mbr_t *mbr, mbr_t *tt, int offset) 438 { 439 char *pager = "/usr/bin/less"; 440 char *p; 441 sig_t opipe; 442 extern const unsigned char manpage[]; 443 extern const int manpage_sz; 444 FILE *f; 445 446 opipe = signal(SIGPIPE, SIG_IGN); 447 if ((p = getenv("PAGER")) != NULL && (*p != '\0')) 448 pager = p; 449 if (asprintf(&p, "gunzip -qc|%s", pager) != -1) { 450 f = popen(p, "w"); 451 if (f) { 452 (void) fwrite(manpage, manpage_sz, 1, f); 453 pclose(f); 454 } 455 free(p); 456 } 457 458 (void)signal(SIGPIPE, opipe); 459 return (CMD_CONT); 460 } 461 462