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 char 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. */
1404 u64_t off64
= mul64u(offset
, SECTOR_SIZE
);
1408 /* Minix-vmd has a 64 bit seek. */
1409 if (fcntl(device
, F_SEEK
, off64
) < 0) return -1;
1411 /* Minix has to gross things with the partition base. */
1412 struct partition geom0
, geom_seek
;
1414 if (offset
>= (LONG_MAX
/ SECTOR_SIZE
- 1)) {
1415 /* Move partition base. */
1416 if (ioctl(device
, DIOCGETP
, &geom0
) < 0) return -1;
1417 geom_seek
.base
= add64(geom0
.base
, off64
);
1418 geom_seek
.size
= cvu64(cmp64(add64u(off64
, SECTOR_SIZE
),
1419 geom0
.size
) <= 0 ? _STATIC_BLOCK_SIZE
: 0);
1421 if (ioctl(device
, DIOCSETP
, &geom_seek
) < 0) return -1;
1422 if (lseek(device
, (off_t
) 0, SEEK_SET
) == -1) return -1;
1424 /* Can reach this point normally. */
1425 if (lseek(device
, (off_t
) offset
* SECTOR_SIZE
, SEEK_SET
) == -1)
1431 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1432 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1436 if (offset
>= (LONG_MAX
/ SECTOR_SIZE
- 1)) {
1437 /* Restore partition base and size. */
1439 if (ioctl(device
, DIOCSETP
, &geom0
) < 0) return -1;
1445 int cylinderalign(region_t
*reg
)
1447 if(reg
->is_used_part
) {
1448 if(reg
->used_part
.lowsec
!= table
[0].lowsec
+ sectors
1449 && (reg
->used_part
.lowsec
% secpcyl
)) {
1451 extra
= secpcyl
- (reg
->used_part
.lowsec
% secpcyl
);
1452 reg
->used_part
.lowsec
+= extra
;
1453 reg
->used_part
.size
-= extra
;
1455 if((reg
->used_part
.size
+1) % secpcyl
) {
1456 reg
->used_part
.size
-= secpcyl
- ((reg
->used_part
.size
+ 1) % secpcyl
);
1458 return reg
->used_part
.size
> 0;
1461 if(reg
->free_sec_start
!= table
[0].lowsec
+ sectors
&& (reg
->free_sec_start
% secpcyl
)) {
1462 /* Start is unaligned. Round up. */
1463 reg
->free_sec_start
+= secpcyl
- (reg
->free_sec_start
% secpcyl
);
1465 if((reg
->free_sec_last
+1) % secpcyl
) {
1466 /* End is unaligned. Round down. */
1467 reg
->free_sec_last
-= (reg
->free_sec_last
+1) % secpcyl
;
1470 /* Return nonzero if anything remains of the region after rounding. */
1471 return reg
->free_sec_last
> reg
->free_sec_start
;
1474 void regionize(void)
1476 int free_sec
, i
, si
;
1480 free_sec
= table
[0].lowsec
+ sectors
;
1482 /* Create region data used in autopart mode. */
1483 free_regions
= used_regions
= nr_regions
= nr_partitions
= 0;
1484 if(table
[0].lowsec
> table
[sort_order
[1]].lowsec
&&
1485 table
[sort_order
[1]].sysind
!= NO_PART
) {
1486 printf("\nSanity check failed on %s - first partition starts before disk.\n"
1487 "Please use expert mode to correct it.\n", curdev
->name
);
1490 for(si
= 1; si
<= NR_PARTITIONS
; si
++) {
1492 if(i
< 1 || i
> NR_PARTITIONS
) {
1493 printf("Sorry, something unexpected has happened (%d out of range).\n", i
);
1497 if(table
[i
].sysind
== NO_PART
)
1500 /* Free space before this partition? */
1501 if(table
[i
].lowsec
> free_sec
) {
1502 /* Free region before this partition. */
1503 regions
[nr_regions
].free_sec_start
= free_sec
;
1504 regions
[nr_regions
].free_sec_last
= table
[i
].lowsec
-1;
1505 regions
[nr_regions
].is_used_part
= 0;
1506 if(cylinderalign(®ions
[nr_regions
])) {
1514 if(table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
||
1515 table
[i
].lowsec
< table
[sort_order
[si
-1]].lowsec
+ table
[sort_order
[si
-1]].size
) {
1516 printf("\nSanity check failed on %s - partitions overlap.\n"
1517 "Please use expert mode to correct it.\n", curdev
->name
);
1521 if(table
[i
].size
> table
[0].size
) {
1522 printf("\nSanity check failed on %s - partition is larger than disk.\n"
1523 "Please use expert mode to correct it.\n", curdev
->name
);
1526 if(table
[i
].size
< 1) {
1527 printf("\nSanity check failed on %s - zero-sized partition.\n"
1528 "Please use expert mode to correct it.\n", curdev
->name
);
1532 /* Remember used region. */
1533 memcpy(®ions
[nr_regions
].used_part
, &table
[i
], sizeof(table
[i
]));
1534 free_sec
= table
[i
].lowsec
+table
[i
].size
;
1535 regions
[nr_regions
].is_used_part
= 1;
1536 regions
[nr_regions
].tableno
= i
;
1542 /* Special case: space after partitions. */
1543 if(free_sec
< table
[0].lowsec
+ table
[0].size
-1) {
1544 regions
[nr_regions
].free_sec_start
= free_sec
;
1545 regions
[nr_regions
].free_sec_last
= table
[0].lowsec
+ table
[0].size
-1;
1546 regions
[nr_regions
].is_used_part
= 0;
1547 if(cylinderalign(®ions
[nr_regions
])) {
1555 void m_read(int ev
, int *biosdrive
)
1556 /* Read the partition table from the current device. */
1559 struct part_entry
*pe
;
1562 if (ev
!= 'r' || device
>= 0) return;
1564 /* Open() may cause kernel messages: */
1568 if ((device
= open(curdev
->name
, mode
= O_RDWR
, 0666)) < 0) {
1569 if (device
>= 0) { close(device
); device
= -1; }
1573 system_hz
= (u32_t
) sysconf(_SC_CLK_TCK
);
1575 ioctl(device
, DIOCTIMEOUT
, &v
);
1577 memset(bootblock
, 0, sizeof(bootblock
));
1579 n
= boot_readwrite(0);
1581 if (n
<= 0) stat_start(1);
1586 if (n
< SECTOR_SIZE
) {
1591 if (n
<= 0) stat_end(5);
1593 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1595 if(biosdrive
) (*biosdrive
)++;
1597 if(!open_ct_ok(device
)) {
1598 printf("\n%s: device in use! skipping it.", curdev
->subname
);
1605 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1606 NR_PARTITIONS
* sizeof(table
[1]));
1607 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1608 /* Invalid boot block, install bootstrap, wipe partition table.
1610 memset(bootblock
, 0, sizeof(bootblock
));
1611 installboot(bootblock
, MASTERBOOT
);
1612 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1615 /* Fix an extended partition table up to something mere mortals can
1616 * understand. Record already defined partitions.
1618 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1620 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1621 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1622 existing
[i
]= pe
->sysind
!= NO_PART
;
1627 /* Warn about grave dangers ahead. */
1630 printf("Warning: You are in an extended partition.");
1637 void m_write(int ev
, object_t
*op
)
1638 /* Write the partition table back if modified. */
1640 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1642 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1643 if (device
< 0) { dirty
= 0; return; }
1647 printf("%s is not changed, or has already been written",
1655 /* Will this stop him? Probably not... */
1657 printf("You have changed an extended partition. Bad Idea.");
1661 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1662 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1663 if (pe
->sysind
== NO_PART
) {
1664 memset(pe
, 0, sizeof(*pe
));
1666 abs2dos(&pe
->start_head
, pe
->lowsec
);
1667 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1669 /* Fear and loathing time: */
1671 pe
->lowsec
-= ext_part(pe
->sysind
)
1675 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1676 bootblock
[510]= 0x55;
1677 bootblock
[511]= 0xAA;
1679 if (boot_readwrite(1) < 0) {
1681 printf("%s: %s", curdev
->name
, strerror(errno
));
1688 void m_shell(int ev
, object_t
*op
)
1689 /* Shell escape, to do calculations for instance. */
1692 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1694 if (ev
!= 's') return;
1699 switch (pid
= fork()) {
1702 printf("can't fork: %s\n", strerror(errno
));
1706 if (device
>= 0) (void) close(device
);
1707 execl("/bin/sh", "sh", (char *) nil
);
1710 printf("/bin/sh: %s\n", strerror(errno
));
1714 sigint
= signal(SIGINT
, SIG_IGN
);
1715 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1716 sigterm
= signal(SIGTERM
, SIG_IGN
);
1717 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1718 (void) signal(SIGINT
, sigint
);
1719 (void) signal(SIGQUIT
, sigquit
);
1720 (void) signal(SIGTERM
, sigterm
);
1725 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1726 stat_start(0); /* Match the stat_start in the child. */
1728 event(ctrl('L'), op
);
1733 void m_quit(int ev
, object_t
*op
)
1734 /* Write the partition table if modified and exit. */
1736 if (ev
!= 'q' && ev
!= 'x') return;
1740 if (dirty
) event(E_WRITE
, op
);
1741 if (dirty
) quitting
= 0;
1744 void m_help(int ev
, object_t
*op
)
1745 /* For people without a clue; let's hope they can find the '?' key. */
1747 static struct help
{
1751 { "? !", "This help / more advice!" },
1752 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1753 { "0-9 (a-f)", "Enter value" },
1754 { "hjkl (arrow keys)", "Move around" },
1755 { "CTRL-K CTRL-J", "Move entry up/down" },
1756 { "CTRL-L", "Redraw screen" },
1757 { ">", "Start a subpartition table" },
1758 { "<", "Back to the primary partition table" },
1759 { "m", "Cycle through magic values" },
1760 { "spacebar", "Show \"Size\" or \"Last\"" },
1761 { "r w", "Read/write partition table" },
1762 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1763 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1765 static char *advice
[] = {
1766 "* Choose a disk with '+' and '-', then hit 'r'.",
1767 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1768 "* To make a new partition: Move over to the Size or Kb field of an unused",
1769 " partition and type the size. Hit the 'm' key to pad the partition out to",
1770 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1771 " You can hit 'm' more than once on a base or size field to see several",
1772 " interesting values go by. Note: Other Operating Systems can be picky about",
1773 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1774 " head or sector numbers.",
1775 "* To reuse a partition: Change the type to MINIX.",
1776 "* To delete a partition: Type a zero in the hex Type field.",
1777 "* To make a partition active: Type '+' in the Num field.",
1778 "* To study the list of keys: Type '?'.",
1784 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1786 printf("%-25s - %s", hp
->keys
, hp
->what
);
1790 putstr("Things like ");
1791 putstr(t_so
); putstr("this"); putstr(t_se
);
1792 putstr(" must be checked, but ");
1793 putstr(t_md
); putstr("this"); putstr(t_me
);
1794 putstr(" is not really a problem");
1800 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1808 void event(int ev
, object_t
*op
)
1809 /* Simply call all modifiers for an event, each one knows when to act. */
1814 m_orientation(ev
, op
);
1830 prettysizeprint(int kb
)
1833 static char str
[200];
1835 if(MIN_REGION_SECTORS
> kb
*2)
1845 sprintf(str
, "%4d %cB%s", kb
, unit
,
1846 toosmall
? ", too small for MINIX 3" : "");
1851 printregions(region_t
*theregions
, int indent
, int p_nr_partitions
, int p_free_regions
, int p_nr_regions
, int numbers
)
1857 if((p_nr_partitions
>= NR_PARTITIONS
|| !p_free_regions
) && p_free_regions
)
1859 for(r
= 0; r
< p_nr_regions
; r
++, reg
++) {
1860 unsigned long units
;
1861 if(reg
->is_used_part
) {
1863 name
= typ2txt(reg
->used_part
.sysind
);
1864 printf("%*s", indent
, ""); type2col(reg
->used_part
.sysind
);
1865 if(numbers
) printf("[%d] ", r
);
1866 printf("In use by %-10s ", name
);
1867 units
= reg
->used_part
.size
/ 2;
1869 printf(" (%s)\n", prettysizeprint(units
));
1871 printf("%*s", indent
, "");
1873 if(!nofree
) printf("[%d] ", r
);
1874 else printf("[-] ");
1876 printf("Free space ");
1877 units
= ((reg
->free_sec_last
- reg
->free_sec_start
+1))/2;
1878 printf(" (%s)\n", prettysizeprint(units
));
1882 if(numbers
&& p_nr_partitions
>= NR_PARTITIONS
&& p_free_regions
) {
1884 "\nNote: there is free space on this disk, but you can't select it,\n"
1885 "because there isn't a free slot in the partition table to use it.\n"
1886 "You can reclaim the free space by deleting an adjacent region.\n");
1896 is_sure(char *fmt
, ...)
1903 printf(" Please enter 'yes' or 'no': ");
1905 if(!fgets(yesno
, sizeof(yesno
)-1, stdin
)) exit(1);
1907 if (strcmp(yesno
, "yes\n") == 0) return(IS_YES
);
1908 if (strcmp(yesno
, "no\n") == 0) return(IS_NO
);
1912 void warn(char *message
)
1914 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
);
1918 may_kill_region(void)
1924 if(used_regions
< 1) return 1;
1926 printf("\n -- Delete in-use region? --\n\n");
1928 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1929 printf("\nEnter the region number to delete or ENTER to continue: ");
1931 fgets(line
, sizeof(line
)-2, stdin
);
1932 if(!isdigit(line
[0]))
1936 if(r
< 0 || r
>= nr_regions
) {
1937 printf("This choice is out of range.\n");
1941 if(!regions
[r
].is_used_part
) {
1942 printf("This region is not in use.\n");
1946 i
= regions
[r
].tableno
;
1948 printf("\nPlease confirm that you want to delete region %d, losing all data it", r
);
1949 printf("\ncontains. You're disk is not actually updated right away, but still.");
1953 confirmation
= is_sure("Are you sure you want to continue?");
1954 if (confirmation
== IS_NO
) return 0;
1955 } while (confirmation
!= IS_YES
);
1957 table
[i
].sysind
= NO_PART
;
1961 /* User may go again. */
1970 static char line
[100];
1973 printstep(2, "Select a disk region");
1975 if(nr_regions
< 1) {
1976 printf("\nNo regions found - maybe the drive is too small.\n"
1977 "Please try expert mode.\n");
1981 if(nr_partitions
>= NR_PARTITIONS
|| !free_regions
) {
1988 printf("\nPlease select the region that you want to use for the MINIX 3 setup.");
1989 printf("\nIf you select an in-use region it will be overwritten by MINIX. The");
1990 printf("\nfollowing region%s were found on the selected disk:\n\n",
1991 SORNOT(nr_regions
));
1992 printregions(regions
, 3, nr_partitions
, free_regions
, nr_regions
, 1);
1997 printf("Enter the region number to use or type 'delete': ");
1998 if(nr_regions
== 1) printf(" [0] ");
2001 if(!fgets(line
, sizeof(line
)-2, stdin
))
2004 if (nr_regions
== 1 && line
[0] == '\n') {
2009 if(strcmp(line
,"delete\n") == 0) {
2014 if(sscanf(line
, "%d", &rn
) != 1) {
2015 warn("invalid choice");
2019 if(rn
< 0 || rn
>= nr_regions
) {
2020 warn("out of range");
2024 if(nofree
&& !regions
[rn
].is_used_part
) {
2025 warn("not available");
2033 return(®ions
[rn
]);
2036 void printstep(int step
, char *str
)
2039 n
= printf("\n --- Substep 3.%d: %s ---", step
, str
);
2040 while(n
++ < 73) printf("-");
2048 int i
, choice
, drives
;
2049 static char line
[500];
2052 printstep(1, "Select a disk to install MINIX 3");
2053 printf("\nProbing for disks. This may take a short while.");
2058 for(; i
< MAX_DEVICES
;) {
2061 m_read('r', &biosdrive
);
2063 devices
[i
].dev
= curdev
;
2064 devices
[i
].free_regions
= free_regions
;
2065 devices
[i
].nr_regions
= nr_regions
;
2066 devices
[i
].nr_partitions
= nr_partitions
;
2067 devices
[i
].used_regions
= used_regions
;
2068 devices
[i
].sectors
= table
[0].size
;
2069 curdev
->biosdrive
= biosdrive
-1;
2070 memcpy(devices
[i
].regions
, regions
, sizeof(regions
));
2074 nextdevice(NULL
, 1);
2075 if(curdev
== firstdev
)
2082 printf("\nFound no drives - can't partition.\n");
2086 printf(" Probing done.\n");
2087 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives
),
2088 drives
== 1 ? "was" : "were");
2090 for(i
= 0; i
< drives
; i
++) {
2092 printf("Disk [%d]: ", i
);
2093 printf("%s, ", devices
[i
].dev
->name
);
2094 printf("%s\n", prettysizeprint(devices
[i
].sectors
/2));
2095 printregions(devices
[i
].regions
, 8,
2096 devices
[i
].nr_partitions
,
2097 devices
[i
].free_regions
,
2098 devices
[i
].nr_regions
, 0);
2103 printf("Enter the disk number to use: ");
2104 if (drives
== 1) printf("[0] ");
2106 if(!fgets(line
, sizeof(line
)-2, stdin
))
2108 if (line
[0] == '\n' && drives
== 1) {
2112 if(sscanf(line
, "%d", &choice
) != 1) {
2113 warn("choose a disk");
2116 if(choice
< 0 || choice
>= i
) {
2117 warn("out of range");
2123 return devices
[choice
].dev
;
2127 scribble_region(region_t
*reg
, struct part_entry
**pe
, int *made_new
)
2129 int ex
, changed
= 0, i
;
2130 struct part_entry
*newpart
;
2131 if(!reg
->is_used_part
) {
2132 ex
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2133 if(made_new
) *made_new
= 1;
2134 } else if(made_new
) *made_new
= 0;
2135 if(!reg
->is_used_part
) {
2136 for(i
= 1; i
<= NR_PARTITIONS
; i
++)
2137 if(table
[i
].sysind
== NO_PART
)
2139 if(i
> NR_PARTITIONS
) {
2140 /* Bug, should've been caught earlier. */
2141 printf("Couldn't find a free slot. Please try expert mode.\n");
2144 newpart
= &table
[i
];
2145 newpart
->lowsec
= reg
->free_sec_start
;
2146 newpart
->size
= reg
->free_sec_last
- reg
->free_sec_start
+ 1;
2148 newpart
->sysind
= MINIX_PART
;
2150 newpart
= ®
->used_part
;
2159 sanitycheck_failed(char *dev
, struct part_entry
*pe
)
2161 struct partition part
;
2163 unsigned long it_lowsec
, it_secsize
;
2165 if((fd
= open(dev
, O_RDONLY
)) < 0) {
2170 if (ioctl(fd
, DIOCGETP
, &part
) < 0) {
2171 fprintf(stderr
, "DIOCGETP failed\n");
2176 if(!open_ct_ok(fd
)) {
2177 printf("\nAutopart error: the disk is in use. This means that although a\n"
2178 "new table has been written, it won't be in use by the system\n"
2179 "until it's no longer in use (or a reboot is done). Just in case,\n"
2180 "I'm not going to continue. Please un-use the disk (or reboot) and try\n"
2187 it_lowsec
= div64u(part
.base
, SECTOR_SIZE
);
2188 it_secsize
= div64u(part
.size
, SECTOR_SIZE
);
2190 if(it_lowsec
!= pe
->lowsec
|| it_secsize
!= pe
->size
) {
2191 fprintf(stderr
, "\nReturned and set numbers don't match up!\n");
2192 fprintf(stderr
, "This can happen if the disk is still opened.\n");
2200 do_autopart(int resultfd
)
2204 struct part_entry
*pe
;
2205 struct part_entry orig_table
[1 + NR_PARTITIONS
];
2211 curdev
= select_disk();
2222 memcpy(orig_table
, table
, sizeof(table
));
2226 r
= select_region();
2227 } while(!r
); /* Back to step 2. */
2230 if(scribble_region(r
, &pe
, &newp
)) {
2233 char partbuf
[100], devname
[100];
2234 struct part_entry
*tpe
= NULL
;
2236 printstep(3, "Confirm your choices");
2238 region
= (int)(r
-regions
);
2239 /* disk = (int) (curdev-devices); */
2241 printf("\nThis is the point of no return. You have selected to install MINIX 3\n");
2242 printf("into region %d of disk %s. Please confirm that you want\n",
2243 region
, curdev
->name
);
2244 printf("to use this selection to install MINIX 3.\n\n");
2247 confirmation
= is_sure("Are you sure you want to continue?");
2248 if (confirmation
== IS_NO
) return 1;
2249 } while (confirmation
!= IS_YES
);
2251 /* Retrieve partition number in sorted order that we
2252 * have scribbled in.
2255 for(i
= 1; i
<= NR_PARTITIONS
; i
++) {
2258 if(si
< 1 || si
> NR_PARTITIONS
) {
2259 fprintf(stderr
, "Autopart internal error (out of range) (nothing written).\n");
2262 if(table
[si
].lowsec
== pe
->lowsec
) {
2264 fprintf(stderr
, "Autopart internal error (part found twice) (nothing written).\n");
2267 check_ind(&table
[si
]);
2268 table
[si
].sysind
= MINIX_PART
;
2274 fprintf(stderr
, "Autopart internal error (part not found) (nothing written).\n");
2279 fprintf(stderr
, "Autopart internal error (couldn't update disk).\n");
2282 name
=strrchr(curdev
->name
, '/');
2283 if(!name
) name
= curdev
->name
;
2286 sprintf(partbuf
, "%sp%d d%dp%d\n", name
, found
-1,
2287 curdev
->biosdrive
, found
-1);
2288 sprintf(devname
, "/dev/%sp%d", name
, found
-1);
2289 if(resultfd
>= 0 && write(resultfd
, partbuf
, strlen(partbuf
)) < strlen(partbuf
)) {
2290 fprintf(stderr
, "Autopart internal error (couldn't write result).\n");
2304 if(sanitycheck_failed(devname
, tpe
)) {
2305 fprintf(stderr
, "Autopart internal error (disk sanity check failed).\n");
2311 if((fd
=open(devname
, O_WRONLY
)) < 0) {
2314 /* Clear any subpartitioning. */
2315 static unsigned char sub
[2048];
2318 write(fd
, sub
, sizeof(sub
));
2328 int main(int argc
, char **argv
)
2334 /* autopart uses getopt() */
2335 while((c
= getopt(argc
, argv
, "m:f:")) != EOF
) {
2338 min_region_mb
= atoi(optarg
);
2341 /* Make sure old data file is gone. */
2343 if((resultfd
=open(optarg
, O_CREAT
| O_WRONLY
| O_TRUNC
)) < 0) {
2347 sync(); /* Make sure no old data file lingers. */
2350 fprintf(stderr
, "Unknown option\n");
2358 for (i
= 0; i
< argc
; i
++) {
2359 newdevice(argv
[i
], 0, 0);
2362 if (firstdev
== nil
) {
2371 if (firstdev
== nil
) {
2372 fprintf(stderr
, "autopart couldn't find any devices.\n");
2375 r
= do_autopart(resultfd
);
2376 if(resultfd
>= 0) { close(resultfd
); }