1 /* part 1.57 - Partition table editor Author: Kees J. Bot
3 * Needs about 22k heap+stack.
21 #include <sys/ioctl.h>
22 #include <minix/config.h>
23 #include <minix/const.h>
24 #include <minix/partition.h>
25 #include <minix/u64.h>
26 #include <machine/partition.h>
29 /* True if a partition is an extended partition. */
30 #define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
32 /* Minix master bootstrap code. */
33 static char MASTERBOOT
[] = "/usr/mdec/mbr";
36 ----first---- --geom/last-- ------sectors-----
37 Device Cyl Head Sec Cyl Head Sec Base Size Kb
39 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521
41 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440
42 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142
43 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939
44 3 p3 00 None 0 0 0 0 0 -1 0 0 0
47 #define MAXSIZE 999999999L /* Will 1T be enough this year? */
48 #define SECTOR_SIZE 512
49 #define DEV_FD0 0x200 /* Device number of /dev/fd0 */
50 #define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */
52 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
53 #define arraylimit(a) ((a) + arraysize(a))
55 void report(const char *label
)
57 fprintf(stderr
, "part: %s: %s\n", label
, strerror(errno
));
60 void fatal(const char *label
)
66 struct termios termios
;
68 void save_ttyflags(void)
69 /* Save tty attributes for later restoration. */
71 if (tcgetattr(0, &termios
) < 0) fatal("");
74 void restore_ttyflags(void)
75 /* Reset the tty flags to how we got 'em. */
77 if (tcsetattr(0, TCSANOW
, &termios
) < 0) fatal("");
81 /* Set the terminal to raw mode, no signals, no echoing. */
83 struct termios rawterm
;
86 rawterm
.c_lflag
&= ~(ICANON
|ISIG
|ECHO
);
87 rawterm
.c_iflag
&= ~(ICRNL
);
88 if (tcsetattr(0, TCSANOW
, &rawterm
) < 0) fatal("");
91 #define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
93 char t_cd
[16], t_cm
[32], t_so
[16], t_se
[16], t_md
[16], t_me
[16];
98 /* Get terminal capabilities and set the tty to "editor" mode. */
101 static char termbuf
[1024];
104 if ((term
= getenv("TERM")) == nil
|| tgetent(termbuf
, term
) != 1) {
105 fprintf(stderr
, "part: Can't get terminal capabilities\n");
108 if (tgetstr("cd", (tp
= t_cd
, &tp
)) == nil
109 || tgetstr("cm", (tp
= t_cm
, &tp
)) == nil
) {
110 fprintf(stderr
, "part: This terminal is too dumb\n");
115 (void) tgetstr("so", (tp
= t_so
, &tp
));
116 (void) tgetstr("se", (tp
= t_se
, &tp
));
117 (void) tgetstr("md", (tp
= t_md
, &tp
));
118 (void) tgetstr("me", (tp
= t_me
, &tp
));
133 while ((c
= *s
++) != 0) putchr(c
);
136 void set_cursor(int row
, int col
)
138 tputs(tgoto(t_cm
, col
, row
), 1, putchr
);
141 int statusrow
= STATUSROW
;
145 void stat_start(int serious
)
146 /* Prepare for printing on a fresh status line, possibly highlighted. */
148 set_cursor(statusrow
++, 0);
149 tputs(t_cd
, 1, putchr
);
150 if (serious
) tputs(t_so
, 1, putchr
);
153 void stat_end(int ktl
)
154 /* Closing bracket for stat_start. Sets "keystrokes to live" of message. */
156 tputs(t_se
, 1, putchr
);
161 void stat_reset(void)
162 /* Reset the statusline pointer and clear old messages if expired. */
164 if (stat_ktl
> 0 && --stat_ktl
== 0) {
165 statusrow
= STATUSROW
;
168 if (need_help
&& statusrow
< (24-2)) {
169 if (statusrow
> STATUSROW
) stat_start(0);
172 "Type '+' or '-' to change, 'r' to read, '?' for more help, 'q' to exit");
174 statusrow
= STATUSROW
;
178 void clear_screen(void)
181 tputs(t_cd
, 1, putchr
);
187 /* Reset the tty to cooked mode. */
190 set_cursor(statusrow
, 0);
191 tputs(t_cd
, 1, putchr
);
194 void *alloc(size_t n
)
198 if ((m
= malloc(n
)) == nil
) { reset_tty(); fatal(""); }
203 #ifndef makedev /* Missing in sys/types.h */
204 #define minor(dev) (((dev) >> MINOR) & BYTE)
205 #define major(dev) (((dev) >> MAJOR) & BYTE)
206 #define makedev(major, minor) \
207 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
210 typedef enum parttype
{ DUNNO
, SUBPART
, PRIMARY
, FLOPPY
} parttype_t
;
212 typedef struct device
{
213 struct device
*next
, *prev
; /* Circular dequeue. */
214 dev_t rdev
; /* Device number (sorting only). */
215 char *name
; /* E.g. /dev/c0d0 */
216 char *subname
; /* E.g. /dev/c0d0:2 */
220 device_t
*firstdev
= nil
, *curdev
;
222 void newdevice(char *name
, int scanning
)
223 /* Add a device to the device list. If scanning is set then we are reading
224 * /dev, so insert the device in device number order and make /dev/c0d0 current.
227 device_t
*new, *nextdev
, *prevdev
;
232 if (stat(name
, &st
) < 0 || !S_ISBLK(st
.st_mode
)) return;
234 switch (major(st
.st_rdev
)) {
237 if (minor(st
.st_rdev
) >= 4) return;
244 /* Disk controller */
245 if (minor(st
.st_rdev
) >= 0x80
246 || minor(st
.st_rdev
) % 5 != 0) return;
251 /* Interesting device found. */
253 (void) stat(name
, &st
);
256 new= alloc(sizeof(*new));
257 new->rdev
= st
.st_rdev
;
258 new->name
= alloc((strlen(name
) + 1) * sizeof(new->name
[0]));
259 strcpy(new->name
, name
);
260 new->subname
= new->name
;
261 new->parttype
= DUNNO
;
262 if (major(st
.st_rdev
) == major(DEV_FD0
) && minor(st
.st_rdev
) < 112) {
263 new->parttype
= FLOPPY
;
265 if (st
.st_rdev
>= DEV_C0D0
&& minor(st
.st_rdev
) < 128
266 && minor(st
.st_rdev
) % 5 == 0) {
267 new->parttype
= PRIMARY
;
270 if (firstdev
== nil
) {
272 new->next
= new->prev
= new;
277 while (new->rdev
>= nextdev
->rdev
278 && (nextdev
= nextdev
->next
) != firstdev
) {}
279 prevdev
= nextdev
->prev
;
285 if (new->rdev
< firstdev
->rdev
) firstdev
= new;
286 if (new->rdev
== DEV_C0D0
) curdev
= new;
287 if (curdev
->rdev
!= DEV_C0D0
) curdev
= firstdev
;
290 void getdevices(void)
291 /* Get all block devices from /dev that look interesting. */
295 char name
[5 + NAME_MAX
+ 1];
297 if ((d
= opendir("/dev")) == nil
) fatal("/dev");
299 while ((e
= readdir(d
)) != nil
) {
300 strcpy(name
, "/dev/");
301 strcpy(name
+ 5, e
->d_name
);
308 unsigned char bootblock
[SECTOR_SIZE
];
309 struct part_entry table
[1 + NR_PARTITIONS
];
310 int existing
[1 + NR_PARTITIONS
];
311 unsigned long offset
= 0, extbase
= 0, extsize
;
313 char sort_index
[1 + NR_PARTITIONS
];
314 unsigned cylinders
= 1, heads
= 1, sectors
= 1, secpcyl
= 1;
315 unsigned alt_cyls
= 1, alt_heads
= 1, alt_secs
= 1;
319 unsigned long sortbase(struct part_entry
*pe
)
321 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
;
325 /* Let the sort_index array show the order partitions are sorted in. */
328 int idx
[1 + NR_PARTITIONS
];
330 for (i
= 1; i
<= NR_PARTITIONS
; i
++) idx
[i
]= i
;
332 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
333 for (j
= 1; j
<= NR_PARTITIONS
-1; j
++) {
334 int sj
= idx
[j
], sj1
= idx
[j
+1];
336 if (sortbase(&table
[sj
]) > sortbase(&table
[sj1
])) {
342 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_index
[idx
[i
]]= i
;
345 void dos2chs(unsigned char *dos
, unsigned *chs
)
346 /* Extract cylinder, head and sector from the three bytes DOS uses to address
347 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
348 * of the sector byte. The sector number is rebased to count from 0.
351 chs
[0]= ((dos
[1] & 0xC0) << 2) | dos
[2];
353 chs
[2]= (dos
[1] & 0x3F) - 1;
356 void abs2dos(unsigned char *dos
, unsigned long pos
)
357 /* Translate a sector offset to three DOS bytes. */
362 h
= (pos
% secpcyl
) / sectors
;
363 s
= pos
% sectors
+ 1;
366 dos
[1]= s
| ((c
>> 2) & 0xC0);
370 void recompute0(void)
371 /* Recompute the partition size for the device after a geometry change. */
374 cylinders
= heads
= sectors
= 1;
375 memset(table
, 0, sizeof(table
));
377 if (!precise
&& offset
== 0) {
379 table
[0].size
= (unsigned long) cylinders
* heads
* sectors
;
381 table
[0].sysind
= device
< 0 ? NO_PART
: MINIX_PART
;
382 secpcyl
= heads
* sectors
;
385 void guess_geometry(void)
386 /* With a bit of work one can deduce the disk geometry from the partition
387 * table. This may be necessary if the driver gets it wrong. (If partition
388 * tables didn't have C/H/S numbers we would not care at all...)
392 struct part_entry
*pe
;
396 unsigned char HS
[256][8]; /* Bit map off all possible H/S */
398 alt_cyls
= alt_heads
= alt_secs
= 0;
400 /* Initially all possible H/S combinations are possible. HS[h][0]
401 * bit 0 is used to rule out a head value.
403 for (h
= 1; h
<= 255; h
++) {
404 for (s
= 0; s
< 8; s
++) HS
[h
][s
]= 0xFF;
407 for (i
= 0; i
< 2*NR_PARTITIONS
; i
++) {
408 pe
= &(table
+1)[i
>> 1];
409 if (pe
->sysind
== NO_PART
) continue;
411 /* Get the end or start sector numbers (in that order). */
413 dos2chs(&pe
->last_head
, chs
);
414 sec
= pe
->lowsec
+ pe
->size
- 1;
416 dos2chs(&pe
->start_head
, chs
);
420 if (chs
[0] >= alt_cyls
) alt_cyls
= chs
[0]+1;
422 /* Which H/S combinations can be ruled out? */
423 for (h
= 1; h
<= 255; h
++) {
424 if (HS
[h
][0] == 0) continue;
426 for (s
= 1; s
<= 63; s
++) {
427 if ((chs
[0] * h
+ chs
[1]) * s
+ chs
[2] != sec
) {
428 HS
[h
][s
/8] &= ~(1 << (s
%8));
430 if (HS
[h
][s
/8] & (1 << (s
%8))) n
++;
432 if (n
== 0) HS
[h
][0]= 0;
436 /* See if only one remains. */
438 for (h
= 1; h
<= 255; h
++) {
439 if (HS
[h
][0] == 0) continue;
440 for (s
= 1; s
<= 63; s
++) {
441 if (HS
[h
][s
/8] & (1 << (s
%8))) {
449 /* Forget it if more than one choice... */
450 if (i
> 1) alt_cyls
= alt_heads
= alt_secs
= 0;
454 /* Find out the geometry of the device by querying the driver, or by looking
455 * at the partition table. These numbers are crosschecked to make sure that
456 * the geometry is correct. Master bootstraps other than the Minix one use
457 * the CHS numbers in the partition table to load the bootstrap of the active
463 struct partition geometry
;
466 /* Geometry already known. */
473 if (device
< 0) return;
475 /* Try to guess the geometry from the partition table. */
478 /* Try to get the geometry from the driver. */
479 (void) fstat(device
, &dst
);
481 if (S_ISBLK(dst
.st_mode
) || S_ISCHR(dst
.st_mode
)) {
482 /* Try to get the drive's geometry from the driver. */
484 if (ioctl(device
, DIOCGETP
, &geometry
) < 0)
487 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
488 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
489 cylinders
= geometry
.cylinders
;
490 heads
= geometry
.heads
;
491 sectors
= geometry
.sectors
;
499 /* Getting the geometry from the driver failed, so use the
500 * alternate geometry.
502 if (alt_heads
== 0) {
503 alt_cyls
= table
[0].size
/ (64 * 32);
513 printf("Failure to get the geometry of %s: %s", curdev
->name
,
514 errno
== ENOTTY
? "No driver support" : strerror(err
));
517 printf("The geometry has been guessed as %ux%ux%u",
518 cylinders
, heads
, sectors
);
521 if (alt_heads
== 0) {
527 if (heads
!= alt_heads
|| sectors
!= alt_secs
) {
533 "The %ux%ux%u geometry obtained from the device driver does not match",
534 cylinders
, heads
, sectors
);
538 "the %ux%ux%u geometry implied by the partition table. Hit 'X' to switch",
539 alt_cyls
, alt_heads
, alt_secs
);
543 "between the two geometries to see what is best. Note that the geometry");
547 "must be correct when the table is written or the system may not boot!");
552 /* Show the base and size of the device instead of the whole drive.
553 * This makes sense for subpartitioning primary partitions.
555 if (precise
&& ioctl(device
, DIOCGETP
, &geometry
) >= 0) {
556 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
557 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
565 typedef struct indicators
{ /* Partition type to partition name. */
570 indicators_t ind_table
[]= {
574 { 0x03, "XENIX usr" },
576 { 0x05, "EXTENDED" },
578 { 0x07, "HPFS/NTFS" },
580 { 0x09, "COHERENT" },
585 { 0x0F, "EXTENDED" },
587 { 0x40, "VENIX286" },
588 { 0x42, "W2000 Dyn" },
589 { 0x52, "MICROPORT" },
591 { 0x64, "NOVELL286" },
592 { 0x65, "NOVELL386" },
594 { 0x80, "MINIX-OLD" },
596 { 0x82, "LINUXswap" },
599 { 0x94, "AMOEBAbad" },
602 { 0xB8, "BSDI swap" },
605 { 0xFF, "BADBLOCKS" },
608 char *typ2txt(int ind
)
609 /* Translate a numeric partition indicator for human eyes. */
613 for (pind
= ind_table
; pind
< arraylimit(ind_table
); pind
++) {
614 if (pind
->ind
== ind
) return pind
->name
;
619 int round_sysind(int ind
, int delta
)
620 /* Find the next known partition type starting with ind in direction delta. */
624 ind
= (ind
+ delta
) & 0xFF;
627 for (pind
= arraylimit(ind_table
)-1; pind
->ind
> ind
; pind
--) {}
629 for (pind
= ind_table
; pind
->ind
< ind
; pind
++) {}
634 /* Objects on the screen, either simple pieces of the text or the cylinder
635 * number of the start of partition three.
637 typedef enum objtype
{
638 O_INFO
, O_TEXT
, O_DEV
, O_SUB
,
639 O_TYPTXT
, O_SORT
, O_NUM
, O_TYPHEX
,
640 O_CYL
, O_HEAD
, O_SEC
,
641 O_SCYL
, O_SHEAD
, O_SSEC
, O_LCYL
, O_LHEAD
, O_LSEC
, O_BASE
, O_SIZE
, O_KB
644 #define rjust(type) ((type) >= O_TYPHEX)
645 #define computed(type) ((type) >= O_TYPTXT)
647 typedef struct object
{
649 objtype_t type
; /* Text field, cylinder number, etc. */
650 char flags
; /* Modifiable? */
654 struct part_entry
*entry
; /* What does the object refer to? */
656 char value
[20]; /* Value when printed. */
659 #define OF_MOD 0x01 /* Object value is modifiable. */
660 #define OF_ODD 0x02 /* It has a somewhat odd value. */
661 #define OF_BAD 0x04 /* Its value is no good at all. */
663 /* Events: (Keypress events are the value of the key pressed.) */
664 #define E_ENTER (-1) /* Cursor moves onto object. */
665 #define E_LEAVE (-2) /* Cursor leaves object. */
666 #define E_WRITE (-3) /* Write, but not by typing 'w'. */
668 /* The O_SIZE objects have a dual identity. */
669 enum howend
{ SIZE
, LAST
} howend
= SIZE
;
671 object_t
*world
= nil
;
672 object_t
*curobj
= nil
;
674 object_t
*newobject(objtype_t type
, int flags
, int row
, int col
, int len
)
675 /* Make a new object given a type, flags, position and length on the screen. */
678 object_t
**aop
= &world
;
680 new= alloc(sizeof(*new));
697 unsigned long entry2base(struct part_entry
*pe
)
698 /* Return the base sector of the partition if defined. */
700 return pe
->sysind
== NO_PART
? 0 : pe
->lowsec
;
703 unsigned long entry2last(struct part_entry
*pe
)
705 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
+ pe
->size
- 1;
708 unsigned long entry2size(struct part_entry
*pe
)
710 return pe
->sysind
== NO_PART
? 0 : pe
->size
;
713 int overlap(unsigned long sec
)
714 /* See if sec is part of another partition. */
716 struct part_entry
*pe
;
718 for (pe
= table
+ 1; pe
<= table
+ NR_PARTITIONS
; pe
++) {
719 if (pe
->sysind
== NO_PART
) continue;
721 if (pe
->lowsec
< sec
&& sec
< pe
->lowsec
+ pe
->size
)
727 int aligned(unsigned long sec
, unsigned unit
)
728 /* True if sec is aligned to unit or if it is no problem if it is unaligned. */
730 return (offset
!= 0 && extbase
== 0) || (sec
% unit
== 0);
733 void print(object_t
*op
)
734 /* Print an object's value if it changed. */
736 struct part_entry
*pe
= op
->entry
;
743 /* Remember the old flags and value. */
745 strcpy(oldvalue
, op
->value
);
747 op
->flags
&= ~(OF_ODD
| OF_BAD
);
752 static struct field
{ int type
; char *name
; } fields
[]= {
753 { O_DEV
, "Select device" },
754 { O_NUM
, "Active flag" },
755 { O_TYPHEX
, "Hex partition type" },
756 { O_TYPTXT
, "Partition type" },
757 { O_SCYL
, "Start cylinder" },
758 { O_SHEAD
, "Start head" },
759 { O_SSEC
, "Start sector" },
760 { O_CYL
, "Number of cylinders" },
761 { O_HEAD
, "Number of heads" },
762 { O_SEC
, "Sectors per track" },
763 { O_LCYL
, "Last cylinder" },
764 { O_LHEAD
, "Last head" },
765 { O_LSEC
, "Last sector" },
766 { O_BASE
, "Base sector" },
767 { O_SIZE
, "Size in sectors" },
768 { O_KB
, "Size in kilobytes" },
771 struct field
*fp
= fields
;
773 while (fp
->type
>= 0 && fp
->type
!= curobj
->type
) fp
++;
774 strcpy(op
->value
, fp
->name
);
778 /* Simple text field. */
779 strcpy(op
->value
, op
->text
);
783 /* Name of currently edited device. */
784 name
= op
->type
== O_DEV
? curdev
->name
:
785 offset
== 0 ? "" : curdev
->subname
;
786 if ((n
= strlen(name
)) < op
->len
) n
= op
->len
;
787 strcpy(op
->value
, name
+ (n
- op
->len
));
788 if (device
< 0 && op
->type
== O_DEV
) op
->flags
|= OF_BAD
;
791 /* Position and active flag. */
792 sprintf(op
->value
, "%d%c", (int) (pe
- table
- 1),
793 pe
->bootind
& ACTIVE_FLAG
? '*' : ' ');
796 /* Position if the driver sorts the table. */
797 sprintf(op
->value
, "%s%d",
798 curdev
->parttype
>= PRIMARY
? "p" :
799 curdev
->parttype
== SUBPART
? "s" : "",
800 (curdev
->parttype
== SUBPART
||
801 curdev
->parttype
== FLOPPY
? pe
- table
802 : sort_index
[pe
- table
]) - 1);
805 /* Hex partition type indicator. */
806 sprintf(op
->value
, "%02X", pe
->sysind
);
809 /* Ascii partition type indicator. */
810 strcpy(op
->value
, typ2txt(pe
->sysind
));
813 /* Partition's start cylinder. */
814 sprintf(op
->value
, "%lu", entry2base(pe
) / secpcyl
);
819 sprintf(op
->value
, "%lu", t
% secpcyl
/ sectors
);
820 if (!aligned(t
, secpcyl
) && t
!= table
[0].lowsec
+ sectors
)
826 sprintf(op
->value
, "%lu", t
% sectors
);
827 if (!aligned(t
, sectors
)) op
->flags
|= OF_ODD
;
830 /* Number of cylinders. */
831 sprintf(op
->value
, "%u", cylinders
);
834 /* Number of heads. */
835 sprintf(op
->value
, "%u", heads
);
838 /* Number of sectors per track. */
839 sprintf(op
->value
, "%u", sectors
);
842 /* Partition's last cylinder. */
844 sprintf(op
->value
, "%lu", t
== -1 ? 0 : t
/ secpcyl
);
847 /* Partition's last head. */
849 sprintf(op
->value
, "%lu", t
== -1 ? 0 : t
% secpcyl
/ sectors
);
850 if (!aligned(t
+ 1, secpcyl
)) op
->flags
|= OF_ODD
;
853 /* Partition's last sector. */
855 sprintf(op
->value
, t
== -1 ? "-1" : "%lu", t
% sectors
);
856 if (!aligned(t
+ 1, sectors
)) op
->flags
|= OF_ODD
;
859 /* Partition's base sector. */
860 sprintf(op
->value
, "%lu", entry2base(pe
));
861 if (pe
->sysind
!= NO_PART
&& pe
!= &table
[0]
862 && (pe
->lowsec
<= table
[0].lowsec
|| overlap(pe
->lowsec
)))
866 /* Size of partitition in sectors. */
867 t
= howend
== SIZE
? entry2size(pe
) : entry2last(pe
);
868 sprintf(op
->value
, "%lu", pe
->sysind
== NO_PART
? 0 : t
);
869 if (pe
->sysind
!= NO_PART
&& (pe
->size
== 0
870 || pe
->lowsec
+ pe
->size
> table
[0].lowsec
+ table
[0].size
871 || overlap(pe
->lowsec
+ pe
->size
)))
875 /* Size of partitition in kilobytes. */
876 sprintf(op
->value
, "%lu", entry2size(pe
) / 2);
879 sprintf(op
->value
, "?? %d ??", op
->type
);
882 if (device
< 0 && computed(op
->type
)) strcpy(op
->value
, "?");
884 /* If a value overflows the print field then show a blank
885 * reverse video field.
887 if ((n
= strlen(op
->value
)) > op
->len
) {
892 /* Right or left justified? */
893 if (rjust(op
->type
)) {
894 memmove(op
->value
+ (op
->len
- n
), op
->value
, n
);
895 memset(op
->value
, ' ', op
->len
- n
);
897 memset(op
->value
+ n
, ' ', op
->len
- n
);
899 op
->value
[op
->len
]= 0;
901 if ((op
->flags
& (OF_ODD
| OF_BAD
)) == (oldflags
& (OF_ODD
| OF_BAD
))
902 && strcmp(op
->value
, oldvalue
) == 0) {
903 /* The value did not change. */
907 set_cursor(op
->row
, rjust(op
->type
) ? op
->col
- (op
->len
-1) : op
->col
);
909 if (op
->flags
& OF_BAD
) tputs(t_so
, 1, putchr
);
911 if (op
->flags
& OF_ODD
) tputs(t_md
, 1, putchr
);
913 if (op
->flags
& OF_BAD
) tputs(t_se
, 1, putchr
);
915 if (op
->flags
& OF_ODD
) tputs(t_me
, 1, putchr
);
919 /* Repaint all objects that changed. */
923 for (op
= world
; op
!= nil
; op
= op
->next
) print(op
);
926 int typing
; /* Set if a digit has been typed to set a value. */
927 int magic
; /* Changes when using the magic key. */
929 void event(int ev
, object_t
*op
);
931 void m_redraw(int ev
, object_t
*op
)
932 /* Redraw the screen. */
936 if (ev
!= ctrl('L')) return;
939 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) op2
->value
[0]= 0;
942 void m_toggle(int ev
, object_t
*op
)
943 /* Toggle between the driver and alternate geometry. */
947 if (ev
!= 'X') return;
948 if (alt_cyls
== cylinders
&& alt_heads
== heads
&& alt_secs
== sectors
)
951 t
= cylinders
; cylinders
= alt_cyls
; alt_cyls
= t
;
952 t
= heads
; heads
= alt_heads
; alt_heads
= t
;
953 t
= sectors
; sectors
= alt_secs
; alt_secs
= t
;
958 char size_last
[]= "Size";
960 void m_orientation(int ev
, object_t
*op
)
962 if (ev
!= ' ') return;
967 strcpy(size_last
, "Last");
971 strcpy(size_last
, "Size");
975 void m_move(int ev
, object_t
*op
)
976 /* Move to the nearest modifiably object in the intended direction. Objects
977 * on the same row or column are really near.
980 object_t
*near
, *op2
;
981 unsigned dist
, d2
, dr
, dc
;
983 if (ev
!= 'h' && ev
!= 'j' && ev
!= 'k' && ev
!= 'l' && ev
!= 'H')
987 /* No device open? Then try to read first. */
989 if (device
< 0) return;
995 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
996 if (op2
== op
|| !(op2
->flags
& OF_MOD
)) continue;
998 dr
= abs(op2
->row
- op
->row
);
999 dc
= abs(op2
->col
- op
->col
);
1001 d2
= 25*dr
*dr
+ dc
*dc
;
1002 if (op2
->row
!= op
->row
&& op2
->col
!= op
->col
) d2
+= 1000;
1005 case 'h': /* Left */
1006 if (op2
->col
>= op
->col
) d2
= -1;
1008 case 'j': /* Down */
1009 if (op2
->row
<= op
->row
) d2
= -1;
1012 if (op2
->row
>= op
->row
) d2
= -1;
1014 case 'l': /* Right */
1015 if (op2
->col
<= op
->col
) d2
= -1;
1017 case 'H': /* Home */
1018 if (op2
->type
== O_DEV
) d2
= 0;
1020 if (d2
< dist
) { near
= op2
; dist
= d2
; }
1022 if (near
!= op
) event(E_LEAVE
, op
);
1023 event(E_ENTER
, near
);
1026 void m_updown(int ev
, object_t
*op
)
1027 /* Move a partition table entry up or down. */
1030 struct part_entry tmp
;
1033 if (ev
!= ctrl('K') && ev
!= ctrl('J')) return;
1034 if (op
->entry
== nil
) return;
1036 i
= op
->entry
- table
;
1037 if (ev
== ctrl('K')) {
1041 if (i
>= NR_PARTITIONS
) return;
1045 tmp
= table
[i
]; table
[i
]= table
[j
]; table
[j
]= tmp
;
1046 tmpx
= existing
[i
]; existing
[i
]= existing
[j
]; existing
[j
]= tmpx
;
1049 event(ev
== ctrl('K') ? 'k' : 'j', op
);
1052 void m_enter(int ev
, object_t
*op
)
1053 /* We've moved onto this object. */
1055 if (ev
!= E_ENTER
&& ev
!= ' ' && ev
!= '<' && ev
!= '>' && ev
!= 'X')
1062 void m_leave(int ev
, object_t
*op
)
1063 /* About to leave this object. */
1065 if (ev
!= E_LEAVE
) return;
1068 int within(unsigned *var
, unsigned low
, unsigned value
, unsigned high
)
1069 /* Only set *var to value if it looks reasonable. */
1071 if (low
<= value
&& value
<= high
) {
1078 int lwithin(unsigned long *var
, unsigned long low
, unsigned long value
,
1081 if (low
<= value
&& value
<= high
) {
1088 int nextdevice(object_t
*op
, int delta
)
1089 /* Select the next or previous device from the device list. */
1093 if (offset
!= 0) return 0;
1094 if (dirty
) event(E_WRITE
, op
);
1095 if (dirty
) return 0;
1098 (void) close(device
);
1106 curdev
= curdev
->prev
;
1107 while (delta
< -1 && major(curdev
->rdev
) == major(rdev
)
1108 && curdev
->rdev
< rdev
);
1111 curdev
= curdev
->next
;
1112 while (delta
> 1 && major(curdev
->rdev
) == major(rdev
)
1113 && curdev
->rdev
> rdev
);
1118 void check_ind(struct part_entry
*pe
)
1119 /* If there are no other partitions then make this new one active. */
1121 struct part_entry
*pe2
;
1123 if (pe
->sysind
!= NO_PART
) return;
1125 for (pe2
= table
+ 1; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++)
1126 if (pe2
->sysind
!= NO_PART
|| pe2
->bootind
& ACTIVE_FLAG
) break;
1128 if (pe2
== table
+ 1 + NR_PARTITIONS
) pe
->bootind
= ACTIVE_FLAG
;
1131 int check_existing(struct part_entry
*pe
)
1132 /* Check and if not ask if an existing partition may be modified. */
1134 static int expert
= 0;
1137 if (expert
|| pe
== nil
|| !existing
[pe
- table
]) return 1;
1140 putstr("Do you wish to modify existing partitions? (y/n) ");
1142 while ((c
= getchar()) != 'y' && c
!= 'n') {}
1145 return (expert
= (c
== 'y'));
1148 void m_modify(int ev
, object_t
*op
)
1149 /* Increment, decrement, set, or toggle the value of an object, using
1150 * arithmetic tricks the author doesn't understand either.
1154 struct part_entry
*pe
= op
->entry
;
1157 unsigned long surplus
;
1158 int radix
= op
->type
== O_TYPHEX
? 0x10 : 10;
1161 if (device
< 0 && op
->type
!= O_DEV
) return;
1165 mul
= radix
; delta
= -1; typing
= 0;
1168 mul
= radix
; delta
= 1; typing
= 0;
1171 if (!typing
) return;
1178 if ('0' <= ev
&& ev
<= '9')
1181 if (radix
== 0x10 && 'a' <= ev
&& ev
<= 'f')
1182 delta
= ev
- 'a' + 10;
1184 if (radix
== 0x10 && 'A' <= ev
&& ev
<= 'F')
1185 delta
= ev
- 'A' + 10;
1189 mul
= typing
? radix
*radix
: 0;
1194 if (!check_existing(pe
)) return;
1198 if (ev
!= '-' && ev
!= '+') return;
1199 if (!nextdevice(op
, delta
)) return;
1202 if (!within(&cylinders
, 1,
1203 cylinders
* mul
/ radix
+ delta
, 1024)) return;
1207 if (!within(&heads
, 1, heads
* mul
/ radix
+ delta
, 255))
1212 if (!within(§ors
, 1, sectors
* mul
/ radix
+ delta
, 63))
1217 if (ev
!= '-' && ev
!= '+') return;
1218 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1219 if (op2
->type
== O_NUM
&& ev
== '+')
1220 op2
->entry
->bootind
= 0;
1222 op
->entry
->bootind
= ev
== '+' ? ACTIVE_FLAG
: 0;
1226 pe
->sysind
= pe
->sysind
* mul
/ radix
+ delta
;
1229 if (ev
!= '-' && ev
!= '+') return;
1231 pe
->sysind
= round_sysind(pe
->sysind
, delta
);
1238 if (op
->type
!= O_SCYL
&& ev
!= '-' && ev
!= '+') return;
1240 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1243 if (!lwithin(&t
, 0L,
1244 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1246 if (howend
== LAST
|| op
->type
!= O_BASE
)
1247 pe
->size
-= t
- pe
->lowsec
;
1250 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1257 if (op
->type
!= O_LCYL
&& ev
!= '-' && ev
!= '+') return;
1259 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1260 t
= pe
->lowsec
+ pe
->size
- 1 + level
;
1261 surplus
= t
% level
- mul
/ radix
* level
;
1262 if (!lwithin(&t
, 0L,
1263 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1265 pe
->size
= t
- pe
->lowsec
+ 1;
1267 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1271 if (mul
== 0) pe
->size
= 0; /* new value, no surplus */
1273 if (pe
->sysind
== NO_PART
) {
1274 if (op
->type
== O_KB
|| howend
== SIZE
) {
1275 /* First let loose magic to set the base. */
1282 memset(pe
, 0, sizeof(*pe
));
1284 t
= (op
->type
== O_KB
|| howend
== SIZE
) ? pe
->size
1285 : pe
->lowsec
+ pe
->size
- 1;
1287 if (!lwithin(&t
, 0L,
1288 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1290 pe
->size
= (op
->type
== O_KB
|| howend
== SIZE
) ? t
:
1293 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1299 /* The order among the entries may have changed. */
1304 unsigned long spell
[3 + 4 * (1+NR_PARTITIONS
)];
1308 void newspell(unsigned long charm
)
1309 /* Add a new spell, descending order for the base, ascending for the size. */
1313 if (charm
- table
[0].lowsec
> table
[0].size
) return;
1315 for (i
= 0; i
< nspells
; i
++) {
1316 if (charm
== spell
[i
]) return; /* duplicate */
1318 if (touching
== O_BASE
) {
1319 if (charm
== table
[0].lowsec
+ table
[0].size
) return;
1320 if ((spell
[0] - charm
) < (spell
[0] - spell
[i
])) break;
1322 if (charm
== table
[0].lowsec
) return;
1323 if ((charm
- spell
[0]) < (spell
[i
] - spell
[0])) break;
1326 for (j
= ++nspells
; j
> i
; j
--) spell
[j
]= spell
[j
-1];
1330 void m_magic(int ev
, object_t
*op
)
1331 /* Apply magic onto a base or size number. */
1333 struct part_entry
*pe
= op
->entry
, *pe2
;
1334 int rough
= (offset
!= 0 && extbase
== 0);
1336 if (ev
!= 'm' || device
< 0) return;
1339 if (!check_existing(pe
)) return;
1342 /* See what magic we can let loose on this value. */
1345 /* First spell, the current value. */
1348 case O_SHEAD
: /* Start of partition. */
1352 spell
[0]= pe
->lowsec
;
1356 case O_LSEC
: /* End of partition. */
1360 spell
[0]= pe
->lowsec
+ pe
->size
;
1365 if (pe
->sysind
== NO_PART
) {
1366 memset(pe
, 0, sizeof(*pe
));
1368 pe
->sysind
= MINIX_PART
;
1370 if (touching
== O_SIZE
) {
1371 /* First let loose magic on the base. */
1374 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1375 if (op2
->row
== op
->row
&&
1376 op2
->type
== O_BASE
) {
1385 /* Avoid the first sector on the device. */
1386 if (spell
[0] == table
[0].lowsec
) newspell(spell
[0] + 1);
1388 /* Further interesting values are the the bases of other
1389 * partitions or their ends.
1391 for (pe2
= table
; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++) {
1392 if (pe2
== pe
|| pe2
->sysind
== NO_PART
) continue;
1393 if (pe2
->lowsec
== table
[0].lowsec
)
1394 newspell(table
[0].lowsec
+ 1);
1396 newspell(pe2
->lowsec
);
1397 newspell(pe2
->lowsec
+ pe2
->size
);
1398 if (touching
== O_BASE
&& howend
== SIZE
) {
1399 newspell(pe2
->lowsec
- pe
->size
);
1400 newspell(pe2
->lowsec
+ pe2
->size
- pe
->size
);
1402 if (pe2
->lowsec
% sectors
!= 0) rough
= 1;
1404 /* Present values rounded up to the next cylinder unless
1405 * the table is already a mess. Use "start + 1 track" instead
1406 * of "start + 1 cylinder". Also add the end of the last
1410 unsigned long n
= spell
[0];
1411 if (n
== table
[0].lowsec
) n
++;
1412 n
= (n
+ sectors
- 1) / sectors
* sectors
;
1413 if (n
!= table
[0].lowsec
+ sectors
)
1414 n
= (n
+ secpcyl
- 1) / secpcyl
* secpcyl
;
1416 if (touching
== O_SIZE
)
1417 newspell(table
[0].size
/ secpcyl
* secpcyl
);
1420 /* Magic has been applied, a spell needs to be chosen. */
1422 if (++magic
== nspells
) magic
= 0;
1424 if (touching
== O_BASE
) {
1425 if (howend
== LAST
) pe
->size
-= spell
[magic
] - pe
->lowsec
;
1426 pe
->lowsec
= spell
[magic
];
1428 pe
->size
= spell
[magic
] - pe
->lowsec
;
1430 /* The order among the entries may have changed. */
1435 typedef struct diving
{
1437 struct part_entry old0
;
1439 parttype_t oldparttype
;
1440 unsigned long oldoffset
;
1441 unsigned long oldextbase
;
1444 diving_t
*diving
= nil
;
1446 void m_in(int ev
, object_t
*op
)
1447 /* Go down into a primary or extended partition. */
1450 struct part_entry
*pe
= op
->entry
, ext
;
1453 if (ev
!= '>' || device
< 0 || pe
== nil
|| pe
== &table
[0]
1454 || (!(pe
->sysind
== MINIX_PART
&& offset
== 0)
1455 && !ext_part(pe
->sysind
))
1456 || pe
->size
== 0) return;
1459 if (extbase
!= 0) ext
.size
= extbase
+ extsize
- ext
.lowsec
;
1461 if (dirty
) event(E_WRITE
, op
);
1463 if (device
>= 0) { close(device
); device
= -1; }
1465 newdiv
= alloc(sizeof(*newdiv
));
1466 newdiv
->old0
= table
[0];
1467 newdiv
->oldsubname
= curdev
->subname
;
1468 newdiv
->oldparttype
= curdev
->parttype
;
1469 newdiv
->oldoffset
= offset
;
1470 newdiv
->oldextbase
= extbase
;
1476 n
= strlen(diving
->oldsubname
);
1477 curdev
->subname
= alloc((n
+ 3) * sizeof(curdev
->subname
[0]));
1478 strcpy(curdev
->subname
, diving
->oldsubname
);
1479 curdev
->subname
[n
++]= ':';
1480 curdev
->subname
[n
++]= '0' + (pe
- table
- 1);
1481 curdev
->subname
[n
]= 0;
1483 curdev
->parttype
= curdev
->parttype
== PRIMARY
? SUBPART
: DUNNO
;
1485 if (ext_part(ext
.sysind
) && extbase
== 0) {
1486 extbase
= ext
.lowsec
;
1488 curdev
->parttype
= DUNNO
;
1495 void m_out(int ev
, object_t
*op
)
1496 /* Go up from an extended or subpartition table to its enclosing. */
1500 if (ev
!= '<' || diving
== nil
) return;
1502 if (dirty
) event(E_WRITE
, op
);
1504 if (device
>= 0) { close(device
); device
= -1; }
1509 table
[0]= olddiv
->old0
;
1511 free(curdev
->subname
);
1512 curdev
->subname
= olddiv
->oldsubname
;
1514 curdev
->parttype
= olddiv
->oldparttype
;
1515 offset
= olddiv
->oldoffset
;
1516 extbase
= olddiv
->oldextbase
;
1521 if (diving
== nil
) submerged
= 0; /* We surfaced. */
1524 void installboot(unsigned char *bootblock
, char *masterboot
)
1525 /* Install code from a master bootstrap into a boot block. */
1528 unsigned char buf
[SECTOR_SIZE
];
1532 if ((mfp
= fopen(masterboot
, "r")) == nil
) {
1533 err
= strerror(errno
);
1537 n
= fread(buf
, sizeof(char), SECTOR_SIZE
, mfp
);
1539 err
= strerror(errno
);
1544 err
= "Is probably not a boot sector, too small";
1548 else if (n
< SECTOR_SIZE
&& n
> PART_TABLE_OFF
) {
1549 /* if only code, it cannot override partition table */
1550 err
= "Does not fit in a boot sector";
1554 else if (n
== SECTOR_SIZE
) {
1555 if (buf
[510] != 0x55 || buf
[511] != 0xaa) {
1556 err
= "Is not a boot sector (bad magic)";
1563 if (n
> PART_TABLE_OFF
) {
1564 err
= "Does not fit in a boot sector";
1569 memcpy(bootblock
, buf
, n
);
1572 /* Bootstrap installed. */
1577 printf("%s: %s", masterboot
, err
);
1581 ssize_t
boot_readwrite(int rw
)
1582 /* Read (0) or write (1) the boot sector. */
1584 u64_t off64
= mul64u(offset
, SECTOR_SIZE
);
1588 /* Minix-vmd has a 64 bit seek. */
1589 if (fcntl(device
, F_SEEK
, off64
) < 0) return -1;
1591 /* Minix has to gross things with the partition base. */
1592 struct partition geom0
, geom_seek
;
1594 if (offset
>= (LONG_MAX
/ SECTOR_SIZE
- 1)) {
1595 /* Move partition base. */
1596 if (ioctl(device
, DIOCGETP
, &geom0
) < 0) return -1;
1597 geom_seek
.base
= add64(geom0
.base
, off64
);
1598 geom_seek
.size
= cvu64(cmp64(add64u(off64
, SECTOR_SIZE
),
1599 geom0
.size
) <= 0 ? _STATIC_BLOCK_SIZE
: 0);
1601 if (ioctl(device
, DIOCSETP
, &geom_seek
) < 0) return -1;
1602 if (lseek(device
, (off_t
) 0, SEEK_SET
) == -1) return -1;
1604 /* Can reach this point normally. */
1605 if (lseek(device
, (off_t
) offset
* SECTOR_SIZE
, SEEK_SET
) == -1)
1611 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1612 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1616 if (offset
>= (LONG_MAX
/ SECTOR_SIZE
- 1)) {
1617 /* Restore partition base and size. */
1619 if (ioctl(device
, DIOCSETP
, &geom0
) < 0) return -1;
1625 void m_read(int ev
, object_t
*op
)
1626 /* Read the partition table from the current device. */
1629 struct part_entry
*pe
;
1631 if (ev
!= 'r' || device
>= 0) return;
1633 /* Open() may cause kernel messages: */
1637 if (((device
= open(curdev
->name
, mode
= O_RDWR
, 0666)) < 0
1639 || (device
= open(curdev
->name
, mode
= O_RDONLY
)) < 0))
1642 printf("%s: %s", curdev
->name
, strerror(errno
));
1644 if (device
>= 0) { close(device
); device
= -1; }
1648 /* Assume up to five lines of kernel messages. */
1652 if (mode
== O_RDONLY
) {
1654 printf("%s: Readonly", curdev
->name
);
1657 memset(bootblock
, 0, sizeof(bootblock
));
1659 n
= boot_readwrite(0);
1661 if (n
<= 0) stat_start(1);
1663 printf("%s: %s", curdev
->name
, strerror(errno
));
1667 if (n
< SECTOR_SIZE
) printf("%s: Unexpected EOF", curdev
->subname
);
1668 if (n
<= 0) stat_end(5);
1670 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1672 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1673 NR_PARTITIONS
* sizeof(table
[1]));
1674 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1675 if ((table
[i
].bootind
& ~ACTIVE_FLAG
) != 0) break;
1677 if (i
<= NR_PARTITIONS
|| bootblock
[510] != 0x55
1678 || bootblock
[511] != 0xAA) {
1679 /* Invalid boot block, install bootstrap, wipe partition table.
1681 memset(bootblock
, 0, sizeof(bootblock
));
1682 installboot(bootblock
, MASTERBOOT
);
1683 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1685 printf("%s: Invalid partition table (reset)", curdev
->subname
);
1689 /* Fix an extended partition table up to something mere mortals can
1690 * understand. Record already defined partitions.
1692 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1694 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1695 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1696 existing
[i
]= pe
->sysind
!= NO_PART
;
1701 /* Warn about grave dangers ahead. */
1704 printf("Warning: You are in an extended partition.");
1709 void m_write(int ev
, object_t
*op
)
1710 /* Write the partition table back if modified. */
1713 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1715 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1716 if (device
< 0) { dirty
= 0; return; }
1720 printf("%s is not changed, or has already been written",
1727 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1728 /* Invalid boot block, warn user. */
1730 printf("Warning: About to write a new table on %s",
1735 /* Will this stop the luser? Probably not... */
1737 printf("You have changed an extended partition. Bad Idea.");
1741 putstr("Save partition table? (y/n) ");
1744 while ((c
= getchar()) != 'y' && c
!= 'n' && c
!= ctrl('?')) {}
1746 if (c
== ctrl('?')) putstr("DEL"); else putchr(c
);
1748 if (c
== 'n' && ev
== E_WRITE
) dirty
= 0;
1749 if (c
!= 'y') return;
1751 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1752 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1753 if (pe
->sysind
== NO_PART
) {
1754 memset(pe
, 0, sizeof(*pe
));
1756 abs2dos(&pe
->start_head
, pe
->lowsec
);
1757 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1759 /* Fear and loathing time: */
1761 pe
->lowsec
-= ext_part(pe
->sysind
)
1765 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1766 bootblock
[510]= 0x55;
1767 bootblock
[511]= 0xAA;
1769 if (boot_readwrite(1) < 0) {
1771 printf("%s: %s", curdev
->name
, strerror(errno
));
1778 void m_shell(int ev
, object_t
*op
)
1779 /* Shell escape, to do calculations for instance. */
1782 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1784 if (ev
!= 's') return;
1789 switch (pid
= fork()) {
1792 printf("can't fork: %s\n", strerror(errno
));
1796 if (device
>= 0) (void) close(device
);
1797 execl("/bin/sh", "sh", (char *) nil
);
1800 printf("/bin/sh: %s\n", strerror(errno
));
1804 sigint
= signal(SIGINT
, SIG_IGN
);
1805 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1806 sigterm
= signal(SIGTERM
, SIG_IGN
);
1807 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1808 (void) signal(SIGINT
, sigint
);
1809 (void) signal(SIGQUIT
, sigquit
);
1810 (void) signal(SIGTERM
, sigterm
);
1815 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1816 stat_start(0); /* Match the stat_start in the child. */
1818 event(ctrl('L'), op
);
1821 void m_dump(int ev
, object_t
*op
)
1822 /* Raw dump of the partition table. */
1824 struct part_entry table
[NR_PARTITIONS
], *pe
;
1828 if (ev
!= 'p' || device
< 0) return;
1830 memcpy(table
, bootblock
+PART_TABLE_OFF
,
1831 NR_PARTITIONS
* sizeof(table
[0]));
1832 for (i
= 0; i
< NR_PARTITIONS
; i
++) {
1835 dos2chs(&pe
->start_head
, chs
);
1836 printf("%2d%c %02X%15d%5d%4d",
1838 pe
->bootind
& ACTIVE_FLAG
? '*' : ' ',
1840 chs
[0], chs
[1], chs
[2]);
1841 dos2chs(&pe
->last_head
, chs
);
1842 printf("%6d%5d%4d%10lu%10ld%9lu",
1843 chs
[0], chs
[1], chs
[2],
1845 howend
== SIZE
? pe
->size
: pe
->size
+ pe
->lowsec
- 1,
1850 printf("(Raw dump of the original %.40s table)",
1857 void m_quit(int ev
, object_t
*op
)
1858 /* Write the partition table if modified and exit. */
1860 if (ev
!= 'q' && ev
!= 'x') return;
1864 if (dirty
) event(E_WRITE
, op
);
1865 if (dirty
) quitting
= 0;
1868 void m_help(int ev
, object_t
*op
)
1869 /* For people without a clue; let's hope they can find the '?' key. */
1871 static struct help
{
1875 { "? !", "This help / more advice!" },
1876 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1877 { "0-9 (a-f)", "Enter value" },
1878 { "hjkl (arrow keys)", "Move around" },
1879 { "CTRL-K CTRL-J", "Move entry up/down" },
1880 { "CTRL-L", "Redraw screen" },
1881 { ">", "Start a subpartition table" },
1882 { "<", "Back to the primary partition table" },
1883 { "m", "Cycle through magic values" },
1884 { "spacebar", "Show \"Size\" or \"Last\"" },
1885 { "r w", "Read/write partition table" },
1886 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1887 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1889 static char *advice
[] = {
1890 "* Choose a disk with '+' and '-', then hit 'r'.",
1891 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1892 "* To make a new partition: Move over to the Size or Kb field of an unused",
1893 " partition and type the size. Hit the 'm' key to pad the partition out to",
1894 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1895 " You can hit 'm' more than once on a base or size field to see several",
1896 " interesting values go by. Note: Other Operating Systems can be picky about",
1897 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1898 " head or sector numbers.",
1899 "* To reuse a partition: Change the type to MINIX.",
1900 "* To delete a partition: Type a zero in the hex Type field.",
1901 "* To make a partition active: Type '+' in the Num field.",
1902 "* To study the list of keys: Type '?'.",
1908 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1910 printf("%-25s - %s", hp
->keys
, hp
->what
);
1914 putstr("Things like ");
1915 putstr(t_so
); putstr("this"); putstr(t_se
);
1916 putstr(" must be checked, but ");
1917 putstr(t_md
); putstr("this"); putstr(t_me
);
1918 putstr(" is not really a problem");
1924 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1932 void event(int ev
, object_t
*op
)
1933 /* Simply call all modifiers for an event, each one knows when to act. */
1938 m_orientation(ev
, op
);
1955 /* Get a single keypress. Translate compound keypresses (arrow keys) to
1956 * their simpler equivalents.
1963 set_cursor(curobj
->row
, curobj
->col
);
1967 if (read(0, &ch
, sizeof(ch
)) < 0) fatal("stdin");
1968 c
= (unsigned char) ch
;
1972 case ctrl('['): esc
= 1; break;
1973 case '_': c
= '-'; break;
1974 case '=': c
= '+'; break;
1978 esc
= c
== '[' ? 2 : 0;
1982 case 'D': c
= 'h'; break;
1983 case 'B': c
= 'j'; break;
1984 case 'A': c
= 'k'; break;
1985 case 'C': c
= 'l'; break;
1986 case 'H': c
= 'H'; break;
1988 case 'S': c
= '-'; break;
1990 case 'T': c
= '+'; break;
1999 case ctrl('B'): c
= 'h'; break;
2000 case ctrl('N'): c
= 'j'; break;
2001 case ctrl('P'): c
= 'k'; break;
2002 case ctrl('F'): c
= 'l'; break;
2009 /* Get keypress, handle event, display results, reset screen, ad infinitum. */
2024 int main(int argc
, char **argv
)
2028 struct part_entry
*pe
;
2030 /* Define a few objects to show on the screen. First text: */
2031 op
= newobject(O_INFO
, 0, 0, 2, 19);
2032 op
= newobject(O_TEXT
, 0, 0, 22, 13); op
->text
= "----first----";
2033 op
= newobject(O_TEXT
, 0, 0, 37, 13); op
->text
= "--geom/last--";
2034 op
= newobject(O_TEXT
, 0, 0, 52, 18); op
->text
= "------sectors-----";
2035 op
= newobject(O_TEXT
, 0, 1, 4, 6); op
->text
= "Device";
2036 op
= newobject(O_TEXT
, 0, 1, 23, 12); op
->text
= "Cyl Head Sec";
2037 op
= newobject(O_TEXT
, 0, 1, 38, 12); op
->text
= "Cyl Head Sec";
2038 op
= newobject(O_TEXT
, 0, 1, 56, 4); op
->text
= "Base";
2039 op
= newobject(O_TEXT
, 0, 1, 66, 4); op
->text
= size_last
;
2040 op
= newobject(O_TEXT
, 0, 1, 78, 2); op
->text
= "Kb";
2041 op
= newobject(O_TEXT
, 0, 4, 0, 15); op
->text
= "Num Sort Type";
2043 /* The device is the current object: */
2044 curobj
= newobject(O_DEV
, OF_MOD
, 2, 4, 15);
2045 op
= newobject(O_SUB
, 0, 3, 4, 15);
2048 op
= newobject(O_CYL
, OF_MOD
, 2, 40, 5); op
->entry
= &table
[0];
2049 op
= newobject(O_HEAD
, OF_MOD
, 2, 45, 3); op
->entry
= &table
[0];
2050 op
= newobject(O_SEC
, OF_MOD
, 2, 49, 2); op
->entry
= &table
[0];
2052 /* Objects for the device: */
2053 op
= newobject(O_SCYL
, 0, 3, 25, 5); op
->entry
= &table
[0];
2054 op
= newobject(O_SHEAD
, 0, 3, 30, 3); op
->entry
= &table
[0];
2055 op
= newobject(O_SSEC
, 0, 3, 34, 2); op
->entry
= &table
[0];
2056 op
= newobject(O_LCYL
, 0, 3, 40, 5); op
->entry
= &table
[0];
2057 op
= newobject(O_LHEAD
, 0, 3, 45, 3); op
->entry
= &table
[0];
2058 op
= newobject(O_LSEC
, 0, 3, 49, 2); op
->entry
= &table
[0];
2059 op
= newobject(O_BASE
, 0, 3, 59, 9); op
->entry
= &table
[0];
2060 op
= newobject(O_SIZE
, 0, 3, 69, 9); op
->entry
= &table
[0];
2061 op
= newobject(O_KB
, 0, 3, 79, 9); op
->entry
= &table
[0];
2063 /* Objects for each partition: */
2064 for (r
= 5, pe
= table
+1; pe
<= table
+NR_PARTITIONS
; r
++, pe
++) {
2065 op
= newobject(O_NUM
, OF_MOD
, r
, 1, 2); op
->entry
= pe
;
2066 op
= newobject(O_SORT
, 0, r
, 5, 2); op
->entry
= pe
;
2067 op
= newobject(O_TYPHEX
, OF_MOD
, r
, 10, 2); op
->entry
= pe
;
2068 op
= newobject(O_TYPTXT
, OF_MOD
, r
, 12, 9); op
->entry
= pe
;
2069 op
= newobject(O_SCYL
, OF_MOD
, r
, 25, 5); op
->entry
= pe
;
2070 op
= newobject(O_SHEAD
, OF_MOD
, r
, 30, 3); op
->entry
= pe
;
2071 op
= newobject(O_SSEC
, OF_MOD
, r
, 34, 2); op
->entry
= pe
;
2072 op
= newobject(O_LCYL
, OF_MOD
, r
, 40, 5); op
->entry
= pe
;
2073 op
= newobject(O_LHEAD
, OF_MOD
, r
, 45, 3); op
->entry
= pe
;
2074 op
= newobject(O_LSEC
, OF_MOD
, r
, 49, 2); op
->entry
= pe
;
2075 op
= newobject(O_BASE
, OF_MOD
, r
, 59, 9); op
->entry
= pe
;
2076 op
= newobject(O_SIZE
, OF_MOD
, r
, 69, 9); op
->entry
= pe
;
2077 op
= newobject(O_KB
, OF_MOD
, r
, 79, 9); op
->entry
= pe
;
2080 for (i
= 1; i
< argc
; i
++) newdevice(argv
[i
], 0);
2082 if (firstdev
== nil
) {
2089 if (firstdev
!= nil
) {