00001
00002
00003
00004
00005
00006
00007
00008
00009 #define nil 0
00010 #include <sys/types.h>
00011 #include <stdio.h>
00012 #include <termcap.h>
00013 #include <errno.h>
00014 #include <unistd.h>
00015 #include <stddef.h>
00016 #include <ctype.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <signal.h>
00020 #include <fcntl.h>
00021 #include <time.h>
00022 #include <dirent.h>
00023 #include <limits.h>
00024 #include <a.out.h>
00025 #include <sys/stat.h>
00026 #include <sys/wait.h>
00027 #include <sys/ioctl.h>
00028 #include <minix/config.h>
00029 #include <minix/const.h>
00030 #include <minix/partition.h>
00031 #include <minix/u64.h>
00032 #include <ibm/partition.h>
00033 #include <termios.h>
00034 #include <stdarg.h>
00035
00036
00037 static void printstep(int step, char *message);
00038
00039
00040 #define ext_part(s) ((s) == 0x05 || (s) == 0x0F)
00041
00042
00043 static char MASTERBOOT[] = "/usr/mdec/masterboot";
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #define MAXSIZE 999999999L
00058 #define SECTOR_SIZE 512
00059 #define DEV_FD0 0x200
00060 #define DEV_C0D0 0x300
00061
00062 int min_region_mb = 500;
00063
00064 #define MIN_REGION_SECTORS (1024*1024*min_region_mb/SECTOR_SIZE)
00065
00066 #define MAX_REGION_MB 4095
00067 #define MAX_REGION_SECTORS (1024*(1024/SECTOR_SIZE)*MAX_REGION_MB)
00068
00069 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
00070 #define arraylimit(a) ((a) + arraysize(a))
00071
00072 #define SORNOT(n) ((n) == 1 ? "" : "s")
00073
00074
00075 #define COL_RED 1
00076 #define COL_GREEN 2
00077 #define COL_ORANGE 3
00078 #define COL_BLUE 4
00079 #define COL_MAGENTA 5
00080 #define COL_CYAN 6
00081
00082 #define SURE_SERIOUS 1
00083 #define SURE_BACK 2
00084
00085 void col(int col)
00086 {
00087 if(!col) printf("\033[0m");
00088 else printf("\033[3%dm", col % 10);
00089 }
00090
00091 void type2col(int type)
00092 {
00093 switch(type) {
00094
00095 case 0x80:
00096 case MINIX_PART: col(COL_GREEN); break;
00097
00098
00099 case 0x0B: case 0x0C: case 0x0E: case 0x0F: case 0x42:
00100 case 0x07: col(COL_CYAN); break;
00101
00102
00103 case 0x82: case 0x83: col(COL_ORANGE); break;
00104 }
00105 }
00106
00107 int open_ct_ok(int fd)
00108 {
00109 int c = -1;
00110 if(ioctl(fd, DIOCOPENCT, &c) < 0) {
00111 printf("Warning: couldn't verify opencount, continuing\n");
00112 return 1;
00113 }
00114
00115 if(c == 1) return 1;
00116 if(c < 1) { printf("Error: open count %d\n", c); }
00117
00118 return 0;
00119 }
00120
00121 void report(const char *label)
00122 {
00123 fprintf(stderr, "part: %s: %s\n", label, strerror(errno));
00124 }
00125
00126 void fatal(const char *label)
00127 {
00128 report(label);
00129 exit(1);
00130 }
00131
00132 struct termios termios;
00133
00134 void save_ttyflags(void)
00135
00136 {
00137 if (tcgetattr(0, &termios) < 0) fatal("");
00138 }
00139
00140 void restore_ttyflags(void)
00141
00142 {
00143 if (tcsetattr(0, TCSANOW, &termios) < 0) fatal("");
00144 }
00145
00146 void tty_raw(void)
00147
00148 {
00149 struct termios rawterm;
00150
00151 rawterm= termios;
00152 rawterm.c_lflag &= ~(ICANON|ISIG|ECHO);
00153 rawterm.c_iflag &= ~(ICRNL);
00154 if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal("");
00155 }
00156
00157 #define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37'))
00158
00159 char t_cd[16], t_cm[32], t_so[16], t_se[16], t_md[16], t_me[16];
00160 int t_li, t_co;
00161 #define STATUSROW 10
00162
00163 void init_tty(void)
00164
00165 {
00166 char *term;
00167 static char termbuf[1024];
00168 char *tp;
00169
00170 if ((term= getenv("TERM")) == nil || tgetent(termbuf, term) != 1) {
00171 fprintf(stderr, "part: Can't get terminal capabilities\n");
00172 exit(1);
00173 }
00174 if (tgetstr("cd", (tp= t_cd, &tp)) == nil
00175 || tgetstr("cm", (tp= t_cm, &tp)) == nil) {
00176 fprintf(stderr, "part: This terminal is too dumb\n");
00177 exit(1);
00178 }
00179 t_li= tgetnum("li");
00180 t_co= tgetnum("co");
00181 (void) tgetstr("so", (tp= t_so, &tp));
00182 (void) tgetstr("se", (tp= t_se, &tp));
00183 (void) tgetstr("md", (tp= t_md, &tp));
00184 (void) tgetstr("me", (tp= t_me, &tp));
00185
00186 save_ttyflags();
00187 tty_raw();
00188 }
00189
00190 void putchr(int c)
00191 {
00192 putchar(c);
00193 }
00194
00195 void putstr(char *s)
00196 {
00197 int c;
00198
00199 while ((c= *s++) != 0) putchr(c);
00200 }
00201
00202 void set_cursor(int row, int col)
00203 {
00204 tputs(tgoto(t_cm, col, row), 1, putchr);
00205 }
00206
00207 int statusrow= STATUSROW;
00208 int stat_ktl= 1;
00209 int need_help= 1;
00210
00211 void stat_start(int serious)
00212
00213 {
00214 set_cursor(statusrow++, 0);
00215 tputs(t_cd, 1, putchr);
00216 if (serious) tputs(t_so, 1, putchr);
00217 }
00218
00219 void stat_end(int ktl)
00220
00221 {
00222 tputs(t_se, 1, putchr);
00223 stat_ktl= ktl;
00224 need_help= 1;
00225 }
00226
00227 void stat_reset(void)
00228
00229 {
00230 if (stat_ktl > 0 && --stat_ktl == 0) {
00231 statusrow= STATUSROW;
00232 need_help= 1;
00233 }
00234 if (need_help && statusrow < (24-2)) {
00235 if (statusrow > STATUSROW) stat_start(0);
00236 stat_start(0);
00237 putstr(
00238 "Type '+' or '-' to change, 'r' to read, '?' for more help, '!' for advice");
00239 }
00240 statusrow= STATUSROW;
00241 need_help= 0;
00242 }
00243
00244 void clear_screen(void)
00245 {
00246 set_cursor(0, 0);
00247 tputs(t_cd, 1, putchr);
00248 stat_ktl= 1;
00249 stat_reset();
00250 }
00251
00252 void reset_tty(void)
00253
00254 {
00255 restore_ttyflags();
00256 set_cursor(statusrow, 0);
00257 tputs(t_cd, 1, putchr);
00258 }
00259
00260 void *alloc(size_t n)
00261 {
00262 void *m;
00263
00264 if ((m= malloc(n)) == nil) { reset_tty(); fatal(""); }
00265
00266 return m;
00267 }
00268
00269 #ifndef makedev
00270 #define minor(dev) (((dev) >> MINOR) & BYTE)
00271 #define major(dev) (((dev) >> MAJOR) & BYTE)
00272 #define makedev(major, minor) \
00273 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
00274 #endif
00275
00276 typedef enum parttype { DUNNO, SUBPART, PRIMARY, FLOPPY } parttype_t;
00277
00278 typedef struct device {
00279 struct device *next, *prev;
00280 dev_t rdev;
00281 char *name;
00282 char *subname;
00283 parttype_t parttype;
00284 int biosdrive;
00285 } device_t;
00286
00287 typedef struct region {
00288
00289
00290
00291
00292 struct part_entry used_part;
00293 int is_used_part;
00294 int tableno;
00295 int free_sec_start, free_sec_last;
00296 } region_t;
00297
00298
00299
00300
00301 #define NR_REGIONS (2*NR_PARTITIONS+1)
00302 region_t regions[NR_REGIONS];
00303 int nr_partitions = 0, nr_regions = 0, free_regions, used_regions;
00304 int nordonly = 0;
00305
00306 device_t *firstdev= nil, *curdev;
00307
00308 #define MAX_DEVICES 100
00309 static struct {
00310 device_t *dev;
00311 int nr_partitions, free_regions, used_regions, sectors, nr_regions;
00312 int biosdrive;
00313 region_t regions[NR_REGIONS];
00314 } devices[MAX_DEVICES];
00315
00316 void newdevice(char *name, int scanning, int disk_only)
00317
00318
00319
00320 {
00321 device_t *new, *nextdev, *prevdev;
00322 struct stat st;
00323
00324 st.st_rdev= 0;
00325 if (scanning) {
00326 if (stat(name, &st) < 0 || !S_ISBLK(st.st_mode)) return;
00327
00328 switch (major(st.st_rdev)) {
00329 case 3:
00330
00331 if (minor(st.st_rdev) >= 0x80
00332 || minor(st.st_rdev) % 5 != 0) return;
00333 break;
00334 default:
00335 return;
00336 }
00337
00338 } else {
00339 if(stat(name, &st) < 0) { perror(name); return; }
00340 }
00341
00342 new= alloc(sizeof(*new));
00343 new->rdev= st.st_rdev;
00344 new->name= alloc((strlen(name) + 1) * sizeof(new->name[0]));
00345 strcpy(new->name, name);
00346 new->subname= new->name;
00347 new->parttype= DUNNO;
00348 if (major(st.st_rdev) == major(DEV_FD0) && minor(st.st_rdev) < 112) {
00349 new->parttype= FLOPPY;
00350 } else
00351 if (st.st_rdev >= DEV_C0D0 && minor(st.st_rdev) < 128
00352 && minor(st.st_rdev) % 5 == 0) {
00353 new->parttype= PRIMARY;
00354 }
00355
00356 if (firstdev == nil) {
00357 firstdev= new;
00358 new->next= new->prev= new;
00359 curdev= firstdev;
00360 return;
00361 }
00362 nextdev= firstdev;
00363 while (new->rdev >= nextdev->rdev
00364 && (nextdev= nextdev->next) != firstdev) {}
00365 prevdev= nextdev->prev;
00366 new->next= nextdev;
00367 nextdev->prev= new;
00368 new->prev= prevdev;
00369 prevdev->next= new;
00370
00371 if (new->rdev < firstdev->rdev) firstdev= new;
00372 if (new->rdev == DEV_C0D0) curdev= new;
00373 if (curdev->rdev != DEV_C0D0) curdev= firstdev;
00374 }
00375
00376 void getdevices(int disk_only)
00377
00378 {
00379 DIR *d;
00380 struct dirent *e;
00381 char name[5 + NAME_MAX + 1];
00382
00383 if ((d= opendir("/dev")) == nil) fatal("/dev");
00384
00385 while ((e= readdir(d)) != nil) {
00386 strcpy(name, "/dev/");
00387 strcpy(name + 5, e->d_name);
00388 newdevice(name, 1, disk_only);
00389 }
00390 (void) closedir(d);
00391 }
00392
00393
00394 unsigned char bootstrap[] = {
00395 0353,0001,0000,0061,0300,0216,0330,0216,0300,0372,0216,0320,0274,0000,0174,0373,
00396 0275,0276,0007,0211,0346,0126,0277,0000,0006,0271,0000,0001,0374,0363,0245,0352,
00397 0044,0006,0000,0000,0264,0002,0315,0026,0250,0010,0164,0033,0350,0071,0001,0174,
00398 0007,0060,0344,0315,0026,0242,0205,0007,0054,0060,0074,0012,0163,0363,0120,0350,
00399 0046,0001,0205,0007,0130,0353,0012,0240,0002,0006,0204,0300,0165,0003,0351,0147,
00400 0000,0230,0262,0005,0366,0362,0262,0200,0000,0302,0210,0340,0120,0350,0234,0000,
00401 0163,0003,0351,0147,0000,0130,0054,0001,0175,0003,0351,0141,0000,0276,0276,0175,
00402 0211,0357,0271,0040,0000,0363,0245,0200,0301,0004,0211,0356,0215,0174,0020,0070,
00403 0154,0004,0164,0016,0213,0135,0010,0053,0134,0010,0213,0135,0012,0033,0134,0012,
00404 0163,0014,0212,0044,0206,0144,0020,0210,0044,0106,0071,0376,0162,0364,0211,0376,
00405 0201,0376,0356,0007,0162,0326,0342,0322,0211,0356,0264,0020,0366,0344,0001,0306,
00406 0200,0174,0004,0001,0162,0026,0353,0021,0204,0322,0175,0041,0211,0356,0200,0174,
00407 0004,0000,0164,0013,0366,0004,0200,0164,0006,0350,0070,0000,0162,0053,0303,0203,
00408 0306,0020,0201,0376,0376,0007,0162,0346,0350,0215,0000,0211,0007,0376,0302,0204,
00409 0322,0174,0023,0315,0021,0321,0340,0321,0340,0200,0344,0003,0070,0342,0167,0355,
00410 0350,0011,0000,0162,0350,0303,0350,0003,0000,0162,0146,0303,0211,0356,0214,0134,
00411 0010,0214,0134,0012,0277,0003,0000,0122,0006,0127,0264,0010,0315,0023,0137,0007,
00412 0200,0341,0077,0376,0306,0210,0310,0366,0346,0211,0303,0213,0104,0010,0213,0124,
00413 0012,0367,0363,0222,0210,0325,0366,0361,0060,0322,0321,0352,0321,0352,0010,0342,
00414 0210,0321,0376,0301,0132,0210,0306,0273,0000,0174,0270,0001,0002,0315,0023,0163,
00415 0020,0200,0374,0200,0164,0011,0117,0174,0006,0060,0344,0315,0023,0163,0270,0371,
00416 0303,0201,0076,0376,0175,0125,0252,0165,0001,0303,0350,0013,0000,0243,0007,0353,
00417 0005,0350,0004,0000,0227,0007,0353,0376,0136,0255,0126,0211,0306,0254,0204,0300,
00418 0164,0011,0264,0016,0273,0001,0000,0315,0020,0353,0362,0303,0057,0144,0145,0166,
00419 0057,0150,0144,0077,0010,0000,0015,0012,0000,0116,0157,0156,0145,0040,0141,0143,
00420 0164,0151,0166,0145,0015,0012,0000,0122,0145,0141,0144,0040,0145,0162,0162,0157,
00421 0162,0040,0000,0116,0157,0164,0040,0142,0157,0157,0164,0141,0142,0154,0145,0040,
00422 0000,0000,
00423 };
00424
00425 int dirty= 0;
00426 unsigned char bootblock[SECTOR_SIZE];
00427 struct part_entry table[1 + NR_PARTITIONS];
00428 int existing[1 + NR_PARTITIONS];
00429 unsigned long offset= 0, extbase= 0, extsize;
00430 int submerged= 0;
00431 char sort_index[1 + NR_PARTITIONS], sort_order[1 + NR_PARTITIONS];
00432 unsigned cylinders= 1, heads= 1, sectors= 1, secpcyl= 1;
00433 unsigned alt_cyls= 1, alt_heads= 1, alt_secs= 1;
00434 int precise= 0;
00435 int device= -1;
00436
00437 unsigned long sortbase(struct part_entry *pe)
00438 {
00439 return pe->sysind == NO_PART ? -1 : pe->lowsec;
00440 }
00441
00442 void sort(void)
00443
00444 {
00445 int i, j;
00446
00447 for (i= 1; i <= NR_PARTITIONS; i++) sort_order[i]= i;
00448
00449 for (i= 1; i <= NR_PARTITIONS; i++) {
00450 for (j= 1; j <= NR_PARTITIONS-1; j++) {
00451 int sj= sort_order[j], sj1= sort_order[j+1];
00452
00453 if (sortbase(&table[sj]) > sortbase(&table[sj1])) {
00454 sort_order[j]= sj1;
00455 sort_order[j+1]= sj;
00456 }
00457 }
00458 }
00459 for (i= 1; i <= NR_PARTITIONS; i++) sort_index[sort_order[i]]= i;
00460 }
00461
00462 void dos2chs(unsigned char *dos, unsigned *chs)
00463
00464
00465
00466
00467 {
00468 chs[0]= ((dos[1] & 0xC0) << 2) | dos[2];
00469 chs[1]= dos[0];
00470 chs[2]= (dos[1] & 0x3F) - 1;
00471 }
00472
00473 void abs2dos(unsigned char *dos, unsigned long pos)
00474
00475 {
00476 unsigned h, c, s;
00477
00478 c= pos / secpcyl;
00479 h= (pos % secpcyl) / sectors;
00480 s= pos % sectors + 1;
00481
00482 dos[0]= h;
00483 dos[1]= s | ((c >> 2) & 0xC0);
00484 dos[2]= c & 0xFF;
00485 }
00486
00487 void recompute0(void)
00488
00489 {
00490 if (device < 0) {
00491 cylinders= heads= sectors= 1;
00492 memset(table, 0, sizeof(table));
00493 } else
00494 if (!precise && offset == 0) {
00495 table[0].lowsec= 0;
00496 table[0].size= (unsigned long) cylinders * heads * sectors;
00497 }
00498 table[0].sysind= device < 0 ? NO_PART : MINIX_PART;
00499 secpcyl= heads * sectors;
00500 }
00501
00502 void guess_geometry(void)
00503
00504
00505
00506
00507 {
00508 int i, n;
00509 struct part_entry *pe;
00510 unsigned chs[3];
00511 unsigned long sec;
00512 unsigned h, s;
00513 unsigned char HS[256][8];
00514
00515 alt_cyls= alt_heads= alt_secs= 0;
00516
00517
00518
00519
00520 for (h= 1; h <= 255; h++) {
00521 for (s= 0; s < 8; s++) HS[h][s]= 0xFF;
00522 }
00523
00524 for (i= 0; i < 2*NR_PARTITIONS; i++) {
00525 pe= &(table+1)[i >> 1];
00526 if (pe->sysind == NO_PART) continue;
00527
00528
00529 if ((i & 1) == 0) {
00530 dos2chs(&pe->last_head, chs);
00531 sec= pe->lowsec + pe->size - 1;
00532 } else {
00533 dos2chs(&pe->start_head, chs);
00534 sec= pe->lowsec;
00535 }
00536
00537 if (chs[0] >= alt_cyls) alt_cyls= chs[0]+1;
00538
00539
00540 for (h= 1; h <= 255; h++) {
00541 if (HS[h][0] == 0) continue;
00542 n = 0;
00543 for (s= 1; s <= 63; s++) {
00544 if ((chs[0] * h + chs[1]) * s + chs[2] != sec) {
00545 HS[h][s/8] &= ~(1 << (s%8));
00546 }
00547 if (HS[h][s/8] & (1 << (s%8))) n++;
00548 }
00549 if (n == 0) HS[h][0]= 0;
00550 }
00551 }
00552
00553
00554 i= 0;
00555 for (h= 1; h <= 255; h++) {
00556 if (HS[h][0] == 0) continue;
00557 for (s= 1; s <= 63; s++) {
00558 if (HS[h][s/8] & (1 << (s%8))) {
00559 i++;
00560 alt_heads= h;
00561 alt_secs= s;
00562 }
00563 }
00564 }
00565
00566
00567 if (i > 1) alt_cyls= alt_heads= alt_secs= 0;
00568 }
00569
00570 void geometry(void)
00571
00572
00573
00574
00575
00576
00577 {
00578 struct stat dst;
00579 int err= 0;
00580 struct partition geometry;
00581
00582 if (submerged) {
00583
00584 sort();
00585 return;
00586 }
00587 precise= 0;
00588 cylinders= 0;
00589 recompute0();
00590 if (device < 0) return;
00591
00592
00593 guess_geometry();
00594
00595
00596 (void) fstat(device, &dst);
00597
00598 if (S_ISBLK(dst.st_mode) || S_ISCHR(dst.st_mode)) {
00599
00600
00601 if (ioctl(device, DIOCGETP, &geometry) < 0)
00602 err= errno;
00603 else {
00604 table[0].lowsec= div64u(geometry.base, SECTOR_SIZE);
00605 table[0].size= div64u(geometry.size, SECTOR_SIZE);
00606 cylinders= geometry.cylinders;
00607 heads= geometry.heads;
00608 sectors= geometry.sectors;
00609 precise= 1;
00610 }
00611 } else {
00612 err= ENODEV;
00613 }
00614
00615 if (err != 0) {
00616
00617
00618
00619 if (alt_heads == 0) {
00620 alt_cyls= table[0].size / (64 * 32);
00621 alt_heads= 64;
00622 alt_secs= 32;
00623 }
00624
00625 cylinders= alt_cyls;
00626 heads= alt_heads;
00627 sectors= alt_secs;
00628
00629 stat_start(1);
00630 printf("Failure to get the geometry of %s: %s", curdev->name,
00631 errno == ENOTTY ? "No driver support" : strerror(err));
00632 stat_end(5);
00633 stat_start(0);
00634 printf("The geometry has been guessed as %ux%ux%u",
00635 cylinders, heads, sectors);
00636 stat_end(5);
00637 } else {
00638 if (alt_heads == 0) {
00639 alt_cyls= cylinders;
00640 alt_heads= heads;
00641 alt_secs= sectors;
00642 }
00643
00644 if (heads != alt_heads || sectors != alt_secs) {
00645 printf(
00646 "The %ux%ux%u geometry obtained from the driver\n"
00647 "does not match the %ux%ux%u geometry implied by the partition\n"
00648 "table. Please use expert mode instead.\n");
00649 exit(1);
00650 }
00651 }
00652
00653
00654
00655
00656 if (precise && ioctl(device, DIOCGETP, &geometry) >= 0) {
00657 table[0].lowsec= div64u(geometry.base, SECTOR_SIZE);
00658 table[0].size= div64u(geometry.size, SECTOR_SIZE);
00659 } else {
00660 precise= 0;
00661 }
00662 recompute0();
00663 sort();
00664 }
00665
00666 typedef struct indicators {
00667 unsigned char ind;
00668 char name[10];
00669 } indicators_t;
00670
00671 indicators_t ind_table[]= {
00672 { 0x00, "None" },
00673 { 0x01, "FAT-12" },
00674 { 0x02, "XENIX /" },
00675 { 0x03, "XENIX usr" },
00676 { 0x04, "FAT-16" },
00677 { 0x05, "EXTENDED" },
00678 { 0x06, "FAT-16" },
00679 { 0x07, "HPFS/NTFS" },
00680 { 0x08, "AIX" },
00681 { 0x09, "COHERENT" },
00682 { 0x0A, "OS/2" },
00683 { 0x0B, "FAT-32" },
00684 { 0x0C, "FAT?" },
00685 { 0x0E, "FAT?" },
00686 { 0x0F, "EXTENDED" },
00687 { 0x10, "OPUS" },
00688 { 0x40, "VENIX286" },
00689 { 0x42, "W2000 Dyn" },
00690 { 0x52, "MICROPORT" },
00691 { 0x63, "386/IX" },
00692 { 0x64, "NOVELL286" },
00693 { 0x65, "NOVELL386" },
00694 { 0x75, "PC/IX" },
00695 { 0x80, "MINIX-OLD" },
00696 { 0x81, "MINIX" },
00697 { 0x82, "LINUXswap" },
00698 { 0x83, "LINUX" },
00699 { 0x93, "AMOEBA" },
00700 { 0x94, "AMOEBAbad" },
00701 { 0xA5, "386BSD" },
00702 { 0xB7, "BSDI" },
00703 { 0xB8, "BSDI swap" },
00704 { 0xC7, "SYRINX" },
00705 { 0xDB, "CPM" },
00706 { 0xFF, "BADBLOCKS" },
00707 };
00708
00709 char *typ2txt(int ind)
00710
00711 {
00712 indicators_t *pind;
00713
00714 for (pind= ind_table; pind < arraylimit(ind_table); pind++) {
00715 if (pind->ind == ind) return pind->name;
00716 }
00717 return "unknown system";
00718 }
00719
00720 int round_sysind(int ind, int delta)
00721
00722 {
00723 indicators_t *pind;
00724
00725 ind= (ind + delta) & 0xFF;
00726
00727 if (delta < 0) {
00728 for (pind= arraylimit(ind_table)-1; pind->ind > ind; pind--) {}
00729 } else {
00730 for (pind= ind_table; pind->ind < ind; pind++) {}
00731 }
00732 return pind->ind;
00733 }
00734
00735
00736
00737
00738 typedef enum objtype {
00739 O_INFO, O_TEXT, O_DEV, O_SUB,
00740 O_TYPTXT, O_SORT, O_NUM, O_TYPHEX,
00741 O_CYL, O_HEAD, O_SEC,
00742 O_SCYL, O_SHEAD, O_SSEC, O_LCYL, O_LHEAD, O_LSEC, O_BASE, O_SIZE, O_KB
00743 } objtype_t;
00744
00745 #define rjust(type) ((type) >= O_TYPHEX)
00746 #define computed(type) ((type) >= O_TYPTXT)
00747
00748 typedef struct object {
00749 struct object *next;
00750 objtype_t type;
00751 char flags;
00752 char row;
00753 char col;
00754 char len;
00755 struct part_entry *entry;
00756 char *text;
00757 char value[20];
00758 } object_t;
00759
00760 #define OF_MOD 0x01
00761 #define OF_ODD 0x02
00762 #define OF_BAD 0x04
00763
00764
00765 #define E_ENTER (-1)
00766 #define E_LEAVE (-2)
00767 #define E_WRITE (-3)
00768
00769
00770 enum howend { SIZE, LAST } howend= SIZE;
00771
00772 object_t *world= nil;
00773 object_t *curobj= nil;
00774
00775 object_t *newobject(objtype_t type, int flags, int row, int col, int len)
00776
00777 {
00778 object_t *new;
00779 object_t **aop= &world;
00780
00781 new= alloc(sizeof(*new));
00782
00783 new->type= type;
00784 new->flags= flags;
00785 new->row= row;
00786 new->col= col;
00787 new->len= len;
00788 new->entry= nil;
00789 new->text= "";
00790 new->value[0]= 0;
00791
00792 new->next= *aop;
00793 *aop= new;
00794
00795 return new;
00796 }
00797
00798 unsigned long entry2base(struct part_entry *pe)
00799
00800 {
00801 return pe->sysind == NO_PART ? 0 : pe->lowsec;
00802 }
00803
00804 unsigned long entry2last(struct part_entry *pe)
00805 {
00806 return pe->sysind == NO_PART ? -1 : pe->lowsec + pe->size - 1;
00807 }
00808
00809 unsigned long entry2size(struct part_entry *pe)
00810 {
00811 return pe->sysind == NO_PART ? 0 : pe->size;
00812 }
00813
00814 int overlap(unsigned long sec)
00815
00816 {
00817 struct part_entry *pe;
00818
00819 for (pe= table + 1; pe <= table + NR_PARTITIONS; pe++) {
00820 if (pe->sysind == NO_PART) continue;
00821
00822 if (pe->lowsec < sec && sec < pe->lowsec + pe->size)
00823 return 1;
00824 }
00825 return 0;
00826 }
00827
00828 int aligned(unsigned long sec, unsigned unit)
00829
00830 {
00831 return (offset != 0 && extbase == 0) || (sec % unit == 0);
00832 }
00833
00834 void print(object_t *op)
00835
00836 {
00837 struct part_entry *pe= op->entry;
00838 int n;
00839 unsigned long t;
00840 char *name;
00841 int oldflags;
00842 char oldvalue[20];
00843
00844
00845 oldflags= op->flags;
00846 strcpy(oldvalue, op->value);
00847
00848 op->flags&= ~(OF_ODD | OF_BAD);
00849
00850 switch (op->type) {
00851 case O_INFO: {
00852
00853 static struct field { int type; char *name; } fields[]= {
00854 { O_DEV, "Select device" },
00855 { O_NUM, "Active flag" },
00856 { O_TYPHEX, "Hex partition type" },
00857 { O_TYPTXT, "Partition type" },
00858 { O_SCYL, "Start cylinder" },
00859 { O_SHEAD, "Start head" },
00860 { O_SSEC, "Start sector" },
00861 { O_CYL, "Number of cylinders" },
00862 { O_HEAD, "Number of heads" },
00863 { O_SEC, "Sectors per track" },
00864 { O_LCYL, "Last cylinder" },
00865 { O_LHEAD, "Last head" },
00866 { O_LSEC, "Last sector" },
00867 { O_BASE, "Base sector" },
00868 { O_SIZE, "Size in sectors" },
00869 { O_KB, "Size in kilobytes" },
00870 { -1, "?" },
00871 };
00872 struct field *fp= fields;
00873
00874 while (fp->type >= 0 && fp->type != curobj->type) fp++;
00875 strcpy(op->value, fp->name);
00876 op->flags|= OF_ODD;
00877 break; }
00878 case O_TEXT:
00879
00880 strcpy(op->value, op->text);
00881 break;
00882 case O_DEV:
00883 case O_SUB:
00884
00885 name= op->type == O_DEV ? curdev->name :
00886 offset == 0 ? "" : curdev->subname;
00887 if ((n= strlen(name)) < op->len) n= op->len;
00888 strcpy(op->value, name + (n - op->len));
00889 if (device < 0 && op->type == O_DEV) op->flags|= OF_BAD;
00890 break;
00891 case O_NUM:
00892
00893 sprintf(op->value, "%d%c", (int) (pe - table - 1),
00894 pe->bootind & ACTIVE_FLAG ? '*' : ' ');
00895 break;
00896 case O_SORT:
00897
00898 sprintf(op->value, "%s%d",
00899 curdev->parttype >= PRIMARY ? "p" :
00900 curdev->parttype == SUBPART ? "s" : "",
00901 (curdev->parttype == SUBPART ||
00902 curdev->parttype == FLOPPY ? pe - table
00903 : sort_index[pe - table]) - 1);
00904 break;
00905 case O_TYPHEX:
00906
00907 sprintf(op->value, "%02X", pe->sysind);
00908 break;
00909 case O_TYPTXT:
00910
00911 strcpy(op->value, typ2txt(pe->sysind));
00912 break;
00913 case O_SCYL:
00914
00915 sprintf(op->value, "%lu", entry2base(pe) / secpcyl);
00916 break;
00917 case O_SHEAD:
00918
00919 t= entry2base(pe);
00920 sprintf(op->value, "%lu", t % secpcyl / sectors);
00921 if (!aligned(t, secpcyl) && t != table[0].lowsec + sectors)
00922 op->flags|= OF_ODD;
00923 break;
00924 case O_SSEC:
00925
00926 t= entry2base(pe);
00927 sprintf(op->value, "%lu", t % sectors);
00928 if (!aligned(t, sectors)) op->flags|= OF_ODD;
00929 break;
00930 case O_CYL:
00931
00932 sprintf(op->value, "%u", cylinders);
00933 break;
00934 case O_HEAD:
00935
00936 sprintf(op->value, "%u", heads);
00937 break;
00938 case O_SEC:
00939
00940 sprintf(op->value, "%u", sectors);
00941 break;
00942 case O_LCYL:
00943
00944 t= entry2last(pe);
00945 sprintf(op->value, "%lu", t == -1 ? 0 : t / secpcyl);
00946 break;
00947 case O_LHEAD:
00948
00949 t= entry2last(pe);
00950 sprintf(op->value, "%lu", t == -1 ? 0 : t % secpcyl / sectors);
00951 if (!aligned(t + 1, secpcyl)) op->flags|= OF_ODD;
00952 break;
00953 case O_LSEC:
00954
00955 t= entry2last(pe);
00956 sprintf(op->value, t == -1 ? "-1" : "%lu", t % sectors);
00957 if (!aligned(t + 1, sectors)) op->flags|= OF_ODD;
00958 break;
00959 case O_BASE:
00960
00961 sprintf(op->value, "%lu", entry2base(pe));
00962 if (pe->sysind != NO_PART && pe != &table[0]
00963 && (pe->lowsec <= table[0].lowsec || overlap(pe->lowsec)))
00964 op->flags|= OF_BAD;
00965 break;
00966 case O_SIZE:
00967
00968 t= howend == SIZE ? entry2size(pe) : entry2last(pe);
00969 sprintf(op->value, "%lu", pe->sysind == NO_PART ? 0 : t);
00970 if (pe->sysind != NO_PART && (pe->size == 0
00971 || pe->lowsec + pe->size > table[0].lowsec + table[0].size
00972 || overlap(pe->lowsec + pe->size)))
00973 op->flags|= OF_BAD;
00974 break;
00975 case O_KB:
00976
00977 sprintf(op->value, "%lu", entry2size(pe) / 2);
00978 break;
00979 default:
00980 sprintf(op->value, "?? %d ??", op->type);
00981 }
00982
00983 if (device < 0 && computed(op->type)) strcpy(op->value, "?");
00984
00985
00986
00987
00988 if ((n= strlen(op->value)) > op->len) {
00989 n= 0;
00990 op->flags|= OF_BAD;
00991 }
00992
00993
00994 if (rjust(op->type)) {
00995 memmove(op->value + (op->len - n), op->value, n);
00996 memset(op->value, ' ', op->len - n);
00997 } else {
00998 memset(op->value + n, ' ', op->len - n);
00999 }
01000 op->value[op->len]= 0;
01001
01002 if ((op->flags & (OF_ODD | OF_BAD)) == (oldflags & (OF_ODD | OF_BAD))
01003 && strcmp(op->value, oldvalue) == 0) {
01004
01005 return;
01006 }
01007
01008 set_cursor(op->row, rjust(op->type) ? op->col - (op->len-1) : op->col);
01009
01010 if (op->flags & OF_BAD) tputs(t_so, 1, putchr);
01011 else
01012 if (op->flags & OF_ODD) tputs(t_md, 1, putchr);
01013 putstr(op->value);
01014 if (op->flags & OF_BAD) tputs(t_se, 1, putchr);
01015 else
01016 if (op->flags & OF_ODD) tputs(t_me, 1, putchr);
01017 }
01018
01019 void display(void)
01020
01021 {
01022 object_t *op;
01023
01024 for (op= world; op != nil; op= op->next) print(op);
01025 }
01026
01027 int typing;
01028 int magic;
01029
01030 void event(int ev, object_t *op);
01031
01032 void m_redraw(int ev, object_t *op)
01033
01034 {
01035 object_t *op2;
01036
01037 if (ev != ctrl('L')) return;
01038
01039 clear_screen();
01040 for (op2= world; op2 != nil; op2= op2->next) op2->value[0]= 0;
01041 }
01042
01043 void m_toggle(int ev, object_t *op)
01044
01045 {
01046 unsigned t;
01047
01048 if (ev != 'X') return;
01049 if (alt_cyls == cylinders && alt_heads == heads && alt_secs == sectors)
01050 return;
01051
01052 t= cylinders; cylinders= alt_cyls; alt_cyls= t;
01053 t= heads; heads= alt_heads; alt_heads= t;
01054 t= sectors; sectors= alt_secs; alt_secs= t;
01055 dirty= 1;
01056 recompute0();
01057 }
01058
01059 char size_last[]= "Size";
01060
01061 void m_orientation(int ev, object_t *op)
01062 {
01063 if (ev != ' ') return;
01064
01065 switch (howend) {
01066 case SIZE:
01067 howend= LAST;
01068 strcpy(size_last, "Last");
01069 break;
01070 case LAST:
01071 howend= SIZE;
01072 strcpy(size_last, "Size");
01073 }
01074 }
01075
01076 void m_move(int ev, object_t *op)
01077
01078
01079
01080 {
01081 object_t *near, *op2;
01082 unsigned dist, d2, dr, dc;
01083
01084 if (ev != 'h' && ev != 'j' && ev != 'k' && ev != 'l' && ev != 'H')
01085 return;
01086
01087 if (device < 0) {
01088
01089 event('r', op);
01090 if (device < 0) return;
01091 }
01092
01093 near= op;
01094 dist= -1;
01095
01096 for (op2= world; op2 != nil; op2= op2->next) {
01097 if (op2 == op || !(op2->flags & OF_MOD)) continue;
01098
01099 dr= abs(op2->row - op->row);
01100 dc= abs(op2->col - op->col);
01101
01102 d2= 25*dr*dr + dc*dc;
01103 if (op2->row != op->row && op2->col != op->col) d2+= 1000;
01104
01105 switch (ev) {
01106 case 'h':
01107 if (op2->col >= op->col) d2= -1;
01108 break;
01109 case 'j':
01110 if (op2->row <= op->row) d2= -1;
01111 break;
01112 case 'k':
01113 if (op2->row >= op->row) d2= -1;
01114 break;
01115 case 'l':
01116 if (op2->col <= op->col) d2= -1;
01117 break;
01118 case 'H':
01119 if (op2->type == O_DEV) d2= 0;
01120 }
01121 if (d2 < dist) { near= op2; dist= d2; }
01122 }
01123 if (near != op) event(E_LEAVE, op);
01124 event(E_ENTER, near);
01125 }
01126
01127 void m_updown(int ev, object_t *op)
01128
01129 {
01130 int i, j;
01131 struct part_entry tmp;
01132 int tmpx;
01133
01134 if (ev != ctrl('K') && ev != ctrl('J')) return;
01135 if (op->entry == nil) return;
01136
01137 i= op->entry - table;
01138 if (ev == ctrl('K')) {
01139 if (i <= 1) return;
01140 j= i-1;
01141 } else {
01142 if (i >= NR_PARTITIONS) return;
01143 j= i+1;
01144 }
01145
01146 tmp= table[i]; table[i]= table[j]; table[j]= tmp;
01147 tmpx= existing[i]; existing[i]= existing[j]; existing[j]= tmpx;
01148 sort();
01149 dirty= 1;
01150 event(ev == ctrl('K') ? 'k' : 'j', op);
01151 }
01152
01153 void m_enter(int ev, object_t *op)
01154
01155 {
01156 if (ev != E_ENTER && ev != ' ' && ev != '<' && ev != '>' && ev != 'X')
01157 return;
01158 curobj= op;
01159 typing= 0;
01160 magic= 0;
01161 }
01162
01163 void m_leave(int ev, object_t *op)
01164
01165 {
01166 if (ev != E_LEAVE) return;
01167 }
01168
01169 int within(unsigned *var, unsigned low, unsigned value, unsigned high)
01170
01171 {
01172 if (low <= value && value <= high) {
01173 *var= value;
01174 return 1;
01175 } else
01176 return 0;
01177 }
01178
01179 int lwithin(unsigned long *var, unsigned long low, unsigned long value,
01180 unsigned long high)
01181 {
01182 if (low <= value && value <= high) {
01183 *var= value;
01184 return 1;
01185 } else
01186 return 0;
01187 }
01188
01189 int nextdevice(object_t *op, int delta)
01190
01191 {
01192 dev_t rdev;
01193
01194 if (offset != 0) return 0;
01195 if (dirty) event(E_WRITE, op);
01196 if (dirty) return 0;
01197
01198 if (device >= 0) {
01199 (void) close(device);
01200 device= -1;
01201 }
01202 recompute0();
01203
01204 rdev= curdev->rdev;
01205 if (delta < 0) {
01206 do
01207 curdev= curdev->prev;
01208 while (delta < -1 && major(curdev->rdev) == major(rdev)
01209 && curdev->rdev < rdev);
01210 } else {
01211 do
01212 curdev= curdev->next;
01213 while (delta > 1 && major(curdev->rdev) == major(rdev)
01214 && curdev->rdev > rdev);
01215 }
01216 return 1;
01217 }
01218
01219 void check_ind(struct part_entry *pe)
01220
01221 {
01222 struct part_entry *pe2;
01223 int i = 0;
01224
01225 for (pe2= table + 1; pe2 < table + 1 + NR_PARTITIONS; pe2++, i++)
01226 if (pe2->sysind != NO_PART && (pe2->bootind & ACTIVE_FLAG))
01227 return;
01228
01229 pe->bootind= ACTIVE_FLAG;
01230 dirty = 1;
01231 }
01232
01233 int check_existing(struct part_entry *pe)
01234
01235 {
01236 static int expert= 0;
01237 int c;
01238
01239 if (expert || pe == nil || !existing[pe - table]) return 1;
01240
01241 stat_start(1);
01242 putstr("Do you wish to modify existing partitions? (y/n) ");
01243 fflush(stdout);
01244 while ((c= getchar()) != 'y' && c != 'n') {}
01245 putchr(c);
01246 stat_end(3);
01247 return (expert= (c == 'y'));
01248 }
01249
01250 void m_modify(int ev, object_t *op)
01251
01252
01253
01254 {
01255 object_t *op2;
01256 struct part_entry *pe= op->entry;
01257 int mul, delta;
01258 unsigned level= 1;
01259 unsigned long surplus;
01260 int radix= op->type == O_TYPHEX ? 0x10 : 10;
01261 unsigned long t;
01262
01263 if (device < 0 && op->type != O_DEV) return;
01264
01265 switch (ev) {
01266 case '-':
01267 mul= radix; delta= -1; typing= 0;
01268 break;
01269 case '+':
01270 mul= radix; delta= 1; typing= 0;
01271 break;
01272 case '\b':
01273 if (!typing) return;
01274 mul= 1; delta= 0;
01275 break;
01276 case '\r':
01277 typing= 0;
01278 return;
01279 default:
01280 if ('0' <= ev && ev <= '9')
01281 delta= ev - '0';
01282 else
01283 if (radix == 0x10 && 'a' <= ev && ev <= 'f')
01284 delta= ev - 'a' + 10;
01285 else
01286 if (radix == 0x10 && 'A' <= ev && ev <= 'F')
01287 delta= ev - 'A' + 10;
01288 else
01289 return;
01290
01291 mul= typing ? radix*radix : 0;
01292 typing= 1;
01293 }
01294 magic= 0;
01295
01296 if (!check_existing(pe)) return;
01297
01298 switch (op->type) {
01299 case O_DEV:
01300 if (ev != '-' && ev != '+') return;
01301 if (!nextdevice(op, delta)) return;
01302 break;
01303 case O_CYL:
01304 if (!within(&cylinders, 1,
01305 cylinders * mul / radix + delta, 1024)) return;
01306 recompute0();
01307 break;
01308 case O_HEAD:
01309 if (!within(&heads, 1, heads * mul / radix + delta, 255))
01310 return;
01311 recompute0();
01312 break;
01313 case O_SEC:
01314 if (!within(§ors, 1, sectors * mul / radix + delta, 63))
01315 return;
01316 recompute0();
01317 break;
01318 case O_NUM:
01319 if (ev != '-' && ev != '+') return;
01320 for (op2= world; op2 != nil; op2= op2->next) {
01321 if (op2->type == O_NUM && ev == '+')
01322 op2->entry->bootind= 0;
01323 }
01324 op->entry->bootind= ev == '+' ? ACTIVE_FLAG : 0;
01325 break;
01326 case O_TYPHEX:
01327 check_ind(pe);
01328 pe->sysind= pe->sysind * mul / radix + delta;
01329 break;
01330 case O_TYPTXT:
01331 if (ev != '-' && ev != '+') return;
01332 check_ind(pe);
01333 pe->sysind= round_sysind(pe->sysind, delta);
01334 break;
01335 case O_SCYL:
01336 level= heads;
01337 case O_SHEAD:
01338 level*= sectors;
01339 case O_SSEC:
01340 if (op->type != O_SCYL && ev != '-' && ev != '+') return;
01341 case O_BASE:
01342 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe));
01343 t= pe->lowsec;
01344 surplus= t % level;
01345 if (!lwithin(&t, 0L,
01346 (t / level * mul / radix + delta) * level + surplus,
01347 MAXSIZE)) return;
01348 if (howend == LAST || op->type != O_BASE)
01349 pe->size-= t - pe->lowsec;
01350 pe->lowsec= t;
01351 check_ind(pe);
01352 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
01353 break;
01354 case O_LCYL:
01355 level= heads;
01356 case O_LHEAD:
01357 level*= sectors;
01358 case O_LSEC:
01359 if (op->type != O_LCYL && ev != '-' && ev != '+') return;
01360
01361 if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe));
01362 t= pe->lowsec + pe->size - 1 + level;
01363 surplus= t % level - mul / radix * level;
01364 if (!lwithin(&t, 0L,
01365 (t / level * mul / radix + delta) * level + surplus,
01366 MAXSIZE)) return;
01367 pe->size= t - pe->lowsec + 1;
01368 check_ind(pe);
01369 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
01370 break;
01371 case O_KB:
01372 level= 2;
01373 if (mul == 0) pe->size= 0;
01374 case O_SIZE:
01375 if (pe->sysind == NO_PART) {
01376 if (op->type == O_KB || howend == SIZE) {
01377
01378 event('m', op);
01379 magic= 0;
01380 pe->size= 0;
01381 event(ev, op);
01382 return;
01383 }
01384 memset(pe, 0, sizeof(*pe));
01385 }
01386 t= (op->type == O_KB || howend == SIZE) ? pe->size
01387 : pe->lowsec + pe->size - 1;
01388 surplus= t % level;
01389 if (!lwithin(&t, 0L,
01390 (t / level * mul / radix + delta) * level + surplus,
01391 MAXSIZE)) return;
01392 pe->size= (op->type == O_KB || howend == SIZE) ? t :
01393 t - pe->lowsec + 1;
01394 check_ind(pe);
01395 if (pe->sysind == NO_PART) pe->sysind= MINIX_PART;
01396 break;
01397 default:
01398 return;
01399 }
01400
01401
01402 sort();
01403 dirty= 1;
01404 }
01405
01406 unsigned long spell[3 + 4 * (1+NR_PARTITIONS)];
01407 int nspells;
01408 objtype_t touching;
01409
01410 void newspell(unsigned long charm)
01411
01412 {
01413 int i, j;
01414
01415 if (charm - table[0].lowsec > table[0].size) return;
01416
01417 for (i= 0; i < nspells; i++) {
01418 if (charm == spell[i]) return;
01419
01420 if (touching == O_BASE) {
01421 if (charm == table[0].lowsec + table[0].size) return;
01422 if ((spell[0] - charm) < (spell[0] - spell[i])) break;
01423 } else {
01424 if (charm == table[0].lowsec) return;
01425 if ((charm - spell[0]) < (spell[i] - spell[0])) break;
01426 }
01427 }
01428 for (j= ++nspells; j > i; j--) spell[j]= spell[j-1];
01429 spell[i]= charm;
01430 }
01431
01432 void m_magic(int ev, object_t *op)
01433
01434 {
01435 struct part_entry *pe= op->entry, *pe2;
01436 int rough= (offset != 0 && extbase == 0);
01437
01438 if (ev != 'm' || device < 0) return;
01439 typing= 0;
01440
01441 if (!check_existing(pe)) return;
01442
01443 if (magic == 0) {
01444
01445 nspells= 1;
01446
01447
01448 switch (op->type) {
01449 case O_SCYL:
01450 case O_SHEAD:
01451 case O_SSEC:
01452 case O_BASE:
01453 touching= O_BASE;
01454 spell[0]= pe->lowsec;
01455 break;
01456 case O_LCYL:
01457 case O_LHEAD:
01458 case O_LSEC:
01459 case O_KB:
01460 case O_SIZE:
01461 touching= O_SIZE;
01462 spell[0]= pe->lowsec + pe->size;
01463 break;
01464 default:
01465 return;
01466 }
01467 if (pe->sysind == NO_PART) {
01468 memset(pe, 0, sizeof(*pe));
01469 check_ind(pe);
01470 pe->sysind= MINIX_PART;
01471 spell[0]= 0;
01472 if (touching == O_SIZE) {
01473
01474 object_t *op2;
01475
01476 for (op2= world; op2 != nil; op2= op2->next) {
01477 if (op2->row == op->row &&
01478 op2->type == O_BASE) {
01479 event('m', op2);
01480 }
01481 }
01482 magic= 0;
01483 event('m', op);
01484 return;
01485 }
01486 }
01487
01488 if (spell[0] == table[0].lowsec) newspell(spell[0] + 1);
01489
01490
01491
01492
01493 for (pe2= table; pe2 < table + 1 + NR_PARTITIONS; pe2++) {
01494 if (pe2 == pe || pe2->sysind == NO_PART) continue;
01495 if (pe2->lowsec == table[0].lowsec)
01496 newspell(table[0].lowsec + 1);
01497 else
01498 newspell(pe2->lowsec);
01499 newspell(pe2->lowsec + pe2->size);
01500 if (touching == O_BASE && howend == SIZE) {
01501 newspell(pe2->lowsec - pe->size);
01502 newspell(pe2->lowsec + pe2->size - pe->size);
01503 }
01504 if (pe2->lowsec % sectors != 0) rough= 1;
01505 }
01506
01507
01508
01509
01510
01511 if (!rough) {
01512 unsigned long n= spell[0];
01513 if (n == table[0].lowsec) n++;
01514 n= (n + sectors - 1) / sectors * sectors;
01515 if (n != table[0].lowsec + sectors)
01516 n= (n + secpcyl - 1) / secpcyl * secpcyl;
01517 newspell(n);
01518 if (touching == O_SIZE)
01519 newspell(table[0].size / secpcyl * secpcyl);
01520 }
01521 }
01522
01523
01524 if (++magic == nspells) magic= 0;
01525
01526 if (touching == O_BASE) {
01527 if (howend == LAST) pe->size-= spell[magic] - pe->lowsec;
01528 pe->lowsec= spell[magic];
01529 } else
01530 pe->size= spell[magic] - pe->lowsec;
01531
01532
01533 sort();
01534 dirty= 1;
01535 }
01536
01537 typedef struct diving {
01538 struct diving *up;
01539 struct part_entry old0;
01540 char *oldsubname;
01541 parttype_t oldparttype;
01542 unsigned long oldoffset;
01543 unsigned long oldextbase;
01544 } diving_t;
01545
01546 diving_t *diving= nil;
01547
01548 void m_in(int ev, object_t *op)
01549
01550 {
01551 diving_t *newdiv;
01552 struct part_entry *pe= op->entry, ext;
01553 int n;
01554
01555 if (ev != '>' || device < 0 || pe == nil || pe == &table[0]
01556 || (!(pe->sysind == MINIX_PART && offset == 0)
01557 && !ext_part(pe->sysind))
01558 || pe->size == 0) return;
01559
01560 ext= *pe;
01561 if (extbase != 0) ext.size= extbase + extsize - ext.lowsec;
01562
01563 if (dirty) event(E_WRITE, op);
01564 if (dirty) return;
01565 if (device >= 0) { close(device); device= -1; }
01566
01567 newdiv= alloc(sizeof(*newdiv));
01568 newdiv->old0= table[0];
01569 newdiv->oldsubname= curdev->subname;
01570 newdiv->oldparttype= curdev->parttype;
01571 newdiv->oldoffset= offset;
01572 newdiv->oldextbase= extbase;
01573 newdiv->up= diving;
01574 diving= newdiv;
01575
01576 table[0]= ext;
01577
01578 n= strlen(diving->oldsubname);
01579 curdev->subname= alloc((n + 3) * sizeof(curdev->subname[0]));
01580 strcpy(curdev->subname, diving->oldsubname);
01581 curdev->subname[n++]= ':';
01582 curdev->subname[n++]= '0' + (pe - table - 1);
01583 curdev->subname[n]= 0;
01584
01585 curdev->parttype= curdev->parttype == PRIMARY ? SUBPART : DUNNO;
01586 offset= ext.lowsec;
01587 if (ext_part(ext.sysind) && extbase == 0) {
01588 extbase= ext.lowsec;
01589 extsize= ext.size;
01590 curdev->parttype= DUNNO;
01591 }
01592
01593 submerged= 1;
01594 event('r', op);
01595 }
01596
01597 void m_out(int ev, object_t *op)
01598
01599 {
01600 diving_t *olddiv;
01601
01602 if (ev != '<' || diving == nil) return;
01603
01604 if (dirty) event(E_WRITE, op);
01605 if (dirty) return;
01606 if (device >= 0) { close(device); device= -1; }
01607
01608 olddiv= diving;
01609 diving= olddiv->up;
01610
01611 table[0]= olddiv->old0;
01612
01613 free(curdev->subname);
01614 curdev->subname= olddiv->oldsubname;
01615
01616 curdev->parttype= olddiv->oldparttype;
01617 offset= olddiv->oldoffset;
01618 extbase= olddiv->oldextbase;
01619
01620 free(olddiv);
01621
01622 event('r', op);
01623 if (diving == nil) submerged= 0;
01624 }
01625
01626 void installboot(unsigned char *bootblock, char *masterboot)
01627
01628 {
01629 FILE *mfp;
01630 struct exec hdr;
01631 int n;
01632 char *err;
01633
01634 if ((mfp= fopen(masterboot, "r")) == nil) {
01635 err= strerror(errno);
01636 goto m_err;
01637 }
01638
01639 n= fread(&hdr, sizeof(char), A_MINHDR, mfp);
01640 if (ferror(mfp)) {
01641 err= strerror(errno);
01642 fclose(mfp);
01643 goto m_err;
01644 }
01645
01646 if (n < A_MINHDR || BADMAG(hdr) || hdr.a_cpu != A_I8086) {
01647 err= "Not an 8086 executable";
01648 fclose(mfp);
01649 goto m_err;
01650 }
01651
01652 if (hdr.a_text + hdr.a_data > PART_TABLE_OFF) {
01653 err= "Does not fit in a boot sector";
01654 fclose(mfp);
01655 goto m_err;
01656 }
01657
01658 fseek(mfp, hdr.a_hdrlen, 0);
01659 fread(bootblock, sizeof(char), (size_t) (hdr.a_text + hdr.a_data), mfp);
01660 if (ferror(mfp)) {
01661 err= strerror(errno);
01662 fclose(mfp);
01663 goto m_err;
01664 }
01665 fclose(mfp);
01666
01667
01668 return;
01669
01670 m_err:
01671 stat_start(1);
01672 printf("%s: %s", masterboot, err);
01673 stat_end(5);
01674 }
01675
01676 ssize_t boot_readwrite(int rw)
01677
01678 {
01679 u64_t off64 = mul64u(offset, SECTOR_SIZE);
01680 int r;
01681
01682 #if __minix_vmd
01683
01684 if (fcntl(device, F_SEEK, off64) < 0) return -1;
01685 #else
01686
01687 struct partition geom0, geom_seek;
01688
01689 if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) {
01690
01691 if (ioctl(device, DIOCGETP, &geom0) < 0) return -1;
01692 geom_seek.base = add64(geom0.base, off64);
01693 geom_seek.size = cvu64(cmp64(add64u(off64, SECTOR_SIZE),
01694 geom0.size) <= 0 ? _STATIC_BLOCK_SIZE : 0);
01695 sync();
01696 if (ioctl(device, DIOCSETP, &geom_seek) < 0) return -1;
01697 if (lseek(device, (off_t) 0, SEEK_SET) == -1) return -1;
01698 } else {
01699
01700 if (lseek(device, (off_t) offset * SECTOR_SIZE, SEEK_SET) == -1)
01701 return -1;
01702 }
01703 #endif
01704
01705 switch (rw) {
01706 case 0: r= read(device, bootblock, SECTOR_SIZE); break;
01707 case 1: r= write(device, bootblock, SECTOR_SIZE); break;
01708 }
01709
01710 #if !__minix_vmd
01711 if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) {
01712
01713 sync();
01714 if (ioctl(device, DIOCSETP, &geom0) < 0) return -1;
01715 }
01716 #endif
01717 return r;
01718 }
01719
01720 int cylinderalign(region_t *reg)
01721 {
01722 if(reg->is_used_part) {
01723 if(reg->used_part.lowsec != table[0].lowsec + sectors
01724 && (reg->used_part.lowsec % secpcyl)) {
01725 int extra;
01726 extra = secpcyl - (reg->used_part.lowsec % secpcyl);
01727 reg->used_part.lowsec += extra;
01728 reg->used_part.size -= extra;
01729 }
01730 if((reg->used_part.size+1) % secpcyl) {
01731 reg->used_part.size -= secpcyl - ((reg->used_part.size + 1) % secpcyl);
01732 }
01733 return reg->used_part.size > 0;
01734 }
01735
01736 if(reg->free_sec_start != table[0].lowsec + sectors && (reg->free_sec_start % secpcyl)) {
01737
01738 reg->free_sec_start += secpcyl - (reg->free_sec_start % secpcyl);
01739 }
01740 if((reg->free_sec_last+1) % secpcyl) {
01741
01742 reg->free_sec_last -= (reg->free_sec_last+1) % secpcyl;
01743 }
01744
01745
01746 return reg->free_sec_last > reg->free_sec_start;
01747 }
01748
01749 void regionize(void)
01750 {
01751 int free_sec, i, si;
01752
01753 sort();
01754
01755 free_sec = table[0].lowsec + sectors;
01756
01757
01758 free_regions = used_regions = nr_regions = nr_partitions = 0;
01759 if(table[0].lowsec > table[sort_order[1]].lowsec &&
01760 table[sort_order[1]].sysind != NO_PART) {
01761 printf("\nSanity check failed on %s - first partition starts before disk.\n"
01762 "Please use expert mode to correct it.\n", curdev->name);
01763 exit(1);
01764 }
01765 for(si = 1; si <= NR_PARTITIONS; si++) {
01766 i = sort_order[si];
01767 if(i < 1 || i > NR_PARTITIONS) {
01768 printf("Sorry, something unexpected has happened (%d out of range).\n", i);
01769 exit(1);
01770 }
01771
01772 if(table[i].sysind == NO_PART)
01773 break;
01774
01775
01776 if(table[i].lowsec > free_sec) {
01777
01778 regions[nr_regions].free_sec_start = free_sec;
01779 regions[nr_regions].free_sec_last = table[i].lowsec-1;
01780 regions[nr_regions].is_used_part = 0;
01781 if(cylinderalign(®ions[nr_regions])) {
01782 nr_regions++;
01783 free_regions++;
01784 }
01785 }
01786
01787
01788 if(si > 1) {
01789 if(table[i].lowsec < table[sort_order[si-1]].lowsec ||
01790 table[i].lowsec < table[sort_order[si-1]].lowsec + table[sort_order[si-1]].size) {
01791 printf("\nSanity check failed on %s - partitions overlap.\n"
01792 "Please use expert mode to correct it.\n", curdev->name);
01793 exit(1);
01794 }
01795 }
01796 if(table[i].size > table[0].size) {
01797 printf("\nSanity check failed on %s - partition is larger than disk.\n"
01798 "Please use expert mode to correct it.\n", curdev->name);
01799 exit(1);
01800 }
01801 if(table[i].size < 1) {
01802 printf("\nSanity check failed on %s - zero-sized partition.\n"
01803 "Please use expert mode to correct it.\n", curdev->name);
01804 exit(1);
01805 }
01806
01807
01808 memcpy(®ions[nr_regions].used_part, &table[i], sizeof(table[i]));
01809 free_sec = table[i].lowsec+table[i].size;
01810 regions[nr_regions].is_used_part = 1;
01811 regions[nr_regions].tableno = i;
01812 nr_partitions++;
01813 nr_regions++;
01814 used_regions++;
01815 }
01816
01817
01818 if(free_sec < table[0].lowsec + table[0].size-1) {
01819 regions[nr_regions].free_sec_start = free_sec;
01820 regions[nr_regions].free_sec_last = table[0].lowsec + table[0].size-1;
01821 regions[nr_regions].is_used_part = 0;
01822 if(cylinderalign(®ions[nr_regions])) {
01823 nr_regions++;
01824 free_regions++;
01825 }
01826 }
01827
01828 }
01829
01830 void m_read(int ev, int *biosdrive)
01831
01832 {
01833 int si, i, mode, n, r, v;
01834 struct part_entry *pe;
01835
01836 if (ev != 'r' || device >= 0) return;
01837
01838
01839 stat_start(0);
01840 fflush(stdout);
01841
01842 if ((device= open(curdev->name, mode= O_RDWR, 0666)) < 0) {
01843 if (device >= 0) { close(device); device= -1; }
01844 return;
01845 }
01846
01847 v = 2*HZ;
01848 ioctl(device, DIOCTIMEOUT, &v);
01849
01850 memset(bootblock, 0, sizeof(bootblock));
01851
01852 n= boot_readwrite(0);
01853
01854 if (n <= 0) stat_start(1);
01855 if (n < 0) {
01856 close(device);
01857 device= -1;
01858 } else
01859 if (n < SECTOR_SIZE) {
01860 close(device);
01861 device= -1;
01862 return;
01863 }
01864 if (n <= 0) stat_end(5);
01865
01866 if (n < SECTOR_SIZE) n= SECTOR_SIZE;
01867
01868 if(biosdrive) (*biosdrive)++;
01869
01870 if(!open_ct_ok(device)) {
01871 printf("\n%s: device in use! skipping it.", curdev->subname);
01872 fflush(stdout);
01873 close(device);
01874 device= -1;
01875 return;
01876 }
01877
01878 memcpy(table+1, bootblock+PART_TABLE_OFF,
01879 NR_PARTITIONS * sizeof(table[1]));
01880 if (bootblock[510] != 0x55 || bootblock[511] != 0xAA) {
01881
01882
01883 memset(bootblock, 0, sizeof(bootblock));
01884 installboot(bootblock, MASTERBOOT);
01885 memset(table+1, 0, NR_PARTITIONS * sizeof(table[1]));
01886 }
01887
01888
01889
01890
01891 for (i= 1; i <= NR_PARTITIONS; i++) {
01892 pe= &table[i];
01893 if (extbase != 0 && pe->sysind != NO_PART)
01894 pe->lowsec+= ext_part(pe->sysind) ? extbase : offset;
01895 existing[i]= pe->sysind != NO_PART;
01896 }
01897 geometry();
01898 dirty= 0;
01899
01900
01901 if (extbase != 0) {
01902 stat_start(1);
01903 printf("Warning: You are in an extended partition.");
01904 stat_end(5);
01905 }
01906
01907 regionize();
01908 }
01909
01910 void m_write(int ev, object_t *op)
01911
01912 {
01913 int c;
01914 struct part_entry new_table[NR_PARTITIONS], *pe;
01915
01916 if (ev != 'w' && ev != E_WRITE) return;
01917 if (device < 0) { dirty= 0; return; }
01918 if (!dirty) {
01919 if (ev == 'w') {
01920 stat_start(1);
01921 printf("%s is not changed, or has already been written",
01922 curdev->subname);
01923 stat_end(2);
01924 }
01925 return;
01926 }
01927
01928 if (extbase != 0) {
01929
01930 stat_start(1);
01931 printf("You have changed an extended partition. Bad Idea.");
01932 stat_end(5);
01933 }
01934
01935 memcpy(new_table, table+1, NR_PARTITIONS * sizeof(table[1]));
01936 for (pe= new_table; pe < new_table + NR_PARTITIONS; pe++) {
01937 if (pe->sysind == NO_PART) {
01938 memset(pe, 0, sizeof(*pe));
01939 } else {
01940 abs2dos(&pe->start_head, pe->lowsec);
01941 abs2dos(&pe->last_head, pe->lowsec + pe->size - 1);
01942
01943
01944 if (extbase != 0)
01945 pe->lowsec-= ext_part(pe->sysind)
01946 ? extbase : offset;
01947 }
01948 }
01949 memcpy(bootblock+PART_TABLE_OFF, new_table, sizeof(new_table));
01950 bootblock[510]= 0x55;
01951 bootblock[511]= 0xAA;
01952
01953 if (boot_readwrite(1) < 0) {
01954 stat_start(1);
01955 printf("%s: %s", curdev->name, strerror(errno));
01956 stat_end(5);
01957 return;
01958 }
01959 dirty= 0;
01960 }
01961
01962 void m_shell(int ev, object_t *op)
01963
01964 {
01965 int r, pid, status;
01966 void (*sigint)(int), (*sigquit)(int), (*sigterm)(int);
01967
01968 if (ev != 's') return;
01969
01970 reset_tty();
01971 fflush(stdout);
01972
01973 switch (pid= fork()) {
01974 case -1:
01975 stat_start(1);
01976 printf("can't fork: %s\n", strerror(errno));
01977 stat_end(3);
01978 break;
01979 case 0:
01980 if (device >= 0) (void) close(device);
01981 execl("/bin/sh", "sh", (char *) nil);
01982 r= errno;
01983 stat_start(1);
01984 printf("/bin/sh: %s\n", strerror(errno));
01985 stat_end(3);
01986 exit(127);
01987 }
01988 sigint= signal(SIGINT, SIG_IGN);
01989 sigquit= signal(SIGQUIT, SIG_IGN);
01990 sigterm= signal(SIGTERM, SIG_IGN);
01991 while (pid >= 0 && (r= wait(&status)) >= 0 && r != pid) {}
01992 (void) signal(SIGINT, sigint);
01993 (void) signal(SIGQUIT, sigquit);
01994 (void) signal(SIGTERM, sigterm);
01995 tty_raw();
01996 if (pid < 0)
01997 ;
01998 else
01999 if (WIFEXITED(status) && WEXITSTATUS(status) == 127)
02000 stat_start(0);
02001 else
02002 event(ctrl('L'), op);
02003 }
02004
02005 void m_dump(struct part_entry *print_table)
02006
02007 {
02008 struct part_entry *pe;
02009 int i;
02010 unsigned chs[3];
02011
02012 printf(" Partition + type Cyl Head Sec Cyl Head Sec Base Size Kb\n");
02013 for (i= 1; i <= NR_PARTITIONS; i++) {
02014 pe= &print_table[i];
02015 dos2chs(&pe->start_head, chs);
02016 printf("%2d%c %02X%15d%5d%4d",
02017 i,
02018 pe->bootind & ACTIVE_FLAG ? '*' : ' ',
02019 pe->sysind,
02020 chs[0], chs[1], chs[2]);
02021 dos2chs(&pe->last_head, chs);
02022 printf("%6d%5d%4d%10lu%10ld%9lu\n",
02023 chs[0], chs[1], chs[2],
02024 pe->lowsec,
02025 howend == SIZE ? pe->size : pe->size + pe->lowsec - 1,
02026 pe->size / 2);
02027 }
02028 }
02029
02030 int quitting= 0;
02031
02032 void m_quit(int ev, object_t *op)
02033
02034 {
02035 if (ev != 'q' && ev != 'x') return;
02036
02037 quitting= 1;
02038
02039 if (dirty) event(E_WRITE, op);
02040 if (dirty) quitting= 0;
02041 }
02042
02043 void m_help(int ev, object_t *op)
02044
02045 {
02046 static struct help {
02047 char *keys;
02048 char *what;
02049 } help[]= {
02050 { "? !", "This help / more advice!" },
02051 { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" },
02052 { "0-9 (a-f)", "Enter value" },
02053 { "hjkl (arrow keys)", "Move around" },
02054 { "CTRL-K CTRL-J", "Move entry up/down" },
02055 { "CTRL-L", "Redraw screen" },
02056 { ">", "Start a subpartition table" },
02057 { "<", "Back to the primary partition table" },
02058 { "m", "Cycle through magic values" },
02059 { "spacebar", "Show \"Size\" or \"Last\"" },
02060 { "r w", "Read/write partition table" },
02061 { "p s q x", "Raw dump / Shell escape / Quit / Exit" },
02062 { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" },
02063 };
02064 static char *advice[] = {
02065 "* Choose a disk with '+' and '-', then hit 'r'.",
02066 "* To change any value: Move to it and use '+', '-' or type the desired value.",
02067 "* To make a new partition: Move over to the Size or Kb field of an unused",
02068 " partition and type the size. Hit the 'm' key to pad the partition out to",
02069 " a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.",
02070 " You can hit 'm' more than once on a base or size field to see several",
02071 " interesting values go by. Note: Other Operating Systems can be picky about",
02072 " partitions that are not padded to cylinder boundaries. Look for highlighted",
02073 " head or sector numbers.",
02074 "* To reuse a partition: Change the type to MINIX.",
02075 "* To delete a partition: Type a zero in the hex Type field.",
02076 "* To make a partition active: Type '+' in the Num field.",
02077 "* To study the list of keys: Type '?'.",
02078 };
02079
02080 if (ev == '?') {
02081 struct help *hp;
02082
02083 for (hp= help; hp < arraylimit(help); hp++) {
02084 stat_start(0);
02085 printf("%-25s - %s", hp->keys, hp->what);
02086 stat_end(0);
02087 }
02088 stat_start(0);
02089 putstr("Things like ");
02090 putstr(t_so); putstr("this"); putstr(t_se);
02091 putstr(" must be checked, but ");
02092 putstr(t_md); putstr("this"); putstr(t_me);
02093 putstr(" is not really a problem");
02094 stat_end(0);
02095 } else
02096 if (ev == '!') {
02097 char **ap;
02098
02099 for (ap= advice; ap < arraylimit(advice); ap++) {
02100 stat_start(0);
02101 putstr(*ap);
02102 stat_end(0);
02103 }
02104 }
02105 }
02106
02107 void event(int ev, object_t *op)
02108
02109 {
02110 m_help(ev, op);
02111 m_redraw(ev, op);
02112 m_toggle(ev, op);
02113 m_orientation(ev, op);
02114 m_move(ev, op);
02115 m_updown(ev, op);
02116 m_enter(ev, op);
02117 m_leave(ev, op);
02118 m_modify(ev, op);
02119 m_magic(ev, op);
02120 m_in(ev, op);
02121 m_out(ev, op);
02122 m_read(ev, NULL);
02123 m_write(ev, op);
02124 m_shell(ev, op);
02125 m_quit(ev, op);
02126 }
02127
02128 int keypress(void)
02129
02130
02131
02132 {
02133 char ch;
02134 int c;
02135 int esc= 0;
02136
02137 set_cursor(curobj->row, curobj->col);
02138 fflush(stdout);
02139
02140 do {
02141 if (read(0, &ch, sizeof(ch)) < 0) fatal("stdin");
02142 c= (unsigned char) ch;
02143 switch (esc) {
02144 case 0:
02145 switch (c) {
02146 case ctrl('['): esc= 1; break;
02147 case '_': c= '-'; break;
02148 case '=': c= '+'; break;
02149 }
02150 break;
02151 case 1:
02152 esc= c == '[' ? 2 : 0;
02153 break;
02154 case 2:
02155 switch (c) {
02156 case 'D': c= 'h'; break;
02157 case 'B': c= 'j'; break;
02158 case 'A': c= 'k'; break;
02159 case 'C': c= 'l'; break;
02160 case 'H': c= 'H'; break;
02161 case 'U':
02162 case 'S': c= '-'; break;
02163 case 'V':
02164 case 'T': c= '+'; break;
02165 }
02166
02167 default:
02168 esc= 0;
02169 }
02170 } while (esc > 0);
02171
02172 switch (c) {
02173 case ctrl('B'): c= 'h'; break;
02174 case ctrl('N'): c= 'j'; break;
02175 case ctrl('P'): c= 'k'; break;
02176 case ctrl('F'): c= 'l'; break;
02177 }
02178
02179 return c;
02180 }
02181
02182 void mainloop(void)
02183
02184 {
02185 int key;
02186
02187 while (!quitting) {
02188 stat_reset();
02189
02190 key= keypress();
02191
02192 event(key, curobj);
02193
02194 display();
02195 }
02196 }
02197
02198 char *
02199 prettysizeprint(int kb)
02200 {
02201 int toosmall = 0;
02202 static char str[200];
02203 char unit = 'k';
02204 if(MIN_REGION_SECTORS > kb*2)
02205 toosmall = 1;
02206 if(kb >= 5*1024) {
02207 kb /= 1024;
02208 unit = 'M';
02209 if(kb >= 5*1024) {
02210 kb /= 1024;
02211 unit = 'G';
02212 }
02213 }
02214 sprintf(str, "%4d %cB%s", kb, unit,
02215 toosmall ? ", too small for MINIX 3" : "");
02216 return str;
02217 }
02218
02219 void
02220 printregions(region_t *theregions, int indent, int p_nr_partitions, int p_free_regions, int p_nr_regions, int numbers)
02221 {
02222 int r, nofree = 0;
02223 region_t *reg;
02224 reg = theregions;
02225
02226 if((p_nr_partitions >= NR_PARTITIONS || !p_free_regions) && p_free_regions)
02227 nofree = 1;
02228 for(r = 0; r < p_nr_regions; r++, reg++) {
02229 unsigned long units;
02230 if(reg->is_used_part) {
02231 char *name;
02232 name = typ2txt(reg->used_part.sysind);
02233 printf("%*s", indent, ""); type2col(reg->used_part.sysind);
02234 if(numbers) printf("[%d] ", r);
02235 printf("In use by %-10s ", name);
02236 units = reg->used_part.size / 2;
02237 col(0);
02238 printf(" (%s)\n", prettysizeprint(units));
02239 } else {
02240 printf("%*s", indent, "");
02241 if(numbers) {
02242 if(!nofree) printf("[%d] ", r);
02243 else printf("[-] ");
02244 }
02245 printf("Free space ");
02246 units = ((reg->free_sec_last - reg->free_sec_start+1))/2;
02247 printf(" (%s)\n", prettysizeprint(units));
02248 }
02249 }
02250
02251 if(numbers && p_nr_partitions >= NR_PARTITIONS && p_free_regions) {
02252 printf(
02253 "\nNote: there is free space on this disk, but you can't select it,\n"
02254 "because there isn't a free slot in the partition table to use it.\n"
02255 "You can reclaim the free space by deleting an adjacent region.\n");
02256 }
02257
02258 return;
02259 }
02260
02261 #define IS_YES 3
02262 #define IS_NO 4
02263 #define IS_OTHER 5
02264 int
02265 is_sure(char *fmt, ...)
02266 {
02267 char yesno[10];
02268 va_list ap;
02269 va_start (ap, fmt);
02270 vprintf(fmt, ap);
02271 va_end(ap);
02272 printf(" Please enter 'yes' or 'no': ");
02273 fflush(stdout);
02274 if(!fgets(yesno, sizeof(yesno)-1, stdin)) exit(1);
02275
02276 if (strcmp(yesno, "yes\n") == 0) return(IS_YES);
02277 if (strcmp(yesno, "no\n") == 0) return(IS_NO);
02278 return IS_OTHER;
02279 }
02280
02281 void warn(char *message)
02282 {
02283 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);
02284 }
02285
02286 int
02287 may_kill_region(void)
02288 {
02289 int confirmation;
02290 char line[100];
02291 int r, i;
02292
02293 if(used_regions < 1) return 1;
02294
02295 printf("\n -- Delete in-use region? --\n\n");
02296
02297 printregions(regions, 3, nr_partitions, free_regions, nr_regions, 1);
02298 printf("\nEnter the region number to delete or ENTER to continue: ");
02299 fflush(NULL);
02300 fgets(line, sizeof(line)-2, stdin);
02301 if(!isdigit(line[0]))
02302 return 1;
02303
02304 r=atoi(line);
02305 if(r < 0 || r >= nr_regions) {
02306 printf("This choice is out of range.\n");
02307 return 0;
02308 }
02309
02310 if(!regions[r].is_used_part) {
02311 printf("This region is not in use.\n");
02312 return 0;
02313 }
02314
02315 i = regions[r].tableno;
02316
02317 printf("\nPlease confirm that you want to delete region %d, losing all data it", r);
02318 printf("\ncontains. You're disk is not actually updated right away, but still.");
02319 printf("\n\n");
02320
02321 do {
02322 confirmation = is_sure("Are you sure you want to continue?");
02323 if (confirmation == IS_NO) return 0;
02324 } while (confirmation != IS_YES);
02325
02326 table[i].sysind = NO_PART;
02327 dirty = 1;
02328 regionize();
02329
02330
02331 return 0;
02332 }
02333
02334
02335 region_t *
02336 select_region(void)
02337 {
02338 int r, rem, rn, done = 0;
02339 static char line[100];
02340 region_t *reg;
02341 int nofree = 0;
02342
02343 printstep(2, "Select a disk region");
02344
02345 if(nr_regions < 1) {
02346 printf("\nNo regions found - maybe the drive is too small.\n"
02347 "Please try expert mode.\n");
02348 exit(1);
02349 }
02350
02351 if(nr_partitions >= NR_PARTITIONS || !free_regions) {
02352 if(free_regions) {
02353 nofree = 1;
02354 }
02355 }
02356
02357
02358 printf("\nPlease select the region that you want to use for the MINIX 3 setup.");
02359 printf("\nIf you select an in-use region it will be overwritten by MINIX. The");
02360 printf("\nfollowing region%s were found on the selected disk:\n\n",
02361 SORNOT(nr_regions));
02362 printregions(regions, 3, nr_partitions, free_regions, nr_regions, 1);
02363
02364
02365 printf("\n");
02366 do {
02367 printf("Enter the region number to use or type 'delete': ");
02368 if(nr_regions == 1) printf(" [0] ");
02369 fflush(NULL);
02370
02371 if(!fgets(line, sizeof(line)-2, stdin))
02372 exit(1);
02373
02374 if (nr_regions == 1 && line[0] == '\n') {
02375 rn = 0;
02376 done = 1;
02377 }
02378 else {
02379 if(strcmp(line,"delete\n") == 0) {
02380 may_kill_region();
02381 return NULL;
02382 }
02383
02384 if(sscanf(line, "%d", &rn) != 1) {
02385 warn("invalid choice");
02386 continue;
02387 }
02388
02389 if(rn < 0 || rn >= nr_regions) {
02390 warn("out of range");
02391 continue;
02392 }
02393
02394 if(nofree && !regions[rn].is_used_part) {
02395 warn("not available");
02396 continue;
02397 }
02398
02399 done = 1;
02400 }
02401 } while(! done);
02402
02403 return(®ions[rn]);
02404 }
02405
02406 static void printstep(int step, char *str)
02407 {
02408 int n;
02409 n = printf("\n --- Substep 4.%d: %s ---", step, str);
02410 while(n++ < 73) printf("-");
02411 printf("\n");
02412 }
02413
02414 device_t *
02415 select_disk(void)
02416 {
02417 int done = 0;
02418 int i, choice, drives;
02419 static char line[500];
02420 int biosdrive = 0;
02421
02422 printstep(1, "Select a disk to install MINIX 3");
02423 printf("\nProbing for disks. This may take a short while.");
02424
02425 i = 0;
02426 curdev=firstdev;
02427
02428 for(; i < MAX_DEVICES;) {
02429 printf(".");
02430 fflush(stdout);
02431 m_read('r', &biosdrive);
02432 if(device >= 0) {
02433 devices[i].dev = curdev;
02434 devices[i].free_regions = free_regions;
02435 devices[i].nr_regions = nr_regions;
02436 devices[i].nr_partitions = nr_partitions;
02437 devices[i].used_regions = used_regions;
02438 devices[i].sectors = table[0].size;
02439 curdev->biosdrive = biosdrive-1;
02440 memcpy(devices[i].regions, regions, sizeof(regions));
02441 i++;
02442 }
02443
02444 nextdevice(NULL, 1);
02445 if(curdev == firstdev)
02446 break;
02447 }
02448
02449 drives = i;
02450
02451 if(drives < 1) {
02452 printf("\nFound no drives - can't partition.\n");
02453 exit(1);
02454 }
02455
02456 printf(" Probing done.\n");
02457 printf("The following disk%s %s found on your system:\n\n", SORNOT(drives),
02458 drives == 1 ? "was" : "were");
02459
02460 for(i = 0; i < drives; i++) {
02461 printf(" ");
02462 printf("Disk [%d]: ", i);
02463 printf("%s, ", devices[i].dev->name);
02464 printf("%s\n", prettysizeprint(devices[i].sectors/2));
02465 printregions(devices[i].regions, 8,
02466 devices[i].nr_partitions,
02467 devices[i].free_regions,
02468 devices[i].nr_regions, 0);
02469 }
02470
02471 printf("\n");
02472 do {
02473 printf("Enter the disk number to use: ");
02474 if (drives == 1) printf("[0] ");
02475 fflush(NULL);
02476 if(!fgets(line, sizeof(line)-2, stdin))
02477 exit(1);
02478 if (line[0] == '\n' && drives == 1) {
02479 choice = 0;
02480 done = 1;
02481 } else {
02482 if(sscanf(line, "%d", &choice) != 1) {
02483 warn("choose a disk");
02484 continue;
02485 }
02486 if(choice < 0 || choice >= i) {
02487 warn("out of range");
02488 continue;
02489 }
02490 done = 1;
02491 }
02492 } while(! done);
02493 return devices[choice].dev;
02494 }
02495
02496 int
02497 scribble_region(region_t *reg, struct part_entry **pe, int *made_new)
02498 {
02499 int ex, trunc = 0, changed = 0, i;
02500 struct part_entry *newpart;
02501 if(reg->is_used_part && reg->used_part.size > MAX_REGION_SECTORS) {
02502 reg->used_part.size = MAX_REGION_SECTORS;
02503 trunc = 1;
02504 changed = 1;
02505 cylinderalign(reg);
02506 }
02507 if(!reg->is_used_part) {
02508 ex = reg->free_sec_last - reg->free_sec_start + 1;
02509 if(ex > MAX_REGION_SECTORS) {
02510 reg->free_sec_last -= ex - MAX_REGION_SECTORS;
02511 trunc = 1;
02512 changed = 1;
02513 cylinderalign(reg);
02514 }
02515 if(made_new) *made_new = 1;
02516 } else if(made_new) *made_new = 0;
02517 #if 0
02518 if(trunc) {
02519 printf("\nWill only use %dMB.\n", MAX_REGION_MB);
02520 }
02521 #endif
02522 if(!reg->is_used_part) {
02523 for(i = 1; i <= NR_PARTITIONS; i++)
02524 if(table[i].sysind == NO_PART)
02525 break;
02526 if(i > NR_PARTITIONS) {
02527
02528 printf("Couldn't find a free slot. Please try expert mode.\n");
02529 exit(1);
02530 }
02531 newpart = &table[i];
02532 newpart->lowsec = reg->free_sec_start;
02533 newpart->size = reg->free_sec_last - reg->free_sec_start + 1;
02534 changed = 1;
02535 newpart->sysind = MINIX_PART;
02536 } else {
02537 newpart = ®->used_part;
02538 }
02539 *pe = newpart;
02540 changed = 1;
02541 dirty = 1;
02542 return changed;
02543 }
02544
02545 int
02546 sanitycheck_failed(char *dev, struct part_entry *pe)
02547 {
02548 struct partition part;
02549 int fd;
02550 unsigned long it_lowsec, it_secsize;
02551
02552 if((fd = open(dev, O_RDONLY)) < 0) {
02553 perror(dev);
02554 return 1;
02555 }
02556
02557 if (ioctl(fd, DIOCGETP, &part) < 0) {
02558 fprintf(stderr, "DIOCGETP failed\n");
02559 perror(dev);
02560 return 1;
02561 }
02562
02563 if(!open_ct_ok(fd)) {
02564 printf("\nAutopart error: the disk is in use. This means that although a\n"
02565 "new table has been written, it won't be in use by the system\n"
02566 "until it's no longer in use (or a reboot is done). Just in case,\n"
02567 "I'm not going to continue. Please un-use the disk (or reboot) and try\n"
02568 "again.\n\n");
02569 return 1;
02570 }
02571
02572 close(fd);
02573
02574 it_lowsec = div64u(part.base, SECTOR_SIZE);
02575 it_secsize = div64u(part.size, SECTOR_SIZE);
02576
02577 if(it_lowsec != pe->lowsec || it_secsize != pe->size) {
02578 fprintf(stderr, "\nReturned and set numbers don't match up!\n");
02579 fprintf(stderr, "This can happen if the disk is still opened.\n");
02580 return 1;
02581 }
02582
02583 return 0;
02584 }
02585
02586 int
02587 do_autopart(int resultfd)
02588 {
02589 int confirmation;
02590 region_t *r;
02591 struct part_entry *pe;
02592 char sure[50];
02593 struct part_entry orig_table[1 + NR_PARTITIONS];
02594 int region, disk, newp;
02595
02596 nordonly = 1;
02597
02598 do {
02599 curdev = select_disk();
02600 } while(!curdev);
02601
02602 if(device >= 0) {
02603 close(device);
02604 device = -1;
02605 }
02606 recompute0();
02607
02608 m_read('r', NULL);
02609
02610 memcpy(orig_table, table, sizeof(table));
02611
02612 do {
02613
02614 r = select_region();
02615 } while(!r);
02616
02617
02618 if(scribble_region(r, &pe, &newp)) {
02619 char *name;
02620 int i, found = -1;
02621 char partbuf[100], devname[100];
02622 struct part_entry *tpe;
02623
02624 printstep(3, "Confirm your choices");
02625
02626 region = (int)(r-regions);
02627
02628
02629 printf("\nThis is the point of no return. You have selected to install MINIX 3\n");
02630 printf("into region %d of disk %s. Please confirm that you want\n",
02631 region, curdev->name);
02632 printf("to use this selection to install MINIX 3.\n\n");
02633
02634 do {
02635 confirmation = is_sure("Are you sure you want to continue?");
02636 if (confirmation == IS_NO) return 1;
02637 } while (confirmation != IS_YES);
02638
02639
02640
02641
02642 sort();
02643 for(i = 1; i <= NR_PARTITIONS; i++) {
02644 int si;
02645 si = sort_order[i];
02646 if(si < 1 || si > NR_PARTITIONS) {
02647 fprintf(stderr, "Autopart internal error (out of range) (nothing written).\n");
02648 exit(1);
02649 }
02650 if(table[si].lowsec == pe->lowsec) {
02651 if(found > 0) {
02652 fprintf(stderr, "Autopart internal error (part found twice) (nothing written).\n");
02653 exit(1);
02654 }
02655 check_ind(&table[si]);
02656 table[si].sysind = MINIX_PART;
02657 found = i;
02658 tpe = &table[si];
02659 }
02660 }
02661 if(found < 1) {
02662 fprintf(stderr, "Autopart internal error (part not found) (nothing written).\n");
02663 exit(1);
02664 }
02665 m_write('w', NULL);
02666 if(dirty) {
02667 fprintf(stderr, "Autopart internal error (couldn't update disk).\n");
02668 exit(1);
02669 }
02670 name=strrchr(curdev->name, '/');
02671 if(!name) name = curdev->name;
02672 else name++;
02673
02674 sprintf(partbuf, "%sp%d d%dp%d\n", name, found-1,
02675 curdev->biosdrive, found-1);
02676 sprintf(devname, "/dev/%sp%d", name, found-1);
02677 if(resultfd >= 0 && write(resultfd, partbuf, strlen(partbuf)) < strlen(partbuf)) {
02678 fprintf(stderr, "Autopart internal error (couldn't write result).\n");
02679 exit(1);
02680 }
02681 if(device >= 0) {
02682 close(device);
02683 device = -1;
02684 }
02685
02686 #if 0
02687 m_dump(orig_table);
02688 printf("\n");
02689 m_dump(table);
02690 #endif
02691
02692 if(sanitycheck_failed(devname, tpe)) {
02693 fprintf(stderr, "Autopart internal error (disk sanity check failed).\n");
02694 exit(1);
02695 }
02696
02697 if(newp) {
02698 int fd;
02699 if((fd=open(devname, O_WRONLY)) < 0) {
02700 perror(devname);
02701 } else {
02702
02703 static unsigned char sub[2048];
02704 sub[510] = 0x55;
02705 sub[511] = 0xAA;
02706 write(fd, sub, sizeof(sub));
02707 close(fd);
02708 }
02709 }
02710 return 0;
02711 }
02712
02713 return 1;
02714 }
02715
02716 int main(int argc, char **argv)
02717 {
02718 object_t *op;
02719 int i, r, key;
02720 struct part_entry *pe;
02721 char *name;
02722 int autopart = 0;
02723 int resultfd = -1;
02724
02725
02726 if(!(name = strrchr(argv[0], '/'))) name = argv[0];
02727 else name++;
02728 if(!strcmp(name, "autopart"))
02729 autopart = 1;
02730
02731 if(!autopart) {
02732
02733 op= newobject(O_INFO, 0, 0, 2, 19);
02734 op= newobject(O_TEXT, 0, 0, 22, 13); op->text= "----first----";
02735 op= newobject(O_TEXT, 0, 0, 37, 13); op->text= "--geom/last--";
02736 op= newobject(O_TEXT, 0, 0, 52, 18); op->text= "------sectors-----";
02737 op= newobject(O_TEXT, 0, 1, 4, 6); op->text= "Device";
02738 op= newobject(O_TEXT, 0, 1, 23, 12); op->text= "Cyl Head Sec";
02739 op= newobject(O_TEXT, 0, 1, 38, 12); op->text= "Cyl Head Sec";
02740 op= newobject(O_TEXT, 0, 1, 56, 4); op->text= "Base";
02741 op= newobject(O_TEXT, 0, 1, 66, 4); op->text= size_last;
02742 op= newobject(O_TEXT, 0, 1, 78, 2); op->text= "Kb";
02743 op= newobject(O_TEXT, 0, 4, 0, 15); op->text= "Num Sort Type";
02744
02745
02746 curobj= newobject(O_DEV, OF_MOD, 2, 4, 15);
02747 op= newobject(O_SUB, 0, 3, 4, 15);
02748
02749
02750 op= newobject(O_CYL, OF_MOD, 2, 40, 5); op->entry= &table[0];
02751 op= newobject(O_HEAD, OF_MOD, 2, 45, 3); op->entry= &table[0];
02752 op= newobject(O_SEC, OF_MOD, 2, 49, 2); op->entry= &table[0];
02753
02754
02755 op= newobject(O_SCYL, 0, 3, 25, 5); op->entry= &table[0];
02756 op= newobject(O_SHEAD, 0, 3, 30, 3); op->entry= &table[0];
02757 op= newobject(O_SSEC, 0, 3, 34, 2); op->entry= &table[0];
02758 op= newobject(O_LCYL, 0, 3, 40, 5); op->entry= &table[0];
02759 op= newobject(O_LHEAD, 0, 3, 45, 3); op->entry= &table[0];
02760 op= newobject(O_LSEC, 0, 3, 49, 2); op->entry= &table[0];
02761 op= newobject(O_BASE, 0, 3, 59, 9); op->entry= &table[0];
02762 op= newobject(O_SIZE, 0, 3, 69, 9); op->entry= &table[0];
02763 op= newobject(O_KB, 0, 3, 79, 9); op->entry= &table[0];
02764
02765
02766 for (r= 5, pe= table+1; pe <= table+NR_PARTITIONS; r++, pe++) {
02767 op= newobject(O_NUM, OF_MOD, r, 1, 2); op->entry= pe;
02768 op= newobject(O_SORT, 0, r, 5, 2); op->entry= pe;
02769 op= newobject(O_TYPHEX, OF_MOD, r, 10, 2); op->entry= pe;
02770 op= newobject(O_TYPTXT, OF_MOD, r, 12, 9); op->entry= pe;
02771 op= newobject(O_SCYL, OF_MOD, r, 25, 5); op->entry= pe;
02772 op= newobject(O_SHEAD, OF_MOD, r, 30, 3); op->entry= pe;
02773 op= newobject(O_SSEC, OF_MOD, r, 34, 2); op->entry= pe;
02774 op= newobject(O_LCYL, OF_MOD, r, 40, 5); op->entry= pe;
02775 op= newobject(O_LHEAD, OF_MOD, r, 45, 3); op->entry= pe;
02776 op= newobject(O_LSEC, OF_MOD, r, 49, 2); op->entry= pe;
02777 op= newobject(O_BASE, OF_MOD, r, 59, 9); op->entry= pe;
02778 op= newobject(O_SIZE, OF_MOD, r, 69, 9); op->entry= pe;
02779 op= newobject(O_KB, OF_MOD, r, 79, 9); op->entry= pe;
02780 }
02781 } else {
02782 int c;
02783
02784 while((c = getopt(argc, argv, "m:f:")) != EOF) {
02785 switch(c) {
02786 case 'm':
02787 min_region_mb = atoi(optarg);
02788 break;
02789 case 'f':
02790
02791 unlink(optarg);
02792 if((resultfd=open(optarg, O_CREAT | O_WRONLY | O_TRUNC)) < 0) {
02793 perror(optarg);
02794 return 1;
02795 }
02796 sync();
02797 break;
02798 default:
02799 fprintf(stderr, "Unknown option\n");
02800 return 1;
02801 }
02802 }
02803 }
02804 argc -= optind;
02805 argv += optind;
02806
02807 for (i= 0; i < argc; i++) {
02808 newdevice(argv[i], 0, 0);
02809 }
02810
02811 if (firstdev == nil) {
02812 getdevices(autopart);
02813 key= ctrl('L');
02814 } else {
02815 key= 'r';
02816 }
02817
02818 if(autopart) {
02819 int r;
02820 if (firstdev == nil) {
02821 fprintf(stderr, "autopart couldn't find any devices.\n");
02822 return 1;
02823 }
02824 r = do_autopart(resultfd);
02825 if(resultfd >= 0) { close(resultfd); }
02826 return r;
02827 }
02828
02829 if (firstdev != nil) {
02830 init_tty();
02831 clear_screen();
02832 event(key, curobj);
02833 display();
02834 mainloop();
02835 reset_tty();
02836 }
02837 exit(0);
02838 }