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/u64.h>
31 #include <minix/com.h>
32 #include <machine/partition.h>
36 /* Declare prototype. */
37 void printstep(int step
, char *message
);
39 /* True if a partition is an extended partition. */
40 #define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
42 /* Minix master bootstrap code. */
43 char MASTERBOOT
[] = "/usr/mdec/mbr";
46 ----first---- --geom/last-- ------sectors-----
47 Device Cyl Head Sec Cyl Head Sec Base Size Kb
49 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521
51 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440
52 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142
53 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939
54 3 p3 00 None 0 0 0 0 0 -1 0 0 0
57 #define MAXSIZE 999999999L
58 #define SECTOR_SIZE 512
59 #define DEV_FD0 0x200 /* Device number of /dev/fd0 */
60 #define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */
62 int min_region_mb
= 500;
64 #define MIN_REGION_SECTORS (1024*1024*min_region_mb/SECTOR_SIZE)
66 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
67 #define arraylimit(a) ((a) + arraysize(a))
69 #define SORNOT(n) ((n) == 1 ? "" : "s")
79 #define SURE_SERIOUS 1
84 if(!col
) printf("\033[0m");
85 else printf("\033[3%dm", col
% 10);
88 void type2col(int type
)
93 case MINIX_PART
: col(COL_GREEN
); break;
96 case 0x0B: case 0x0C: case 0x0E: case 0x0F: case 0x42:
97 case 0x07: col(COL_CYAN
); break;
100 case 0x82: case 0x83: col(COL_ORANGE
); break;
104 int open_ct_ok(int fd
)
107 if(ioctl(fd
, DIOCOPENCT
, &c
) < 0) {
108 printf("Warning: couldn't verify opencount, continuing\n");
113 if(c
< 1) { printf("Error: open count %d\n", c
); }
118 void report(const char *label
)
120 fprintf(stderr
, "part: %s: %s\n", label
, strerror(errno
));
123 void fatal(const char *label
)
129 struct termios termios
;
131 void restore_ttyflags(void)
132 /* Reset the tty flags to how we got 'em. */
134 if (tcsetattr(0, TCSANOW
, &termios
) < 0) fatal("");
138 /* Set the terminal to raw mode, no signals, no echoing. */
140 struct termios rawterm
;
143 rawterm
.c_lflag
&= ~(ICANON
|ISIG
|ECHO
);
144 rawterm
.c_iflag
&= ~(ICRNL
);
145 if (tcsetattr(0, TCSANOW
, &rawterm
) < 0) fatal("");
148 #define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
150 char t_cd
[16], t_cm
[32], t_so
[16], t_se
[16], t_md
[16], t_me
[16];
162 while ((c
= *s
++) != 0) putchr(c
);
165 void set_cursor(int row
, int col
)
167 tputs(tgoto(t_cm
, col
, row
), 1, putchr
);
170 int statusrow
= STATUSROW
;
174 void stat_start(int serious
)
175 /* Prepare for printing on a fresh status line, possibly highlighted. */
177 set_cursor(statusrow
++, 0);
178 tputs(t_cd
, 1, putchr
);
179 if (serious
) tputs(t_so
, 1, putchr
);
182 void stat_end(int ktl
)
183 /* Closing bracket for stat_start. Sets "keystrokes to live" of message. */
185 tputs(t_se
, 1, putchr
);
190 void stat_reset(void)
191 /* Reset the statusline pointer and clear old messages if expired. */
193 if (stat_ktl
> 0 && --stat_ktl
== 0) {
194 statusrow
= STATUSROW
;
197 if (need_help
&& statusrow
< (24-2)) {
198 if (statusrow
> STATUSROW
) stat_start(0);
201 "Type '+' or '-' to change, 'r' to read, '?' for more help, '!' for advice");
203 statusrow
= STATUSROW
;
207 void clear_screen(void)
210 tputs(t_cd
, 1, putchr
);
216 /* Reset the tty to cooked mode. */
219 set_cursor(statusrow
, 0);
220 tputs(t_cd
, 1, putchr
);
223 void *alloc(size_t n
)
227 if ((m
= malloc(n
)) == nil
) { reset_tty(); fatal(""); }
232 typedef enum parttype
{ DUNNO
, SUBPART
, PRIMARY
, FLOPPY
} parttype_t
;
234 typedef struct device
{
235 struct device
*next
, *prev
; /* Circular dequeue. */
236 dev_t rdev
; /* Device number (sorting only). */
237 char *name
; /* E.g. /dev/c0d0 */
238 char *subname
; /* E.g. /dev/c0d0:2 */
243 typedef struct region
{
244 /* A region is either an existing top-level partition
245 * entry (used_part is non-NULL) or free space (free_*
248 struct part_entry used_part
;
251 int free_sec_start
, free_sec_last
;
254 /* A disk has between 1 and 2*partitions+1 regions;
255 * the last case is free space before and after every partition.
257 #define NR_REGIONS (2*NR_PARTITIONS+1)
258 region_t regions
[NR_REGIONS
];
259 int nr_partitions
= 0, nr_regions
= 0, free_regions
, used_regions
;
262 device_t
*firstdev
= nil
, *curdev
;
264 #define MAX_DEVICES 100
267 int nr_partitions
, free_regions
, used_regions
, sectors
, nr_regions
;
269 region_t regions
[NR_REGIONS
];
270 } devices
[MAX_DEVICES
];
272 void newdevice(char *name
, int scanning
, int disk_only
)
273 /* Add a device to the device list. If scanning is set then we are reading
274 * /dev, so insert the device in device number order and make /dev/c0d0 current.
277 device_t
*new, *nextdev
, *prevdev
;
282 if (stat(name
, &st
) < 0 || !S_ISBLK(st
.st_mode
)) return;
284 switch (major(st
.st_rdev
)) {
286 /* Disk controller */
287 if (minor(st
.st_rdev
) >= 0x80
288 || minor(st
.st_rdev
) % 5 != 0) return;
293 /* Interesting device found. */
295 if(stat(name
, &st
) < 0) { perror(name
); return; }
298 new= alloc(sizeof(*new));
299 new->rdev
= st
.st_rdev
;
300 new->name
= alloc((strlen(name
) + 1) * sizeof(new->name
[0]));
301 strcpy(new->name
, name
);
302 new->subname
= new->name
;
303 new->parttype
= DUNNO
;
304 if (major(st
.st_rdev
) == major(DEV_FD0
) && minor(st
.st_rdev
) < 112) {
305 new->parttype
= FLOPPY
;
307 if (st
.st_rdev
>= DEV_C0D0
&& minor(st
.st_rdev
) < 128
308 && minor(st
.st_rdev
) % 5 == 0) {
309 new->parttype
= PRIMARY
;
312 if (firstdev
== nil
) {
314 new->next
= new->prev
= new;
319 while (new->rdev
>= nextdev
->rdev
320 && (nextdev
= nextdev
->next
) != firstdev
) {}
321 prevdev
= nextdev
->prev
;
327 if (new->rdev
< firstdev
->rdev
) firstdev
= new;
328 if (new->rdev
== DEV_C0D0
) curdev
= new;
329 if (curdev
->rdev
!= DEV_C0D0
) curdev
= firstdev
;
332 void getdevices(void)
333 /* Get all block devices from /dev that look interesting. */
337 char name
[5 + NAME_MAX
+ 1];
339 if ((d
= opendir("/dev")) == nil
) fatal("/dev");
341 while ((e
= readdir(d
)) != nil
) {
342 strcpy(name
, "/dev/");
343 strcpy(name
+ 5, e
->d_name
);
344 newdevice(name
, 1, 1);
350 unsigned char bootblock
[SECTOR_SIZE
];
351 struct part_entry table
[1 + NR_PARTITIONS
];
352 int existing
[1 + NR_PARTITIONS
];
353 unsigned long offset
= 0, extbase
= 0, extsize
;
355 int sort_index
[1 + NR_PARTITIONS
], sort_order
[1 + NR_PARTITIONS
];
356 unsigned cylinders
= 1, heads
= 1, sectors
= 1, secpcyl
= 1;
357 unsigned alt_cyls
= 1, alt_heads
= 1, alt_secs
= 1;
361 unsigned long sortbase(struct part_entry
*pe
)
363 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
;
367 /* Let the sort_index array show the order partitions are sorted in. */
371 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_order
[i
]= i
;
373 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
374 for (j
= 1; j
<= NR_PARTITIONS
-1; j
++) {
375 int sj
= sort_order
[j
], sj1
= sort_order
[j
+1];
377 if (sortbase(&table
[sj
]) > sortbase(&table
[sj1
])) {
383 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_index
[sort_order
[i
]]= i
;
386 void dos2chs(unsigned char *dos
, unsigned *chs
)
387 /* Extract cylinder, head and sector from the three bytes DOS uses to address
388 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
389 * of the sector byte. The sector number is rebased to count from 0.
392 chs
[0]= ((dos
[1] & 0xC0) << 2) | dos
[2];
394 chs
[2]= (dos
[1] & 0x3F) - 1;
397 void abs2dos(unsigned char *dos
, unsigned long pos
)
398 /* Translate a sector offset to three DOS bytes. */
403 h
= (pos
% secpcyl
) / sectors
;
404 s
= pos
% sectors
+ 1;
407 dos
[1]= s
| ((c
>> 2) & 0xC0);
411 void recompute0(void)
412 /* Recompute the partition size for the device after a geometry change. */
415 cylinders
= heads
= sectors
= 1;
416 memset(table
, 0, sizeof(table
));
418 if (!precise
&& offset
== 0) {
420 table
[0].size
= (unsigned long) cylinders
* heads
* sectors
;
422 table
[0].sysind
= device
< 0 ? NO_PART
: MINIX_PART
;
423 secpcyl
= heads
* sectors
;
426 void guess_geometry(void)
427 /* With a bit of work one can deduce the disk geometry from the partition
428 * table. This may be necessary if the driver gets it wrong. (If partition
429 * tables didn't have C/H/S numbers we would not care at all...)
433 struct part_entry
*pe
;
437 unsigned char HS
[256][8]; /* Bit map off all possible H/S */
439 alt_cyls
= alt_heads
= alt_secs
= 0;
441 /* Initially all possible H/S combinations are possible. HS[h][0]
442 * bit 0 is used to rule out a head value.
444 for (h
= 1; h
<= 255; h
++) {
445 for (s
= 0; s
< 8; s
++) HS
[h
][s
]= 0xFF;
448 for (i
= 0; i
< 2*NR_PARTITIONS
; i
++) {
449 pe
= &(table
+1)[i
>> 1];
450 if (pe
->sysind
== NO_PART
) continue;
452 /* Get the end or start sector numbers (in that order). */
454 dos2chs(&pe
->last_head
, chs
);
455 sec
= pe
->lowsec
+ pe
->size
- 1;
457 dos2chs(&pe
->start_head
, chs
);
461 if (chs
[0] >= alt_cyls
) alt_cyls
= chs
[0]+1;
463 /* Which H/S combinations can be ruled out? */
464 for (h
= 1; h
<= 255; h
++) {
465 if (HS
[h
][0] == 0) continue;
467 for (s
= 1; s
<= 63; s
++) {
468 if ((chs
[0] * h
+ chs
[1]) * s
+ chs
[2] != sec
) {
469 HS
[h
][s
/8] &= ~(1 << (s
%8));
471 if (HS
[h
][s
/8] & (1 << (s
%8))) n
++;
473 if (n
== 0) HS
[h
][0]= 0;
477 /* See if only one remains. */
479 for (h
= 1; h
<= 255; h
++) {
480 if (HS
[h
][0] == 0) continue;
481 for (s
= 1; s
<= 63; s
++) {
482 if (HS
[h
][s
/8] & (1 << (s
%8))) {
490 /* Forget it if more than one choice... */
491 if (i
> 1) alt_cyls
= alt_heads
= alt_secs
= 0;
495 /* Find out the geometry of the device by querying the driver, or by looking
496 * at the partition table. These numbers are crosschecked to make sure that
497 * the geometry is correct. Master bootstraps other than the Minix one use
498 * the CHS numbers in the partition table to load the bootstrap of the active
504 struct partition geometry
;
507 /* Geometry already known. */
514 if (device
< 0) return;
516 /* Try to guess the geometry from the partition table. */
519 /* Try to get the geometry from the driver. */
520 (void) fstat(device
, &dst
);
522 if (S_ISBLK(dst
.st_mode
) || S_ISCHR(dst
.st_mode
)) {
523 /* Try to get the drive's geometry from the driver. */
525 if (ioctl(device
, DIOCGETP
, &geometry
) < 0)
528 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
529 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
530 cylinders
= geometry
.cylinders
;
531 heads
= geometry
.heads
;
532 sectors
= geometry
.sectors
;
540 /* Getting the geometry from the driver failed, so use the
541 * alternate geometry.
543 if (alt_heads
== 0) {
544 alt_cyls
= table
[0].size
/ (64 * 32);
554 printf("Failure to get the geometry of %s: %s", curdev
->name
,
555 errno
== ENOTTY
? "No driver support" : strerror(err
));
558 printf("The geometry has been guessed as %ux%ux%u",
559 cylinders
, heads
, sectors
);
562 if (alt_heads
== 0) {
568 if (heads
!= alt_heads
|| sectors
!= alt_secs
) {
570 "The geometry obtained from the driver\n"
571 "does not match the geometry implied by the partition\n"
572 "table. Please use expert mode instead.\n");
577 /* Show the base and size of the device instead of the whole drive.
578 * This makes sense for subpartitioning primary partitions.
580 if (precise
&& ioctl(device
, DIOCGETP
, &geometry
) >= 0) {
581 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
582 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
590 typedef struct indicators
{ /* Partition type to partition name. */
595 indicators_t ind_table
[]= {
599 { 0x03, "XENIX usr" },
601 { 0x05, "EXTENDED" },
603 { 0x07, "HPFS/NTFS" },
605 { 0x09, "COHERENT" },
610 { 0x0F, "EXTENDED" },
612 { 0x40, "VENIX286" },
613 { 0x42, "W2000 Dyn" },
614 { 0x52, "MICROPORT" },
616 { 0x64, "NOVELL286" },
617 { 0x65, "NOVELL386" },
619 { 0x80, "MINIX-OLD" },
621 { 0x82, "LINUXswap" },
624 { 0x94, "AMOEBAbad" },
627 { 0xB8, "BSDI swap" },
630 { 0xFF, "BADBLOCKS" },
633 char *typ2txt(int ind
)
634 /* Translate a numeric partition indicator for human eyes. */
638 for (pind
= ind_table
; pind
< arraylimit(ind_table
); pind
++) {
639 if (pind
->ind
== ind
) return pind
->name
;
641 return "unknown system";
644 int round_sysind(int ind
, int delta
)
645 /* Find the next known partition type starting with ind in direction delta. */
649 ind
= (ind
+ delta
) & 0xFF;
652 for (pind
= arraylimit(ind_table
)-1; pind
->ind
> ind
; pind
--) {}
654 for (pind
= ind_table
; pind
->ind
< ind
; pind
++) {}
659 /* Objects on the screen, either simple pieces of the text or the cylinder
660 * number of the start of partition three.
662 typedef enum objtype
{
663 O_INFO
, O_TEXT
, O_DEV
, O_SUB
,
664 O_TYPTXT
, O_SORT
, O_NUM
, O_TYPHEX
,
665 O_CYL
, O_HEAD
, O_SEC
,
666 O_SCYL
, O_SHEAD
, O_SSEC
, O_LCYL
, O_LHEAD
, O_LSEC
, O_BASE
, O_SIZE
, O_KB
669 #define rjust(type) ((type) >= O_TYPHEX)
670 #define computed(type) ((type) >= O_TYPTXT)
672 typedef struct object
{
674 objtype_t type
; /* Text field, cylinder number, etc. */
675 char flags
; /* Modifiable? */
679 struct part_entry
*entry
; /* What does the object refer to? */
681 char value
[20]; /* Value when printed. */
684 #define OF_MOD 0x01 /* Object value is modifiable. */
685 #define OF_ODD 0x02 /* It has a somewhat odd value. */
686 #define OF_BAD 0x04 /* Its value is no good at all. */
688 /* Events: (Keypress events are the value of the key pressed.) */
689 #define E_ENTER (-1) /* Cursor moves onto object. */
690 #define E_LEAVE (-2) /* Cursor leaves object. */
691 #define E_WRITE (-3) /* Write, but not by typing 'w'. */
693 /* The O_SIZE objects have a dual identity. */
694 enum howend
{ SIZE
, LAST
} howend
= SIZE
;
696 object_t
*world
= nil
;
697 object_t
*curobj
= nil
;
699 object_t
*newobject(objtype_t type
, int flags
, int row
, int col
, int len
)
700 /* Make a new object given a type, flags, position and length on the screen. */
703 object_t
**aop
= &world
;
705 new= alloc(sizeof(*new));
722 unsigned long entry2base(struct part_entry
*pe
)
723 /* Return the base sector of the partition if defined. */
725 return pe
->sysind
== NO_PART
? 0 : pe
->lowsec
;
728 unsigned long entry2last(struct part_entry
*pe
)
730 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
+ pe
->size
- 1;
733 unsigned long entry2size(struct part_entry
*pe
)
735 return pe
->sysind
== NO_PART
? 0 : pe
->size
;
738 int typing
; /* Set if a digit has been typed to set a value. */
739 int magic
; /* Changes when using the magic key. */
741 void event(int ev
, object_t
*op
);
743 void m_redraw(int ev
, object_t
*op
)
744 /* Redraw the screen. */
748 if (ev
!= ctrl('L')) return;
751 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) op2
->value
[0]= 0;
754 void m_toggle(int ev
, object_t
*op
)
755 /* Toggle between the driver and alternate geometry. */
759 if (ev
!= 'X') return;
760 if (alt_cyls
== cylinders
&& alt_heads
== heads
&& alt_secs
== sectors
)
763 t
= cylinders
; cylinders
= alt_cyls
; alt_cyls
= t
;
764 t
= heads
; heads
= alt_heads
; alt_heads
= t
;
765 t
= sectors
; sectors
= alt_secs
; alt_secs
= t
;
770 char size_last
[]= "Size";
772 void m_orientation(int ev
, object_t
*op
)
774 if (ev
!= ' ') return;
779 strcpy(size_last
, "Last");
783 strcpy(size_last
, "Size");
787 void m_move(int ev
, object_t
*op
)
788 /* Move to the nearest modifiably object in the intended direction. Objects
789 * on the same row or column are really near.
792 object_t
*near
, *op2
;
793 unsigned dist
, d2
, dr
, dc
;
795 if (ev
!= 'h' && ev
!= 'j' && ev
!= 'k' && ev
!= 'l' && ev
!= 'H')
799 /* No device open? Then try to read first. */
801 if (device
< 0) return;
807 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
808 if (op2
== op
|| !(op2
->flags
& OF_MOD
)) continue;
810 dr
= abs(op2
->row
- op
->row
);
811 dc
= abs(op2
->col
- op
->col
);
813 d2
= 25*dr
*dr
+ dc
*dc
;
814 if (op2
->row
!= op
->row
&& op2
->col
!= op
->col
) d2
+= 1000;
818 if (op2
->col
>= op
->col
) d2
= -1;
821 if (op2
->row
<= op
->row
) d2
= -1;
824 if (op2
->row
>= op
->row
) d2
= -1;
826 case 'l': /* Right */
827 if (op2
->col
<= op
->col
) d2
= -1;
830 if (op2
->type
== O_DEV
) d2
= 0;
832 if (d2
< dist
) { near
= op2
; dist
= d2
; }
834 if (near
!= op
) event(E_LEAVE
, op
);
835 event(E_ENTER
, near
);
838 void m_updown(int ev
, object_t
*op
)
839 /* Move a partition table entry up or down. */
842 struct part_entry tmp
;
845 if (ev
!= ctrl('K') && ev
!= ctrl('J')) return;
846 if (op
->entry
== nil
) return;
848 i
= op
->entry
- table
;
849 if (ev
== ctrl('K')) {
853 if (i
>= NR_PARTITIONS
) return;
857 tmp
= table
[i
]; table
[i
]= table
[j
]; table
[j
]= tmp
;
858 tmpx
= existing
[i
]; existing
[i
]= existing
[j
]; existing
[j
]= tmpx
;
861 event(ev
== ctrl('K') ? 'k' : 'j', op
);
864 void m_enter(int ev
, object_t
*op
)
865 /* We've moved onto this object. */
867 if (ev
!= E_ENTER
&& ev
!= ' ' && ev
!= '<' && ev
!= '>' && ev
!= 'X')
874 void m_leave(int ev
, object_t
*op
)
875 /* About to leave this object. */
877 if (ev
!= E_LEAVE
) return;
880 int within(unsigned *var
, unsigned low
, unsigned value
, unsigned high
)
881 /* Only set *var to value if it looks reasonable. */
883 if (low
<= value
&& value
<= high
) {
890 int lwithin(unsigned long *var
, unsigned long low
, unsigned long value
,
893 if (low
<= value
&& value
<= high
) {
900 int nextdevice(object_t
*op
, int delta
)
901 /* Select the next or previous device from the device list. */
905 if (offset
!= 0) return 0;
906 if (dirty
) event(E_WRITE
, op
);
910 (void) close(device
);
918 curdev
= curdev
->prev
;
919 while (delta
< -1 && major(curdev
->rdev
) == major(rdev
)
920 && curdev
->rdev
< rdev
);
923 curdev
= curdev
->next
;
924 while (delta
> 1 && major(curdev
->rdev
) == major(rdev
)
925 && curdev
->rdev
> rdev
);
930 void check_ind(struct part_entry
*pe
)
931 /* If there are no other partitions then make this new one active. */
933 struct part_entry
*pe2
;
936 for (pe2
= table
+ 1; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++, i
++)
937 if (pe2
->sysind
!= NO_PART
&& (pe2
->bootind
& ACTIVE_FLAG
))
940 pe
->bootind
= ACTIVE_FLAG
;
944 int check_existing(struct part_entry
*pe
)
945 /* Check and if not ask if an existing partition may be modified. */
947 static int expert
= 0;
950 if (expert
|| pe
== nil
|| !existing
[pe
- table
]) return 1;
953 putstr("Do you wish to modify existing partitions? (y/n) ");
955 while ((c
= getchar()) != 'y' && c
!= 'n') {}
958 return (expert
= (c
== 'y'));
961 void m_modify(int ev
, object_t
*op
)
962 /* Increment, decrement, set, or toggle the value of an object, using
963 * arithmetic tricks the author doesn't understand either.
967 struct part_entry
*pe
= op
->entry
;
970 unsigned long surplus
;
971 int radix
= op
->type
== O_TYPHEX
? 0x10 : 10;
974 if (device
< 0 && op
->type
!= O_DEV
) return;
978 mul
= radix
; delta
= -1; typing
= 0;
981 mul
= radix
; delta
= 1; typing
= 0;
991 if ('0' <= ev
&& ev
<= '9')
994 if (radix
== 0x10 && 'a' <= ev
&& ev
<= 'f')
995 delta
= ev
- 'a' + 10;
997 if (radix
== 0x10 && 'A' <= ev
&& ev
<= 'F')
998 delta
= ev
- 'A' + 10;
1002 mul
= typing
? radix
*radix
: 0;
1007 if (!check_existing(pe
)) return;
1011 if (ev
!= '-' && ev
!= '+') return;
1012 if (!nextdevice(op
, delta
)) return;
1015 if (!within(&cylinders
, 1,
1016 cylinders
* mul
/ radix
+ delta
, 1024)) return;
1020 if (!within(&heads
, 1, heads
* mul
/ radix
+ delta
, 255))
1025 if (!within(§ors
, 1, sectors
* mul
/ radix
+ delta
, 63))
1030 if (ev
!= '-' && ev
!= '+') return;
1031 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1032 if (op2
->type
== O_NUM
&& ev
== '+')
1033 op2
->entry
->bootind
= 0;
1035 op
->entry
->bootind
= ev
== '+' ? ACTIVE_FLAG
: 0;
1039 pe
->sysind
= pe
->sysind
* mul
/ radix
+ delta
;
1042 if (ev
!= '-' && ev
!= '+') return;
1044 pe
->sysind
= round_sysind(pe
->sysind
, delta
);
1051 if (op
->type
!= O_SCYL
&& ev
!= '-' && ev
!= '+') return;
1053 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1056 if (!lwithin(&t
, 0L,
1057 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1059 if (howend
== LAST
|| op
->type
!= O_BASE
)
1060 pe
->size
-= t
- pe
->lowsec
;
1063 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1070 if (op
->type
!= O_LCYL
&& ev
!= '-' && ev
!= '+') return;
1072 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1073 t
= pe
->lowsec
+ pe
->size
- 1 + level
;
1074 surplus
= t
% level
- mul
/ radix
* level
;
1075 if (!lwithin(&t
, 0L,
1076 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1078 pe
->size
= t
- pe
->lowsec
+ 1;
1080 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1084 if (mul
== 0) pe
->size
= 0; /* new value, no surplus */
1086 if (pe
->sysind
== NO_PART
) {
1087 if (op
->type
== O_KB
|| howend
== SIZE
) {
1088 /* First let loose magic to set the base. */
1095 memset(pe
, 0, sizeof(*pe
));
1097 t
= (op
->type
== O_KB
|| howend
== SIZE
) ? pe
->size
1098 : pe
->lowsec
+ pe
->size
- 1;
1100 if (!lwithin(&t
, 0L,
1101 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1103 pe
->size
= (op
->type
== O_KB
|| howend
== SIZE
) ? t
:
1106 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1112 /* The order among the entries may have changed. */
1117 unsigned long spell
[3 + 4 * (1+NR_PARTITIONS
)];
1121 void newspell(unsigned long charm
)
1122 /* Add a new spell, descending order for the base, ascending for the size. */
1126 if (charm
- table
[0].lowsec
> table
[0].size
) return;
1128 for (i
= 0; i
< nspells
; i
++) {
1129 if (charm
== spell
[i
]) return; /* duplicate */
1131 if (touching
== O_BASE
) {
1132 if (charm
== table
[0].lowsec
+ table
[0].size
) return;
1133 if ((spell
[0] - charm
) < (spell
[0] - spell
[i
])) break;
1135 if (charm
== table
[0].lowsec
) return;
1136 if ((charm
- spell
[0]) < (spell
[i
] - spell
[0])) break;
1139 for (j
= ++nspells
; j
> i
; j
--) spell
[j
]= spell
[j
-1];
1143 void m_magic(int ev
, object_t
*op
)
1144 /* Apply magic onto a base or size number. */
1146 struct part_entry
*pe
= op
->entry
, *pe2
;
1147 int rough
= (offset
!= 0 && extbase
== 0);
1149 if (ev
!= 'm' || device
< 0) return;
1152 if (!check_existing(pe
)) return;
1155 /* See what magic we can let loose on this value. */
1158 /* First spell, the current value. */
1161 case O_SHEAD
: /* Start of partition. */
1165 spell
[0]= pe
->lowsec
;
1169 case O_LSEC
: /* End of partition. */
1173 spell
[0]= pe
->lowsec
+ pe
->size
;
1178 if (pe
->sysind
== NO_PART
) {
1179 memset(pe
, 0, sizeof(*pe
));
1181 pe
->sysind
= MINIX_PART
;
1183 if (touching
== O_SIZE
) {
1184 /* First let loose magic on the base. */
1187 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1188 if (op2
->row
== op
->row
&&
1189 op2
->type
== O_BASE
) {
1198 /* Avoid the first sector on the device. */
1199 if (spell
[0] == table
[0].lowsec
) newspell(spell
[0] + 1);
1201 /* Further interesting values are the the bases of other
1202 * partitions or their ends.
1204 for (pe2
= table
; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++) {
1205 if (pe2
== pe
|| pe2
->sysind
== NO_PART
) continue;
1206 if (pe2
->lowsec
== table
[0].lowsec
)
1207 newspell(table
[0].lowsec
+ 1);
1209 newspell(pe2
->lowsec
);
1210 newspell(pe2
->lowsec
+ pe2
->size
);
1211 if (touching
== O_BASE
&& howend
== SIZE
) {
1212 newspell(pe2
->lowsec
- pe
->size
);
1213 newspell(pe2
->lowsec
+ pe2
->size
- pe
->size
);
1215 if (pe2
->lowsec
% sectors
!= 0) rough
= 1;
1217 /* Present values rounded up to the next cylinder unless
1218 * the table is already a mess. Use "start + 1 track" instead
1219 * of "start + 1 cylinder". Also add the end of the last
1223 unsigned long n
= spell
[0];
1224 if (n
== table
[0].lowsec
) n
++;
1225 n
= (n
+ sectors
- 1) / sectors
* sectors
;
1226 if (n
!= table
[0].lowsec
+ sectors
)
1227 n
= (n
+ secpcyl
- 1) / secpcyl
* secpcyl
;
1229 if (touching
== O_SIZE
)
1230 newspell(table
[0].size
/ secpcyl
* secpcyl
);
1233 /* Magic has been applied, a spell needs to be chosen. */
1235 if (++magic
== nspells
) magic
= 0;
1237 if (touching
== O_BASE
) {
1238 if (howend
== LAST
) pe
->size
-= spell
[magic
] - pe
->lowsec
;
1239 pe
->lowsec
= spell
[magic
];
1241 pe
->size
= spell
[magic
] - pe
->lowsec
;
1243 /* The order among the entries may have changed. */
1248 typedef struct diving
{
1250 struct part_entry old0
;
1252 parttype_t oldparttype
;
1253 unsigned long oldoffset
;
1254 unsigned long oldextbase
;
1257 diving_t
*diving
= nil
;
1259 void m_in(int ev
, object_t
*op
)
1260 /* Go down into a primary or extended partition. */
1263 struct part_entry
*pe
= op
->entry
, ext
;
1266 if (ev
!= '>' || device
< 0 || pe
== nil
|| pe
== &table
[0]
1267 || (!(pe
->sysind
== MINIX_PART
&& offset
== 0)
1268 && !ext_part(pe
->sysind
))
1269 || pe
->size
== 0) return;
1272 if (extbase
!= 0) ext
.size
= extbase
+ extsize
- ext
.lowsec
;
1274 if (dirty
) event(E_WRITE
, op
);
1276 if (device
>= 0) { close(device
); device
= -1; }
1278 newdiv
= alloc(sizeof(*newdiv
));
1279 newdiv
->old0
= table
[0];
1280 newdiv
->oldsubname
= curdev
->subname
;
1281 newdiv
->oldparttype
= curdev
->parttype
;
1282 newdiv
->oldoffset
= offset
;
1283 newdiv
->oldextbase
= extbase
;
1289 n
= strlen(diving
->oldsubname
);
1290 curdev
->subname
= alloc((n
+ 3) * sizeof(curdev
->subname
[0]));
1291 strcpy(curdev
->subname
, diving
->oldsubname
);
1292 curdev
->subname
[n
++]= ':';
1293 curdev
->subname
[n
++]= '0' + (pe
- table
- 1);
1294 curdev
->subname
[n
]= 0;
1296 curdev
->parttype
= curdev
->parttype
== PRIMARY
? SUBPART
: DUNNO
;
1298 if (ext_part(ext
.sysind
) && extbase
== 0) {
1299 extbase
= ext
.lowsec
;
1301 curdev
->parttype
= DUNNO
;
1308 void m_out(int ev
, object_t
*op
)
1309 /* Go up from an extended or subpartition table to its enclosing. */
1313 if (ev
!= '<' || diving
== nil
) return;
1315 if (dirty
) event(E_WRITE
, op
);
1317 if (device
>= 0) { close(device
); device
= -1; }
1322 table
[0]= olddiv
->old0
;
1324 free(curdev
->subname
);
1325 curdev
->subname
= olddiv
->oldsubname
;
1327 curdev
->parttype
= olddiv
->oldparttype
;
1328 offset
= olddiv
->oldoffset
;
1329 extbase
= olddiv
->oldextbase
;
1334 if (diving
== nil
) submerged
= 0; /* We surfaced. */
1337 void installboot(unsigned char *bootblock
, char *masterboot
)
1338 /* Install code from a master bootstrap into a boot block. */
1341 unsigned char buf
[SECTOR_SIZE
];
1345 if ((mfp
= fopen(masterboot
, "r")) == nil
) {
1346 err
= strerror(errno
);
1350 n
= fread(buf
, sizeof(char), SECTOR_SIZE
, mfp
);
1352 err
= strerror(errno
);
1357 err
= "Is probably not a boot sector, too small";
1361 else if (n
< SECTOR_SIZE
&& n
> PART_TABLE_OFF
) {
1362 /* if only code, it cannot override partition table */
1363 err
= "Does not fit in a boot sector";
1367 else if (n
== SECTOR_SIZE
) {
1368 if (buf
[510] != 0x55 || buf
[511] != 0xaa) {
1369 err
= "Is not a boot sector (bad magic)";
1376 if (n
> PART_TABLE_OFF
) {
1377 err
= "Does not fit in a boot sector";
1382 memcpy(bootblock
, buf
, n
);
1385 /* Bootstrap installed. */
1390 printf("%s: %s", masterboot
, err
);
1394 ssize_t
boot_readwrite(int rw
)
1395 /* Read (0) or write (1) the boot sector. */
1399 if (lseek64(device
, (u64_t
) offset
* SECTOR_SIZE
, SEEK_SET
, NULL
) < 0)
1403 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1404 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1410 int cylinderalign(region_t
*reg
)
1412 if(reg
->is_used_part
) {
1413 if(reg
->used_part
.lowsec
!= table
[0].lowsec
+ sectors
1414 && (reg
->used_part
.lowsec
% secpcyl
)) {
1416 extra
= secpcyl
- (reg
->used_part
.lowsec
% secpcyl
);
1417 reg
->used_part
.lowsec
+= extra
;
1418 reg
->used_part
.size
-= extra
;
1420 if((reg
->used_part
.size
+1) % secpcyl
) {
1421 reg
->used_part
.size
-= secpcyl
- ((reg
->used_part
.size
+ 1) % secpcyl
);
1423 return reg
->used_part
.size
> 0;
1426 if(reg
->free_sec_start
!= table
[0].lowsec
+ sectors
&& (reg
->free_sec_start
% secpcyl
)) {
1427 /* Start is unaligned. Round up. */
1428 reg
->free_sec_start
+= secpcyl
- (reg
->free_sec_start
% secpcyl
);
1430 if((reg
->free_sec_last
+1) % secpcyl
) {
1431 /* End is unaligned. Round down. */
1432 reg
->free_sec_last
-= (reg
->free_sec_last
+1) % secpcyl
;
1435 /* Return nonzero if anything remains of the region after rounding. */
1436 return reg
->free_sec_last
> reg
->free_sec_start
;
1439 void regionize(void)
1441 int free_sec
, i
, si
;
1445 free_sec
= table
[0].lowsec
+ sectors
;
1447 /* Create region data used in autopart mode. */
1448 free_regions
= used_regions
= nr_regions
= nr_partitions
= 0;
1449 if(table
[0].lowsec
> table
[sort_order
[1]].lowsec
&&
1450 table
[sort_order
[1]].sysind
!= NO_PART
) {
1451 printf("\nSanity check failed on %s - first partition starts before disk.\n"
1452 "Please use expert mode to correct it.\n", curdev
->name
);
1455 for(si
= 1; si
<= NR_PARTITIONS
; si
++) {
1457 if(i
< 1 || i
> NR_PARTITIONS
) {
1458 printf("Sorry, something unexpected has happened (%d out of range).\n", i
);
1462 if(table
[i
].sysind
== NO_PART
)
1465 /* Free space before this partition? */
1466 if(table
[i
].lowsec
> free_sec
) {
1467 /* Free region before this partition. */
1468 regions
[nr_regions
].free_sec_start
= free_sec
;
1469 regions
[nr_regions
].free_sec_last
= table
[i
].lowsec
-1;
1470 regions
[nr_regions
].is_used_part
= 0;
1471 if(cylinderalign(®ions
[nr_regions
])) {
1479 if(table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
||
1480 table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
+ table
[sort_order
[si
-1]].size
) {
1481 printf("\nSanity check failed on %s - partitions overlap.\n"
1482 "Please use expert mode to correct it.\n", curdev
->name
);
1486 if(table
[i
].size
> table
[0].size
) {
1487 printf("\nSanity check failed on %s - partition is larger than disk.\n"
1488 "Please use expert mode to correct it.\n", curdev
->name
);
1491 if(table
[i
].size
< 1) {
1492 printf("\nSanity check failed on %s - zero-sized partition.\n"
1493 "Please use expert mode to correct it.\n", curdev
->name
);
1497 /* Remember used region. */
1498 memcpy(®ions
[nr_regions
].used_part
, &table
[i
], sizeof(table
[i
]));
1499 free_sec
= table
[i
].lowsec
+table
[i
].size
;
1500 regions
[nr_regions
].is_used_part
= 1;
1501 regions
[nr_regions
].tableno
= i
;
1507 /* Special case: space after partitions. */
1508 if(free_sec
< table
[0].lowsec
+ table
[0].size
-1) {
1509 regions
[nr_regions
].free_sec_start
= free_sec
;
1510 regions
[nr_regions
].free_sec_last
= table
[0].lowsec
+ table
[0].size
-1;
1511 regions
[nr_regions
].is_used_part
= 0;
1512 if(cylinderalign(®ions
[nr_regions
])) {
1520 void m_read(int ev
, int *biosdrive
)
1521 /* Read the partition table from the current device. */
1524 struct part_entry
*pe
;
1527 if (ev
!= 'r' || device
>= 0) return;
1529 /* Open() may cause kernel messages: */
1533 if ((device
= open(curdev
->name
, mode
= O_RDWR
, 0666)) < 0) {
1534 if (device
>= 0) { close(device
); device
= -1; }
1538 system_hz
= (u32_t
) sysconf(_SC_CLK_TCK
);
1540 ioctl(device
, DIOCTIMEOUT
, &v
);
1542 memset(bootblock
, 0, sizeof(bootblock
));
1544 n
= boot_readwrite(0);
1546 if (n
<= 0) stat_start(1);
1551 if (n
< SECTOR_SIZE
) {
1556 if (n
<= 0) stat_end(5);
1558 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1560 if(biosdrive
) (*biosdrive
)++;
1562 if(!open_ct_ok(device
)) {
1563 printf("\n%s: device in use! skipping it.", curdev
->subname
);
1570 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1571 NR_PARTITIONS
* sizeof(table
[1]));
1572 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1573 /* Invalid boot block, install bootstrap, wipe partition table.
1575 memset(bootblock
, 0, sizeof(bootblock
));
1576 installboot(bootblock
, MASTERBOOT
);
1577 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1580 /* Fix an extended partition table up to something mere mortals can
1581 * understand. Record already defined partitions.
1583 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1585 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1586 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1587 existing
[i
]= pe
->sysind
!= NO_PART
;
1592 /* Warn about grave dangers ahead. */
1595 printf("Warning: You are in an extended partition.");
1602 void m_write(int ev
, object_t
*op
)
1603 /* Write the partition table back if modified. */
1605 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1607 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1608 if (device
< 0) { dirty
= 0; return; }
1612 printf("%s is not changed, or has already been written",
1620 /* Will this stop him? Probably not... */
1622 printf("You have changed an extended partition. Bad Idea.");
1626 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1627 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1628 if (pe
->sysind
== NO_PART
) {
1629 memset(pe
, 0, sizeof(*pe
));
1631 abs2dos(&pe
->start_head
, pe
->lowsec
);
1632 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1634 /* Fear and loathing time: */
1636 pe
->lowsec
-= ext_part(pe
->sysind
)
1640 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1641 bootblock
[510]= 0x55;
1642 bootblock
[511]= 0xAA;
1644 if (boot_readwrite(1) < 0) {
1646 printf("%s: %s", curdev
->name
, strerror(errno
));
1653 void m_shell(int ev
, object_t
*op
)
1654 /* Shell escape, to do calculations for instance. */
1657 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1659 if (ev
!= 's') return;
1664 switch (pid
= fork()) {
1667 printf("can't fork: %s\n", strerror(errno
));
1671 if (device
>= 0) (void) close(device
);
1672 execl("/bin/sh", "sh", (char *) nil
);
1675 printf("/bin/sh: %s\n", strerror(errno
));
1679 sigint
= signal(SIGINT
, SIG_IGN
);
1680 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1681 sigterm
= signal(SIGTERM
, SIG_IGN
);
1682 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1683 (void) signal(SIGINT
, sigint
);
1684 (void) signal(SIGQUIT
, sigquit
);
1685 (void) signal(SIGTERM
, sigterm
);
1690 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1691 stat_start(0); /* Match the stat_start in the child. */
1693 event(ctrl('L'), op
);
1698 void m_quit(int ev
, object_t
*op
)
1699 /* Write the partition table if modified and exit. */
1701 if (ev
!= 'q' && ev
!= 'x') return;
1705 if (dirty
) event(E_WRITE
, op
);
1706 if (dirty
) quitting
= 0;
1709 void m_help(int ev
, object_t
*op
)
1710 /* For people without a clue; let's hope they can find the '?' key. */
1712 static struct help
{
1716 { "? !", "This help / more advice!" },
1717 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1718 { "0-9 (a-f)", "Enter value" },
1719 { "hjkl (arrow keys)", "Move around" },
1720 { "CTRL-K CTRL-J", "Move entry up/down" },
1721 { "CTRL-L", "Redraw screen" },
1722 { ">", "Start a subpartition table" },
1723 { "<", "Back to the primary partition table" },
1724 { "m", "Cycle through magic values" },
1725 { "spacebar", "Show \"Size\" or \"Last\"" },
1726 { "r w", "Read/write partition table" },
1727 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1728 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1730 static char *advice
[] = {
1731 "* Choose a disk with '+' and '-', then hit 'r'.",
1732 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1733 "* To make a new partition: Move over to the Size or Kb field of an unused",
1734 " partition and type the size. Hit the 'm' key to pad the partition out to",
1735 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1736 " You can hit 'm' more than once on a base or size field to see several",
1737 " interesting values go by. Note: Other Operating Systems can be picky about",
1738 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1739 " head or sector numbers.",
1740 "* To reuse a partition: Change the type to MINIX.",
1741 "* To delete a partition: Type a zero in the hex Type field.",
1742 "* To make a partition active: Type '+' in the Num field.",
1743 "* To study the list of keys: Type '?'.",
1749 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1751 printf("%-25s - %s", hp
->keys
, hp
->what
);
1755 putstr("Things like ");
1756 putstr(t_so
); putstr("this"); putstr(t_se
);
1757 putstr(" must be checked, but ");
1758 putstr(t_md
); putstr("this"); putstr(t_me
);
1759 putstr(" is not really a problem");
1765 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1773 void event(int ev
, object_t
*op
)
1774 /* Simply call all modifiers for an event, each one knows when to act. */
1779 m_orientation(ev
, op
);
1795 prettysizeprint(int kb
)
1798 static char str
[200];
1800 if(MIN_REGION_SECTORS
> kb
*2)
1810 sprintf(str
, "%4d %cB%s", kb
, unit
,
1811 toosmall
? ", too small for MINIX 3" : "");
1816 printregions(region_t
*theregions
, int indent
, int p_nr_partitions
, int p_free_regions
, int p_nr_regions
, int numbers
)
1822 if((p_nr_partitions
>= NR_PARTITIONS
|| !p_free_regions
) && p_free_regions
)
1824 for(r
= 0; r
< p_nr_regions
; r
++, reg
++) {
1825 unsigned long units
;
1826 if(reg
->is_used_part
) {
1828 name
= typ2txt(reg
->used_part
.sysind
);
1829 printf("%*s", indent
, ""); type2col(reg
->used_part
.sysind
);
1830 if(numbers
) printf("[%d] ", r
);
1831 printf("In use by %-10s ", name
);
1832 units
= reg
->used_part
.size
/ 2;
1834 printf(" (%s)\n", prettysizeprint(units
));
1836 printf("%*s", indent
, "");
1838 if(!nofree
) printf("[%d] ", r
);
1839 else printf("[-] ");
1841 printf("Free space ");
1842 units
= ((reg
->free_sec_last
- reg
->free_sec_start
+1))/2;
1843 printf(" (%s)\n", prettysizeprint(units
));
1847 if(numbers
&& p_nr_partitions
>= NR_PARTITIONS
&& p_free_regions
) {
1849 "\nNote: there is free space on this disk, but you can't select it,\n"
1850 "because there isn't a free slot in the partition table to use it.\n"
1851 "You can reclaim the free space by deleting an adjacent region.\n");
1861 is_sure(char *fmt
, ...)
1868 printf(" Please enter 'yes' or 'no': ");
1870 if(!fgets(yesno
, sizeof(yesno
)-1, stdin
)) exit(1);
1872 if (strcmp(yesno
, "yes\n") == 0) return(IS_YES
);
1873 if (strcmp(yesno
, "no\n") == 0) return(IS_NO
);
1877 void warn(char *message
)
1879 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
);
1883 may_kill_region(void)
1889 if(used_regions
< 1) return 1;
1891 printf("\n -- Delete in-use region? --\n\n");
1893 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1894 printf("\nEnter the region number to delete or ENTER to continue: ");
1896 fgets(line
, sizeof(line
)-2, stdin
);
1897 if(!isdigit(line
[0]))
1901 if(r
< 0 || r
>= nr_regions
) {
1902 printf("This choice is out of range.\n");
1906 if(!regions
[r
].is_used_part
) {
1907 printf("This region is not in use.\n");
1911 i
= regions
[r
].tableno
;
1913 printf("\nPlease confirm that you want to delete region %d, losing all data it", r
);
1914 printf("\ncontains. You're disk is not actually updated right away, but still.");
1918 confirmation
= is_sure("Are you sure you want to continue?");
1919 if (confirmation
== IS_NO
) return 0;
1920 } while (confirmation
!= IS_YES
);
1922 table
[i
].sysind
= NO_PART
;
1926 /* User may go again. */
1935 static char line
[100];
1938 printstep(2, "Select a disk region");
1940 if(nr_regions
< 1) {
1941 printf("\nNo regions found - maybe the drive is too small.\n"
1942 "Please try expert mode.\n");
1946 if(nr_partitions
>= NR_PARTITIONS
|| !free_regions
) {
1953 printf("\nPlease select the region that you want to use for the MINIX 3 setup.");
1954 printf("\nIf you select an in-use region it will be overwritten by MINIX. The");
1955 printf("\nfollowing region%s were found on the selected disk:\n\n",
1956 SORNOT(nr_regions
));
1957 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1962 printf("Enter the region number to use or type 'delete': ");
1963 if(nr_regions
== 1) printf(" [0] ");
1966 if(!fgets(line
, sizeof(line
)-2, stdin
))
1969 if (nr_regions
== 1 && line
[0] == '\n') {
1974 if(strcmp(line
,"delete\n") == 0) {
1979 if(sscanf(line
, "%d", &rn
) != 1) {
1980 warn("invalid choice");
1984 if(rn
< 0 || rn
>= nr_regions
) {
1985 warn("out of range");
1989 if(nofree
&& !regions
[rn
].is_used_part
) {
1990 warn("not available");
1998 return(®ions
[rn
]);
2001 void printstep(int step
, char *str
)
2004 n
= printf("\n --- Substep 3.%d: %s ---", step
, str
);
2005 while(n
++ < 73) printf("-");
2013 int i
, choice
, drives
;
2014 static char line
[500];
2017 printstep(1, "Select a disk to install MINIX 3");
2018 printf("\nProbing for disks. This may take a short while.");
2023 for(; i
< MAX_DEVICES
;) {
2026 m_read('r', &biosdrive
);
2028 devices
[i
].dev
= curdev
;
2029 devices
[i
].free_regions
= free_regions
;
2030 devices
[i
].nr_regions
= nr_regions
;
2031 devices
[i
].nr_partitions
= nr_partitions
;
2032 devices
[i
].used_regions
= used_regions
;
2033 devices
[i
].sectors
= table
[0].size
;
2034 curdev
->biosdrive
= biosdrive
-1;
2035 memcpy(devices
[i
].regions
, regions
, sizeof(regions
));
2039 nextdevice(NULL
, 1);
2040 if(curdev
== firstdev
)
2047 printf("\nFound no drives - can't partition.\n");
2051 printf(" Probing done.\n");
2052 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives
),
2053 drives
== 1 ? "was" : "were");
2055 for(i
= 0; i
< drives
; i
++) {
2057 printf("Disk [%d]: ", i
);
2058 printf("%s, ", devices
[i
].dev
->name
);
2059 printf("%s\n", prettysizeprint(devices
[i
].sectors
/2));
2060 printregions(devices
[i
].regions
, 8,
2061 devices
[i
].nr_partitions
,
2062 devices
[i
].free_regions
,
2063 devices
[i
].nr_regions
, 0);
2068 printf("Enter the disk number to use: ");
2069 if (drives
== 1) printf("[0] ");
2071 if(!fgets(line
, sizeof(line
)-2, stdin
))
2073 if (line
[0] == '\n' && drives
== 1) {
2077 if(sscanf(line
, "%d", &choice
) != 1) {
2078 warn("choose a disk");
2081 if(choice
< 0 || choice
>= i
) {
2082 warn("out of range");
2088 return devices
[choice
].dev
;
2092 scribble_region(region_t
*reg
, struct part_entry
**pe
, int *made_new
)
2094 int ex
, changed
= 0, i
;
2095 struct part_entry
*newpart
;
2096 if(!reg
->is_used_part
) {
2097 ex
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2098 if(made_new
) *made_new
= 1;
2099 } else if(made_new
) *made_new
= 0;
2100 if(!reg
->is_used_part
) {
2101 for(i
= 1; i
<= NR_PARTITIONS
; i
++)
2102 if(table
[i
].sysind
== NO_PART
)
2104 if(i
> NR_PARTITIONS
) {
2105 /* Bug, should've been caught earlier. */
2106 printf("Couldn't find a free slot. Please try expert mode.\n");
2109 newpart
= &table
[i
];
2110 newpart
->lowsec
= reg
->free_sec_start
;
2111 newpart
->size
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2113 newpart
->sysind
= MINIX_PART
;
2115 newpart
= ®
->used_part
;
2124 sanitycheck_failed(char *dev
, struct part_entry
*pe
)
2126 struct partition part
;
2128 unsigned long it_lowsec
, it_secsize
;
2130 if((fd
= open(dev
, O_RDONLY
)) < 0) {
2135 if (ioctl(fd
, DIOCGETP
, &part
) < 0) {
2136 fprintf(stderr
, "DIOCGETP failed\n");
2141 if(!open_ct_ok(fd
)) {
2142 printf("\nAutopart error: the disk is in use. This means that although a\n"
2143 "new table has been written, it won't be in use by the system\n"
2144 "until it's no longer in use (or a reboot is done). Just in case,\n"
2145 "I'm not going to continue. Please un-use the disk (or reboot) and try\n"
2152 it_lowsec
= div64u(part
.base
, SECTOR_SIZE
);
2153 it_secsize
= div64u(part
.size
, SECTOR_SIZE
);
2155 if(it_lowsec
!= pe
->lowsec
|| it_secsize
!= pe
->size
) {
2156 fprintf(stderr
, "\nReturned and set numbers don't match up!\n");
2157 fprintf(stderr
, "This can happen if the disk is still opened.\n");
2165 do_autopart(int resultfd
)
2169 struct part_entry
*pe
;
2170 struct part_entry orig_table
[1 + NR_PARTITIONS
];
2176 curdev
= select_disk();
2187 memcpy(orig_table
, table
, sizeof(table
));
2191 r
= select_region();
2192 } while(!r
); /* Back to step 2. */
2195 if(scribble_region(r
, &pe
, &newp
)) {
2198 char partbuf
[100], devname
[100];
2199 struct part_entry
*tpe
= NULL
;
2201 printstep(3, "Confirm your choices");
2203 region
= (int)(r
-regions
);
2204 /* disk = (int) (curdev-devices); */
2206 printf("\nThis is the point of no return. You have selected to install MINIX 3\n");
2207 printf("into region %d of disk %s. Please confirm that you want\n",
2208 region
, curdev
->name
);
2209 printf("to use this selection to install MINIX 3.\n\n");
2212 confirmation
= is_sure("Are you sure you want to continue?");
2213 if (confirmation
== IS_NO
) return 1;
2214 } while (confirmation
!= IS_YES
);
2216 /* Retrieve partition number in sorted order that we
2217 * have scribbled in.
2220 for(i
= 1; i
<= NR_PARTITIONS
; i
++) {
2223 if(si
< 1 || si
> NR_PARTITIONS
) {
2224 fprintf(stderr
, "Autopart internal error (out of range) (nothing written).\n");
2227 if(table
[si
].lowsec
== pe
->lowsec
) {
2229 fprintf(stderr
, "Autopart internal error (part found twice) (nothing written).\n");
2232 check_ind(&table
[si
]);
2233 table
[si
].sysind
= MINIX_PART
;
2239 fprintf(stderr
, "Autopart internal error (part not found) (nothing written).\n");
2244 fprintf(stderr
, "Autopart internal error (couldn't update disk).\n");
2247 name
=strrchr(curdev
->name
, '/');
2248 if(!name
) name
= curdev
->name
;
2251 sprintf(partbuf
, "%sp%d d%dp%d\n", name
, found
-1,
2252 curdev
->biosdrive
, found
-1);
2253 sprintf(devname
, "/dev/%sp%d", name
, found
-1);
2254 if(resultfd
>= 0 && write(resultfd
, partbuf
, strlen(partbuf
)) < strlen(partbuf
)) {
2255 fprintf(stderr
, "Autopart internal error (couldn't write result).\n");
2269 if(sanitycheck_failed(devname
, tpe
)) {
2270 fprintf(stderr
, "Autopart internal error (disk sanity check failed).\n");
2276 if((fd
=open(devname
, O_WRONLY
)) < 0) {
2279 /* Clear any subpartitioning. */
2280 static unsigned char sub
[2048];
2283 write(fd
, sub
, sizeof(sub
));
2293 int main(int argc
, char **argv
)
2299 /* autopart uses getopt() */
2300 while((c
= getopt(argc
, argv
, "m:f:")) != EOF
) {
2303 min_region_mb
= atoi(optarg
);
2306 /* Make sure old data file is gone. */
2308 if((resultfd
=open(optarg
, O_CREAT
| O_WRONLY
| O_TRUNC
)) < 0) {
2312 sync(); /* Make sure no old data file lingers. */
2315 fprintf(stderr
, "Unknown option\n");
2323 for (i
= 0; i
< argc
; i
++) {
2324 newdevice(argv
[i
], 0, 0);
2327 if (firstdev
== nil
) {
2336 if (firstdev
== nil
) {
2337 fprintf(stderr
, "autopart couldn't find any devices.\n");
2340 r
= do_autopart(resultfd
);
2341 if(resultfd
>= 0) { close(resultfd
); }