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