1 //
2 // pdisk - an editor for Apple format partition tables
3 //
4 // Written by Eryk Vershen
5 //
6 // Still under development (as of 15 January 1998)
7 //
8
9 /*
10 * Copyright 1996,1997,1998 by Apple Computer, Inc.
11 * All Rights Reserved
12 *
13 * Permission to use, copy, modify, and distribute this software and
14 * its documentation for any purpose and without fee is hereby granted,
15 * provided that the above copyright notice appears in all copies and
16 * that both the copyright notice and this permission notice appear in
17 * supporting documentation.
18 *
19 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE.
22 *
23 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
25 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
26 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
27 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 */
29
30 // for printf()
31 #include <stdio.h>
32
33 #if defined(__linux__) || defined(__NetBSD__)
34 #include <getopt.h>
35 #endif
36 #ifdef __linux__
37 #include <malloc.h>
38 #else
39 // for malloc() & free()
40 #include <stdlib.h>
41 #if !defined(__unix__)
42 // for SIOUXsettings
43 #include <SIOUX.h>
44 #endif
45 #endif
46
47 #ifdef __unix__
48 #include <unistd.h>
49 #endif
50
51 // for strncpy() & strlen()
52 #include <string.h>
53 // for O_RDONLY
54 #include <fcntl.h>
55 // for errno
56 #include <errno.h>
57
58 #ifdef __linux__
59 #include <sys/ioctl.h>
60 #include <linux/fs.h>
61 #include <linux/hdreg.h>
62 #endif
63
64 #include <stdint.h>
65
66 #include "pdisk.h"
67 #include "io.h"
68 #include "partition_map.h"
69 #include "pathname.h"
70 #include "hfs_misc.h"
71 #include "errors.h"
72 #include "dump.h"
73 #include "validate.h"
74 #include "version.h"
75 #include "util.h"
76
77
78 //
79 // Defines
80 //
81 #define ARGV_CHUNK 5
82 #define CFLAG_DEFAULT 0
83 #define DFLAG_DEFAULT 0
84 #define HFLAG_DEFAULT 0
85 #define INTERACT_DEFAULT 0
86 #define LFLAG_DEFAULT 0
87 #define RFLAG_DEFAULT 0
88 #define VFLAG_DEFAULT 0
89
90
91 //
92 // Types
93 //
94
95
96 //
97 // Global Constants
98 //
99 enum getopt_values {
100 kLongOption = 0,
101 kBadOption = '?',
102 kOptionArg = 1000,
103 kListOption = 1001,
104 kLogicalOption = 1002
105 };
106
107
108 //
109 // Global Variables
110 //
111 int lflag = LFLAG_DEFAULT; /* list the device */
112 char *lfile; /* list */
113 int vflag = VFLAG_DEFAULT; /* show version */
114 int hflag = HFLAG_DEFAULT; /* show help */
115 int dflag = DFLAG_DEFAULT; /* turn on debugging commands and printout */
116 int rflag = RFLAG_DEFAULT; /* open device read Only */
117 int interactive = INTERACT_DEFAULT;
118 int cflag = CFLAG_DEFAULT; /* compute device size */
119
120 static int first_get = 1;
121
122
123 //
124 // Forward declarations
125 //
126 void do_change_map_size(partition_map_header *map);
127 void do_update_dpme(partition_map *entry);
128 void do_create_partition(partition_map_header *map, int get_type);
129 void do_delete_partition(partition_map_header *map);
130 void do_display_block(partition_map_header *map, char *alt_name);
131 void do_display_entry(partition_map_header *map);
132 void do_examine_patch_partition(partition_map_header *map);
133 int do_expert(partition_map_header *map, char *name);
134 void do_rename_partition(partition_map_header *map);
135 void do_change_type(partition_map_header *map);
136 void do_reorder(partition_map_header *map);
137 void do_write_partition_map(partition_map_header *map);
138 void edit(char *name, int ask_logical_size);
139 int get_base_argument(long *number, partition_map_header *map);
140 int get_command_line(int *argc, char ***argv);
141 int get_size_argument(long *number, partition_map_header *map);
142 int get_options(int argc, char **argv);
143 void interact(void);
144 void print_edit_notes(void);
145 void print_expert_notes(void);
146 void print_top_notes(void);
147
148
149 //
150 // Routines
151 //
152 int
main(int argc,char ** argv)153 main(int argc, char **argv)
154 {
155 #if defined(__linux__) || defined(__unix__)
156 int name_index;
157 #else
158 SIOUXSettings.rows = 100;
159 printf("This app uses the SIOUX console library\n");
160 printf("Choose 'Quit' from the file menu to quit.\n\n");
161 printf("Use fake disk names (/dev/scsi<bus>.<id>; i.e. /dev/scsi0.1, /dev/scsi1.3, etc.).\n\n");
162
163 SIOUXSettings.autocloseonquit = 0; /* Do we close the SIOUX window on program termination ... */
164 SIOUXSettings.asktosaveonclose = 0; /* Do we offer to save on a close ... */
165 #endif
166
167 init_program_name(argv);
168
169 if (sizeof(DPME) != PBLOCK_SIZE) {
170 fatal(-1, "Size of partition map entry (%zu) "
171 "is not equal to block size (%d)\n", sizeof(DPME), PBLOCK_SIZE);
172 }
173 if (sizeof(Block0) != PBLOCK_SIZE) {
174 fatal(-1, "Size of block zero structure (%zu) "
175 "is not equal to block size (%d)\n", sizeof(Block0), PBLOCK_SIZE);
176 }
177 if (strcmp(VERSION, get_version_string()) != 0) {
178 fatal(-1, "Version string static form (%s) does not match dynamic form (%s)\n",
179 VERSION, get_version_string());
180 }
181
182 #if defined(__linux__) || defined(__unix__)
183 name_index = get_options(argc, argv);
184
185 if (vflag) {
186 printf("version " VERSION " (" RELEASE_DATE ")\n");
187 }
188 if (hflag) {
189 do_help();
190 } else if (interactive) {
191 interact();
192 } else if (lflag) {
193 if (lfile != NULL) {
194 dump(lfile);
195 } else if (name_index < argc) {
196 while (name_index < argc) {
197 dump(argv[name_index++]);
198 }
199 } else {
200 #ifdef __linux__
201 list_all_disks();
202 #else
203 usage("no device argument");
204 do_help();
205 #endif
206 }
207 } else if (name_index < argc) {
208 while (name_index < argc) {
209 edit(argv[name_index++], 0);
210 }
211 } else if (!vflag) {
212 usage("no device argument");
213 do_help();
214 }
215 return 0;
216 #else
217 interactive = 1;
218
219 interact();
220
221 SIOUXSettings.autocloseonquit = 1;
222 //printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n");
223 exit(0);
224 #endif
225 }
226
227
228 void
print_top_notes(void)229 print_top_notes(void)
230 {
231 printf("Notes:\n");
232 printf(" Disks have fake names of the form /dev/scsi<bus>.<id>\n");
233 printf(" For example, /dev/scsi0.1, /dev/scsi1.3, and so on.\n");
234 printf(" Linux style names are also allowed (i.e /dev/sda or /dev/hda).\n");
235 printf(" Due to some technical problems these names may not match\n");
236 printf(" the 'real' linux names.\n");
237 printf("\n");
238 }
239
240
241 void
interact(void)242 interact(void)
243 {
244 char *name;
245 int command;
246 int ask_logical_size;
247
248 while (get_command("Top level command (? for help): ", first_get, &command)) {
249 first_get = 0;
250 ask_logical_size = 0;
251
252 switch (command) {
253 case '?':
254 print_top_notes();
255 // fall through
256 case 'H':
257 case 'h':
258 printf("Commands are:\n");
259 printf(" h print help\n");
260 printf(" v print the version number and release date\n");
261 printf(" l list device's map\n");
262 #ifdef __linux__
263 printf(" L list all devices' maps\n");
264 #endif
265 printf(" e edit device's map\n");
266 printf(" E (edit map with specified block size)\n");
267 printf(" r toggle readonly flag\n");
268 printf(" f toggle show filesystem name flag\n");
269 if (dflag) {
270 printf(" a toggle abbreviate flag\n");
271 printf(" p toggle physical flag\n");
272 printf(" c toggle compute size flag\n");
273 printf(" d toggle debug flag\n");
274 printf(" x examine block n of device\n");
275 }
276 printf(" q quit the program\n");
277 break;
278 case 'Q':
279 case 'q':
280 return;
281 break;
282 case 'V':
283 case 'v':
284 printf("version " VERSION " (" RELEASE_DATE ")\n");
285 break;
286 #ifdef __linux__
287 case 'L':
288 list_all_disks();
289 break;
290 #endif
291 case 'l':
292 if (get_string_argument("Name of device: ", &name, 1) == 0) {
293 bad_input("Bad name");
294 break;
295 }
296 dump(name);
297 free(name);
298 break;
299 case 'E':
300 ask_logical_size = 1;
301 case 'e':
302 if (get_string_argument("Name of device: ", &name, 1) == 0) {
303 bad_input("Bad name");
304 break;
305 }
306 edit(name, ask_logical_size);
307 free(name);
308 break;
309 case 'R':
310 case 'r':
311 if (rflag) {
312 rflag = 0;
313 } else {
314 rflag = 1;
315 }
316 printf("Now in %s mode.\n", (rflag)?"readonly":"read/write");
317 break;
318 case 'F':
319 case 'f':
320 if (fflag) {
321 fflag = 0;
322 } else {
323 fflag = 1;
324 }
325 printf("Now in show %s name mode.\n", (fflag)?"filesystem":"partition");
326 break;
327 case 'A':
328 case 'a':
329 if (dflag) {
330 if (aflag) {
331 aflag = 0;
332 } else {
333 aflag = 1;
334 }
335 printf("Now in %s mode.\n", (aflag)?"abbreviate":"full type");
336 } else {
337 goto do_error;
338 }
339 break;
340 case 'P':
341 case 'p':
342 if (dflag) {
343 if (pflag) {
344 pflag = 0;
345 } else {
346 pflag = 1;
347 }
348 printf("Now in %s mode.\n", (pflag)?"physical":"logical");
349 } else {
350 goto do_error;
351 }
352 break;
353 case 'D':
354 case 'd':
355 if (dflag) {
356 dflag = 0;
357 } else {
358 dflag = 1;
359 }
360 printf("Now in %s mode.\n", (dflag)?"debug":"normal");
361 break;
362 case 'C':
363 case 'c':
364 if (dflag) {
365 if (cflag) {
366 cflag = 0;
367 } else {
368 cflag = 1;
369 }
370 printf("Now in %s device size mode.\n", (cflag)?"always compute":"use existing");
371 } else {
372 goto do_error;
373 }
374 break;
375 case 'X':
376 case 'x':
377 if (dflag) {
378 do_display_block(0, 0);
379 } else {
380 goto do_error;
381 }
382 break;
383 default:
384 do_error:
385 bad_input("No such command (%c)", command);
386 break;
387 }
388 }
389 }
390
391
392 #if defined(__linux__) || defined(__unix__)
393 int
get_options(int argc,char ** argv)394 get_options(int argc, char **argv)
395 {
396 int c;
397 #if defined(__linux__) || defined(__NetBSD__)
398 static struct option long_options[] =
399 {
400 // name has_arg &flag val
401 {"help", no_argument, 0, 'h'},
402 {"list", optional_argument, 0, kListOption},
403 {"version", no_argument, 0, 'v'},
404 {"debug", no_argument, 0, 'd'},
405 {"readonly", no_argument, 0, 'r'},
406 {"abbr", no_argument, 0, 'a'},
407 {"fname", no_argument, 0, 'f'},
408 {"logical", no_argument, 0, kLogicalOption},
409 {"interactive", no_argument, 0, 'i'},
410 {"compute_size", no_argument, 0, 'c'},
411 {0, 0, 0, 0}
412 };
413 int option_index = 0;
414 #else
415 extern int opterr; /* who does error messages */
416 extern int optopt; /* char that caused the error */
417 int getopt_error; /* getopt choked */
418 #endif
419 extern int optind; /* next argv index */
420 extern char *optarg; /* pointer to argument */
421 int flag = 0;
422
423 lflag = LFLAG_DEFAULT;
424 lfile = NULL;
425 vflag = VFLAG_DEFAULT;
426 hflag = HFLAG_DEFAULT;
427 dflag = DFLAG_DEFAULT;
428 rflag = RFLAG_DEFAULT;
429 aflag = AFLAG_DEFAULT;
430 pflag = PFLAG_DEFAULT;
431 interactive = INTERACT_DEFAULT;
432 cflag = CFLAG_DEFAULT;
433 fflag = FFLAG_DEFAULT;
434
435 #if defined(__linux__) || defined(__NetBSD__)
436 optind = 0; // reset option scanner logic
437 while ((c = getopt_long(argc, argv, "hlvdraLicf", long_options,
438 &option_index)) >= 0)
439 #else
440 opterr = 0; /* tell getopt to be quiet */
441 while ((c = getopt(argc, argv, "hlvdraLicf")) != EOF)
442 #endif
443 {
444 #if !(defined(__linux__) || defined(__NetBSD__))
445 if (c == '?') {
446 getopt_error = 1;
447 c = optopt;
448 } else {
449 getopt_error = 0;
450 }
451 #endif
452 switch (c) {
453 case kLongOption:
454 // option_index would be used here
455 break;
456 case 'h':
457 hflag = (HFLAG_DEFAULT)?0:1;
458 break;
459 case kListOption:
460 if (optarg != NULL) {
461 lfile = optarg;
462 }
463 // fall through
464 case 'l':
465 lflag = (LFLAG_DEFAULT)?0:1;
466 break;
467 case 'v':
468 vflag = (VFLAG_DEFAULT)?0:1;
469 break;
470 case 'd':
471 dflag = (DFLAG_DEFAULT)?0:1;
472 break;
473 case 'c':
474 cflag = (CFLAG_DEFAULT)?0:1;
475 break;
476 case 'r':
477 rflag = (RFLAG_DEFAULT)?0:1;
478 break;
479 case 'f':
480 fflag = (FFLAG_DEFAULT)?0:1;
481 break;
482 case 'i':
483 interactive = (INTERACT_DEFAULT)?0:1;
484 break;
485 case 'a':
486 aflag = (AFLAG_DEFAULT)?0:1;
487 break;
488 case 'L':
489 case kLogicalOption:
490 pflag = (PFLAG_DEFAULT)?0:1;
491 break;
492 case kBadOption:
493 default:
494 flag = 1;
495 break;
496 }
497 }
498 if (flag) {
499 usage("bad arguments");
500 }
501 return optind;
502 }
503 #endif
504
505
506 void
print_edit_notes(void)507 print_edit_notes(void)
508 {
509 printf("Notes:\n");
510 printf(" Base and length fields are blocks, which vary in size between media.\n");
511 printf(" The base field can be <nth>p; i.e. use the base of the nth partition.\n");
512 printf(" The length field can be a length followed by k, m, g or t to indicate\n");
513 printf(" kilo, mega, giga, or tera bytes; also the length can be <nth>p; i.e. use\n");
514 printf(" the length of the nth partition.\n");
515 printf(" The name of a partition is descriptive text.\n");
516 printf("\n");
517 }
518
519
520 //
521 // Edit the file
522 //
523 void
edit(char * name,int ask_logical_size)524 edit(char *name, int ask_logical_size)
525 {
526 partition_map_header *map;
527 int command;
528 int order;
529 int get_type;
530 int valid_file;
531
532 map = open_partition_map(name, &valid_file, ask_logical_size);
533 if (!valid_file) {
534 return;
535 }
536
537 printf("Edit %s -\n", name);
538
539 #if 0 /* this check is not found in linux fdisk-0.1 */
540 if (map != NULL && map->blocks_in_map > MAX_LINUX_MAP) {
541 error(-1, "Map contains more than %d blocks - Linux may have trouble", MAX_LINUX_MAP);
542 }
543 #endif
544
545 while (get_command("Command (? for help): ", first_get, &command)) {
546 first_get = 0;
547 order = 1;
548 get_type = 0;
549
550 switch (command) {
551 case '?':
552 print_edit_notes();
553 // fall through
554 case 'H':
555 case 'h':
556 printf("Commands are:\n");
557 printf(" C (create with type also specified)\n");
558 printf(" c create new partition (standard unix root)\n");
559 printf(" d delete a partition\n");
560 printf(" h help\n");
561 printf(" i initialize partition map\n");
562 printf(" n (re)name a partition\n");
563 printf(" P (print ordered by base address)\n");
564 printf(" p print the partition table\n");
565 printf(" q quit editing\n");
566 printf(" r reorder partition entry in map\n");
567 printf(" s change size of partition map\n");
568 printf(" t change a partition's type\n");
569 if (!rflag) {
570 printf(" w write the partition table\n");
571 }
572 if (dflag) {
573 printf(" x extra extensions for experts\n");
574 }
575 break;
576 case 'P':
577 order = 0;
578 // fall through
579 case 'p':
580 dump_partition_map(map, order);
581 break;
582 case 'Q':
583 case 'q':
584 if (map && map->changed) {
585 if (get_okay("Discard changes? [n/y]: ", 0) != 1) {
586 break;
587 }
588 }
589 flush_to_newline(1);
590 goto finis;
591 break;
592 case 'I':
593 case 'i':
594 map = init_partition_map(name, map);
595 break;
596 case 'C':
597 get_type = 1;
598 // fall through
599 case 'c':
600 do_create_partition(map, get_type);
601 break;
602 case 'N':
603 case 'n':
604 do_rename_partition(map);
605 break;
606 case 'D':
607 case 'd':
608 do_delete_partition(map);
609 break;
610 case 'R':
611 case 'r':
612 do_reorder(map);
613 break;
614 case 'S':
615 case 's':
616 do_change_map_size(map);
617 break;
618 case 'T':
619 case 't':
620 do_change_type(map);
621 break;
622 case 'X':
623 case 'x':
624 if (!dflag) {
625 goto do_error;
626 } else if (do_expert(map, name)) {
627 flush_to_newline(1);
628 goto finis;
629 }
630 break;
631 case 'W':
632 case 'w':
633 if (!rflag) {
634 do_write_partition_map(map);
635 } else {
636 goto do_error;
637 }
638 break;
639 default:
640 do_error:
641 bad_input("No such command (%c)", command);
642 break;
643 }
644 }
645 finis:
646
647 close_partition_map(map);
648 }
649
650 void
do_update_dpme(partition_map * entry)651 do_update_dpme(partition_map *entry)
652 {
653 int slice = 0;
654 if (!entry) return;
655 dpme_init_flags(entry->data);
656 entry->HFS_name = get_HFS_name(entry, &entry->HFS_kind);
657 if (istrncmp(entry->data->dpme_type, kUnixType, DPISTRLEN) == 0) {
658 printf("Available partition slices for %s:\n",entry->data->dpme_type);
659 printf(" a root partition\n");
660 printf(" b swap partition\n");
661 printf(" c do not set any bzb bits\n");
662 printf(" g user partition\n");
663 printf("Other lettered values will create user partitions\n");
664 get_command("Select a slice for default bzb values: ",0,&slice);
665 }
666 bzb_init_slice((BZB *)entry->data->dpme_bzb,slice);
667 entry->the_map->changed = 1;
668 }
669
670 void
do_create_partition(partition_map_header * map,int get_type)671 do_create_partition(partition_map_header *map, int get_type)
672 {
673 long base;
674 long length;
675 char *name = 0;
676 char *type_name = 0;
677
678 if (map == NULL) {
679 bad_input("No partition map exists");
680 return;
681 }
682 if (!rflag && map->writable == 0) {
683 printf("The map is not writable.\n");
684 }
685 // XXX add help feature (i.e. '?' in any argument routine prints help string)
686 if (get_base_argument(&base, map) == 0) {
687 return;
688 }
689 if (get_size_argument(&length, map) == 0) {
690 return;
691 }
692
693 if (get_string_argument("Name of partition: ", &name, 1) == 0) {
694 bad_input("Bad name");
695 return;
696 }
697 if (get_type == 0) {
698 add_partition_to_map(name, kUnixType, base, length, map);
699 #if 0 /* this check is not found in linux fdisk-0.1 */
700 if (map->blocks_in_map > MAX_LINUX_MAP) {
701 error(-1, "Map contains more than %d blocks - Linux may have trouble", MAX_LINUX_MAP);
702 }
703 goto xit1;
704 #endif
705 } else if (get_string_argument("Type of partition: ", &type_name, 1) == 0) {
706 bad_input("Bad type");
707 goto xit1;
708 } else {
709 if (istrncmp(type_name, kFreeType, DPISTRLEN) == 0) {
710 bad_input("Can't create a partition with the Free type");
711 goto xit2;
712 }
713 if (istrncmp(type_name, kMapType, DPISTRLEN) == 0) {
714 bad_input("Can't create a partition with the Map type");
715 goto xit2;
716 }
717 add_partition_to_map(name, type_name, base, length, map);
718 #if 0 /* this check is not found in linux fdisk-0.1 */
719 if (map->blocks_in_map > MAX_LINUX_MAP) {
720 error(-1, "Map contains more than %d blocks - Linux may have trouble", MAX_LINUX_MAP);
721 }
722 #endif
723 }
724 do_update_dpme(find_entry_by_base(base,map));
725 xit2:
726 if (type_name)
727 free(type_name);
728 xit1:
729 if (name)
730 free(name);
731 return;
732 }
733
734
735 int
get_base_argument(long * number,partition_map_header * map)736 get_base_argument(long *number, partition_map_header *map)
737 {
738 partition_map * entry;
739 int result = 0;
740
741 if (get_number_argument("First block: ", number, kDefault) == 0) {
742 bad_input("Bad block number");
743 } else {
744 result = 1;
745 if (get_partition_modifier()) {
746 entry = find_entry_by_disk_address(*number, map);
747 if (entry == NULL) {
748 bad_input("Bad partition number");
749 result = 0;
750 } else {
751 *number = entry->data->dpme_pblock_start;
752 }
753 }
754 }
755 return result;
756 }
757
758
759 int
get_size_argument(long * number,partition_map_header * map)760 get_size_argument(long *number, partition_map_header *map)
761 {
762 partition_map * entry;
763 int result = 0;
764 uint32_t multiple;
765
766 if (get_number_argument("Length in blocks: ", number, kDefault) == 0) {
767 bad_input("Bad length");
768 } else {
769 multiple = get_multiplier(map->logical_block);
770 if (multiple == 0) {
771 bad_input("Bad multiplier");
772 } else if (multiple != 1) {
773 *number *= multiple;
774 result = 1;
775 } else if (get_partition_modifier()) {
776 entry = find_entry_by_disk_address(*number, map);
777 if (entry == NULL) {
778 bad_input("Bad partition number");
779 } else {
780 *number = entry->data->dpme_pblocks;
781 result = 1;
782 }
783 } else {
784 result = 1;
785 }
786 }
787 return result;
788 }
789
790
791 void
do_rename_partition(partition_map_header * map)792 do_rename_partition(partition_map_header *map)
793 {
794 partition_map * entry;
795 long ix;
796 char *name;
797
798 if (map == NULL) {
799 bad_input("No partition map exists");
800 return;
801 }
802 if (!rflag && map->writable == 0) {
803 printf("The map is not writable.\n");
804 }
805 if (get_number_argument("Partition number: ", &ix, kDefault) == 0) {
806 bad_input("Bad partition number");
807 return;
808 }
809 if (get_string_argument("New name of partition: ", &name, 1) == 0) {
810 bad_input("Bad name");
811 return;
812 }
813
814 // find partition and change it
815 entry = find_entry_by_disk_address(ix, map);
816 if (entry == NULL) {
817 printf("No such partition\n");
818 } else {
819 // stuff name into partition map entry data
820 strncpy(entry->data->dpme_name, name, DPISTRLEN);
821 map->changed = 1;
822 }
823 free(name);
824 return;
825 }
826
827 void
do_change_type(partition_map_header * map)828 do_change_type(partition_map_header *map)
829 {
830 partition_map * entry;
831 long ix;
832 char *type = NULL;
833
834 if (map == NULL) {
835 bad_input("No partition map exists");
836 return;
837 }
838
839 if (!rflag && map->writable == 0) {
840 printf("The map is not writeable.\n");
841 }
842
843 if (get_number_argument("Partition number: ", &ix, kDefault) == 0) {
844 bad_input("Bad partition number");
845 return;
846 }
847
848 entry = find_entry_by_disk_address(ix, map);
849
850 if (entry == NULL ) {
851 printf("No such partition\n");
852 goto out;
853 }
854
855 printf("Existing partition type ``%s''.\n", entry->data->dpme_type);
856 if (get_string_argument("New type of partition: ", &type, 1) == 0) {
857 bad_input("Bad type");
858 goto out;
859 }
860
861 strncpy(entry->data->dpme_type, type, DPISTRLEN);
862 do_update_dpme(entry);
863 map->changed = 1;
864
865 out:
866 if (type)
867 free(type);
868 return;
869 }
870
871
872 void
do_delete_partition(partition_map_header * map)873 do_delete_partition(partition_map_header *map)
874 {
875 partition_map * cur;
876 long ix;
877
878 if (map == NULL) {
879 bad_input("No partition map exists");
880 return;
881 }
882 if (!rflag && map->writable == 0) {
883 printf("The map is not writable.\n");
884 }
885 if (get_number_argument("Partition number: ", &ix, kDefault) == 0) {
886 bad_input("Bad partition number");
887 return;
888 }
889
890 // find partition and delete it
891 cur = find_entry_by_disk_address(ix, map);
892 if (cur == NULL) {
893 printf("No such partition\n");
894 } else {
895 delete_partition_from_map(cur);
896 }
897 }
898
899
900 void
do_reorder(partition_map_header * map)901 do_reorder(partition_map_header *map)
902 {
903 long old_index;
904 long ix;
905
906 if (map == NULL) {
907 bad_input("No partition map exists");
908 return;
909 }
910 if (!rflag && map->writable == 0) {
911 printf("The map is not writable.\n");
912 }
913 if (get_number_argument("Partition number: ", &old_index, kDefault) == 0) {
914 bad_input("Bad partition number");
915 return;
916 }
917 if (get_number_argument("New number: ", &ix, kDefault) == 0) {
918 bad_input("Bad partition number");
919 return;
920 }
921
922 move_entry_in_map(old_index, ix, map);
923 }
924
925
926 void
do_write_partition_map(partition_map_header * map)927 do_write_partition_map(partition_map_header *map)
928 {
929 if (map == NULL) {
930 bad_input("No partition map exists");
931 return;
932 }
933 if (map->changed == 0 && map->written == 0) {
934 bad_input("The map has not been changed.");
935 return;
936 }
937 if (map->writable == 0) {
938 bad_input("The map is not writable.");
939 return;
940 }
941 #if 0 /* this check is not found in linux fdisk-0.1 */
942 if (map->blocks_in_map > MAX_LINUX_MAP) {
943 error(-1, "Map contains more than %d blocks - Linux may have trouble", MAX_LINUX_MAP);
944 }
945 #endif
946 printf("Writing the map destroys what was there before. ");
947 if (get_okay("Is that okay? [n/y]: ", 0) != 1) {
948 return;
949 }
950
951 write_partition_map(map);
952
953 map->changed = 0;
954 map->written = 1;
955
956 // exit(0);
957 }
958
959
960 void
print_expert_notes(void)961 print_expert_notes(void)
962 {
963 printf("Notes:\n");
964 printf(" The expert commands are for low level and experimental features.\n");
965 printf(" These commands are available only when debug mode is on.\n");
966 printf("\n");
967 }
968
969
970 int
do_expert(partition_map_header * map,char * name)971 do_expert(partition_map_header *map, char *name)
972 {
973 int command;
974 int quit = 0;
975
976 while (get_command("Expert command (? for help): ", first_get, &command)) {
977 first_get = 0;
978
979 switch (command) {
980 case '?':
981 print_expert_notes();
982 // fall through
983 case 'H':
984 case 'h':
985 printf("Commands are:\n");
986 printf(" h print help\n");
987 printf(" d dump block n\n");
988 printf(" p print the partition table\n");
989 if (dflag) {
990 printf(" P (show data structures - debugging)\n");
991 }
992 printf(" f full display of nth entry\n");
993 printf(" v validate map\n");
994 printf(" e examine patch partition\n");
995 printf(" q return to main edit menu\n");
996 printf(" Q quit editing\n");
997 break;
998 case 'q':
999 flush_to_newline(1);
1000 goto finis;
1001 break;
1002 case 'Q':
1003 if (map->changed) {
1004 if (get_okay("Discard changes? [n/y]: ", 0) != 1) {
1005 break;
1006 }
1007 }
1008 quit = 1;
1009 goto finis;
1010 break;
1011 case 'P':
1012 if (dflag) {
1013 show_data_structures(map);
1014 break;
1015 }
1016 // fall through
1017 case 'p':
1018 dump_partition_map(map, 1);
1019 break;
1020 case 'D':
1021 case 'd':
1022 do_display_block(map, name);
1023 break;
1024 case 'F':
1025 case 'f':
1026 do_display_entry(map);
1027 break;
1028 case 'V':
1029 case 'v':
1030 validate_map(map);
1031 break;
1032 case 'E':
1033 case 'e':
1034 do_examine_patch_partition(map);
1035 break;
1036 default:
1037 bad_input("No such command (%c)", command);
1038 break;
1039 }
1040 }
1041 finis:
1042 return quit;
1043 }
1044
1045 void
do_change_map_size(partition_map_header * map)1046 do_change_map_size(partition_map_header *map)
1047 {
1048 long size;
1049
1050 if (map == NULL) {
1051 bad_input("No partition map exists");
1052 return;
1053 }
1054 if (!rflag && map->writable == 0) {
1055 printf("The map is not writable.\n");
1056 }
1057 if (get_number_argument("New size: ", &size, kDefault) == 0) {
1058 bad_input("Bad size");
1059 return;
1060 }
1061 resize_map(size, map);
1062 }
1063
1064
1065 void
do_display_block(partition_map_header * map,char * alt_name)1066 do_display_block(partition_map_header *map, char *alt_name)
1067 {
1068 MEDIA m;
1069 long number;
1070 char *name;
1071 static uint8_t *display_block;
1072 static int display_g;
1073 int g;
1074 static long next_number = -1;
1075
1076 if (map != NULL) {
1077 name = 0;
1078 m = map->m;
1079 g = map->logical_block;
1080 } else {
1081 if (alt_name == 0) {
1082 if (get_string_argument("Name of device: ", &name, 1) == 0) {
1083 bad_input("Bad name");
1084 return;
1085 }
1086 } else {
1087 name = strdup(alt_name);
1088 }
1089 m = open_pathname_as_media(name, O_RDONLY);
1090 if (m == 0) {
1091 error(errno, "can't open file '%s'", name);
1092 free(name);
1093 return;
1094 }
1095 g = media_granularity(m);
1096 if (g < PBLOCK_SIZE) {
1097 g = PBLOCK_SIZE;
1098 }
1099 }
1100 if (get_number_argument("Block number: ", &number, next_number) == 0) {
1101 bad_input("Bad block number");
1102 goto xit;
1103 }
1104 if (display_block == NULL || display_g < g) {
1105 if (display_block != NULL) {
1106 free(display_block);
1107 display_g = 0;
1108 }
1109 display_block = (uint8_t *) malloc(g);
1110 if (display_block == NULL) {
1111 error(errno, "can't allocate memory for display block buffer");
1112 goto xit;
1113 }
1114 display_g = g;
1115 }
1116 if (read_media(m, ((long long)number) * g, g, (char *)display_block) != 0) {
1117 printf("block %ld -", number);
1118 dump_block((uint8_t*) display_block, g);
1119 next_number = number + 1;
1120 }
1121
1122 xit:
1123 if (name) {
1124 close_media(m);
1125 free(name);
1126 }
1127 return;
1128 }
1129
1130
1131 void
do_display_entry(partition_map_header * map)1132 do_display_entry(partition_map_header *map)
1133 {
1134 long number;
1135
1136 if (map == NULL) {
1137 bad_input("No partition map exists");
1138 return;
1139 }
1140 if (get_number_argument("Partition number: ", &number, kDefault) == 0) {
1141 bad_input("Bad partition number");
1142 return;
1143 }
1144 if (number == 0) {
1145 full_dump_block_zero(map);
1146 } else {
1147 full_dump_partition_entry(map, number);
1148 }
1149 }
1150
1151
1152 void
do_examine_patch_partition(partition_map_header * map)1153 do_examine_patch_partition(partition_map_header *map)
1154 {
1155 partition_map * entry;
1156
1157 if (map == NULL) {
1158 bad_input("No partition map exists");
1159 return;
1160 }
1161 entry = find_entry_by_type(kPatchType, map);
1162 if (entry == NULL) {
1163 printf("No patch partition\n");
1164 } else {
1165 display_patches(entry);
1166 }
1167 }
1168