1 /* part 1.57 - Partition table editor Author: Kees J. Bot
3 * Needs about 22k heap+stack.
22 #include <sys/ioctl.h>
23 #include <minix/config.h>
24 #include <minix/const.h>
25 #include <minix/partition.h>
26 #include <minix/u64.h>
27 #include <machine/partition.h>
30 /* True if a partition is an extended partition. */
31 #define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
33 /* Minix master bootstrap code. */
34 static char MASTERBOOT
[] = "/usr/mdec/masterboot";
37 ----first---- --geom/last-- ------sectors-----
38 Device Cyl Head Sec Cyl Head Sec Base Size Kb
40 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521
42 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440
43 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142
44 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939
45 3 p3 00 None 0 0 0 0 0 -1 0 0 0
48 #define MAXSIZE 999999999L /* Will 1T be enough this year? */
49 #define SECTOR_SIZE 512
50 #define DEV_FD0 0x200 /* Device number of /dev/fd0 */
51 #define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */
53 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
54 #define arraylimit(a) ((a) + arraysize(a))
56 void report(const char *label
)
58 fprintf(stderr
, "part: %s: %s\n", label
, strerror(errno
));
61 void fatal(const char *label
)
67 struct termios termios
;
69 void save_ttyflags(void)
70 /* Save tty attributes for later restoration. */
72 if (tcgetattr(0, &termios
) < 0) fatal("");
75 void restore_ttyflags(void)
76 /* Reset the tty flags to how we got 'em. */
78 if (tcsetattr(0, TCSANOW
, &termios
) < 0) fatal("");
82 /* Set the terminal to raw mode, no signals, no echoing. */
84 struct termios rawterm
;
87 rawterm
.c_lflag
&= ~(ICANON
|ISIG
|ECHO
);
88 rawterm
.c_iflag
&= ~(ICRNL
);
89 if (tcsetattr(0, TCSANOW
, &rawterm
) < 0) fatal("");
92 #define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
94 char t_cd
[16], t_cm
[32], t_so
[16], t_se
[16], t_md
[16], t_me
[16];
99 /* Get terminal capabilities and set the tty to "editor" mode. */
102 static char termbuf
[1024];
105 if ((term
= getenv("TERM")) == nil
|| tgetent(termbuf
, term
) != 1) {
106 fprintf(stderr
, "part: Can't get terminal capabilities\n");
109 if (tgetstr("cd", (tp
= t_cd
, &tp
)) == nil
110 || tgetstr("cm", (tp
= t_cm
, &tp
)) == nil
) {
111 fprintf(stderr
, "part: This terminal is too dumb\n");
116 (void) tgetstr("so", (tp
= t_so
, &tp
));
117 (void) tgetstr("se", (tp
= t_se
, &tp
));
118 (void) tgetstr("md", (tp
= t_md
, &tp
));
119 (void) tgetstr("me", (tp
= t_me
, &tp
));
134 while ((c
= *s
++) != 0) putchr(c
);
137 void set_cursor(int row
, int col
)
139 tputs(tgoto(t_cm
, col
, row
), 1, putchr
);
142 int statusrow
= STATUSROW
;
146 void stat_start(int serious
)
147 /* Prepare for printing on a fresh status line, possibly highlighted. */
149 set_cursor(statusrow
++, 0);
150 tputs(t_cd
, 1, putchr
);
151 if (serious
) tputs(t_so
, 1, putchr
);
154 void stat_end(int ktl
)
155 /* Closing bracket for stat_start. Sets "keystrokes to live" of message. */
157 tputs(t_se
, 1, putchr
);
162 void stat_reset(void)
163 /* Reset the statusline pointer and clear old messages if expired. */
165 if (stat_ktl
> 0 && --stat_ktl
== 0) {
166 statusrow
= STATUSROW
;
169 if (need_help
&& statusrow
< (24-2)) {
170 if (statusrow
> STATUSROW
) stat_start(0);
173 "Type '+' or '-' to change, 'r' to read, '?' for more help, 'q' to exit");
175 statusrow
= STATUSROW
;
179 void clear_screen(void)
182 tputs(t_cd
, 1, putchr
);
188 /* Reset the tty to cooked mode. */
191 set_cursor(statusrow
, 0);
192 tputs(t_cd
, 1, putchr
);
195 void *alloc(size_t n
)
199 if ((m
= malloc(n
)) == nil
) { reset_tty(); fatal(""); }
204 #ifndef makedev /* Missing in sys/types.h */
205 #define minor(dev) (((dev) >> MINOR) & BYTE)
206 #define major(dev) (((dev) >> MAJOR) & BYTE)
207 #define makedev(major, minor) \
208 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
211 typedef enum parttype
{ DUNNO
, SUBPART
, PRIMARY
, FLOPPY
} parttype_t
;
213 typedef struct device
{
214 struct device
*next
, *prev
; /* Circular dequeue. */
215 dev_t rdev
; /* Device number (sorting only). */
216 char *name
; /* E.g. /dev/c0d0 */
217 char *subname
; /* E.g. /dev/c0d0:2 */
221 device_t
*firstdev
= nil
, *curdev
;
223 void newdevice(char *name
, int scanning
)
224 /* Add a device to the device list. If scanning is set then we are reading
225 * /dev, so insert the device in device number order and make /dev/c0d0 current.
228 device_t
*new, *nextdev
, *prevdev
;
233 if (stat(name
, &st
) < 0 || !S_ISBLK(st
.st_mode
)) return;
235 switch (major(st
.st_rdev
)) {
238 if (minor(st
.st_rdev
) >= 4) return;
245 /* Disk controller */
246 if (minor(st
.st_rdev
) >= 0x80
247 || minor(st
.st_rdev
) % 5 != 0) return;
252 /* Interesting device found. */
254 (void) stat(name
, &st
);
257 new= alloc(sizeof(*new));
258 new->rdev
= st
.st_rdev
;
259 new->name
= alloc((strlen(name
) + 1) * sizeof(new->name
[0]));
260 strcpy(new->name
, name
);
261 new->subname
= new->name
;
262 new->parttype
= DUNNO
;
263 if (major(st
.st_rdev
) == major(DEV_FD0
) && minor(st
.st_rdev
) < 112) {
264 new->parttype
= FLOPPY
;
266 if (st
.st_rdev
>= DEV_C0D0
&& minor(st
.st_rdev
) < 128
267 && minor(st
.st_rdev
) % 5 == 0) {
268 new->parttype
= PRIMARY
;
271 if (firstdev
== nil
) {
273 new->next
= new->prev
= new;
278 while (new->rdev
>= nextdev
->rdev
279 && (nextdev
= nextdev
->next
) != firstdev
) {}
280 prevdev
= nextdev
->prev
;
286 if (new->rdev
< firstdev
->rdev
) firstdev
= new;
287 if (new->rdev
== DEV_C0D0
) curdev
= new;
288 if (curdev
->rdev
!= DEV_C0D0
) curdev
= firstdev
;
291 void getdevices(void)
292 /* Get all block devices from /dev that look interesting. */
296 char name
[5 + NAME_MAX
+ 1];
298 if ((d
= opendir("/dev")) == nil
) fatal("/dev");
300 while ((e
= readdir(d
)) != nil
) {
301 strcpy(name
, "/dev/");
302 strcpy(name
+ 5, e
->d_name
);
308 /* One featureful master bootstrap. */
309 unsigned char bootstrap
[] = {
310 0353,0001,0000,0061,0300,0216,0330,0216,0300,0372,0216,0320,0274,0000,0174,0373,
311 0275,0276,0007,0211,0346,0126,0277,0000,0006,0271,0000,0001,0374,0363,0245,0352,
312 0044,0006,0000,0000,0264,0002,0315,0026,0250,0010,0164,0033,0350,0071,0001,0174,
313 0007,0060,0344,0315,0026,0242,0205,0007,0054,0060,0074,0012,0163,0363,0120,0350,
314 0046,0001,0205,0007,0130,0353,0012,0240,0002,0006,0204,0300,0165,0003,0351,0147,
315 0000,0230,0262,0005,0366,0362,0262,0200,0000,0302,0210,0340,0120,0350,0234,0000,
316 0163,0003,0351,0147,0000,0130,0054,0001,0175,0003,0351,0141,0000,0276,0276,0175,
317 0211,0357,0271,0040,0000,0363,0245,0200,0301,0004,0211,0356,0215,0174,0020,0070,
318 0154,0004,0164,0016,0213,0135,0010,0053,0134,0010,0213,0135,0012,0033,0134,0012,
319 0163,0014,0212,0044,0206,0144,0020,0210,0044,0106,0071,0376,0162,0364,0211,0376,
320 0201,0376,0356,0007,0162,0326,0342,0322,0211,0356,0264,0020,0366,0344,0001,0306,
321 0200,0174,0004,0001,0162,0026,0353,0021,0204,0322,0175,0041,0211,0356,0200,0174,
322 0004,0000,0164,0013,0366,0004,0200,0164,0006,0350,0070,0000,0162,0053,0303,0203,
323 0306,0020,0201,0376,0376,0007,0162,0346,0350,0215,0000,0211,0007,0376,0302,0204,
324 0322,0174,0023,0315,0021,0321,0340,0321,0340,0200,0344,0003,0070,0342,0167,0355,
325 0350,0011,0000,0162,0350,0303,0350,0003,0000,0162,0146,0303,0211,0356,0214,0134,
326 0010,0214,0134,0012,0277,0003,0000,0122,0006,0127,0264,0010,0315,0023,0137,0007,
327 0200,0341,0077,0376,0306,0210,0310,0366,0346,0211,0303,0213,0104,0010,0213,0124,
328 0012,0367,0363,0222,0210,0325,0366,0361,0060,0322,0321,0352,0321,0352,0010,0342,
329 0210,0321,0376,0301,0132,0210,0306,0273,0000,0174,0270,0001,0002,0315,0023,0163,
330 0020,0200,0374,0200,0164,0011,0117,0174,0006,0060,0344,0315,0023,0163,0270,0371,
331 0303,0201,0076,0376,0175,0125,0252,0165,0001,0303,0350,0013,0000,0243,0007,0353,
332 0005,0350,0004,0000,0227,0007,0353,0376,0136,0255,0126,0211,0306,0254,0204,0300,
333 0164,0011,0264,0016,0273,0001,0000,0315,0020,0353,0362,0303,0057,0144,0145,0166,
334 0057,0150,0144,0077,0010,0000,0015,0012,0000,0116,0157,0156,0145,0040,0141,0143,
335 0164,0151,0166,0145,0015,0012,0000,0122,0145,0141,0144,0040,0145,0162,0162,0157,
336 0162,0040,0000,0116,0157,0164,0040,0142,0157,0157,0164,0141,0142,0154,0145,0040,
341 unsigned char bootblock
[SECTOR_SIZE
];
342 struct part_entry table
[1 + NR_PARTITIONS
];
343 int existing
[1 + NR_PARTITIONS
];
344 unsigned long offset
= 0, extbase
= 0, extsize
;
346 char sort_index
[1 + NR_PARTITIONS
];
347 unsigned cylinders
= 1, heads
= 1, sectors
= 1, secpcyl
= 1;
348 unsigned alt_cyls
= 1, alt_heads
= 1, alt_secs
= 1;
352 unsigned long sortbase(struct part_entry
*pe
)
354 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
;
358 /* Let the sort_index array show the order partitions are sorted in. */
361 int idx
[1 + NR_PARTITIONS
];
363 for (i
= 1; i
<= NR_PARTITIONS
; i
++) idx
[i
]= i
;
365 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
366 for (j
= 1; j
<= NR_PARTITIONS
-1; j
++) {
367 int sj
= idx
[j
], sj1
= idx
[j
+1];
369 if (sortbase(&table
[sj
]) > sortbase(&table
[sj1
])) {
375 for (i
= 1; i
<= NR_PARTITIONS
; i
++) sort_index
[idx
[i
]]= i
;
378 void dos2chs(unsigned char *dos
, unsigned *chs
)
379 /* Extract cylinder, head and sector from the three bytes DOS uses to address
380 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
381 * of the sector byte. The sector number is rebased to count from 0.
384 chs
[0]= ((dos
[1] & 0xC0) << 2) | dos
[2];
386 chs
[2]= (dos
[1] & 0x3F) - 1;
389 void abs2dos(unsigned char *dos
, unsigned long pos
)
390 /* Translate a sector offset to three DOS bytes. */
395 h
= (pos
% secpcyl
) / sectors
;
396 s
= pos
% sectors
+ 1;
399 dos
[1]= s
| ((c
>> 2) & 0xC0);
403 void recompute0(void)
404 /* Recompute the partition size for the device after a geometry change. */
407 cylinders
= heads
= sectors
= 1;
408 memset(table
, 0, sizeof(table
));
410 if (!precise
&& offset
== 0) {
412 table
[0].size
= (unsigned long) cylinders
* heads
* sectors
;
414 table
[0].sysind
= device
< 0 ? NO_PART
: MINIX_PART
;
415 secpcyl
= heads
* sectors
;
418 void guess_geometry(void)
419 /* With a bit of work one can deduce the disk geometry from the partition
420 * table. This may be necessary if the driver gets it wrong. (If partition
421 * tables didn't have C/H/S numbers we would not care at all...)
425 struct part_entry
*pe
;
429 unsigned char HS
[256][8]; /* Bit map off all possible H/S */
431 alt_cyls
= alt_heads
= alt_secs
= 0;
433 /* Initially all possible H/S combinations are possible. HS[h][0]
434 * bit 0 is used to rule out a head value.
436 for (h
= 1; h
<= 255; h
++) {
437 for (s
= 0; s
< 8; s
++) HS
[h
][s
]= 0xFF;
440 for (i
= 0; i
< 2*NR_PARTITIONS
; i
++) {
441 pe
= &(table
+1)[i
>> 1];
442 if (pe
->sysind
== NO_PART
) continue;
444 /* Get the end or start sector numbers (in that order). */
446 dos2chs(&pe
->last_head
, chs
);
447 sec
= pe
->lowsec
+ pe
->size
- 1;
449 dos2chs(&pe
->start_head
, chs
);
453 if (chs
[0] >= alt_cyls
) alt_cyls
= chs
[0]+1;
455 /* Which H/S combinations can be ruled out? */
456 for (h
= 1; h
<= 255; h
++) {
457 if (HS
[h
][0] == 0) continue;
459 for (s
= 1; s
<= 63; s
++) {
460 if ((chs
[0] * h
+ chs
[1]) * s
+ chs
[2] != sec
) {
461 HS
[h
][s
/8] &= ~(1 << (s
%8));
463 if (HS
[h
][s
/8] & (1 << (s
%8))) n
++;
465 if (n
== 0) HS
[h
][0]= 0;
469 /* See if only one remains. */
471 for (h
= 1; h
<= 255; h
++) {
472 if (HS
[h
][0] == 0) continue;
473 for (s
= 1; s
<= 63; s
++) {
474 if (HS
[h
][s
/8] & (1 << (s
%8))) {
482 /* Forget it if more than one choice... */
483 if (i
> 1) alt_cyls
= alt_heads
= alt_secs
= 0;
487 /* Find out the geometry of the device by querying the driver, or by looking
488 * at the partition table. These numbers are crosschecked to make sure that
489 * the geometry is correct. Master bootstraps other than the Minix one use
490 * the CHS numbers in the partition table to load the bootstrap of the active
496 struct partition geometry
;
499 /* Geometry already known. */
506 if (device
< 0) return;
508 /* Try to guess the geometry from the partition table. */
511 /* Try to get the geometry from the driver. */
512 (void) fstat(device
, &dst
);
514 if (S_ISBLK(dst
.st_mode
) || S_ISCHR(dst
.st_mode
)) {
515 /* Try to get the drive's geometry from the driver. */
517 if (ioctl(device
, DIOCGETP
, &geometry
) < 0)
520 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
521 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
522 cylinders
= geometry
.cylinders
;
523 heads
= geometry
.heads
;
524 sectors
= geometry
.sectors
;
532 /* Getting the geometry from the driver failed, so use the
533 * alternate geometry.
535 if (alt_heads
== 0) {
536 alt_cyls
= table
[0].size
/ (64 * 32);
546 printf("Failure to get the geometry of %s: %s", curdev
->name
,
547 errno
== ENOTTY
? "No driver support" : strerror(err
));
550 printf("The geometry has been guessed as %ux%ux%u",
551 cylinders
, heads
, sectors
);
554 if (alt_heads
== 0) {
560 if (heads
!= alt_heads
|| sectors
!= alt_secs
) {
566 "The %ux%ux%u geometry obtained from the device driver does not match",
567 cylinders
, heads
, sectors
);
571 "the %ux%ux%u geometry implied by the partition table. Hit 'X' to switch",
572 alt_cyls
, alt_heads
, alt_secs
);
576 "between the two geometries to see what is best. Note that the geometry");
580 "must be correct when the table is written or the system may not boot!");
585 /* Show the base and size of the device instead of the whole drive.
586 * This makes sense for subpartitioning primary partitions.
588 if (precise
&& ioctl(device
, DIOCGETP
, &geometry
) >= 0) {
589 table
[0].lowsec
= div64u(geometry
.base
, SECTOR_SIZE
);
590 table
[0].size
= div64u(geometry
.size
, SECTOR_SIZE
);
598 typedef struct indicators
{ /* Partition type to partition name. */
603 indicators_t ind_table
[]= {
607 { 0x03, "XENIX usr" },
609 { 0x05, "EXTENDED" },
611 { 0x07, "HPFS/NTFS" },
613 { 0x09, "COHERENT" },
618 { 0x0F, "EXTENDED" },
620 { 0x40, "VENIX286" },
621 { 0x42, "W2000 Dyn" },
622 { 0x52, "MICROPORT" },
624 { 0x64, "NOVELL286" },
625 { 0x65, "NOVELL386" },
627 { 0x80, "MINIX-OLD" },
629 { 0x82, "LINUXswap" },
632 { 0x94, "AMOEBAbad" },
635 { 0xB8, "BSDI swap" },
638 { 0xFF, "BADBLOCKS" },
641 char *typ2txt(int ind
)
642 /* Translate a numeric partition indicator for human eyes. */
646 for (pind
= ind_table
; pind
< arraylimit(ind_table
); pind
++) {
647 if (pind
->ind
== ind
) return pind
->name
;
652 int round_sysind(int ind
, int delta
)
653 /* Find the next known partition type starting with ind in direction delta. */
657 ind
= (ind
+ delta
) & 0xFF;
660 for (pind
= arraylimit(ind_table
)-1; pind
->ind
> ind
; pind
--) {}
662 for (pind
= ind_table
; pind
->ind
< ind
; pind
++) {}
667 /* Objects on the screen, either simple pieces of the text or the cylinder
668 * number of the start of partition three.
670 typedef enum objtype
{
671 O_INFO
, O_TEXT
, O_DEV
, O_SUB
,
672 O_TYPTXT
, O_SORT
, O_NUM
, O_TYPHEX
,
673 O_CYL
, O_HEAD
, O_SEC
,
674 O_SCYL
, O_SHEAD
, O_SSEC
, O_LCYL
, O_LHEAD
, O_LSEC
, O_BASE
, O_SIZE
, O_KB
677 #define rjust(type) ((type) >= O_TYPHEX)
678 #define computed(type) ((type) >= O_TYPTXT)
680 typedef struct object
{
682 objtype_t type
; /* Text field, cylinder number, etc. */
683 char flags
; /* Modifiable? */
687 struct part_entry
*entry
; /* What does the object refer to? */
689 char value
[20]; /* Value when printed. */
692 #define OF_MOD 0x01 /* Object value is modifiable. */
693 #define OF_ODD 0x02 /* It has a somewhat odd value. */
694 #define OF_BAD 0x04 /* Its value is no good at all. */
696 /* Events: (Keypress events are the value of the key pressed.) */
697 #define E_ENTER (-1) /* Cursor moves onto object. */
698 #define E_LEAVE (-2) /* Cursor leaves object. */
699 #define E_WRITE (-3) /* Write, but not by typing 'w'. */
701 /* The O_SIZE objects have a dual identity. */
702 enum howend
{ SIZE
, LAST
} howend
= SIZE
;
704 object_t
*world
= nil
;
705 object_t
*curobj
= nil
;
707 object_t
*newobject(objtype_t type
, int flags
, int row
, int col
, int len
)
708 /* Make a new object given a type, flags, position and length on the screen. */
711 object_t
**aop
= &world
;
713 new= alloc(sizeof(*new));
730 unsigned long entry2base(struct part_entry
*pe
)
731 /* Return the base sector of the partition if defined. */
733 return pe
->sysind
== NO_PART
? 0 : pe
->lowsec
;
736 unsigned long entry2last(struct part_entry
*pe
)
738 return pe
->sysind
== NO_PART
? -1 : pe
->lowsec
+ pe
->size
- 1;
741 unsigned long entry2size(struct part_entry
*pe
)
743 return pe
->sysind
== NO_PART
? 0 : pe
->size
;
746 int overlap(unsigned long sec
)
747 /* See if sec is part of another partition. */
749 struct part_entry
*pe
;
751 for (pe
= table
+ 1; pe
<= table
+ NR_PARTITIONS
; pe
++) {
752 if (pe
->sysind
== NO_PART
) continue;
754 if (pe
->lowsec
< sec
&& sec
< pe
->lowsec
+ pe
->size
)
760 int aligned(unsigned long sec
, unsigned unit
)
761 /* True if sec is aligned to unit or if it is no problem if it is unaligned. */
763 return (offset
!= 0 && extbase
== 0) || (sec
% unit
== 0);
766 void print(object_t
*op
)
767 /* Print an object's value if it changed. */
769 struct part_entry
*pe
= op
->entry
;
776 /* Remember the old flags and value. */
778 strcpy(oldvalue
, op
->value
);
780 op
->flags
&= ~(OF_ODD
| OF_BAD
);
785 static struct field
{ int type
; char *name
; } fields
[]= {
786 { O_DEV
, "Select device" },
787 { O_NUM
, "Active flag" },
788 { O_TYPHEX
, "Hex partition type" },
789 { O_TYPTXT
, "Partition type" },
790 { O_SCYL
, "Start cylinder" },
791 { O_SHEAD
, "Start head" },
792 { O_SSEC
, "Start sector" },
793 { O_CYL
, "Number of cylinders" },
794 { O_HEAD
, "Number of heads" },
795 { O_SEC
, "Sectors per track" },
796 { O_LCYL
, "Last cylinder" },
797 { O_LHEAD
, "Last head" },
798 { O_LSEC
, "Last sector" },
799 { O_BASE
, "Base sector" },
800 { O_SIZE
, "Size in sectors" },
801 { O_KB
, "Size in kilobytes" },
804 struct field
*fp
= fields
;
806 while (fp
->type
>= 0 && fp
->type
!= curobj
->type
) fp
++;
807 strcpy(op
->value
, fp
->name
);
811 /* Simple text field. */
812 strcpy(op
->value
, op
->text
);
816 /* Name of currently edited device. */
817 name
= op
->type
== O_DEV
? curdev
->name
:
818 offset
== 0 ? "" : curdev
->subname
;
819 if ((n
= strlen(name
)) < op
->len
) n
= op
->len
;
820 strcpy(op
->value
, name
+ (n
- op
->len
));
821 if (device
< 0 && op
->type
== O_DEV
) op
->flags
|= OF_BAD
;
824 /* Position and active flag. */
825 sprintf(op
->value
, "%d%c", (int) (pe
- table
- 1),
826 pe
->bootind
& ACTIVE_FLAG
? '*' : ' ');
829 /* Position if the driver sorts the table. */
830 sprintf(op
->value
, "%s%d",
831 curdev
->parttype
>= PRIMARY
? "p" :
832 curdev
->parttype
== SUBPART
? "s" : "",
833 (curdev
->parttype
== SUBPART
||
834 curdev
->parttype
== FLOPPY
? pe
- table
835 : sort_index
[pe
- table
]) - 1);
838 /* Hex partition type indicator. */
839 sprintf(op
->value
, "%02X", pe
->sysind
);
842 /* Ascii partition type indicator. */
843 strcpy(op
->value
, typ2txt(pe
->sysind
));
846 /* Partition's start cylinder. */
847 sprintf(op
->value
, "%lu", entry2base(pe
) / secpcyl
);
852 sprintf(op
->value
, "%lu", t
% secpcyl
/ sectors
);
853 if (!aligned(t
, secpcyl
) && t
!= table
[0].lowsec
+ sectors
)
859 sprintf(op
->value
, "%lu", t
% sectors
);
860 if (!aligned(t
, sectors
)) op
->flags
|= OF_ODD
;
863 /* Number of cylinders. */
864 sprintf(op
->value
, "%u", cylinders
);
867 /* Number of heads. */
868 sprintf(op
->value
, "%u", heads
);
871 /* Number of sectors per track. */
872 sprintf(op
->value
, "%u", sectors
);
875 /* Partition's last cylinder. */
877 sprintf(op
->value
, "%lu", t
== -1 ? 0 : t
/ secpcyl
);
880 /* Partition's last head. */
882 sprintf(op
->value
, "%lu", t
== -1 ? 0 : t
% secpcyl
/ sectors
);
883 if (!aligned(t
+ 1, secpcyl
)) op
->flags
|= OF_ODD
;
886 /* Partition's last sector. */
888 sprintf(op
->value
, t
== -1 ? "-1" : "%lu", t
% sectors
);
889 if (!aligned(t
+ 1, sectors
)) op
->flags
|= OF_ODD
;
892 /* Partition's base sector. */
893 sprintf(op
->value
, "%lu", entry2base(pe
));
894 if (pe
->sysind
!= NO_PART
&& pe
!= &table
[0]
895 && (pe
->lowsec
<= table
[0].lowsec
|| overlap(pe
->lowsec
)))
899 /* Size of partitition in sectors. */
900 t
= howend
== SIZE
? entry2size(pe
) : entry2last(pe
);
901 sprintf(op
->value
, "%lu", pe
->sysind
== NO_PART
? 0 : t
);
902 if (pe
->sysind
!= NO_PART
&& (pe
->size
== 0
903 || pe
->lowsec
+ pe
->size
> table
[0].lowsec
+ table
[0].size
904 || overlap(pe
->lowsec
+ pe
->size
)))
908 /* Size of partitition in kilobytes. */
909 sprintf(op
->value
, "%lu", entry2size(pe
) / 2);
912 sprintf(op
->value
, "?? %d ??", op
->type
);
915 if (device
< 0 && computed(op
->type
)) strcpy(op
->value
, "?");
917 /* If a value overflows the print field then show a blank
918 * reverse video field.
920 if ((n
= strlen(op
->value
)) > op
->len
) {
925 /* Right or left justified? */
926 if (rjust(op
->type
)) {
927 memmove(op
->value
+ (op
->len
- n
), op
->value
, n
);
928 memset(op
->value
, ' ', op
->len
- n
);
930 memset(op
->value
+ n
, ' ', op
->len
- n
);
932 op
->value
[op
->len
]= 0;
934 if ((op
->flags
& (OF_ODD
| OF_BAD
)) == (oldflags
& (OF_ODD
| OF_BAD
))
935 && strcmp(op
->value
, oldvalue
) == 0) {
936 /* The value did not change. */
940 set_cursor(op
->row
, rjust(op
->type
) ? op
->col
- (op
->len
-1) : op
->col
);
942 if (op
->flags
& OF_BAD
) tputs(t_so
, 1, putchr
);
944 if (op
->flags
& OF_ODD
) tputs(t_md
, 1, putchr
);
946 if (op
->flags
& OF_BAD
) tputs(t_se
, 1, putchr
);
948 if (op
->flags
& OF_ODD
) tputs(t_me
, 1, putchr
);
952 /* Repaint all objects that changed. */
956 for (op
= world
; op
!= nil
; op
= op
->next
) print(op
);
959 int typing
; /* Set if a digit has been typed to set a value. */
960 int magic
; /* Changes when using the magic key. */
962 void event(int ev
, object_t
*op
);
964 void m_redraw(int ev
, object_t
*op
)
965 /* Redraw the screen. */
969 if (ev
!= ctrl('L')) return;
972 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) op2
->value
[0]= 0;
975 void m_toggle(int ev
, object_t
*op
)
976 /* Toggle between the driver and alternate geometry. */
980 if (ev
!= 'X') return;
981 if (alt_cyls
== cylinders
&& alt_heads
== heads
&& alt_secs
== sectors
)
984 t
= cylinders
; cylinders
= alt_cyls
; alt_cyls
= t
;
985 t
= heads
; heads
= alt_heads
; alt_heads
= t
;
986 t
= sectors
; sectors
= alt_secs
; alt_secs
= t
;
991 char size_last
[]= "Size";
993 void m_orientation(int ev
, object_t
*op
)
995 if (ev
!= ' ') return;
1000 strcpy(size_last
, "Last");
1004 strcpy(size_last
, "Size");
1008 void m_move(int ev
, object_t
*op
)
1009 /* Move to the nearest modifiably object in the intended direction. Objects
1010 * on the same row or column are really near.
1013 object_t
*near
, *op2
;
1014 unsigned dist
, d2
, dr
, dc
;
1016 if (ev
!= 'h' && ev
!= 'j' && ev
!= 'k' && ev
!= 'l' && ev
!= 'H')
1020 /* No device open? Then try to read first. */
1022 if (device
< 0) return;
1028 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1029 if (op2
== op
|| !(op2
->flags
& OF_MOD
)) continue;
1031 dr
= abs(op2
->row
- op
->row
);
1032 dc
= abs(op2
->col
- op
->col
);
1034 d2
= 25*dr
*dr
+ dc
*dc
;
1035 if (op2
->row
!= op
->row
&& op2
->col
!= op
->col
) d2
+= 1000;
1038 case 'h': /* Left */
1039 if (op2
->col
>= op
->col
) d2
= -1;
1041 case 'j': /* Down */
1042 if (op2
->row
<= op
->row
) d2
= -1;
1045 if (op2
->row
>= op
->row
) d2
= -1;
1047 case 'l': /* Right */
1048 if (op2
->col
<= op
->col
) d2
= -1;
1050 case 'H': /* Home */
1051 if (op2
->type
== O_DEV
) d2
= 0;
1053 if (d2
< dist
) { near
= op2
; dist
= d2
; }
1055 if (near
!= op
) event(E_LEAVE
, op
);
1056 event(E_ENTER
, near
);
1059 void m_updown(int ev
, object_t
*op
)
1060 /* Move a partition table entry up or down. */
1063 struct part_entry tmp
;
1066 if (ev
!= ctrl('K') && ev
!= ctrl('J')) return;
1067 if (op
->entry
== nil
) return;
1069 i
= op
->entry
- table
;
1070 if (ev
== ctrl('K')) {
1074 if (i
>= NR_PARTITIONS
) return;
1078 tmp
= table
[i
]; table
[i
]= table
[j
]; table
[j
]= tmp
;
1079 tmpx
= existing
[i
]; existing
[i
]= existing
[j
]; existing
[j
]= tmpx
;
1082 event(ev
== ctrl('K') ? 'k' : 'j', op
);
1085 void m_enter(int ev
, object_t
*op
)
1086 /* We've moved onto this object. */
1088 if (ev
!= E_ENTER
&& ev
!= ' ' && ev
!= '<' && ev
!= '>' && ev
!= 'X')
1095 void m_leave(int ev
, object_t
*op
)
1096 /* About to leave this object. */
1098 if (ev
!= E_LEAVE
) return;
1101 int within(unsigned *var
, unsigned low
, unsigned value
, unsigned high
)
1102 /* Only set *var to value if it looks reasonable. */
1104 if (low
<= value
&& value
<= high
) {
1111 int lwithin(unsigned long *var
, unsigned long low
, unsigned long value
,
1114 if (low
<= value
&& value
<= high
) {
1121 int nextdevice(object_t
*op
, int delta
)
1122 /* Select the next or previous device from the device list. */
1126 if (offset
!= 0) return 0;
1127 if (dirty
) event(E_WRITE
, op
);
1128 if (dirty
) return 0;
1131 (void) close(device
);
1139 curdev
= curdev
->prev
;
1140 while (delta
< -1 && major(curdev
->rdev
) == major(rdev
)
1141 && curdev
->rdev
< rdev
);
1144 curdev
= curdev
->next
;
1145 while (delta
> 1 && major(curdev
->rdev
) == major(rdev
)
1146 && curdev
->rdev
> rdev
);
1151 void check_ind(struct part_entry
*pe
)
1152 /* If there are no other partitions then make this new one active. */
1154 struct part_entry
*pe2
;
1156 if (pe
->sysind
!= NO_PART
) return;
1158 for (pe2
= table
+ 1; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++)
1159 if (pe2
->sysind
!= NO_PART
|| pe2
->bootind
& ACTIVE_FLAG
) break;
1161 if (pe2
== table
+ 1 + NR_PARTITIONS
) pe
->bootind
= ACTIVE_FLAG
;
1164 int check_existing(struct part_entry
*pe
)
1165 /* Check and if not ask if an existing partition may be modified. */
1167 static int expert
= 0;
1170 if (expert
|| pe
== nil
|| !existing
[pe
- table
]) return 1;
1173 putstr("Do you wish to modify existing partitions? (y/n) ");
1175 while ((c
= getchar()) != 'y' && c
!= 'n') {}
1178 return (expert
= (c
== 'y'));
1181 void m_modify(int ev
, object_t
*op
)
1182 /* Increment, decrement, set, or toggle the value of an object, using
1183 * arithmetic tricks the author doesn't understand either.
1187 struct part_entry
*pe
= op
->entry
;
1190 unsigned long surplus
;
1191 int radix
= op
->type
== O_TYPHEX
? 0x10 : 10;
1194 if (device
< 0 && op
->type
!= O_DEV
) return;
1198 mul
= radix
; delta
= -1; typing
= 0;
1201 mul
= radix
; delta
= 1; typing
= 0;
1204 if (!typing
) return;
1211 if ('0' <= ev
&& ev
<= '9')
1214 if (radix
== 0x10 && 'a' <= ev
&& ev
<= 'f')
1215 delta
= ev
- 'a' + 10;
1217 if (radix
== 0x10 && 'A' <= ev
&& ev
<= 'F')
1218 delta
= ev
- 'A' + 10;
1222 mul
= typing
? radix
*radix
: 0;
1227 if (!check_existing(pe
)) return;
1231 if (ev
!= '-' && ev
!= '+') return;
1232 if (!nextdevice(op
, delta
)) return;
1235 if (!within(&cylinders
, 1,
1236 cylinders
* mul
/ radix
+ delta
, 1024)) return;
1240 if (!within(&heads
, 1, heads
* mul
/ radix
+ delta
, 255))
1245 if (!within(§ors
, 1, sectors
* mul
/ radix
+ delta
, 63))
1250 if (ev
!= '-' && ev
!= '+') return;
1251 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1252 if (op2
->type
== O_NUM
&& ev
== '+')
1253 op2
->entry
->bootind
= 0;
1255 op
->entry
->bootind
= ev
== '+' ? ACTIVE_FLAG
: 0;
1259 pe
->sysind
= pe
->sysind
* mul
/ radix
+ delta
;
1262 if (ev
!= '-' && ev
!= '+') return;
1264 pe
->sysind
= round_sysind(pe
->sysind
, delta
);
1271 if (op
->type
!= O_SCYL
&& ev
!= '-' && ev
!= '+') return;
1273 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1276 if (!lwithin(&t
, 0L,
1277 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1279 if (howend
== LAST
|| op
->type
!= O_BASE
)
1280 pe
->size
-= t
- pe
->lowsec
;
1283 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1290 if (op
->type
!= O_LCYL
&& ev
!= '-' && ev
!= '+') return;
1292 if (pe
->sysind
== NO_PART
) memset(pe
, 0, sizeof(*pe
));
1293 t
= pe
->lowsec
+ pe
->size
- 1 + level
;
1294 surplus
= t
% level
- mul
/ radix
* level
;
1295 if (!lwithin(&t
, 0L,
1296 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1298 pe
->size
= t
- pe
->lowsec
+ 1;
1300 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1304 if (mul
== 0) pe
->size
= 0; /* new value, no surplus */
1306 if (pe
->sysind
== NO_PART
) {
1307 if (op
->type
== O_KB
|| howend
== SIZE
) {
1308 /* First let loose magic to set the base. */
1315 memset(pe
, 0, sizeof(*pe
));
1317 t
= (op
->type
== O_KB
|| howend
== SIZE
) ? pe
->size
1318 : pe
->lowsec
+ pe
->size
- 1;
1320 if (!lwithin(&t
, 0L,
1321 (t
/ level
* mul
/ radix
+ delta
) * level
+ surplus
,
1323 pe
->size
= (op
->type
== O_KB
|| howend
== SIZE
) ? t
:
1326 if (pe
->sysind
== NO_PART
) pe
->sysind
= MINIX_PART
;
1332 /* The order among the entries may have changed. */
1337 unsigned long spell
[3 + 4 * (1+NR_PARTITIONS
)];
1341 void newspell(unsigned long charm
)
1342 /* Add a new spell, descending order for the base, ascending for the size. */
1346 if (charm
- table
[0].lowsec
> table
[0].size
) return;
1348 for (i
= 0; i
< nspells
; i
++) {
1349 if (charm
== spell
[i
]) return; /* duplicate */
1351 if (touching
== O_BASE
) {
1352 if (charm
== table
[0].lowsec
+ table
[0].size
) return;
1353 if ((spell
[0] - charm
) < (spell
[0] - spell
[i
])) break;
1355 if (charm
== table
[0].lowsec
) return;
1356 if ((charm
- spell
[0]) < (spell
[i
] - spell
[0])) break;
1359 for (j
= ++nspells
; j
> i
; j
--) spell
[j
]= spell
[j
-1];
1363 void m_magic(int ev
, object_t
*op
)
1364 /* Apply magic onto a base or size number. */
1366 struct part_entry
*pe
= op
->entry
, *pe2
;
1367 int rough
= (offset
!= 0 && extbase
== 0);
1369 if (ev
!= 'm' || device
< 0) return;
1372 if (!check_existing(pe
)) return;
1375 /* See what magic we can let loose on this value. */
1378 /* First spell, the current value. */
1381 case O_SHEAD
: /* Start of partition. */
1385 spell
[0]= pe
->lowsec
;
1389 case O_LSEC
: /* End of partition. */
1393 spell
[0]= pe
->lowsec
+ pe
->size
;
1398 if (pe
->sysind
== NO_PART
) {
1399 memset(pe
, 0, sizeof(*pe
));
1401 pe
->sysind
= MINIX_PART
;
1403 if (touching
== O_SIZE
) {
1404 /* First let loose magic on the base. */
1407 for (op2
= world
; op2
!= nil
; op2
= op2
->next
) {
1408 if (op2
->row
== op
->row
&&
1409 op2
->type
== O_BASE
) {
1418 /* Avoid the first sector on the device. */
1419 if (spell
[0] == table
[0].lowsec
) newspell(spell
[0] + 1);
1421 /* Further interesting values are the the bases of other
1422 * partitions or their ends.
1424 for (pe2
= table
; pe2
< table
+ 1 + NR_PARTITIONS
; pe2
++) {
1425 if (pe2
== pe
|| pe2
->sysind
== NO_PART
) continue;
1426 if (pe2
->lowsec
== table
[0].lowsec
)
1427 newspell(table
[0].lowsec
+ 1);
1429 newspell(pe2
->lowsec
);
1430 newspell(pe2
->lowsec
+ pe2
->size
);
1431 if (touching
== O_BASE
&& howend
== SIZE
) {
1432 newspell(pe2
->lowsec
- pe
->size
);
1433 newspell(pe2
->lowsec
+ pe2
->size
- pe
->size
);
1435 if (pe2
->lowsec
% sectors
!= 0) rough
= 1;
1437 /* Present values rounded up to the next cylinder unless
1438 * the table is already a mess. Use "start + 1 track" instead
1439 * of "start + 1 cylinder". Also add the end of the last
1443 unsigned long n
= spell
[0];
1444 if (n
== table
[0].lowsec
) n
++;
1445 n
= (n
+ sectors
- 1) / sectors
* sectors
;
1446 if (n
!= table
[0].lowsec
+ sectors
)
1447 n
= (n
+ secpcyl
- 1) / secpcyl
* secpcyl
;
1449 if (touching
== O_SIZE
)
1450 newspell(table
[0].size
/ secpcyl
* secpcyl
);
1453 /* Magic has been applied, a spell needs to be chosen. */
1455 if (++magic
== nspells
) magic
= 0;
1457 if (touching
== O_BASE
) {
1458 if (howend
== LAST
) pe
->size
-= spell
[magic
] - pe
->lowsec
;
1459 pe
->lowsec
= spell
[magic
];
1461 pe
->size
= spell
[magic
] - pe
->lowsec
;
1463 /* The order among the entries may have changed. */
1468 typedef struct diving
{
1470 struct part_entry old0
;
1472 parttype_t oldparttype
;
1473 unsigned long oldoffset
;
1474 unsigned long oldextbase
;
1477 diving_t
*diving
= nil
;
1479 void m_in(int ev
, object_t
*op
)
1480 /* Go down into a primary or extended partition. */
1483 struct part_entry
*pe
= op
->entry
, ext
;
1486 if (ev
!= '>' || device
< 0 || pe
== nil
|| pe
== &table
[0]
1487 || (!(pe
->sysind
== MINIX_PART
&& offset
== 0)
1488 && !ext_part(pe
->sysind
))
1489 || pe
->size
== 0) return;
1492 if (extbase
!= 0) ext
.size
= extbase
+ extsize
- ext
.lowsec
;
1494 if (dirty
) event(E_WRITE
, op
);
1496 if (device
>= 0) { close(device
); device
= -1; }
1498 newdiv
= alloc(sizeof(*newdiv
));
1499 newdiv
->old0
= table
[0];
1500 newdiv
->oldsubname
= curdev
->subname
;
1501 newdiv
->oldparttype
= curdev
->parttype
;
1502 newdiv
->oldoffset
= offset
;
1503 newdiv
->oldextbase
= extbase
;
1509 n
= strlen(diving
->oldsubname
);
1510 curdev
->subname
= alloc((n
+ 3) * sizeof(curdev
->subname
[0]));
1511 strcpy(curdev
->subname
, diving
->oldsubname
);
1512 curdev
->subname
[n
++]= ':';
1513 curdev
->subname
[n
++]= '0' + (pe
- table
- 1);
1514 curdev
->subname
[n
]= 0;
1516 curdev
->parttype
= curdev
->parttype
== PRIMARY
? SUBPART
: DUNNO
;
1518 if (ext_part(ext
.sysind
) && extbase
== 0) {
1519 extbase
= ext
.lowsec
;
1521 curdev
->parttype
= DUNNO
;
1528 void m_out(int ev
, object_t
*op
)
1529 /* Go up from an extended or subpartition table to its enclosing. */
1533 if (ev
!= '<' || diving
== nil
) return;
1535 if (dirty
) event(E_WRITE
, op
);
1537 if (device
>= 0) { close(device
); device
= -1; }
1542 table
[0]= olddiv
->old0
;
1544 free(curdev
->subname
);
1545 curdev
->subname
= olddiv
->oldsubname
;
1547 curdev
->parttype
= olddiv
->oldparttype
;
1548 offset
= olddiv
->oldoffset
;
1549 extbase
= olddiv
->oldextbase
;
1554 if (diving
== nil
) submerged
= 0; /* We surfaced. */
1557 void installboot(unsigned char *bootblock
, char *masterboot
)
1558 /* Install code from a master bootstrap into a boot block. */
1565 if ((mfp
= fopen(masterboot
, "r")) == nil
) {
1566 err
= strerror(errno
);
1570 n
= fread(&hdr
, sizeof(char), A_MINHDR
, mfp
);
1572 err
= strerror(errno
);
1577 if (n
< A_MINHDR
|| BADMAG(hdr
) || hdr
.a_cpu
!= A_I8086
) {
1578 err
= "Not an 8086 executable";
1583 if (hdr
.a_text
+ hdr
.a_data
> PART_TABLE_OFF
) {
1584 err
= "Does not fit in a boot sector";
1589 fseek(mfp
, hdr
.a_hdrlen
, 0);
1590 fread(bootblock
, sizeof(char), (size_t) (hdr
.a_text
+ hdr
.a_data
), mfp
);
1592 err
= strerror(errno
);
1598 /* Bootstrap installed. */
1603 printf("%s: %s", masterboot
, err
);
1607 ssize_t
boot_readwrite(int rw
)
1608 /* Read (0) or write (1) the boot sector. */
1610 u64_t off64
= mul64u(offset
, SECTOR_SIZE
);
1614 /* Minix-vmd has a 64 bit seek. */
1615 if (fcntl(device
, F_SEEK
, off64
) < 0) return -1;
1617 /* Minix has to gross things with the partition base. */
1618 struct partition geom0
, geom_seek
;
1620 if (offset
>= (LONG_MAX
/ SECTOR_SIZE
- 1)) {
1621 /* Move partition base. */
1622 if (ioctl(device
, DIOCGETP
, &geom0
) < 0) return -1;
1623 geom_seek
.base
= add64(geom0
.base
, off64
);
1624 geom_seek
.size
= cvu64(cmp64(add64u(off64
, SECTOR_SIZE
),
1625 geom0
.size
) <= 0 ? _STATIC_BLOCK_SIZE
: 0);
1627 if (ioctl(device
, DIOCSETP
, &geom_seek
) < 0) return -1;
1628 if (lseek(device
, (off_t
) 0, SEEK_SET
) == -1) return -1;
1630 /* Can reach this point normally. */
1631 if (lseek(device
, (off_t
) offset
* SECTOR_SIZE
, SEEK_SET
) == -1)
1637 case 0: r
= read(device
, bootblock
, SECTOR_SIZE
); break;
1638 case 1: r
= write(device
, bootblock
, SECTOR_SIZE
); break;
1642 if (offset
>= (LONG_MAX
/ SECTOR_SIZE
- 1)) {
1643 /* Restore partition base and size. */
1645 if (ioctl(device
, DIOCSETP
, &geom0
) < 0) return -1;
1651 void m_read(int ev
, object_t
*op
)
1652 /* Read the partition table from the current device. */
1655 struct part_entry
*pe
;
1657 if (ev
!= 'r' || device
>= 0) return;
1659 /* Open() may cause kernel messages: */
1663 if (((device
= open(curdev
->name
, mode
= O_RDWR
, 0666)) < 0
1665 || (device
= open(curdev
->name
, mode
= O_RDONLY
)) < 0))
1668 printf("%s: %s", curdev
->name
, strerror(errno
));
1670 if (device
>= 0) { close(device
); device
= -1; }
1674 /* Assume up to five lines of kernel messages. */
1678 if (mode
== O_RDONLY
) {
1680 printf("%s: Readonly", curdev
->name
);
1683 memset(bootblock
, 0, sizeof(bootblock
));
1685 n
= boot_readwrite(0);
1687 if (n
<= 0) stat_start(1);
1689 printf("%s: %s", curdev
->name
, strerror(errno
));
1693 if (n
< SECTOR_SIZE
) printf("%s: Unexpected EOF", curdev
->subname
);
1694 if (n
<= 0) stat_end(5);
1696 if (n
< SECTOR_SIZE
) n
= SECTOR_SIZE
;
1698 memcpy(table
+1, bootblock
+PART_TABLE_OFF
,
1699 NR_PARTITIONS
* sizeof(table
[1]));
1700 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1701 if ((table
[i
].bootind
& ~ACTIVE_FLAG
) != 0) break;
1703 if (i
<= NR_PARTITIONS
|| bootblock
[510] != 0x55
1704 || bootblock
[511] != 0xAA) {
1705 /* Invalid boot block, install bootstrap, wipe partition table.
1707 memset(bootblock
, 0, sizeof(bootblock
));
1708 installboot(bootblock
, MASTERBOOT
);
1709 memset(table
+1, 0, NR_PARTITIONS
* sizeof(table
[1]));
1711 printf("%s: Invalid partition table (reset)", curdev
->subname
);
1715 /* Fix an extended partition table up to something mere mortals can
1716 * understand. Record already defined partitions.
1718 for (i
= 1; i
<= NR_PARTITIONS
; i
++) {
1720 if (extbase
!= 0 && pe
->sysind
!= NO_PART
)
1721 pe
->lowsec
+= ext_part(pe
->sysind
) ? extbase
: offset
;
1722 existing
[i
]= pe
->sysind
!= NO_PART
;
1727 /* Warn about grave dangers ahead. */
1730 printf("Warning: You are in an extended partition.");
1735 void m_write(int ev
, object_t
*op
)
1736 /* Write the partition table back if modified. */
1739 struct part_entry new_table
[NR_PARTITIONS
], *pe
;
1741 if (ev
!= 'w' && ev
!= E_WRITE
) return;
1742 if (device
< 0) { dirty
= 0; return; }
1746 printf("%s is not changed, or has already been written",
1753 if (bootblock
[510] != 0x55 || bootblock
[511] != 0xAA) {
1754 /* Invalid boot block, warn user. */
1756 printf("Warning: About to write a new table on %s",
1761 /* Will this stop the luser? Probably not... */
1763 printf("You have changed an extended partition. Bad Idea.");
1767 putstr("Save partition table? (y/n) ");
1770 while ((c
= getchar()) != 'y' && c
!= 'n' && c
!= ctrl('?')) {}
1772 if (c
== ctrl('?')) putstr("DEL"); else putchr(c
);
1774 if (c
== 'n' && ev
== E_WRITE
) dirty
= 0;
1775 if (c
!= 'y') return;
1777 memcpy(new_table
, table
+1, NR_PARTITIONS
* sizeof(table
[1]));
1778 for (pe
= new_table
; pe
< new_table
+ NR_PARTITIONS
; pe
++) {
1779 if (pe
->sysind
== NO_PART
) {
1780 memset(pe
, 0, sizeof(*pe
));
1782 abs2dos(&pe
->start_head
, pe
->lowsec
);
1783 abs2dos(&pe
->last_head
, pe
->lowsec
+ pe
->size
- 1);
1785 /* Fear and loathing time: */
1787 pe
->lowsec
-= ext_part(pe
->sysind
)
1791 memcpy(bootblock
+PART_TABLE_OFF
, new_table
, sizeof(new_table
));
1792 bootblock
[510]= 0x55;
1793 bootblock
[511]= 0xAA;
1795 if (boot_readwrite(1) < 0) {
1797 printf("%s: %s", curdev
->name
, strerror(errno
));
1804 void m_shell(int ev
, object_t
*op
)
1805 /* Shell escape, to do calculations for instance. */
1808 void (*sigint
)(int), (*sigquit
)(int), (*sigterm
)(int);
1810 if (ev
!= 's') return;
1815 switch (pid
= fork()) {
1818 printf("can't fork: %s\n", strerror(errno
));
1822 if (device
>= 0) (void) close(device
);
1823 execl("/bin/sh", "sh", (char *) nil
);
1826 printf("/bin/sh: %s\n", strerror(errno
));
1830 sigint
= signal(SIGINT
, SIG_IGN
);
1831 sigquit
= signal(SIGQUIT
, SIG_IGN
);
1832 sigterm
= signal(SIGTERM
, SIG_IGN
);
1833 while (pid
>= 0 && (r
= wait(&status
)) >= 0 && r
!= pid
) {}
1834 (void) signal(SIGINT
, sigint
);
1835 (void) signal(SIGQUIT
, sigquit
);
1836 (void) signal(SIGTERM
, sigterm
);
1841 if (WIFEXITED(status
) && WEXITSTATUS(status
) == 127)
1842 stat_start(0); /* Match the stat_start in the child. */
1844 event(ctrl('L'), op
);
1847 void m_dump(int ev
, object_t
*op
)
1848 /* Raw dump of the partition table. */
1850 struct part_entry table
[NR_PARTITIONS
], *pe
;
1854 if (ev
!= 'p' || device
< 0) return;
1856 memcpy(table
, bootblock
+PART_TABLE_OFF
,
1857 NR_PARTITIONS
* sizeof(table
[0]));
1858 for (i
= 0; i
< NR_PARTITIONS
; i
++) {
1861 dos2chs(&pe
->start_head
, chs
);
1862 printf("%2d%c %02X%15d%5d%4d",
1864 pe
->bootind
& ACTIVE_FLAG
? '*' : ' ',
1866 chs
[0], chs
[1], chs
[2]);
1867 dos2chs(&pe
->last_head
, chs
);
1868 printf("%6d%5d%4d%10lu%10ld%9lu",
1869 chs
[0], chs
[1], chs
[2],
1871 howend
== SIZE
? pe
->size
: pe
->size
+ pe
->lowsec
- 1,
1876 printf("(Raw dump of the original %.40s table)",
1883 void m_quit(int ev
, object_t
*op
)
1884 /* Write the partition table if modified and exit. */
1886 if (ev
!= 'q' && ev
!= 'x') return;
1890 if (dirty
) event(E_WRITE
, op
);
1891 if (dirty
) quitting
= 0;
1894 void m_help(int ev
, object_t
*op
)
1895 /* For people without a clue; let's hope they can find the '?' key. */
1897 static struct help
{
1901 { "? !", "This help / more advice!" },
1902 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
1903 { "0-9 (a-f)", "Enter value" },
1904 { "hjkl (arrow keys)", "Move around" },
1905 { "CTRL-K CTRL-J", "Move entry up/down" },
1906 { "CTRL-L", "Redraw screen" },
1907 { ">", "Start a subpartition table" },
1908 { "<", "Back to the primary partition table" },
1909 { "m", "Cycle through magic values" },
1910 { "spacebar", "Show \"Size\" or \"Last\"" },
1911 { "r w", "Read/write partition table" },
1912 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
1913 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
1915 static char *advice
[] = {
1916 "* Choose a disk with '+' and '-', then hit 'r'.",
1917 "* To change any value: Move to it and use '+', '-' or type the desired value.",
1918 "* To make a new partition: Move over to the Size or Kb field of an unused",
1919 " partition and type the size. Hit the 'm' key to pad the partition out to",
1920 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
1921 " You can hit 'm' more than once on a base or size field to see several",
1922 " interesting values go by. Note: Other Operating Systems can be picky about",
1923 " partitions that are not padded to cylinder boundaries. Look for highlighted",
1924 " head or sector numbers.",
1925 "* To reuse a partition: Change the type to MINIX.",
1926 "* To delete a partition: Type a zero in the hex Type field.",
1927 "* To make a partition active: Type '+' in the Num field.",
1928 "* To study the list of keys: Type '?'.",
1934 for (hp
= help
; hp
< arraylimit(help
); hp
++) {
1936 printf("%-25s - %s", hp
->keys
, hp
->what
);
1940 putstr("Things like ");
1941 putstr(t_so
); putstr("this"); putstr(t_se
);
1942 putstr(" must be checked, but ");
1943 putstr(t_md
); putstr("this"); putstr(t_me
);
1944 putstr(" is not really a problem");
1950 for (ap
= advice
; ap
< arraylimit(advice
); ap
++) {
1958 void event(int ev
, object_t
*op
)
1959 /* Simply call all modifiers for an event, each one knows when to act. */
1964 m_orientation(ev
, op
);
1981 /* Get a single keypress. Translate compound keypresses (arrow keys) to
1982 * their simpler equivalents.
1989 set_cursor(curobj
->row
, curobj
->col
);
1993 if (read(0, &ch
, sizeof(ch
)) < 0) fatal("stdin");
1994 c
= (unsigned char) ch
;
1998 case ctrl('['): esc
= 1; break;
1999 case '_': c
= '-'; break;
2000 case '=': c
= '+'; break;
2004 esc
= c
== '[' ? 2 : 0;
2008 case 'D': c
= 'h'; break;
2009 case 'B': c
= 'j'; break;
2010 case 'A': c
= 'k'; break;
2011 case 'C': c
= 'l'; break;
2012 case 'H': c
= 'H'; break;
2014 case 'S': c
= '-'; break;
2016 case 'T': c
= '+'; break;
2025 case ctrl('B'): c
= 'h'; break;
2026 case ctrl('N'): c
= 'j'; break;
2027 case ctrl('P'): c
= 'k'; break;
2028 case ctrl('F'): c
= 'l'; break;
2035 /* Get keypress, handle event, display results, reset screen, ad infinitum. */
2050 int main(int argc
, char **argv
)
2054 struct part_entry
*pe
;
2056 /* Define a few objects to show on the screen. First text: */
2057 op
= newobject(O_INFO
, 0, 0, 2, 19);
2058 op
= newobject(O_TEXT
, 0, 0, 22, 13); op
->text
= "----first----";
2059 op
= newobject(O_TEXT
, 0, 0, 37, 13); op
->text
= "--geom/last--";
2060 op
= newobject(O_TEXT
, 0, 0, 52, 18); op
->text
= "------sectors-----";
2061 op
= newobject(O_TEXT
, 0, 1, 4, 6); op
->text
= "Device";
2062 op
= newobject(O_TEXT
, 0, 1, 23, 12); op
->text
= "Cyl Head Sec";
2063 op
= newobject(O_TEXT
, 0, 1, 38, 12); op
->text
= "Cyl Head Sec";
2064 op
= newobject(O_TEXT
, 0, 1, 56, 4); op
->text
= "Base";
2065 op
= newobject(O_TEXT
, 0, 1, 66, 4); op
->text
= size_last
;
2066 op
= newobject(O_TEXT
, 0, 1, 78, 2); op
->text
= "Kb";
2067 op
= newobject(O_TEXT
, 0, 4, 0, 15); op
->text
= "Num Sort Type";
2069 /* The device is the current object: */
2070 curobj
= newobject(O_DEV
, OF_MOD
, 2, 4, 15);
2071 op
= newobject(O_SUB
, 0, 3, 4, 15);
2074 op
= newobject(O_CYL
, OF_MOD
, 2, 40, 5); op
->entry
= &table
[0];
2075 op
= newobject(O_HEAD
, OF_MOD
, 2, 45, 3); op
->entry
= &table
[0];
2076 op
= newobject(O_SEC
, OF_MOD
, 2, 49, 2); op
->entry
= &table
[0];
2078 /* Objects for the device: */
2079 op
= newobject(O_SCYL
, 0, 3, 25, 5); op
->entry
= &table
[0];
2080 op
= newobject(O_SHEAD
, 0, 3, 30, 3); op
->entry
= &table
[0];
2081 op
= newobject(O_SSEC
, 0, 3, 34, 2); op
->entry
= &table
[0];
2082 op
= newobject(O_LCYL
, 0, 3, 40, 5); op
->entry
= &table
[0];
2083 op
= newobject(O_LHEAD
, 0, 3, 45, 3); op
->entry
= &table
[0];
2084 op
= newobject(O_LSEC
, 0, 3, 49, 2); op
->entry
= &table
[0];
2085 op
= newobject(O_BASE
, 0, 3, 59, 9); op
->entry
= &table
[0];
2086 op
= newobject(O_SIZE
, 0, 3, 69, 9); op
->entry
= &table
[0];
2087 op
= newobject(O_KB
, 0, 3, 79, 9); op
->entry
= &table
[0];
2089 /* Objects for each partition: */
2090 for (r
= 5, pe
= table
+1; pe
<= table
+NR_PARTITIONS
; r
++, pe
++) {
2091 op
= newobject(O_NUM
, OF_MOD
, r
, 1, 2); op
->entry
= pe
;
2092 op
= newobject(O_SORT
, 0, r
, 5, 2); op
->entry
= pe
;
2093 op
= newobject(O_TYPHEX
, OF_MOD
, r
, 10, 2); op
->entry
= pe
;
2094 op
= newobject(O_TYPTXT
, OF_MOD
, r
, 12, 9); op
->entry
= pe
;
2095 op
= newobject(O_SCYL
, OF_MOD
, r
, 25, 5); op
->entry
= pe
;
2096 op
= newobject(O_SHEAD
, OF_MOD
, r
, 30, 3); op
->entry
= pe
;
2097 op
= newobject(O_SSEC
, OF_MOD
, r
, 34, 2); op
->entry
= pe
;
2098 op
= newobject(O_LCYL
, OF_MOD
, r
, 40, 5); op
->entry
= pe
;
2099 op
= newobject(O_LHEAD
, OF_MOD
, r
, 45, 3); op
->entry
= pe
;
2100 op
= newobject(O_LSEC
, OF_MOD
, r
, 49, 2); op
->entry
= pe
;
2101 op
= newobject(O_BASE
, OF_MOD
, r
, 59, 9); op
->entry
= pe
;
2102 op
= newobject(O_SIZE
, OF_MOD
, r
, 69, 9); op
->entry
= pe
;
2103 op
= newobject(O_KB
, OF_MOD
, r
, 79, 9); op
->entry
= pe
;
2106 for (i
= 1; i
< argc
; i
++) newdevice(argv
[i
], 0);
2108 if (firstdev
== nil
) {
2115 if (firstdev
!= nil
) {