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