autopart.c

Go to the documentation of this file.
00001 /*      part 1.57 - Partition table editor              Author: Kees J. Bot
00002  *                                                              13 Mar 1992
00003  * Needs about 22k heap+stack.
00004  *
00005  * Forked july 2005 into autopart (Ben Gras), a mode which gives the user
00006  * an easier time.
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 /* Declare prototype. */
00037 static void printstep(int step, char *message);
00038 
00039 /* True if a partition is an extended partition. */
00040 #define ext_part(s)     ((s) == 0x05 || (s) == 0x0F)
00041 
00042 /* Minix master bootstrap code. */
00043 static char MASTERBOOT[] = "/usr/mdec/masterboot";
00044 
00045 /* Template:
00046                       ----first----  --geom/last--  ------sectors-----
00047     Device             Cyl Head Sec   Cyl Head Sec      Base      Size        Kb
00048     /dev/c0d0                          977    5  17
00049     /dev/c0d0:2          0    0   2   976    4  16         2     83043     41521
00050 Num Sort   Type
00051  0* p0   81 MINIX        0    0   3    33    4   9         3      2880      1440
00052  1  p1   81 MINIX       33    4  10   178    2   2      2883     12284      6142
00053  2  p2   81 MINIX      178    2   3   976    4  16     15167     67878     33939
00054  3  p3   00 None         0    0   0     0    0  -1         0         0         0
00055 
00056  */
00057 #define MAXSIZE         999999999L
00058 #define SECTOR_SIZE     512
00059 #define DEV_FD0         0x200           /* Device number of /dev/fd0 */
00060 #define DEV_C0D0        0x300           /* Device number of /dev/c0d0 */
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 /* screen colours */
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                 /* minix */
00095                 case 0x80:
00096                 case MINIX_PART:        col(COL_GREEN); break;
00097 
00098                 /* dos/windows */
00099                 case 0x0B: case 0x0C: case 0x0E: case 0x0F: case 0x42:
00100                 case 0x07:              col(COL_CYAN);          break;
00101 
00102                 /* linux */
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 /* Save tty attributes for later restoration. */
00136 {
00137         if (tcgetattr(0, &termios) < 0) fatal("");
00138 }
00139 
00140 void restore_ttyflags(void)
00141 /* Reset the tty flags to how we got 'em. */
00142 {
00143         if (tcsetattr(0, TCSANOW, &termios) < 0) fatal("");
00144 }
00145 
00146 void tty_raw(void)
00147 /* Set the terminal to raw mode, no signals, no echoing. */
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 /* Get terminal capabilities and set the tty to "editor" mode. */
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 /* Prepare for printing on a fresh status line, possibly highlighted. */
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 /* Closing bracket for stat_start.  Sets "keystrokes to live" of message. */
00221 {
00222         tputs(t_se, 1, putchr);
00223         stat_ktl= ktl;
00224         need_help= 1;
00225 }
00226 
00227 void stat_reset(void)
00228 /* Reset the statusline pointer and clear old messages if expired. */
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 /* Reset the tty to cooked mode. */
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         /* Missing in sys/types.h */
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;     /* Circular dequeue. */
00280         dev_t   rdev;                   /* Device number (sorting only). */
00281         char    *name;                  /* E.g. /dev/c0d0 */
00282         char    *subname;               /* E.g. /dev/c0d0:2 */
00283         parttype_t parttype;
00284         int biosdrive;
00285 } device_t;
00286 
00287 typedef struct region {
00288         /* A region is either an existing top-level partition
00289          * entry (used_part is non-NULL) or free space (free_*
00290          * contains data).
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 /* A disk has between 1 and 2*partitions+1 regions;
00299  * the last case is free space before and after every partition.
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 /* Add a device to the device list.  If scanning is set then we are reading
00318  * /dev, so insert the device in device number order and make /dev/c0d0 current.
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                         /* Disk controller */
00331                         if (minor(st.st_rdev) >= 0x80
00332                                         || minor(st.st_rdev) % 5 != 0) return;
00333                         break;
00334                 default:
00335                         return;
00336                 }
00337                 /* Interesting device found. */
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 /* Get all block devices from /dev that look interesting. */
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 /* One featureful master bootstrap. */
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 /* Let the sort_index array show the order partitions are sorted in. */
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 /* Extract cylinder, head and sector from the three bytes DOS uses to address
00464  * a sector.  Note that bits 8 & 9 of the cylinder number come from bit 6 & 7
00465  * of the sector byte.  The sector number is rebased to count from 0.
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 /* Translate a sector offset to three DOS bytes. */
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 /* Recompute the partition size for the device after a geometry change. */
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 /* With a bit of work one can deduce the disk geometry from the partition
00504  * table.  This may be necessary if the driver gets it wrong.  (If partition
00505  * tables didn't have C/H/S numbers we would not care at all...)
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];       /* Bit map off all possible H/S */
00514 
00515         alt_cyls= alt_heads= alt_secs= 0;
00516 
00517         /* Initially all possible H/S combinations are possible.  HS[h][0]
00518          * bit 0 is used to rule out a head value.
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                 /* Get the end or start sector numbers (in that order). */
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                 /* Which H/S combinations can be ruled out? */
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         /* See if only one remains. */
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         /* Forget it if more than one choice... */
00567         if (i > 1) alt_cyls= alt_heads= alt_secs= 0;
00568 }
00569 
00570 void geometry(void)
00571 /* Find out the geometry of the device by querying the driver, or by looking
00572  * at the partition table.  These numbers are crosschecked to make sure that
00573  * the geometry is correct.  Master bootstraps other than the Minix one use
00574  * the CHS numbers in the partition table to load the bootstrap of the active
00575  * partition.
00576  */
00577 {
00578         struct stat dst;
00579         int err= 0;
00580         struct partition geometry;
00581 
00582         if (submerged) {
00583                 /* Geometry already known. */
00584                 sort();
00585                 return;
00586         }
00587         precise= 0;
00588         cylinders= 0;
00589         recompute0();
00590         if (device < 0) return;
00591 
00592         /* Try to guess the geometry from the partition table. */
00593         guess_geometry();
00594 
00595         /* Try to get the geometry from the driver. */
00596         (void) fstat(device, &dst);
00597 
00598         if (S_ISBLK(dst.st_mode) || S_ISCHR(dst.st_mode)) {
00599                 /* Try to get the drive's geometry from the driver. */
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                 /* Getting the geometry from the driver failed, so use the
00617                  * alternate geometry.
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         /* Show the base and size of the device instead of the whole drive.
00654          * This makes sense for subpartitioning primary partitions.
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 {     /* Partition type to partition name. */
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 /* Translate a numeric partition indicator for human eyes. */
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 /* Find the next known partition type starting with ind in direction delta. */
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 /* Objects on the screen, either simple pieces of the text or the cylinder
00736  * number of the start of partition three.
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;           /* Text field, cylinder number, etc. */
00751         char            flags;          /* Modifiable? */
00752         char            row;
00753         char            col;
00754         char            len;
00755         struct part_entry *entry;       /* What does the object refer to? */
00756         char              *text;
00757         char            value[20];      /* Value when printed. */
00758 } object_t;
00759 
00760 #define OF_MOD          0x01    /* Object value is modifiable. */
00761 #define OF_ODD          0x02    /* It has a somewhat odd value. */
00762 #define OF_BAD          0x04    /* Its value is no good at all. */
00763 
00764 /* Events: (Keypress events are the value of the key pressed.) */
00765 #define E_ENTER         (-1)    /* Cursor moves onto object. */
00766 #define E_LEAVE         (-2)    /* Cursor leaves object. */
00767 #define E_WRITE         (-3)    /* Write, but not by typing 'w'. */
00768 
00769 /* The O_SIZE objects have a dual identity. */
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 /* Make a new object given a type, flags, position and length on the screen. */
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 /* Return the base sector of the partition if defined. */
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 /* See if sec is part of another partition. */
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 /* True if sec is aligned to unit or if it is no problem if it is unaligned. */
00830 {
00831         return (offset != 0 && extbase == 0) || (sec % unit == 0);
00832 }
00833 
00834 void print(object_t *op)
00835 /* Print an object's value if it changed. */
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         /* Remember the old flags and value. */
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                                 /* Current field. */
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                                 /* Simple text field. */
00880                 strcpy(op->value, op->text);
00881                 break;
00882         case O_DEV:
00883         case O_SUB:
00884                                 /* Name of currently edited device. */
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                                 /* Position and active flag. */
00893                 sprintf(op->value, "%d%c", (int) (pe - table - 1),
00894                                         pe->bootind & ACTIVE_FLAG ? '*' : ' ');
00895                 break;
00896         case O_SORT:
00897                                 /* Position if the driver sorts the table. */
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                                 /* Hex partition type indicator. */
00907                 sprintf(op->value, "%02X", pe->sysind);
00908                 break;
00909         case O_TYPTXT:
00910                                 /* Ascii partition type indicator. */
00911                 strcpy(op->value, typ2txt(pe->sysind));
00912                 break;
00913         case O_SCYL:
00914                                 /* Partition's start cylinder. */
00915                 sprintf(op->value, "%lu", entry2base(pe) / secpcyl);
00916                 break;
00917         case O_SHEAD:
00918                                 /* Start head. */
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                                 /* Start sector. */
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                                 /* Number of cylinders. */
00932                 sprintf(op->value, "%u", cylinders);
00933                 break;
00934         case O_HEAD:
00935                                 /* Number of heads. */
00936                 sprintf(op->value, "%u", heads);
00937                 break;
00938         case O_SEC:
00939                                 /* Number of sectors per track. */
00940                 sprintf(op->value, "%u", sectors);
00941                 break;
00942         case O_LCYL:
00943                                 /* Partition's last cylinder. */
00944                 t= entry2last(pe);
00945                 sprintf(op->value, "%lu", t == -1 ? 0 : t / secpcyl);
00946                 break;
00947         case O_LHEAD:
00948                                 /* Partition's last head. */
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                                 /* Partition's last sector. */
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                                 /* Partition's base sector. */
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                                 /* Size of partitition in sectors. */
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                                 /* Size of partitition in kilobytes. */
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         /* If a value overflows the print field then show a blank
00986          * reverse video field.
00987          */
00988         if ((n= strlen(op->value)) > op->len) {
00989                 n= 0;
00990                 op->flags|= OF_BAD;
00991         }
00992 
00993         /* Right or left justified? */
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                 /* The value did not change. */
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 /* Repaint all objects that changed. */
01021 {
01022         object_t *op;
01023 
01024         for (op= world; op != nil; op= op->next) print(op);
01025 }
01026 
01027 int typing;     /* Set if a digit has been typed to set a value. */
01028 int magic;      /* Changes when using the magic key. */
01029 
01030 void event(int ev, object_t *op);
01031 
01032 void m_redraw(int ev, object_t *op)
01033 /* Redraw the screen. */
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 /* Toggle between the driver and alternate geometry. */
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 /* Move to the nearest modifiably object in the intended direction.  Objects
01078  * on the same row or column are really near.
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                 /* No device open?  Then try to read first. */
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':       /* Left */
01107                         if (op2->col >= op->col) d2= -1;
01108                         break;
01109                 case 'j':       /* Down */
01110                         if (op2->row <= op->row) d2= -1;
01111                         break;
01112                 case 'k':       /* Up */
01113                         if (op2->row >= op->row) d2= -1;
01114                         break;
01115                 case 'l':       /* Right */
01116                         if (op2->col <= op->col) d2= -1;
01117                         break;
01118                 case 'H':       /* Home */
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 /* Move a partition table entry up or down. */
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 /* We've moved onto this object. */
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 /* About to leave this object. */
01165 {
01166         if (ev != E_LEAVE) return;
01167 }
01168 
01169 int within(unsigned *var, unsigned low, unsigned value, unsigned high)
01170 /* Only set *var to value if it looks reasonable. */
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 /* Select the next or previous device from the device list. */
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 /* If there are no other partitions then make this new one active. */
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 /* Check and if not ask if an existing partition may be modified. */
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 /* Increment, decrement, set, or toggle the value of an object, using
01252  * arithmetic tricks the author doesn't understand either.
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(&sectors, 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;      /* new value, no surplus */
01374         case O_SIZE:
01375                 if (pe->sysind == NO_PART) {
01376                         if (op->type == O_KB || howend == SIZE) {
01377                                 /* First let loose magic to set the base. */
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         /* The order among the entries may have changed. */
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 /* Add a new spell, descending order for the base, ascending for the size. */
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;  /* duplicate */
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 /* Apply magic onto a base or size number. */
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                 /* See what magic we can let loose on this value. */
01445                 nspells= 1;
01446 
01447                 /* First spell, the current value. */
01448                 switch (op->type) {
01449                 case O_SCYL:
01450                 case O_SHEAD:   /* Start of partition. */
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:    /* End of partition. */
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                                 /* First let loose magic on the base. */
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                 /* Avoid the first sector on the device. */
01488                 if (spell[0] == table[0].lowsec) newspell(spell[0] + 1);
01489 
01490                 /* Further interesting values are the the bases of other
01491                  * partitions or their ends.
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                 /* Present values rounded up to the next cylinder unless
01507                  * the table is already a mess.  Use "start + 1 track" instead
01508                  * of "start + 1 cylinder".  Also add the end of the last
01509                  * cylinder.
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         /* Magic has been applied, a spell needs to be chosen. */
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         /* The order among the entries may have changed. */
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 /* Go down into a primary or extended partition. */
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 /* Go up from an extended or subpartition table to its enclosing. */
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;        /* We surfaced. */
01624 }
01625 
01626 void installboot(unsigned char *bootblock, char *masterboot)
01627 /* Install code from a master bootstrap into a boot block. */
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         /* Bootstrap installed. */
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 /* Read (0) or write (1) the boot sector. */
01678 {
01679         u64_t off64 = mul64u(offset, SECTOR_SIZE);
01680         int r;
01681 
01682 #if __minix_vmd
01683         /* Minix-vmd has a 64 bit seek. */
01684         if (fcntl(device, F_SEEK, off64) < 0) return -1;
01685 #else
01686         /* Minix has to gross things with the partition base. */
01687         struct partition geom0, geom_seek;
01688 
01689         if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) {
01690                 /* Move partition base. */
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                 /* Can reach this point normally. */
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                 /* Restore partition base and size. */
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                 /* Start is unaligned. Round up. */
01738                 reg->free_sec_start += secpcyl - (reg->free_sec_start % secpcyl);
01739         }
01740         if((reg->free_sec_last+1) % secpcyl) {
01741                 /* End is unaligned. Round down. */
01742                 reg->free_sec_last -= (reg->free_sec_last+1) % secpcyl;
01743         }
01744         
01745         /* Return nonzero if anything remains of the region after rounding. */
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         /* Create region data used in autopart mode. */
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                 /* Free space before this partition? */
01776                 if(table[i].lowsec > free_sec) {
01777                         /* Free region before this partition. */
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(&regions[nr_regions])) {
01782                                 nr_regions++;
01783                                 free_regions++;
01784                         }
01785                 }
01786 
01787                 /* Sanity check. */
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                 /* Remember used region. */
01808                 memcpy(&regions[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         /* Special case: space after partitions. */
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(&regions[nr_regions])) {
01823                         nr_regions++;
01824                         free_regions++;
01825                 }
01826         }
01827 
01828 }
01829 
01830 void m_read(int ev, int *biosdrive)
01831 /* Read the partition table from the current device. */
01832 {
01833         int si, i, mode, n, r, v;
01834         struct part_entry *pe;
01835 
01836         if (ev != 'r' || device >= 0) return;
01837 
01838         /* Open() may cause kernel messages: */
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                 /* Invalid boot block, install bootstrap, wipe partition table.
01882                  */
01883                 memset(bootblock, 0, sizeof(bootblock));
01884                 installboot(bootblock, MASTERBOOT);
01885                 memset(table+1, 0, NR_PARTITIONS * sizeof(table[1]));
01886         }
01887 
01888         /* Fix an extended partition table up to something mere mortals can
01889          * understand.  Record already defined partitions.
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         /* Warn about grave dangers ahead. */
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 /* Write the partition table back if modified. */
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                 /* Will this stop him?  Probably not... */
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                         /* Fear and loathing time: */
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 /* Shell escape, to do calculations for instance. */
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);  /* Match the stat_start in the child. */
02001         else
02002                 event(ctrl('L'), op);
02003 }
02004 
02005 void m_dump(struct part_entry *print_table)
02006 /* Raw dump of the partition table. */
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 /* Write the partition table if modified and exit. */
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 /* For people without a clue; let's hope they can find the '?' key. */
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 /* Simply call all modifiers for an event, each one knows when to act. */
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 /* Get a single keypress.  Translate compound keypresses (arrow keys) to
02130  * their simpler equivalents.
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                         /*FALL THROUGH*/
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 /* Get keypress, handle event, display results, reset screen, ad infinitum. */
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         /* User may go again. */
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(&regions[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                         /* Bug, should've been caught earlier. */
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 = &reg->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                 /* Show regions. */
02614                 r = select_region();
02615         } while(!r);    /* Back to step 2. */
02616 
02617         /* Write things. */
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                 /* disk = (int) (curdev-devices); */
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                 /* Retrieve partition number in sorted order that we
02640                  * have scribbled in.
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                                 /* Clear any subpartitioning. */
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         /* Autopilot mode if invoked as autopart. */
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         /* Define a few objects to show on the screen.  First text: */
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         /* The device is the current object: */
02746     curobj= newobject(O_DEV,  OF_MOD, 2,  4, 15);
02747         op= newobject(O_SUB,       0, 3,  4, 15);
02748 
02749         /* Geometry: */
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         /* Objects for the device: */
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         /* Objects for each partition: */
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         /* autopart uses getopt() */
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                                 /* Make sure old data file is gone. */
02791                                 unlink(optarg);
02792                                 if((resultfd=open(optarg, O_CREAT | O_WRONLY | O_TRUNC)) < 0) {
02793                                         perror(optarg);
02794                                         return 1;
02795                                 }
02796                                 sync(); /* Make sure no old data file lingers. */
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 }

Generated on Fri Apr 14 22:56:57 2006 for minix by  doxygen 1.4.6