1 /* $OpenBSD: pdisk.c,v 1.87 2016/05/28 22:26:13 tb Exp $ */ 2 3 /* 4 * pdisk - an editor for Apple format partition tables 5 * 6 * Written by Eryk Vershen 7 * 8 * Still under development (as of 15 January 1998) 9 */ 10 11 /* 12 * Copyright 1996,1997,1998 by Apple Computer, Inc. 13 * All Rights Reserved 14 * 15 * Permission to use, copy, modify, and distribute this software and 16 * its documentation for any purpose and without fee is hereby granted, 17 * provided that the above copyright notice appears in all copies and 18 * that both the copyright notice and this permission notice appear in 19 * supporting documentation. 20 * 21 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 22 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE. 24 * 25 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 26 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 27 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 28 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 29 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30 */ 31 32 #include <sys/param.h> /* DEV_BSIZE */ 33 #include <sys/dkio.h> 34 #include <sys/disklabel.h> 35 #include <sys/ioctl.h> 36 #include <sys/queue.h> 37 #include <sys/stat.h> 38 39 #include <err.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <util.h> 46 47 #include "partition_map.h" 48 #include "io.h" 49 #include "dump.h" 50 51 int lflag; /* list the device */ 52 int rflag; /* open device read Only */ 53 54 static int first_get = 1; 55 56 void do_dump_map(struct partition_map *, int); 57 void do_change_map_size(struct partition_map *); 58 void do_create_partition(struct partition_map *, int); 59 void do_delete_partition(struct partition_map *); 60 void do_display_entry(struct partition_map *); 61 void do_rename_partition(struct partition_map *); 62 void do_change_type(struct partition_map *); 63 void do_reorder(struct partition_map *); 64 void do_write_partition_map(struct partition_map *); 65 void edit(struct partition_map **); 66 int get_base_argument(long *, struct partition_map *); 67 int get_size_argument(long *, struct partition_map *); 68 69 __dead static void usage(void); 70 71 int 72 main(int argc, char **argv) 73 { 74 struct disklabel dl; 75 struct stat st; 76 struct partition_map *map; 77 int c, fd, oflags; 78 79 oflags = O_RDWR; 80 while ((c = getopt(argc, argv, "lr")) != -1) { 81 switch (c) { 82 case 'l': 83 lflag = 1; 84 oflags = O_RDONLY; 85 break; 86 case 'r': 87 rflag = 1; 88 oflags = O_RDONLY; 89 break; 90 default: 91 usage(); 92 break; 93 } 94 } 95 96 argc -= optind; 97 argv += optind; 98 99 if (argc != 1) 100 usage(); 101 102 fd = opendev(*argv, oflags, OPENDEV_PART, NULL); 103 if (fd == -1) 104 err(1, "can't open file '%s'", *argv); 105 106 if (fstat(fd, &st) == -1) 107 err(1, "can't fstat %s", *argv); 108 if (!S_ISCHR(st.st_mode)) 109 errx(1, "%s is not a character device", *argv); 110 111 if (ioctl(fd, DIOCGPDINFO, &dl) == -1) 112 err(1, "can't get disklabel for %s", *argv); 113 if (dl.d_secsize != DEV_BSIZE) 114 errx(1, "disk sector size (%d) != 512\n", dl.d_secsize); 115 116 if (pledge("stdio", NULL) == -1) 117 err(1, "pledge"); 118 119 map = open_partition_map(fd, *argv, DL_GETDSIZE(&dl), dl.d_secsize); 120 if (map != NULL) { 121 if (lflag) 122 dump_partition_map(map); 123 else 124 edit(&map); 125 } 126 127 free_partition_map(map); 128 close(fd); 129 130 return 0; 131 } 132 133 /* 134 * Edit the file 135 */ 136 void 137 edit(struct partition_map **mapp) 138 { 139 struct partition_map *map = *mapp; 140 struct partition_map *oldmap; 141 int command; 142 143 printf("Edit %s -\n", map->name); 144 145 while (get_command("Command (? for help): ", first_get, &command)) { 146 first_get = 0; 147 148 switch (command) { 149 case '?': 150 printf("Notes:\n" 151 " Base and length fields are blocks, which " 152 "vary in size between media.\n" 153 " The base field can be <nth>p; i.e. the " 154 "base of the nth partition.\n" 155 " The length field can be a length followed " 156 "by k, m, g or t to indicate\n" 157 " kilo, mega, giga, or tera bytes.\n" 158 " The length field can also be <nth>p; i.e. " 159 "the length of the nth partition.\n" 160 " The name of a partition is descriptive " 161 "text.\n\n"); 162 163 /* fall through */ 164 case 'h': 165 printf("Commands are:\n" 166 " ? verbose command help\n" 167 " C create a partition of a specified type\n" 168 " c create an OpenBSD partition\n" 169 " d delete a partition\n" 170 " f full display of a partition\n" 171 " h command help\n" 172 " i (re)initialize the partition map\n" 173 " n (re)name a partition\n" 174 " P show the partition map's data structures\n" 175 " p print the partition map\n" 176 " q quit editing\n" 177 " r reorder (swap) disk positions of two " 178 "entries in the partition map\n" 179 " s change the size of the partition map\n" 180 " t change the type of a partition\n" 181 " w write the partition map to disk\n"); 182 break; 183 case 'P': 184 do_dump_map(map, 1); 185 break; 186 case 'p': 187 do_dump_map(map, 0); 188 break; 189 case 'q': 190 if (map->changed) { 191 if (get_okay("Discard changes? [n/y]: ", 0) != 192 1) { 193 break; 194 } 195 } 196 flush_to_newline(1); 197 return; 198 case 'i': 199 if (get_okay("Discard current map? [n/y]: ", 0) == 1) { 200 oldmap = map; 201 map = create_partition_map(oldmap->fd, 202 oldmap->name, oldmap->media_size, 203 oldmap->sbBlkSize); 204 if (map == NULL) 205 break; 206 *mapp = map; 207 free_partition_map(oldmap); 208 } 209 break; 210 case 'C': 211 do_create_partition(map, 1); 212 break; 213 case 'c': 214 do_create_partition(map, 0); 215 break; 216 case 'n': 217 do_rename_partition(map); 218 break; 219 case 'd': 220 do_delete_partition(map); 221 break; 222 case 'r': 223 do_reorder(map); 224 break; 225 case 's': 226 do_change_map_size(map); 227 break; 228 case 't': 229 do_change_type(map); 230 break; 231 case 'w': 232 do_write_partition_map(map); 233 break; 234 case 'f': 235 do_display_entry(map); 236 break; 237 default: 238 bad_input("No such command (%c)", command); 239 break; 240 } 241 } 242 } 243 244 void 245 do_create_partition(struct partition_map *map, int get_type) 246 { 247 long base, length; 248 char *name = NULL; 249 char *type = NULL; 250 251 if (get_base_argument(&base, map) == 0) 252 return; 253 if (get_size_argument(&length, map) == 0) 254 return; 255 256 name = get_dpistr_argument("Name of partition: "); 257 if (name == NULL) { 258 bad_input("Bad name"); 259 goto out; 260 } 261 262 if (get_type == 0) 263 type = strdup(kUnixType); 264 else 265 type = get_dpistr_argument("Type of partition: "); 266 if (type == NULL) { 267 bad_input("Bad type"); 268 goto out; 269 } 270 271 if (strncasecmp(type, kFreeType, DPISTRLEN) == 0) { 272 bad_input("Can't create a partition with the Free type"); 273 goto out; 274 } 275 if (strncasecmp(type, kMapType, DPISTRLEN) == 0) { 276 bad_input("Can't create a partition with the Map type"); 277 goto out; 278 } 279 280 add_partition_to_map(name, type, base, length, map); 281 282 out: 283 free(type); 284 free(name); 285 286 return; 287 } 288 289 int 290 get_base_argument(long *number, struct partition_map *map) 291 { 292 struct entry *entry; 293 int result = 0; 294 295 if (get_number_argument("First block: ", number) == 0) { 296 bad_input("Bad block number"); 297 } else { 298 result = 1; 299 if (get_partition_modifier()) { 300 entry = find_entry_by_disk_address(*number, map); 301 if (entry == NULL) { 302 bad_input("Bad partition number"); 303 result = 0; 304 } else { 305 *number = entry->dpme_pblock_start; 306 } 307 } 308 } 309 return result; 310 } 311 312 313 int 314 get_size_argument(long *number, struct partition_map *map) 315 { 316 struct entry *entry; 317 unsigned long multiple; 318 int result = 0; 319 320 if (get_number_argument("Length in blocks: ", number) == 0) { 321 bad_input("Bad length"); 322 } else { 323 multiple = get_multiplier(map->sbBlkSize); 324 if (multiple == 0) { 325 bad_input("Bad multiplier"); 326 } else if (multiple != 1) { 327 *number *= multiple; 328 result = 1; 329 } else if (get_partition_modifier()) { 330 entry = find_entry_by_disk_address(*number, map); 331 if (entry == NULL) { 332 bad_input("Bad partition number"); 333 } else { 334 *number = entry->dpme_pblocks; 335 result = 1; 336 } 337 } else { 338 result = 1; 339 } 340 } 341 return result; 342 } 343 344 345 void 346 do_rename_partition(struct partition_map *map) 347 { 348 struct entry *entry; 349 char *name; 350 long ix; 351 352 if (get_number_argument("Partition number: ", &ix) == 0) { 353 bad_input("Bad partition number"); 354 return; 355 } 356 entry = find_entry_by_disk_address(ix, map); 357 if (entry == NULL) { 358 printf("No such partition\n"); 359 return; 360 } 361 362 printf("Existing partition name ``%s''.\n", entry->dpme_name); 363 name = get_dpistr_argument("New name of partition: "); 364 if (name == NULL) { 365 bad_input("Bad name"); 366 return; 367 } 368 369 /* 370 * Since dpme_name is supposed to be NUL-filled, make sure 371 * current contents are zapped before copying in new name! 372 */ 373 memset(entry->dpme_name, 0, sizeof(entry->dpme_name)); 374 strlcpy(entry->dpme_name, name, sizeof(entry->dpme_name)); 375 map->changed = 1; 376 377 free(name); 378 return; 379 } 380 381 void 382 do_change_type(struct partition_map *map) 383 { 384 struct entry *entry; 385 char *type; 386 long ix; 387 388 if (get_number_argument("Partition number: ", &ix) == 0) { 389 bad_input("Bad partition number"); 390 return; 391 } 392 entry = find_entry_by_disk_address(ix, map); 393 if (entry == NULL) { 394 printf("No such partition\n"); 395 return; 396 } 397 398 printf("Existing partition type ``%s''.\n", entry->dpme_type); 399 type = get_dpistr_argument("New type of partition: "); 400 if (type == NULL) { 401 bad_input("Bad type"); 402 return; 403 } 404 405 /* 406 * Since dpme_type is supposed to be NUL-filled, make sure 407 * current contents are zapped before copying in new type! 408 */ 409 memset(entry->dpme_type, 0, sizeof(entry->dpme_type)); 410 strncpy(entry->dpme_type, type, sizeof(entry->dpme_type)); 411 map->changed = 1; 412 413 free(type); 414 return; 415 } 416 417 418 void 419 do_delete_partition(struct partition_map *map) 420 { 421 struct entry *cur; 422 long ix; 423 424 if (get_number_argument("Partition number: ", &ix) == 0) { 425 bad_input("Bad partition number"); 426 return; 427 } 428 429 cur = find_entry_by_disk_address(ix, map); 430 if (cur == NULL) 431 printf("No such partition\n"); 432 else 433 delete_partition_from_map(cur); 434 } 435 436 437 void 438 do_reorder(struct partition_map *map) 439 { 440 long ix, old_index; 441 442 if (get_number_argument("Partition number: ", &old_index) == 0) { 443 bad_input("Bad partition number"); 444 return; 445 } 446 if (get_number_argument("New number: ", &ix) == 0) { 447 bad_input("Bad partition number"); 448 return; 449 } 450 move_entry_in_map(old_index, ix, map); 451 } 452 453 454 void 455 do_write_partition_map(struct partition_map *map) 456 { 457 if (map->changed == 0) { 458 bad_input("The map has not been changed."); 459 return; 460 } 461 if (rflag) { 462 bad_input("The map is not writable."); 463 return; 464 } 465 printf("Writing the map destroys what was there before. "); 466 if (get_okay("Is that okay? [n/y]: ", 0) != 1) { 467 return; 468 } 469 write_partition_map(map); 470 471 map->changed = 0; 472 } 473 474 475 void 476 do_change_map_size(struct partition_map *map) 477 { 478 long size; 479 480 if (get_number_argument("New size: ", &size) == 0) { 481 bad_input("Bad size"); 482 return; 483 } 484 resize_map(size, map); 485 } 486 487 488 void 489 do_display_entry(struct partition_map *map) 490 { 491 long number; 492 493 if (get_number_argument("Partition number: ", &number) == 0) { 494 bad_input("Bad partition number"); 495 return; 496 } 497 if (number == 0) 498 full_dump_block_zero(map); 499 else 500 full_dump_partition_entry(map, number); 501 } 502 503 void 504 do_dump_map(struct partition_map *map, int verbose) 505 { 506 if (verbose) 507 show_data_structures(map); 508 else 509 dump_partition_map(map); 510 } 511 512 __dead static void 513 usage(void) 514 { 515 extern char *__progname; 516 517 fprintf(stderr, "usage: %s [-lr] disk\n", __progname); 518 519 exit(1); 520 } 521