source: trunk/minix/commands/ibm/autopart.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: 68.7 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 * Forked july 2005 into autopart (Ben Gras), a mode which gives the user
6 * an easier time.
7 *
8 */
9#define nil 0
10#include <sys/types.h>
11#include <stdio.h>
12#include <termcap.h>
13#include <errno.h>
14#include <unistd.h>
15#include <stddef.h>
16#include <ctype.h>
17#include <stdlib.h>
18#include <string.h>
19#include <signal.h>
20#include <fcntl.h>
21#include <time.h>
22#include <dirent.h>
23#include <limits.h>
24#include <a.out.h>
25#include <sys/stat.h>
26#include <sys/wait.h>
27#include <sys/ioctl.h>
28#include <minix/config.h>
29#include <minix/const.h>
30#include <minix/partition.h>
31#include <minix/u64.h>
32#include <ibm/partition.h>
33#include <termios.h>
34#include <stdarg.h>
35
36/* Declare prototype. */
37static void printstep(int step, char *message);
38
39/* True if a partition is an extended partition. */
40#define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
41
42/* Minix master bootstrap code. */
43static char MASTERBOOT[] = "/usr/mdec/masterboot";
44
45/* Template:
46 ----first---- --geom/last-- ------sectors-----
47 Device Cyl Head Sec Cyl Head Sec Base Size Kb
48 /dev/c0d0 977 5 17
49 /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521
50Num Sort Type
51 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440
52 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142
53 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939
54 3 p3 00 None 0 0 0 0 0 -1 0 0 0
55
56 */
57#define MAXSIZE 999999999L
58#define SECTOR_SIZE 512
59#define DEV_FD0 0x200 /* Device number of /dev/fd0 */
60#define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */
61
62int min_region_mb = 500;
63
64#define MIN_REGION_SECTORS (1024*1024*min_region_mb/SECTOR_SIZE)
65
66#define MAX_REGION_MB 4095
67#define MAX_REGION_SECTORS (1024*(1024/SECTOR_SIZE)*MAX_REGION_MB)
68
69#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
70#define arraylimit(a) ((a) + arraysize(a))
71
72#define SORNOT(n) ((n) == 1 ? "" : "s")
73
74/* screen colours */
75#define COL_RED 1
76#define COL_GREEN 2
77#define COL_ORANGE 3
78#define COL_BLUE 4
79#define COL_MAGENTA 5
80#define COL_CYAN 6
81
82#define SURE_SERIOUS 1
83#define SURE_BACK 2
84
85void col(int col)
86{
87 if(!col) printf("\033[0m");
88 else printf("\033[3%dm", col % 10);
89}
90
91void type2col(int type)
92{
93 switch(type) {
94 /* minix */
95 case 0x80:
96 case MINIX_PART: col(COL_GREEN); break;
97
98 /* dos/windows */
99 case 0x0B: case 0x0C: case 0x0E: case 0x0F: case 0x42:
100 case 0x07: col(COL_CYAN); break;
101
102 /* linux */
103 case 0x82: case 0x83: col(COL_ORANGE); break;
104 }
105}
106
107int open_ct_ok(int fd)
108{
109 int c = -1;
110 if(ioctl(fd, DIOCOPENCT, &c) < 0) {
111 printf("Warning: couldn't verify opencount, continuing\n");
112 return 1;
113 }
114
115 if(c == 1) return 1;
116 if(c < 1) { printf("Error: open count %d\n", c); }
117
118 return 0;
119}
120
121void report(const char *label)
122{
123 fprintf(stderr, "part: %s: %s\n", label, strerror(errno));
124}
125
126void fatal(const char *label)
127{
128 report(label);
129 exit(1);
130}
131
132struct termios termios;
133
134void save_ttyflags(void)
135/* Save tty attributes for later restoration. */
136{
137 if (tcgetattr(0, &termios) < 0) fatal("");
138}
139
140void restore_ttyflags(void)
141/* Reset the tty flags to how we got 'em. */
142{
143 if (tcsetattr(0, TCSANOW, &termios) < 0) fatal("");
144}
145
146void tty_raw(void)
147/* Set the terminal to raw mode, no signals, no echoing. */
148{
149 struct termios rawterm;
150
151 rawterm= termios;
152 rawterm.c_lflag &= ~(ICANON|ISIG|ECHO);
153 rawterm.c_iflag &= ~(ICRNL);
154 if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal("");
155}
156
157#define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
158
159char t_cd[16], t_cm[32], t_so[16], t_se[16], t_md[16], t_me[16];
160int t_li, t_co;
161#define STATUSROW 10
162
163void init_tty(void)
164/* Get terminal capabilities and set the tty to "editor" mode. */
165{
166 char *term;
167 static char termbuf[1024];
168 char *tp;
169
170 if ((term= getenv("TERM")) == nil || tgetent(termbuf, term) != 1) {
171 fprintf(stderr, "part: Can't get terminal capabilities\n");
172 exit(1);
173 }
174 if (tgetstr("cd", (tp= t_cd, &tp)) == nil
175 || tgetstr("cm", (tp= t_cm, &tp)) == nil) {
176 fprintf(stderr, "part: This terminal is too dumb\n");
177 exit(1);
178 }
179 t_li= tgetnum("li");
180 t_co= tgetnum("co");
181 (void) tgetstr("so", (tp= t_so, &tp));
182 (void) tgetstr("se", (tp= t_se, &tp));
183 (void) tgetstr("md", (tp= t_md, &tp));
184 (void) tgetstr("me", (tp= t_me, &tp));
185
186 save_ttyflags();
187 tty_raw();
188}
189
190void putchr(int c)
191{
192 putchar(c);
193}
194
195void putstr(char *s)
196{
197 int c;
198
199 while ((c= *s++) != 0) putchr(c);
200}
201
202void set_cursor(int row, int col)
203{
204 tputs(tgoto(t_cm, col, row), 1, putchr);
205}
206
207int statusrow= STATUSROW;
208int stat_ktl= 1;
209int need_help= 1;
210
211void stat_start(int serious)
212/* Prepare for printing on a fresh status line, possibly highlighted. */
213{
214 set_cursor(statusrow++, 0);
215 tputs(t_cd, 1, putchr);
216 if (serious) tputs(t_so, 1, putchr);
217}
218
219void stat_end(int ktl)
220/* Closing bracket for stat_start. Sets "keystrokes to live" of message. */
221{
222 tputs(t_se, 1, putchr);
223 stat_ktl= ktl;
224 need_help= 1;
225}
226
227void stat_reset(void)
228/* Reset the statusline pointer and clear old messages if expired. */
229{
230 if (stat_ktl > 0 && --stat_ktl == 0) {
231 statusrow= STATUSROW;
232 need_help= 1;
233 }
234 if (need_help && statusrow < (24-2)) {
235 if (statusrow > STATUSROW) stat_start(0);
236 stat_start(0);
237 putstr(
238"Type '+' or '-' to change, 'r' to read, '?' for more help, '!' for advice");
239 }
240 statusrow= STATUSROW;
241 need_help= 0;
242}
243
244void clear_screen(void)
245{
246 set_cursor(0, 0);
247 tputs(t_cd, 1, putchr);
248 stat_ktl= 1;
249 stat_reset();
250}
251
252void reset_tty(void)
253/* Reset the tty to cooked mode. */
254{
255 restore_ttyflags();
256 set_cursor(statusrow, 0);
257 tputs(t_cd, 1, putchr);
258}
259
260void *alloc(size_t n)
261{
262 void *m;
263
264 if ((m= malloc(n)) == nil) { reset_tty(); fatal(""); }
265
266 return m;
267}
268
269#ifndef makedev /* Missing in sys/types.h */
270#define minor(dev) (((dev) >> MINOR) & BYTE)
271#define major(dev) (((dev) >> MAJOR) & BYTE)
272#define makedev(major, minor) \
273 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
274#endif
275
276typedef enum parttype { DUNNO, SUBPART, PRIMARY, FLOPPY } parttype_t;
277
278typedef struct device {
279 struct device *next, *prev; /* Circular dequeue. */
280 dev_t rdev; /* Device number (sorting only). */
281 char *name; /* E.g. /dev/c0d0 */
282 char *subname; /* E.g. /dev/c0d0:2 */
283 parttype_t parttype;
284 int biosdrive;
285} device_t;
286
287typedef struct region {
288 /* A region is either an existing top-level partition
289 * entry (used_part is non-NULL) or free space (free_*
290 * contains data).
291 */
292 struct part_entry used_part;
293 int is_used_part;
294 int tableno;
295 int free_sec_start, free_sec_last;
296} region_t;
297
298/* A disk has between 1 and 2*partitions+1 regions;
299 * the last case is free space before and after every partition.
300 */
301#define NR_REGIONS (2*NR_PARTITIONS+1)
302region_t regions[NR_REGIONS];
303int nr_partitions = 0, nr_regions = 0, free_regions, used_regions;
304int nordonly = 0;
305
306device_t *firstdev= nil, *curdev;
307
308#define MAX_DEVICES 100
309 static struct {
310 device_t *dev;
311 int nr_partitions, free_regions, used_regions, sectors, nr_regions;
312 int biosdrive;
313 region_t regions[NR_REGIONS];
314 } devices[MAX_DEVICES];
315
316void newdevice(char *name, int scanning, int disk_only)
317/* Add a device to the device list. If scanning is set then we are reading
318 * /dev, so insert the device in device number order and make /dev/c0d0 current.
319 */
320{
321 device_t *new, *nextdev, *prevdev;
322 struct stat st;
323
324 st.st_rdev= 0;
325 if (scanning) {
326 if (stat(name, &st) < 0 || !S_ISBLK(st.st_mode)) return;
327
328 switch (major(st.st_rdev)) {
329 case 3:
330 /* Disk controller */
331 if (minor(st.st_rdev) >= 0x80
332 || minor(st.st_rdev) % 5 != 0) return;
333 break;
334 default:
335 return;
336 }
337 /* Interesting device found. */
338 } else {
339 if(stat(name, &st) < 0) { perror(name); return; }
340 }
341
342 new= alloc(sizeof(*new));
343 new->rdev= st.st_rdev;
344 new->name= alloc((strlen(name) + 1) * sizeof(new->name[0]));
345 strcpy(new->name, name);
346 new->subname= new->name;
347 new->parttype= DUNNO;
348 if (major(st.st_rdev) == major(DEV_FD0) && minor(st.st_rdev) < 112) {
349 new->parttype= FLOPPY;
350 } else
351 if (st.st_rdev >= DEV_C0D0 && minor(st.st_rdev) < 128
352 && minor(st.st_rdev) % 5 == 0) {
353 new->parttype= PRIMARY;
354 }
355
356 if (firstdev == nil) {
357 firstdev= new;
358 new->next= new->prev= new;
359 curdev= firstdev;
360 return;
361 }
362 nextdev= firstdev;
363 while (new->rdev >= nextdev->rdev
364 && (nextdev= nextdev->next) != firstdev) {}
365 prevdev= nextdev->prev;
366 new->next= nextdev;
367 nextdev->prev= new;
368 new->prev= prevdev;
369 prevdev->next= new;
370
371 if (new->rdev < firstdev->rdev) firstdev= new;
372 if (new->rdev == DEV_C0D0) curdev= new;
373 if (curdev->rdev != DEV_C0D0) curdev= firstdev;
374}
375
376void getdevices(int disk_only)
377/* Get all block devices from /dev that look interesting. */
378{
379 DIR *d;
380 struct dirent *e;
381 char name[5 + NAME_MAX + 1];
382
383 if ((d= opendir("/dev")) == nil) fatal("/dev");
384
385 while ((e= readdir(d)) != nil) {
386 strcpy(name, "/dev/");
387 strcpy(name + 5, e->d_name);
388 newdevice(name, 1, disk_only);
389 }
390 (void) closedir(d);
391}
392
393/* One featureful master bootstrap. */
394unsigned char bootstrap[] = {
3950353,0001,0000,0061,0300,0216,0330,0216,0300,0372,0216,0320,0274,0000,0174,0373,
3960275,0276,0007,0211,0346,0126,0277,0000,0006,0271,0000,0001,0374,0363,0245,0352,
3970044,0006,0000,0000,0264,0002,0315,0026,0250,0010,0164,0033,0350,0071,0001,0174,
3980007,0060,0344,0315,0026,0242,0205,0007,0054,0060,0074,0012,0163,0363,0120,0350,
3990046,0001,0205,0007,0130,0353,0012,0240,0002,0006,0204,0300,0165,0003,0351,0147,
4000000,0230,0262,0005,0366,0362,0262,0200,0000,0302,0210,0340,0120,0350,0234,0000,
4010163,0003,0351,0147,0000,0130,0054,0001,0175,0003,0351,0141,0000,0276,0276,0175,
4020211,0357,0271,0040,0000,0363,0245,0200,0301,0004,0211,0356,0215,0174,0020,0070,
4030154,0004,0164,0016,0213,0135,0010,0053,0134,0010,0213,0135,0012,0033,0134,0012,
4040163,0014,0212,0044,0206,0144,0020,0210,0044,0106,0071,0376,0162,0364,0211,0376,
4050201,0376,0356,0007,0162,0326,0342,0322,0211,0356,0264,0020,0366,0344,0001,0306,
4060200,0174,0004,0001,0162,0026,0353,0021,0204,0322,0175,0041,0211,0356,0200,0174,
4070004,0000,0164,0013,0366,0004,0200,0164,0006,0350,0070,0000,0162,0053,0303,0203,
4080306,0020,0201,0376,0376,0007,0162,0346,0350,0215,0000,0211,0007,0376,0302,0204,
4090322,0174,0023,0315,0021,0321,0340,0321,0340,0200,0344,0003,0070,0342,0167,0355,
4100350,0011,0000,0162,0350,0303,0350,0003,0000,0162,0146,0303,0211,0356,0214,0134,
4110010,0214,0134,0012,0277,0003,0000,0122,0006,0127,0264,0010,0315,0023,0137,0007,
4120200,0341,0077,0376,0306,0210,0310,0366,0346,0211,0303,0213,0104,0010,0213,0124,
4130012,0367,0363,0222,0210,0325,0366,0361,0060,0322,0321,0352,0321,0352,0010,0342,
4140210,0321,0376,0301,0132,0210,0306,0273,0000,0174,0270,0001,0002,0315,0023,0163,
4150020,0200,0374,0200,0164,0011,0117,0174,0006,0060,0344,0315,0023,0163,0270,0371,
4160303,0201,0076,0376,0175,0125,0252,0165,0001,0303,0350,0013,0000,0243,0007,0353,
4170005,0350,0004,0000,0227,0007,0353,0376,0136,0255,0126,0211,0306,0254,0204,0300,
4180164,0011,0264,0016,0273,0001,0000,0315,0020,0353,0362,0303,0057,0144,0145,0166,
4190057,0150,0144,0077,0010,0000,0015,0012,0000,0116,0157,0156,0145,0040,0141,0143,
4200164,0151,0166,0145,0015,0012,0000,0122,0145,0141,0144,0040,0145,0162,0162,0157,
4210162,0040,0000,0116,0157,0164,0040,0142,0157,0157,0164,0141,0142,0154,0145,0040,
4220000,0000,
423};
424
425int dirty= 0;
426unsigned char bootblock[SECTOR_SIZE];
427struct part_entry table[1 + NR_PARTITIONS];
428int existing[1 + NR_PARTITIONS];
429unsigned long offset= 0, extbase= 0, extsize;
430int submerged= 0;
431char sort_index[1 + NR_PARTITIONS], sort_order[1 + NR_PARTITIONS];
432unsigned cylinders= 1, heads= 1, sectors= 1, secpcyl= 1;
433unsigned alt_cyls= 1, alt_heads= 1, alt_secs= 1;
434int precise= 0;
435int device= -1;
436
437unsigned long sortbase(struct part_entry *pe)
438{
439 return pe->sysind == NO_PART ? -1 : pe->lowsec;
440}
441
442void sort(void)
443/* Let the sort_index array show the order partitions are sorted in. */
444{
445 int i, j;
446
447 for (i= 1; i <= NR_PARTITIONS; i++) sort_order[i]= i;
448
449 for (i= 1; i <= NR_PARTITIONS; i++) {
450 for (j= 1; j <= NR_PARTITIONS-1; j++) {
451 int sj= sort_order[j], sj1= sort_order[j+1];
452
453 if (sortbase(&table[sj]) > sortbase(&table[sj1])) {
454 sort_order[j]= sj1;
455 sort_order[j+1]= sj;
456 }
457 }
458 }
459 for (i= 1; i <= NR_PARTITIONS; i++) sort_index[sort_order[i]]= i;
460}
461
462void dos2chs(unsigned char *dos, unsigned *chs)
463/* Extract cylinder, head and sector from the three bytes DOS uses to address
464 * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
465 * of the sector byte. The sector number is rebased to count from 0.
466 */
467{
468 chs[0]= ((dos[1] & 0xC0) << 2) | dos[2];
469 chs[1]= dos[0];
470 chs[2]= (dos[1] & 0x3F) - 1;
471}
472
473void abs2dos(unsigned char *dos, unsigned long pos)
474/* Translate a sector offset to three DOS bytes. */
475{
476 unsigned h, c, s;
477
478 c= pos / secpcyl;
479 h= (pos % secpcyl) / sectors;
480 s= pos % sectors + 1;
481
482 dos[0]= h;
483 dos[1]= s | ((c >> 2) & 0xC0);
484 dos[2]= c & 0xFF;
485}
486
487void recompute0(void)
488/* Recompute the partition size for the device after a geometry change. */
489{
490 if (device < 0) {
491 cylinders= heads= sectors= 1;
492 memset(table, 0, sizeof(table));
493 } else
494 if (!precise && offset == 0) {
495 table[0].lowsec= 0;
496 table[0].size= (unsigned long) cylinders * heads * sectors;
497 }
498 table[0].sysind= device < 0 ? NO_PART : MINIX_PART;
499 secpcyl= heads * sectors;
500}
501
502void guess_geometry(void)
503/* With a bit of work one can deduce the disk geometry from the partition
504 * table. This may be necessary if the driver gets it wrong. (If partition
505 * tables didn't have C/H/S numbers we would not care at all...)
506 */
507{
508 int i, n;
509 struct part_entry *pe;
510 unsigned chs[3];
511 unsigned long sec;
512 unsigned h, s;
513 unsigned char HS[256][8]; /* Bit map off all possible H/S */
514
515 alt_cyls= alt_heads= alt_secs= 0;
516
517 /* Initially all possible H/S combinations are possible. HS[h][0]
518 * bit 0 is used to rule out a head value.
519 */
520 for (h= 1; h <= 255; h++) {
521 for (s= 0; s < 8; s++) HS[h][s]= 0xFF;
522 }
523
524 for (i= 0; i < 2*NR_PARTITIONS; i++) {
525 pe= &(table+1)[i >> 1];
526 if (pe->sysind == NO_PART) continue;
527
528 /* Get the end or start sector numbers (in that order). */
529 if ((i & 1) == 0) {
530 dos2chs(&pe->last_head, chs);
531 sec= pe->lowsec + pe->size - 1;
532 } else {
533 dos2chs(&pe->start_head, chs);
534 sec= pe->lowsec;
535 }
536
537 if (chs[0] >= alt_cyls) alt_cyls= chs[0]+1;
538
539 /* Which H/S combinations can be ruled out? */
540 for (h= 1; h <= 255; h++) {
541 if (HS[h][0] == 0) continue;
542 n = 0;
543 for (s= 1; s <= 63; s++) {
544 if ((chs[0] * h + chs[1]) * s + chs[2] != sec) {
545 HS[h][s/8] &= ~(1 << (s%8));
546 }
547 if (HS[h][s/8] & (1 << (s%8))) n++;
548 }
549 if (n == 0) HS[h][0]= 0;
550 }
551 }
552
553 /* See if only one remains. */
554 i= 0;
555 for (h= 1; h <= 255; h++) {
556 if (HS[h][0] == 0) continue;
557 for (s= 1; s <= 63; s++) {
558 if (HS[h][s/8] & (1 << (s%8))) {
559 i++;
560 alt_heads= h;
561 alt_secs= s;
562 }
563 }
564 }
565
566 /* Forget it if more than one choice... */
567 if (i > 1) alt_cyls= alt_heads= alt_secs= 0;
568}
569
570void geometry(void)
571/* Find out the geometry of the device by querying the driver, or by looking
572 * at the partition table. These numbers are crosschecked to make sure that
573 * the geometry is correct. Master bootstraps other than the Minix one use
574 * the CHS numbers in the partition table to load the bootstrap of the active
575 * partition.
576 */
577{
578 struct stat dst;
579 int err= 0;
580 struct partition geometry;
581
582 if (submerged) {
583 /* Geometry already known. */
584 sort();
585 return;
586 }
587 precise= 0;
588 cylinders= 0;
589 recompute0();
590 if (device < 0) return;
591
592 /* Try to guess the geometry from the partition table. */
593 guess_geometry();
594
595 /* Try to get the geometry from the driver. */
596 (void) fstat(device, &dst);
597
598 if (S_ISBLK(dst.st_mode) || S_ISCHR(dst.st_mode)) {
599 /* Try to get the drive's geometry from the driver. */
600
601 if (ioctl(device, DIOCGETP, &geometry) < 0)
602 err= errno;
603 else {
604 table[0].lowsec= div64u(geometry.base, SECTOR_SIZE);
605 table[0].size= div64u(geometry.size, SECTOR_SIZE);
606 cylinders= geometry.cylinders;
607 heads= geometry.heads;
608 sectors= geometry.sectors;
609 precise= 1;
610 }
611 } else {
612 err= ENODEV;
613 }
614
615 if (err != 0) {
616 /* Getting the geometry from the driver failed, so use the
617 * alternate geometry.
618 */
619 if (alt_heads == 0) {
620 alt_cyls= table[0].size / (64 * 32);
621 alt_heads= 64;
622 alt_secs= 32;
623 }
624
625 cylinders= alt_cyls;
626 heads= alt_heads;
627 sectors= alt_secs;
628
629 stat_start(1);
630 printf("Failure to get the geometry of %s: %s", curdev->name,
631 errno == ENOTTY ? "No driver support" : strerror(err));
632 stat_end(5);
633 stat_start(0);
634 printf("The geometry has been guessed as %ux%ux%u",
635 cylinders, heads, sectors);
636 stat_end(5);
637 } else {
638 if (alt_heads == 0) {
639 alt_cyls= cylinders;
640 alt_heads= heads;
641 alt_secs= sectors;
642 }
643
644 if (heads != alt_heads || sectors != alt_secs) {
645printf(
646"The %ux%ux%u geometry obtained from the driver\n"
647"does not match the %ux%ux%u geometry implied by the partition\n"
648"table. Please use expert mode instead.\n");
649exit(1);
650 }
651 }
652
653 /* Show the base and size of the device instead of the whole drive.
654 * This makes sense for subpartitioning primary partitions.
655 */
656 if (precise && ioctl(device, DIOCGETP, &geometry) >= 0) {
657 table[0].lowsec= div64u(geometry.base, SECTOR_SIZE);
658 table[0].size= div64u(geometry.size, SECTOR_SIZE);
659 } else {
660 precise= 0;
661 }
662 recompute0();
663 sort();
664}
665
666typedef struct indicators { /* Partition type to partition name. */
667 unsigned char ind;
668 char name[10];
669} indicators_t;
670
671indicators_t ind_table[]= {
672 { 0x00, "None" },
673 { 0x01, "FAT-12" },
674 { 0x02, "XENIX /" },
675 { 0x03, "XENIX usr" },
676 { 0x04, "FAT-16" },
677 { 0x05, "EXTENDED" },
678 { 0x06, "FAT-16" },
679 { 0x07, "HPFS/NTFS" },
680 { 0x08, "AIX" },
681 { 0x09, "COHERENT" },
682 { 0x0A, "OS/2" },
683 { 0x0B, "FAT-32" },
684 { 0x0C, "FAT?" },
685 { 0x0E, "FAT?" },
686 { 0x0F, "EXTENDED" },
687 { 0x10, "OPUS" },
688 { 0x40, "VENIX286" },
689 { 0x42, "W2000 Dyn" },
690 { 0x52, "MICROPORT" },
691 { 0x63, "386/IX" },
692 { 0x64, "NOVELL286" },
693 { 0x65, "NOVELL386" },
694 { 0x75, "PC/IX" },
695 { 0x80, "MINIX-OLD" },
696 { 0x81, "MINIX" },
697 { 0x82, "LINUXswap" },
698 { 0x83, "LINUX" },
699 { 0x93, "AMOEBA" },
700 { 0x94, "AMOEBAbad" },
701 { 0xA5, "386BSD" },
702 { 0xB7, "BSDI" },
703 { 0xB8, "BSDI swap" },
704 { 0xC7, "SYRINX" },
705 { 0xDB, "CPM" },
706 { 0xFF, "BADBLOCKS" },
707};
708
709char *typ2txt(int ind)
710/* Translate a numeric partition indicator for human eyes. */
711{
712 indicators_t *pind;
713
714 for (pind= ind_table; pind < arraylimit(ind_table); pind++) {
715 if (pind->ind == ind) return pind->name;
716 }
717 return "unknown system";
718}
719
720int round_sysind(int ind, int delta)
721/* Find the next known partition type starting with ind in direction delta. */
722{
723 indicators_t *pind;
724
725 ind= (ind + delta) & 0xFF;
726
727 if (delta < 0) {
728 for (pind= arraylimit(ind_table)-1; pind->ind > ind; pind--) {}
729 } else {
730 for (pind= ind_table; pind->ind < ind; pind++) {}
731 }
732 return pind->ind;
733}
734
735/* Objects on the screen, either simple pieces of the text or the cylinder
736 * number of the start of partition three.
737 */
738typedef enum objtype {
739 O_INFO, O_TEXT, O_DEV, O_SUB,
740 O_TYPTXT, O_SORT, O_NUM, O_TYPHEX,
741 O_CYL, O_HEAD, O_SEC,
742 O_SCYL, O_SHEAD, O_SSEC, O_LCYL, O_LHEAD, O_LSEC, O_BASE, O_SIZE, O_KB
743} objtype_t;
744
745#define rjust(type) ((type) >= O_TYPHEX)
746#define computed(type) ((type) >= O_TYPTXT)
747
748typedef struct object {
749 struct object *next;
750 objtype_t type; /* Text field, cylinder number, etc. */
751 char flags; /* Modifiable? */
752 char row;
753 char col;
754 char len;
755 struct part_entry *entry; /* What does the object refer to? */
756 char *text;
757 char value[20]; /* Value when printed. */
758} object_t;
759
760#define OF_MOD 0x01 /* Object value is modifiable. */
761#define OF_ODD 0x02 /* It has a somewhat odd value. */
762#define OF_BAD 0x04 /* Its value is no good at all. */
763
764/* Events: (Keypress events are the value of the key pressed.) */
765#define E_ENTER (-1) /* Cursor moves onto object. */
766#define E_LEAVE (-2) /* Cursor leaves object. */
767#define E_WRITE (-3) /* Write, but not by typing 'w'. */
768
769/* The O_SIZE objects have a dual identity. */
770enum howend { SIZE, LAST } howend= SIZE;
771
772object_t *world= nil;
773object_t *curobj= nil;
774
775object_t *newobject(objtype_t type, int flags, int row, int col, int len)
776/* Make a new object given a type, flags, position and length on the screen. */
777{
778 object_t *new;
779 object_t **aop= &world;
780
781 new= alloc(sizeof(*new));
782
783 new->type= type;
784 new->flags= flags;
785 new->row= row;
786 new->col= col;
787 new->len= len;
788 new->entry= nil;
789 new->text= "";
790 new->value[0]= 0;
791
792 new->next= *aop;
793 *aop= new;
794
795 return new;
796}
797
798unsigned long entry2base(struct part_entry *pe)
799/* Return the base sector of the partition if defined. */
800{
801 return pe->sysind == NO_PART ? 0 : pe->lowsec;
802}
803
804unsigned long entry2last(struct part_entry *pe)
805{
806 return pe->sysind == NO_PART ? -1 : pe->lowsec + pe->size - 1;
807}
808
809unsigned long entry2size(struct part_entry *pe)
810{
811 return pe->sysind == NO_PART ? 0 : pe->size;
812}
813
814int overlap(unsigned long sec)
815/* See if sec is part of another partition. */
816{
817 struct part_entry *pe;
818
819 for (pe= table + 1; pe <= table + NR_PARTITIONS; pe++) {
820 if (pe->sysind == NO_PART) continue;
821
822 if (pe->lowsec < sec && sec < pe->lowsec + pe->size)
823 return 1;
824 }
825 return 0;
826}
827
828int aligned(unsigned long sec, unsigned unit)
829/* True if sec is aligned to unit or if it is no problem if it is unaligned. */
830{
831 return (offset != 0 && extbase == 0) || (sec % unit == 0);
832}
833
834void print(object_t *op)
835/* Print an object's value if it changed. */
836{
837 struct part_entry *pe= op->entry;
838 int n;
839 unsigned long t;
840 char *name;
841 int oldflags;
842 char oldvalue[20];
843
844 /* Remember the old flags and value. */
845 oldflags= op->flags;
846 strcpy(oldvalue, op->value);
847
848 op->flags&= ~(OF_ODD | OF_BAD);
849
850 switch (op->type) {
851 case O_INFO: {
852 /* Current field. */
853 static struct field { int type; char *name; } fields[]= {
854 { O_DEV, "Select device" },
855 { O_NUM, "Active flag" },
856 { O_TYPHEX, "Hex partition type" },
857 { O_TYPTXT, "Partition type" },
858 { O_SCYL, "Start cylinder" },
859 { O_SHEAD, "Start head" },
860 { O_SSEC, "Start sector" },
861 { O_CYL, "Number of cylinders" },
862 { O_HEAD, "Number of heads" },
863 { O_SEC, "Sectors per track" },
864 { O_LCYL, "Last cylinder" },
865 { O_LHEAD, "Last head" },
866 { O_LSEC, "Last sector" },
867 { O_BASE, "Base sector" },
868 { O_SIZE, "Size in sectors" },
869 { O_KB, "Size in kilobytes" },
870 { -1, "?" },
871 };
872 struct field *fp= fields;
873
874 while (fp->type >= 0 && fp->type != curobj->type) fp++;
875 strcpy(op->value, fp->name);
876 op->flags|= OF_ODD;
877 break; }
878 case O_TEXT:
879 /* Simple text field. */
880 strcpy(op->value, op->text);
881 break;
882 case O_DEV:
883 case O_SUB:
884 /* Name of currently edited device. */
885 name= op->type == O_DEV ? curdev->name :
886 offset == 0 ? "" : curdev->subname;
887 if ((n= strlen(name)) < op->len) n= op->len;
888 strcpy(op->value, name + (n - op->len));
889 if (device < 0 && op->type == O_DEV) op->flags|= OF_BAD;
890 break;
891 case O_NUM:
892 /* Position and active flag. */
893 sprintf(op->value, "%d%c", (int) (pe - table - 1),
894 pe->bootind & ACTIVE_FLAG ? '*' : ' ');
895 break;
896 case O_SORT:
897 /* Position if the driver sorts the table. */
898 sprintf(op->value, "%s%d",
899 curdev->parttype >= PRIMARY ? "p" :
900 curdev->parttype == SUBPART ? "s" : "",
901 (curdev->parttype == SUBPART ||
902 curdev->parttype == FLOPPY ? pe - table
903 : sort_index[pe - table]) - 1);
904 break;
905 case O_TYPHEX:
906 /* Hex partition type indicator. */
907 sprintf(op->value, "%02X", pe->sysind);
908 break;
909 case O_TYPTXT:
910 /* Ascii partition type indicator. */
911 strcpy(op->value, typ2txt(pe->sysind));
912 break;
913 case O_SCYL:
914 /* Partition's start cylinder. */
915 sprintf(op->value, "%lu", entry2base(pe) / secpcyl);
916 break;
917 case O_SHEAD:
918 /* Start head. */
919 t= entry2base(pe);
920 sprintf(op->value, "%lu", t % secpcyl / sectors);
921 if (!aligned(t, secpcyl) && t != table[0].lowsec + sectors)
922 op->flags|= OF_ODD;
923 break;
924 case O_SSEC:
925 /* Start sector. */
926 t= entry2base(pe);
927 sprintf(op->value, "%lu", t % sectors);
928 if (!aligned(t, sectors)) op->flags|= OF_ODD;
929 break;
930 case O_CYL:
931 /* Number of cylinders. */
932 sprintf(op->value, "%u", cylinders);
933 break;
934 case O_HEAD:
935 /* Number of heads. */
936 sprintf(op->value, "%u", heads);
937 break;
938 case O_SEC:
939 /* Number of sectors per track. */
940 sprintf(op->value, "%u", sectors);
941 break;
942 case O_LCYL:
943 /* Partition's last cylinder. */
944 t= entry2last(pe);
945 sprintf(op->value, "%lu", t == -1 ? 0 : t / secpcyl);
946 break;
947 case O_LHEAD:
948 /* Partition's last head. */
949 t= entry2last(pe);
950 sprintf(op->value, "%lu", t == -1 ? 0 : t % secpcyl / sectors);
951 if (!aligned(t + 1, secpcyl)) op->flags|= OF_ODD;
952 break;
953 case O_LSEC:
954 /* Partition's last sector. */
955 t= entry2last(pe);
956 sprintf(op->value, t == -1 ? "-1" : "%lu", t % sectors);
957 if (!aligned(t + 1, sectors)) op->flags|= OF_ODD;
958 break;
959 case O_BASE:
960 /* Partition's base sector. */
961 sprintf(op->value, "%lu", entry2base(pe));
962 if (pe->sysind != NO_PART && pe != &table[0]
963 && (pe->lowsec <= table[0].lowsec || overlap(pe->lowsec)))
964 op->flags|= OF_BAD;
965 break;
966 case O_SIZE:
967 /* Size of partitition in sectors. */
968 t= howend == SIZE ? entry2size(pe) : entry2last(pe);
969 sprintf(op->value, "%lu", pe->sysind == NO_PART ? 0 : t);
970 if (pe->sysind != NO_PART && (pe->size == 0
971 || pe->lowsec + pe->size > table[0].lowsec + table[0].size
972 || overlap(pe->lowsec + pe->size)))
973 op->flags|= OF_BAD;
974 break;
975 case O_KB:
976 /* Size of partitition in kilobytes. */
977 sprintf(op->value, "%lu", entry2size(pe) / 2);
978 break;
979 default:
980 sprintf(op->value, "?? %d ??", op->type);
981 }
982
983 if (device < 0 && computed(op->type)) strcpy(op->value, "?");
984
985 /* If a value overflows the print field then show a blank
986 * reverse video field.
987 */
988 if ((n= strlen(op->value)) > op->len) {
989 n= 0;
990 op->flags|= OF_BAD;
991 }
992
993 /* Right or left justified? */
994 if (rjust(op->type)) {
995 memmove(op->value + (op->len - n), op->value, n);
996 memset(op->value, ' ', op->len - n);
997 } else {
998 memset(op->value + n, ' ', op->len - n);
999 }
1000 op->value[op->len]= 0;
1001
1002 if ((op->flags & (OF_ODD | OF_BAD)) == (oldflags & (OF_ODD | OF_BAD))
1003 && strcmp(op->value, oldvalue) == 0) {
1004 /* The value did not change. */
1005 return;
1006 }
1007
1008 set_cursor(op->row, rjust(op->type) ? op->col - (op->len-1) : op->col);
1009
1010 if (op->flags & OF_BAD) tputs(t_so, 1, putchr);
1011 else
1012 if (op->flags & OF_ODD) tputs(t_md, 1, putchr);
1013 putstr(op->value);
1014 if (op->flags & OF_BAD) tputs(t_se, 1, putchr);
1015 else
1016 if (op->flags & OF_ODD) tputs(t_me, 1, putchr);
1017}
1018
1019void display(void)
1020/* Repaint all objects that changed. */
1021{
1022 object_t *op;
1023
1024 for (op= world; op != nil; op= op->next) print(op);
1025}
1026
1027int typing; /* Set if a digit has been typed to set a value. */
1028int magic; /* Changes when using the magic key. */
1029
1030void event(int ev, object_t *op);
1031
1032void m_redraw(int ev, object_t *op)
1033/* Redraw the screen. */
1034{
1035 object_t *op2;
1036
1037 if (ev != ctrl('L')) return;
1038
1039 clear_screen();
1040 for (op2= world; op2 != nil; op2= op2->next) op2->value[0]= 0;
1041}
1042
1043void m_toggle(int ev, object_t *op)
1044/* Toggle between the driver and alternate geometry. */
1045{
1046 unsigned t;
1047
1048 if (ev != 'X') return;
1049 if (alt_cyls == cylinders && alt_heads == heads && alt_secs == sectors)
1050 return;
1051
1052 t= cylinders; cylinders= alt_cyls; alt_cyls= t;
1053 t= heads; heads= alt_heads; alt_heads= t;
1054 t= sectors; sectors= alt_secs; alt_secs= t;
1055 dirty= 1;
1056 recompute0();
1057}
1058
1059char size_last[]= "Size";
1060
1061void m_orientation(int ev, object_t *op)
1062{
1063 if (ev != ' ') return;
1064
1065 switch (howend) {
1066 case SIZE:
1067 howend= LAST;
1068 strcpy(size_last, "Last");
1069 break;
1070 case LAST:
1071 howend= SIZE;
1072 strcpy(size_last, "Size");
1073 }
1074}
1075
1076void m_move(int ev, object_t *op)
1077/* Move to the nearest modifiably object in the intended direction. Objects
1078 * on the same row or column are really near.
1079 */
1080{
1081 object_t *near, *op2;
1082 unsigned dist, d2, dr, dc;
1083
1084 if (ev != 'h' && ev != 'j' && ev != 'k' && ev != 'l' && ev != 'H')
1085 return;
1086
1087 if (device < 0) {
1088 /* No device open? Then try to read first. */
1089 event('r', op);
1090 if (device < 0) return;
1091 }
1092
1093 near= op;
1094 dist= -1;
1095
1096 for (op2= world; op2 != nil; op2= op2->next) {
1097 if (op2 == op || !(op2->flags & OF_MOD)) continue;
1098
1099 dr= abs(op2->row - op->row);
1100 dc= abs(op2->col - op->col);
1101
1102 d2= 25*dr*dr + dc*dc;
1103 if (op2->row != op->row && op2->col != op->col) d2+= 1000;
1104
1105 switch (ev) {
1106 case 'h': /* Left */
1107 if (op2->col >= op->col) d2= -1;
1108 break;
1109 case 'j': /* Down */
1110 if (op2->row <= op->row) d2= -1;
1111 break;
1112 case 'k': /* Up */
1113 if (op2->row >= op->row) d2= -1;
1114 break;
1115 case 'l': /* Right */
1116 if (op2->col <= op->col) d2= -1;
1117 break;
1118 case 'H': /* Home */
1119 if (op2->type == O_DEV) d2= 0;
1120 }
1121 if (d2 < dist) { near= op2; dist= d2; }
1122 }
1123 if (near != op) event(E_LEAVE, op);
1124 event(E_ENTER, near);
1125}
1126
1127void m_updown(int ev, object_t *op)
1128/* Move a partition table entry up or down. */
1129{
1130 int i, j;
1131 struct part_entry tmp;
1132 int tmpx;
1133
1134 if (ev != ctrl('K') && ev != ctrl('J')) return;
1135 if (op->entry == nil) return;
1136
1137 i= op->entry - table;
1138 if (ev == ctrl('K')) {
1139 if (i <= 1) return;
1140 j= i-1;
1141 } else {
1142 if (i >= NR_PARTITIONS) return;
1143 j= i+1;
1144 }
1145
1146 tmp= table[i]; table[i]= table[j]; table[j]= tmp;
1147 tmpx= existing[i]; existing[i]= existing[j]; existing[j]= tmpx;
1148 sort();
1149 dirty= 1;
1150 event(ev == ctrl('K') ? 'k' : 'j', op);
1151}
1152
1153void m_enter(int ev, object_t *op)
1154/* We've moved onto this object. */
1155{
1156 if (ev != E_ENTER && ev != ' ' && ev != '<' && ev != '>' && ev != 'X')
1157 return;
1158 curobj= op;
1159 typing= 0;
1160 magic= 0;
1161}
1162
1163void m_leave(int ev, object_t *op)
1164/* About to leave this object. */
1165{
1166 if (ev != E_LEAVE) return;
1167}
1168
1169int within(unsigned *var, unsigned low, unsigned value, unsigned high)
1170/* Only set *var to value if it looks reasonable. */
1171{
1172 if (low <= value && value <= high) {
1173 *var= value;
1174 return 1;
1175 } else
1176 return 0;
1177}
1178
1179int lwithin(unsigned long *var, unsigned long low, unsigned long value,
1180 unsigned long high)
1181{
1182 if (low <= value && value <= high) {
1183 *var= value;
1184 return 1;
1185 } else
1186 return 0;
1187}
1188
1189int nextdevice(object_t *op, int delta)
1190/* Select the next or previous device from the device list. */
1191{
1192 dev_t rdev;
1193
1194 if (offset != 0) return 0;
1195 if (dirty) event(E_WRITE, op);
1196 if (dirty) return 0;
1197
1198 if (device >= 0) {
1199 (void) close(device);
1200 device= -1;
1201 }
1202 recompute0();
1203
1204 rdev= curdev->rdev;
1205 if (delta < 0) {
1206 do
1207 curdev= curdev->prev;
1208 while (delta < -1 && major(curdev->rdev) == major(rdev)
1209 && curdev->rdev < rdev);
1210 } else {
1211 do
1212 curdev= curdev->next;
1213 while (delta > 1 && major(curdev->rdev) == major(rdev)
1214 && curdev->rdev > rdev);
1215 }
1216 return 1;
1217}
1218
1219void check_ind(struct part_entry *pe)
1220/* If there are no other partitions then make this new one active. */
1221{
1222 struct part_entry *pe2;
1223 int i = 0;
1224
1225 for (pe2= table + 1; pe2 < table + 1 + NR_PARTITIONS; pe2++, i++)
1226 if (pe2->sysind != NO_PART && (pe2->bootind & ACTIVE_FLAG))
1227 return;
1228
1229 pe->bootind= ACTIVE_FLAG;
1230 dirty = 1;
1231}
1232
1233int check_existing(struct part_entry *pe)
1234/* Check and if not ask if an existing partition may be modified. */
1235{
1236 static int expert= 0;
1237 int c;
1238
1239 if (expert || pe == nil || !existing[pe - table]) return 1;
1240
1241 stat_start(1);
1242 putstr("Do you wish to modify existing partitions? (y/n) ");
1243 fflush(stdout);
1244 while ((c= getchar()) != 'y' && c != 'n') {}
1245 putchr(c);
1246 stat_end(3);
1247 return (expert= (c == 'y'));
1248}
1249
1250void m_modify(int ev, object_t *op)
1251/* Increment, decrement, set, or toggle the value of an object, using
1252 * arithmetic tricks the author doesn't understand either.
1253 */
1254{
1255 object_t *op2;
1256 struct part_entry *pe= op->entry;
1257 int mul, delta;
1258 unsigned level= 1;
1259 unsigned long surplus;
1260 int radix= op->type == O_TYPHEX ? 0x10 : 10;
1261 unsigned long t;
1262
1263 if (device < 0 && op->type != O_DEV) return;
1264
1265 switch (ev) {
1266 case '-':
1267 mul= radix; delta= -1; typing= 0;
1268 break;
1269 case '+':
1270 mul= radix; delta= 1; typing= 0;
1271 break;
1272 case '\b':
1273 if (!typing) return;
1274 mul= 1; delta= 0;
1275 break;
1276 case '\r':
1277 typing= 0;
1278 return;
1279 default:
1280 if ('0' <= ev && ev <= '9')
1281 delta= ev - '0';
1282 else
1283 if (radix == 0x10 && 'a' <= ev && ev <= 'f')
1284 delta= ev - 'a' + 10;
1285 else
1286 if (radix == 0x10 && 'A' <= ev && ev <= 'F')
1287 delta= ev - 'A' + 10;
1288 else
1289 return;
1290
1291 mul= typing ? radix*radix : 0;
1292 typing= 1;
1293 }
1294 magic= 0;
1295
1296 if (!check_existing(pe)) return;
1297
1298 switch (op->type) {
1299 case O_DEV:
1300 if (ev != '-' && ev != '+') return;
1301 if (!nextdevice(op, delta)) return;
1302 break;
1303 case O_CYL:
1304 if (!within(&cylinders, 1,
1305 cylinders * mul / radix + delta, 1024)) return;
1306 recompute0();
1307 break;
1308 case O_HEAD:
1309 if (!within(&heads, 1, heads * mul / radix + delta, 255))
1310 return;
1311 recompute0();
1312 break;
1313 case O_SEC:
1314 if (!within(&sectors, 1, sectors * mul / radix + delta, 63))
1315 return;
1316 recompute0();
1317 break;
1318 case O_NUM:
1319 if (ev != '-' && ev != '+') return;
1320 for (op2= world; op2 != nil; op2= op2->next) {
1321 if (op2->type == O_NUM && ev == '+')
1322 op2->entry->bootind= 0;
1323 }
1324 op->entry->bootind= ev == '+' ? ACTIVE_FLAG : 0;
1325 break;
1326 case O_TYPHEX:
1327 check_ind(pe);
1328 pe->sysind= pe->sysind * mul / radix + delta;
1329 break;
1330 case O_TYPTXT:
1331 if (ev != '-' && ev != '+') return;
1332 check_ind(pe);
1333 pe->sysind= round_sysind(pe->sysind, delta);
1334 break;
1335 case O_SCYL:
1336 level= heads;
1337 case O_SHEAD:
1338 level*= sectors;
1339 case O_SSEC:
1340 if (op->type != O_SCYL && ev != '-' && ev != '+') return;
1341 case O_BASE:
1342 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe));
1343 t= pe->lowsec;
1344 surplus= t % level;
1345 if (!lwithin(&t, 0L,
1346 (t / level * mul / radix + delta) * level + surplus,
1347 MAXSIZE)) return;
1348 if (howend == LAST || op->type != O_BASE)
1349 pe->size-= t - pe->lowsec;
1350 pe->lowsec= t;
1351 check_ind(pe);
1352 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
1353 break;
1354 case O_LCYL:
1355 level= heads;
1356 case O_LHEAD:
1357 level*= sectors;
1358 case O_LSEC:
1359 if (op->type != O_LCYL && ev != '-' && ev != '+') return;
1360
1361 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe));
1362 t= pe->lowsec + pe->size - 1 + level;
1363 surplus= t % level - mul / radix * level;
1364 if (!lwithin(&t, 0L,
1365 (t / level * mul / radix + delta) * level + surplus,
1366 MAXSIZE)) return;
1367 pe->size= t - pe->lowsec + 1;
1368 check_ind(pe);
1369 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
1370 break;
1371 case O_KB:
1372 level= 2;
1373 if (mul == 0) pe->size= 0; /* new value, no surplus */
1374 case O_SIZE:
1375 if (pe->sysind == NO_PART) {
1376 if (op->type == O_KB || howend == SIZE) {
1377 /* First let loose magic to set the base. */
1378 event('m', op);
1379 magic= 0;
1380 pe->size= 0;
1381 event(ev, op);
1382 return;
1383 }
1384 memset(pe, 0, sizeof(*pe));
1385 }
1386 t= (op->type == O_KB || howend == SIZE) ? pe->size
1387 : pe->lowsec + pe->size - 1;
1388 surplus= t % level;
1389 if (!lwithin(&t, 0L,
1390 (t / level * mul / radix + delta) * level + surplus,
1391 MAXSIZE)) return;
1392 pe->size= (op->type == O_KB || howend == SIZE) ? t :
1393 t - pe->lowsec + 1;
1394 check_ind(pe);
1395 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
1396 break;
1397 default:
1398 return;
1399 }
1400
1401 /* The order among the entries may have changed. */
1402 sort();
1403 dirty= 1;
1404}
1405
1406unsigned long spell[3 + 4 * (1+NR_PARTITIONS)];
1407int nspells;
1408objtype_t touching;
1409
1410void newspell(unsigned long charm)
1411/* Add a new spell, descending order for the base, ascending for the size. */
1412{
1413 int i, j;
1414
1415 if (charm - table[0].lowsec > table[0].size) return;
1416
1417 for (i= 0; i < nspells; i++) {
1418 if (charm == spell[i]) return; /* duplicate */
1419
1420 if (touching == O_BASE) {
1421 if (charm == table[0].lowsec + table[0].size) return;
1422 if ((spell[0] - charm) < (spell[0] - spell[i])) break;
1423 } else {
1424 if (charm == table[0].lowsec) return;
1425 if ((charm - spell[0]) < (spell[i] - spell[0])) break;
1426 }
1427 }
1428 for (j= ++nspells; j > i; j--) spell[j]= spell[j-1];
1429 spell[i]= charm;
1430}
1431
1432void m_magic(int ev, object_t *op)
1433/* Apply magic onto a base or size number. */
1434{
1435 struct part_entry *pe= op->entry, *pe2;
1436 int rough= (offset != 0 && extbase == 0);
1437
1438 if (ev != 'm' || device < 0) return;
1439 typing= 0;
1440
1441 if (!check_existing(pe)) return;
1442
1443 if (magic == 0) {
1444 /* See what magic we can let loose on this value. */
1445 nspells= 1;
1446
1447 /* First spell, the current value. */
1448 switch (op->type) {
1449 case O_SCYL:
1450 case O_SHEAD: /* Start of partition. */
1451 case O_SSEC:
1452 case O_BASE:
1453 touching= O_BASE;
1454 spell[0]= pe->lowsec;
1455 break;
1456 case O_LCYL:
1457 case O_LHEAD:
1458 case O_LSEC: /* End of partition. */
1459 case O_KB:
1460 case O_SIZE:
1461 touching= O_SIZE;
1462 spell[0]= pe->lowsec + pe->size;
1463 break;
1464 default:
1465 return;
1466 }
1467 if (pe->sysind == NO_PART) {
1468 memset(pe, 0, sizeof(*pe));
1469 check_ind(pe);
1470 pe->sysind= MINIX_PART;
1471 spell[0]= 0;
1472 if (touching == O_SIZE) {
1473 /* First let loose magic on the base. */
1474 object_t *op2;
1475
1476 for (op2= world; op2 != nil; op2= op2->next) {
1477 if (op2->row == op->row &&
1478 op2->type == O_BASE) {
1479 event('m', op2);
1480 }
1481 }
1482 magic= 0;
1483 event('m', op);
1484 return;
1485 }
1486 }
1487 /* Avoid the first sector on the device. */
1488 if (spell[0] == table[0].lowsec) newspell(spell[0] + 1);
1489
1490 /* Further interesting values are the the bases of other
1491 * partitions or their ends.
1492 */
1493 for (pe2= table; pe2 < table + 1 + NR_PARTITIONS; pe2++) {
1494 if (pe2 == pe || pe2->sysind == NO_PART) continue;
1495 if (pe2->lowsec == table[0].lowsec)
1496 newspell(table[0].lowsec + 1);
1497 else
1498 newspell(pe2->lowsec);
1499 newspell(pe2->lowsec + pe2->size);
1500 if (touching == O_BASE && howend == SIZE) {
1501 newspell(pe2->lowsec - pe->size);
1502 newspell(pe2->lowsec + pe2->size - pe->size);
1503 }
1504 if (pe2->lowsec % sectors != 0) rough= 1;
1505 }
1506 /* Present values rounded up to the next cylinder unless
1507 * the table is already a mess. Use "start + 1 track" instead
1508 * of "start + 1 cylinder". Also add the end of the last
1509 * cylinder.
1510 */
1511 if (!rough) {
1512 unsigned long n= spell[0];
1513 if (n == table[0].lowsec) n++;
1514 n= (n + sectors - 1) / sectors * sectors;
1515 if (n != table[0].lowsec + sectors)
1516 n= (n + secpcyl - 1) / secpcyl * secpcyl;
1517 newspell(n);
1518 if (touching == O_SIZE)
1519 newspell(table[0].size / secpcyl * secpcyl);
1520 }
1521 }
1522 /* Magic has been applied, a spell needs to be chosen. */
1523
1524 if (++magic == nspells) magic= 0;
1525
1526 if (touching == O_BASE) {
1527 if (howend == LAST) pe->size-= spell[magic] - pe->lowsec;
1528 pe->lowsec= spell[magic];
1529 } else
1530 pe->size= spell[magic] - pe->lowsec;
1531
1532 /* The order among the entries may have changed. */
1533 sort();
1534 dirty= 1;
1535}
1536
1537typedef struct diving {
1538 struct diving *up;
1539 struct part_entry old0;
1540 char *oldsubname;
1541 parttype_t oldparttype;
1542 unsigned long oldoffset;
1543 unsigned long oldextbase;
1544} diving_t;
1545
1546diving_t *diving= nil;
1547
1548void m_in(int ev, object_t *op)
1549/* Go down into a primary or extended partition. */
1550{
1551 diving_t *newdiv;
1552 struct part_entry *pe= op->entry, ext;
1553 int n;
1554
1555 if (ev != '>' || device < 0 || pe == nil || pe == &table[0]
1556 || (!(pe->sysind == MINIX_PART && offset == 0)
1557 && !ext_part(pe->sysind))
1558 || pe->size == 0) return;
1559
1560 ext= *pe;
1561 if (extbase != 0) ext.size= extbase + extsize - ext.lowsec;
1562
1563 if (dirty) event(E_WRITE, op);
1564 if (dirty) return;
1565 if (device >= 0) { close(device); device= -1; }
1566
1567 newdiv= alloc(sizeof(*newdiv));
1568 newdiv->old0= table[0];
1569 newdiv->oldsubname= curdev->subname;
1570 newdiv->oldparttype= curdev->parttype;
1571 newdiv->oldoffset= offset;
1572 newdiv->oldextbase= extbase;
1573 newdiv->up= diving;
1574 diving= newdiv;
1575
1576 table[0]= ext;
1577
1578 n= strlen(diving->oldsubname);
1579 curdev->subname= alloc((n + 3) * sizeof(curdev->subname[0]));
1580 strcpy(curdev->subname, diving->oldsubname);
1581 curdev->subname[n++]= ':';
1582 curdev->subname[n++]= '0' + (pe - table - 1);
1583 curdev->subname[n]= 0;
1584
1585 curdev->parttype= curdev->parttype == PRIMARY ? SUBPART : DUNNO;
1586 offset= ext.lowsec;
1587 if (ext_part(ext.sysind) && extbase == 0) {
1588 extbase= ext.lowsec;
1589 extsize= ext.size;
1590 curdev->parttype= DUNNO;
1591 }
1592
1593 submerged= 1;
1594 event('r', op);
1595}
1596
1597void m_out(int ev, object_t *op)
1598/* Go up from an extended or subpartition table to its enclosing. */
1599{
1600 diving_t *olddiv;
1601
1602 if (ev != '<' || diving == nil) return;
1603
1604 if (dirty) event(E_WRITE, op);
1605 if (dirty) return;
1606 if (device >= 0) { close(device); device= -1; }
1607
1608 olddiv= diving;
1609 diving= olddiv->up;
1610
1611 table[0]= olddiv->old0;
1612
1613 free(curdev->subname);
1614 curdev->subname= olddiv->oldsubname;
1615
1616 curdev->parttype= olddiv->oldparttype;
1617 offset= olddiv->oldoffset;
1618 extbase= olddiv->oldextbase;
1619
1620 free(olddiv);
1621
1622 event('r', op);
1623 if (diving == nil) submerged= 0; /* We surfaced. */
1624}
1625
1626void installboot(unsigned char *bootblock, char *masterboot)
1627/* Install code from a master bootstrap into a boot block. */
1628{
1629 FILE *mfp;
1630 struct exec hdr;
1631 int n;
1632 char *err;
1633
1634 if ((mfp= fopen(masterboot, "r")) == nil) {
1635 err= strerror(errno);
1636 goto m_err;
1637 }
1638
1639 n= fread(&hdr, sizeof(char), A_MINHDR, mfp);
1640 if (ferror(mfp)) {
1641 err= strerror(errno);
1642 fclose(mfp);
1643 goto m_err;
1644 }
1645
1646 if (n < A_MINHDR || BADMAG(hdr) || hdr.a_cpu != A_I8086) {
1647 err= "Not an 8086 executable";
1648 fclose(mfp);
1649 goto m_err;
1650 }
1651
1652 if (hdr.a_text + hdr.a_data > PART_TABLE_OFF) {
1653 err= "Does not fit in a boot sector";
1654 fclose(mfp);
1655 goto m_err;
1656 }
1657
1658 fseek(mfp, hdr.a_hdrlen, 0);
1659 fread(bootblock, sizeof(char), (size_t) (hdr.a_text + hdr.a_data), mfp);
1660 if (ferror(mfp)) {
1661 err= strerror(errno);
1662 fclose(mfp);
1663 goto m_err;
1664 }
1665 fclose(mfp);
1666
1667 /* Bootstrap installed. */
1668 return;
1669
1670 m_err:
1671 stat_start(1);
1672 printf("%s: %s", masterboot, err);
1673 stat_end(5);
1674}
1675
1676ssize_t boot_readwrite(int rw)
1677/* Read (0) or write (1) the boot sector. */
1678{
1679 u64_t off64 = mul64u(offset, SECTOR_SIZE);
1680 int r;
1681
1682#if __minix_vmd
1683 /* Minix-vmd has a 64 bit seek. */
1684 if (fcntl(device, F_SEEK, off64) < 0) return -1;
1685#else
1686 /* Minix has to gross things with the partition base. */
1687 struct partition geom0, geom_seek;
1688
1689 if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) {
1690 /* Move partition base. */
1691 if (ioctl(device, DIOCGETP, &geom0) < 0) return -1;
1692 geom_seek.base = add64(geom0.base, off64);
1693 geom_seek.size = cvu64(cmp64(add64u(off64, SECTOR_SIZE),
1694 geom0.size) <= 0 ? _STATIC_BLOCK_SIZE : 0);
1695 sync();
1696 if (ioctl(device, DIOCSETP, &geom_seek) < 0) return -1;
1697 if (lseek(device, (off_t) 0, SEEK_SET) == -1) return -1;
1698 } else {
1699 /* Can reach this point normally. */
1700 if (lseek(device, (off_t) offset * SECTOR_SIZE, SEEK_SET) == -1)
1701 return -1;
1702 }
1703#endif
1704
1705 switch (rw) {
1706 case 0: r= read(device, bootblock, SECTOR_SIZE); break;
1707 case 1: r= write(device, bootblock, SECTOR_SIZE); break;
1708 }
1709
1710#if !__minix_vmd
1711 if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) {
1712 /* Restore partition base and size. */
1713 sync();
1714 if (ioctl(device, DIOCSETP, &geom0) < 0) return -1;
1715 }
1716#endif
1717 return r;
1718}
1719
1720int cylinderalign(region_t *reg)
1721{
1722 if(reg->is_used_part) {
1723 if(reg->used_part.lowsec != table[0].lowsec + sectors
1724 && (reg->used_part.lowsec % secpcyl)) {
1725 int extra;
1726 extra = secpcyl - (reg->used_part.lowsec % secpcyl);
1727 reg->used_part.lowsec += extra;
1728 reg->used_part.size -= extra;
1729 }
1730 if((reg->used_part.size+1) % secpcyl) {
1731 reg->used_part.size -= secpcyl - ((reg->used_part.size + 1) % secpcyl);
1732 }
1733 return reg->used_part.size > 0;
1734 }
1735
1736 if(reg->free_sec_start != table[0].lowsec + sectors && (reg->free_sec_start % secpcyl)) {
1737 /* Start is unaligned. Round up. */
1738 reg->free_sec_start += secpcyl - (reg->free_sec_start % secpcyl);
1739 }
1740 if((reg->free_sec_last+1) % secpcyl) {
1741 /* End is unaligned. Round down. */
1742 reg->free_sec_last -= (reg->free_sec_last+1) % secpcyl;
1743 }
1744
1745 /* Return nonzero if anything remains of the region after rounding. */
1746 return reg->free_sec_last > reg->free_sec_start;
1747}
1748
1749void regionize(void)
1750{
1751 int free_sec, i, si;
1752
1753 sort();
1754
1755 free_sec = table[0].lowsec + sectors;
1756
1757 /* Create region data used in autopart mode. */
1758 free_regions = used_regions = nr_regions = nr_partitions = 0;
1759 if(table[0].lowsec > table[sort_order[1]].lowsec &&
1760 table[sort_order[1]].sysind != NO_PART) {
1761 printf("\nSanity check failed on %s - first partition starts before disk.\n"
1762 "Please use expert mode to correct it.\n", curdev->name);
1763 exit(1);
1764 }
1765 for(si = 1; si <= NR_PARTITIONS; si++) {
1766 i = sort_order[si];
1767 if(i < 1 || i > NR_PARTITIONS) {
1768 printf("Sorry, something unexpected has happened (%d out of range).\n", i);
1769 exit(1);
1770 }
1771
1772 if(table[i].sysind == NO_PART)
1773 break;
1774
1775 /* Free space before this partition? */
1776 if(table[i].lowsec > free_sec) {
1777 /* Free region before this partition. */
1778 regions[nr_regions].free_sec_start = free_sec;
1779 regions[nr_regions].free_sec_last = table[i].lowsec-1;
1780 regions[nr_regions].is_used_part = 0;
1781 if(cylinderalign(&regions[nr_regions])) {
1782 nr_regions++;
1783 free_regions++;
1784 }
1785 }
1786
1787 /* Sanity check. */
1788 if(si > 1) {
1789 if(table[i].lowsec < table[sort_order[si-1]].lowsec ||
1790 table[i].lowsec < table[sort_order[si-1]].lowsec + table[sort_order[si-1]].size) {
1791 printf("\nSanity check failed on %s - partitions overlap.\n"
1792 "Please use expert mode to correct it.\n", curdev->name);
1793 exit(1);
1794 }
1795 }
1796 if(table[i].size > table[0].size) {
1797 printf("\nSanity check failed on %s - partition is larger than disk.\n"
1798 "Please use expert mode to correct it.\n", curdev->name);
1799 exit(1);
1800 }
1801 if(table[i].size < 1) {
1802 printf("\nSanity check failed on %s - zero-sized partition.\n"
1803 "Please use expert mode to correct it.\n", curdev->name);
1804 exit(1);
1805 }
1806
1807 /* Remember used region. */
1808 memcpy(&regions[nr_regions].used_part, &table[i], sizeof(table[i]));
1809 free_sec = table[i].lowsec+table[i].size;
1810 regions[nr_regions].is_used_part = 1;
1811 regions[nr_regions].tableno = i;
1812 nr_partitions++;
1813 nr_regions++;
1814 used_regions++;
1815 }
1816
1817 /* Special case: space after partitions. */
1818 if(free_sec < table[0].lowsec + table[0].size-1) {
1819 regions[nr_regions].free_sec_start = free_sec;
1820 regions[nr_regions].free_sec_last = table[0].lowsec + table[0].size-1;
1821 regions[nr_regions].is_used_part = 0;
1822 if(cylinderalign(&regions[nr_regions])) {
1823 nr_regions++;
1824 free_regions++;
1825 }
1826 }
1827
1828}
1829
1830void m_read(int ev, int *biosdrive)
1831/* Read the partition table from the current device. */
1832{
1833 int si, i, mode, n, r, v;
1834 struct part_entry *pe;
1835
1836 if (ev != 'r' || device >= 0) return;
1837
1838 /* Open() may cause kernel messages: */
1839 stat_start(0);
1840 fflush(stdout);
1841
1842 if ((device= open(curdev->name, mode= O_RDWR, 0666)) < 0) {
1843 if (device >= 0) { close(device); device= -1; }
1844 return;
1845 }
1846
1847 v = 2*HZ;
1848 ioctl(device, DIOCTIMEOUT, &v);
1849
1850 memset(bootblock, 0, sizeof(bootblock));
1851
1852 n= boot_readwrite(0);
1853
1854 if (n <= 0) stat_start(1);
1855 if (n < 0) {
1856 close(device);
1857 device= -1;
1858 } else
1859 if (n < SECTOR_SIZE) {
1860 close(device);
1861 device= -1;
1862 return;
1863 }
1864 if (n <= 0) stat_end(5);
1865
1866 if (n < SECTOR_SIZE) n= SECTOR_SIZE;
1867
1868 if(biosdrive) (*biosdrive)++;
1869
1870 if(!open_ct_ok(device)) {
1871 printf("\n%s: device in use! skipping it.", curdev->subname);
1872 fflush(stdout);
1873 close(device);
1874 device= -1;
1875 return;
1876 }
1877
1878 memcpy(table+1, bootblock+PART_TABLE_OFF,
1879 NR_PARTITIONS * sizeof(table[1]));
1880 if (bootblock[510] != 0x55 || bootblock[511] != 0xAA) {
1881 /* Invalid boot block, install bootstrap, wipe partition table.
1882 */
1883 memset(bootblock, 0, sizeof(bootblock));
1884 installboot(bootblock, MASTERBOOT);
1885 memset(table+1, 0, NR_PARTITIONS * sizeof(table[1]));
1886 }
1887
1888 /* Fix an extended partition table up to something mere mortals can
1889 * understand. Record already defined partitions.
1890 */
1891 for (i= 1; i <= NR_PARTITIONS; i++) {
1892 pe= &table[i];
1893 if (extbase != 0 && pe->sysind != NO_PART)
1894 pe->lowsec+= ext_part(pe->sysind) ? extbase : offset;
1895 existing[i]= pe->sysind != NO_PART;
1896 }
1897 geometry();
1898 dirty= 0;
1899
1900 /* Warn about grave dangers ahead. */
1901 if (extbase != 0) {
1902 stat_start(1);
1903 printf("Warning: You are in an extended partition.");
1904 stat_end(5);
1905 }
1906
1907 regionize();
1908}
1909
1910void m_write(int ev, object_t *op)
1911/* Write the partition table back if modified. */
1912{
1913 int c;
1914 struct part_entry new_table[NR_PARTITIONS], *pe;
1915
1916 if (ev != 'w' && ev != E_WRITE) return;
1917 if (device < 0) { dirty= 0; return; }
1918 if (!dirty) {
1919 if (ev == 'w') {
1920 stat_start(1);
1921 printf("%s is not changed, or has already been written",
1922 curdev->subname);
1923 stat_end(2);
1924 }
1925 return;
1926 }
1927
1928 if (extbase != 0) {
1929 /* Will this stop him? Probably not... */
1930 stat_start(1);
1931 printf("You have changed an extended partition. Bad Idea.");
1932 stat_end(5);
1933 }
1934
1935 memcpy(new_table, table+1, NR_PARTITIONS * sizeof(table[1]));
1936 for (pe= new_table; pe < new_table + NR_PARTITIONS; pe++) {
1937 if (pe->sysind == NO_PART) {
1938 memset(pe, 0, sizeof(*pe));
1939 } else {
1940 abs2dos(&pe->start_head, pe->lowsec);
1941 abs2dos(&pe->last_head, pe->lowsec + pe->size - 1);
1942
1943 /* Fear and loathing time: */
1944 if (extbase != 0)
1945 pe->lowsec-= ext_part(pe->sysind)
1946 ? extbase : offset;
1947 }
1948 }
1949 memcpy(bootblock+PART_TABLE_OFF, new_table, sizeof(new_table));
1950 bootblock[510]= 0x55;
1951 bootblock[511]= 0xAA;
1952
1953 if (boot_readwrite(1) < 0) {
1954 stat_start(1);
1955 printf("%s: %s", curdev->name, strerror(errno));
1956 stat_end(5);
1957 return;
1958 }
1959 dirty= 0;
1960}
1961
1962void m_shell(int ev, object_t *op)
1963/* Shell escape, to do calculations for instance. */
1964{
1965 int r, pid, status;
1966 void (*sigint)(int), (*sigquit)(int), (*sigterm)(int);
1967
1968 if (ev != 's') return;
1969
1970 reset_tty();
1971 fflush(stdout);
1972
1973 switch (pid= fork()) {
1974 case -1:
1975 stat_start(1);
1976 printf("can't fork: %s\n", strerror(errno));
1977 stat_end(3);
1978 break;
1979 case 0:
1980 if (device >= 0) (void) close(device);
1981 execl("/bin/sh", "sh", (char *) nil);
1982 r= errno;
1983 stat_start(1);
1984 printf("/bin/sh: %s\n", strerror(errno));
1985 stat_end(3);
1986 exit(127);
1987 }
1988 sigint= signal(SIGINT, SIG_IGN);
1989 sigquit= signal(SIGQUIT, SIG_IGN);
1990 sigterm= signal(SIGTERM, SIG_IGN);
1991 while (pid >= 0 && (r= wait(&status)) >= 0 && r != pid) {}
1992 (void) signal(SIGINT, sigint);
1993 (void) signal(SIGQUIT, sigquit);
1994 (void) signal(SIGTERM, sigterm);
1995 tty_raw();
1996 if (pid < 0)
1997 ;
1998 else
1999 if (WIFEXITED(status) && WEXITSTATUS(status) == 127)
2000 stat_start(0); /* Match the stat_start in the child. */
2001 else
2002 event(ctrl('L'), op);
2003}
2004
2005void m_dump(struct part_entry *print_table)
2006/* Raw dump of the partition table. */
2007{
2008 struct part_entry *pe;
2009 int i;
2010 unsigned chs[3];
2011
2012printf(" Partition + type Cyl Head Sec Cyl Head Sec Base Size Kb\n");
2013 for (i= 1; i <= NR_PARTITIONS; i++) {
2014 pe= &print_table[i];
2015 dos2chs(&pe->start_head, chs);
2016 printf("%2d%c %02X%15d%5d%4d",
2017 i,
2018 pe->bootind & ACTIVE_FLAG ? '*' : ' ',
2019 pe->sysind,
2020 chs[0], chs[1], chs[2]);
2021 dos2chs(&pe->last_head, chs);
2022 printf("%6d%5d%4d%10lu%10ld%9lu\n",
2023 chs[0], chs[1], chs[2],
2024 pe->lowsec,
2025 howend == SIZE ? pe->size : pe->size + pe->lowsec - 1,
2026 pe->size / 2);
2027 }
2028}
2029
2030int quitting= 0;
2031
2032void m_quit(int ev, object_t *op)
2033/* Write the partition table if modified and exit. */
2034{
2035 if (ev != 'q' && ev != 'x') return;
2036
2037 quitting= 1;
2038
2039 if (dirty) event(E_WRITE, op);
2040 if (dirty) quitting= 0;
2041}
2042
2043void m_help(int ev, object_t *op)
2044/* For people without a clue; let's hope they can find the '?' key. */
2045{
2046 static struct help {
2047 char *keys;
2048 char *what;
2049 } help[]= {
2050 { "? !", "This help / more advice!" },
2051 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
2052 { "0-9 (a-f)", "Enter value" },
2053 { "hjkl (arrow keys)", "Move around" },
2054 { "CTRL-K CTRL-J", "Move entry up/down" },
2055 { "CTRL-L", "Redraw screen" },
2056 { ">", "Start a subpartition table" },
2057 { "<", "Back to the primary partition table" },
2058 { "m", "Cycle through magic values" },
2059 { "spacebar", "Show \"Size\" or \"Last\"" },
2060 { "r w", "Read/write partition table" },
2061 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
2062 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
2063 };
2064 static char *advice[] = {
2065"* Choose a disk with '+' and '-', then hit 'r'.",
2066"* To change any value: Move to it and use '+', '-' or type the desired value.",
2067"* To make a new partition: Move over to the Size or Kb field of an unused",
2068" partition and type the size. Hit the 'm' key to pad the partition out to",
2069" a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
2070" You can hit 'm' more than once on a base or size field to see several",
2071" interesting values go by. Note: Other Operating Systems can be picky about",
2072" partitions that are not padded to cylinder boundaries. Look for highlighted",
2073" head or sector numbers.",
2074"* To reuse a partition: Change the type to MINIX.",
2075"* To delete a partition: Type a zero in the hex Type field.",
2076"* To make a partition active: Type '+' in the Num field.",
2077"* To study the list of keys: Type '?'.",
2078 };
2079
2080 if (ev == '?') {
2081 struct help *hp;
2082
2083 for (hp= help; hp < arraylimit(help); hp++) {
2084 stat_start(0);
2085 printf("%-25s - %s", hp->keys, hp->what);
2086 stat_end(0);
2087 }
2088 stat_start(0);
2089 putstr("Things like ");
2090 putstr(t_so); putstr("this"); putstr(t_se);
2091 putstr(" must be checked, but ");
2092 putstr(t_md); putstr("this"); putstr(t_me);
2093 putstr(" is not really a problem");
2094 stat_end(0);
2095 } else
2096 if (ev == '!') {
2097 char **ap;
2098
2099 for (ap= advice; ap < arraylimit(advice); ap++) {
2100 stat_start(0);
2101 putstr(*ap);
2102 stat_end(0);
2103 }
2104 }
2105}
2106
2107void event(int ev, object_t *op)
2108/* Simply call all modifiers for an event, each one knows when to act. */
2109{
2110 m_help(ev, op);
2111 m_redraw(ev, op);
2112 m_toggle(ev, op);
2113 m_orientation(ev, op);
2114 m_move(ev, op);
2115 m_updown(ev, op);
2116 m_enter(ev, op);
2117 m_leave(ev, op);
2118 m_modify(ev, op);
2119 m_magic(ev, op);
2120 m_in(ev, op);
2121 m_out(ev, op);
2122 m_read(ev, NULL);
2123 m_write(ev, op);
2124 m_shell(ev, op);
2125 m_quit(ev, op);
2126}
2127
2128int keypress(void)
2129/* Get a single keypress. Translate compound keypresses (arrow keys) to
2130 * their simpler equivalents.
2131 */
2132{
2133 char ch;
2134 int c;
2135 int esc= 0;
2136
2137 set_cursor(curobj->row, curobj->col);
2138 fflush(stdout);
2139
2140 do {
2141 if (read(0, &ch, sizeof(ch)) < 0) fatal("stdin");
2142 c= (unsigned char) ch;
2143 switch (esc) {
2144 case 0:
2145 switch (c) {
2146 case ctrl('['): esc= 1; break;
2147 case '_': c= '-'; break;
2148 case '=': c= '+'; break;
2149 }
2150 break;
2151 case 1:
2152 esc= c == '[' ? 2 : 0;
2153 break;
2154 case 2:
2155 switch (c) {
2156 case 'D': c= 'h'; break;
2157 case 'B': c= 'j'; break;
2158 case 'A': c= 'k'; break;
2159 case 'C': c= 'l'; break;
2160 case 'H': c= 'H'; break;
2161 case 'U':
2162 case 'S': c= '-'; break;
2163 case 'V':
2164 case 'T': c= '+'; break;
2165 }
2166 /*FALL THROUGH*/
2167 default:
2168 esc= 0;
2169 }
2170 } while (esc > 0);
2171
2172 switch (c) {
2173 case ctrl('B'): c= 'h'; break;
2174 case ctrl('N'): c= 'j'; break;
2175 case ctrl('P'): c= 'k'; break;
2176 case ctrl('F'): c= 'l'; break;
2177 }
2178
2179 return c;
2180}
2181
2182void mainloop(void)
2183/* Get keypress, handle event, display results, reset screen, ad infinitum. */
2184{
2185 int key;
2186
2187 while (!quitting) {
2188 stat_reset();
2189
2190 key= keypress();
2191
2192 event(key, curobj);
2193
2194 display();
2195 }
2196}
2197
2198char *
2199prettysizeprint(int kb)
2200{
2201 int toosmall = 0;
2202 static char str[200];
2203 char unit = 'k';
2204 if(MIN_REGION_SECTORS > kb*2)
2205 toosmall = 1;
2206 if(kb >= 5*1024) {
2207 kb /= 1024;
2208 unit = 'M';
2209 if(kb >= 5*1024) {
2210 kb /= 1024;
2211 unit = 'G';
2212 }
2213 }
2214 sprintf(str, "%4d %cB%s", kb, unit,
2215 toosmall ? ", too small for MINIX 3" : "");
2216 return str;
2217}
2218
2219void
2220printregions(region_t *theregions, int indent, int p_nr_partitions, int p_free_regions, int p_nr_regions, int numbers)
2221{
2222 int r, nofree = 0;
2223 region_t *reg;
2224 reg = theregions;
2225
2226 if((p_nr_partitions >= NR_PARTITIONS || !p_free_regions) && p_free_regions)
2227 nofree = 1;
2228 for(r = 0; r < p_nr_regions; r++, reg++) {
2229 unsigned long units;
2230 if(reg->is_used_part) {
2231 char *name;
2232 name = typ2txt(reg->used_part.sysind);
2233 printf("%*s", indent, ""); type2col(reg->used_part.sysind);
2234 if(numbers) printf("[%d] ", r);
2235 printf("In use by %-10s ", name);
2236 units = reg->used_part.size / 2;
2237 col(0);
2238 printf(" (%s)\n", prettysizeprint(units));
2239 } else {
2240 printf("%*s", indent, "");
2241 if(numbers) {
2242 if(!nofree) printf("[%d] ", r);
2243 else printf("[-] ");
2244 }
2245 printf("Free space ");
2246 units = ((reg->free_sec_last - reg->free_sec_start+1))/2;
2247 printf(" (%s)\n", prettysizeprint(units));
2248 }
2249 }
2250
2251 if(numbers && p_nr_partitions >= NR_PARTITIONS && p_free_regions) {
2252 printf(
2253"\nNote: there is free space on this disk, but you can't select it,\n"
2254"because there isn't a free slot in the partition table to use it.\n"
2255"You can reclaim the free space by deleting an adjacent region.\n");
2256 }
2257
2258 return;
2259}
2260
2261#define IS_YES 3
2262#define IS_NO 4
2263#define IS_OTHER 5
2264int
2265is_sure(char *fmt, ...)
2266{
2267 char yesno[10];
2268 va_list ap;
2269 va_start (ap, fmt);
2270 vprintf(fmt, ap);
2271 va_end(ap);
2272 printf(" Please enter 'yes' or 'no': ");
2273 fflush(stdout);
2274 if(!fgets(yesno, sizeof(yesno)-1, stdin)) exit(1);
2275
2276 if (strcmp(yesno, "yes\n") == 0) return(IS_YES);
2277 if (strcmp(yesno, "no\n") == 0) return(IS_NO);
2278 return IS_OTHER;
2279}
2280
2281void warn(char *message)
2282{
2283 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ! %s\n",message);
2284}
2285
2286int
2287may_kill_region(void)
2288{
2289 int confirmation;
2290 char line[100];
2291 int r, i;
2292
2293 if(used_regions < 1) return 1;
2294
2295 printf("\n -- Delete in-use region? --\n\n");
2296
2297 printregions(regions, 3, nr_partitions, free_regions, nr_regions, 1);
2298 printf("\nEnter the region number to delete or ENTER to continue: ");
2299 fflush(NULL);
2300 fgets(line, sizeof(line)-2, stdin);
2301 if(!isdigit(line[0]))
2302 return 1;
2303
2304 r=atoi(line);
2305 if(r < 0 || r >= nr_regions) {
2306 printf("This choice is out of range.\n");
2307 return 0;
2308 }
2309
2310 if(!regions[r].is_used_part) {
2311 printf("This region is not in use.\n");
2312 return 0;
2313 }
2314
2315 i = regions[r].tableno;
2316
2317 printf("\nPlease confirm that you want to delete region %d, losing all data it", r);
2318 printf("\ncontains. You're disk is not actually updated right away, but still.");
2319 printf("\n\n");
2320
2321 do {
2322 confirmation = is_sure("Are you sure you want to continue?");
2323 if (confirmation == IS_NO) return 0;
2324 } while (confirmation != IS_YES);
2325
2326 table[i].sysind = NO_PART;
2327 dirty = 1;
2328 regionize();
2329
2330 /* User may go again. */
2331 return 0;
2332}
2333
2334
2335region_t *
2336select_region(void)
2337{
2338 int r, rem, rn, done = 0;
2339 static char line[100];
2340 region_t *reg;
2341 int nofree = 0;
2342
2343 printstep(2, "Select a disk region");
2344
2345 if(nr_regions < 1) {
2346 printf("\nNo regions found - maybe the drive is too small.\n"
2347 "Please try expert mode.\n");
2348 exit(1);
2349 }
2350
2351 if(nr_partitions >= NR_PARTITIONS || !free_regions) {
2352 if(free_regions) {
2353 nofree = 1;
2354 }
2355 }
2356
2357
2358 printf("\nPlease select the region that you want to use for the MINIX 3 setup.");
2359 printf("\nIf you select an in-use region it will be overwritten by MINIX. The");
2360 printf("\nfollowing region%s were found on the selected disk:\n\n",
2361 SORNOT(nr_regions));
2362 printregions(regions, 3, nr_partitions, free_regions, nr_regions, 1);
2363
2364
2365 printf("\n");
2366 do {
2367 printf("Enter the region number to use or type 'delete': ");
2368 if(nr_regions == 1) printf(" [0] ");
2369 fflush(NULL);
2370
2371 if(!fgets(line, sizeof(line)-2, stdin))
2372 exit(1);
2373
2374 if (nr_regions == 1 && line[0] == '\n') {
2375 rn = 0;
2376 done = 1;
2377 }
2378 else {
2379 if(strcmp(line,"delete\n") == 0) {
2380 may_kill_region();
2381 return NULL;
2382 }
2383
2384 if(sscanf(line, "%d", &rn) != 1) {
2385 warn("invalid choice");
2386 continue;
2387 }
2388
2389 if(rn < 0 || rn >= nr_regions) {
2390 warn("out of range");
2391 continue;
2392 }
2393
2394 if(nofree && !regions[rn].is_used_part) {
2395 warn("not available");
2396 continue;
2397 }
2398
2399 done = 1;
2400 }
2401 } while(! done);
2402
2403 return(&regions[rn]);
2404}
2405
2406static void printstep(int step, char *str)
2407{
2408 int n;
2409 n = printf("\n --- Substep 4.%d: %s ---", step, str);
2410 while(n++ < 73) printf("-");
2411 printf("\n");
2412}
2413
2414device_t *
2415select_disk(void)
2416{
2417 int done = 0;
2418 int i, choice, drives;
2419 static char line[500];
2420 int biosdrive = 0;
2421
2422 printstep(1, "Select a disk to install MINIX 3");
2423 printf("\nProbing for disks. This may take a short while.");
2424
2425 i = 0;
2426 curdev=firstdev;
2427
2428 for(; i < MAX_DEVICES;) {
2429 printf(".");
2430 fflush(stdout);
2431 m_read('r', &biosdrive);
2432 if(device >= 0) {
2433 devices[i].dev = curdev;
2434 devices[i].free_regions = free_regions;
2435 devices[i].nr_regions = nr_regions;
2436 devices[i].nr_partitions = nr_partitions;
2437 devices[i].used_regions = used_regions;
2438 devices[i].sectors = table[0].size;
2439 curdev->biosdrive = biosdrive-1;
2440 memcpy(devices[i].regions, regions, sizeof(regions));
2441 i++;
2442 }
2443
2444 nextdevice(NULL, 1);
2445 if(curdev == firstdev)
2446 break;
2447 }
2448
2449 drives = i;
2450
2451 if(drives < 1) {
2452 printf("\nFound no drives - can't partition.\n");
2453 exit(1);
2454 }
2455
2456 printf(" Probing done.\n");
2457 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives),
2458 drives == 1 ? "was" : "were");
2459
2460 for(i = 0; i < drives; i++) {
2461 printf(" ");
2462 printf("Disk [%d]: ", i);
2463 printf("%s, ", devices[i].dev->name);
2464 printf("%s\n", prettysizeprint(devices[i].sectors/2));
2465 printregions(devices[i].regions, 8,
2466 devices[i].nr_partitions,
2467 devices[i].free_regions,
2468 devices[i].nr_regions, 0);
2469 }
2470
2471 printf("\n");
2472 do {
2473 printf("Enter the disk number to use: ");
2474 if (drives == 1) printf("[0] ");
2475 fflush(NULL);
2476 if(!fgets(line, sizeof(line)-2, stdin))
2477 exit(1);
2478 if (line[0] == '\n' && drives == 1) {
2479 choice = 0;
2480 done = 1;
2481 } else {
2482 if(sscanf(line, "%d", &choice) != 1) {
2483 warn("choose a disk");
2484 continue;
2485 }
2486 if(choice < 0 || choice >= i) {
2487 warn("out of range");
2488 continue;
2489 }
2490 done = 1;
2491 }
2492 } while(! done);
2493 return devices[choice].dev;
2494}
2495
2496int
2497scribble_region(region_t *reg, struct part_entry **pe, int *made_new)
2498{
2499 int ex, trunc = 0, changed = 0, i;
2500 struct part_entry *newpart;
2501 if(reg->is_used_part && reg->used_part.size > MAX_REGION_SECTORS) {
2502 reg->used_part.size = MAX_REGION_SECTORS;
2503 trunc = 1;
2504 changed = 1;
2505 cylinderalign(reg);
2506 }
2507 if(!reg->is_used_part) {
2508 ex = reg->free_sec_last - reg->free_sec_start + 1;
2509 if(ex > MAX_REGION_SECTORS) {
2510 reg->free_sec_last -= ex - MAX_REGION_SECTORS;
2511 trunc = 1;
2512 changed = 1;
2513 cylinderalign(reg);
2514 }
2515 if(made_new) *made_new = 1;
2516 } else if(made_new) *made_new = 0;
2517#if 0
2518 if(trunc) {
2519 printf("\nWill only use %dMB.\n", MAX_REGION_MB);
2520 }
2521#endif
2522 if(!reg->is_used_part) {
2523 for(i = 1; i <= NR_PARTITIONS; i++)
2524 if(table[i].sysind == NO_PART)
2525 break;
2526 if(i > NR_PARTITIONS) {
2527 /* Bug, should've been caught earlier. */
2528 printf("Couldn't find a free slot. Please try expert mode.\n");
2529 exit(1);
2530 }
2531 newpart = &table[i];
2532 newpart->lowsec = reg->free_sec_start;
2533 newpart->size = reg->free_sec_last - reg->free_sec_start + 1;
2534 changed = 1;
2535 newpart->sysind = MINIX_PART;
2536 } else {
2537 newpart = &reg->used_part;
2538 }
2539 *pe = newpart;
2540 changed = 1;
2541 dirty = 1;
2542 return changed;
2543}
2544
2545int
2546sanitycheck_failed(char *dev, struct part_entry *pe)
2547{
2548 struct partition part;
2549 int fd;
2550 unsigned long it_lowsec, it_secsize;
2551
2552 if((fd = open(dev, O_RDONLY)) < 0) {
2553 perror(dev);
2554 return 1;
2555 }
2556
2557 if (ioctl(fd, DIOCGETP, &part) < 0) {
2558 fprintf(stderr, "DIOCGETP failed\n");
2559 perror(dev);
2560 return 1;
2561 }
2562
2563 if(!open_ct_ok(fd)) {
2564 printf("\nAutopart error: the disk is in use. This means that although a\n"
2565 "new table has been written, it won't be in use by the system\n"
2566 "until it's no longer in use (or a reboot is done). Just in case,\n"
2567 "I'm not going to continue. Please un-use the disk (or reboot) and try\n"
2568 "again.\n\n");
2569 return 1;
2570 }
2571
2572 close(fd);
2573
2574 it_lowsec = div64u(part.base, SECTOR_SIZE);
2575 it_secsize = div64u(part.size, SECTOR_SIZE);
2576
2577 if(it_lowsec != pe->lowsec || it_secsize != pe->size) {
2578 fprintf(stderr, "\nReturned and set numbers don't match up!\n");
2579 fprintf(stderr, "This can happen if the disk is still opened.\n");
2580 return 1;
2581 }
2582
2583 return 0;
2584}
2585
2586int
2587do_autopart(int resultfd)
2588{
2589 int confirmation;
2590 region_t *r;
2591 struct part_entry *pe;
2592 char sure[50];
2593 struct part_entry orig_table[1 + NR_PARTITIONS];
2594 int region, disk, newp;
2595
2596 nordonly = 1;
2597
2598 do {
2599 curdev = select_disk();
2600 } while(!curdev);
2601
2602 if(device >= 0) {
2603 close(device);
2604 device = -1;
2605 }
2606 recompute0();
2607
2608 m_read('r', NULL);
2609
2610 memcpy(orig_table, table, sizeof(table));
2611
2612 do {
2613 /* Show regions. */
2614 r = select_region();
2615 } while(!r); /* Back to step 2. */
2616
2617 /* Write things. */
2618 if(scribble_region(r, &pe, &newp)) {
2619 char *name;
2620 int i, found = -1;
2621 char partbuf[100], devname[100];
2622 struct part_entry *tpe;
2623
2624 printstep(3, "Confirm your choices");
2625
2626 region = (int)(r-regions);
2627 /* disk = (int) (curdev-devices); */
2628
2629 printf("\nThis is the point of no return. You have selected to install MINIX 3\n");
2630 printf("into region %d of disk %s. Please confirm that you want\n",
2631 region, curdev->name);
2632 printf("to use this selection to install MINIX 3.\n\n");
2633
2634 do {
2635 confirmation = is_sure("Are you sure you want to continue?");
2636 if (confirmation == IS_NO) return 1;
2637 } while (confirmation != IS_YES);
2638
2639 /* Retrieve partition number in sorted order that we
2640 * have scribbled in.
2641 */
2642 sort();
2643 for(i = 1; i <= NR_PARTITIONS; i++) {
2644 int si;
2645 si = sort_order[i];
2646 if(si < 1 || si > NR_PARTITIONS) {
2647 fprintf(stderr, "Autopart internal error (out of range) (nothing written).\n");
2648 exit(1);
2649 }
2650 if(table[si].lowsec == pe->lowsec) {
2651 if(found > 0) {
2652 fprintf(stderr, "Autopart internal error (part found twice) (nothing written).\n");
2653 exit(1);
2654 }
2655 check_ind(&table[si]);
2656 table[si].sysind = MINIX_PART;
2657 found = i;
2658 tpe = &table[si];
2659 }
2660 }
2661 if(found < 1) {
2662 fprintf(stderr, "Autopart internal error (part not found) (nothing written).\n");
2663 exit(1);
2664 }
2665 m_write('w', NULL);
2666 if(dirty) {
2667 fprintf(stderr, "Autopart internal error (couldn't update disk).\n");
2668 exit(1);
2669 }
2670 name=strrchr(curdev->name, '/');
2671 if(!name) name = curdev->name;
2672 else name++;
2673
2674 sprintf(partbuf, "%sp%d d%dp%d\n", name, found-1,
2675 curdev->biosdrive, found-1);
2676 sprintf(devname, "/dev/%sp%d", name, found-1);
2677 if(resultfd >= 0 && write(resultfd, partbuf, strlen(partbuf)) < strlen(partbuf)) {
2678 fprintf(stderr, "Autopart internal error (couldn't write result).\n");
2679 exit(1);
2680 }
2681 if(device >= 0) {
2682 close(device);
2683 device = -1;
2684 }
2685
2686#if 0
2687 m_dump(orig_table);
2688 printf("\n");
2689 m_dump(table);
2690#endif
2691
2692 if(sanitycheck_failed(devname, tpe)) {
2693 fprintf(stderr, "Autopart internal error (disk sanity check failed).\n");
2694 exit(1);
2695 }
2696
2697 if(newp) {
2698 int fd;
2699 if((fd=open(devname, O_WRONLY)) < 0) {
2700 perror(devname);
2701 } else {
2702 /* Clear any subpartitioning. */
2703 static unsigned char sub[2048];
2704 sub[510] = 0x55;
2705 sub[511] = 0xAA;
2706 write(fd, sub, sizeof(sub));
2707 close(fd);
2708 }
2709 }
2710 return 0;
2711 }
2712
2713 return 1;
2714}
2715
2716int main(int argc, char **argv)
2717{
2718 object_t *op;
2719 int i, r, key;
2720 struct part_entry *pe;
2721 char *name;
2722 int autopart = 0;
2723 int resultfd = -1;
2724
2725 /* Autopilot mode if invoked as autopart. */
2726 if(!(name = strrchr(argv[0], '/'))) name = argv[0];
2727 else name++;
2728 if(!strcmp(name, "autopart"))
2729 autopart = 1;
2730
2731 if(!autopart) {
2732 /* Define a few objects to show on the screen. First text: */
2733 op= newobject(O_INFO, 0, 0, 2, 19);
2734 op= newobject(O_TEXT, 0, 0, 22, 13); op->text= "----first----";
2735 op= newobject(O_TEXT, 0, 0, 37, 13); op->text= "--geom/last--";
2736 op= newobject(O_TEXT, 0, 0, 52, 18); op->text= "------sectors-----";
2737 op= newobject(O_TEXT, 0, 1, 4, 6); op->text= "Device";
2738 op= newobject(O_TEXT, 0, 1, 23, 12); op->text= "Cyl Head Sec";
2739 op= newobject(O_TEXT, 0, 1, 38, 12); op->text= "Cyl Head Sec";
2740 op= newobject(O_TEXT, 0, 1, 56, 4); op->text= "Base";
2741 op= newobject(O_TEXT, 0, 1, 66, 4); op->text= size_last;
2742 op= newobject(O_TEXT, 0, 1, 78, 2); op->text= "Kb";
2743 op= newobject(O_TEXT, 0, 4, 0, 15); op->text= "Num Sort Type";
2744
2745 /* The device is the current object: */
2746 curobj= newobject(O_DEV, OF_MOD, 2, 4, 15);
2747 op= newobject(O_SUB, 0, 3, 4, 15);
2748
2749 /* Geometry: */
2750 op= newobject(O_CYL, OF_MOD, 2, 40, 5); op->entry= &table[0];
2751 op= newobject(O_HEAD, OF_MOD, 2, 45, 3); op->entry= &table[0];
2752 op= newobject(O_SEC, OF_MOD, 2, 49, 2); op->entry= &table[0];
2753
2754 /* Objects for the device: */
2755 op= newobject(O_SCYL, 0, 3, 25, 5); op->entry= &table[0];
2756 op= newobject(O_SHEAD, 0, 3, 30, 3); op->entry= &table[0];
2757 op= newobject(O_SSEC, 0, 3, 34, 2); op->entry= &table[0];
2758 op= newobject(O_LCYL, 0, 3, 40, 5); op->entry= &table[0];
2759 op= newobject(O_LHEAD, 0, 3, 45, 3); op->entry= &table[0];
2760 op= newobject(O_LSEC, 0, 3, 49, 2); op->entry= &table[0];
2761 op= newobject(O_BASE, 0, 3, 59, 9); op->entry= &table[0];
2762 op= newobject(O_SIZE, 0, 3, 69, 9); op->entry= &table[0];
2763 op= newobject(O_KB, 0, 3, 79, 9); op->entry= &table[0];
2764
2765 /* Objects for each partition: */
2766 for (r= 5, pe= table+1; pe <= table+NR_PARTITIONS; r++, pe++) {
2767 op= newobject(O_NUM, OF_MOD, r, 1, 2); op->entry= pe;
2768 op= newobject(O_SORT, 0, r, 5, 2); op->entry= pe;
2769 op= newobject(O_TYPHEX, OF_MOD, r, 10, 2); op->entry= pe;
2770 op= newobject(O_TYPTXT, OF_MOD, r, 12, 9); op->entry= pe;
2771 op= newobject(O_SCYL, OF_MOD, r, 25, 5); op->entry= pe;
2772 op= newobject(O_SHEAD, OF_MOD, r, 30, 3); op->entry= pe;
2773 op= newobject(O_SSEC, OF_MOD, r, 34, 2); op->entry= pe;
2774 op= newobject(O_LCYL, OF_MOD, r, 40, 5); op->entry= pe;
2775 op= newobject(O_LHEAD, OF_MOD, r, 45, 3); op->entry= pe;
2776 op= newobject(O_LSEC, OF_MOD, r, 49, 2); op->entry= pe;
2777 op= newobject(O_BASE, OF_MOD, r, 59, 9); op->entry= pe;
2778 op= newobject(O_SIZE, OF_MOD, r, 69, 9); op->entry= pe;
2779 op= newobject(O_KB, OF_MOD, r, 79, 9); op->entry= pe;
2780 }
2781 } else {
2782 int c;
2783 /* autopart uses getopt() */
2784 while((c = getopt(argc, argv, "m:f:")) != EOF) {
2785 switch(c) {
2786 case 'm':
2787 min_region_mb = atoi(optarg);
2788 break;
2789 case 'f':
2790 /* Make sure old data file is gone. */
2791 unlink(optarg);
2792 if((resultfd=open(optarg, O_CREAT | O_WRONLY | O_TRUNC)) < 0) {
2793 perror(optarg);
2794 return 1;
2795 }
2796 sync(); /* Make sure no old data file lingers. */
2797 break;
2798 default:
2799 fprintf(stderr, "Unknown option\n");
2800 return 1;
2801 }
2802 }
2803 }
2804 argc -= optind;
2805 argv += optind;
2806
2807 for (i= 0; i < argc; i++) {
2808 newdevice(argv[i], 0, 0);
2809 }
2810
2811 if (firstdev == nil) {
2812 getdevices(autopart);
2813 key= ctrl('L');
2814 } else {
2815 key= 'r';
2816 }
2817
2818 if(autopart) {
2819 int r;
2820 if (firstdev == nil) {
2821 fprintf(stderr, "autopart couldn't find any devices.\n");
2822 return 1;
2823 }
2824 r = do_autopart(resultfd);
2825 if(resultfd >= 0) { close(resultfd); }
2826 return r;
2827 }
2828
2829 if (firstdev != nil) {
2830 init_tty();
2831 clear_screen();
2832 event(key, curobj);
2833 display();
2834 mainloop();
2835 reset_tty();
2836 }
2837 exit(0);
2838}
Note: See TracBrowser for help on using the repository browser.