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