source: trunk/minix/commands/ibm/part.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 52.5 KB
Line 
1/* part 1.57 - Partition table editor Author: Kees J. Bot
2 * 13 Mar 1992
3 * Needs about 22k heap+stack.
4 */
5#define nil 0
6#include <sys/types.h>
7#include <stdio.h>
8#include <termcap.h>
9#include <errno.h>
10#include <unistd.h>
11#include <stddef.h>
12#include <stdlib.h>
13#include <string.h>
14#include <signal.h>
15#include <fcntl.h>
16#include <time.h>
17#include <dirent.h>
18#include <limits.h>
19#include <a.out.h>
20#include <sys/stat.h>
21#include <sys/wait.h>
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 <ibm/partition.h>
28#include <termios.h>
29
30/* True if a partition is an extended partition. */
31#define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
32
33/* Minix master bootstrap code. */
34static char MASTERBOOT[] = "/usr/mdec/masterboot";
35
36/* Template:
37 ----first---- --geom/last-- ------sectors-----
38 Device Cyl Head Sec Cyl Head Sec Base Size Kb
39 /dev/c0d0 977 5 17
40 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521
41Num Sort Type
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
46
47 */
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 */
52
53#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
54#define arraylimit(a) ((a) + arraysize(a))
55
56void report(const char *label)
57{
58 fprintf(stderr, "part: %s: %s\n", label, strerror(errno));
59}
60
61void fatal(const char *label)
62{
63 report(label);
64 exit(1);
65}
66
67struct termios termios;
68
69void save_ttyflags(void)
70/* Save tty attributes for later restoration. */
71{
72 if (tcgetattr(0, &termios) < 0) fatal("");
73}
74
75void restore_ttyflags(void)
76/* Reset the tty flags to how we got 'em. */
77{
78 if (tcsetattr(0, TCSANOW, &termios) < 0) fatal("");
79}
80
81void tty_raw(void)
82/* Set the terminal to raw mode, no signals, no echoing. */
83{
84 struct termios rawterm;
85
86 rawterm= termios;
87 rawterm.c_lflag &= ~(ICANON|ISIG|ECHO);
88 rawterm.c_iflag &= ~(ICRNL);
89 if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal("");
90}
91
92#define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
93
94char t_cd[16], t_cm[32], t_so[16], t_se[16], t_md[16], t_me[16];
95int t_li, t_co;
96#define STATUSROW 10
97
98void init_tty(void)
99/* Get terminal capabilities and set the tty to "editor" mode. */
100{
101 char *term;
102 static char termbuf[1024];
103 char *tp;
104
105 if ((term= getenv("TERM")) == nil || tgetent(termbuf, term) != 1) {
106 fprintf(stderr, "part: Can't get terminal capabilities\n");
107 exit(1);
108 }
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");
112 exit(1);
113 }
114 t_li= tgetnum("li");
115 t_co= tgetnum("co");
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));
120
121 save_ttyflags();
122 tty_raw();
123}
124
125void putchr(int c)
126{
127 putchar(c);
128}
129
130void putstr(char *s)
131{
132 int c;
133
134 while ((c= *s++) != 0) putchr(c);
135}
136
137void set_cursor(int row, int col)
138{
139 tputs(tgoto(t_cm, col, row), 1, putchr);
140}
141
142int statusrow= STATUSROW;
143int stat_ktl= 1;
144int need_help= 1;
145
146void stat_start(int serious)
147/* Prepare for printing on a fresh status line, possibly highlighted. */
148{
149 set_cursor(statusrow++, 0);
150 tputs(t_cd, 1, putchr);
151 if (serious) tputs(t_so, 1, putchr);
152}
153
154void stat_end(int ktl)
155/* Closing bracket for stat_start. Sets "keystrokes to live" of message. */
156{
157 tputs(t_se, 1, putchr);
158 stat_ktl= ktl;
159 need_help= 1;
160}
161
162void stat_reset(void)
163/* Reset the statusline pointer and clear old messages if expired. */
164{
165 if (stat_ktl > 0 && --stat_ktl == 0) {
166 statusrow= STATUSROW;
167 need_help= 1;
168 }
169 if (need_help && statusrow < (24-2)) {
170 if (statusrow > STATUSROW) stat_start(0);
171 stat_start(0);
172 putstr(
173"Type '+' or '-' to change, 'r' to read, '?' for more help, 'q' to exit");
174 }
175 statusrow= STATUSROW;
176 need_help= 0;
177}
178
179void clear_screen(void)
180{
181 set_cursor(0, 0);
182 tputs(t_cd, 1, putchr);
183 stat_ktl= 1;
184 stat_reset();
185}
186
187void reset_tty(void)
188/* Reset the tty to cooked mode. */
189{
190 restore_ttyflags();
191 set_cursor(statusrow, 0);
192 tputs(t_cd, 1, putchr);
193}
194
195void *alloc(size_t n)
196{
197 void *m;
198
199 if ((m= malloc(n)) == nil) { reset_tty(); fatal(""); }
200
201 return m;
202}
203
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)))
209#endif
210
211typedef enum parttype { DUNNO, SUBPART, PRIMARY, FLOPPY } parttype_t;
212
213typedef 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 */
218 parttype_t parttype;
219} device_t;
220
221device_t *firstdev= nil, *curdev;
222
223void 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.
226 */
227{
228 device_t *new, *nextdev, *prevdev;
229 struct stat st;
230
231 st.st_rdev= 0;
232 if (scanning) {
233 if (stat(name, &st) < 0 || !S_ISBLK(st.st_mode)) return;
234
235 switch (major(st.st_rdev)) {
236 case 2:
237 /* Floppy */
238 if (minor(st.st_rdev) >= 4) return;
239 break;
240 case 3:
241 case 8:
242 case 10:
243 case 12:
244 case 16:
245 /* Disk controller */
246 if (minor(st.st_rdev) >= 0x80
247 || minor(st.st_rdev) % 5 != 0) return;
248 break;
249 default:
250 return;
251 }
252 /* Interesting device found. */
253 } else {
254 (void) stat(name, &st);
255 }
256
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;
265 } else
266 if (st.st_rdev >= DEV_C0D0 && minor(st.st_rdev) < 128
267 && minor(st.st_rdev) % 5 == 0) {
268 new->parttype= PRIMARY;
269 }
270
271 if (firstdev == nil) {
272 firstdev= new;
273 new->next= new->prev= new;
274 curdev= firstdev;
275 return;
276 }
277 nextdev= firstdev;
278 while (new->rdev >= nextdev->rdev
279 && (nextdev= nextdev->next) != firstdev) {}
280 prevdev= nextdev->prev;
281 new->next= nextdev;
282 nextdev->prev= new;
283 new->prev= prevdev;
284 prevdev->next= new;
285
286 if (new->rdev < firstdev->rdev) firstdev= new;
287 if (new->rdev == DEV_C0D0) curdev= new;
288 if (curdev->rdev != DEV_C0D0) curdev= firstdev;
289}
290
291void getdevices(void)
292/* Get all block devices from /dev that look interesting. */
293{
294 DIR *d;
295 struct dirent *e;
296 char name[5 + NAME_MAX + 1];
297
298 if ((d= opendir("/dev")) == nil) fatal("/dev");
299
300 while ((e= readdir(d)) != nil) {
301 strcpy(name, "/dev/");
302 strcpy(name + 5, e->d_name);
303 newdevice(name, 1);
304 }
305 (void) closedir(d);
306}
307
308/* One featureful master bootstrap. */
309unsigned char bootstrap[] = {
3100353,0001,0000,0061,0300,0216,0330,0216,0300,0372,0216,0320,0274,0000,0174,0373,
3110275,0276,0007,0211,0346,0126,0277,0000,0006,0271,0000,0001,0374,0363,0245,0352,
3120044,0006,0000,0000,0264,0002,0315,0026,0250,0010,0164,0033,0350,0071,0001,0174,
3130007,0060,0344,0315,0026,0242,0205,0007,0054,0060,0074,0012,0163,0363,0120,0350,
3140046,0001,0205,0007,0130,0353,0012,0240,0002,0006,0204,0300,0165,0003,0351,0147,
3150000,0230,0262,0005,0366,0362,0262,0200,0000,0302,0210,0340,0120,0350,0234,0000,
3160163,0003,0351,0147,0000,0130,0054,0001,0175,0003,0351,0141,0000,0276,0276,0175,
3170211,0357,0271,0040,0000,0363,0245,0200,0301,0004,0211,0356,0215,0174,0020,0070,
3180154,0004,0164,0016,0213,0135,0010,0053,0134,0010,0213,0135,0012,0033,0134,0012,
3190163,0014,0212,0044,0206,0144,0020,0210,0044,0106,0071,0376,0162,0364,0211,0376,
3200201,0376,0356,0007,0162,0326,0342,0322,0211,0356,0264,0020,0366,0344,0001,0306,
3210200,0174,0004,0001,0162,0026,0353,0021,0204,0322,0175,0041,0211,0356,0200,0174,
3220004,0000,0164,0013,0366,0004,0200,0164,0006,0350,0070,0000,0162,0053,0303,0203,
3230306,0020,0201,0376,0376,0007,0162,0346,0350,0215,0000,0211,0007,0376,0302,0204,
3240322,0174,0023,0315,0021,0321,0340,0321,0340,0200,0344,0003,0070,0342,0167,0355,
3250350,0011,0000,0162,0350,0303,0350,0003,0000,0162,0146,0303,0211,0356,0214,0134,
3260010,0214,0134,0012,0277,0003,0000,0122,0006,0127,0264,0010,0315,0023,0137,0007,
3270200,0341,0077,0376,0306,0210,0310,0366,0346,0211,0303,0213,0104,0010,0213,0124,
3280012,0367,0363,0222,0210,0325,0366,0361,0060,0322,0321,0352,0321,0352,0010,0342,
3290210,0321,0376,0301,0132,0210,0306,0273,0000,0174,0270,0001,0002,0315,0023,0163,
3300020,0200,0374,0200,0164,0011,0117,0174,0006,0060,0344,0315,0023,0163,0270,0371,
3310303,0201,0076,0376,0175,0125,0252,0165,0001,0303,0350,0013,0000,0243,0007,0353,
3320005,0350,0004,0000,0227,0007,0353,0376,0136,0255,0126,0211,0306,0254,0204,0300,
3330164,0011,0264,0016,0273,0001,0000,0315,0020,0353,0362,0303,0057,0144,0145,0166,
3340057,0150,0144,0077,0010,0000,0015,0012,0000,0116,0157,0156,0145,0040,0141,0143,
3350164,0151,0166,0145,0015,0012,0000,0122,0145,0141,0144,0040,0145,0162,0162,0157,
3360162,0040,0000,0116,0157,0164,0040,0142,0157,0157,0164,0141,0142,0154,0145,0040,
3370000,0000,
338};
339
340int dirty= 0;
341unsigned char bootblock[SECTOR_SIZE];
342struct part_entry table[1 + NR_PARTITIONS];
343int existing[1 + NR_PARTITIONS];
344unsigned long offset= 0, extbase= 0, extsize;
345int submerged= 0;
346char sort_index[1 + NR_PARTITIONS];
347unsigned cylinders= 1, heads= 1, sectors= 1, secpcyl= 1;
348unsigned alt_cyls= 1, alt_heads= 1, alt_secs= 1;
349int precise= 0;
350int device= -1;
351
352unsigned long sortbase(struct part_entry *pe)
353{
354 return pe->sysind == NO_PART ? -1 : pe->lowsec;
355}
356
357void sort(void)
358/* Let the sort_index array show the order partitions are sorted in. */
359{
360 int i, j;
361 int idx[1 + NR_PARTITIONS];
362
363 for (i= 1; i <= NR_PARTITIONS; i++) idx[i]= i;
364
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];
368
369 if (sortbase(&table[sj]) > sortbase(&table[sj1])) {
370 idx[j]= sj1;
371 idx[j+1]= sj;
372 }
373 }
374 }
375 for (i= 1; i <= NR_PARTITIONS; i++) sort_index[idx[i]]= i;
376}
377
378void 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.
382 */
383{
384 chs[0]= ((dos[1] & 0xC0) << 2) | dos[2];
385 chs[1]= dos[0];
386 chs[2]= (dos[1] & 0x3F) - 1;
387}
388
389void abs2dos(unsigned char *dos, unsigned long pos)
390/* Translate a sector offset to three DOS bytes. */
391{
392 unsigned h, c, s;
393
394 c= pos / secpcyl;
395 h= (pos % secpcyl) / sectors;
396 s= pos % sectors + 1;
397
398 dos[0]= h;
399 dos[1]= s | ((c >> 2) & 0xC0);
400 dos[2]= c & 0xFF;
401}
402
403void recompute0(void)
404/* Recompute the partition size for the device after a geometry change. */
405{
406 if (device < 0) {
407 cylinders= heads= sectors= 1;
408 memset(table, 0, sizeof(table));
409 } else
410 if (!precise && offset == 0) {
411 table[0].lowsec= 0;
412 table[0].size= (unsigned long) cylinders * heads * sectors;
413 }
414 table[0].sysind= device < 0 ? NO_PART : MINIX_PART;
415 secpcyl= heads * sectors;
416}
417
418void 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...)
422 */
423{
424 int i, n;
425 struct part_entry *pe;
426 unsigned chs[3];
427 unsigned long sec;
428 unsigned h, s;
429 unsigned char HS[256][8]; /* Bit map off all possible H/S */
430
431 alt_cyls= alt_heads= alt_secs= 0;
432
433 /* Initially all possible H/S combinations are possible. HS[h][0]
434 * bit 0 is used to rule out a head value.
435 */
436 for (h= 1; h <= 255; h++) {
437 for (s= 0; s < 8; s++) HS[h][s]= 0xFF;
438 }
439
440 for (i= 0; i < 2*NR_PARTITIONS; i++) {
441 pe= &(table+1)[i >> 1];
442 if (pe->sysind == NO_PART) continue;
443
444 /* Get the end or start sector numbers (in that order). */
445 if ((i & 1) == 0) {
446 dos2chs(&pe->last_head, chs);
447 sec= pe->lowsec + pe->size - 1;
448 } else {
449 dos2chs(&pe->start_head, chs);
450 sec= pe->lowsec;
451 }
452
453 if (chs[0] >= alt_cyls) alt_cyls= chs[0]+1;
454
455 /* Which H/S combinations can be ruled out? */
456 for (h= 1; h <= 255; h++) {
457 if (HS[h][0] == 0) continue;
458 n = 0;
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));
462 }
463 if (HS[h][s/8] & (1 << (s%8))) n++;
464 }
465 if (n == 0) HS[h][0]= 0;
466 }
467 }
468
469 /* See if only one remains. */
470 i= 0;
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))) {
475 i++;
476 alt_heads= h;
477 alt_secs= s;
478 }
479 }
480 }
481
482 /* Forget it if more than one choice... */
483 if (i > 1) alt_cyls= alt_heads= alt_secs= 0;
484}
485
486void geometry(void)
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
491 * partition.
492 */
493{
494 struct stat dst;
495 int err= 0;
496 struct partition geometry;
497
498 if (submerged) {
499 /* Geometry already known. */
500 sort();
501 return;
502 }
503 precise= 0;
504 cylinders= 0;
505 recompute0();
506 if (device < 0) return;
507
508 /* Try to guess the geometry from the partition table. */
509 guess_geometry();
510
511 /* Try to get the geometry from the driver. */
512 (void) fstat(device, &dst);
513
514 if (S_ISBLK(dst.st_mode) || S_ISCHR(dst.st_mode)) {
515 /* Try to get the drive's geometry from the driver. */
516
517 if (ioctl(device, DIOCGETP, &geometry) < 0)
518 err= errno;
519 else {
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;
525 precise= 1;
526 }
527 } else {
528 err= ENODEV;
529 }
530
531 if (err != 0) {
532 /* Getting the geometry from the driver failed, so use the
533 * alternate geometry.
534 */
535 if (alt_heads == 0) {
536 alt_cyls= table[0].size / (64 * 32);
537 alt_heads= 64;
538 alt_secs= 32;
539 }
540
541 cylinders= alt_cyls;
542 heads= alt_heads;
543 sectors= alt_secs;
544
545 stat_start(1);
546 printf("Failure to get the geometry of %s: %s", curdev->name,
547 errno == ENOTTY ? "No driver support" : strerror(err));
548 stat_end(5);
549 stat_start(0);
550 printf("The geometry has been guessed as %ux%ux%u",
551 cylinders, heads, sectors);
552 stat_end(5);
553 } else {
554 if (alt_heads == 0) {
555 alt_cyls= cylinders;
556 alt_heads= heads;
557 alt_secs= sectors;
558 }
559
560 if (heads != alt_heads || sectors != alt_secs) {
561 stat_start(1);
562 printf("WARNING:");
563 stat_end(10);
564 stat_start(0);
565 printf(
566"The %ux%ux%u geometry obtained from the device driver does not match",
567 cylinders, heads, sectors);
568 stat_end(10);
569 stat_start(0);
570 printf(
571"the %ux%ux%u geometry implied by the partition table. Hit 'X' to switch",
572 alt_cyls, alt_heads, alt_secs);
573 stat_end(10);
574 stat_start(0);
575 printf(
576"between the two geometries to see what is best. Note that the geometry");
577 stat_end(10);
578 stat_start(0);
579 printf(
580"must be correct when the table is written or the system may not boot!");
581 stat_end(10);
582 }
583 }
584
585 /* Show the base and size of the device instead of the whole drive.
586 * This makes sense for subpartitioning primary partitions.
587 */
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);
591 } else {
592 precise= 0;
593 }
594 recompute0();
595 sort();
596}
597
598typedef struct indicators { /* Partition type to partition name. */
599 unsigned char ind;
600 char name[10];
601} indicators_t;
602
603indicators_t ind_table[]= {
604 { 0x00, "None" },
605 { 0x01, "FAT-12" },
606 { 0x02, "XENIX /" },
607 { 0x03, "XENIX usr" },
608 { 0x04, "FAT-16" },
609 { 0x05, "EXTENDED" },
610 { 0x06, "FAT-16" },
611 { 0x07, "HPFS/NTFS" },
612 { 0x08, "AIX" },
613 { 0x09, "COHERENT" },
614 { 0x0A, "OS/2" },
615 { 0x0B, "FAT-32" },
616 { 0x0C, "FAT?" },
617 { 0x0E, "FAT?" },
618 { 0x0F, "EXTENDED" },
619 { 0x10, "OPUS" },
620 { 0x40, "VENIX286" },
621 { 0x42, "W2000 Dyn" },
622 { 0x52, "MICROPORT" },
623 { 0x63, "386/IX" },
624 { 0x64, "NOVELL286" },
625 { 0x65, "NOVELL386" },
626 { 0x75, "PC/IX" },
627 { 0x80, "MINIX-OLD" },
628 { 0x81, "MINIX" },
629 { 0x82, "LINUXswap" },
630 { 0x83, "LINUX" },
631 { 0x93, "AMOEBA" },
632 { 0x94, "AMOEBAbad" },
633 { 0xA5, "386BSD" },
634 { 0xB7, "BSDI" },
635 { 0xB8, "BSDI swap" },
636 { 0xC7, "SYRINX" },
637 { 0xDB, "CPM" },
638 { 0xFF, "BADBLOCKS" },
639};
640
641char *typ2txt(int ind)
642/* Translate a numeric partition indicator for human eyes. */
643{
644 indicators_t *pind;
645
646 for (pind= ind_table; pind < arraylimit(ind_table); pind++) {
647 if (pind->ind == ind) return pind->name;
648 }
649 return "";
650}
651
652int round_sysind(int ind, int delta)
653/* Find the next known partition type starting with ind in direction delta. */
654{
655 indicators_t *pind;
656
657 ind= (ind + delta) & 0xFF;
658
659 if (delta < 0) {
660 for (pind= arraylimit(ind_table)-1; pind->ind > ind; pind--) {}
661 } else {
662 for (pind= ind_table; pind->ind < ind; pind++) {}
663 }
664 return pind->ind;
665}
666
667/* Objects on the screen, either simple pieces of the text or the cylinder
668 * number of the start of partition three.
669 */
670typedef 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
675} objtype_t;
676
677#define rjust(type) ((type) >= O_TYPHEX)
678#define computed(type) ((type) >= O_TYPTXT)
679
680typedef struct object {
681 struct object *next;
682 objtype_t type; /* Text field, cylinder number, etc. */
683 char flags; /* Modifiable? */
684 char row;
685 char col;
686 char len;
687 struct part_entry *entry; /* What does the object refer to? */
688 char *text;
689 char value[20]; /* Value when printed. */
690} object_t;
691
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. */
695
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'. */
700
701/* The O_SIZE objects have a dual identity. */
702enum howend { SIZE, LAST } howend= SIZE;
703
704object_t *world= nil;
705object_t *curobj= nil;
706
707object_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. */
709{
710 object_t *new;
711 object_t **aop= &world;
712
713 new= alloc(sizeof(*new));
714
715 new->type= type;
716 new->flags= flags;
717 new->row= row;
718 new->col= col;
719 new->len= len;
720 new->entry= nil;
721 new->text= "";
722 new->value[0]= 0;
723
724 new->next= *aop;
725 *aop= new;
726
727 return new;
728}
729
730unsigned long entry2base(struct part_entry *pe)
731/* Return the base sector of the partition if defined. */
732{
733 return pe->sysind == NO_PART ? 0 : pe->lowsec;
734}
735
736unsigned long entry2last(struct part_entry *pe)
737{
738 return pe->sysind == NO_PART ? -1 : pe->lowsec + pe->size - 1;
739}
740
741unsigned long entry2size(struct part_entry *pe)
742{
743 return pe->sysind == NO_PART ? 0 : pe->size;
744}
745
746int overlap(unsigned long sec)
747/* See if sec is part of another partition. */
748{
749 struct part_entry *pe;
750
751 for (pe= table + 1; pe <= table + NR_PARTITIONS; pe++) {
752 if (pe->sysind == NO_PART) continue;
753
754 if (pe->lowsec < sec && sec < pe->lowsec + pe->size)
755 return 1;
756 }
757 return 0;
758}
759
760int aligned(unsigned long sec, unsigned unit)
761/* True if sec is aligned to unit or if it is no problem if it is unaligned. */
762{
763 return (offset != 0 && extbase == 0) || (sec % unit == 0);
764}
765
766void print(object_t *op)
767/* Print an object's value if it changed. */
768{
769 struct part_entry *pe= op->entry;
770 int n;
771 unsigned long t;
772 char *name;
773 int oldflags;
774 char oldvalue[20];
775
776 /* Remember the old flags and value. */
777 oldflags= op->flags;
778 strcpy(oldvalue, op->value);
779
780 op->flags&= ~(OF_ODD | OF_BAD);
781
782 switch (op->type) {
783 case O_INFO: {
784 /* Current field. */
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" },
802 { -1, "?" },
803 };
804 struct field *fp= fields;
805
806 while (fp->type >= 0 && fp->type != curobj->type) fp++;
807 strcpy(op->value, fp->name);
808 op->flags|= OF_ODD;
809 break; }
810 case O_TEXT:
811 /* Simple text field. */
812 strcpy(op->value, op->text);
813 break;
814 case O_DEV:
815 case O_SUB:
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;
822 break;
823 case O_NUM:
824 /* Position and active flag. */
825 sprintf(op->value, "%d%c", (int) (pe - table - 1),
826 pe->bootind & ACTIVE_FLAG ? '*' : ' ');
827 break;
828 case O_SORT:
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);
836 break;
837 case O_TYPHEX:
838 /* Hex partition type indicator. */
839 sprintf(op->value, "%02X", pe->sysind);
840 break;
841 case O_TYPTXT:
842 /* Ascii partition type indicator. */
843 strcpy(op->value, typ2txt(pe->sysind));
844 break;
845 case O_SCYL:
846 /* Partition's start cylinder. */
847 sprintf(op->value, "%lu", entry2base(pe) / secpcyl);
848 break;
849 case O_SHEAD:
850 /* Start head. */
851 t= entry2base(pe);
852 sprintf(op->value, "%lu", t % secpcyl / sectors);
853 if (!aligned(t, secpcyl) && t != table[0].lowsec + sectors)
854 op->flags|= OF_ODD;
855 break;
856 case O_SSEC:
857 /* Start sector. */
858 t= entry2base(pe);
859 sprintf(op->value, "%lu", t % sectors);
860 if (!aligned(t, sectors)) op->flags|= OF_ODD;
861 break;
862 case O_CYL:
863 /* Number of cylinders. */
864 sprintf(op->value, "%u", cylinders);
865 break;
866 case O_HEAD:
867 /* Number of heads. */
868 sprintf(op->value, "%u", heads);
869 break;
870 case O_SEC:
871 /* Number of sectors per track. */
872 sprintf(op->value, "%u", sectors);
873 break;
874 case O_LCYL:
875 /* Partition's last cylinder. */
876 t= entry2last(pe);
877 sprintf(op->value, "%lu", t == -1 ? 0 : t / secpcyl);
878 break;
879 case O_LHEAD:
880 /* Partition's last head. */
881 t= entry2last(pe);
882 sprintf(op->value, "%lu", t == -1 ? 0 : t % secpcyl / sectors);
883 if (!aligned(t + 1, secpcyl)) op->flags|= OF_ODD;
884 break;
885 case O_LSEC:
886 /* Partition's last sector. */
887 t= entry2last(pe);
888 sprintf(op->value, t == -1 ? "-1" : "%lu", t % sectors);
889 if (!aligned(t + 1, sectors)) op->flags|= OF_ODD;
890 break;
891 case O_BASE:
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)))
896 op->flags|= OF_BAD;
897 break;
898 case O_SIZE:
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)))
905 op->flags|= OF_BAD;
906 break;
907 case O_KB:
908 /* Size of partitition in kilobytes. */
909 sprintf(op->value, "%lu", entry2size(pe) / 2);
910 break;
911 default:
912 sprintf(op->value, "?? %d ??", op->type);
913 }
914
915 if (device < 0 && computed(op->type)) strcpy(op->value, "?");
916
917 /* If a value overflows the print field then show a blank
918 * reverse video field.
919 */
920 if ((n= strlen(op->value)) > op->len) {
921 n= 0;
922 op->flags|= OF_BAD;
923 }
924
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);
929 } else {
930 memset(op->value + n, ' ', op->len - n);
931 }
932 op->value[op->len]= 0;
933
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. */
937 return;
938 }
939
940 set_cursor(op->row, rjust(op->type) ? op->col - (op->len-1) : op->col);
941
942 if (op->flags & OF_BAD) tputs(t_so, 1, putchr);
943 else
944 if (op->flags & OF_ODD) tputs(t_md, 1, putchr);
945 putstr(op->value);
946 if (op->flags & OF_BAD) tputs(t_se, 1, putchr);
947 else
948 if (op->flags & OF_ODD) tputs(t_me, 1, putchr);
949}
950
951void display(void)
952/* Repaint all objects that changed. */
953{
954 object_t *op;
955
956 for (op= world; op != nil; op= op->next) print(op);
957}
958
959int typing; /* Set if a digit has been typed to set a value. */
960int magic; /* Changes when using the magic key. */
961
962void event(int ev, object_t *op);
963
964void m_redraw(int ev, object_t *op)
965/* Redraw the screen. */
966{
967 object_t *op2;
968
969 if (ev != ctrl('L')) return;
970
971 clear_screen();
972 for (op2= world; op2 != nil; op2= op2->next) op2->value[0]= 0;
973}
974
975void m_toggle(int ev, object_t *op)
976/* Toggle between the driver and alternate geometry. */
977{
978 unsigned t;
979
980 if (ev != 'X') return;
981 if (alt_cyls == cylinders && alt_heads == heads && alt_secs == sectors)
982 return;
983
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;
987 dirty= 1;
988 recompute0();
989}
990
991char size_last[]= "Size";
992
993void m_orientation(int ev, object_t *op)
994{
995 if (ev != ' ') return;
996
997 switch (howend) {
998 case SIZE:
999 howend= LAST;
1000 strcpy(size_last, "Last");
1001 break;
1002 case LAST:
1003 howend= SIZE;
1004 strcpy(size_last, "Size");
1005 }
1006}
1007
1008void 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.
1011 */
1012{
1013 object_t *near, *op2;
1014 unsigned dist, d2, dr, dc;
1015
1016 if (ev != 'h' && ev != 'j' && ev != 'k' && ev != 'l' && ev != 'H')
1017 return;
1018
1019 if (device < 0) {
1020 /* No device open? Then try to read first. */
1021 event('r', op);
1022 if (device < 0) return;
1023 }
1024
1025 near= op;
1026 dist= -1;
1027
1028 for (op2= world; op2 != nil; op2= op2->next) {
1029 if (op2 == op || !(op2->flags & OF_MOD)) continue;
1030
1031 dr= abs(op2->row - op->row);
1032 dc= abs(op2->col - op->col);
1033
1034 d2= 25*dr*dr + dc*dc;
1035 if (op2->row != op->row && op2->col != op->col) d2+= 1000;
1036
1037 switch (ev) {
1038 case 'h': /* Left */
1039 if (op2->col >= op->col) d2= -1;
1040 break;
1041 case 'j': /* Down */
1042 if (op2->row <= op->row) d2= -1;
1043 break;
1044 case 'k': /* Up */
1045 if (op2->row >= op->row) d2= -1;
1046 break;
1047 case 'l': /* Right */
1048 if (op2->col <= op->col) d2= -1;
1049 break;
1050 case 'H': /* Home */
1051 if (op2->type == O_DEV) d2= 0;
1052 }
1053 if (d2 < dist) { near= op2; dist= d2; }
1054 }
1055 if (near != op) event(E_LEAVE, op);
1056 event(E_ENTER, near);
1057}
1058
1059void m_updown(int ev, object_t *op)
1060/* Move a partition table entry up or down. */
1061{
1062 int i, j;
1063 struct part_entry tmp;
1064 int tmpx;
1065
1066 if (ev != ctrl('K') && ev != ctrl('J')) return;
1067 if (op->entry == nil) return;
1068
1069 i= op->entry - table;
1070 if (ev == ctrl('K')) {
1071 if (i <= 1) return;
1072 j= i-1;
1073 } else {
1074 if (i >= NR_PARTITIONS) return;
1075 j= i+1;
1076 }
1077
1078 tmp= table[i]; table[i]= table[j]; table[j]= tmp;
1079 tmpx= existing[i]; existing[i]= existing[j]; existing[j]= tmpx;
1080 sort();
1081 dirty= 1;
1082 event(ev == ctrl('K') ? 'k' : 'j', op);
1083}
1084
1085void m_enter(int ev, object_t *op)
1086/* We've moved onto this object. */
1087{
1088 if (ev != E_ENTER && ev != ' ' && ev != '<' && ev != '>' && ev != 'X')
1089 return;
1090 curobj= op;
1091 typing= 0;
1092 magic= 0;
1093}
1094
1095void m_leave(int ev, object_t *op)
1096/* About to leave this object. */
1097{
1098 if (ev != E_LEAVE) return;
1099}
1100
1101int within(unsigned *var, unsigned low, unsigned value, unsigned high)
1102/* Only set *var to value if it looks reasonable. */
1103{
1104 if (low <= value && value <= high) {
1105 *var= value;
1106 return 1;
1107 } else
1108 return 0;
1109}
1110
1111int lwithin(unsigned long *var, unsigned long low, unsigned long value,
1112 unsigned long high)
1113{
1114 if (low <= value && value <= high) {
1115 *var= value;
1116 return 1;
1117 } else
1118 return 0;
1119}
1120
1121int nextdevice(object_t *op, int delta)
1122/* Select the next or previous device from the device list. */
1123{
1124 dev_t rdev;
1125
1126 if (offset != 0) return 0;
1127 if (dirty) event(E_WRITE, op);
1128 if (dirty) return 0;
1129
1130 if (device >= 0) {
1131 (void) close(device);
1132 device= -1;
1133 }
1134 recompute0();
1135
1136 rdev= curdev->rdev;
1137 if (delta < 0) {
1138 do
1139 curdev= curdev->prev;
1140 while (delta < -1 && major(curdev->rdev) == major(rdev)
1141 && curdev->rdev < rdev);
1142 } else {
1143 do
1144 curdev= curdev->next;
1145 while (delta > 1 && major(curdev->rdev) == major(rdev)
1146 && curdev->rdev > rdev);
1147 }
1148 return 1;
1149}
1150
1151void check_ind(struct part_entry *pe)
1152/* If there are no other partitions then make this new one active. */
1153{
1154 struct part_entry *pe2;
1155
1156 if (pe->sysind != NO_PART) return;
1157
1158 for (pe2= table + 1; pe2 < table + 1 + NR_PARTITIONS; pe2++)
1159 if (pe2->sysind != NO_PART || pe2->bootind & ACTIVE_FLAG) break;
1160
1161 if (pe2 == table + 1 + NR_PARTITIONS) pe->bootind= ACTIVE_FLAG;
1162}
1163
1164int check_existing(struct part_entry *pe)
1165/* Check and if not ask if an existing partition may be modified. */
1166{
1167 static int expert= 0;
1168 int c;
1169
1170 if (expert || pe == nil || !existing[pe - table]) return 1;
1171
1172 stat_start(1);
1173 putstr("Do you wish to modify existing partitions? (y/n) ");
1174 fflush(stdout);
1175 while ((c= getchar()) != 'y' && c != 'n') {}
1176 putchr(c);
1177 stat_end(3);
1178 return (expert= (c == 'y'));
1179}
1180
1181void 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.
1184 */
1185{
1186 object_t *op2;
1187 struct part_entry *pe= op->entry;
1188 int mul, delta;
1189 unsigned level= 1;
1190 unsigned long surplus;
1191 int radix= op->type == O_TYPHEX ? 0x10 : 10;
1192 unsigned long t;
1193
1194 if (device < 0 && op->type != O_DEV) return;
1195
1196 switch (ev) {
1197 case '-':
1198 mul= radix; delta= -1; typing= 0;
1199 break;
1200 case '+':
1201 mul= radix; delta= 1; typing= 0;
1202 break;
1203 case '\b':
1204 if (!typing) return;
1205 mul= 1; delta= 0;
1206 break;
1207 case '\r':
1208 typing= 0;
1209 return;
1210 default:
1211 if ('0' <= ev && ev <= '9')
1212 delta= ev - '0';
1213 else
1214 if (radix == 0x10 && 'a' <= ev && ev <= 'f')
1215 delta= ev - 'a' + 10;
1216 else
1217 if (radix == 0x10 && 'A' <= ev && ev <= 'F')
1218 delta= ev - 'A' + 10;
1219 else
1220 return;
1221
1222 mul= typing ? radix*radix : 0;
1223 typing= 1;
1224 }
1225 magic= 0;
1226
1227 if (!check_existing(pe)) return;
1228
1229 switch (op->type) {
1230 case O_DEV:
1231 if (ev != '-' && ev != '+') return;
1232 if (!nextdevice(op, delta)) return;
1233 break;
1234 case O_CYL:
1235 if (!within(&cylinders, 1,
1236 cylinders * mul / radix + delta, 1024)) return;
1237 recompute0();
1238 break;
1239 case O_HEAD:
1240 if (!within(&heads, 1, heads * mul / radix + delta, 255))
1241 return;
1242 recompute0();
1243 break;
1244 case O_SEC:
1245 if (!within(&sectors, 1, sectors * mul / radix + delta, 63))
1246 return;
1247 recompute0();
1248 break;
1249 case O_NUM:
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;
1254 }
1255 op->entry->bootind= ev == '+' ? ACTIVE_FLAG : 0;
1256 break;
1257 case O_TYPHEX:
1258 check_ind(pe);
1259 pe->sysind= pe->sysind * mul / radix + delta;
1260 break;
1261 case O_TYPTXT:
1262 if (ev != '-' && ev != '+') return;
1263 check_ind(pe);
1264 pe->sysind= round_sysind(pe->sysind, delta);
1265 break;
1266 case O_SCYL:
1267 level= heads;
1268 case O_SHEAD:
1269 level*= sectors;
1270 case O_SSEC:
1271 if (op->type != O_SCYL && ev != '-' && ev != '+') return;
1272 case O_BASE:
1273 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe));
1274 t= pe->lowsec;
1275 surplus= t % level;
1276 if (!lwithin(&t, 0L,
1277 (t / level * mul / radix + delta) * level + surplus,
1278 MAXSIZE)) return;
1279 if (howend == LAST || op->type != O_BASE)
1280 pe->size-= t - pe->lowsec;
1281 pe->lowsec= t;
1282 check_ind(pe);
1283 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
1284 break;
1285 case O_LCYL:
1286 level= heads;
1287 case O_LHEAD:
1288 level*= sectors;
1289 case O_LSEC:
1290 if (op->type != O_LCYL && ev != '-' && ev != '+') return;
1291
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,
1297 MAXSIZE)) return;
1298 pe->size= t - pe->lowsec + 1;
1299 check_ind(pe);
1300 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
1301 break;
1302 case O_KB:
1303 level= 2;
1304 if (mul == 0) pe->size= 0; /* new value, no surplus */
1305 case O_SIZE:
1306 if (pe->sysind == NO_PART) {
1307 if (op->type == O_KB || howend == SIZE) {
1308 /* First let loose magic to set the base. */
1309 event('m', op);
1310 magic= 0;
1311 pe->size= 0;
1312 event(ev, op);
1313 return;
1314 }
1315 memset(pe, 0, sizeof(*pe));
1316 }
1317 t= (op->type == O_KB || howend == SIZE) ? pe->size
1318 : pe->lowsec + pe->size - 1;
1319 surplus= t % level;
1320 if (!lwithin(&t, 0L,
1321 (t / level * mul / radix + delta) * level + surplus,
1322 MAXSIZE)) return;
1323 pe->size= (op->type == O_KB || howend == SIZE) ? t :
1324 t - pe->lowsec + 1;
1325 check_ind(pe);
1326 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
1327 break;
1328 default:
1329 return;
1330 }
1331
1332 /* The order among the entries may have changed. */
1333 sort();
1334 dirty= 1;
1335}
1336
1337unsigned long spell[3 + 4 * (1+NR_PARTITIONS)];
1338int nspells;
1339objtype_t touching;
1340
1341void newspell(unsigned long charm)
1342/* Add a new spell, descending order for the base, ascending for the size. */
1343{
1344 int i, j;
1345
1346 if (charm - table[0].lowsec > table[0].size) return;
1347
1348 for (i= 0; i < nspells; i++) {
1349 if (charm == spell[i]) return; /* duplicate */
1350
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;
1354 } else {
1355 if (charm == table[0].lowsec) return;
1356 if ((charm - spell[0]) < (spell[i] - spell[0])) break;
1357 }
1358 }
1359 for (j= ++nspells; j > i; j--) spell[j]= spell[j-1];
1360 spell[i]= charm;
1361}
1362
1363void m_magic(int ev, object_t *op)
1364/* Apply magic onto a base or size number. */
1365{
1366 struct part_entry *pe= op->entry, *pe2;
1367 int rough= (offset != 0 && extbase == 0);
1368
1369 if (ev != 'm' || device < 0) return;
1370 typing= 0;
1371
1372 if (!check_existing(pe)) return;
1373
1374 if (magic == 0) {
1375 /* See what magic we can let loose on this value. */
1376 nspells= 1;
1377
1378 /* First spell, the current value. */
1379 switch (op->type) {
1380 case O_SCYL:
1381 case O_SHEAD: /* Start of partition. */
1382 case O_SSEC:
1383 case O_BASE:
1384 touching= O_BASE;
1385 spell[0]= pe->lowsec;
1386 break;
1387 case O_LCYL:
1388 case O_LHEAD:
1389 case O_LSEC: /* End of partition. */
1390 case O_KB:
1391 case O_SIZE:
1392 touching= O_SIZE;
1393 spell[0]= pe->lowsec + pe->size;
1394 break;
1395 default:
1396 return;
1397 }
1398 if (pe->sysind == NO_PART) {
1399 memset(pe, 0, sizeof(*pe));
1400 check_ind(pe);
1401 pe->sysind= MINIX_PART;
1402 spell[0]= 0;
1403 if (touching == O_SIZE) {
1404 /* First let loose magic on the base. */
1405 object_t *op2;
1406
1407 for (op2= world; op2 != nil; op2= op2->next) {
1408 if (op2->row == op->row &&
1409 op2->type == O_BASE) {
1410 event('m', op2);
1411 }
1412 }
1413 magic= 0;
1414 event('m', op);
1415 return;
1416 }
1417 }
1418 /* Avoid the first sector on the device. */
1419 if (spell[0] == table[0].lowsec) newspell(spell[0] + 1);
1420
1421 /* Further interesting values are the the bases of other
1422 * partitions or their ends.
1423 */
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);
1428 else
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);
1434 }
1435 if (pe2->lowsec % sectors != 0) rough= 1;
1436 }
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
1440 * cylinder.
1441 */
1442 if (!rough) {
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;
1448 newspell(n);
1449 if (touching == O_SIZE)
1450 newspell(table[0].size / secpcyl * secpcyl);
1451 }
1452 }
1453 /* Magic has been applied, a spell needs to be chosen. */
1454
1455 if (++magic == nspells) magic= 0;
1456
1457 if (touching == O_BASE) {
1458 if (howend == LAST) pe->size-= spell[magic] - pe->lowsec;
1459 pe->lowsec= spell[magic];
1460 } else
1461 pe->size= spell[magic] - pe->lowsec;
1462
1463 /* The order among the entries may have changed. */
1464 sort();
1465 dirty= 1;
1466}
1467
1468typedef struct diving {
1469 struct diving *up;
1470 struct part_entry old0;
1471 char *oldsubname;
1472 parttype_t oldparttype;
1473 unsigned long oldoffset;
1474 unsigned long oldextbase;
1475} diving_t;
1476
1477diving_t *diving= nil;
1478
1479void m_in(int ev, object_t *op)
1480/* Go down into a primary or extended partition. */
1481{
1482 diving_t *newdiv;
1483 struct part_entry *pe= op->entry, ext;
1484 int n;
1485
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;
1490
1491 ext= *pe;
1492 if (extbase != 0) ext.size= extbase + extsize - ext.lowsec;
1493
1494 if (dirty) event(E_WRITE, op);
1495 if (dirty) return;
1496 if (device >= 0) { close(device); device= -1; }
1497
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;
1504 newdiv->up= diving;
1505 diving= newdiv;
1506
1507 table[0]= ext;
1508
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;
1515
1516 curdev->parttype= curdev->parttype == PRIMARY ? SUBPART : DUNNO;
1517 offset= ext.lowsec;
1518 if (ext_part(ext.sysind) && extbase == 0) {
1519 extbase= ext.lowsec;
1520 extsize= ext.size;
1521 curdev->parttype= DUNNO;
1522 }
1523
1524 submerged= 1;
1525 event('r', op);
1526}
1527
1528void m_out(int ev, object_t *op)
1529/* Go up from an extended or subpartition table to its enclosing. */
1530{
1531 diving_t *olddiv;
1532
1533 if (ev != '<' || diving == nil) return;
1534
1535 if (dirty) event(E_WRITE, op);
1536 if (dirty) return;
1537 if (device >= 0) { close(device); device= -1; }
1538
1539 olddiv= diving;
1540 diving= olddiv->up;
1541
1542 table[0]= olddiv->old0;
1543
1544 free(curdev->subname);
1545 curdev->subname= olddiv->oldsubname;
1546
1547 curdev->parttype= olddiv->oldparttype;
1548 offset= olddiv->oldoffset;
1549 extbase= olddiv->oldextbase;
1550
1551 free(olddiv);
1552
1553 event('r', op);
1554 if (diving == nil) submerged= 0; /* We surfaced. */
1555}
1556
1557void installboot(unsigned char *bootblock, char *masterboot)
1558/* Install code from a master bootstrap into a boot block. */
1559{
1560 FILE *mfp;
1561 struct exec hdr;
1562 int n;
1563 char *err;
1564
1565 if ((mfp= fopen(masterboot, "r")) == nil) {
1566 err= strerror(errno);
1567 goto m_err;
1568 }
1569
1570 n= fread(&hdr, sizeof(char), A_MINHDR, mfp);
1571 if (ferror(mfp)) {
1572 err= strerror(errno);
1573 fclose(mfp);
1574 goto m_err;
1575 }
1576
1577 if (n < A_MINHDR || BADMAG(hdr) || hdr.a_cpu != A_I8086) {
1578 err= "Not an 8086 executable";
1579 fclose(mfp);
1580 goto m_err;
1581 }
1582
1583 if (hdr.a_text + hdr.a_data > PART_TABLE_OFF) {
1584 err= "Does not fit in a boot sector";
1585 fclose(mfp);
1586 goto m_err;
1587 }
1588
1589 fseek(mfp, hdr.a_hdrlen, 0);
1590 fread(bootblock, sizeof(char), (size_t) (hdr.a_text + hdr.a_data), mfp);
1591 if (ferror(mfp)) {
1592 err= strerror(errno);
1593 fclose(mfp);
1594 goto m_err;
1595 }
1596 fclose(mfp);
1597
1598 /* Bootstrap installed. */
1599 return;
1600
1601 m_err:
1602 stat_start(1);
1603 printf("%s: %s", masterboot, err);
1604 stat_end(5);
1605}
1606
1607ssize_t boot_readwrite(int rw)
1608/* Read (0) or write (1) the boot sector. */
1609{
1610 u64_t off64 = mul64u(offset, SECTOR_SIZE);
1611 int r;
1612
1613#if __minix_vmd
1614 /* Minix-vmd has a 64 bit seek. */
1615 if (fcntl(device, F_SEEK, off64) < 0) return -1;
1616#else
1617 /* Minix has to gross things with the partition base. */
1618 struct partition geom0, geom_seek;
1619
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);
1626 sync();
1627 if (ioctl(device, DIOCSETP, &geom_seek) < 0) return -1;
1628 if (lseek(device, (off_t) 0, SEEK_SET) == -1) return -1;
1629 } else {
1630 /* Can reach this point normally. */
1631 if (lseek(device, (off_t) offset * SECTOR_SIZE, SEEK_SET) == -1)
1632 return -1;
1633 }
1634#endif
1635
1636 switch (rw) {
1637 case 0: r= read(device, bootblock, SECTOR_SIZE); break;
1638 case 1: r= write(device, bootblock, SECTOR_SIZE); break;
1639 }
1640
1641#if !__minix_vmd
1642 if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) {
1643 /* Restore partition base and size. */
1644 sync();
1645 if (ioctl(device, DIOCSETP, &geom0) < 0) return -1;
1646 }
1647#endif
1648 return r;
1649}
1650
1651void m_read(int ev, object_t *op)
1652/* Read the partition table from the current device. */
1653{
1654 int i, mode, n;
1655 struct part_entry *pe;
1656
1657 if (ev != 'r' || device >= 0) return;
1658
1659 /* Open() may cause kernel messages: */
1660 stat_start(0);
1661 fflush(stdout);
1662
1663 if (((device= open(curdev->name, mode= O_RDWR, 0666)) < 0
1664 && (errno != EACCES
1665 || (device= open(curdev->name, mode= O_RDONLY)) < 0))
1666 ) {
1667 stat_start(1);
1668 printf("%s: %s", curdev->name, strerror(errno));
1669 stat_end(5);
1670 if (device >= 0) { close(device); device= -1; }
1671 return;
1672 }
1673
1674 /* Assume up to five lines of kernel messages. */
1675 statusrow+= 5-1;
1676 stat_end(5);
1677
1678 if (mode == O_RDONLY) {
1679 stat_start(1);
1680 printf("%s: Readonly", curdev->name);
1681 stat_end(5);
1682 }
1683 memset(bootblock, 0, sizeof(bootblock));
1684
1685 n= boot_readwrite(0);
1686
1687 if (n <= 0) stat_start(1);
1688 if (n < 0) {
1689 printf("%s: %s", curdev->name, strerror(errno));
1690 close(device);
1691 device= -1;
1692 } else
1693 if (n < SECTOR_SIZE) printf("%s: Unexpected EOF", curdev->subname);
1694 if (n <= 0) stat_end(5);
1695
1696 if (n < SECTOR_SIZE) n= SECTOR_SIZE;
1697
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;
1702 }
1703 if (i <= NR_PARTITIONS || bootblock[510] != 0x55
1704 || bootblock[511] != 0xAA) {
1705 /* Invalid boot block, install bootstrap, wipe partition table.
1706 */
1707 memset(bootblock, 0, sizeof(bootblock));
1708 installboot(bootblock, MASTERBOOT);
1709 memset(table+1, 0, NR_PARTITIONS * sizeof(table[1]));
1710 stat_start(1);
1711 printf("%s: Invalid partition table (reset)", curdev->subname);
1712 stat_end(5);
1713 }
1714
1715 /* Fix an extended partition table up to something mere mortals can
1716 * understand. Record already defined partitions.
1717 */
1718 for (i= 1; i <= NR_PARTITIONS; i++) {
1719 pe= &table[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;
1723 }
1724 geometry();
1725 dirty= 0;
1726
1727 /* Warn about grave dangers ahead. */
1728 if (extbase != 0) {
1729 stat_start(1);
1730 printf("Warning: You are in an extended partition.");
1731 stat_end(5);
1732 }
1733}
1734
1735void m_write(int ev, object_t *op)
1736/* Write the partition table back if modified. */
1737{
1738 int c;
1739 struct part_entry new_table[NR_PARTITIONS], *pe;
1740
1741 if (ev != 'w' && ev != E_WRITE) return;
1742 if (device < 0) { dirty= 0; return; }
1743 if (!dirty) {
1744 if (ev == 'w') {
1745 stat_start(1);
1746 printf("%s is not changed, or has already been written",
1747 curdev->subname);
1748 stat_end(2);
1749 }
1750 return;
1751 }
1752
1753 if (bootblock[510] != 0x55 || bootblock[511] != 0xAA) {
1754 /* Invalid boot block, warn user. */
1755 stat_start(1);
1756 printf("Warning: About to write a new table on %s",
1757 curdev->subname);
1758 stat_end(5);
1759 }
1760 if (extbase != 0) {
1761 /* Will this stop the luser? Probably not... */
1762 stat_start(1);
1763 printf("You have changed an extended partition. Bad Idea.");
1764 stat_end(5);
1765 }
1766 stat_start(1);
1767 putstr("Save partition table? (y/n) ");
1768 fflush(stdout);
1769
1770 while ((c= getchar()) != 'y' && c != 'n' && c != ctrl('?')) {}
1771
1772 if (c == ctrl('?')) putstr("DEL"); else putchr(c);
1773 stat_end(5);
1774 if (c == 'n' && ev == E_WRITE) dirty= 0;
1775 if (c != 'y') return;
1776
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));
1781 } else {
1782 abs2dos(&pe->start_head, pe->lowsec);
1783 abs2dos(&pe->last_head, pe->lowsec + pe->size - 1);
1784
1785 /* Fear and loathing time: */
1786 if (extbase != 0)
1787 pe->lowsec-= ext_part(pe->sysind)
1788 ? extbase : offset;
1789 }
1790 }
1791 memcpy(bootblock+PART_TABLE_OFF, new_table, sizeof(new_table));
1792 bootblock[510]= 0x55;
1793 bootblock[511]= 0xAA;
1794
1795 if (boot_readwrite(1) < 0) {
1796 stat_start(1);
1797 printf("%s: %s", curdev->name, strerror(errno));
1798 stat_end(5);
1799 return;
1800 }
1801 dirty= 0;
1802}
1803
1804void m_shell(int ev, object_t *op)
1805/* Shell escape, to do calculations for instance. */
1806{
1807 int r, pid, status;
1808 void (*sigint)(int), (*sigquit)(int), (*sigterm)(int);
1809
1810 if (ev != 's') return;
1811
1812 reset_tty();
1813 fflush(stdout);
1814
1815 switch (pid= fork()) {
1816 case -1:
1817 stat_start(1);
1818 printf("can't fork: %s\n", strerror(errno));
1819 stat_end(3);
1820 break;
1821 case 0:
1822 if (device >= 0) (void) close(device);
1823 execl("/bin/sh", "sh", (char *) nil);
1824 r= errno;
1825 stat_start(1);
1826 printf("/bin/sh: %s\n", strerror(errno));
1827 stat_end(3);
1828 exit(127);
1829 }
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);
1837 tty_raw();
1838 if (pid < 0)
1839 ;
1840 else
1841 if (WIFEXITED(status) && WEXITSTATUS(status) == 127)
1842 stat_start(0); /* Match the stat_start in the child. */
1843 else
1844 event(ctrl('L'), op);
1845}
1846
1847void m_dump(int ev, object_t *op)
1848/* Raw dump of the partition table. */
1849{
1850 struct part_entry table[NR_PARTITIONS], *pe;
1851 int i;
1852 unsigned chs[3];
1853
1854 if (ev != 'p' || device < 0) return;
1855
1856 memcpy(table, bootblock+PART_TABLE_OFF,
1857 NR_PARTITIONS * sizeof(table[0]));
1858 for (i= 0; i < NR_PARTITIONS; i++) {
1859 pe= &table[i];
1860 stat_start(0);
1861 dos2chs(&pe->start_head, chs);
1862 printf("%2d%c %02X%15d%5d%4d",
1863 i+1,
1864 pe->bootind & ACTIVE_FLAG ? '*' : ' ',
1865 pe->sysind,
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],
1870 pe->lowsec,
1871 howend == SIZE ? pe->size : pe->size + pe->lowsec - 1,
1872 pe->size / 2);
1873 stat_end(10);
1874 }
1875 stat_start(0);
1876 printf("(Raw dump of the original %.40s table)",
1877 curdev->subname);
1878 stat_end(10);
1879}
1880
1881int quitting= 0;
1882
1883void m_quit(int ev, object_t *op)
1884/* Write the partition table if modified and exit. */
1885{
1886 if (ev != 'q' && ev != 'x') return;
1887
1888 quitting= 1;
1889
1890 if (dirty) event(E_WRITE, op);
1891 if (dirty) quitting= 0;
1892}
1893
1894void m_help(int ev, object_t *op)
1895/* For people without a clue; let's hope they can find the '?' key. */
1896{
1897 static struct help {
1898 char *keys;
1899 char *what;
1900 } 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\"" },
1914 };
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 '?'.",
1929 };
1930
1931 if (ev == '?') {
1932 struct help *hp;
1933
1934 for (hp= help; hp < arraylimit(help); hp++) {
1935 stat_start(0);
1936 printf("%-25s - %s", hp->keys, hp->what);
1937 stat_end(0);
1938 }
1939 stat_start(0);
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");
1945 stat_end(0);
1946 } else
1947 if (ev == '!') {
1948 char **ap;
1949
1950 for (ap= advice; ap < arraylimit(advice); ap++) {
1951 stat_start(0);
1952 putstr(*ap);
1953 stat_end(0);
1954 }
1955 }
1956}
1957
1958void event(int ev, object_t *op)
1959/* Simply call all modifiers for an event, each one knows when to act. */
1960{
1961 m_help(ev, op);
1962 m_redraw(ev, op);
1963 m_toggle(ev, op);
1964 m_orientation(ev, op);
1965 m_move(ev, op);
1966 m_updown(ev, op);
1967 m_enter(ev, op);
1968 m_leave(ev, op);
1969 m_modify(ev, op);
1970 m_magic(ev, op);
1971 m_in(ev, op);
1972 m_out(ev, op);
1973 m_read(ev, op);
1974 m_write(ev, op);
1975 m_shell(ev, op);
1976 m_dump(ev, op);
1977 m_quit(ev, op);
1978}
1979
1980int keypress(void)
1981/* Get a single keypress. Translate compound keypresses (arrow keys) to
1982 * their simpler equivalents.
1983 */
1984{
1985 char ch;
1986 int c;
1987 int esc= 0;
1988
1989 set_cursor(curobj->row, curobj->col);
1990 fflush(stdout);
1991
1992 do {
1993 if (read(0, &ch, sizeof(ch)) < 0) fatal("stdin");
1994 c= (unsigned char) ch;
1995 switch (esc) {
1996 case 0:
1997 switch (c) {
1998 case ctrl('['): esc= 1; break;
1999 case '_': c= '-'; break;
2000 case '=': c= '+'; break;
2001 }
2002 break;
2003 case 1:
2004 esc= c == '[' ? 2 : 0;
2005 break;
2006 case 2:
2007 switch (c) {
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;
2013 case 'U':
2014 case 'S': c= '-'; break;
2015 case 'V':
2016 case 'T': c= '+'; break;
2017 }
2018 /*FALL THROUGH*/
2019 default:
2020 esc= 0;
2021 }
2022 } while (esc > 0);
2023
2024 switch (c) {
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;
2029 }
2030
2031 return c;
2032}
2033
2034void mainloop(void)
2035/* Get keypress, handle event, display results, reset screen, ad infinitum. */
2036{
2037 int key;
2038
2039 while (!quitting) {
2040 stat_reset();
2041
2042 key= keypress();
2043
2044 event(key, curobj);
2045
2046 display();
2047 }
2048}
2049
2050int main(int argc, char **argv)
2051{
2052 object_t *op;
2053 int i, r, key;
2054 struct part_entry *pe;
2055
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";
2068
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);
2072
2073 /* Geometry: */
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];
2077
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];
2088
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;
2104 }
2105
2106 for (i= 1; i < argc; i++) newdevice(argv[i], 0);
2107
2108 if (firstdev == nil) {
2109 getdevices();
2110 key= ctrl('L');
2111 } else {
2112 key= 'r';
2113 }
2114
2115 if (firstdev != nil) {
2116 init_tty();
2117 clear_screen();
2118 event(key, curobj);
2119 display();
2120 mainloop();
2121 reset_tty();
2122 }
2123 exit(0);
2124}
Note: See TracBrowser for help on using the repository browser.