Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / pdisk / pdisk.c
blob9b5860d79e7e83146ee73ca9610d6409582079a7
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 //
9 /*
10 * Copyright 1996,1997,1998 by Apple Computer, Inc.
11 * All Rights Reserved
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.
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.
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.
30 // for printf()
31 #include <stdio.h>
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
47 #ifdef __unix__
48 #include <unistd.h>
49 #endif
51 // for strncpy() & strlen()
52 #include <string.h>
53 // for O_RDONLY
54 #include <fcntl.h>
55 // for errno
56 #include <errno.h>
58 #ifdef __linux__
59 #include <sys/ioctl.h>
60 #include <linux/fs.h>
61 #include <linux/hdreg.h>
62 #endif
64 #include "pdisk.h"
65 #include "io.h"
66 #include "partition_map.h"
67 #include "pathname.h"
68 #include "hfs_misc.h"
69 #include "errors.h"
70 #include "dump.h"
71 #include "validate.h"
72 #include "version.h"
73 #include "util.h"
77 // Defines
79 #define ARGV_CHUNK 5
80 #define CFLAG_DEFAULT 0
81 #define DFLAG_DEFAULT 0
82 #define HFLAG_DEFAULT 0
83 #define INTERACT_DEFAULT 0
84 #define LFLAG_DEFAULT 0
85 #define RFLAG_DEFAULT 0
86 #define VFLAG_DEFAULT 0
90 // Types
95 // Global Constants
97 enum getopt_values {
98 kLongOption = 0,
99 kBadOption = '?',
100 kOptionArg = 1000,
101 kListOption = 1001,
102 kLogicalOption = 1002
107 // Global Variables
109 int lflag = LFLAG_DEFAULT; /* list the device */
110 char *lfile; /* list */
111 int vflag = VFLAG_DEFAULT; /* show version */
112 int hflag = HFLAG_DEFAULT; /* show help */
113 int dflag = DFLAG_DEFAULT; /* turn on debugging commands and printout */
114 int rflag = RFLAG_DEFAULT; /* open device read Only */
115 int interactive = INTERACT_DEFAULT;
116 int cflag = CFLAG_DEFAULT; /* compute device size */
118 static int first_get = 1;
122 // Forward declarations
124 void do_change_map_size(partition_map_header *map);
125 void do_update_dpme(partition_map *entry);
126 void do_create_partition(partition_map_header *map, int get_type);
127 void do_delete_partition(partition_map_header *map);
128 void do_display_block(partition_map_header *map, char *alt_name);
129 void do_display_entry(partition_map_header *map);
130 void do_examine_patch_partition(partition_map_header *map);
131 int do_expert(partition_map_header *map, char *name);
132 void do_rename_partition(partition_map_header *map);
133 void do_change_type(partition_map_header *map);
134 void do_reorder(partition_map_header *map);
135 void do_write_partition_map(partition_map_header *map);
136 void edit(char *name, int ask_logical_size);
137 int get_base_argument(long *number, partition_map_header *map);
138 int get_command_line(int *argc, char ***argv);
139 int get_size_argument(long *number, partition_map_header *map);
140 int get_options(int argc, char **argv);
141 void interact(void);
142 void print_edit_notes(void);
143 void print_expert_notes(void);
144 void print_top_notes(void);
148 // Routines
151 main(int argc, char **argv)
153 #if defined(__linux__) || defined(__unix__)
154 int name_index;
155 #else
156 SIOUXSettings.rows = 100;
157 printf("This app uses the SIOUX console library\n");
158 printf("Choose 'Quit' from the file menu to quit.\n\n");
159 printf("Use fake disk names (/dev/scsi<bus>.<id>; i.e. /dev/scsi0.1, /dev/scsi1.3, etc.).\n\n");
161 SIOUXSettings.autocloseonquit = 0; /* Do we close the SIOUX window on program termination ... */
162 SIOUXSettings.asktosaveonclose = 0; /* Do we offer to save on a close ... */
163 #endif
165 init_program_name(argv);
167 if (sizeof(DPME) != PBLOCK_SIZE) {
168 fatal(-1, "Size of partition map entry (%d) "
169 "is not equal to block size (%d)\n",
170 sizeof(DPME), PBLOCK_SIZE);
172 if (sizeof(Block0) != PBLOCK_SIZE) {
173 fatal(-1, "Size of block zero structure (%d) "
174 "is not equal to block size (%d)\n",
175 sizeof(Block0), PBLOCK_SIZE);
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());
182 #if defined(__linux__) || defined(__unix__)
183 name_index = get_options(argc, argv);
185 if (vflag) {
186 printf("version " VERSION " (" RELEASE_DATE ")\n");
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++]);
199 } else {
200 #ifdef __linux__
201 list_all_disks();
202 #else
203 usage("no device argument");
204 do_help();
205 #endif
207 } else if (name_index < argc) {
208 while (name_index < argc) {
209 edit(argv[name_index++], 0);
211 } else if (!vflag) {
212 usage("no device argument");
213 do_help();
215 return 0;
216 #else
217 interactive = 1;
219 interact();
221 SIOUXSettings.autocloseonquit = 1;
222 //printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n");
223 exit(0);
224 #endif
228 void
229 print_top_notes()
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");
241 void
242 interact()
244 char *name;
245 int command;
246 int ask_logical_size;
248 while (get_command("Top level command (? for help): ", first_get, &command)) {
249 first_get = 0;
250 ask_logical_size = 0;
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");
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;
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;
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;
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;
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;
335 printf("Now in %s mode.\n", (aflag)?"abbreviate":"full type");
336 } else {
337 goto do_error;
339 break;
340 case 'P':
341 case 'p':
342 if (dflag) {
343 if (pflag) {
344 pflag = 0;
345 } else {
346 pflag = 1;
348 printf("Now in %s mode.\n", (pflag)?"physical":"logical");
349 } else {
350 goto do_error;
352 break;
353 case 'D':
354 case 'd':
355 if (dflag) {
356 dflag = 0;
357 } else {
358 dflag = 1;
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;
370 printf("Now in %s device size mode.\n", (cflag)?"always compute":"use existing");
371 } else {
372 goto do_error;
374 break;
375 case 'X':
376 case 'x':
377 if (dflag) {
378 do_display_block(0, 0);
379 } else {
380 goto do_error;
382 break;
383 default:
384 do_error:
385 bad_input("No such command (%c)", command);
386 break;
392 #if defined(__linux__) || defined(__unix__)
394 get_options(int argc, char **argv)
396 int c;
397 #if defined(__linux__) || defined(__NetBSD__)
398 static struct option long_options[] =
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}
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;
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;
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
444 #if !(defined(__linux__) || defined(__NetBSD__))
445 if (c == '?') {
446 getopt_error = 1;
447 c = optopt;
448 } else {
449 getopt_error = 0;
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;
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;
498 if (flag) {
499 usage("bad arguments");
501 return optind;
503 #endif
506 void
507 print_edit_notes()
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");
521 // Edit the file
523 void
524 edit(char *name, int ask_logical_size)
526 partition_map_header *map;
527 int command;
528 int order;
529 int get_type;
530 int valid_file;
532 map = open_partition_map(name, &valid_file, ask_logical_size);
533 if (!valid_file) {
534 return;
537 printf("Edit %s -\n", name);
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);
543 #endif
545 while (get_command("Command (? for help): ", first_get, &command)) {
546 first_get = 0;
547 order = 1;
548 get_type = 0;
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");
572 if (dflag) {
573 printf(" x extra extensions for experts\n");
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;
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;
630 break;
631 case 'W':
632 case 'w':
633 if (!rflag) {
634 do_write_partition_map(map);
635 } else {
636 goto do_error;
638 break;
639 default:
640 do_error:
641 bad_input("No such command (%c)", command);
642 break;
645 finis:
647 close_partition_map(map);
650 void
651 do_update_dpme(partition_map *entry)
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);
666 bzb_init_slice((BZB *)entry->data->dpme_bzb,slice);
667 entry->the_map->changed = 1;
670 void
671 do_create_partition(partition_map_header *map, int get_type)
673 long base;
674 long length;
675 char *name = 0;
676 char *type_name = 0;
678 if (map == NULL) {
679 bad_input("No partition map exists");
680 return;
682 if (!rflag && map->writable == 0) {
683 printf("The map is not writable.\n");
685 // XXX add help feature (i.e. '?' in any argument routine prints help string)
686 if (get_base_argument(&base, map) == 0) {
687 return;
689 if (get_size_argument(&length, map) == 0) {
690 return;
693 if (get_string_argument("Name of partition: ", &name, 1) == 0) {
694 bad_input("Bad name");
695 return;
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);
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;
713 if (istrncmp(type_name, kMapType, DPISTRLEN) == 0) {
714 bad_input("Can't create a partition with the Map type");
715 goto xit2;
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);
722 #endif
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;
736 get_base_argument(long *number, partition_map_header *map)
738 partition_map * entry;
739 int result = 0;
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;
755 return result;
760 get_size_argument(long *number, partition_map_header *map)
762 partition_map * entry;
763 int result = 0;
764 unsigned long multiple;
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;
783 } else {
784 result = 1;
787 return result;
791 void
792 do_rename_partition(partition_map_header *map)
794 partition_map * entry;
795 long ix;
796 char *name;
798 if (map == NULL) {
799 bad_input("No partition map exists");
800 return;
802 if (!rflag && map->writable == 0) {
803 printf("The map is not writable.\n");
805 if (get_number_argument("Partition number: ", &ix, kDefault) == 0) {
806 bad_input("Bad partition number");
807 return;
809 if (get_string_argument("New name of partition: ", &name, 1) == 0) {
810 bad_input("Bad name");
811 return;
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;
823 free(name);
824 return;
827 void
828 do_change_type(partition_map_header *map)
830 partition_map * entry;
831 long ix;
832 char *type = NULL;
834 if (map == NULL) {
835 bad_input("No partition map exists");
836 return;
839 if (!rflag && map->writable == 0) {
840 printf("The map is not writeable.\n");
843 if (get_number_argument("Partition number: ", &ix, kDefault) == 0) {
844 bad_input("Bad partition number");
845 return;
848 entry = find_entry_by_disk_address(ix, map);
850 if (entry == NULL ) {
851 printf("No such partition\n");
852 goto out;
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;
861 strncpy(entry->data->dpme_type, type, DPISTRLEN);
862 do_update_dpme(entry);
863 map->changed = 1;
865 out:
866 if (type)
867 free(type);
868 return;
872 void
873 do_delete_partition(partition_map_header *map)
875 partition_map * cur;
876 long ix;
878 if (map == NULL) {
879 bad_input("No partition map exists");
880 return;
882 if (!rflag && map->writable == 0) {
883 printf("The map is not writable.\n");
885 if (get_number_argument("Partition number: ", &ix, kDefault) == 0) {
886 bad_input("Bad partition number");
887 return;
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);
900 void
901 do_reorder(partition_map_header *map)
903 long old_index;
904 long ix;
906 if (map == NULL) {
907 bad_input("No partition map exists");
908 return;
910 if (!rflag && map->writable == 0) {
911 printf("The map is not writable.\n");
913 if (get_number_argument("Partition number: ", &old_index, kDefault) == 0) {
914 bad_input("Bad partition number");
915 return;
917 if (get_number_argument("New number: ", &ix, kDefault) == 0) {
918 bad_input("Bad partition number");
919 return;
922 move_entry_in_map(old_index, ix, map);
926 void
927 do_write_partition_map(partition_map_header *map)
929 if (map == NULL) {
930 bad_input("No partition map exists");
931 return;
933 if (map->changed == 0 && map->written == 0) {
934 bad_input("The map has not been changed.");
935 return;
937 if (map->writable == 0) {
938 bad_input("The map is not writable.");
939 return;
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);
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;
951 write_partition_map(map);
953 map->changed = 0;
954 map->written = 1;
956 // exit(0);
960 void
961 print_expert_notes()
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");
971 do_expert(partition_map_header *map, char *name)
973 int command;
974 int quit = 0;
976 while (get_command("Expert command (? for help): ", first_get, &command)) {
977 first_get = 0;
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");
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;
1008 quit = 1;
1009 goto finis;
1010 break;
1011 case 'P':
1012 if (dflag) {
1013 show_data_structures(map);
1014 break;
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;
1041 finis:
1042 return quit;
1045 void
1046 do_change_map_size(partition_map_header *map)
1048 long size;
1050 if (map == NULL) {
1051 bad_input("No partition map exists");
1052 return;
1054 if (!rflag && map->writable == 0) {
1055 printf("The map is not writable.\n");
1057 if (get_number_argument("New size: ", &size, kDefault) == 0) {
1058 bad_input("Bad size");
1059 return;
1061 resize_map(size, map);
1065 void
1066 do_display_block(partition_map_header *map, char *alt_name)
1068 MEDIA m;
1069 long number;
1070 char *name;
1071 static unsigned char *display_block;
1072 static int display_g;
1073 int g;
1074 static long next_number = -1;
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;
1086 } else {
1087 name = strdup(alt_name);
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;
1095 g = media_granularity(m);
1096 if (g < PBLOCK_SIZE) {
1097 g = PBLOCK_SIZE;
1100 if (get_number_argument("Block number: ", &number, next_number) == 0) {
1101 bad_input("Bad block number");
1102 goto xit;
1104 if (display_block == NULL || display_g < g) {
1105 if (display_block != NULL) {
1106 free(display_block);
1107 display_g = 0;
1109 display_block = (unsigned char *) malloc(g);
1110 if (display_block == NULL) {
1111 error(errno, "can't allocate memory for display block buffer");
1112 goto xit;
1114 display_g = g;
1116 if (read_media(m, ((long long)number) * g, g, (char *)display_block) != 0) {
1117 printf("block %ld -", number);
1118 dump_block((unsigned char*) display_block, g);
1119 next_number = number + 1;
1122 xit:
1123 if (name) {
1124 close_media(m);
1125 free(name);
1127 return;
1131 void
1132 do_display_entry(partition_map_header *map)
1134 long number;
1136 if (map == NULL) {
1137 bad_input("No partition map exists");
1138 return;
1140 if (get_number_argument("Partition number: ", &number, kDefault) == 0) {
1141 bad_input("Bad partition number");
1142 return;
1144 if (number == 0) {
1145 full_dump_block_zero(map);
1146 } else {
1147 full_dump_partition_entry(map, number);
1152 void
1153 do_examine_patch_partition(partition_map_header *map)
1155 partition_map * entry;
1157 if (map == NULL) {
1158 bad_input("No partition map exists");
1159 return;
1161 entry = find_entry_by_type(kPatchType, map);
1162 if (entry == NULL) {
1163 printf("No patch partition\n");
1164 } else {
1165 display_patches(entry);