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