1 /* part 1.57 - Partition table editor Author: Kees J. Bot
3 * Needs about 22k heap+stack.
5 * Forked july 2005 into autopart (Ben Gras), a mode which gives the user
10 #include <sys/types.h>
26 #include <sys/ioctl.h>
27 #include <minix/config.h>
28 #include <minix/const.h>
29 #include <minix/partition.h>
30 #include <minix/com.h>
31 #include <machine/partition.h>
35 /* Declare prototype. */
36 void printstep(int step
, char *message
);
38 /* True if a partition is an extended partition. */
39 #define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
41 /* Minix master bootstrap code. */
42 char MASTERBOOT
[] = "/usr/mdec/mbr";
45 ----first---- --geom/last-- ------sectors-----
46 Device Cyl Head Sec Cyl Head Sec Base Size Kb
48 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521
50 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440
51 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142
52 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939
53 3 p3 00 None 0 0 0 0 0 -1 0 0 0
56 #define MAXSIZE 999999999L
57 #define SECTOR_SIZE 512
58 #define DEV_FD0 0x200 /* Device number of /dev/fd0 */
59 #define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */
61 int min_region_mb
= 500;
63 #define MIN_REGION_SECTORS (1024*1024*min_region_mb/SECTOR_SIZE)
65 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
66 #define arraylimit(a) ((a) + arraysize(a))
68 #define SORNOT(n) ((n) == 1 ? "" : "s")
78 #define SURE_SERIOUS 1
83 if(!col
) printf("\033[0m");
84 else printf("\033[3%dm", col
% 10);
87 void type2col(int type
)
92 case MINIX_PART
: col(COL_GREEN
); break;
95 case 0x0B: case 0x0C: case 0x0E: case 0x0F: case 0x42:
96 case 0x07: col(COL_CYAN
); break;
99 case 0x82: case 0x83: col(COL_ORANGE
); break;
103 int open_ct_ok(int fd
)
106 if(ioctl(fd
, DIOCOPENCT
, &c
) < 0) {
107 printf("Warning: couldn't verify opencount, continuing\n");
112 if(c
< 1) { printf("Error: open count %d\n", c
); }
117 void report(const char *label
)
119 fprintf(stderr
, "part: %s: %s\n", label
, strerror(errno
));
122 void fatal(const char *label
)
128 struct termios termios
;
130 void restore_ttyflags(void)
131 /* Reset the tty flags to how we got 'em. */
133 if (tcsetattr(0, TCSANOW
, &termios
) < 0) fatal("");
137 /* Set the terminal to raw mode, no signals, no echoing. */
139 struct termios rawterm
;
142 rawterm
.c_lflag
&= ~(ICANON
|ISIG
|ECHO
);
143 rawterm
.c_iflag
&= ~(ICRNL
);
144 if (tcsetattr(0, TCSANOW
, &rawterm
) < 0) fatal("");
147 #define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
149 char t_cd
[16], t_cm
[32], t_so
[16], t_se
[16], t_md
[16], t_me
[16];
161 while ((c
= *s
++) != 0) putchr(c
);
164 void set_cursor(int row
, int col
)
166 tputs(tgoto(t_cm
, col
, row
), 1, putchr
);
169 int statusrow
= STATUSROW
;
173 void stat_start(int serious
)
174 /* Prepare for printing on a fresh status line, possibly highlighted. */
176 set_cursor(statusrow
++, 0);
177 tputs(t_cd
, 1, putchr
);
178 if (serious
) tputs(t_so
, 1, putchr
);
181 void stat_end(int ktl
)
182 /* Closing bracket for stat_start. Sets "keystrokes to live" of message. */
184 tputs(t_se
, 1, putchr
);
189 void stat_reset(void)
190 /* Reset the statusline pointer and clear old messages if expired. */
192 if (stat_ktl
> 0 && --stat_ktl
== 0) {
193 statusrow
= STATUSROW
;
196 if (need_help
&& statusrow
< (24-2)) {
197 if (statusrow
> STATUSROW
) stat_start(0);
200 "Type '+' or '-' to change, 'r' to read, '?' for more help, '!' for advice");
202 statusrow
= STATUSROW
;
206 void clear_screen(void)
209 tputs(t_cd
, 1, putchr
);
215 /* Reset the tty to cooked mode. */
218 set_cursor(statusrow
, 0);
219 tputs(t_cd
, 1, putchr
);
222 void *alloc(size_t n
)
226 if ((m
= malloc(n
)) == nil
) { reset_tty(); fatal(""); }
231 typedef enum parttype
{ DUNNO
, SUBPART
, PRIMARY
, FLOPPY
} parttype_t
;
233 typedef struct device
{
234 struct device
*next
, *prev
; /* Circular dequeue. */
235 dev_t rdev
; /* Device number (sorting only). */
236 char *name
; /* E.g. /dev/c0d0 */
237 char *subname
; /* E.g. /dev/c0d0:2 */
242 typedef struct region
{
243 /* A region is either an existing top-level partition
244 * entry (used_part is non-NULL) or free space (free_*
247 struct part_entry used_part
;
250 int free_sec_start
, free_sec_last
;
253 /* A disk has between 1 and 2*partitions+1 regions;
254 * the last case is free space before and after every partition.
256 #define NR_REGIONS (2*NR_PARTITIONS+1)
257 region_t regions
[NR_REGIONS
];
258 int nr_partitions
= 0, nr_regions
= 0, free_regions
, used_regions
;
261 device_t
*firstdev
= nil
, *curdev
;
263 #define MAX_DEVICES 100
266 int nr_partitions
, free_regions
, used_regions
, sectors
, nr_regions
;
268 region_t regions
[NR_REGIONS
];
269 } devices
[MAX_DEVICES
];
271 void newdevice(char *name
, int scanning
, int disk_only
)
272 /* Add a device to the device list. If scanning is set then we are reading
273 * /dev, so insert the device in device number order and make /dev/c0d0 current.
276 device_t
*new, *nextdev
, *prevdev
;
281 if (stat(name
, &st
) < 0 || !S_ISBLK(st
.st_mode
)) return;
283 switch (major(st
.st_rdev
)) {
285 /* Disk controller */
286 if (minor(st
.st_rdev
) >= 0x80
287 || minor(st
.st_rdev
) % 5 != 0) return;
292 /* Interesting device found. */
294 if(stat(name
, &st
) < 0) { perror(name
); return; }
297 new= alloc(sizeof(*new));
298 new->rdev
= st
.st_rdev
;
299 new->name
= alloc((strlen(name
) + 1) * sizeof(new->name
[0]));
300 strcpy(new->name
, name
);
301 new->subname
= new->name
;
302 new->parttype
= DUNNO
;
303 if (major(st
.st_rdev
) == major(DEV_FD0
) && minor(st
.st_rdev
) < 112) {
304 new->parttype
= FLOPPY
;
306 if (st
.st_rdev
>= DEV_C0D0
&& minor(st
.st_rdev
) < 128
307 && minor(st
.st_rdev
) % 5 == 0) {
308 new->parttype
= PRIMARY
;
311 if (firstdev
== nil
) {
313 new->next
= new->prev
= new;
318 while (new->rdev
>= nextdev
->rdev
319 && (nextdev
= nextdev
->next
) != firstdev
) {}
320 prevdev
= nextdev
->prev
;
326 if (new->rdev
< firstdev
->rdev
) firstdev
= new;
327 if (new->rdev
== DEV_C0D0
) curdev
= new;
328 if (curdev
->rdev
!= DEV_C0D0
) curdev
= firstdev
;
331 void getdevices(void)
332 /* Get all block devices from /dev that look interesting. */
336 char name
[5 + NAME_MAX
+ 1];
338 if ((d
= opendir("/dev")) == nil
) fatal("/dev");
340 while ((e
= readdir(d
)) != nil
) {
341 strcpy(name
, "/dev/");
342 strcpy(name
+ 5, e
->d_name
);
343 newdevice(name
, 1, 1);
349 unsigned char bootblock
[SECTOR_SIZE
];
350 struct part_entry table
[1 + NR_PARTITIONS
];
351 int existing
[1 + NR_PARTITIONS
];
352 unsigned long offset
= 0, extbase
= 0, extsize
;
354 int sort_index
[1 + NR_PARTITIONS
], sort_order
[1 + NR_PARTITIONS
];
355 unsigned cylinders
= 1, heads
= 1, sectors
= 1, secpcyl
= 1;
356 unsigned alt_cyls
= 1, alt_heads
= 1, alt_secs
= 1;
360 unsigned long sortbase(struct part_entry
*pe
)
362 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
;
366 /* Let the sort_index array show the order partitions are sorted in. */
370 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_order
[i
]= i
;
372 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
373 for (j
= 1; j
<= NR_PARTITIONS
-1; j
++) {
374 int sj
= sort_order
[j
], sj1
= sort_order
[j
+1];
376 if (sortbase(&table
[sj
]) > sortbase(&table
[sj1
])) {
382 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_index
[sort_order
[i
]]= i
;
385 void dos2chs(unsigned char *dos
, unsigned *chs
)
386 /* Extract cylinder, head and sector from the three bytes DOS uses to address
387 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
388 * of the sector byte. The sector number is rebased to count from 0.
391 chs
[0]= ((dos
[1] & 0xC0) << 2) | dos
[2];
393 chs
[2]= (dos
[1] & 0x3F) - 1;
396 void abs2dos(unsigned char *dos
, unsigned long pos
)
397 /* Translate a sector offset to three DOS bytes. */
402 h
= (pos
% secpcyl
) / sectors
;
403 s
= pos
% sectors
+ 1;
406 dos
[1]= s
| ((c
>> 2) & 0xC0);
410 void recompute0(void)
411 /* Recompute the partition size for the device after a geometry change. */
414 cylinders
= heads
= sectors
= 1;
415 memset(table
, 0, sizeof(table
));
417 if (!precise
&& offset
== 0) {
419 table
[0].size
= (unsigned long) cylinders
* heads
* sectors
;
421 table
[0].sysind
= device
< 0 ? NO_PART
: MINIX_PART
;
422 secpcyl
= heads
* sectors
;
425 void guess_geometry(void)
426 /* With a bit of work one can deduce the disk geometry from the partition
427 * table. This may be necessary if the driver gets it wrong. (If partition
428 * tables didn't have C/H/S numbers we would not care at all...)
432 struct part_entry
*pe
;
436 unsigned char HS
[256][8]; /* Bit map off all possible H/S */
438 alt_cyls
= alt_heads
= alt_secs
= 0;
440 /* Initially all possible H/S combinations are possible. HS[h][0]
441 * bit 0 is used to rule out a head value.
443 for (h
= 1; h
<= 255; h
++) {
444 for (s
= 0; s
< 8; s
++) HS
[h
][s
]= 0xFF;
447 for (i
= 0; i
< 2*NR_PARTITIONS
; i
++) {
448 pe
= &(table
+1)[i
>> 1];
449 if (pe
->sysind
== NO_PART
) continue;
451 /* Get the end or start sector numbers (in that order). */
453 dos2chs(&pe
->last_head
, chs
);
454 sec
= pe
->lowsec
+ pe
->size
- 1;
456 dos2chs(&pe
->start_head
, chs
);
460 if (chs
[0] >= alt_cyls
) alt_cyls
= chs
[0]+1;
462 /* Which H/S combinations can be ruled out? */
463 for (h
= 1; h
<= 255; h
++) {
464 if (HS
[h
][0] == 0) continue;
466 for (s
= 1; s
<= 63; s
++) {
467 if ((chs
[0] * h
+ chs
[1]) * s
+ chs
[2] != sec
) {
468 HS
[h
][s
/8] &= ~(1 << (s
%8));
470 if (HS
[h
][s
/8] & (1 << (s
%8))) n
++;
472 if (n
== 0) HS
[h
][0]= 0;
476 /* See if only one remains. */
478 for (h
= 1; h
<= 255; h
++) {
479 if (HS
[h
][0] == 0) continue;
480 for (s
= 1; s
<= 63; s
++) {
481 if (HS
[h
][s
/8] & (1 << (s
%8))) {
489 /* Forget it if more than one choice... */
490 if (i
> 1) alt_cyls
= alt_heads
= alt_secs
= 0;
494 /* Find out the geometry of the device by querying the driver, or by looking
495 * at the partition table. These numbers are crosschecked to make sure that
496 * the geometry is correct. Master bootstraps other than the Minix one use
497 * the CHS numbers in the partition table to load the bootstrap of the active
503 struct part_geom geometry
;
506 /* Geometry already known. */
513 if (device
< 0) return;
515 /* Try to guess the geometry from the partition table. */
518 /* Try to get the geometry from the driver. */
519 (void) fstat(device
, &dst
);
521 if (S_ISBLK(dst
.st_mode
) || S_ISCHR(dst
.st_mode
)) {
522 /* Try to get the drive's geometry from the driver. */
524 if (ioctl(device
, DIOCGETP
, &geometry
) < 0)
527 table
[0].lowsec
= (unsigned long)(geometry
.base
/
529 table
[0].size
= (unsigned long)(geometry
.size
/
531 cylinders
= geometry
.cylinders
;
532 heads
= geometry
.heads
;
533 sectors
= geometry
.sectors
;
541 /* Getting the geometry from the driver failed, so use the
542 * alternate geometry.
544 if (alt_heads
== 0) {
545 alt_cyls
= table
[0].size
/ (64 * 32);
555 printf("Failure to get the geometry of %s: %s", curdev
->name
,
556 errno
== ENOTTY
? "No driver support" : strerror(err
));
559 printf("The geometry has been guessed as %ux%ux%u",
560 cylinders
, heads
, sectors
);
563 if (alt_heads
== 0) {
569 if (heads
!= alt_heads
|| sectors
!= alt_secs
) {
571 "The geometry obtained from the driver\n"
572 "does not match the geometry implied by the partition\n"
573 "table. Please use expert mode instead.\n");
578 /* Show the base and size of the device instead of the whole drive.
579 * This makes sense for subpartitioning primary partitions.
581 if (precise
&& ioctl(device
, DIOCGETP
, &geometry
) >= 0) {
582 table
[0].lowsec
= (unsigned long)(geometry
.base
/ SECTOR_SIZE
);
583 table
[0].size
= (unsigned long)(geometry
.size
/ SECTOR_SIZE
);
591 typedef struct indicators
{ /* Partition type to partition name. */
596 indicators_t ind_table
[]= {
600 { 0x03, "XENIX usr" },
602 { 0x05, "EXTENDED" },
604 { 0x07, "HPFS/NTFS" },
606 { 0x09, "COHERENT" },
611 { 0x0F, "EXTENDED" },
613 { 0x40, "VENIX286" },
614 { 0x42, "W2000 Dyn" },
615 { 0x52, "MICROPORT" },
617 { 0x64, "NOVELL286" },
618 { 0x65, "NOVELL386" },
620 { 0x80, "MINIX-OLD" },
622 { 0x82, "LINUXswap" },
625 { 0x94, "AMOEBAbad" },
628 { 0xB8, "BSDI swap" },
631 { 0xFF, "BADBLOCKS" },
634 char *typ2txt(int ind
)
635 /* Translate a numeric partition indicator for human eyes. */
639 for (pind
= ind_table
; pind
< arraylimit(ind_table
); pind
++) {
640 if (pind
->ind
== ind
) return pind
->name
;
642 return "unknown system";
645 int round_sysind(int ind
, int delta
)
646 /* Find the next known partition type starting with ind in direction delta. */
650 ind
= (ind
+ delta
) & 0xFF;
653 for (pind
= arraylimit(ind_table
)-1; pind
->ind
> ind
; pind
--) {}
655 for (pind
= ind_table
; pind
->ind
< ind
; pind
++) {}
660 /* Objects on the screen, either simple pieces of the text or the cylinder
661 * number of the start of partition three.
663 typedef enum objtype
{
664 O_INFO
, O_TEXT
, O_DEV
, O_SUB
,
665 O_TYPTXT
, O_SORT
, O_NUM
, O_TYPHEX
,
666 O_CYL
, O_HEAD
, O_SEC
,
667 O_SCYL
, O_SHEAD
, O_SSEC
, O_LCYL
, O_LHEAD
, O_LSEC
, O_BASE
, O_SIZE
, O_KB
670 #define rjust(type) ((type) >= O_TYPHEX)
671 #define computed(type) ((type) >= O_TYPTXT)
673 typedef struct object
{
675 objtype_t type
; /* Text field, cylinder number, etc. */
676 char flags
; /* Modifiable? */
680 struct part_entry
*entry
; /* What does the object refer to? */
682 char value
[20]; /* Value when printed. */
685 #define OF_MOD 0x01 /* Object value is modifiable. */
686 #define OF_ODD 0x02 /* It has a somewhat odd value. */
687 #define OF_BAD 0x04 /* Its value is no good at all. */
689 /* Events: (Keypress events are the value of the key pressed.) */
690 #define E_ENTER (-1) /* Cursor moves onto object. */
691 #define E_LEAVE (-2) /* Cursor leaves object. */
692 #define E_WRITE (-3) /* Write, but not by typing 'w'. */
694 /* The O_SIZE objects have a dual identity. */
695 enum howend
{ SIZE
, LAST
} howend
= SIZE
;
697 object_t
*world
= nil
;
698 object_t
*curobj
= nil
;
700 object_t
*newobject(objtype_t type
, int flags
, int row
, int col
, int len
)
701 /* Make a new object given a type, flags, position and length on the screen. */
704 object_t
**aop
= &world
;
706 new= alloc(sizeof(*new));
723 unsigned long entry2base(struct part_entry
*pe
)
724 /* Return the base sector of the partition if defined. */
726 return pe
->sysind
== NO_PART
? 0 : pe
->lowsec
;
729 unsigned long entry2last(struct part_entry
*pe
)
731 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
+ pe
->size
- 1;
734 unsigned long entry2size(struct part_entry
*pe
)
736 return pe
->sysind
== NO_PART
? 0 : pe
->size
;
739 int typing
; /* Set if a digit has been typed to set a value. */
740 int magic
; /* Changes when using the magic key. */
742 void event(int ev
, object_t
*op
);
744 void m_redraw(int ev
, object_t
*op
)
745 /* Redraw the screen. */
749 if (ev
!= ctrl('L')) return;
752 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) op2
->value
[0]= 0;
755 void m_toggle(int ev
, object_t
*op
)
756 /* Toggle between the driver and alternate geometry. */
760 if (ev
!= 'X') return;
761 if (alt_cyls
== cylinders
&& alt_heads
== heads
&& alt_secs
== sectors
)
764 t
= cylinders
; cylinders
= alt_cyls
; alt_cyls
= t
;
765 t
= heads
; heads
= alt_heads
; alt_heads
= t
;
766 t
= sectors
; sectors
= alt_secs
; alt_secs
= t
;
771 char size_last
[]= "Size";
773 void m_orientation(int ev
, object_t
*op
)
775 if (ev
!= ' ') return;
780 strcpy(size_last
, "Last");
784 strcpy(size_last
, "Size");
788 void m_move(int ev
, object_t
*op
)
789 /* Move to the nearest modifiably object in the intended direction. Objects
790 * on the same row or column are really near.
793 object_t
*near
, *op2
;
794 unsigned dist
, d2
, dr
, dc
;
796 if (ev
!= 'h' && ev
!= 'j' && ev
!= 'k' && ev
!= 'l' && ev
!= 'H')
800 /* No device open? Then try to read first. */
802 if (device
< 0) return;
808 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
809 if (op2
== op
|| !(op2
->flags
& OF_MOD
)) continue;
811 dr
= abs(op2
->row
- op
->row
);
812 dc
= abs(op2
->col
- op
->col
);
814 d2
= 25*dr
*dr
+ dc
*dc
;
815 if (op2
->row
!= op
->row
&& op2
->col
!= op
->col
) d2
+= 1000;
819 if (op2
->col
>= op
->col
) d2
= -1;
822 if (op2
->row
<= op
->row
) d2
= -1;
825 if (op2
->row
>= op
->row
) d2
= -1;
827 case 'l': /* Right */
828 if (op2
->col
<= op
->col
) d2
= -1;
831 if (op2
->type
== O_DEV
) d2
= 0;
833 if (d2
< dist
) { near
= op2
; dist
= d2
; }
835 if (near
!= op
) event(E_LEAVE
, op
);
836 event(E_ENTER
, near
);
839 void m_updown(int ev
, object_t
*op
)
840 /* Move a partition table entry up or down. */
843 struct part_entry tmp
;
846 if (ev
!= ctrl('K') && ev
!= ctrl('J')) return;
847 if (op
->entry
== nil
) return;
849 i
= op
->entry
- table
;
850 if (ev
== ctrl('K')) {
854 if (i
>= NR_PARTITIONS
) return;
858 tmp
= table
[i
]; table
[i
]= table
[j
]; table
[j
]= tmp
;
859 tmpx
= existing
[i
]; existing
[i
]= existing
[j
]; existing
[j
]= tmpx
;
862 event(ev
== ctrl('K') ? 'k' : 'j', op
);
865 void m_enter(int ev
, object_t
*op
)
866 /* We've moved onto this object. */
868 if (ev
!= E_ENTER
&& ev
!= ' ' && ev
!= '<' && ev
!= '>' && ev
!= 'X')
875 void m_leave(int ev
, object_t
*op
)
876 /* About to leave this object. */
878 if (ev
!= E_LEAVE
) return;
881 int within(unsigned *var
, unsigned low
, unsigned value
, unsigned high
)
882 /* Only set *var to value if it looks reasonable. */
884 if (low
<= value
&& value
<= high
) {
891 int lwithin(unsigned long *var
, unsigned long low
, unsigned long value
,
894 if (low
<= value
&& value
<= high
) {
901 int nextdevice(object_t
*op
, int delta
)
902 /* Select the next or previous device from the device list. */
906 if (offset
!= 0) return 0;
907 if (dirty
) event(E_WRITE
, op
);
911 (void) close(device
);
919 curdev
= curdev
->prev
;
920 while (delta
< -1 && major(curdev
->rdev
) == major(rdev
)
921 && curdev
->rdev
< rdev
);
924 curdev
= curdev
->next
;
925 while (delta
> 1 && major(curdev
->rdev
) == major(rdev
)
926 && curdev
->rdev
> rdev
);
931 void check_ind(struct part_entry
*pe
)
932 /* If there are no other partitions then make this new one active. */
934 struct part_entry
*pe2
;
937 for (pe2
= table
+ 1; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++, i
++)
938 if (pe2
->sysind
!= NO_PART
&& (pe2
->bootind
& ACTIVE_FLAG
))
941 pe
->bootind
= ACTIVE_FLAG
;
945 int check_existing(struct part_entry
*pe
)
946 /* Check and if not ask if an existing partition may be modified. */
948 static int expert
= 0;
951 if (expert
|| pe
== nil
|| !existing
[pe
- table
]) return 1;
954 putstr("Do you wish to modify existing partitions? (y/n) ");
956 while ((c
= getchar()) != 'y' && c
!= 'n') {}
959 return (expert
= (c
== 'y'));
962 void m_modify(int ev
, object_t
*op
)
963 /* Increment, decrement, set, or toggle the value of an object, using
964 * arithmetic tricks the author doesn't understand either.
968 struct part_entry
*pe
= op
->entry
;
971 unsigned long surplus
;
972 int radix
= op
->type
== O_TYPHEX
? 0x10 : 10;
975 if (device
< 0 && op
->type
!= O_DEV
) return;
979 mul
= radix
; delta
= -1; typing
= 0;
982 mul
= radix
; delta
= 1; typing
= 0;
992 if ('0' <= ev
&& ev
<= '9')
995 if (radix
== 0x10 && 'a' <= ev
&& ev
<= 'f')
996 delta
= ev
- 'a' + 10;
998 if (radix
== 0x10 && 'A' <= ev
&& ev
<= 'F')
999 delta
= ev
- 'A' + 10;
1003 mul
= typing
? radix
*radix
: 0;
1008 if (!check_existing(pe
)) return;
1012 if (ev
!= '-' && ev
!= '+') return;
1013 if (!nextdevice(op
, delta
)) return;
1016 if (!within(&cylinders
, 1,
1017 cylinders
* mul
/ radix
+ delta
, 1024)) return;
1021 if (!within(&heads
, 1, heads
* mul
/ radix
+ delta
, 255))
1026 if (!within(§ors
, 1, sectors
* mul
/ radix
+ delta
, 63))
1031 if (ev
!= '-' && ev
!= '+') return;
1032 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1033 if (op2
->type
== O_NUM
&& ev
== '+')
1034 op2
->entry
->bootind
= 0;
1036 op
->entry
->bootind
= ev
== '+' ? ACTIVE_FLAG
: 0;
1040 pe
->sysind
= pe
->sysind
* mul
/ radix
+ delta
;
1043 if (ev
!= '-' && ev
!= '+') return;
1045 pe
->sysind
= round_sysind(pe
->sysind
, delta
);
1052 if (op
->type
!= O_SCYL
&& ev
!= '-' && ev
!= '+') return;
1054 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1057 if (!lwithin(&t
, 0L,
1058 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1060 if (howend
== LAST
|| op
->type
!= O_BASE
)
1061 pe
->size
-= t
- pe
->lowsec
;
1064 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1071 if (op
->type
!= O_LCYL
&& ev
!= '-' && ev
!= '+') return;
1073 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1074 t
= pe
->lowsec
+ pe
->size
- 1 + level
;
1075 surplus
= t
% level
- mul
/ radix
* level
;
1076 if (!lwithin(&t
, 0L,
1077 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1079 pe
->size
= t
- pe
->lowsec
+ 1;
1081 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1085 if (mul
== 0) pe
->size
= 0; /* new value, no surplus */
1087 if (pe
->sysind
== NO_PART
) {
1088 if (op
->type
== O_KB
|| howend
== SIZE
) {
1089 /* First let loose magic to set the base. */
1096 memset(pe
, 0, sizeof(*pe
));
1098 t
= (op
->type
== O_KB
|| howend
== SIZE
) ? pe
->size
1099 : pe
->lowsec
+ pe
->size
- 1;
1101 if (!lwithin(&t
, 0L,
1102 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1104 pe
->size
= (op
->type
== O_KB
|| howend
== SIZE
) ? t
:
1107 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1113 /* The order among the entries may have changed. */
1118 unsigned long spell
[3 + 4 * (1+NR_PARTITIONS
)];
1122 void newspell(unsigned long charm
)
1123 /* Add a new spell, descending order for the base, ascending for the size. */
1127 if (charm
- table
[0].lowsec
> table
[0].size
) return;
1129 for (i
= 0; i
< nspells
; i
++) {
1130 if (charm
== spell
[i
]) return; /* duplicate */
1132 if (touching
== O_BASE
) {
1133 if (charm
== table
[0].lowsec
+ table
[0].size
) return;
1134 if ((spell
[0] - charm
) < (spell
[0] - spell
[i
])) break;
1136 if (charm
== table
[0].lowsec
) return;
1137 if ((charm
- spell
[0]) < (spell
[i
] - spell
[0])) break;
1140 for (j
= ++nspells
; j
> i
; j
--) spell
[j
]= spell
[j
-1];
1144 void m_magic(int ev
, object_t
*op
)
1145 /* Apply magic onto a base or size number. */
1147 struct part_entry
*pe
= op
->entry
, *pe2
;
1148 int rough
= (offset
!= 0 && extbase
== 0);
1150 if (ev
!= 'm' || device
< 0) return;
1153 if (!check_existing(pe
)) return;
1156 /* See what magic we can let loose on this value. */
1159 /* First spell, the current value. */
1162 case O_SHEAD
: /* Start of partition. */
1166 spell
[0]= pe
->lowsec
;
1170 case O_LSEC
: /* End of partition. */
1174 spell
[0]= pe
->lowsec
+ pe
->size
;
1179 if (pe
->sysind
== NO_PART
) {
1180 memset(pe
, 0, sizeof(*pe
));
1182 pe
->sysind
= MINIX_PART
;
1184 if (touching
== O_SIZE
) {
1185 /* First let loose magic on the base. */
1188 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1189 if (op2
->row
== op
->row
&&
1190 op2
->type
== O_BASE
) {
1199 /* Avoid the first sector on the device. */
1200 if (spell
[0] == table
[0].lowsec
) newspell(spell
[0] + 1);
1202 /* Further interesting values are the the bases of other
1203 * partitions or their ends.
1205 for (pe2
= table
; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++) {
1206 if (pe2
== pe
|| pe2
->sysind
== NO_PART
) continue;
1207 if (pe2
->lowsec
== table
[0].lowsec
)
1208 newspell(table
[0].lowsec
+ 1);
1210 newspell(pe2
->lowsec
);
1211 newspell(pe2
->lowsec
+ pe2
->size
);
1212 if (touching
== O_BASE
&& howend
== SIZE
) {
1213 newspell(pe2
->lowsec
- pe
->size
);
1214 newspell(pe2
->lowsec
+ pe2
->size
- pe
->size
);
1216 if (pe2
->lowsec
% sectors
!= 0) rough
= 1;
1218 /* Present values rounded up to the next cylinder unless
1219 * the table is already a mess. Use "start + 1 track" instead
1220 * of "start + 1 cylinder". Also add the end of the last
1224 unsigned long n
= spell
[0];
1225 if (n
== table
[0].lowsec
) n
++;
1226 n
= (n
+ sectors
- 1) / sectors
* sectors
;
1227 if (n
!= table
[0].lowsec
+ sectors
)
1228 n
= (n
+ secpcyl
- 1) / secpcyl
* secpcyl
;
1230 if (touching
== O_SIZE
)
1231 newspell(table
[0].size
/ secpcyl
* secpcyl
);
1234 /* Magic has been applied, a spell needs to be chosen. */
1236 if (++magic
== nspells
) magic
= 0;
1238 if (touching
== O_BASE
) {
1239 if (howend
== LAST
) pe
->size
-= spell
[magic
] - pe
->lowsec
;
1240 pe
->lowsec
= spell
[magic
];
1242 pe
->size
= spell
[magic
] - pe
->lowsec
;
1244 /* The order among the entries may have changed. */
1249 typedef struct diving
{
1251 struct part_entry old0
;
1253 parttype_t oldparttype
;
1254 unsigned long oldoffset
;
1255 unsigned long oldextbase
;
1258 diving_t
*diving
= nil
;
1260 void m_in(int ev
, object_t
*op
)
1261 /* Go down into a primary or extended partition. */
1264 struct part_entry
*pe
= op
->entry
, ext
;
1267 if (ev
!= '>' || device
< 0 || pe
== nil
|| pe
== &table
[0]
1268 || (!(pe
->sysind
== MINIX_PART
&& offset
== 0)
1269 && !ext_part(pe
->sysind
))
1270 || pe
->size
== 0) return;
1273 if (extbase
!= 0) ext
.size
= extbase
+ extsize
- ext
.lowsec
;
1275 if (dirty
) event(E_WRITE
, op
);
1277 if (device
>= 0) { close(device
); device
= -1; }
1279 newdiv
= alloc(sizeof(*newdiv
));
1280 newdiv
->old0
= table
[0];
1281 newdiv
->oldsubname
= curdev
->subname
;
1282 newdiv
->oldparttype
= curdev
->parttype
;
1283 newdiv
->oldoffset
= offset
;
1284 newdiv
->oldextbase
= extbase
;
1290 n
= strlen(diving
->oldsubname
);
1291 curdev
->subname
= alloc((n
+ 3) * sizeof(curdev
->subname
[0]));
1292 strcpy(curdev
->subname
, diving
->oldsubname
);
1293 curdev
->subname
[n
++]= ':';
1294 curdev
->subname
[n
++]= '0' + (pe
- table
- 1);
1295 curdev
->subname
[n
]= 0;
1297 curdev
->parttype
= curdev
->parttype
== PRIMARY
? SUBPART
: DUNNO
;
1299 if (ext_part(ext
.sysind
) && extbase
== 0) {
1300 extbase
= ext
.lowsec
;
1302 curdev
->parttype
= DUNNO
;
1309 void m_out(int ev
, object_t
*op
)
1310 /* Go up from an extended or subpartition table to its enclosing. */
1314 if (ev
!= '<' || diving
== nil
) return;
1316 if (dirty
) event(E_WRITE
, op
);
1318 if (device
>= 0) { close(device
); device
= -1; }
1323 table
[0]= olddiv
->old0
;
1325 free(curdev
->subname
);
1326 curdev
->subname
= olddiv
->oldsubname
;
1328 curdev
->parttype
= olddiv
->oldparttype
;
1329 offset
= olddiv
->oldoffset
;
1330 extbase
= olddiv
->oldextbase
;
1335 if (diving
== nil
) submerged
= 0; /* We surfaced. */
1338 void installboot(unsigned char *bootblock
, char *masterboot
)
1339 /* Install code from a master bootstrap into a boot block. */
1342 unsigned char buf
[SECTOR_SIZE
];
1346 if ((mfp
= fopen(masterboot
, "r")) == nil
) {
1347 err
= strerror(errno
);
1351 n
= fread(buf
, sizeof(char), SECTOR_SIZE
, mfp
);
1353 err
= strerror(errno
);
1358 err
= "Is probably not a boot sector, too small";
1362 else if (n
< SECTOR_SIZE
&& n
> PART_TABLE_OFF
) {
1363 /* if only code, it cannot override partition table */
1364 err
= "Does not fit in a boot sector";
1368 else if (n
== SECTOR_SIZE
) {
1369 if (buf
[510] != 0x55 || buf
[511] != 0xaa) {
1370 err
= "Is not a boot sector (bad magic)";
1377 if (n
> PART_TABLE_OFF
) {
1378 err
= "Does not fit in a boot sector";
1383 memcpy(bootblock
, buf
, n
);
1386 /* Bootstrap installed. */
1391 printf("%s: %s", masterboot
, err
);
1395 ssize_t
boot_readwrite(int rw
)
1396 /* Read (0) or write (1) the boot sector. */
1400 if (lseek(device
, offset
* SECTOR_SIZE
, SEEK_SET
) < 0)
1404 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1405 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1411 int cylinderalign(region_t
*reg
)
1413 if(reg
->is_used_part
) {
1414 if(reg
->used_part
.lowsec
!= table
[0].lowsec
+ sectors
1415 && (reg
->used_part
.lowsec
% secpcyl
)) {
1417 extra
= secpcyl
- (reg
->used_part
.lowsec
% secpcyl
);
1418 reg
->used_part
.lowsec
+= extra
;
1419 reg
->used_part
.size
-= extra
;
1421 if((reg
->used_part
.size
+1) % secpcyl
) {
1422 reg
->used_part
.size
-= secpcyl
- ((reg
->used_part
.size
+ 1) % secpcyl
);
1424 return reg
->used_part
.size
> 0;
1427 if(reg
->free_sec_start
!= table
[0].lowsec
+ sectors
&& (reg
->free_sec_start
% secpcyl
)) {
1428 /* Start is unaligned. Round up. */
1429 reg
->free_sec_start
+= secpcyl
- (reg
->free_sec_start
% secpcyl
);
1431 if((reg
->free_sec_last
+1) % secpcyl
) {
1432 /* End is unaligned. Round down. */
1433 reg
->free_sec_last
-= (reg
->free_sec_last
+1) % secpcyl
;
1436 /* Return nonzero if anything remains of the region after rounding. */
1437 return reg
->free_sec_last
> reg
->free_sec_start
;
1440 void regionize(void)
1442 int free_sec
, i
, si
;
1446 free_sec
= table
[0].lowsec
+ sectors
;
1448 /* Create region data used in autopart mode. */
1449 free_regions
= used_regions
= nr_regions
= nr_partitions
= 0;
1450 if(table
[0].lowsec
> table
[sort_order
[1]].lowsec
&&
1451 table
[sort_order
[1]].sysind
!= NO_PART
) {
1452 printf("\nSanity check failed on %s - first partition starts before disk.\n"
1453 "Please use expert mode to correct it.\n", curdev
->name
);
1456 for(si
= 1; si
<= NR_PARTITIONS
; si
++) {
1458 if(i
< 1 || i
> NR_PARTITIONS
) {
1459 printf("Sorry, something unexpected has happened (%d out of range).\n", i
);
1463 if(table
[i
].sysind
== NO_PART
)
1466 /* Free space before this partition? */
1467 if(table
[i
].lowsec
> free_sec
) {
1468 /* Free region before this partition. */
1469 regions
[nr_regions
].free_sec_start
= free_sec
;
1470 regions
[nr_regions
].free_sec_last
= table
[i
].lowsec
-1;
1471 regions
[nr_regions
].is_used_part
= 0;
1472 if(cylinderalign(®ions
[nr_regions
])) {
1480 if(table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
||
1481 table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
+ table
[sort_order
[si
-1]].size
) {
1482 printf("\nSanity check failed on %s - partitions overlap.\n"
1483 "Please use expert mode to correct it.\n", curdev
->name
);
1487 if(table
[i
].size
> table
[0].size
) {
1488 printf("\nSanity check failed on %s - partition is larger than disk.\n"
1489 "Please use expert mode to correct it.\n", curdev
->name
);
1492 if(table
[i
].size
< 1) {
1493 printf("\nSanity check failed on %s - zero-sized partition.\n"
1494 "Please use expert mode to correct it.\n", curdev
->name
);
1498 /* Remember used region. */
1499 memcpy(®ions
[nr_regions
].used_part
, &table
[i
], sizeof(table
[i
]));
1500 free_sec
= table
[i
].lowsec
+table
[i
].size
;
1501 regions
[nr_regions
].is_used_part
= 1;
1502 regions
[nr_regions
].tableno
= i
;
1508 /* Special case: space after partitions. */
1509 if(free_sec
< table
[0].lowsec
+ table
[0].size
-1) {
1510 regions
[nr_regions
].free_sec_start
= free_sec
;
1511 regions
[nr_regions
].free_sec_last
= table
[0].lowsec
+ table
[0].size
-1;
1512 regions
[nr_regions
].is_used_part
= 0;
1513 if(cylinderalign(®ions
[nr_regions
])) {
1521 void m_read(int ev
, int *biosdrive
)
1522 /* Read the partition table from the current device. */
1525 struct part_entry
*pe
;
1528 if (ev
!= 'r' || device
>= 0) return;
1530 /* Open() may cause kernel messages: */
1534 device
= open(curdev
->name
, O_RDWR
, 0666);
1539 system_hz
= (u32_t
) sysconf(_SC_CLK_TCK
);
1541 ioctl(device
, DIOCTIMEOUT
, &v
);
1543 memset(bootblock
, 0, sizeof(bootblock
));
1545 n
= boot_readwrite(0);
1547 if (n
<= 0) stat_start(1);
1552 if (n
< SECTOR_SIZE
) {
1557 if (n
<= 0) stat_end(5);
1559 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1561 if(biosdrive
) (*biosdrive
)++;
1563 if(!open_ct_ok(device
)) {
1564 printf("\n%s: device in use! skipping it.", curdev
->subname
);
1571 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1572 NR_PARTITIONS
* sizeof(table
[1]));
1573 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1574 /* Invalid boot block, install bootstrap, wipe partition table.
1576 memset(bootblock
, 0, sizeof(bootblock
));
1577 installboot(bootblock
, MASTERBOOT
);
1578 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1581 /* Fix an extended partition table up to something mere mortals can
1582 * understand. Record already defined partitions.
1584 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1586 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1587 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1588 existing
[i
]= pe
->sysind
!= NO_PART
;
1593 /* Warn about grave dangers ahead. */
1596 printf("Warning: You are in an extended partition.");
1603 void m_write(int ev
, object_t
*op
)
1604 /* Write the partition table back if modified. */
1606 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1608 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1609 if (device
< 0) { dirty
= 0; return; }
1613 printf("%s is not changed, or has already been written",
1621 /* Will this stop him? Probably not... */
1623 printf("You have changed an extended partition. Bad Idea.");
1627 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1628 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1629 if (pe
->sysind
== NO_PART
) {
1630 memset(pe
, 0, sizeof(*pe
));
1632 abs2dos(&pe
->start_head
, pe
->lowsec
);
1633 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1635 /* Fear and loathing time: */
1637 pe
->lowsec
-= ext_part(pe
->sysind
)
1641 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1642 bootblock
[510]= 0x55;
1643 bootblock
[511]= 0xAA;
1645 if (boot_readwrite(1) < 0) {
1647 printf("%s: %s", curdev
->name
, strerror(errno
));
1654 void m_shell(int ev
, object_t
*op
)
1655 /* Shell escape, to do calculations for instance. */
1658 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1660 if (ev
!= 's') return;
1665 switch (pid
= fork()) {
1668 printf("can't fork: %s\n", strerror(errno
));
1672 if (device
>= 0) (void) close(device
);
1673 execl("/bin/sh", "sh", (char *) nil
);
1676 printf("/bin/sh: %s\n", strerror(errno
));
1680 sigint
= signal(SIGINT
, SIG_IGN
);
1681 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1682 sigterm
= signal(SIGTERM
, SIG_IGN
);
1683 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1684 (void) signal(SIGINT
, sigint
);
1685 (void) signal(SIGQUIT
, sigquit
);
1686 (void) signal(SIGTERM
, sigterm
);
1691 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1692 stat_start(0); /* Match the stat_start in the child. */
1694 event(ctrl('L'), op
);
1699 void m_quit(int ev
, object_t
*op
)
1700 /* Write the partition table if modified and exit. */
1702 if (ev
!= 'q' && ev
!= 'x') return;
1706 if (dirty
) event(E_WRITE
, op
);
1707 if (dirty
) quitting
= 0;
1710 void m_help(int ev
, object_t
*op
)
1711 /* For people without a clue; let's hope they can find the '?' key. */
1713 static struct help
{
1717 { "? !", "This help / more advice!" },
1718 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1719 { "0-9 (a-f)", "Enter value" },
1720 { "hjkl (arrow keys)", "Move around" },
1721 { "CTRL-K CTRL-J", "Move entry up/down" },
1722 { "CTRL-L", "Redraw screen" },
1723 { ">", "Start a subpartition table" },
1724 { "<", "Back to the primary partition table" },
1725 { "m", "Cycle through magic values" },
1726 { "spacebar", "Show \"Size\" or \"Last\"" },
1727 { "r w", "Read/write partition table" },
1728 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1729 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1731 static char *advice
[] = {
1732 "* Choose a disk with '+' and '-', then hit 'r'.",
1733 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1734 "* To make a new partition: Move over to the Size or Kb field of an unused",
1735 " partition and type the size. Hit the 'm' key to pad the partition out to",
1736 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1737 " You can hit 'm' more than once on a base or size field to see several",
1738 " interesting values go by. Note: Other Operating Systems can be picky about",
1739 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1740 " head or sector numbers.",
1741 "* To reuse a partition: Change the type to MINIX.",
1742 "* To delete a partition: Type a zero in the hex Type field.",
1743 "* To make a partition active: Type '+' in the Num field.",
1744 "* To study the list of keys: Type '?'.",
1750 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1752 printf("%-25s - %s", hp
->keys
, hp
->what
);
1756 putstr("Things like ");
1757 putstr(t_so
); putstr("this"); putstr(t_se
);
1758 putstr(" must be checked, but ");
1759 putstr(t_md
); putstr("this"); putstr(t_me
);
1760 putstr(" is not really a problem");
1766 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1774 void event(int ev
, object_t
*op
)
1775 /* Simply call all modifiers for an event, each one knows when to act. */
1780 m_orientation(ev
, op
);
1796 prettysizeprint(int kb
)
1799 static char str
[200];
1801 if(MIN_REGION_SECTORS
> kb
*2)
1811 sprintf(str
, "%4d %cB%s", kb
, unit
,
1812 toosmall
? ", too small for MINIX 3" : "");
1817 printregions(region_t
*theregions
, int indent
, int p_nr_partitions
, int p_free_regions
, int p_nr_regions
, int numbers
)
1823 if((p_nr_partitions
>= NR_PARTITIONS
|| !p_free_regions
) && p_free_regions
)
1825 for(r
= 0; r
< p_nr_regions
; r
++, reg
++) {
1826 unsigned long units
;
1827 if(reg
->is_used_part
) {
1829 name
= typ2txt(reg
->used_part
.sysind
);
1830 printf("%*s", indent
, ""); type2col(reg
->used_part
.sysind
);
1831 if(numbers
) printf("[%d] ", r
);
1832 printf("In use by %-10s ", name
);
1833 units
= reg
->used_part
.size
/ 2;
1835 printf(" (%s)\n", prettysizeprint(units
));
1837 printf("%*s", indent
, "");
1839 if(!nofree
) printf("[%d] ", r
);
1840 else printf("[-] ");
1842 printf("Free space ");
1843 units
= ((reg
->free_sec_last
- reg
->free_sec_start
+1))/2;
1844 printf(" (%s)\n", prettysizeprint(units
));
1848 if(numbers
&& p_nr_partitions
>= NR_PARTITIONS
&& p_free_regions
) {
1850 "\nNote: there is free space on this disk, but you can't select it,\n"
1851 "because there isn't a free slot in the partition table to use it.\n"
1852 "You can reclaim the free space by deleting an adjacent region.\n");
1862 is_sure(char *fmt
, ...)
1869 printf(" Please enter 'yes' or 'no': ");
1871 if(!fgets(yesno
, sizeof(yesno
)-1, stdin
)) exit(1);
1873 if (strcmp(yesno
, "yes\n") == 0) return(IS_YES
);
1874 if (strcmp(yesno
, "no\n") == 0) return(IS_NO
);
1878 void warn(char *message
)
1880 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ! %s\n",message
);
1884 may_kill_region(void)
1890 if(used_regions
< 1) return 1;
1892 printf("\n -- Delete in-use region? --\n\n");
1894 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1895 printf("\nEnter the region number to delete or ENTER to continue: ");
1897 fgets(line
, sizeof(line
)-2, stdin
);
1898 if(!isdigit(line
[0]))
1902 if(r
< 0 || r
>= nr_regions
) {
1903 printf("This choice is out of range.\n");
1907 if(!regions
[r
].is_used_part
) {
1908 printf("This region is not in use.\n");
1912 i
= regions
[r
].tableno
;
1914 printf("\nPlease confirm that you want to delete region %d, losing all data it", r
);
1915 printf("\ncontains. You're disk is not actually updated right away, but still.");
1919 confirmation
= is_sure("Are you sure you want to continue?");
1920 if (confirmation
== IS_NO
) return 0;
1921 } while (confirmation
!= IS_YES
);
1923 table
[i
].sysind
= NO_PART
;
1927 /* User may go again. */
1936 static char line
[100];
1939 printstep(2, "Select a disk region");
1941 if(nr_regions
< 1) {
1942 printf("\nNo regions found - maybe the drive is too small.\n"
1943 "Please try expert mode.\n");
1947 if(nr_partitions
>= NR_PARTITIONS
|| !free_regions
) {
1954 printf("\nPlease select the region that you want to use for the MINIX 3 setup.");
1955 printf("\nIf you select an in-use region it will be overwritten by MINIX. The");
1956 printf("\nfollowing region%s were found on the selected disk:\n\n",
1957 SORNOT(nr_regions
));
1958 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1963 printf("Enter the region number to use or type 'delete': ");
1964 if(nr_regions
== 1) printf(" [0] ");
1967 if(!fgets(line
, sizeof(line
)-2, stdin
))
1970 if (nr_regions
== 1 && line
[0] == '\n') {
1975 if(strcmp(line
,"delete\n") == 0) {
1980 if(sscanf(line
, "%d", &rn
) != 1) {
1981 warn("invalid choice");
1985 if(rn
< 0 || rn
>= nr_regions
) {
1986 warn("out of range");
1990 if(nofree
&& !regions
[rn
].is_used_part
) {
1991 warn("not available");
1999 return(®ions
[rn
]);
2002 void printstep(int step
, char *str
)
2005 n
= printf("\n --- Substep 3.%d: %s ---", step
, str
);
2006 while(n
++ < 73) printf("-");
2014 int i
, choice
, drives
;
2015 static char line
[500];
2018 printstep(1, "Select a disk to install MINIX 3");
2019 printf("\nProbing for disks. This may take a short while.");
2024 for(; i
< MAX_DEVICES
;) {
2027 m_read('r', &biosdrive
);
2029 devices
[i
].dev
= curdev
;
2030 devices
[i
].free_regions
= free_regions
;
2031 devices
[i
].nr_regions
= nr_regions
;
2032 devices
[i
].nr_partitions
= nr_partitions
;
2033 devices
[i
].used_regions
= used_regions
;
2034 devices
[i
].sectors
= table
[0].size
;
2035 curdev
->biosdrive
= biosdrive
-1;
2036 memcpy(devices
[i
].regions
, regions
, sizeof(regions
));
2040 nextdevice(NULL
, 1);
2041 if(curdev
== firstdev
)
2048 printf("\nFound no drives - can't partition.\n");
2052 printf(" Probing done.\n");
2053 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives
),
2054 drives
== 1 ? "was" : "were");
2056 for(i
= 0; i
< drives
; i
++) {
2058 printf("Disk [%d]: ", i
);
2059 printf("%s, ", devices
[i
].dev
->name
);
2060 printf("%s\n", prettysizeprint(devices
[i
].sectors
/2));
2061 printregions(devices
[i
].regions
, 8,
2062 devices
[i
].nr_partitions
,
2063 devices
[i
].free_regions
,
2064 devices
[i
].nr_regions
, 0);
2069 printf("Enter the disk number to use: ");
2070 if (drives
== 1) printf("[0] ");
2072 if(!fgets(line
, sizeof(line
)-2, stdin
))
2074 if (line
[0] == '\n' && drives
== 1) {
2078 if(sscanf(line
, "%d", &choice
) != 1) {
2079 warn("choose a disk");
2082 if(choice
< 0 || choice
>= i
) {
2083 warn("out of range");
2089 return devices
[choice
].dev
;
2093 scribble_region(region_t
*reg
, struct part_entry
**pe
, int *made_new
)
2095 int ex
, changed
= 0, i
;
2096 struct part_entry
*newpart
;
2097 if(!reg
->is_used_part
) {
2098 ex
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2099 if(made_new
) *made_new
= 1;
2100 } else if(made_new
) *made_new
= 0;
2101 if(!reg
->is_used_part
) {
2102 for(i
= 1; i
<= NR_PARTITIONS
; i
++)
2103 if(table
[i
].sysind
== NO_PART
)
2105 if(i
> NR_PARTITIONS
) {
2106 /* Bug, should've been caught earlier. */
2107 printf("Couldn't find a free slot. Please try expert mode.\n");
2110 newpart
= &table
[i
];
2111 newpart
->lowsec
= reg
->free_sec_start
;
2112 newpart
->size
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2114 newpart
->sysind
= MINIX_PART
;
2116 newpart
= ®
->used_part
;
2125 sanitycheck_failed(char *dev
, struct part_entry
*pe
)
2127 struct part_geom part
;
2129 unsigned long it_lowsec
, it_secsize
;
2131 if((fd
= open(dev
, O_RDONLY
)) < 0) {
2136 if (ioctl(fd
, DIOCGETP
, &part
) < 0) {
2137 fprintf(stderr
, "DIOCGETP failed\n");
2142 if(!open_ct_ok(fd
)) {
2143 printf("\nAutopart error: the disk is in use. This means that although a\n"
2144 "new table has been written, it won't be in use by the system\n"
2145 "until it's no longer in use (or a reboot is done). Just in case,\n"
2146 "I'm not going to continue. Please un-use the disk (or reboot) and try\n"
2153 it_lowsec
= (unsigned long)(part
.base
/ SECTOR_SIZE
);
2154 it_secsize
= (unsigned long)(part
.size
/ SECTOR_SIZE
);
2156 if(it_lowsec
!= pe
->lowsec
|| it_secsize
!= pe
->size
) {
2157 fprintf(stderr
, "\nReturned and set numbers don't match up!\n");
2158 fprintf(stderr
, "This can happen if the disk is still opened.\n");
2166 do_autopart(int resultfd
)
2170 struct part_entry
*pe
;
2171 struct part_entry orig_table
[1 + NR_PARTITIONS
];
2177 curdev
= select_disk();
2188 memcpy(orig_table
, table
, sizeof(table
));
2192 r
= select_region();
2193 } while(!r
); /* Back to step 2. */
2196 if(scribble_region(r
, &pe
, &newp
)) {
2199 char partbuf
[100], devname
[100];
2200 struct part_entry
*tpe
= NULL
;
2202 printstep(3, "Confirm your choices");
2204 region
= (int)(r
-regions
);
2205 /* disk = (int) (curdev-devices); */
2207 printf("\nThis is the point of no return. You have selected to install MINIX 3\n");
2208 printf("into region %d of disk %s. Please confirm that you want\n",
2209 region
, curdev
->name
);
2210 printf("to use this selection to install MINIX 3.\n\n");
2213 confirmation
= is_sure("Are you sure you want to continue?");
2214 if (confirmation
== IS_NO
) return 1;
2215 } while (confirmation
!= IS_YES
);
2217 /* Retrieve partition number in sorted order that we
2218 * have scribbled in.
2221 for(i
= 1; i
<= NR_PARTITIONS
; i
++) {
2224 if(si
< 1 || si
> NR_PARTITIONS
) {
2225 fprintf(stderr
, "Autopart internal error (out of range) (nothing written).\n");
2228 if(table
[si
].lowsec
== pe
->lowsec
) {
2230 fprintf(stderr
, "Autopart internal error (part found twice) (nothing written).\n");
2233 check_ind(&table
[si
]);
2234 table
[si
].sysind
= MINIX_PART
;
2240 fprintf(stderr
, "Autopart internal error (part not found) (nothing written).\n");
2245 fprintf(stderr
, "Autopart internal error (couldn't update disk).\n");
2248 name
=strrchr(curdev
->name
, '/');
2249 if(!name
) name
= curdev
->name
;
2252 sprintf(partbuf
, "%sp%d d%dp%d\n", name
, found
-1,
2253 curdev
->biosdrive
, found
-1);
2254 sprintf(devname
, "/dev/%sp%d", name
, found
-1);
2255 if(resultfd
>= 0 && write(resultfd
, partbuf
, strlen(partbuf
)) < strlen(partbuf
)) {
2256 fprintf(stderr
, "Autopart internal error (couldn't write result).\n");
2270 if(sanitycheck_failed(devname
, tpe
)) {
2271 fprintf(stderr
, "Autopart internal error (disk sanity check failed).\n");
2277 if((fd
=open(devname
, O_WRONLY
)) < 0) {
2280 /* Clear any subpartitioning. */
2281 static unsigned char sub
[2048];
2284 write(fd
, sub
, sizeof(sub
));
2294 int main(int argc
, char **argv
)
2300 /* autopart uses getopt() */
2301 while((c
= getopt(argc
, argv
, "m:f:")) != EOF
) {
2304 min_region_mb
= atoi(optarg
);
2307 /* Make sure old data file is gone. */
2309 if((resultfd
=open(optarg
, O_CREAT
| O_WRONLY
| O_TRUNC
)) < 0) {
2313 sync(); /* Make sure no old data file lingers. */
2316 fprintf(stderr
, "Unknown option\n");
2324 for (i
= 0; i
< argc
; i
++) {
2325 newdevice(argv
[i
], 0, 0);
2328 if (firstdev
== nil
) {
2337 if (firstdev
== nil
) {
2338 fprintf(stderr
, "autopart couldn't find any devices.\n");
2341 r
= do_autopart(resultfd
);
2342 if(resultfd
>= 0) { close(resultfd
); }