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 #ifndef makedev /* Missing in sys/types.h */
233 #define minor(dev) (((dev) >> MINOR) & BYTE)
234 #define major(dev) (((dev) >> MAJOR) & BYTE)
235 #define makedev(major, minor) \
236 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
239 typedef enum parttype
{ DUNNO
, SUBPART
, PRIMARY
, FLOPPY
} parttype_t
;
241 typedef struct device
{
242 struct device
*next
, *prev
; /* Circular dequeue. */
243 dev_t rdev
; /* Device number (sorting only). */
244 char *name
; /* E.g. /dev/c0d0 */
245 char *subname
; /* E.g. /dev/c0d0:2 */
250 typedef struct region
{
251 /* A region is either an existing top-level partition
252 * entry (used_part is non-NULL) or free space (free_*
255 struct part_entry used_part
;
258 int free_sec_start
, free_sec_last
;
261 /* A disk has between 1 and 2*partitions+1 regions;
262 * the last case is free space before and after every partition.
264 #define NR_REGIONS (2*NR_PARTITIONS+1)
265 region_t regions
[NR_REGIONS
];
266 int nr_partitions
= 0, nr_regions
= 0, free_regions
, used_regions
;
269 device_t
*firstdev
= nil
, *curdev
;
271 #define MAX_DEVICES 100
274 int nr_partitions
, free_regions
, used_regions
, sectors
, nr_regions
;
276 region_t regions
[NR_REGIONS
];
277 } devices
[MAX_DEVICES
];
279 void newdevice(char *name
, int scanning
, int disk_only
)
280 /* Add a device to the device list. If scanning is set then we are reading
281 * /dev, so insert the device in device number order and make /dev/c0d0 current.
284 device_t
*new, *nextdev
, *prevdev
;
289 if (stat(name
, &st
) < 0 || !S_ISBLK(st
.st_mode
)) return;
291 switch (major(st
.st_rdev
)) {
293 /* Disk controller */
294 if (minor(st
.st_rdev
) >= 0x80
295 || minor(st
.st_rdev
) % 5 != 0) return;
300 /* Interesting device found. */
302 if(stat(name
, &st
) < 0) { perror(name
); return; }
305 new= alloc(sizeof(*new));
306 new->rdev
= st
.st_rdev
;
307 new->name
= alloc((strlen(name
) + 1) * sizeof(new->name
[0]));
308 strcpy(new->name
, name
);
309 new->subname
= new->name
;
310 new->parttype
= DUNNO
;
311 if (major(st
.st_rdev
) == major(DEV_FD0
) && minor(st
.st_rdev
) < 112) {
312 new->parttype
= FLOPPY
;
314 if (st
.st_rdev
>= DEV_C0D0
&& minor(st
.st_rdev
) < 128
315 && minor(st
.st_rdev
) % 5 == 0) {
316 new->parttype
= PRIMARY
;
319 if (firstdev
== nil
) {
321 new->next
= new->prev
= new;
326 while (new->rdev
>= nextdev
->rdev
327 && (nextdev
= nextdev
->next
) != firstdev
) {}
328 prevdev
= nextdev
->prev
;
334 if (new->rdev
< firstdev
->rdev
) firstdev
= new;
335 if (new->rdev
== DEV_C0D0
) curdev
= new;
336 if (curdev
->rdev
!= DEV_C0D0
) curdev
= firstdev
;
339 void getdevices(void)
340 /* Get all block devices from /dev that look interesting. */
344 char name
[5 + NAME_MAX
+ 1];
346 if ((d
= opendir("/dev")) == nil
) fatal("/dev");
348 while ((e
= readdir(d
)) != nil
) {
349 strcpy(name
, "/dev/");
350 strcpy(name
+ 5, e
->d_name
);
351 newdevice(name
, 1, 1);
357 unsigned char bootblock
[SECTOR_SIZE
];
358 struct part_entry table
[1 + NR_PARTITIONS
];
359 int existing
[1 + NR_PARTITIONS
];
360 unsigned long offset
= 0, extbase
= 0, extsize
;
362 int sort_index
[1 + NR_PARTITIONS
], sort_order
[1 + NR_PARTITIONS
];
363 unsigned cylinders
= 1, heads
= 1, sectors
= 1, secpcyl
= 1;
364 unsigned alt_cyls
= 1, alt_heads
= 1, alt_secs
= 1;
368 unsigned long sortbase(struct part_entry
*pe
)
370 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
;
374 /* Let the sort_index array show the order partitions are sorted in. */
378 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_order
[i
]= i
;
380 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
381 for (j
= 1; j
<= NR_PARTITIONS
-1; j
++) {
382 int sj
= sort_order
[j
], sj1
= sort_order
[j
+1];
384 if (sortbase(&table
[sj
]) > sortbase(&table
[sj1
])) {
390 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_index
[sort_order
[i
]]= i
;
393 void dos2chs(unsigned char *dos
, unsigned *chs
)
394 /* Extract cylinder, head and sector from the three bytes DOS uses to address
395 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
396 * of the sector byte. The sector number is rebased to count from 0.
399 chs
[0]= ((dos
[1] & 0xC0) << 2) | dos
[2];
401 chs
[2]= (dos
[1] & 0x3F) - 1;
404 void abs2dos(unsigned char *dos
, unsigned long pos
)
405 /* Translate a sector offset to three DOS bytes. */
410 h
= (pos
% secpcyl
) / sectors
;
411 s
= pos
% sectors
+ 1;
414 dos
[1]= s
| ((c
>> 2) & 0xC0);
418 void recompute0(void)
419 /* Recompute the partition size for the device after a geometry change. */
422 cylinders
= heads
= sectors
= 1;
423 memset(table
, 0, sizeof(table
));
425 if (!precise
&& offset
== 0) {
427 table
[0].size
= (unsigned long) cylinders
* heads
* sectors
;
429 table
[0].sysind
= device
< 0 ? NO_PART
: MINIX_PART
;
430 secpcyl
= heads
* sectors
;
433 void guess_geometry(void)
434 /* With a bit of work one can deduce the disk geometry from the partition
435 * table. This may be necessary if the driver gets it wrong. (If partition
436 * tables didn't have C/H/S numbers we would not care at all...)
440 struct part_entry
*pe
;
444 unsigned char HS
[256][8]; /* Bit map off all possible H/S */
446 alt_cyls
= alt_heads
= alt_secs
= 0;
448 /* Initially all possible H/S combinations are possible. HS[h][0]
449 * bit 0 is used to rule out a head value.
451 for (h
= 1; h
<= 255; h
++) {
452 for (s
= 0; s
< 8; s
++) HS
[h
][s
]= 0xFF;
455 for (i
= 0; i
< 2*NR_PARTITIONS
; i
++) {
456 pe
= &(table
+1)[i
>> 1];
457 if (pe
->sysind
== NO_PART
) continue;
459 /* Get the end or start sector numbers (in that order). */
461 dos2chs(&pe
->last_head
, chs
);
462 sec
= pe
->lowsec
+ pe
->size
- 1;
464 dos2chs(&pe
->start_head
, chs
);
468 if (chs
[0] >= alt_cyls
) alt_cyls
= chs
[0]+1;
470 /* Which H/S combinations can be ruled out? */
471 for (h
= 1; h
<= 255; h
++) {
472 if (HS
[h
][0] == 0) continue;
474 for (s
= 1; s
<= 63; s
++) {
475 if ((chs
[0] * h
+ chs
[1]) * s
+ chs
[2] != sec
) {
476 HS
[h
][s
/8] &= ~(1 << (s
%8));
478 if (HS
[h
][s
/8] & (1 << (s
%8))) n
++;
480 if (n
== 0) HS
[h
][0]= 0;
484 /* See if only one remains. */
486 for (h
= 1; h
<= 255; h
++) {
487 if (HS
[h
][0] == 0) continue;
488 for (s
= 1; s
<= 63; s
++) {
489 if (HS
[h
][s
/8] & (1 << (s
%8))) {
497 /* Forget it if more than one choice... */
498 if (i
> 1) alt_cyls
= alt_heads
= alt_secs
= 0;
502 /* Find out the geometry of the device by querying the driver, or by looking
503 * at the partition table. These numbers are crosschecked to make sure that
504 * the geometry is correct. Master bootstraps other than the Minix one use
505 * the CHS numbers in the partition table to load the bootstrap of the active
511 struct partition geometry
;
514 /* Geometry already known. */
521 if (device
< 0) return;
523 /* Try to guess the geometry from the partition table. */
526 /* Try to get the geometry from the driver. */
527 (void) fstat(device
, &dst
);
529 if (S_ISBLK(dst
.st_mode
) || S_ISCHR(dst
.st_mode
)) {
530 /* Try to get the drive's geometry from the driver. */
532 if (ioctl(device
, DIOCGETP
, &geometry
) < 0)
535 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
536 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
537 cylinders
= geometry
.cylinders
;
538 heads
= geometry
.heads
;
539 sectors
= geometry
.sectors
;
547 /* Getting the geometry from the driver failed, so use the
548 * alternate geometry.
550 if (alt_heads
== 0) {
551 alt_cyls
= table
[0].size
/ (64 * 32);
561 printf("Failure to get the geometry of %s: %s", curdev
->name
,
562 errno
== ENOTTY
? "No driver support" : strerror(err
));
565 printf("The geometry has been guessed as %ux%ux%u",
566 cylinders
, heads
, sectors
);
569 if (alt_heads
== 0) {
575 if (heads
!= alt_heads
|| sectors
!= alt_secs
) {
577 "The geometry obtained from the driver\n"
578 "does not match the geometry implied by the partition\n"
579 "table. Please use expert mode instead.\n");
584 /* Show the base and size of the device instead of the whole drive.
585 * This makes sense for subpartitioning primary partitions.
587 if (precise
&& ioctl(device
, DIOCGETP
, &geometry
) >= 0) {
588 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
589 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
597 typedef struct indicators
{ /* Partition type to partition name. */
602 indicators_t ind_table
[]= {
606 { 0x03, "XENIX usr" },
608 { 0x05, "EXTENDED" },
610 { 0x07, "HPFS/NTFS" },
612 { 0x09, "COHERENT" },
617 { 0x0F, "EXTENDED" },
619 { 0x40, "VENIX286" },
620 { 0x42, "W2000 Dyn" },
621 { 0x52, "MICROPORT" },
623 { 0x64, "NOVELL286" },
624 { 0x65, "NOVELL386" },
626 { 0x80, "MINIX-OLD" },
628 { 0x82, "LINUXswap" },
631 { 0x94, "AMOEBAbad" },
634 { 0xB8, "BSDI swap" },
637 { 0xFF, "BADBLOCKS" },
640 char *typ2txt(int ind
)
641 /* Translate a numeric partition indicator for human eyes. */
645 for (pind
= ind_table
; pind
< arraylimit(ind_table
); pind
++) {
646 if (pind
->ind
== ind
) return pind
->name
;
648 return "unknown system";
651 int round_sysind(int ind
, int delta
)
652 /* Find the next known partition type starting with ind in direction delta. */
656 ind
= (ind
+ delta
) & 0xFF;
659 for (pind
= arraylimit(ind_table
)-1; pind
->ind
> ind
; pind
--) {}
661 for (pind
= ind_table
; pind
->ind
< ind
; pind
++) {}
666 /* Objects on the screen, either simple pieces of the text or the cylinder
667 * number of the start of partition three.
669 typedef enum objtype
{
670 O_INFO
, O_TEXT
, O_DEV
, O_SUB
,
671 O_TYPTXT
, O_SORT
, O_NUM
, O_TYPHEX
,
672 O_CYL
, O_HEAD
, O_SEC
,
673 O_SCYL
, O_SHEAD
, O_SSEC
, O_LCYL
, O_LHEAD
, O_LSEC
, O_BASE
, O_SIZE
, O_KB
676 #define rjust(type) ((type) >= O_TYPHEX)
677 #define computed(type) ((type) >= O_TYPTXT)
679 typedef struct object
{
681 objtype_t type
; /* Text field, cylinder number, etc. */
682 char flags
; /* Modifiable? */
686 struct part_entry
*entry
; /* What does the object refer to? */
688 char value
[20]; /* Value when printed. */
691 #define OF_MOD 0x01 /* Object value is modifiable. */
692 #define OF_ODD 0x02 /* It has a somewhat odd value. */
693 #define OF_BAD 0x04 /* Its value is no good at all. */
695 /* Events: (Keypress events are the value of the key pressed.) */
696 #define E_ENTER (-1) /* Cursor moves onto object. */
697 #define E_LEAVE (-2) /* Cursor leaves object. */
698 #define E_WRITE (-3) /* Write, but not by typing 'w'. */
700 /* The O_SIZE objects have a dual identity. */
701 enum howend
{ SIZE
, LAST
} howend
= SIZE
;
703 object_t
*world
= nil
;
704 object_t
*curobj
= nil
;
706 object_t
*newobject(objtype_t type
, int flags
, int row
, int col
, int len
)
707 /* Make a new object given a type, flags, position and length on the screen. */
710 object_t
**aop
= &world
;
712 new= alloc(sizeof(*new));
729 unsigned long entry2base(struct part_entry
*pe
)
730 /* Return the base sector of the partition if defined. */
732 return pe
->sysind
== NO_PART
? 0 : pe
->lowsec
;
735 unsigned long entry2last(struct part_entry
*pe
)
737 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
+ pe
->size
- 1;
740 unsigned long entry2size(struct part_entry
*pe
)
742 return pe
->sysind
== NO_PART
? 0 : pe
->size
;
745 int typing
; /* Set if a digit has been typed to set a value. */
746 int magic
; /* Changes when using the magic key. */
748 void event(int ev
, object_t
*op
);
750 void m_redraw(int ev
, object_t
*op
)
751 /* Redraw the screen. */
755 if (ev
!= ctrl('L')) return;
758 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) op2
->value
[0]= 0;
761 void m_toggle(int ev
, object_t
*op
)
762 /* Toggle between the driver and alternate geometry. */
766 if (ev
!= 'X') return;
767 if (alt_cyls
== cylinders
&& alt_heads
== heads
&& alt_secs
== sectors
)
770 t
= cylinders
; cylinders
= alt_cyls
; alt_cyls
= t
;
771 t
= heads
; heads
= alt_heads
; alt_heads
= t
;
772 t
= sectors
; sectors
= alt_secs
; alt_secs
= t
;
777 char size_last
[]= "Size";
779 void m_orientation(int ev
, object_t
*op
)
781 if (ev
!= ' ') return;
786 strcpy(size_last
, "Last");
790 strcpy(size_last
, "Size");
794 void m_move(int ev
, object_t
*op
)
795 /* Move to the nearest modifiably object in the intended direction. Objects
796 * on the same row or column are really near.
799 object_t
*near
, *op2
;
800 unsigned dist
, d2
, dr
, dc
;
802 if (ev
!= 'h' && ev
!= 'j' && ev
!= 'k' && ev
!= 'l' && ev
!= 'H')
806 /* No device open? Then try to read first. */
808 if (device
< 0) return;
814 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
815 if (op2
== op
|| !(op2
->flags
& OF_MOD
)) continue;
817 dr
= abs(op2
->row
- op
->row
);
818 dc
= abs(op2
->col
- op
->col
);
820 d2
= 25*dr
*dr
+ dc
*dc
;
821 if (op2
->row
!= op
->row
&& op2
->col
!= op
->col
) d2
+= 1000;
825 if (op2
->col
>= op
->col
) d2
= -1;
828 if (op2
->row
<= op
->row
) d2
= -1;
831 if (op2
->row
>= op
->row
) d2
= -1;
833 case 'l': /* Right */
834 if (op2
->col
<= op
->col
) d2
= -1;
837 if (op2
->type
== O_DEV
) d2
= 0;
839 if (d2
< dist
) { near
= op2
; dist
= d2
; }
841 if (near
!= op
) event(E_LEAVE
, op
);
842 event(E_ENTER
, near
);
845 void m_updown(int ev
, object_t
*op
)
846 /* Move a partition table entry up or down. */
849 struct part_entry tmp
;
852 if (ev
!= ctrl('K') && ev
!= ctrl('J')) return;
853 if (op
->entry
== nil
) return;
855 i
= op
->entry
- table
;
856 if (ev
== ctrl('K')) {
860 if (i
>= NR_PARTITIONS
) return;
864 tmp
= table
[i
]; table
[i
]= table
[j
]; table
[j
]= tmp
;
865 tmpx
= existing
[i
]; existing
[i
]= existing
[j
]; existing
[j
]= tmpx
;
868 event(ev
== ctrl('K') ? 'k' : 'j', op
);
871 void m_enter(int ev
, object_t
*op
)
872 /* We've moved onto this object. */
874 if (ev
!= E_ENTER
&& ev
!= ' ' && ev
!= '<' && ev
!= '>' && ev
!= 'X')
881 void m_leave(int ev
, object_t
*op
)
882 /* About to leave this object. */
884 if (ev
!= E_LEAVE
) return;
887 int within(unsigned *var
, unsigned low
, unsigned value
, unsigned high
)
888 /* Only set *var to value if it looks reasonable. */
890 if (low
<= value
&& value
<= high
) {
897 int lwithin(unsigned long *var
, unsigned long low
, unsigned long value
,
900 if (low
<= value
&& value
<= high
) {
907 int nextdevice(object_t
*op
, int delta
)
908 /* Select the next or previous device from the device list. */
912 if (offset
!= 0) return 0;
913 if (dirty
) event(E_WRITE
, op
);
917 (void) close(device
);
925 curdev
= curdev
->prev
;
926 while (delta
< -1 && major(curdev
->rdev
) == major(rdev
)
927 && curdev
->rdev
< rdev
);
930 curdev
= curdev
->next
;
931 while (delta
> 1 && major(curdev
->rdev
) == major(rdev
)
932 && curdev
->rdev
> rdev
);
937 void check_ind(struct part_entry
*pe
)
938 /* If there are no other partitions then make this new one active. */
940 struct part_entry
*pe2
;
943 for (pe2
= table
+ 1; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++, i
++)
944 if (pe2
->sysind
!= NO_PART
&& (pe2
->bootind
& ACTIVE_FLAG
))
947 pe
->bootind
= ACTIVE_FLAG
;
951 int check_existing(struct part_entry
*pe
)
952 /* Check and if not ask if an existing partition may be modified. */
954 static int expert
= 0;
957 if (expert
|| pe
== nil
|| !existing
[pe
- table
]) return 1;
960 putstr("Do you wish to modify existing partitions? (y/n) ");
962 while ((c
= getchar()) != 'y' && c
!= 'n') {}
965 return (expert
= (c
== 'y'));
968 void m_modify(int ev
, object_t
*op
)
969 /* Increment, decrement, set, or toggle the value of an object, using
970 * arithmetic tricks the author doesn't understand either.
974 struct part_entry
*pe
= op
->entry
;
977 unsigned long surplus
;
978 int radix
= op
->type
== O_TYPHEX
? 0x10 : 10;
981 if (device
< 0 && op
->type
!= O_DEV
) return;
985 mul
= radix
; delta
= -1; typing
= 0;
988 mul
= radix
; delta
= 1; typing
= 0;
998 if ('0' <= ev
&& ev
<= '9')
1001 if (radix
== 0x10 && 'a' <= ev
&& ev
<= 'f')
1002 delta
= ev
- 'a' + 10;
1004 if (radix
== 0x10 && 'A' <= ev
&& ev
<= 'F')
1005 delta
= ev
- 'A' + 10;
1009 mul
= typing
? radix
*radix
: 0;
1014 if (!check_existing(pe
)) return;
1018 if (ev
!= '-' && ev
!= '+') return;
1019 if (!nextdevice(op
, delta
)) return;
1022 if (!within(&cylinders
, 1,
1023 cylinders
* mul
/ radix
+ delta
, 1024)) return;
1027 if (!within(&heads
, 1, heads
* mul
/ radix
+ delta
, 255))
1032 if (!within(§ors
, 1, sectors
* mul
/ radix
+ delta
, 63))
1037 if (ev
!= '-' && ev
!= '+') return;
1038 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1039 if (op2
->type
== O_NUM
&& ev
== '+')
1040 op2
->entry
->bootind
= 0;
1042 op
->entry
->bootind
= ev
== '+' ? ACTIVE_FLAG
: 0;
1046 pe
->sysind
= pe
->sysind
* mul
/ radix
+ delta
;
1049 if (ev
!= '-' && ev
!= '+') return;
1051 pe
->sysind
= round_sysind(pe
->sysind
, delta
);
1058 if (op
->type
!= O_SCYL
&& ev
!= '-' && ev
!= '+') return;
1060 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1063 if (!lwithin(&t
, 0L,
1064 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1066 if (howend
== LAST
|| op
->type
!= O_BASE
)
1067 pe
->size
-= t
- pe
->lowsec
;
1070 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1077 if (op
->type
!= O_LCYL
&& ev
!= '-' && ev
!= '+') return;
1079 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1080 t
= pe
->lowsec
+ pe
->size
- 1 + level
;
1081 surplus
= t
% level
- mul
/ radix
* level
;
1082 if (!lwithin(&t
, 0L,
1083 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1085 pe
->size
= t
- pe
->lowsec
+ 1;
1087 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1091 if (mul
== 0) pe
->size
= 0; /* new value, no surplus */
1093 if (pe
->sysind
== NO_PART
) {
1094 if (op
->type
== O_KB
|| howend
== SIZE
) {
1095 /* First let loose magic to set the base. */
1102 memset(pe
, 0, sizeof(*pe
));
1104 t
= (op
->type
== O_KB
|| howend
== SIZE
) ? pe
->size
1105 : pe
->lowsec
+ pe
->size
- 1;
1107 if (!lwithin(&t
, 0L,
1108 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1110 pe
->size
= (op
->type
== O_KB
|| howend
== SIZE
) ? t
:
1113 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1119 /* The order among the entries may have changed. */
1124 unsigned long spell
[3 + 4 * (1+NR_PARTITIONS
)];
1128 void newspell(unsigned long charm
)
1129 /* Add a new spell, descending order for the base, ascending for the size. */
1133 if (charm
- table
[0].lowsec
> table
[0].size
) return;
1135 for (i
= 0; i
< nspells
; i
++) {
1136 if (charm
== spell
[i
]) return; /* duplicate */
1138 if (touching
== O_BASE
) {
1139 if (charm
== table
[0].lowsec
+ table
[0].size
) return;
1140 if ((spell
[0] - charm
) < (spell
[0] - spell
[i
])) break;
1142 if (charm
== table
[0].lowsec
) return;
1143 if ((charm
- spell
[0]) < (spell
[i
] - spell
[0])) break;
1146 for (j
= ++nspells
; j
> i
; j
--) spell
[j
]= spell
[j
-1];
1150 void m_magic(int ev
, object_t
*op
)
1151 /* Apply magic onto a base or size number. */
1153 struct part_entry
*pe
= op
->entry
, *pe2
;
1154 int rough
= (offset
!= 0 && extbase
== 0);
1156 if (ev
!= 'm' || device
< 0) return;
1159 if (!check_existing(pe
)) return;
1162 /* See what magic we can let loose on this value. */
1165 /* First spell, the current value. */
1168 case O_SHEAD
: /* Start of partition. */
1172 spell
[0]= pe
->lowsec
;
1176 case O_LSEC
: /* End of partition. */
1180 spell
[0]= pe
->lowsec
+ pe
->size
;
1185 if (pe
->sysind
== NO_PART
) {
1186 memset(pe
, 0, sizeof(*pe
));
1188 pe
->sysind
= MINIX_PART
;
1190 if (touching
== O_SIZE
) {
1191 /* First let loose magic on the base. */
1194 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1195 if (op2
->row
== op
->row
&&
1196 op2
->type
== O_BASE
) {
1205 /* Avoid the first sector on the device. */
1206 if (spell
[0] == table
[0].lowsec
) newspell(spell
[0] + 1);
1208 /* Further interesting values are the the bases of other
1209 * partitions or their ends.
1211 for (pe2
= table
; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++) {
1212 if (pe2
== pe
|| pe2
->sysind
== NO_PART
) continue;
1213 if (pe2
->lowsec
== table
[0].lowsec
)
1214 newspell(table
[0].lowsec
+ 1);
1216 newspell(pe2
->lowsec
);
1217 newspell(pe2
->lowsec
+ pe2
->size
);
1218 if (touching
== O_BASE
&& howend
== SIZE
) {
1219 newspell(pe2
->lowsec
- pe
->size
);
1220 newspell(pe2
->lowsec
+ pe2
->size
- pe
->size
);
1222 if (pe2
->lowsec
% sectors
!= 0) rough
= 1;
1224 /* Present values rounded up to the next cylinder unless
1225 * the table is already a mess. Use "start + 1 track" instead
1226 * of "start + 1 cylinder". Also add the end of the last
1230 unsigned long n
= spell
[0];
1231 if (n
== table
[0].lowsec
) n
++;
1232 n
= (n
+ sectors
- 1) / sectors
* sectors
;
1233 if (n
!= table
[0].lowsec
+ sectors
)
1234 n
= (n
+ secpcyl
- 1) / secpcyl
* secpcyl
;
1236 if (touching
== O_SIZE
)
1237 newspell(table
[0].size
/ secpcyl
* secpcyl
);
1240 /* Magic has been applied, a spell needs to be chosen. */
1242 if (++magic
== nspells
) magic
= 0;
1244 if (touching
== O_BASE
) {
1245 if (howend
== LAST
) pe
->size
-= spell
[magic
] - pe
->lowsec
;
1246 pe
->lowsec
= spell
[magic
];
1248 pe
->size
= spell
[magic
] - pe
->lowsec
;
1250 /* The order among the entries may have changed. */
1255 typedef struct diving
{
1257 struct part_entry old0
;
1259 parttype_t oldparttype
;
1260 unsigned long oldoffset
;
1261 unsigned long oldextbase
;
1264 diving_t
*diving
= nil
;
1266 void m_in(int ev
, object_t
*op
)
1267 /* Go down into a primary or extended partition. */
1270 struct part_entry
*pe
= op
->entry
, ext
;
1273 if (ev
!= '>' || device
< 0 || pe
== nil
|| pe
== &table
[0]
1274 || (!(pe
->sysind
== MINIX_PART
&& offset
== 0)
1275 && !ext_part(pe
->sysind
))
1276 || pe
->size
== 0) return;
1279 if (extbase
!= 0) ext
.size
= extbase
+ extsize
- ext
.lowsec
;
1281 if (dirty
) event(E_WRITE
, op
);
1283 if (device
>= 0) { close(device
); device
= -1; }
1285 newdiv
= alloc(sizeof(*newdiv
));
1286 newdiv
->old0
= table
[0];
1287 newdiv
->oldsubname
= curdev
->subname
;
1288 newdiv
->oldparttype
= curdev
->parttype
;
1289 newdiv
->oldoffset
= offset
;
1290 newdiv
->oldextbase
= extbase
;
1296 n
= strlen(diving
->oldsubname
);
1297 curdev
->subname
= alloc((n
+ 3) * sizeof(curdev
->subname
[0]));
1298 strcpy(curdev
->subname
, diving
->oldsubname
);
1299 curdev
->subname
[n
++]= ':';
1300 curdev
->subname
[n
++]= '0' + (pe
- table
- 1);
1301 curdev
->subname
[n
]= 0;
1303 curdev
->parttype
= curdev
->parttype
== PRIMARY
? SUBPART
: DUNNO
;
1305 if (ext_part(ext
.sysind
) && extbase
== 0) {
1306 extbase
= ext
.lowsec
;
1308 curdev
->parttype
= DUNNO
;
1315 void m_out(int ev
, object_t
*op
)
1316 /* Go up from an extended or subpartition table to its enclosing. */
1320 if (ev
!= '<' || diving
== nil
) return;
1322 if (dirty
) event(E_WRITE
, op
);
1324 if (device
>= 0) { close(device
); device
= -1; }
1329 table
[0]= olddiv
->old0
;
1331 free(curdev
->subname
);
1332 curdev
->subname
= olddiv
->oldsubname
;
1334 curdev
->parttype
= olddiv
->oldparttype
;
1335 offset
= olddiv
->oldoffset
;
1336 extbase
= olddiv
->oldextbase
;
1341 if (diving
== nil
) submerged
= 0; /* We surfaced. */
1344 void installboot(unsigned char *bootblock
, char *masterboot
)
1345 /* Install code from a master bootstrap into a boot block. */
1348 unsigned char buf
[SECTOR_SIZE
];
1352 if ((mfp
= fopen(masterboot
, "r")) == nil
) {
1353 err
= strerror(errno
);
1357 n
= fread(buf
, sizeof(char), SECTOR_SIZE
, mfp
);
1359 err
= strerror(errno
);
1364 err
= "Is probably not a boot sector, too small";
1368 else if (n
< SECTOR_SIZE
&& n
> PART_TABLE_OFF
) {
1369 /* if only code, it cannot override partition table */
1370 err
= "Does not fit in a boot sector";
1374 else if (n
== SECTOR_SIZE
) {
1375 if (buf
[510] != 0x55 || buf
[511] != 0xaa) {
1376 err
= "Is not a boot sector (bad magic)";
1383 if (n
> PART_TABLE_OFF
) {
1384 err
= "Does not fit in a boot sector";
1389 memcpy(bootblock
, buf
, n
);
1392 /* Bootstrap installed. */
1397 printf("%s: %s", masterboot
, err
);
1401 ssize_t
boot_readwrite(int rw
)
1402 /* Read (0) or write (1) the boot sector. */
1406 if (lseek64(device
, (u64_t
) offset
* SECTOR_SIZE
, SEEK_SET
, NULL
) < 0)
1410 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1411 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1417 int cylinderalign(region_t
*reg
)
1419 if(reg
->is_used_part
) {
1420 if(reg
->used_part
.lowsec
!= table
[0].lowsec
+ sectors
1421 && (reg
->used_part
.lowsec
% secpcyl
)) {
1423 extra
= secpcyl
- (reg
->used_part
.lowsec
% secpcyl
);
1424 reg
->used_part
.lowsec
+= extra
;
1425 reg
->used_part
.size
-= extra
;
1427 if((reg
->used_part
.size
+1) % secpcyl
) {
1428 reg
->used_part
.size
-= secpcyl
- ((reg
->used_part
.size
+ 1) % secpcyl
);
1430 return reg
->used_part
.size
> 0;
1433 if(reg
->free_sec_start
!= table
[0].lowsec
+ sectors
&& (reg
->free_sec_start
% secpcyl
)) {
1434 /* Start is unaligned. Round up. */
1435 reg
->free_sec_start
+= secpcyl
- (reg
->free_sec_start
% secpcyl
);
1437 if((reg
->free_sec_last
+1) % secpcyl
) {
1438 /* End is unaligned. Round down. */
1439 reg
->free_sec_last
-= (reg
->free_sec_last
+1) % secpcyl
;
1442 /* Return nonzero if anything remains of the region after rounding. */
1443 return reg
->free_sec_last
> reg
->free_sec_start
;
1446 void regionize(void)
1448 int free_sec
, i
, si
;
1452 free_sec
= table
[0].lowsec
+ sectors
;
1454 /* Create region data used in autopart mode. */
1455 free_regions
= used_regions
= nr_regions
= nr_partitions
= 0;
1456 if(table
[0].lowsec
> table
[sort_order
[1]].lowsec
&&
1457 table
[sort_order
[1]].sysind
!= NO_PART
) {
1458 printf("\nSanity check failed on %s - first partition starts before disk.\n"
1459 "Please use expert mode to correct it.\n", curdev
->name
);
1462 for(si
= 1; si
<= NR_PARTITIONS
; si
++) {
1464 if(i
< 1 || i
> NR_PARTITIONS
) {
1465 printf("Sorry, something unexpected has happened (%d out of range).\n", i
);
1469 if(table
[i
].sysind
== NO_PART
)
1472 /* Free space before this partition? */
1473 if(table
[i
].lowsec
> free_sec
) {
1474 /* Free region before this partition. */
1475 regions
[nr_regions
].free_sec_start
= free_sec
;
1476 regions
[nr_regions
].free_sec_last
= table
[i
].lowsec
-1;
1477 regions
[nr_regions
].is_used_part
= 0;
1478 if(cylinderalign(®ions
[nr_regions
])) {
1486 if(table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
||
1487 table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
+ table
[sort_order
[si
-1]].size
) {
1488 printf("\nSanity check failed on %s - partitions overlap.\n"
1489 "Please use expert mode to correct it.\n", curdev
->name
);
1493 if(table
[i
].size
> table
[0].size
) {
1494 printf("\nSanity check failed on %s - partition is larger than disk.\n"
1495 "Please use expert mode to correct it.\n", curdev
->name
);
1498 if(table
[i
].size
< 1) {
1499 printf("\nSanity check failed on %s - zero-sized partition.\n"
1500 "Please use expert mode to correct it.\n", curdev
->name
);
1504 /* Remember used region. */
1505 memcpy(®ions
[nr_regions
].used_part
, &table
[i
], sizeof(table
[i
]));
1506 free_sec
= table
[i
].lowsec
+table
[i
].size
;
1507 regions
[nr_regions
].is_used_part
= 1;
1508 regions
[nr_regions
].tableno
= i
;
1514 /* Special case: space after partitions. */
1515 if(free_sec
< table
[0].lowsec
+ table
[0].size
-1) {
1516 regions
[nr_regions
].free_sec_start
= free_sec
;
1517 regions
[nr_regions
].free_sec_last
= table
[0].lowsec
+ table
[0].size
-1;
1518 regions
[nr_regions
].is_used_part
= 0;
1519 if(cylinderalign(®ions
[nr_regions
])) {
1527 void m_read(int ev
, int *biosdrive
)
1528 /* Read the partition table from the current device. */
1531 struct part_entry
*pe
;
1534 if (ev
!= 'r' || device
>= 0) return;
1536 /* Open() may cause kernel messages: */
1540 if ((device
= open(curdev
->name
, mode
= O_RDWR
, 0666)) < 0) {
1541 if (device
>= 0) { close(device
); device
= -1; }
1545 system_hz
= (u32_t
) sysconf(_SC_CLK_TCK
);
1547 ioctl(device
, DIOCTIMEOUT
, &v
);
1549 memset(bootblock
, 0, sizeof(bootblock
));
1551 n
= boot_readwrite(0);
1553 if (n
<= 0) stat_start(1);
1558 if (n
< SECTOR_SIZE
) {
1563 if (n
<= 0) stat_end(5);
1565 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1567 if(biosdrive
) (*biosdrive
)++;
1569 if(!open_ct_ok(device
)) {
1570 printf("\n%s: device in use! skipping it.", curdev
->subname
);
1577 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1578 NR_PARTITIONS
* sizeof(table
[1]));
1579 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1580 /* Invalid boot block, install bootstrap, wipe partition table.
1582 memset(bootblock
, 0, sizeof(bootblock
));
1583 installboot(bootblock
, MASTERBOOT
);
1584 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1587 /* Fix an extended partition table up to something mere mortals can
1588 * understand. Record already defined partitions.
1590 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1592 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1593 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1594 existing
[i
]= pe
->sysind
!= NO_PART
;
1599 /* Warn about grave dangers ahead. */
1602 printf("Warning: You are in an extended partition.");
1609 void m_write(int ev
, object_t
*op
)
1610 /* Write the partition table back if modified. */
1612 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1614 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1615 if (device
< 0) { dirty
= 0; return; }
1619 printf("%s is not changed, or has already been written",
1627 /* Will this stop him? Probably not... */
1629 printf("You have changed an extended partition. Bad Idea.");
1633 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1634 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1635 if (pe
->sysind
== NO_PART
) {
1636 memset(pe
, 0, sizeof(*pe
));
1638 abs2dos(&pe
->start_head
, pe
->lowsec
);
1639 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1641 /* Fear and loathing time: */
1643 pe
->lowsec
-= ext_part(pe
->sysind
)
1647 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1648 bootblock
[510]= 0x55;
1649 bootblock
[511]= 0xAA;
1651 if (boot_readwrite(1) < 0) {
1653 printf("%s: %s", curdev
->name
, strerror(errno
));
1660 void m_shell(int ev
, object_t
*op
)
1661 /* Shell escape, to do calculations for instance. */
1664 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1666 if (ev
!= 's') return;
1671 switch (pid
= fork()) {
1674 printf("can't fork: %s\n", strerror(errno
));
1678 if (device
>= 0) (void) close(device
);
1679 execl("/bin/sh", "sh", (char *) nil
);
1682 printf("/bin/sh: %s\n", strerror(errno
));
1686 sigint
= signal(SIGINT
, SIG_IGN
);
1687 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1688 sigterm
= signal(SIGTERM
, SIG_IGN
);
1689 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1690 (void) signal(SIGINT
, sigint
);
1691 (void) signal(SIGQUIT
, sigquit
);
1692 (void) signal(SIGTERM
, sigterm
);
1697 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1698 stat_start(0); /* Match the stat_start in the child. */
1700 event(ctrl('L'), op
);
1705 void m_quit(int ev
, object_t
*op
)
1706 /* Write the partition table if modified and exit. */
1708 if (ev
!= 'q' && ev
!= 'x') return;
1712 if (dirty
) event(E_WRITE
, op
);
1713 if (dirty
) quitting
= 0;
1716 void m_help(int ev
, object_t
*op
)
1717 /* For people without a clue; let's hope they can find the '?' key. */
1719 static struct help
{
1723 { "? !", "This help / more advice!" },
1724 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1725 { "0-9 (a-f)", "Enter value" },
1726 { "hjkl (arrow keys)", "Move around" },
1727 { "CTRL-K CTRL-J", "Move entry up/down" },
1728 { "CTRL-L", "Redraw screen" },
1729 { ">", "Start a subpartition table" },
1730 { "<", "Back to the primary partition table" },
1731 { "m", "Cycle through magic values" },
1732 { "spacebar", "Show \"Size\" or \"Last\"" },
1733 { "r w", "Read/write partition table" },
1734 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1735 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1737 static char *advice
[] = {
1738 "* Choose a disk with '+' and '-', then hit 'r'.",
1739 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1740 "* To make a new partition: Move over to the Size or Kb field of an unused",
1741 " partition and type the size. Hit the 'm' key to pad the partition out to",
1742 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1743 " You can hit 'm' more than once on a base or size field to see several",
1744 " interesting values go by. Note: Other Operating Systems can be picky about",
1745 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1746 " head or sector numbers.",
1747 "* To reuse a partition: Change the type to MINIX.",
1748 "* To delete a partition: Type a zero in the hex Type field.",
1749 "* To make a partition active: Type '+' in the Num field.",
1750 "* To study the list of keys: Type '?'.",
1756 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1758 printf("%-25s - %s", hp
->keys
, hp
->what
);
1762 putstr("Things like ");
1763 putstr(t_so
); putstr("this"); putstr(t_se
);
1764 putstr(" must be checked, but ");
1765 putstr(t_md
); putstr("this"); putstr(t_me
);
1766 putstr(" is not really a problem");
1772 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1780 void event(int ev
, object_t
*op
)
1781 /* Simply call all modifiers for an event, each one knows when to act. */
1786 m_orientation(ev
, op
);
1802 prettysizeprint(int kb
)
1805 static char str
[200];
1807 if(MIN_REGION_SECTORS
> kb
*2)
1817 sprintf(str
, "%4d %cB%s", kb
, unit
,
1818 toosmall
? ", too small for MINIX 3" : "");
1823 printregions(region_t
*theregions
, int indent
, int p_nr_partitions
, int p_free_regions
, int p_nr_regions
, int numbers
)
1829 if((p_nr_partitions
>= NR_PARTITIONS
|| !p_free_regions
) && p_free_regions
)
1831 for(r
= 0; r
< p_nr_regions
; r
++, reg
++) {
1832 unsigned long units
;
1833 if(reg
->is_used_part
) {
1835 name
= typ2txt(reg
->used_part
.sysind
);
1836 printf("%*s", indent
, ""); type2col(reg
->used_part
.sysind
);
1837 if(numbers
) printf("[%d] ", r
);
1838 printf("In use by %-10s ", name
);
1839 units
= reg
->used_part
.size
/ 2;
1841 printf(" (%s)\n", prettysizeprint(units
));
1843 printf("%*s", indent
, "");
1845 if(!nofree
) printf("[%d] ", r
);
1846 else printf("[-] ");
1848 printf("Free space ");
1849 units
= ((reg
->free_sec_last
- reg
->free_sec_start
+1))/2;
1850 printf(" (%s)\n", prettysizeprint(units
));
1854 if(numbers
&& p_nr_partitions
>= NR_PARTITIONS
&& p_free_regions
) {
1856 "\nNote: there is free space on this disk, but you can't select it,\n"
1857 "because there isn't a free slot in the partition table to use it.\n"
1858 "You can reclaim the free space by deleting an adjacent region.\n");
1868 is_sure(char *fmt
, ...)
1875 printf(" Please enter 'yes' or 'no': ");
1877 if(!fgets(yesno
, sizeof(yesno
)-1, stdin
)) exit(1);
1879 if (strcmp(yesno
, "yes\n") == 0) return(IS_YES
);
1880 if (strcmp(yesno
, "no\n") == 0) return(IS_NO
);
1884 void warn(char *message
)
1886 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
);
1890 may_kill_region(void)
1896 if(used_regions
< 1) return 1;
1898 printf("\n -- Delete in-use region? --\n\n");
1900 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1901 printf("\nEnter the region number to delete or ENTER to continue: ");
1903 fgets(line
, sizeof(line
)-2, stdin
);
1904 if(!isdigit(line
[0]))
1908 if(r
< 0 || r
>= nr_regions
) {
1909 printf("This choice is out of range.\n");
1913 if(!regions
[r
].is_used_part
) {
1914 printf("This region is not in use.\n");
1918 i
= regions
[r
].tableno
;
1920 printf("\nPlease confirm that you want to delete region %d, losing all data it", r
);
1921 printf("\ncontains. You're disk is not actually updated right away, but still.");
1925 confirmation
= is_sure("Are you sure you want to continue?");
1926 if (confirmation
== IS_NO
) return 0;
1927 } while (confirmation
!= IS_YES
);
1929 table
[i
].sysind
= NO_PART
;
1933 /* User may go again. */
1942 static char line
[100];
1945 printstep(2, "Select a disk region");
1947 if(nr_regions
< 1) {
1948 printf("\nNo regions found - maybe the drive is too small.\n"
1949 "Please try expert mode.\n");
1953 if(nr_partitions
>= NR_PARTITIONS
|| !free_regions
) {
1960 printf("\nPlease select the region that you want to use for the MINIX 3 setup.");
1961 printf("\nIf you select an in-use region it will be overwritten by MINIX. The");
1962 printf("\nfollowing region%s were found on the selected disk:\n\n",
1963 SORNOT(nr_regions
));
1964 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1969 printf("Enter the region number to use or type 'delete': ");
1970 if(nr_regions
== 1) printf(" [0] ");
1973 if(!fgets(line
, sizeof(line
)-2, stdin
))
1976 if (nr_regions
== 1 && line
[0] == '\n') {
1981 if(strcmp(line
,"delete\n") == 0) {
1986 if(sscanf(line
, "%d", &rn
) != 1) {
1987 warn("invalid choice");
1991 if(rn
< 0 || rn
>= nr_regions
) {
1992 warn("out of range");
1996 if(nofree
&& !regions
[rn
].is_used_part
) {
1997 warn("not available");
2005 return(®ions
[rn
]);
2008 void printstep(int step
, char *str
)
2011 n
= printf("\n --- Substep 3.%d: %s ---", step
, str
);
2012 while(n
++ < 73) printf("-");
2020 int i
, choice
, drives
;
2021 static char line
[500];
2024 printstep(1, "Select a disk to install MINIX 3");
2025 printf("\nProbing for disks. This may take a short while.");
2030 for(; i
< MAX_DEVICES
;) {
2033 m_read('r', &biosdrive
);
2035 devices
[i
].dev
= curdev
;
2036 devices
[i
].free_regions
= free_regions
;
2037 devices
[i
].nr_regions
= nr_regions
;
2038 devices
[i
].nr_partitions
= nr_partitions
;
2039 devices
[i
].used_regions
= used_regions
;
2040 devices
[i
].sectors
= table
[0].size
;
2041 curdev
->biosdrive
= biosdrive
-1;
2042 memcpy(devices
[i
].regions
, regions
, sizeof(regions
));
2046 nextdevice(NULL
, 1);
2047 if(curdev
== firstdev
)
2054 printf("\nFound no drives - can't partition.\n");
2058 printf(" Probing done.\n");
2059 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives
),
2060 drives
== 1 ? "was" : "were");
2062 for(i
= 0; i
< drives
; i
++) {
2064 printf("Disk [%d]: ", i
);
2065 printf("%s, ", devices
[i
].dev
->name
);
2066 printf("%s\n", prettysizeprint(devices
[i
].sectors
/2));
2067 printregions(devices
[i
].regions
, 8,
2068 devices
[i
].nr_partitions
,
2069 devices
[i
].free_regions
,
2070 devices
[i
].nr_regions
, 0);
2075 printf("Enter the disk number to use: ");
2076 if (drives
== 1) printf("[0] ");
2078 if(!fgets(line
, sizeof(line
)-2, stdin
))
2080 if (line
[0] == '\n' && drives
== 1) {
2084 if(sscanf(line
, "%d", &choice
) != 1) {
2085 warn("choose a disk");
2088 if(choice
< 0 || choice
>= i
) {
2089 warn("out of range");
2095 return devices
[choice
].dev
;
2099 scribble_region(region_t
*reg
, struct part_entry
**pe
, int *made_new
)
2101 int ex
, changed
= 0, i
;
2102 struct part_entry
*newpart
;
2103 if(!reg
->is_used_part
) {
2104 ex
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2105 if(made_new
) *made_new
= 1;
2106 } else if(made_new
) *made_new
= 0;
2107 if(!reg
->is_used_part
) {
2108 for(i
= 1; i
<= NR_PARTITIONS
; i
++)
2109 if(table
[i
].sysind
== NO_PART
)
2111 if(i
> NR_PARTITIONS
) {
2112 /* Bug, should've been caught earlier. */
2113 printf("Couldn't find a free slot. Please try expert mode.\n");
2116 newpart
= &table
[i
];
2117 newpart
->lowsec
= reg
->free_sec_start
;
2118 newpart
->size
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2120 newpart
->sysind
= MINIX_PART
;
2122 newpart
= ®
->used_part
;
2131 sanitycheck_failed(char *dev
, struct part_entry
*pe
)
2133 struct partition part
;
2135 unsigned long it_lowsec
, it_secsize
;
2137 if((fd
= open(dev
, O_RDONLY
)) < 0) {
2142 if (ioctl(fd
, DIOCGETP
, &part
) < 0) {
2143 fprintf(stderr
, "DIOCGETP failed\n");
2148 if(!open_ct_ok(fd
)) {
2149 printf("\nAutopart error: the disk is in use. This means that although a\n"
2150 "new table has been written, it won't be in use by the system\n"
2151 "until it's no longer in use (or a reboot is done). Just in case,\n"
2152 "I'm not going to continue. Please un-use the disk (or reboot) and try\n"
2159 it_lowsec
= div64u(part
.base
, SECTOR_SIZE
);
2160 it_secsize
= div64u(part
.size
, SECTOR_SIZE
);
2162 if(it_lowsec
!= pe
->lowsec
|| it_secsize
!= pe
->size
) {
2163 fprintf(stderr
, "\nReturned and set numbers don't match up!\n");
2164 fprintf(stderr
, "This can happen if the disk is still opened.\n");
2172 do_autopart(int resultfd
)
2176 struct part_entry
*pe
;
2177 struct part_entry orig_table
[1 + NR_PARTITIONS
];
2183 curdev
= select_disk();
2194 memcpy(orig_table
, table
, sizeof(table
));
2198 r
= select_region();
2199 } while(!r
); /* Back to step 2. */
2202 if(scribble_region(r
, &pe
, &newp
)) {
2205 char partbuf
[100], devname
[100];
2206 struct part_entry
*tpe
= NULL
;
2208 printstep(3, "Confirm your choices");
2210 region
= (int)(r
-regions
);
2211 /* disk = (int) (curdev-devices); */
2213 printf("\nThis is the point of no return. You have selected to install MINIX 3\n");
2214 printf("into region %d of disk %s. Please confirm that you want\n",
2215 region
, curdev
->name
);
2216 printf("to use this selection to install MINIX 3.\n\n");
2219 confirmation
= is_sure("Are you sure you want to continue?");
2220 if (confirmation
== IS_NO
) return 1;
2221 } while (confirmation
!= IS_YES
);
2223 /* Retrieve partition number in sorted order that we
2224 * have scribbled in.
2227 for(i
= 1; i
<= NR_PARTITIONS
; i
++) {
2230 if(si
< 1 || si
> NR_PARTITIONS
) {
2231 fprintf(stderr
, "Autopart internal error (out of range) (nothing written).\n");
2234 if(table
[si
].lowsec
== pe
->lowsec
) {
2236 fprintf(stderr
, "Autopart internal error (part found twice) (nothing written).\n");
2239 check_ind(&table
[si
]);
2240 table
[si
].sysind
= MINIX_PART
;
2246 fprintf(stderr
, "Autopart internal error (part not found) (nothing written).\n");
2251 fprintf(stderr
, "Autopart internal error (couldn't update disk).\n");
2254 name
=strrchr(curdev
->name
, '/');
2255 if(!name
) name
= curdev
->name
;
2258 sprintf(partbuf
, "%sp%d d%dp%d\n", name
, found
-1,
2259 curdev
->biosdrive
, found
-1);
2260 sprintf(devname
, "/dev/%sp%d", name
, found
-1);
2261 if(resultfd
>= 0 && write(resultfd
, partbuf
, strlen(partbuf
)) < strlen(partbuf
)) {
2262 fprintf(stderr
, "Autopart internal error (couldn't write result).\n");
2276 if(sanitycheck_failed(devname
, tpe
)) {
2277 fprintf(stderr
, "Autopart internal error (disk sanity check failed).\n");
2283 if((fd
=open(devname
, O_WRONLY
)) < 0) {
2286 /* Clear any subpartitioning. */
2287 static unsigned char sub
[2048];
2290 write(fd
, sub
, sizeof(sub
));
2300 int main(int argc
, char **argv
)
2306 /* autopart uses getopt() */
2307 while((c
= getopt(argc
, argv
, "m:f:")) != EOF
) {
2310 min_region_mb
= atoi(optarg
);
2313 /* Make sure old data file is gone. */
2315 if((resultfd
=open(optarg
, O_CREAT
| O_WRONLY
| O_TRUNC
)) < 0) {
2319 sync(); /* Make sure no old data file lingers. */
2322 fprintf(stderr
, "Unknown option\n");
2330 for (i
= 0; i
< argc
; i
++) {
2331 newdevice(argv
[i
], 0, 0);
2334 if (firstdev
== nil
) {
2343 if (firstdev
== nil
) {
2344 fprintf(stderr
, "autopart couldn't find any devices.\n");
2347 r
= do_autopart(resultfd
);
2348 if(resultfd
>= 0) { close(resultfd
); }