2 // pdisk - an editor for Apple format partition tables
4 // Written by Eryk Vershen
6 // Still under development (as of 15 January 1998)
10 * Copyright 1996,1997,1998 by Apple Computer, Inc.
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.
33 #if defined(__linux__) || defined(__NetBSD__)
39 // for malloc() & free()
41 #if !defined(__unix__)
51 // for strncpy() & strlen()
59 #include <sys/ioctl.h>
61 #include <linux/hdreg.h>
66 #include "partition_map.h"
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
102 kLogicalOption
= 1002
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
);
142 void print_edit_notes(void);
143 void print_expert_notes(void);
144 void print_top_notes(void);
151 main(int argc
, char **argv
)
153 #if defined(__linux__) || defined(__unix__)
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 ... */
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
);
186 printf("version " VERSION
" (" RELEASE_DATE
")\n");
190 } else if (interactive
) {
195 } else if (name_index
< argc
) {
196 while (name_index
< argc
) {
197 dump(argv
[name_index
++]);
203 usage("no device argument");
207 } else if (name_index
< argc
) {
208 while (name_index
< argc
) {
209 edit(argv
[name_index
++], 0);
212 usage("no device argument");
221 SIOUXSettings
.autocloseonquit
= 1;
222 //printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\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");
246 int ask_logical_size
;
248 while (get_command("Top level command (? for help): ", first_get
, &command
)) {
250 ask_logical_size
= 0;
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");
263 printf(" L list all devices' maps\n");
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");
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");
284 printf("version " VERSION
" (" RELEASE_DATE
")\n");
292 if (get_string_argument("Name of device: ", &name
, 1) == 0) {
293 bad_input("Bad name");
300 ask_logical_size
= 1;
302 if (get_string_argument("Name of device: ", &name
, 1) == 0) {
303 bad_input("Bad name");
306 edit(name
, ask_logical_size
);
316 printf("Now in %s mode.\n", (rflag
)?"readonly":"read/write");
325 printf("Now in show %s name mode.\n", (fflag
)?"filesystem":"partition");
335 printf("Now in %s mode.\n", (aflag
)?"abbreviate":"full type");
348 printf("Now in %s mode.\n", (pflag
)?"physical":"logical");
360 printf("Now in %s mode.\n", (dflag
)?"debug":"normal");
370 printf("Now in %s device size mode.\n", (cflag
)?"always compute":"use existing");
378 do_display_block(0, 0);
385 bad_input("No such command (%c)", command
);
392 #if defined(__linux__) || defined(__unix__)
394 get_options(int argc
, char **argv
)
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'},
413 int option_index
= 0;
415 extern int opterr
; /* who does error messages */
416 extern int optopt
; /* char that caused the error */
417 int getopt_error
; /* getopt choked */
419 extern int optind
; /* next argv index */
420 extern char *optarg
; /* pointer to argument */
423 lflag
= LFLAG_DEFAULT
;
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)
440 opterr
= 0; /* tell getopt to be quiet */
441 while ((c
= getopt(argc
, argv
, "hlvdraLicf")) != EOF
)
444 #if !(defined(__linux__) || defined(__NetBSD__))
454 // option_index would be used here
457 hflag
= (HFLAG_DEFAULT
)?0:1;
460 if (optarg
!= NULL
) {
465 lflag
= (LFLAG_DEFAULT
)?0:1;
468 vflag
= (VFLAG_DEFAULT
)?0:1;
471 dflag
= (DFLAG_DEFAULT
)?0:1;
474 cflag
= (CFLAG_DEFAULT
)?0:1;
477 rflag
= (RFLAG_DEFAULT
)?0:1;
480 fflag
= (FFLAG_DEFAULT
)?0:1;
483 interactive
= (INTERACT_DEFAULT
)?0:1;
486 aflag
= (AFLAG_DEFAULT
)?0:1;
490 pflag
= (PFLAG_DEFAULT
)?0:1;
499 usage("bad arguments");
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");
524 edit(char *name
, int ask_logical_size
)
526 partition_map_header
*map
;
532 map
= open_partition_map(name
, &valid_file
, ask_logical_size
);
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
);
545 while (get_command("Command (? for help): ", first_get
, &command
)) {
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");
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");
570 printf(" w write the partition table\n");
573 printf(" x extra extensions for experts\n");
580 dump_partition_map(map
, order
);
584 if (map
&& map
->changed
) {
585 if (get_okay("Discard changes? [n/y]: ", 0) != 1) {
594 map
= init_partition_map(name
, map
);
600 do_create_partition(map
, get_type
);
604 do_rename_partition(map
);
608 do_delete_partition(map
);
616 do_change_map_size(map
);
626 } else if (do_expert(map
, name
)) {
634 do_write_partition_map(map
);
641 bad_input("No such command (%c)", command
);
647 close_partition_map(map
);
651 do_update_dpme(partition_map
*entry
)
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;
671 do_create_partition(partition_map_header
*map
, int get_type
)
679 bad_input("No partition map exists");
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) {
689 if (get_size_argument(&length
, map
) == 0) {
693 if (get_string_argument("Name of partition: ", &name
, 1) == 0) {
694 bad_input("Bad name");
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
);
705 } else if (get_string_argument("Type of partition: ", &type_name
, 1) == 0) {
706 bad_input("Bad type");
709 if (istrncmp(type_name
, kFreeType
, DPISTRLEN
) == 0) {
710 bad_input("Can't create a partition with the Free type");
713 if (istrncmp(type_name
, kMapType
, DPISTRLEN
) == 0) {
714 bad_input("Can't create a partition with the Map type");
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
);
724 do_update_dpme(find_entry_by_base(base
,map
));
736 get_base_argument(long *number
, partition_map_header
*map
)
738 partition_map
* entry
;
741 if (get_number_argument("First block: ", number
, kDefault
) == 0) {
742 bad_input("Bad block number");
745 if (get_partition_modifier()) {
746 entry
= find_entry_by_disk_address(*number
, map
);
748 bad_input("Bad partition number");
751 *number
= entry
->data
->dpme_pblock_start
;
760 get_size_argument(long *number
, partition_map_header
*map
)
762 partition_map
* entry
;
764 unsigned long multiple
;
766 if (get_number_argument("Length in blocks: ", number
, kDefault
) == 0) {
767 bad_input("Bad length");
769 multiple
= get_multiplier(map
->logical_block
);
771 bad_input("Bad multiplier");
772 } else if (multiple
!= 1) {
775 } else if (get_partition_modifier()) {
776 entry
= find_entry_by_disk_address(*number
, map
);
778 bad_input("Bad partition number");
780 *number
= entry
->data
->dpme_pblocks
;
792 do_rename_partition(partition_map_header
*map
)
794 partition_map
* entry
;
799 bad_input("No partition map exists");
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");
809 if (get_string_argument("New name of partition: ", &name
, 1) == 0) {
810 bad_input("Bad name");
814 // find partition and change it
815 entry
= find_entry_by_disk_address(ix
, map
);
817 printf("No such partition\n");
819 // stuff name into partition map entry data
820 strncpy(entry
->data
->dpme_name
, name
, DPISTRLEN
);
828 do_change_type(partition_map_header
*map
)
830 partition_map
* entry
;
835 bad_input("No partition map exists");
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");
848 entry
= find_entry_by_disk_address(ix
, map
);
850 if (entry
== NULL
) {
851 printf("No such partition\n");
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");
861 strncpy(entry
->data
->dpme_type
, type
, DPISTRLEN
);
862 do_update_dpme(entry
);
873 do_delete_partition(partition_map_header
*map
)
879 bad_input("No partition map exists");
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");
890 // find partition and delete it
891 cur
= find_entry_by_disk_address(ix
, map
);
893 printf("No such partition\n");
895 delete_partition_from_map(cur
);
901 do_reorder(partition_map_header
*map
)
907 bad_input("No partition map exists");
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");
917 if (get_number_argument("New number: ", &ix
, kDefault
) == 0) {
918 bad_input("Bad partition number");
922 move_entry_in_map(old_index
, ix
, map
);
927 do_write_partition_map(partition_map_header
*map
)
930 bad_input("No partition map exists");
933 if (map
->changed
== 0 && map
->written
== 0) {
934 bad_input("The map has not been changed.");
937 if (map
->writable
== 0) {
938 bad_input("The map is not writable.");
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
);
946 printf("Writing the map destroys what was there before. ");
947 if (get_okay("Is that okay? [n/y]: ", 0) != 1) {
951 write_partition_map(map
);
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");
971 do_expert(partition_map_header
*map
, char *name
)
976 while (get_command("Expert command (? for help): ", first_get
, &command
)) {
981 print_expert_notes();
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");
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");
1004 if (get_okay("Discard changes? [n/y]: ", 0) != 1) {
1013 show_data_structures(map
);
1018 dump_partition_map(map
, 1);
1022 do_display_block(map
, name
);
1026 do_display_entry(map
);
1034 do_examine_patch_partition(map
);
1037 bad_input("No such command (%c)", command
);
1046 do_change_map_size(partition_map_header
*map
)
1051 bad_input("No partition map exists");
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");
1061 resize_map(size
, map
);
1066 do_display_block(partition_map_header
*map
, char *alt_name
)
1071 static unsigned char *display_block
;
1072 static int display_g
;
1074 static long next_number
= -1;
1079 g
= map
->logical_block
;
1081 if (alt_name
== 0) {
1082 if (get_string_argument("Name of device: ", &name
, 1) == 0) {
1083 bad_input("Bad name");
1087 name
= strdup(alt_name
);
1089 m
= open_pathname_as_media(name
, O_RDONLY
);
1091 error(errno
, "can't open file '%s'", name
);
1095 g
= media_granularity(m
);
1096 if (g
< PBLOCK_SIZE
) {
1100 if (get_number_argument("Block number: ", &number
, next_number
) == 0) {
1101 bad_input("Bad block number");
1104 if (display_block
== NULL
|| display_g
< g
) {
1105 if (display_block
!= NULL
) {
1106 free(display_block
);
1109 display_block
= (unsigned char *) malloc(g
);
1110 if (display_block
== NULL
) {
1111 error(errno
, "can't allocate memory for display block buffer");
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;
1132 do_display_entry(partition_map_header
*map
)
1137 bad_input("No partition map exists");
1140 if (get_number_argument("Partition number: ", &number
, kDefault
) == 0) {
1141 bad_input("Bad partition number");
1145 full_dump_block_zero(map
);
1147 full_dump_partition_entry(map
, number
);
1153 do_examine_patch_partition(partition_map_header
*map
)
1155 partition_map
* entry
;
1158 bad_input("No partition map exists");
1161 entry
= find_entry_by_type(kPatchType
, map
);
1162 if (entry
== NULL
) {
1163 printf("No patch partition\n");
1165 display_patches(entry
);