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 if (t
== -1) strcpy(op
->value
, "-1");
856 else sprintf(op
->value
, "%lu", t
% sectors
);
857 if (!aligned(t
+ 1, sectors
)) op
->flags
|= OF_ODD
;
860 /* Partition's base sector. */
861 sprintf(op
->value
, "%lu", entry2base(pe
));
862 if (pe
->sysind
!= NO_PART
&& pe
!= &table
[0]
863 && (pe
->lowsec
<= table
[0].lowsec
|| overlap(pe
->lowsec
)))
867 /* Size of partitition in sectors. */
868 t
= howend
== SIZE
? entry2size(pe
) : entry2last(pe
);
869 sprintf(op
->value
, "%lu", pe
->sysind
== NO_PART
? 0 : t
);
870 if (pe
->sysind
!= NO_PART
&& (pe
->size
== 0
871 || pe
->lowsec
+ pe
->size
> table
[0].lowsec
+ table
[0].size
872 || overlap(pe
->lowsec
+ pe
->size
)))
876 /* Size of partitition in kilobytes. */
877 sprintf(op
->value
, "%lu", entry2size(pe
) / 2);
880 sprintf(op
->value
, "?? %d ??", op
->type
);
883 if (device
< 0 && computed(op
->type
)) strcpy(op
->value
, "?");
885 /* If a value overflows the print field then show a blank
886 * reverse video field.
888 if ((n
= strlen(op
->value
)) > op
->len
) {
893 /* Right or left justified? */
894 if (rjust(op
->type
)) {
895 memmove(op
->value
+ (op
->len
- n
), op
->value
, n
);
896 memset(op
->value
, ' ', op
->len
- n
);
898 memset(op
->value
+ n
, ' ', op
->len
- n
);
900 op
->value
[(int) op
->len
]= 0;
902 if ((op
->flags
& (OF_ODD
| OF_BAD
)) == (oldflags
& (OF_ODD
| OF_BAD
))
903 && strcmp(op
->value
, oldvalue
) == 0) {
904 /* The value did not change. */
908 set_cursor(op
->row
, rjust(op
->type
) ? op
->col
- (op
->len
-1) : op
->col
);
910 if (op
->flags
& OF_BAD
) tputs(t_so
, 1, putchr
);
912 if (op
->flags
& OF_ODD
) tputs(t_md
, 1, putchr
);
914 if (op
->flags
& OF_BAD
) tputs(t_se
, 1, putchr
);
916 if (op
->flags
& OF_ODD
) tputs(t_me
, 1, putchr
);
920 /* Repaint all objects that changed. */
924 for (op
= world
; op
!= nil
; op
= op
->next
) print(op
);
927 int typing
; /* Set if a digit has been typed to set a value. */
928 int magic
; /* Changes when using the magic key. */
930 void event(int ev
, object_t
*op
);
932 void m_redraw(int ev
, object_t
*op
)
933 /* Redraw the screen. */
937 if (ev
!= ctrl('L')) return;
940 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) op2
->value
[0]= 0;
943 void m_toggle(int ev
, object_t
*op
)
944 /* Toggle between the driver and alternate geometry. */
948 if (ev
!= 'X') return;
949 if (alt_cyls
== cylinders
&& alt_heads
== heads
&& alt_secs
== sectors
)
952 t
= cylinders
; cylinders
= alt_cyls
; alt_cyls
= t
;
953 t
= heads
; heads
= alt_heads
; alt_heads
= t
;
954 t
= sectors
; sectors
= alt_secs
; alt_secs
= t
;
959 char size_last
[]= "Size";
961 void m_orientation(int ev
, object_t
*op
)
963 if (ev
!= ' ') return;
968 strcpy(size_last
, "Last");
972 strcpy(size_last
, "Size");
976 void m_move(int ev
, object_t
*op
)
977 /* Move to the nearest modifiably object in the intended direction. Objects
978 * on the same row or column are really near.
981 object_t
*near
, *op2
;
982 unsigned dist
, d2
, dr
, dc
;
984 if (ev
!= 'h' && ev
!= 'j' && ev
!= 'k' && ev
!= 'l' && ev
!= 'H')
988 /* No device open? Then try to read first. */
990 if (device
< 0) return;
996 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
997 if (op2
== op
|| !(op2
->flags
& OF_MOD
)) continue;
999 dr
= abs(op2
->row
- op
->row
);
1000 dc
= abs(op2
->col
- op
->col
);
1002 d2
= 25*dr
*dr
+ dc
*dc
;
1003 if (op2
->row
!= op
->row
&& op2
->col
!= op
->col
) d2
+= 1000;
1006 case 'h': /* Left */
1007 if (op2
->col
>= op
->col
) d2
= -1;
1009 case 'j': /* Down */
1010 if (op2
->row
<= op
->row
) d2
= -1;
1013 if (op2
->row
>= op
->row
) d2
= -1;
1015 case 'l': /* Right */
1016 if (op2
->col
<= op
->col
) d2
= -1;
1018 case 'H': /* Home */
1019 if (op2
->type
== O_DEV
) d2
= 0;
1021 if (d2
< dist
) { near
= op2
; dist
= d2
; }
1023 if (near
!= op
) event(E_LEAVE
, op
);
1024 event(E_ENTER
, near
);
1027 void m_updown(int ev
, object_t
*op
)
1028 /* Move a partition table entry up or down. */
1031 struct part_entry tmp
;
1034 if (ev
!= ctrl('K') && ev
!= ctrl('J')) return;
1035 if (op
->entry
== nil
) return;
1037 i
= op
->entry
- table
;
1038 if (ev
== ctrl('K')) {
1042 if (i
>= NR_PARTITIONS
) return;
1046 tmp
= table
[i
]; table
[i
]= table
[j
]; table
[j
]= tmp
;
1047 tmpx
= existing
[i
]; existing
[i
]= existing
[j
]; existing
[j
]= tmpx
;
1050 event(ev
== ctrl('K') ? 'k' : 'j', op
);
1053 void m_enter(int ev
, object_t
*op
)
1054 /* We've moved onto this object. */
1056 if (ev
!= E_ENTER
&& ev
!= ' ' && ev
!= '<' && ev
!= '>' && ev
!= 'X')
1063 void m_leave(int ev
, object_t
*op
)
1064 /* About to leave this object. */
1066 if (ev
!= E_LEAVE
) return;
1069 int within(unsigned *var
, unsigned low
, unsigned value
, unsigned high
)
1070 /* Only set *var to value if it looks reasonable. */
1072 if (low
<= value
&& value
<= high
) {
1079 int lwithin(unsigned long *var
, unsigned long low
, unsigned long value
,
1082 if (low
<= value
&& value
<= high
) {
1089 int nextdevice(object_t
*op
, int delta
)
1090 /* Select the next or previous device from the device list. */
1094 if (offset
!= 0) return 0;
1095 if (dirty
) event(E_WRITE
, op
);
1096 if (dirty
) return 0;
1099 (void) close(device
);
1107 curdev
= curdev
->prev
;
1108 while (delta
< -1 && major(curdev
->rdev
) == major(rdev
)
1109 && curdev
->rdev
< rdev
);
1112 curdev
= curdev
->next
;
1113 while (delta
> 1 && major(curdev
->rdev
) == major(rdev
)
1114 && curdev
->rdev
> rdev
);
1119 void check_ind(struct part_entry
*pe
)
1120 /* If there are no other partitions then make this new one active. */
1122 struct part_entry
*pe2
;
1124 if (pe
->sysind
!= NO_PART
) return;
1126 for (pe2
= table
+ 1; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++)
1127 if (pe2
->sysind
!= NO_PART
|| pe2
->bootind
& ACTIVE_FLAG
) break;
1129 if (pe2
== table
+ 1 + NR_PARTITIONS
) pe
->bootind
= ACTIVE_FLAG
;
1132 int check_existing(struct part_entry
*pe
)
1133 /* Check and if not ask if an existing partition may be modified. */
1135 static int expert
= 0;
1138 if (expert
|| pe
== nil
|| !existing
[pe
- table
]) return 1;
1141 putstr("Do you wish to modify existing partitions? (y/n) ");
1143 while ((c
= getchar()) != 'y' && c
!= 'n') {}
1146 return (expert
= (c
== 'y'));
1149 void m_modify(int ev
, object_t
*op
)
1150 /* Increment, decrement, set, or toggle the value of an object, using
1151 * arithmetic tricks the author doesn't understand either.
1155 struct part_entry
*pe
= op
->entry
;
1158 unsigned long surplus
;
1159 int radix
= op
->type
== O_TYPHEX
? 0x10 : 10;
1162 if (device
< 0 && op
->type
!= O_DEV
) return;
1166 mul
= radix
; delta
= -1; typing
= 0;
1169 mul
= radix
; delta
= 1; typing
= 0;
1172 if (!typing
) return;
1179 if ('0' <= ev
&& ev
<= '9')
1182 if (radix
== 0x10 && 'a' <= ev
&& ev
<= 'f')
1183 delta
= ev
- 'a' + 10;
1185 if (radix
== 0x10 && 'A' <= ev
&& ev
<= 'F')
1186 delta
= ev
- 'A' + 10;
1190 mul
= typing
? radix
*radix
: 0;
1195 if (!check_existing(pe
)) return;
1199 if (ev
!= '-' && ev
!= '+') return;
1200 if (!nextdevice(op
, delta
)) return;
1203 if (!within(&cylinders
, 1,
1204 cylinders
* mul
/ radix
+ delta
, 1024)) return;
1208 if (!within(&heads
, 1, heads
* mul
/ radix
+ delta
, 255))
1213 if (!within(§ors
, 1, sectors
* mul
/ radix
+ delta
, 63))
1218 if (ev
!= '-' && ev
!= '+') return;
1219 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1220 if (op2
->type
== O_NUM
&& ev
== '+')
1221 op2
->entry
->bootind
= 0;
1223 op
->entry
->bootind
= ev
== '+' ? ACTIVE_FLAG
: 0;
1227 pe
->sysind
= pe
->sysind
* mul
/ radix
+ delta
;
1230 if (ev
!= '-' && ev
!= '+') return;
1232 pe
->sysind
= round_sysind(pe
->sysind
, delta
);
1239 if (op
->type
!= O_SCYL
&& ev
!= '-' && ev
!= '+') return;
1241 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1244 if (!lwithin(&t
, 0L,
1245 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1247 if (howend
== LAST
|| op
->type
!= O_BASE
)
1248 pe
->size
-= t
- pe
->lowsec
;
1251 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1258 if (op
->type
!= O_LCYL
&& ev
!= '-' && ev
!= '+') return;
1260 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1261 t
= pe
->lowsec
+ pe
->size
- 1 + level
;
1262 surplus
= t
% level
- mul
/ radix
* level
;
1263 if (!lwithin(&t
, 0L,
1264 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1266 pe
->size
= t
- pe
->lowsec
+ 1;
1268 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1272 if (mul
== 0) pe
->size
= 0; /* new value, no surplus */
1274 if (pe
->sysind
== NO_PART
) {
1275 if (op
->type
== O_KB
|| howend
== SIZE
) {
1276 /* First let loose magic to set the base. */
1283 memset(pe
, 0, sizeof(*pe
));
1285 t
= (op
->type
== O_KB
|| howend
== SIZE
) ? pe
->size
1286 : pe
->lowsec
+ pe
->size
- 1;
1288 if (!lwithin(&t
, 0L,
1289 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1291 pe
->size
= (op
->type
== O_KB
|| howend
== SIZE
) ? t
:
1294 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1300 /* The order among the entries may have changed. */
1305 unsigned long spell
[3 + 4 * (1+NR_PARTITIONS
)];
1309 void newspell(unsigned long charm
)
1310 /* Add a new spell, descending order for the base, ascending for the size. */
1314 if (charm
- table
[0].lowsec
> table
[0].size
) return;
1316 for (i
= 0; i
< nspells
; i
++) {
1317 if (charm
== spell
[i
]) return; /* duplicate */
1319 if (touching
== O_BASE
) {
1320 if (charm
== table
[0].lowsec
+ table
[0].size
) return;
1321 if ((spell
[0] - charm
) < (spell
[0] - spell
[i
])) break;
1323 if (charm
== table
[0].lowsec
) return;
1324 if ((charm
- spell
[0]) < (spell
[i
] - spell
[0])) break;
1327 for (j
= ++nspells
; j
> i
; j
--) spell
[j
]= spell
[j
-1];
1331 void m_magic(int ev
, object_t
*op
)
1332 /* Apply magic onto a base or size number. */
1334 struct part_entry
*pe
= op
->entry
, *pe2
;
1335 int rough
= (offset
!= 0 && extbase
== 0);
1337 if (ev
!= 'm' || device
< 0) return;
1340 if (!check_existing(pe
)) return;
1343 /* See what magic we can let loose on this value. */
1346 /* First spell, the current value. */
1349 case O_SHEAD
: /* Start of partition. */
1353 spell
[0]= pe
->lowsec
;
1357 case O_LSEC
: /* End of partition. */
1361 spell
[0]= pe
->lowsec
+ pe
->size
;
1366 if (pe
->sysind
== NO_PART
) {
1367 memset(pe
, 0, sizeof(*pe
));
1369 pe
->sysind
= MINIX_PART
;
1371 if (touching
== O_SIZE
) {
1372 /* First let loose magic on the base. */
1375 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1376 if (op2
->row
== op
->row
&&
1377 op2
->type
== O_BASE
) {
1386 /* Avoid the first sector on the device. */
1387 if (spell
[0] == table
[0].lowsec
) newspell(spell
[0] + 1);
1389 /* Further interesting values are the the bases of other
1390 * partitions or their ends.
1392 for (pe2
= table
; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++) {
1393 if (pe2
== pe
|| pe2
->sysind
== NO_PART
) continue;
1394 if (pe2
->lowsec
== table
[0].lowsec
)
1395 newspell(table
[0].lowsec
+ 1);
1397 newspell(pe2
->lowsec
);
1398 newspell(pe2
->lowsec
+ pe2
->size
);
1399 if (touching
== O_BASE
&& howend
== SIZE
) {
1400 newspell(pe2
->lowsec
- pe
->size
);
1401 newspell(pe2
->lowsec
+ pe2
->size
- pe
->size
);
1403 if (pe2
->lowsec
% sectors
!= 0) rough
= 1;
1405 /* Present values rounded up to the next cylinder unless
1406 * the table is already a mess. Use "start + 1 track" instead
1407 * of "start + 1 cylinder". Also add the end of the last
1411 unsigned long n
= spell
[0];
1412 if (n
== table
[0].lowsec
) n
++;
1413 n
= (n
+ sectors
- 1) / sectors
* sectors
;
1414 if (n
!= table
[0].lowsec
+ sectors
)
1415 n
= (n
+ secpcyl
- 1) / secpcyl
* secpcyl
;
1417 if (touching
== O_SIZE
)
1418 newspell(table
[0].size
/ secpcyl
* secpcyl
);
1421 /* Magic has been applied, a spell needs to be chosen. */
1423 if (++magic
== nspells
) magic
= 0;
1425 if (touching
== O_BASE
) {
1426 if (howend
== LAST
) pe
->size
-= spell
[magic
] - pe
->lowsec
;
1427 pe
->lowsec
= spell
[magic
];
1429 pe
->size
= spell
[magic
] - pe
->lowsec
;
1431 /* The order among the entries may have changed. */
1436 typedef struct diving
{
1438 struct part_entry old0
;
1440 parttype_t oldparttype
;
1441 unsigned long oldoffset
;
1442 unsigned long oldextbase
;
1445 diving_t
*diving
= nil
;
1447 void m_in(int ev
, object_t
*op
)
1448 /* Go down into a primary or extended partition. */
1451 struct part_entry
*pe
= op
->entry
, ext
;
1454 if (ev
!= '>' || device
< 0 || pe
== nil
|| pe
== &table
[0]
1455 || (!(pe
->sysind
== MINIX_PART
&& offset
== 0)
1456 && !ext_part(pe
->sysind
))
1457 || pe
->size
== 0) return;
1460 if (extbase
!= 0) ext
.size
= extbase
+ extsize
- ext
.lowsec
;
1462 if (dirty
) event(E_WRITE
, op
);
1464 if (device
>= 0) { close(device
); device
= -1; }
1466 newdiv
= alloc(sizeof(*newdiv
));
1467 newdiv
->old0
= table
[0];
1468 newdiv
->oldsubname
= curdev
->subname
;
1469 newdiv
->oldparttype
= curdev
->parttype
;
1470 newdiv
->oldoffset
= offset
;
1471 newdiv
->oldextbase
= extbase
;
1477 n
= strlen(diving
->oldsubname
);
1478 curdev
->subname
= alloc((n
+ 3) * sizeof(curdev
->subname
[0]));
1479 strcpy(curdev
->subname
, diving
->oldsubname
);
1480 curdev
->subname
[n
++]= ':';
1481 curdev
->subname
[n
++]= '0' + (pe
- table
- 1);
1482 curdev
->subname
[n
]= 0;
1484 curdev
->parttype
= curdev
->parttype
== PRIMARY
? SUBPART
: DUNNO
;
1486 if (ext_part(ext
.sysind
) && extbase
== 0) {
1487 extbase
= ext
.lowsec
;
1489 curdev
->parttype
= DUNNO
;
1496 void m_out(int ev
, object_t
*op
)
1497 /* Go up from an extended or subpartition table to its enclosing. */
1501 if (ev
!= '<' || diving
== nil
) return;
1503 if (dirty
) event(E_WRITE
, op
);
1505 if (device
>= 0) { close(device
); device
= -1; }
1510 table
[0]= olddiv
->old0
;
1512 free(curdev
->subname
);
1513 curdev
->subname
= olddiv
->oldsubname
;
1515 curdev
->parttype
= olddiv
->oldparttype
;
1516 offset
= olddiv
->oldoffset
;
1517 extbase
= olddiv
->oldextbase
;
1522 if (diving
== nil
) submerged
= 0; /* We surfaced. */
1525 void installboot(unsigned char *bootblock
, char *masterboot
)
1526 /* Install code from a master bootstrap into a boot block. */
1529 unsigned char buf
[SECTOR_SIZE
];
1533 if ((mfp
= fopen(masterboot
, "r")) == nil
) {
1534 err
= strerror(errno
);
1538 n
= fread(buf
, sizeof(char), SECTOR_SIZE
, mfp
);
1540 err
= strerror(errno
);
1545 err
= "Is probably not a boot sector, too small";
1549 else if (n
< SECTOR_SIZE
&& n
> PART_TABLE_OFF
) {
1550 /* if only code, it cannot override partition table */
1551 err
= "Does not fit in a boot sector";
1555 else if (n
== SECTOR_SIZE
) {
1556 if (buf
[510] != 0x55 || buf
[511] != 0xaa) {
1557 err
= "Is not a boot sector (bad magic)";
1564 if (n
> PART_TABLE_OFF
) {
1565 err
= "Does not fit in a boot sector";
1570 memcpy(bootblock
, buf
, n
);
1573 /* Bootstrap installed. */
1578 printf("%s: %s", masterboot
, err
);
1582 ssize_t
boot_readwrite(int rw
)
1583 /* Read (0) or write (1) the boot sector. */
1587 if (lseek64(device
, (u64_t
) offset
* SECTOR_SIZE
, SEEK_SET
, NULL
) < 0)
1591 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1592 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1598 void m_read(int ev
, object_t
*op
)
1599 /* Read the partition table from the current device. */
1602 struct part_entry
*pe
;
1604 if (ev
!= 'r' || device
>= 0) return;
1606 /* Open() may cause kernel messages: */
1610 if (((device
= open(curdev
->name
, mode
= O_RDWR
, 0666)) < 0
1612 || (device
= open(curdev
->name
, mode
= O_RDONLY
)) < 0))
1615 printf("%s: %s", curdev
->name
, strerror(errno
));
1617 if (device
>= 0) { close(device
); device
= -1; }
1621 /* Assume up to five lines of kernel messages. */
1625 if (mode
== O_RDONLY
) {
1627 printf("%s: Readonly", curdev
->name
);
1630 memset(bootblock
, 0, sizeof(bootblock
));
1632 n
= boot_readwrite(0);
1634 if (n
<= 0) stat_start(1);
1636 printf("%s: %s", curdev
->name
, strerror(errno
));
1640 if (n
< SECTOR_SIZE
) printf("%s: Unexpected EOF", curdev
->subname
);
1641 if (n
<= 0) stat_end(5);
1643 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1645 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1646 NR_PARTITIONS
* sizeof(table
[1]));
1647 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1648 if ((table
[i
].bootind
& ~ACTIVE_FLAG
) != 0) break;
1650 if (i
<= NR_PARTITIONS
|| bootblock
[510] != 0x55
1651 || bootblock
[511] != 0xAA) {
1652 /* Invalid boot block, install bootstrap, wipe partition table.
1654 memset(bootblock
, 0, sizeof(bootblock
));
1655 installboot(bootblock
, MASTERBOOT
);
1656 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1658 printf("%s: Invalid partition table (reset)", curdev
->subname
);
1662 /* Fix an extended partition table up to something mere mortals can
1663 * understand. Record already defined partitions.
1665 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1667 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1668 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1669 existing
[i
]= pe
->sysind
!= NO_PART
;
1674 /* Warn about grave dangers ahead. */
1677 printf("Warning: You are in an extended partition.");
1682 void m_write(int ev
, object_t
*op
)
1683 /* Write the partition table back if modified. */
1686 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1688 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1689 if (device
< 0) { dirty
= 0; return; }
1693 printf("%s is not changed, or has already been written",
1700 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1701 /* Invalid boot block, warn user. */
1703 printf("Warning: About to write a new table on %s",
1708 /* Will this stop the luser? Probably not... */
1710 printf("You have changed an extended partition. Bad Idea.");
1714 putstr("Save partition table? (y/n) ");
1717 while ((c
= getchar()) != 'y' && c
!= 'n' && c
!= ctrl('?')) {}
1719 if (c
== ctrl('?')) putstr("DEL"); else putchr(c
);
1721 if (c
== 'n' && ev
== E_WRITE
) dirty
= 0;
1722 if (c
!= 'y') return;
1724 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1725 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1726 if (pe
->sysind
== NO_PART
) {
1727 memset(pe
, 0, sizeof(*pe
));
1729 abs2dos(&pe
->start_head
, pe
->lowsec
);
1730 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1732 /* Fear and loathing time: */
1734 pe
->lowsec
-= ext_part(pe
->sysind
)
1738 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1739 bootblock
[510]= 0x55;
1740 bootblock
[511]= 0xAA;
1742 if (boot_readwrite(1) < 0) {
1744 printf("%s: %s", curdev
->name
, strerror(errno
));
1751 void m_shell(int ev
, object_t
*op
)
1752 /* Shell escape, to do calculations for instance. */
1755 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1757 if (ev
!= 's') return;
1762 switch (pid
= fork()) {
1765 printf("can't fork: %s\n", strerror(errno
));
1769 if (device
>= 0) (void) close(device
);
1770 execl("/bin/sh", "sh", (char *) nil
);
1773 printf("/bin/sh: %s\n", strerror(errno
));
1777 sigint
= signal(SIGINT
, SIG_IGN
);
1778 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1779 sigterm
= signal(SIGTERM
, SIG_IGN
);
1780 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1781 (void) signal(SIGINT
, sigint
);
1782 (void) signal(SIGQUIT
, sigquit
);
1783 (void) signal(SIGTERM
, sigterm
);
1788 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1789 stat_start(0); /* Match the stat_start in the child. */
1791 event(ctrl('L'), op
);
1794 void m_dump(int ev
, object_t
*op
)
1795 /* Raw dump of the partition table. */
1797 struct part_entry table
[NR_PARTITIONS
], *pe
;
1801 if (ev
!= 'p' || device
< 0) return;
1803 memcpy(table
, bootblock
+PART_TABLE_OFF
,
1804 NR_PARTITIONS
* sizeof(table
[0]));
1805 for (i
= 0; i
< NR_PARTITIONS
; i
++) {
1808 dos2chs(&pe
->start_head
, chs
);
1809 printf("%2d%c %02X%15d%5d%4d",
1811 pe
->bootind
& ACTIVE_FLAG
? '*' : ' ',
1813 chs
[0], chs
[1], chs
[2]);
1814 dos2chs(&pe
->last_head
, chs
);
1815 printf("%6d%5d%4d%10lu%10ld%9lu",
1816 chs
[0], chs
[1], chs
[2],
1818 howend
== SIZE
? pe
->size
: pe
->size
+ pe
->lowsec
- 1,
1823 printf("(Raw dump of the original %.40s table)",
1830 void m_quit(int ev
, object_t
*op
)
1831 /* Write the partition table if modified and exit. */
1833 if (ev
!= 'q' && ev
!= 'x') return;
1837 if (dirty
) event(E_WRITE
, op
);
1838 if (dirty
) quitting
= 0;
1841 void m_help(int ev
, object_t
*op
)
1842 /* For people without a clue; let's hope they can find the '?' key. */
1844 static struct help
{
1848 { "? !", "This help / more advice!" },
1849 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1850 { "0-9 (a-f)", "Enter value" },
1851 { "hjkl (arrow keys)", "Move around" },
1852 { "CTRL-K CTRL-J", "Move entry up/down" },
1853 { "CTRL-L", "Redraw screen" },
1854 { ">", "Start a subpartition table" },
1855 { "<", "Back to the primary partition table" },
1856 { "m", "Cycle through magic values" },
1857 { "spacebar", "Show \"Size\" or \"Last\"" },
1858 { "r w", "Read/write partition table" },
1859 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1860 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1862 static char *advice
[] = {
1863 "* Choose a disk with '+' and '-', then hit 'r'.",
1864 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1865 "* To make a new partition: Move over to the Size or Kb field of an unused",
1866 " partition and type the size. Hit the 'm' key to pad the partition out to",
1867 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1868 " You can hit 'm' more than once on a base or size field to see several",
1869 " interesting values go by. Note: Other Operating Systems can be picky about",
1870 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1871 " head or sector numbers.",
1872 "* To reuse a partition: Change the type to MINIX.",
1873 "* To delete a partition: Type a zero in the hex Type field.",
1874 "* To make a partition active: Type '+' in the Num field.",
1875 "* To study the list of keys: Type '?'.",
1881 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1883 printf("%-25s - %s", hp
->keys
, hp
->what
);
1887 putstr("Things like ");
1888 putstr(t_so
); putstr("this"); putstr(t_se
);
1889 putstr(" must be checked, but ");
1890 putstr(t_md
); putstr("this"); putstr(t_me
);
1891 putstr(" is not really a problem");
1897 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1905 void event(int ev
, object_t
*op
)
1906 /* Simply call all modifiers for an event, each one knows when to act. */
1911 m_orientation(ev
, op
);
1928 /* Get a single keypress. Translate compound keypresses (arrow keys) to
1929 * their simpler equivalents.
1936 set_cursor(curobj
->row
, curobj
->col
);
1940 if (read(0, &ch
, sizeof(ch
)) < 0) fatal("stdin");
1941 c
= (unsigned char) ch
;
1945 case ctrl('['): esc
= 1; break;
1946 case '_': c
= '-'; break;
1947 case '=': c
= '+'; break;
1951 esc
= c
== '[' ? 2 : 0;
1955 case 'D': c
= 'h'; break;
1956 case 'B': c
= 'j'; break;
1957 case 'A': c
= 'k'; break;
1958 case 'C': c
= 'l'; break;
1959 case 'H': c
= 'H'; break;
1961 case 'S': c
= '-'; break;
1963 case 'T': c
= '+'; break;
1972 case ctrl('B'): c
= 'h'; break;
1973 case ctrl('N'): c
= 'j'; break;
1974 case ctrl('P'): c
= 'k'; break;
1975 case ctrl('F'): c
= 'l'; break;
1982 /* Get keypress, handle event, display results, reset screen, ad infinitum. */
1997 int main(int argc
, char **argv
)
2001 struct part_entry
*pe
;
2003 /* Define a few objects to show on the screen. First text: */
2004 op
= newobject(O_INFO
, 0, 0, 2, 19);
2005 op
= newobject(O_TEXT
, 0, 0, 22, 13); op
->text
= "----first----";
2006 op
= newobject(O_TEXT
, 0, 0, 37, 13); op
->text
= "--geom/last--";
2007 op
= newobject(O_TEXT
, 0, 0, 52, 18); op
->text
= "------sectors-----";
2008 op
= newobject(O_TEXT
, 0, 1, 4, 6); op
->text
= "Device";
2009 op
= newobject(O_TEXT
, 0, 1, 23, 12); op
->text
= "Cyl Head Sec";
2010 op
= newobject(O_TEXT
, 0, 1, 38, 12); op
->text
= "Cyl Head Sec";
2011 op
= newobject(O_TEXT
, 0, 1, 56, 4); op
->text
= "Base";
2012 op
= newobject(O_TEXT
, 0, 1, 66, 4); op
->text
= size_last
;
2013 op
= newobject(O_TEXT
, 0, 1, 78, 2); op
->text
= "Kb";
2014 op
= newobject(O_TEXT
, 0, 4, 0, 15); op
->text
= "Num Sort Type";
2016 /* The device is the current object: */
2017 curobj
= newobject(O_DEV
, OF_MOD
, 2, 4, 15);
2018 op
= newobject(O_SUB
, 0, 3, 4, 15);
2021 op
= newobject(O_CYL
, OF_MOD
, 2, 40, 5); op
->entry
= &table
[0];
2022 op
= newobject(O_HEAD
, OF_MOD
, 2, 45, 3); op
->entry
= &table
[0];
2023 op
= newobject(O_SEC
, OF_MOD
, 2, 49, 2); op
->entry
= &table
[0];
2025 /* Objects for the device: */
2026 op
= newobject(O_SCYL
, 0, 3, 25, 5); op
->entry
= &table
[0];
2027 op
= newobject(O_SHEAD
, 0, 3, 30, 3); op
->entry
= &table
[0];
2028 op
= newobject(O_SSEC
, 0, 3, 34, 2); op
->entry
= &table
[0];
2029 op
= newobject(O_LCYL
, 0, 3, 40, 5); op
->entry
= &table
[0];
2030 op
= newobject(O_LHEAD
, 0, 3, 45, 3); op
->entry
= &table
[0];
2031 op
= newobject(O_LSEC
, 0, 3, 49, 2); op
->entry
= &table
[0];
2032 op
= newobject(O_BASE
, 0, 3, 59, 9); op
->entry
= &table
[0];
2033 op
= newobject(O_SIZE
, 0, 3, 69, 9); op
->entry
= &table
[0];
2034 op
= newobject(O_KB
, 0, 3, 79, 9); op
->entry
= &table
[0];
2036 /* Objects for each partition: */
2037 for (r
= 5, pe
= table
+1; pe
<= table
+NR_PARTITIONS
; r
++, pe
++) {
2038 op
= newobject(O_NUM
, OF_MOD
, r
, 1, 2); op
->entry
= pe
;
2039 op
= newobject(O_SORT
, 0, r
, 5, 2); op
->entry
= pe
;
2040 op
= newobject(O_TYPHEX
, OF_MOD
, r
, 10, 2); op
->entry
= pe
;
2041 op
= newobject(O_TYPTXT
, OF_MOD
, r
, 12, 9); op
->entry
= pe
;
2042 op
= newobject(O_SCYL
, OF_MOD
, r
, 25, 5); op
->entry
= pe
;
2043 op
= newobject(O_SHEAD
, OF_MOD
, r
, 30, 3); op
->entry
= pe
;
2044 op
= newobject(O_SSEC
, OF_MOD
, r
, 34, 2); op
->entry
= pe
;
2045 op
= newobject(O_LCYL
, OF_MOD
, r
, 40, 5); op
->entry
= pe
;
2046 op
= newobject(O_LHEAD
, OF_MOD
, r
, 45, 3); op
->entry
= pe
;
2047 op
= newobject(O_LSEC
, OF_MOD
, r
, 49, 2); op
->entry
= pe
;
2048 op
= newobject(O_BASE
, OF_MOD
, r
, 59, 9); op
->entry
= pe
;
2049 op
= newobject(O_SIZE
, OF_MOD
, r
, 69, 9); op
->entry
= pe
;
2050 op
= newobject(O_KB
, OF_MOD
, r
, 79, 9); op
->entry
= pe
;
2053 for (i
= 1; i
< argc
; i
++) newdevice(argv
[i
], 0);
2055 if (firstdev
== nil
) {
2062 if (firstdev
!= nil
) {