From 5dd4862b7ea11d317bea596e932eef636f529a5f Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Wed, 13 Jul 2005 10:02:14 +0000 Subject: [PATCH] Fixed some warnings in dosread.c; initial version of autopart (don't try it yet ;)) --- commands/ibm/Makefile | 8 + commands/ibm/autopart.c | 2560 +++++++++++++++++++++++++++++++++++++++ commands/ibm/dosread.c | 36 - 3 files changed, 2568 insertions(+), 36 deletions(-) create mode 100755 commands/ibm/autopart.c diff --git a/commands/ibm/Makefile b/commands/ibm/Makefile index df65f8f17..6318a44cd 100755 --- a/commands/ibm/Makefile +++ b/commands/ibm/Makefile @@ -49,6 +49,10 @@ mixer: mixer.c $(CCLD) -o $@ $? -lcurses install -S 16kw $@ +autopart: autopart.c + $(CCLD) -o $@ $? + install -S 11kw $@ + part: part.c $(CCLD) -o $@ $? install -S 11kw $@ @@ -94,6 +98,7 @@ install: \ /usr/bin/loadfont \ /usr/bin/loadkeys \ /usr/bin/mixer \ + /usr/bin/autopart \ /usr/bin/part \ /usr/bin/partition \ /usr/bin/playwave \ @@ -127,6 +132,9 @@ install: \ /usr/bin/mixer: mixer install -cs -o bin $? $@ +/usr/bin/autopart: autopart + install -lcs $? $@ + /usr/bin/part: part install -cs -o bin $? $@ diff --git a/commands/ibm/autopart.c b/commands/ibm/autopart.c new file mode 100755 index 000000000..0d3a82ab6 --- /dev/null +++ b/commands/ibm/autopart.c @@ -0,0 +1,2560 @@ +/* part 1.57 - Partition table editor Author: Kees J. Bot + * 13 Mar 1992 + * Needs about 22k heap+stack. + * + * Forked july 2005 into autopart (Ben Gras), a mode which gives the user + * an easier time. + * + */ +#define nil 0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* True if a partition is an extended partition. */ +#define ext_part(s) ((s) == 0x05 || (s) == 0x0F) + +/* Minix master bootstrap code. */ +static char MASTERBOOT[] = "/usr/mdec/masterboot"; + +/* Template: + ----first---- --geom/last-- ------sectors----- + Device Cyl Head Sec Cyl Head Sec Base Size Kb + /dev/c0d0 977 5 17 + /dev/c0d0:2 0 0 2 976 4 16 2 83043 41521 +Num Sort Type + 0* p0 81 MINIX 0 0 3 33 4 9 3 2880 1440 + 1 p1 81 MINIX 33 4 10 178 2 2 2883 12284 6142 + 2 p2 81 MINIX 178 2 3 976 4 16 15167 67878 33939 + 3 p3 00 None 0 0 0 0 0 -1 0 0 0 + + */ +#define MAXSIZE 999999999L +#define SECTOR_SIZE 512 +#define DEV_FD0 0x200 /* Device number of /dev/fd0 */ +#define DEV_C0D0 0x300 /* Device number of /dev/c0d0 */ + +#define MIN_REGION_MB 80 +#define MIN_REGION_SECTORS (1024*1024*MIN_REGION_MB/SECTOR_SIZE) + +#define MAX_REGION_MB 4095 +#define MAX_REGION_SECTORS (1024*(1024/SECTOR_SIZE)*MAX_REGION_MB) + +#define arraysize(a) (sizeof(a) / sizeof((a)[0])) +#define arraylimit(a) ((a) + arraysize(a)) + +#define SORNOT(n) ((n) == 1 ? "" : "s") + +int probing = 0, autopartmode = 0; + +void report(const char *label) +{ + fprintf(stderr, "part: %s: %s\n", label, strerror(errno)); +} + +void fatal(const char *label) +{ + report(label); + exit(1); +} + +struct termios termios; + +void save_ttyflags(void) +/* Save tty attributes for later restoration. */ +{ + if (tcgetattr(0, &termios) < 0) fatal(""); +} + +void restore_ttyflags(void) +/* Reset the tty flags to how we got 'em. */ +{ + if (tcsetattr(0, TCSANOW, &termios) < 0) fatal(""); +} + +void tty_raw(void) +/* Set the terminal to raw mode, no signals, no echoing. */ +{ + struct termios rawterm; + + rawterm= termios; + rawterm.c_lflag &= ~(ICANON|ISIG|ECHO); + rawterm.c_iflag &= ~(ICRNL); + if (tcsetattr(0, TCSANOW, &rawterm) < 0) fatal(""); +} + +#define ctrl(c) ((c) == '?' ? '\177' : ((c) & '\37')) + +char t_cd[16], t_cm[32], t_so[16], t_se[16], t_md[16], t_me[16]; +int t_li, t_co; +#define STATUSROW 10 + +void init_tty(void) +/* Get terminal capabilities and set the tty to "editor" mode. */ +{ + char *term; + static char termbuf[1024]; + char *tp; + + if ((term= getenv("TERM")) == nil || tgetent(termbuf, term) != 1) { + fprintf(stderr, "part: Can't get terminal capabilities\n"); + exit(1); + } + if (tgetstr("cd", (tp= t_cd, &tp)) == nil + || tgetstr("cm", (tp= t_cm, &tp)) == nil) { + fprintf(stderr, "part: This terminal is too dumb\n"); + exit(1); + } + t_li= tgetnum("li"); + t_co= tgetnum("co"); + (void) tgetstr("so", (tp= t_so, &tp)); + (void) tgetstr("se", (tp= t_se, &tp)); + (void) tgetstr("md", (tp= t_md, &tp)); + (void) tgetstr("me", (tp= t_me, &tp)); + + save_ttyflags(); + tty_raw(); +} + +void putchr(int c) +{ + putchar(c); +} + +void putstr(char *s) +{ + int c; + + while ((c= *s++) != 0) putchr(c); +} + +void set_cursor(int row, int col) +{ + tputs(tgoto(t_cm, col, row), 1, putchr); +} + +int statusrow= STATUSROW; +int stat_ktl= 1; +int need_help= 1; + +void stat_start(int serious) +/* Prepare for printing on a fresh status line, possibly highlighted. */ +{ + set_cursor(statusrow++, 0); + tputs(t_cd, 1, putchr); + if (serious) tputs(t_so, 1, putchr); +} + +void stat_end(int ktl) +/* Closing bracket for stat_start. Sets "keystrokes to live" of message. */ +{ + tputs(t_se, 1, putchr); + stat_ktl= ktl; + need_help= 1; +} + +void stat_reset(void) +/* Reset the statusline pointer and clear old messages if expired. */ +{ + if (stat_ktl > 0 && --stat_ktl == 0) { + statusrow= STATUSROW; + need_help= 1; + } + if (need_help && statusrow < (24-2)) { + if (statusrow > STATUSROW) stat_start(0); + stat_start(0); + putstr( +"Type '+' or '-' to change, 'r' to read, '?' for more help, '!' for advice"); + } + statusrow= STATUSROW; + need_help= 0; +} + +void clear_screen(void) +{ + set_cursor(0, 0); + tputs(t_cd, 1, putchr); + stat_ktl= 1; + stat_reset(); +} + +void reset_tty(void) +/* Reset the tty to cooked mode. */ +{ + restore_ttyflags(); + set_cursor(statusrow, 0); + tputs(t_cd, 1, putchr); +} + +void *alloc(size_t n) +{ + void *m; + + if ((m= malloc(n)) == nil) { reset_tty(); fatal(""); } + + return m; +} + +#ifndef makedev /* Missing in sys/types.h */ +#define minor(dev) (((dev) >> MINOR) & BYTE) +#define major(dev) (((dev) >> MAJOR) & BYTE) +#define makedev(major, minor) \ + ((dev_t) (((major) << MAJOR) | ((minor) << MINOR))) +#endif + +typedef enum parttype { DUNNO, SUBPART, PRIMARY, FLOPPY } parttype_t; + +typedef struct device { + struct device *next, *prev; /* Circular dequeue. */ + dev_t rdev; /* Device number (sorting only). */ + char *name; /* E.g. /dev/c0d0 */ + char *subname; /* E.g. /dev/c0d0:2 */ + parttype_t parttype; +} device_t; + +typedef struct region { + /* A region is either an existing top-level partition + * entry (used_part is non-NULL) or free space (free_* + * contains data). + */ + struct part_entry *used_part; + int free_sec_start, free_sec_last; +} region_t; + +/* A disk has between 1 and 2*partitions+1 regions; + * the last case is free space before and after every partition. + */ +#define NR_REGIONS (2*NR_PARTITIONS+1) +region_t regions[NR_REGIONS]; +int nr_partitions = 0, nr_regions = 0, free_regions, used_regions; +int nordonly = 0; + +device_t *firstdev= nil, *curdev; + +void newdevice(char *name, int scanning, int disk_only) +/* Add a device to the device list. If scanning is set then we are reading + * /dev, so insert the device in device number order and make /dev/c0d0 current. + */ +{ + device_t *new, *nextdev, *prevdev; + struct stat st; + + st.st_rdev= 0; + if (scanning) { + if (stat(name, &st) < 0 || !S_ISBLK(st.st_mode)) return; + + switch (major(st.st_rdev)) { + case 2: + /* Floppy */ + if (disk_only || minor(st.st_rdev) >= 4) return; + break; + case 3: + case 8: + case 10: + case 12: + case 16: + /* Disk controller */ + if (minor(st.st_rdev) >= 0x80 + || minor(st.st_rdev) % 5 != 0) return; + break; + default: + return; + } + /* Interesting device found. */ + } else { + (void) stat(name, &st); + } + + new= alloc(sizeof(*new)); + new->rdev= st.st_rdev; + new->name= alloc((strlen(name) + 1) * sizeof(new->name[0])); + strcpy(new->name, name); + new->subname= new->name; + new->parttype= DUNNO; + if (major(st.st_rdev) == major(DEV_FD0) && minor(st.st_rdev) < 112) { + new->parttype= FLOPPY; + } else + if (st.st_rdev >= DEV_C0D0 && minor(st.st_rdev) < 128 + && minor(st.st_rdev) % 5 == 0) { + new->parttype= PRIMARY; + } + + if (firstdev == nil) { + firstdev= new; + new->next= new->prev= new; + curdev= firstdev; + return; + } + nextdev= firstdev; + while (new->rdev >= nextdev->rdev + && (nextdev= nextdev->next) != firstdev) {} + prevdev= nextdev->prev; + new->next= nextdev; + nextdev->prev= new; + new->prev= prevdev; + prevdev->next= new; + + if (new->rdev < firstdev->rdev) firstdev= new; + if (new->rdev == DEV_C0D0) curdev= new; + if (curdev->rdev != DEV_C0D0) curdev= firstdev; +} + +void getdevices(int disk_only) +/* Get all block devices from /dev that look interesting. */ +{ + DIR *d; + struct dirent *e; + char name[5 + NAME_MAX + 1]; + + if ((d= opendir("/dev")) == nil) fatal("/dev"); + + while ((e= readdir(d)) != nil) { + strcpy(name, "/dev/"); + strcpy(name + 5, e->d_name); + newdevice(name, 1, disk_only); + } + (void) closedir(d); +} + +/* One featureful master bootstrap. */ +unsigned char bootstrap[] = { +0353,0001,0000,0061,0300,0216,0330,0216,0300,0372,0216,0320,0274,0000,0174,0373, +0275,0276,0007,0211,0346,0126,0277,0000,0006,0271,0000,0001,0374,0363,0245,0352, +0044,0006,0000,0000,0264,0002,0315,0026,0250,0010,0164,0033,0350,0071,0001,0174, +0007,0060,0344,0315,0026,0242,0205,0007,0054,0060,0074,0012,0163,0363,0120,0350, +0046,0001,0205,0007,0130,0353,0012,0240,0002,0006,0204,0300,0165,0003,0351,0147, +0000,0230,0262,0005,0366,0362,0262,0200,0000,0302,0210,0340,0120,0350,0234,0000, +0163,0003,0351,0147,0000,0130,0054,0001,0175,0003,0351,0141,0000,0276,0276,0175, +0211,0357,0271,0040,0000,0363,0245,0200,0301,0004,0211,0356,0215,0174,0020,0070, +0154,0004,0164,0016,0213,0135,0010,0053,0134,0010,0213,0135,0012,0033,0134,0012, +0163,0014,0212,0044,0206,0144,0020,0210,0044,0106,0071,0376,0162,0364,0211,0376, +0201,0376,0356,0007,0162,0326,0342,0322,0211,0356,0264,0020,0366,0344,0001,0306, +0200,0174,0004,0001,0162,0026,0353,0021,0204,0322,0175,0041,0211,0356,0200,0174, +0004,0000,0164,0013,0366,0004,0200,0164,0006,0350,0070,0000,0162,0053,0303,0203, +0306,0020,0201,0376,0376,0007,0162,0346,0350,0215,0000,0211,0007,0376,0302,0204, +0322,0174,0023,0315,0021,0321,0340,0321,0340,0200,0344,0003,0070,0342,0167,0355, +0350,0011,0000,0162,0350,0303,0350,0003,0000,0162,0146,0303,0211,0356,0214,0134, +0010,0214,0134,0012,0277,0003,0000,0122,0006,0127,0264,0010,0315,0023,0137,0007, +0200,0341,0077,0376,0306,0210,0310,0366,0346,0211,0303,0213,0104,0010,0213,0124, +0012,0367,0363,0222,0210,0325,0366,0361,0060,0322,0321,0352,0321,0352,0010,0342, +0210,0321,0376,0301,0132,0210,0306,0273,0000,0174,0270,0001,0002,0315,0023,0163, +0020,0200,0374,0200,0164,0011,0117,0174,0006,0060,0344,0315,0023,0163,0270,0371, +0303,0201,0076,0376,0175,0125,0252,0165,0001,0303,0350,0013,0000,0243,0007,0353, +0005,0350,0004,0000,0227,0007,0353,0376,0136,0255,0126,0211,0306,0254,0204,0300, +0164,0011,0264,0016,0273,0001,0000,0315,0020,0353,0362,0303,0057,0144,0145,0166, +0057,0150,0144,0077,0010,0000,0015,0012,0000,0116,0157,0156,0145,0040,0141,0143, +0164,0151,0166,0145,0015,0012,0000,0122,0145,0141,0144,0040,0145,0162,0162,0157, +0162,0040,0000,0116,0157,0164,0040,0142,0157,0157,0164,0141,0142,0154,0145,0040, +0000,0000, +}; + +int dirty= 0; +unsigned char bootblock[SECTOR_SIZE]; +struct part_entry table[1 + NR_PARTITIONS]; +int existing[1 + NR_PARTITIONS]; +unsigned long offset= 0, extbase= 0, extsize; +int submerged= 0; +char sort_index[1 + NR_PARTITIONS]; +unsigned cylinders= 1, heads= 1, sectors= 1, secpcyl= 1; +unsigned alt_cyls= 1, alt_heads= 1, alt_secs= 1; +int precise= 0; +int device= -1; + +unsigned long sortbase(struct part_entry *pe) +{ + return pe->sysind == NO_PART ? -1 : pe->lowsec; +} + +void sort(void) +/* Let the sort_index array show the order partitions are sorted in. */ +{ + int i, j; + int idx[1 + NR_PARTITIONS]; + + for (i= 1; i <= NR_PARTITIONS; i++) idx[i]= i; + + for (i= 1; i <= NR_PARTITIONS; i++) { + for (j= 1; j <= NR_PARTITIONS-1; j++) { + int sj= idx[j], sj1= idx[j+1]; + + if (sortbase(&table[sj]) > sortbase(&table[sj1])) { + idx[j]= sj1; + idx[j+1]= sj; + } + } + } + for (i= 1; i <= NR_PARTITIONS; i++) sort_index[idx[i]]= i; +} + +void dos2chs(unsigned char *dos, unsigned *chs) +/* Extract cylinder, head and sector from the three bytes DOS uses to address + * a sector. Note that bits 8 & 9 of the cylinder number come from bit 6 & 7 + * of the sector byte. The sector number is rebased to count from 0. + */ +{ + chs[0]= ((dos[1] & 0xC0) << 2) | dos[2]; + chs[1]= dos[0]; + chs[2]= (dos[1] & 0x3F) - 1; +} + +void abs2dos(unsigned char *dos, unsigned long pos) +/* Translate a sector offset to three DOS bytes. */ +{ + unsigned h, c, s; + + c= pos / secpcyl; + h= (pos % secpcyl) / sectors; + s= pos % sectors + 1; + + dos[0]= h; + dos[1]= s | ((c >> 2) & 0xC0); + dos[2]= c & 0xFF; +} + +void recompute0(void) +/* Recompute the partition size for the device after a geometry change. */ +{ + if (device < 0) { + cylinders= heads= sectors= 1; + memset(table, 0, sizeof(table)); + } else + if (!precise && offset == 0) { + table[0].lowsec= 0; + table[0].size= (unsigned long) cylinders * heads * sectors; + } + table[0].sysind= device < 0 ? NO_PART : MINIX_PART; + secpcyl= heads * sectors; +} + +void guess_geometry(void) +/* With a bit of work one can deduce the disk geometry from the partition + * table. This may be necessary if the driver gets it wrong. (If partition + * tables didn't have C/H/S numbers we would not care at all...) + */ +{ + int i, n; + struct part_entry *pe; + unsigned chs[3]; + unsigned long sec; + unsigned h, s; + unsigned char HS[256][8]; /* Bit map off all possible H/S */ + + alt_cyls= alt_heads= alt_secs= 0; + + /* Initially all possible H/S combinations are possible. HS[h][0] + * bit 0 is used to rule out a head value. + */ + for (h= 1; h <= 255; h++) { + for (s= 0; s < 8; s++) HS[h][s]= 0xFF; + } + + for (i= 0; i < 2*NR_PARTITIONS; i++) { + pe= &(table+1)[i >> 1]; + if (pe->sysind == NO_PART) continue; + + /* Get the end or start sector numbers (in that order). */ + if ((i & 1) == 0) { + dos2chs(&pe->last_head, chs); + sec= pe->lowsec + pe->size - 1; + } else { + dos2chs(&pe->start_head, chs); + sec= pe->lowsec; + } + + if (chs[0] >= alt_cyls) alt_cyls= chs[0]+1; + + /* Which H/S combinations can be ruled out? */ + for (h= 1; h <= 255; h++) { + if (HS[h][0] == 0) continue; + n = 0; + for (s= 1; s <= 63; s++) { + if ((chs[0] * h + chs[1]) * s + chs[2] != sec) { + HS[h][s/8] &= ~(1 << (s%8)); + } + if (HS[h][s/8] & (1 << (s%8))) n++; + } + if (n == 0) HS[h][0]= 0; + } + } + + /* See if only one remains. */ + i= 0; + for (h= 1; h <= 255; h++) { + if (HS[h][0] == 0) continue; + for (s= 1; s <= 63; s++) { + if (HS[h][s/8] & (1 << (s%8))) { + i++; + alt_heads= h; + alt_secs= s; + } + } + } + + /* Forget it if more than one choice... */ + if (i > 1) alt_cyls= alt_heads= alt_secs= 0; +} + +void geometry(void) +/* Find out the geometry of the device by querying the driver, or by looking + * at the partition table. These numbers are crosschecked to make sure that + * the geometry is correct. Master bootstraps other than the Minix one use + * the CHS numbers in the partition table to load the bootstrap of the active + * partition. + */ +{ + struct stat dst; + int err= 0; + struct partition geometry; + + if (submerged) { + /* Geometry already known. */ + sort(); + return; + } + precise= 0; + cylinders= 0; + recompute0(); + if (device < 0) return; + + /* Try to guess the geometry from the partition table. */ + guess_geometry(); + + /* Try to get the geometry from the driver. */ + (void) fstat(device, &dst); + + if (S_ISBLK(dst.st_mode) || S_ISCHR(dst.st_mode)) { + /* Try to get the drive's geometry from the driver. */ + + if (ioctl(device, DIOCGETP, &geometry) < 0) + err= errno; + else { + table[0].lowsec= div64u(geometry.base, SECTOR_SIZE); + table[0].size= div64u(geometry.size, SECTOR_SIZE); + cylinders= geometry.cylinders; + heads= geometry.heads; + sectors= geometry.sectors; + precise= 1; + } + } else { + err= ENODEV; + } + + if (err != 0) { + /* Getting the geometry from the driver failed, so use the + * alternate geometry. + */ + if (alt_heads == 0) { + alt_cyls= table[0].size / (64 * 32); + alt_heads= 64; + alt_secs= 32; + } + + cylinders= alt_cyls; + heads= alt_heads; + sectors= alt_secs; + + stat_start(1); + printf("Failure to get the geometry of %s: %s", curdev->name, + errno == ENOTTY ? "No driver support" : strerror(err)); + stat_end(5); + stat_start(0); + printf("The geometry has been guessed as %ux%ux%u", + cylinders, heads, sectors); + stat_end(5); + } else { + if (alt_heads == 0) { + alt_cyls= cylinders; + alt_heads= heads; + alt_secs= sectors; + } + + if (heads != alt_heads || sectors != alt_secs) { + stat_start(1); + printf("WARNING:"); + stat_end(10); + stat_start(0); + printf( +"The %ux%ux%u geometry obtained from the device driver does not match", + cylinders, heads, sectors); + stat_end(10); + stat_start(0); + printf( +"the %ux%ux%u geometry implied by the partition table. Hit 'X' to switch", + alt_cyls, alt_heads, alt_secs); + stat_end(10); + stat_start(0); + printf( +"between the two geometries to see what is best. Note that the geometry"); + stat_end(10); + stat_start(0); + printf( +"must be correct when the table is written or the system may not boot!"); + stat_end(10); + } + } + + /* Show the base and size of the device instead of the whole drive. + * This makes sense for subpartitioning primary partitions. + */ + if (precise && ioctl(device, DIOCGETP, &geometry) >= 0) { + table[0].lowsec= div64u(geometry.base, SECTOR_SIZE); + table[0].size= div64u(geometry.size, SECTOR_SIZE); + } else { + precise= 0; + } + recompute0(); + sort(); +} + +typedef struct indicators { /* Partition type to partition name. */ + unsigned char ind; + char name[10]; +} indicators_t; + +indicators_t ind_table[]= { + { 0x00, "None" }, + { 0x01, "FAT-12" }, + { 0x02, "XENIX /" }, + { 0x03, "XENIX usr" }, + { 0x04, "FAT-16" }, + { 0x05, "EXTENDED" }, + { 0x06, "FAT-16" }, + { 0x07, "HPFS/NTFS" }, + { 0x08, "AIX" }, + { 0x09, "COHERENT" }, + { 0x0A, "OS/2" }, + { 0x0B, "FAT-32" }, + { 0x0C, "FAT?" }, + { 0x0E, "FAT?" }, + { 0x0F, "EXTENDED" }, + { 0x10, "OPUS" }, + { 0x40, "VENIX286" }, + { 0x42, "W2000 Dyn" }, + { 0x52, "MICROPORT" }, + { 0x63, "386/IX" }, + { 0x64, "NOVELL286" }, + { 0x65, "NOVELL386" }, + { 0x75, "PC/IX" }, + { 0x80, "MINIX-OLD" }, + { 0x81, "MINIX" }, + { 0x82, "LINUXswap" }, + { 0x83, "LINUX" }, + { 0x93, "AMOEBA" }, + { 0x94, "AMOEBAbad" }, + { 0xA5, "386BSD" }, + { 0xB7, "BSDI" }, + { 0xB8, "BSDI swap" }, + { 0xC7, "SYRINX" }, + { 0xDB, "CPM" }, + { 0xFF, "BADBLOCKS" }, +}; + +char *typ2txt(int ind) +/* Translate a numeric partition indicator for human eyes. */ +{ + indicators_t *pind; + + for (pind= ind_table; pind < arraylimit(ind_table); pind++) { + if (pind->ind == ind) return pind->name; + } + return ""; +} + +int round_sysind(int ind, int delta) +/* Find the next known partition type starting with ind in direction delta. */ +{ + indicators_t *pind; + + ind= (ind + delta) & 0xFF; + + if (delta < 0) { + for (pind= arraylimit(ind_table)-1; pind->ind > ind; pind--) {} + } else { + for (pind= ind_table; pind->ind < ind; pind++) {} + } + return pind->ind; +} + +/* Objects on the screen, either simple pieces of the text or the cylinder + * number of the start of partition three. + */ +typedef enum objtype { + O_INFO, O_TEXT, O_DEV, O_SUB, + O_TYPTXT, O_SORT, O_NUM, O_TYPHEX, + O_CYL, O_HEAD, O_SEC, + O_SCYL, O_SHEAD, O_SSEC, O_LCYL, O_LHEAD, O_LSEC, O_BASE, O_SIZE, O_KB +} objtype_t; + +#define rjust(type) ((type) >= O_TYPHEX) +#define computed(type) ((type) >= O_TYPTXT) + +typedef struct object { + struct object *next; + objtype_t type; /* Text field, cylinder number, etc. */ + char flags; /* Modifiable? */ + char row; + char col; + char len; + struct part_entry *entry; /* What does the object refer to? */ + char *text; + char value[20]; /* Value when printed. */ +} object_t; + +#define OF_MOD 0x01 /* Object value is modifiable. */ +#define OF_ODD 0x02 /* It has a somewhat odd value. */ +#define OF_BAD 0x04 /* Its value is no good at all. */ + +/* Events: (Keypress events are the value of the key pressed.) */ +#define E_ENTER (-1) /* Cursor moves onto object. */ +#define E_LEAVE (-2) /* Cursor leaves object. */ +#define E_WRITE (-3) /* Write, but not by typing 'w'. */ + +/* The O_SIZE objects have a dual identity. */ +enum howend { SIZE, LAST } howend= SIZE; + +object_t *world= nil; +object_t *curobj= nil; + +object_t *newobject(objtype_t type, int flags, int row, int col, int len) +/* Make a new object given a type, flags, position and length on the screen. */ +{ + object_t *new; + object_t **aop= &world; + + new= alloc(sizeof(*new)); + + new->type= type; + new->flags= flags; + new->row= row; + new->col= col; + new->len= len; + new->entry= nil; + new->text= ""; + new->value[0]= 0; + + new->next= *aop; + *aop= new; + + return new; +} + +unsigned long entry2base(struct part_entry *pe) +/* Return the base sector of the partition if defined. */ +{ + return pe->sysind == NO_PART ? 0 : pe->lowsec; +} + +unsigned long entry2last(struct part_entry *pe) +{ + return pe->sysind == NO_PART ? -1 : pe->lowsec + pe->size - 1; +} + +unsigned long entry2size(struct part_entry *pe) +{ + return pe->sysind == NO_PART ? 0 : pe->size; +} + +int overlap(unsigned long sec) +/* See if sec is part of another partition. */ +{ + struct part_entry *pe; + + for (pe= table + 1; pe <= table + NR_PARTITIONS; pe++) { + if (pe->sysind == NO_PART) continue; + + if (pe->lowsec < sec && sec < pe->lowsec + pe->size) + return 1; + } + return 0; +} + +int aligned(unsigned long sec, unsigned unit) +/* True if sec is aligned to unit or if it is no problem if it is unaligned. */ +{ + return (offset != 0 && extbase == 0) || (sec % unit == 0); +} + +void print(object_t *op) +/* Print an object's value if it changed. */ +{ + struct part_entry *pe= op->entry; + int n; + unsigned long t; + char *name; + int oldflags; + char oldvalue[20]; + + /* Remember the old flags and value. */ + oldflags= op->flags; + strcpy(oldvalue, op->value); + + op->flags&= ~(OF_ODD | OF_BAD); + + switch (op->type) { + case O_INFO: { + /* Current field. */ + static struct field { int type; char *name; } fields[]= { + { O_DEV, "Select device" }, + { O_NUM, "Active flag" }, + { O_TYPHEX, "Hex partition type" }, + { O_TYPTXT, "Partition type" }, + { O_SCYL, "Start cylinder" }, + { O_SHEAD, "Start head" }, + { O_SSEC, "Start sector" }, + { O_CYL, "Number of cylinders" }, + { O_HEAD, "Number of heads" }, + { O_SEC, "Sectors per track" }, + { O_LCYL, "Last cylinder" }, + { O_LHEAD, "Last head" }, + { O_LSEC, "Last sector" }, + { O_BASE, "Base sector" }, + { O_SIZE, "Size in sectors" }, + { O_KB, "Size in kilobytes" }, + { -1, "?" }, + }; + struct field *fp= fields; + + while (fp->type >= 0 && fp->type != curobj->type) fp++; + strcpy(op->value, fp->name); + op->flags|= OF_ODD; + break; } + case O_TEXT: + /* Simple text field. */ + strcpy(op->value, op->text); + break; + case O_DEV: + case O_SUB: + /* Name of currently edited device. */ + name= op->type == O_DEV ? curdev->name : + offset == 0 ? "" : curdev->subname; + if ((n= strlen(name)) < op->len) n= op->len; + strcpy(op->value, name + (n - op->len)); + if (device < 0 && op->type == O_DEV) op->flags|= OF_BAD; + break; + case O_NUM: + /* Position and active flag. */ + sprintf(op->value, "%d%c", (int) (pe - table - 1), + pe->bootind & ACTIVE_FLAG ? '*' : ' '); + break; + case O_SORT: + /* Position if the driver sorts the table. */ + sprintf(op->value, "%s%d", + curdev->parttype >= PRIMARY ? "p" : + curdev->parttype == SUBPART ? "s" : "", + (curdev->parttype == SUBPART || + curdev->parttype == FLOPPY ? pe - table + : sort_index[pe - table]) - 1); + break; + case O_TYPHEX: + /* Hex partition type indicator. */ + sprintf(op->value, "%02X", pe->sysind); + break; + case O_TYPTXT: + /* Ascii partition type indicator. */ + strcpy(op->value, typ2txt(pe->sysind)); + break; + case O_SCYL: + /* Partition's start cylinder. */ + sprintf(op->value, "%lu", entry2base(pe) / secpcyl); + break; + case O_SHEAD: + /* Start head. */ + t= entry2base(pe); + sprintf(op->value, "%lu", t % secpcyl / sectors); + if (!aligned(t, secpcyl) && t != table[0].lowsec + sectors) + op->flags|= OF_ODD; + break; + case O_SSEC: + /* Start sector. */ + t= entry2base(pe); + sprintf(op->value, "%lu", t % sectors); + if (!aligned(t, sectors)) op->flags|= OF_ODD; + break; + case O_CYL: + /* Number of cylinders. */ + sprintf(op->value, "%u", cylinders); + break; + case O_HEAD: + /* Number of heads. */ + sprintf(op->value, "%u", heads); + break; + case O_SEC: + /* Number of sectors per track. */ + sprintf(op->value, "%u", sectors); + break; + case O_LCYL: + /* Partition's last cylinder. */ + t= entry2last(pe); + sprintf(op->value, "%lu", t == -1 ? 0 : t / secpcyl); + break; + case O_LHEAD: + /* Partition's last head. */ + t= entry2last(pe); + sprintf(op->value, "%lu", t == -1 ? 0 : t % secpcyl / sectors); + if (!aligned(t + 1, secpcyl)) op->flags|= OF_ODD; + break; + case O_LSEC: + /* Partition's last sector. */ + t= entry2last(pe); + sprintf(op->value, t == -1 ? "-1" : "%lu", t % sectors); + if (!aligned(t + 1, sectors)) op->flags|= OF_ODD; + break; + case O_BASE: + /* Partition's base sector. */ + sprintf(op->value, "%lu", entry2base(pe)); + if (pe->sysind != NO_PART && pe != &table[0] + && (pe->lowsec <= table[0].lowsec || overlap(pe->lowsec))) + op->flags|= OF_BAD; + break; + case O_SIZE: + /* Size of partitition in sectors. */ + t= howend == SIZE ? entry2size(pe) : entry2last(pe); + sprintf(op->value, "%lu", pe->sysind == NO_PART ? 0 : t); + if (pe->sysind != NO_PART && (pe->size == 0 + || pe->lowsec + pe->size > table[0].lowsec + table[0].size + || overlap(pe->lowsec + pe->size))) + op->flags|= OF_BAD; + break; + case O_KB: + /* Size of partitition in kilobytes. */ + sprintf(op->value, "%lu", entry2size(pe) / 2); + break; + default: + sprintf(op->value, "?? %d ??", op->type); + } + + if (device < 0 && computed(op->type)) strcpy(op->value, "?"); + + /* If a value overflows the print field then show a blank + * reverse video field. + */ + if ((n= strlen(op->value)) > op->len) { + n= 0; + op->flags|= OF_BAD; + } + + /* Right or left justified? */ + if (rjust(op->type)) { + memmove(op->value + (op->len - n), op->value, n); + memset(op->value, ' ', op->len - n); + } else { + memset(op->value + n, ' ', op->len - n); + } + op->value[op->len]= 0; + + if ((op->flags & (OF_ODD | OF_BAD)) == (oldflags & (OF_ODD | OF_BAD)) + && strcmp(op->value, oldvalue) == 0) { + /* The value did not change. */ + return; + } + + set_cursor(op->row, rjust(op->type) ? op->col - (op->len-1) : op->col); + + if (op->flags & OF_BAD) tputs(t_so, 1, putchr); + else + if (op->flags & OF_ODD) tputs(t_md, 1, putchr); + putstr(op->value); + if (op->flags & OF_BAD) tputs(t_se, 1, putchr); + else + if (op->flags & OF_ODD) tputs(t_me, 1, putchr); +} + +void display(void) +/* Repaint all objects that changed. */ +{ + object_t *op; + + for (op= world; op != nil; op= op->next) print(op); +} + +int typing; /* Set if a digit has been typed to set a value. */ +int magic; /* Changes when using the magic key. */ + +void event(int ev, object_t *op); + +void m_redraw(int ev, object_t *op) +/* Redraw the screen. */ +{ + object_t *op2; + + if (ev != ctrl('L')) return; + + clear_screen(); + for (op2= world; op2 != nil; op2= op2->next) op2->value[0]= 0; +} + +void m_toggle(int ev, object_t *op) +/* Toggle between the driver and alternate geometry. */ +{ + unsigned t; + + if (ev != 'X') return; + if (alt_cyls == cylinders && alt_heads == heads && alt_secs == sectors) + return; + + t= cylinders; cylinders= alt_cyls; alt_cyls= t; + t= heads; heads= alt_heads; alt_heads= t; + t= sectors; sectors= alt_secs; alt_secs= t; + dirty= 1; + recompute0(); +} + +char size_last[]= "Size"; + +void m_orientation(int ev, object_t *op) +{ + if (ev != ' ') return; + + switch (howend) { + case SIZE: + howend= LAST; + strcpy(size_last, "Last"); + break; + case LAST: + howend= SIZE; + strcpy(size_last, "Size"); + } +} + +void m_move(int ev, object_t *op) +/* Move to the nearest modifiably object in the intended direction. Objects + * on the same row or column are really near. + */ +{ + object_t *near, *op2; + unsigned dist, d2, dr, dc; + + if (ev != 'h' && ev != 'j' && ev != 'k' && ev != 'l' && ev != 'H') + return; + + if (device < 0) { + /* No device open? Then try to read first. */ + event('r', op); + if (device < 0) return; + } + + near= op; + dist= -1; + + for (op2= world; op2 != nil; op2= op2->next) { + if (op2 == op || !(op2->flags & OF_MOD)) continue; + + dr= abs(op2->row - op->row); + dc= abs(op2->col - op->col); + + d2= 25*dr*dr + dc*dc; + if (op2->row != op->row && op2->col != op->col) d2+= 1000; + + switch (ev) { + case 'h': /* Left */ + if (op2->col >= op->col) d2= -1; + break; + case 'j': /* Down */ + if (op2->row <= op->row) d2= -1; + break; + case 'k': /* Up */ + if (op2->row >= op->row) d2= -1; + break; + case 'l': /* Right */ + if (op2->col <= op->col) d2= -1; + break; + case 'H': /* Home */ + if (op2->type == O_DEV) d2= 0; + } + if (d2 < dist) { near= op2; dist= d2; } + } + if (near != op) event(E_LEAVE, op); + event(E_ENTER, near); +} + +void m_updown(int ev, object_t *op) +/* Move a partition table entry up or down. */ +{ + int i, j; + struct part_entry tmp; + int tmpx; + + if (ev != ctrl('K') && ev != ctrl('J')) return; + if (op->entry == nil) return; + + i= op->entry - table; + if (ev == ctrl('K')) { + if (i <= 1) return; + j= i-1; + } else { + if (i >= NR_PARTITIONS) return; + j= i+1; + } + + tmp= table[i]; table[i]= table[j]; table[j]= tmp; + tmpx= existing[i]; existing[i]= existing[j]; existing[j]= tmpx; + sort(); + dirty= 1; + event(ev == ctrl('K') ? 'k' : 'j', op); +} + +void m_enter(int ev, object_t *op) +/* We've moved onto this object. */ +{ + if (ev != E_ENTER && ev != ' ' && ev != '<' && ev != '>' && ev != 'X') + return; + curobj= op; + typing= 0; + magic= 0; +} + +void m_leave(int ev, object_t *op) +/* About to leave this object. */ +{ + if (ev != E_LEAVE) return; +} + +int within(unsigned *var, unsigned low, unsigned value, unsigned high) +/* Only set *var to value if it looks reasonable. */ +{ + if (low <= value && value <= high) { + *var= value; + return 1; + } else + return 0; +} + +int lwithin(unsigned long *var, unsigned long low, unsigned long value, + unsigned long high) +{ + if (low <= value && value <= high) { + *var= value; + return 1; + } else + return 0; +} + +int nextdevice(object_t *op, int delta) +/* Select the next or previous device from the device list. */ +{ + dev_t rdev; + + if (offset != 0) return 0; + if (dirty) event(E_WRITE, op); + if (dirty) return 0; + + if (device >= 0) { + (void) close(device); + device= -1; + } + recompute0(); + + rdev= curdev->rdev; + if (delta < 0) { + do + curdev= curdev->prev; + while (delta < -1 && major(curdev->rdev) == major(rdev) + && curdev->rdev < rdev); + } else { + do + curdev= curdev->next; + while (delta > 1 && major(curdev->rdev) == major(rdev) + && curdev->rdev > rdev); + } + return 1; +} + +void check_ind(struct part_entry *pe) +/* If there are no other partitions then make this new one active. */ +{ + struct part_entry *pe2; + + if (pe->sysind != NO_PART) return; + + for (pe2= table + 1; pe2 < table + 1 + NR_PARTITIONS; pe2++) + if (pe2->sysind != NO_PART || pe2->bootind & ACTIVE_FLAG) break; + + if (pe2 == table + 1 + NR_PARTITIONS) pe->bootind= ACTIVE_FLAG; +} + +int check_existing(struct part_entry *pe) +/* Check and if not ask if an existing partition may be modified. */ +{ + static int expert= 0; + int c; + + if (expert || pe == nil || !existing[pe - table]) return 1; + + stat_start(1); + putstr("Do you wish to modify existing partitions? (y/n) "); + fflush(stdout); + while ((c= getchar()) != 'y' && c != 'n') {} + putchr(c); + stat_end(3); + return (expert= (c == 'y')); +} + +void m_modify(int ev, object_t *op) +/* Increment, decrement, set, or toggle the value of an object, using + * arithmetic tricks the author doesn't understand either. + */ +{ + object_t *op2; + struct part_entry *pe= op->entry; + int mul, delta; + unsigned level= 1; + unsigned long surplus; + int radix= op->type == O_TYPHEX ? 0x10 : 10; + unsigned long t; + + if (device < 0 && op->type != O_DEV) return; + + switch (ev) { + case '-': + mul= radix; delta= -1; typing= 0; + break; + case '+': + mul= radix; delta= 1; typing= 0; + break; + case '\b': + if (!typing) return; + mul= 1; delta= 0; + break; + case '\r': + typing= 0; + return; + default: + if ('0' <= ev && ev <= '9') + delta= ev - '0'; + else + if (radix == 0x10 && 'a' <= ev && ev <= 'f') + delta= ev - 'a' + 10; + else + if (radix == 0x10 && 'A' <= ev && ev <= 'F') + delta= ev - 'A' + 10; + else + return; + + mul= typing ? radix*radix : 0; + typing= 1; + } + magic= 0; + + if (!check_existing(pe)) return; + + switch (op->type) { + case O_DEV: + if (ev != '-' && ev != '+') return; + if (!nextdevice(op, delta)) return; + break; + case O_CYL: + if (!within(&cylinders, 1, + cylinders * mul / radix + delta, 1024)) return; + recompute0(); + break; + case O_HEAD: + if (!within(&heads, 1, heads * mul / radix + delta, 255)) + return; + recompute0(); + break; + case O_SEC: + if (!within(§ors, 1, sectors * mul / radix + delta, 63)) + return; + recompute0(); + break; + case O_NUM: + if (ev != '-' && ev != '+') return; + for (op2= world; op2 != nil; op2= op2->next) { + if (op2->type == O_NUM && ev == '+') + op2->entry->bootind= 0; + } + op->entry->bootind= ev == '+' ? ACTIVE_FLAG : 0; + break; + case O_TYPHEX: + check_ind(pe); + pe->sysind= pe->sysind * mul / radix + delta; + break; + case O_TYPTXT: + if (ev != '-' && ev != '+') return; + check_ind(pe); + pe->sysind= round_sysind(pe->sysind, delta); + break; + case O_SCYL: + level= heads; + case O_SHEAD: + level*= sectors; + case O_SSEC: + if (op->type != O_SCYL && ev != '-' && ev != '+') return; + case O_BASE: + if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe)); + t= pe->lowsec; + surplus= t % level; + if (!lwithin(&t, 0L, + (t / level * mul / radix + delta) * level + surplus, + MAXSIZE)) return; + if (howend == LAST || op->type != O_BASE) + pe->size-= t - pe->lowsec; + pe->lowsec= t; + check_ind(pe); + if (pe->sysind == NO_PART) pe->sysind= MINIX_PART; + break; + case O_LCYL: + level= heads; + case O_LHEAD: + level*= sectors; + case O_LSEC: + if (op->type != O_LCYL && ev != '-' && ev != '+') return; + + if (pe->sysind == NO_PART) memset(pe, 0, sizeof(*pe)); + t= pe->lowsec + pe->size - 1 + level; + surplus= t % level - mul / radix * level; + if (!lwithin(&t, 0L, + (t / level * mul / radix + delta) * level + surplus, + MAXSIZE)) return; + pe->size= t - pe->lowsec + 1; + check_ind(pe); + if (pe->sysind == NO_PART) pe->sysind= MINIX_PART; + break; + case O_KB: + level= 2; + if (mul == 0) pe->size= 0; /* new value, no surplus */ + case O_SIZE: + if (pe->sysind == NO_PART) { + if (op->type == O_KB || howend == SIZE) { + /* First let loose magic to set the base. */ + event('m', op); + magic= 0; + pe->size= 0; + event(ev, op); + return; + } + memset(pe, 0, sizeof(*pe)); + } + t= (op->type == O_KB || howend == SIZE) ? pe->size + : pe->lowsec + pe->size - 1; + surplus= t % level; + if (!lwithin(&t, 0L, + (t / level * mul / radix + delta) * level + surplus, + MAXSIZE)) return; + pe->size= (op->type == O_KB || howend == SIZE) ? t : + t - pe->lowsec + 1; + check_ind(pe); + if (pe->sysind == NO_PART) pe->sysind= MINIX_PART; + break; + default: + return; + } + + /* The order among the entries may have changed. */ + sort(); + dirty= 1; +} + +unsigned long spell[3 + 4 * (1+NR_PARTITIONS)]; +int nspells; +objtype_t touching; + +void newspell(unsigned long charm) +/* Add a new spell, descending order for the base, ascending for the size. */ +{ + int i, j; + + if (charm - table[0].lowsec > table[0].size) return; + + for (i= 0; i < nspells; i++) { + if (charm == spell[i]) return; /* duplicate */ + + if (touching == O_BASE) { + if (charm == table[0].lowsec + table[0].size) return; + if ((spell[0] - charm) < (spell[0] - spell[i])) break; + } else { + if (charm == table[0].lowsec) return; + if ((charm - spell[0]) < (spell[i] - spell[0])) break; + } + } + for (j= ++nspells; j > i; j--) spell[j]= spell[j-1]; + spell[i]= charm; +} + +void m_magic(int ev, object_t *op) +/* Apply magic onto a base or size number. */ +{ + struct part_entry *pe= op->entry, *pe2; + int rough= (offset != 0 && extbase == 0); + + if (ev != 'm' || device < 0) return; + typing= 0; + + if (!check_existing(pe)) return; + + if (magic == 0) { + /* See what magic we can let loose on this value. */ + nspells= 1; + + /* First spell, the current value. */ + switch (op->type) { + case O_SCYL: + case O_SHEAD: /* Start of partition. */ + case O_SSEC: + case O_BASE: + touching= O_BASE; + spell[0]= pe->lowsec; + break; + case O_LCYL: + case O_LHEAD: + case O_LSEC: /* End of partition. */ + case O_KB: + case O_SIZE: + touching= O_SIZE; + spell[0]= pe->lowsec + pe->size; + break; + default: + return; + } + if (pe->sysind == NO_PART) { + memset(pe, 0, sizeof(*pe)); + check_ind(pe); + pe->sysind= MINIX_PART; + spell[0]= 0; + if (touching == O_SIZE) { + /* First let loose magic on the base. */ + object_t *op2; + + for (op2= world; op2 != nil; op2= op2->next) { + if (op2->row == op->row && + op2->type == O_BASE) { + event('m', op2); + } + } + magic= 0; + event('m', op); + return; + } + } + /* Avoid the first sector on the device. */ + if (spell[0] == table[0].lowsec) newspell(spell[0] + 1); + + /* Further interesting values are the the bases of other + * partitions or their ends. + */ + for (pe2= table; pe2 < table + 1 + NR_PARTITIONS; pe2++) { + if (pe2 == pe || pe2->sysind == NO_PART) continue; + if (pe2->lowsec == table[0].lowsec) + newspell(table[0].lowsec + 1); + else + newspell(pe2->lowsec); + newspell(pe2->lowsec + pe2->size); + if (touching == O_BASE && howend == SIZE) { + newspell(pe2->lowsec - pe->size); + newspell(pe2->lowsec + pe2->size - pe->size); + } + if (pe2->lowsec % sectors != 0) rough= 1; + } + /* Present values rounded up to the next cylinder unless + * the table is already a mess. Use "start + 1 track" instead + * of "start + 1 cylinder". Also add the end of the last + * cylinder. + */ + if (!rough) { + unsigned long n= spell[0]; + if (n == table[0].lowsec) n++; + n= (n + sectors - 1) / sectors * sectors; + if (n != table[0].lowsec + sectors) + n= (n + secpcyl - 1) / secpcyl * secpcyl; + newspell(n); + if (touching == O_SIZE) + newspell(table[0].size / secpcyl * secpcyl); + } + } + /* Magic has been applied, a spell needs to be chosen. */ + + if (++magic == nspells) magic= 0; + + if (touching == O_BASE) { + if (howend == LAST) pe->size-= spell[magic] - pe->lowsec; + pe->lowsec= spell[magic]; + } else + pe->size= spell[magic] - pe->lowsec; + + /* The order among the entries may have changed. */ + sort(); + dirty= 1; +} + +typedef struct diving { + struct diving *up; + struct part_entry old0; + char *oldsubname; + parttype_t oldparttype; + unsigned long oldoffset; + unsigned long oldextbase; +} diving_t; + +diving_t *diving= nil; + +void m_in(int ev, object_t *op) +/* Go down into a primary or extended partition. */ +{ + diving_t *newdiv; + struct part_entry *pe= op->entry, ext; + int n; + + if (ev != '>' || device < 0 || pe == nil || pe == &table[0] + || (!(pe->sysind == MINIX_PART && offset == 0) + && !ext_part(pe->sysind)) + || pe->size == 0) return; + + ext= *pe; + if (extbase != 0) ext.size= extbase + extsize - ext.lowsec; + + if (dirty) event(E_WRITE, op); + if (dirty) return; + if (device >= 0) { close(device); device= -1; } + + newdiv= alloc(sizeof(*newdiv)); + newdiv->old0= table[0]; + newdiv->oldsubname= curdev->subname; + newdiv->oldparttype= curdev->parttype; + newdiv->oldoffset= offset; + newdiv->oldextbase= extbase; + newdiv->up= diving; + diving= newdiv; + + table[0]= ext; + + n= strlen(diving->oldsubname); + curdev->subname= alloc((n + 3) * sizeof(curdev->subname[0])); + strcpy(curdev->subname, diving->oldsubname); + curdev->subname[n++]= ':'; + curdev->subname[n++]= '0' + (pe - table - 1); + curdev->subname[n]= 0; + + curdev->parttype= curdev->parttype == PRIMARY ? SUBPART : DUNNO; + offset= ext.lowsec; + if (ext_part(ext.sysind) && extbase == 0) { + extbase= ext.lowsec; + extsize= ext.size; + curdev->parttype= DUNNO; + } + + submerged= 1; + event('r', op); +} + +void m_out(int ev, object_t *op) +/* Go up from an extended or subpartition table to its enclosing. */ +{ + diving_t *olddiv; + + if (ev != '<' || diving == nil) return; + + if (dirty) event(E_WRITE, op); + if (dirty) return; + if (device >= 0) { close(device); device= -1; } + + olddiv= diving; + diving= olddiv->up; + + table[0]= olddiv->old0; + + free(curdev->subname); + curdev->subname= olddiv->oldsubname; + + curdev->parttype= olddiv->oldparttype; + offset= olddiv->oldoffset; + extbase= olddiv->oldextbase; + + free(olddiv); + + event('r', op); + if (diving == nil) submerged= 0; /* We surfaced. */ +} + +void installboot(unsigned char *bootblock, char *masterboot) +/* Install code from a master bootstrap into a boot block. */ +{ + FILE *mfp; + struct exec hdr; + int n; + char *err; + + if ((mfp= fopen(masterboot, "r")) == nil) { + err= strerror(errno); + goto m_err; + } + + n= fread(&hdr, sizeof(char), A_MINHDR, mfp); + if (ferror(mfp)) { + err= strerror(errno); + fclose(mfp); + goto m_err; + } + + if (n < A_MINHDR || BADMAG(hdr) || hdr.a_cpu != A_I8086) { + err= "Not an 8086 executable"; + fclose(mfp); + goto m_err; + } + + if (hdr.a_text + hdr.a_data > PART_TABLE_OFF) { + err= "Does not fit in a boot sector"; + fclose(mfp); + goto m_err; + } + + fseek(mfp, hdr.a_hdrlen, 0); + fread(bootblock, sizeof(char), (size_t) (hdr.a_text + hdr.a_data), mfp); + if (ferror(mfp)) { + err= strerror(errno); + fclose(mfp); + goto m_err; + } + fclose(mfp); + + /* Bootstrap installed. */ + return; + + m_err: + stat_start(1); + printf("%s: %s", masterboot, err); + stat_end(5); +} + +ssize_t boot_readwrite(int rw) +/* Read (0) or write (1) the boot sector. */ +{ + u64_t off64 = mul64u(offset, SECTOR_SIZE); + int r; + +#if __minix_vmd + /* Minix-vmd has a 64 bit seek. */ + if (fcntl(device, F_SEEK, off64) < 0) return -1; +#else + /* Minix has to gross things with the partition base. */ + struct partition geom0, geom_seek; + + if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) { + /* Move partition base. */ + if (ioctl(device, DIOCGETP, &geom0) < 0) return -1; + geom_seek.base = add64(geom0.base, off64); + geom_seek.size = cvu64(cmp64(add64u(off64, SECTOR_SIZE), + geom0.size) <= 0 ? STATIC_BLOCK_SIZE : 0); + sync(); + if (ioctl(device, DIOCSETP, &geom_seek) < 0) return -1; + if (lseek(device, (off_t) 0, SEEK_SET) == -1) return -1; + } else { + /* Can reach this point normally. */ + if (lseek(device, (off_t) offset * SECTOR_SIZE, SEEK_SET) == -1) + return -1; + } +#endif + + switch (rw) { + case 0: r= read(device, bootblock, SECTOR_SIZE); break; + case 1: r= write(device, bootblock, SECTOR_SIZE); break; + } + +#if !__minix_vmd + if (offset >= (LONG_MAX / SECTOR_SIZE - 1)) { + /* Restore partition base and size. */ + sync(); + if (ioctl(device, DIOCSETP, &geom0) < 0) return -1; + } +#endif + return r; +} + +int bigenough(region_t *reg) +{ + int sectors; + if(reg->used_part) + sectors = reg->used_part->size; + else + sectors = reg->free_sec_last - reg->free_sec_start + 1; + + return sectors >= MIN_REGION_SECTORS; +} + +int cylinderalign(region_t *reg) +{ + if(reg->used_part) { + if(reg->used_part->lowsec != table[0].lowsec + sectors + && (reg->used_part->lowsec % secpcyl)) { + int extra; + extra = secpcyl - (reg->used_part->lowsec % secpcyl); + reg->used_part->lowsec += extra; + reg->used_part->size -= extra; + } + if((reg->used_part->size+1) % secpcyl) { + reg->used_part->size -= secpcyl - (reg->used_part->size % secpcyl); + } + return reg->used_part->size > 0; + } + + if(reg->free_sec_start != table[0].lowsec + sectors && (reg->free_sec_start % secpcyl)) { + /* Start is unaligned. Round up. */ + reg->free_sec_start += secpcyl - (reg->free_sec_start % secpcyl); + } + if(reg->free_sec_last % secpcyl) { + /* End is unaligned. Round down. */ + reg->free_sec_last -= reg->free_sec_last % secpcyl; + } + + /* Return nonzero if anything remains of the region after rounding. */ + return reg->free_sec_last > reg->free_sec_start; +} + +void m_read(int ev, object_t *op) +/* Read the partition table from the current device. */ +{ + int si, i, mode, n, r, free_sec, v; + struct part_entry *pe; + + if (ev != 'r' || device >= 0) return; + + /* Open() may cause kernel messages: */ + stat_start(0); + fflush(stdout); + + if (((device= open(curdev->name, mode= O_RDWR, 0666)) < 0 + && (errno != EACCES + || (!nordonly && (device= open(curdev->name, mode= O_RDONLY)) < 0))) + ) { + stat_start(1); + if(!probing) + printf("%s: %s", curdev->name, strerror(errno)); + stat_end(5); + if (device >= 0) { close(device); device= -1; } + return; + } + + if(probing) { + v = HZ/2; + ioctl(device, DIOCTIMEOUT, &v); + } + + /* Assume up to five lines of kernel messages. */ + statusrow+= 5-1; + stat_end(5); + + if (mode == O_RDONLY) { + stat_start(1); + printf("%s: Readonly", curdev->name); + stat_end(5); + } + memset(bootblock, 0, sizeof(bootblock)); + + n= boot_readwrite(0); + + if (n <= 0) stat_start(1); + if (n < 0) { + if(!probing) + printf("%s: %s", curdev->name, strerror(errno)); + close(device); + device= -1; + } else + if (n < SECTOR_SIZE) { + if(probing) { + close(device); + device= -1; + return; + } + printf("%s: Unexpected EOF", curdev->subname); + } + if (n <= 0) stat_end(5); + + if (n < SECTOR_SIZE) n= SECTOR_SIZE; + + memcpy(table+1, bootblock+PART_TABLE_OFF, + NR_PARTITIONS * sizeof(table[1])); + for (i= 1; i <= NR_PARTITIONS; i++) { + if ((table[i].bootind & ~ACTIVE_FLAG) != 0) break; + } + if (i <= NR_PARTITIONS || bootblock[510] != 0x55 + || bootblock[511] != 0xAA) { + /* Invalid boot block, install bootstrap, wipe partition table. + */ + memset(bootblock, 0, sizeof(bootblock)); + installboot(bootblock, MASTERBOOT); + memset(table+1, 0, NR_PARTITIONS * sizeof(table[1])); + stat_start(1); + if(!probing) + printf("%s: Invalid partition table (reset)", curdev->subname); + stat_end(5); + } + + /* Fix an extended partition table up to something mere mortals can + * understand. Record already defined partitions. + */ + for (i= 1; i <= NR_PARTITIONS; i++) { + pe= &table[i]; + if (extbase != 0 && pe->sysind != NO_PART) + pe->lowsec+= ext_part(pe->sysind) ? extbase : offset; + existing[i]= pe->sysind != NO_PART; + } + geometry(); + dirty= 0; + + /* Warn about grave dangers ahead. */ + if (extbase != 0) { + stat_start(1); + printf("Warning: You are in an extended partition."); + stat_end(5); + } + + free_sec = table[0].lowsec + sectors; + + /* Create region data used in autopart mode. */ + free_regions = used_regions = nr_regions = nr_partitions = 0; + for(si = 1; si <= NR_PARTITIONS; si++) { + i = sort_index[si]; + if(i < 1 || i > NR_PARTITIONS) { + printf("Sorry, something unexpected has happened (%d out of range).\n", i); + exit(1); + } + + if(table[i].sysind == NO_PART) + break; + if(table[i].lowsec > free_sec) { + /* Free region before this partition. */ + regions[nr_regions].free_sec_start = free_sec; + regions[nr_regions].free_sec_last = table[i].lowsec-1; + regions[nr_regions].used_part = NULL; + if(cylinderalign(®ions[nr_regions]) && + bigenough(®ions[nr_regions])) { + nr_regions++; + free_regions++; + } + } + + if(autopartmode && si > 1) { + if(table[i].lowsec < table[sort_index[si-1]].lowsec || + table[i].lowsec < table[sort_index[si-1]].lowsec + table[sort_index[si-1]].size) { + printf("Sanity check failed - partitions overlap.\n" + "Please use expert mode to correct it.\n"); + exit(1); + } + } + + regions[nr_regions].used_part = &table[i]; + free_sec = table[i].lowsec+table[i].size; + nr_partitions++; + + if(bigenough(®ions[nr_regions])) { + nr_regions++; + used_regions++; + } + } + + /* Special case: space after partitions. */ + if(free_sec < table[0].size-1) { + regions[nr_regions].free_sec_start = free_sec; + regions[nr_regions].free_sec_last = table[0].lowsec + table[0].size-1; + regions[nr_regions].used_part = NULL; + if(cylinderalign(®ions[nr_regions]) && + bigenough(®ions[nr_regions])) { + nr_regions++; + free_regions++; + } + } +} + +void m_write(int ev, object_t *op) +/* Write the partition table back if modified. */ +{ + int c; + struct part_entry new_table[NR_PARTITIONS], *pe; + + if (ev != 'w' && ev != E_WRITE) return; + if (device < 0) { dirty= 0; return; } + if (!dirty) { + if (ev == 'w') { + stat_start(1); + printf("%s is not changed, or has already been written", + curdev->subname); + stat_end(2); + } + return; + } + + if (bootblock[510] != 0x55 || bootblock[511] != 0xAA) { + /* Invalid boot block, warn user. */ + stat_start(1); + printf("Warning: About to write a new table on %s", + curdev->subname); + if(autopartmode) printf("\n"); + stat_end(5); + } + if (extbase != 0) { + /* Will this stop him? Probably not... */ + stat_start(1); + printf("You have changed an extended partition. Bad Idea."); + stat_end(5); + } + + if(!autopartmode) { + stat_start(1); + putstr("Save partition table? (y/n) "); + fflush(stdout); + + while ((c= getchar()) != 'y' && c != 'n' && c != ctrl('?')) {} + + if (c == ctrl('?')) putstr("DEL"); else putchr(c); + stat_end(5); + if (c == 'n' && ev == E_WRITE) dirty= 0; + if (c != 'y') return; + } + + memcpy(new_table, table+1, NR_PARTITIONS * sizeof(table[1])); + for (pe= new_table; pe < new_table + NR_PARTITIONS; pe++) { + if (pe->sysind == NO_PART) { + memset(pe, 0, sizeof(*pe)); + } else { + abs2dos(&pe->start_head, pe->lowsec); + abs2dos(&pe->last_head, pe->lowsec + pe->size - 1); + + /* Fear and loathing time: */ + if (extbase != 0) + pe->lowsec-= ext_part(pe->sysind) + ? extbase : offset; + } + } + memcpy(bootblock+PART_TABLE_OFF, new_table, sizeof(new_table)); + bootblock[510]= 0x55; + bootblock[511]= 0xAA; + + if (boot_readwrite(1) < 0) { + stat_start(1); + printf("%s: %s", curdev->name, strerror(errno)); + stat_end(5); + return; + } + dirty= 0; +} + +void m_shell(int ev, object_t *op) +/* Shell escape, to do calculations for instance. */ +{ + int r, pid, status; + void (*sigint)(int), (*sigquit)(int), (*sigterm)(int); + + if (ev != 's') return; + + reset_tty(); + fflush(stdout); + + switch (pid= fork()) { + case -1: + stat_start(1); + printf("can't fork: %s\n", strerror(errno)); + stat_end(3); + break; + case 0: + if (device >= 0) (void) close(device); + execl("/bin/sh", "sh", (char *) nil); + r= errno; + stat_start(1); + printf("/bin/sh: %s\n", strerror(errno)); + stat_end(3); + exit(127); + } + sigint= signal(SIGINT, SIG_IGN); + sigquit= signal(SIGQUIT, SIG_IGN); + sigterm= signal(SIGTERM, SIG_IGN); + while (pid >= 0 && (r= wait(&status)) >= 0 && r != pid) {} + (void) signal(SIGINT, sigint); + (void) signal(SIGQUIT, sigquit); + (void) signal(SIGTERM, sigterm); + tty_raw(); + if (pid < 0) + ; + else + if (WIFEXITED(status) && WEXITSTATUS(status) == 127) + stat_start(0); /* Match the stat_start in the child. */ + else + event(ctrl('L'), op); +} + +void m_dump(int ev, object_t *op) +/* Raw dump of the partition table. */ +{ + struct part_entry table[NR_PARTITIONS], *pe; + int i; + unsigned chs[3]; + + if (ev != 'p' || device < 0) return; + + memcpy(table, bootblock+PART_TABLE_OFF, + NR_PARTITIONS * sizeof(table[0])); + for (i= 0; i < NR_PARTITIONS; i++) { + pe= &table[i]; + stat_start(0); + dos2chs(&pe->start_head, chs); + printf("%2d%c %02X%15d%5d%4d", + i+1, + pe->bootind & ACTIVE_FLAG ? '*' : ' ', + pe->sysind, + chs[0], chs[1], chs[2]); + dos2chs(&pe->last_head, chs); + printf("%6d%5d%4d%10lu%10ld%9lu", + chs[0], chs[1], chs[2], + pe->lowsec, + howend == SIZE ? pe->size : pe->size + pe->lowsec - 1, + pe->size / 2); + stat_end(10); + } + stat_start(0); + printf("(Raw dump of the original %.40s table)", + curdev->subname); + stat_end(10); +} + +int quitting= 0; + +void m_quit(int ev, object_t *op) +/* Write the partition table if modified and exit. */ +{ + if (ev != 'q' && ev != 'x') return; + + quitting= 1; + + if (dirty) event(E_WRITE, op); + if (dirty) quitting= 0; +} + +void m_help(int ev, object_t *op) +/* For people without a clue; let's hope they can find the '?' key. */ +{ + static struct help { + char *keys; + char *what; + } help[]= { + { "? !", "This help / more advice!" }, + { "+ - (= _ PgUp PgDn)","Select/increment/decrement/make active" }, + { "0-9 (a-f)", "Enter value" }, + { "hjkl (arrow keys)", "Move around" }, + { "CTRL-K CTRL-J", "Move entry up/down" }, + { "CTRL-L", "Redraw screen" }, + { ">", "Start a subpartition table" }, + { "<", "Back to the primary partition table" }, + { "m", "Cycle through magic values" }, + { "spacebar", "Show \"Size\" or \"Last\"" }, + { "r w", "Read/write partition table" }, + { "p s q x", "Raw dump / Shell escape / Quit / Exit" }, + { "y n DEL", "Answer \"yes\", \"no\", \"cancel\"" }, + }; + static char *advice[] = { +"* Choose a disk with '+' and '-', then hit 'r'.", +"* To change any value: Move to it and use '+', '-' or type the desired value.", +"* To make a new partition: Move over to the Size or Kb field of an unused", +" partition and type the size. Hit the 'm' key to pad the partition out to", +" a cylinder boundary. Hit 'm' again to pad it out to the end of the disk.", +" You can hit 'm' more than once on a base or size field to see several", +" interesting values go by. Note: Other Operating Systems can be picky about", +" partitions that are not padded to cylinder boundaries. Look for highlighted", +" head or sector numbers.", +"* To reuse a partition: Change the type to MINIX.", +"* To delete a partition: Type a zero in the hex Type field.", +"* To make a partition active: Type '+' in the Num field.", +"* To study the list of keys: Type '?'.", + }; + + if (ev == '?') { + struct help *hp; + + for (hp= help; hp < arraylimit(help); hp++) { + stat_start(0); + printf("%-25s - %s", hp->keys, hp->what); + stat_end(0); + } + stat_start(0); + putstr("Things like "); + putstr(t_so); putstr("this"); putstr(t_se); + putstr(" must be checked, but "); + putstr(t_md); putstr("this"); putstr(t_me); + putstr(" is not really a problem"); + stat_end(0); + } else + if (ev == '!') { + char **ap; + + for (ap= advice; ap < arraylimit(advice); ap++) { + stat_start(0); + putstr(*ap); + stat_end(0); + } + } +} + +void event(int ev, object_t *op) +/* Simply call all modifiers for an event, each one knows when to act. */ +{ + m_help(ev, op); + m_redraw(ev, op); + m_toggle(ev, op); + m_orientation(ev, op); + m_move(ev, op); + m_updown(ev, op); + m_enter(ev, op); + m_leave(ev, op); + m_modify(ev, op); + m_magic(ev, op); + m_in(ev, op); + m_out(ev, op); + m_read(ev, op); + m_write(ev, op); + m_shell(ev, op); + m_dump(ev, op); + m_quit(ev, op); +} + +int keypress(void) +/* Get a single keypress. Translate compound keypresses (arrow keys) to + * their simpler equivalents. + */ +{ + char ch; + int c; + int esc= 0; + + set_cursor(curobj->row, curobj->col); + fflush(stdout); + + do { + if (read(0, &ch, sizeof(ch)) < 0) fatal("stdin"); + c= (unsigned char) ch; + switch (esc) { + case 0: + switch (c) { + case ctrl('['): esc= 1; break; + case '_': c= '-'; break; + case '=': c= '+'; break; + } + break; + case 1: + esc= c == '[' ? 2 : 0; + break; + case 2: + switch (c) { + case 'D': c= 'h'; break; + case 'B': c= 'j'; break; + case 'A': c= 'k'; break; + case 'C': c= 'l'; break; + case 'H': c= 'H'; break; + case 'U': + case 'S': c= '-'; break; + case 'V': + case 'T': c= '+'; break; + } + /*FALL THROUGH*/ + default: + esc= 0; + } + } while (esc > 0); + + switch (c) { + case ctrl('B'): c= 'h'; break; + case ctrl('N'): c= 'j'; break; + case ctrl('P'): c= 'k'; break; + case ctrl('F'): c= 'l'; break; + } + + return c; +} + +void mainloop(void) +/* Get keypress, handle event, display results, reset screen, ad infinitum. */ +{ + int key; + + while (!quitting) { + stat_reset(); + + key= keypress(); + + event(key, curobj); + + display(); + } +} + +char * +prettysizeprint(int kb) +{ + static char str[20]; + char unit = 'k'; + if(kb >= 5*1024) { + kb /= 1024; + unit = 'M'; + if(kb >= 5*1024) { + kb /= 1024; + unit = 'G'; + } + } + sprintf(str, "%d%cB", kb, unit); + return str; +} + +region_t * +select_region(void) +{ + int r, rem, rn; + static char line[100]; + region_t *reg; + int nofree = 0; + + if(nr_regions < 1) { + printf("\nNo regions found - maybe the drive is too small.\n" + "Please try expert mode.\n"); + exit(1); + } + + if(nr_partitions >= NR_PARTITIONS || !free_regions) { + if(free_regions) { + printf("\nThere is no slot available to use any of the free regions.\n"); + nofree = 1; + } else { + printf("There are no free regions.\n"); + } + printf("Please select a region that is in use to \n" + "overwrite it, or use expert mode to free up space.\n"); + } + + do { + reg = regions; + printf("\nI've found the following region%s on this disk (%s).\n" + "(I'm only showing ones of at least %dMB.)\n\n", + SORNOT(nr_regions), prettysizeprint(table[0].size/2), + MIN_REGION_MB); + for(r = 0; r < nr_regions; r++, reg++) { + unsigned long units; + if(reg->used_part) { + char *name; + name = typ2txt(reg->used_part->sysind); + if(!name || strlen(name) < 2) + name = "unknown system"; + printf("\033[31m%2d. in use by %s", r, name); + units = reg->used_part->size / 2; + printf("\033[0m (%s)\n", prettysizeprint(units)); + } else if(!nofree) { + printf("\033[36m%2d. free space", r); + units = ((reg->free_sec_last - reg->free_sec_start+1))/2; + printf("\033[0m (%s)\n", prettysizeprint(units)); + } + } + + if(nofree) { + printf("\nOnly the expert mode can free a slot to use the free space.\n"); + } + + if(nr_regions > 1) { + printf("\nPlease enter region number you want to use: "); + fflush(NULL); + + if(!fgets(line, sizeof(line)-2, stdin)) + exit(1); + + if(sscanf(line, "%d", &rn) != 1) + continue; + + if(rn < 0 || rn >= nr_regions) { + printf("Region number %d is out of range.\n", rn); + continue; + } + + if(nofree && !regions[rn].used_part) { + printf("That region number isn't available.\n"); + continue; + } + + printf("Really use region number %d? Please enter 'yes' or 'no': ", rn); + fflush(NULL); + } else { + rn = 0; + printf("\nUse it? Please enter 'yes' or 'no': "); + fflush(NULL); + } + + if(!fgets(line, sizeof(line)-2, stdin)) + exit(1); + } while(strncmp(line, "yes", 3)); + + return(®ions[rn]); +} + +device_t * +select_disk(void) +{ +#define MAX_DEVICES 100 + static struct { + device_t *dev; + int free_regions, used_regions, sectors; + } devices[MAX_DEVICES]; + int i, choice, drives; + static char line[500]; + + printf("Probing for disks. This may take a short while.\n" + "You can ignore errors while probing. If the system hangs,\n" + "please try expert mode.\n\n"); + + do { + i = 0; + curdev=firstdev; + + for(; i < MAX_DEVICES;) { + m_read('r', NULL); + if(device >= 0) { + devices[i].dev = curdev; + devices[i].free_regions = free_regions; + devices[i].used_regions = used_regions; + devices[i].sectors = table[0].size; + i++; + } + + nextdevice(NULL, 1); + if(curdev == firstdev) + break; + } + + drives = i; + + if(drives < 1) { + printf("\nFound no drives - can't partition.\n"); + exit(1); + } + + printf("\nProbing done; %d drive%s found.\n", drives, SORNOT(drives)); + + printf("\nI've found the following drive%s on your system.\n\n", SORNOT(drives)); + + for(i = 0; i < drives; i++) { + if(drives > 1) + printf(" %2d. ", i); + else printf(" "); + printf(" (%s) %d allocated region%s", + devices[i].dev->name, + devices[i].used_regions, SORNOT(devices[i].used_regions)); + if(devices[i].used_regions < NR_PARTITIONS) { + printf(", %d unallocated one%s ", + devices[i].free_regions, SORNOT(devices[i].free_regions)); + } + printf(" (%s)\n", prettysizeprint(devices[i].sectors/2)); + } + + if(drives > 1) { + printf("\nPlease enter disk number you want to use: "); + fflush(NULL); + if(!fgets(line, sizeof(line)-2, stdin)) + exit(1); + if(sscanf(line, "%d", &choice) != 1) continue; + if(choice < 0 || choice >= i) { + printf("Number out of range.\n"); + continue; + } + printf("\nUse disk number %d (%s)? ", + choice, devices[choice].dev->name); + fflush(NULL); + if(!fgets(line, sizeof(line)-2, stdin)) + exit(1); + } else { + printf("\nUse it? "); + choice = 0; + fflush(NULL); + if(!fgets(line, sizeof(line)-2, stdin)) + exit(1); + if(line[0] != 'y' && line[0] != 'Y') + exit(1); + } + } while(line[0] != 'y' && line[0] != 'Y'); + return devices[choice].dev; +} + +int +scribble_region(region_t *reg) +{ + int ex, trunc = 0, changed = 0, i; + struct part_entry *newpart; + if(reg->used_part && reg->used_part->size > MAX_REGION_SECTORS) { + reg->used_part->size = MAX_REGION_SECTORS; + trunc = 1; + changed = 1; + cylinderalign(reg); + } + if(!reg->used_part) { + ex = reg->free_sec_last - reg->free_sec_start + 1; + if(ex > MAX_REGION_SECTORS) { + reg->free_sec_last -= ex - MAX_REGION_SECTORS; + trunc = 1; + changed = 1; + cylinderalign(reg); + } + } + if(trunc) { + printf("\nShrunk region to %dMB.\n", MAX_REGION_MB); + } + if(!reg->used_part) { + for(i = 1; i <= NR_PARTITIONS; i++) + if(table[i].sysind == NO_PART) + break; + if(i > NR_PARTITIONS) { + /* Bug, should've been caught earlier. */ + printf("Couldn't find a free slot. Please try expert mode.\n"); + exit(1); + } + newpart = &table[i]; + newpart->lowsec = reg->free_sec_start; + newpart->size = reg->free_sec_last - reg->free_sec_start + 1; + changed = 1; + } else newpart = reg->used_part; + newpart->sysind = MINIX_PART; + changed = 1; + + return changed; +} + +int +do_autopart(void) +{ + region_t *r; + + nordonly = 1; + probing = 1; + autopartmode = 1; + + /* Select drive. */ + do { + curdev = select_disk(); + } while(!curdev); + + if(device >= 0) { + close(device); + device = -1; + } + recompute0(); + + /* Read contents. */ + m_read('r', NULL); + + /* Show regions. */ + do { + r = select_region(); + } while(!r); + + /* Write things. */ + if(scribble_region(r)) { + dirty = 1; + m_write('w', NULL); + return !dirty; + } + + return 1; +} + +int main(int argc, char **argv) +{ + object_t *op; + int i, r, key; + struct part_entry *pe; + char *name; + int autopart = 0; + + /* Autopilot mode if invoked as autopart. */ + if(!(name = strrchr(argv[0], '/'))) name = argv[0]; + else name++; + if(!strcmp(name, "autopart")) + autopart = 1; + + if(!autopart) { + /* Define a few objects to show on the screen. First text: */ + op= newobject(O_INFO, 0, 0, 2, 19); + op= newobject(O_TEXT, 0, 0, 22, 13); op->text= "----first----"; + op= newobject(O_TEXT, 0, 0, 37, 13); op->text= "--geom/last--"; + op= newobject(O_TEXT, 0, 0, 52, 18); op->text= "------sectors-----"; + op= newobject(O_TEXT, 0, 1, 4, 6); op->text= "Device"; + op= newobject(O_TEXT, 0, 1, 23, 12); op->text= "Cyl Head Sec"; + op= newobject(O_TEXT, 0, 1, 38, 12); op->text= "Cyl Head Sec"; + op= newobject(O_TEXT, 0, 1, 56, 4); op->text= "Base"; + op= newobject(O_TEXT, 0, 1, 66, 4); op->text= size_last; + op= newobject(O_TEXT, 0, 1, 78, 2); op->text= "Kb"; + op= newobject(O_TEXT, 0, 4, 0, 15); op->text= "Num Sort Type"; + + /* The device is the current object: */ + curobj= newobject(O_DEV, OF_MOD, 2, 4, 15); + op= newobject(O_SUB, 0, 3, 4, 15); + + /* Geometry: */ + op= newobject(O_CYL, OF_MOD, 2, 40, 5); op->entry= &table[0]; + op= newobject(O_HEAD, OF_MOD, 2, 45, 3); op->entry= &table[0]; + op= newobject(O_SEC, OF_MOD, 2, 49, 2); op->entry= &table[0]; + + /* Objects for the device: */ + op= newobject(O_SCYL, 0, 3, 25, 5); op->entry= &table[0]; + op= newobject(O_SHEAD, 0, 3, 30, 3); op->entry= &table[0]; + op= newobject(O_SSEC, 0, 3, 34, 2); op->entry= &table[0]; + op= newobject(O_LCYL, 0, 3, 40, 5); op->entry= &table[0]; + op= newobject(O_LHEAD, 0, 3, 45, 3); op->entry= &table[0]; + op= newobject(O_LSEC, 0, 3, 49, 2); op->entry= &table[0]; + op= newobject(O_BASE, 0, 3, 59, 9); op->entry= &table[0]; + op= newobject(O_SIZE, 0, 3, 69, 9); op->entry= &table[0]; + op= newobject(O_KB, 0, 3, 79, 9); op->entry= &table[0]; + + /* Objects for each partition: */ + for (r= 5, pe= table+1; pe <= table+NR_PARTITIONS; r++, pe++) { + op= newobject(O_NUM, OF_MOD, r, 1, 2); op->entry= pe; + op= newobject(O_SORT, 0, r, 5, 2); op->entry= pe; + op= newobject(O_TYPHEX, OF_MOD, r, 10, 2); op->entry= pe; + op= newobject(O_TYPTXT, OF_MOD, r, 12, 9); op->entry= pe; + op= newobject(O_SCYL, OF_MOD, r, 25, 5); op->entry= pe; + op= newobject(O_SHEAD, OF_MOD, r, 30, 3); op->entry= pe; + op= newobject(O_SSEC, OF_MOD, r, 34, 2); op->entry= pe; + op= newobject(O_LCYL, OF_MOD, r, 40, 5); op->entry= pe; + op= newobject(O_LHEAD, OF_MOD, r, 45, 3); op->entry= pe; + op= newobject(O_LSEC, OF_MOD, r, 49, 2); op->entry= pe; + op= newobject(O_BASE, OF_MOD, r, 59, 9); op->entry= pe; + op= newobject(O_SIZE, OF_MOD, r, 69, 9); op->entry= pe; + op= newobject(O_KB, OF_MOD, r, 79, 9); op->entry= pe; + } + } + + for (i= 1; i < argc; i++) newdevice(argv[i], 0, 0); + + if (firstdev == nil) { + getdevices(autopart); + key= ctrl('L'); + } else { + key= 'r'; + } + + if(autopart) { + if (firstdev == nil) { + fprintf(stderr, "autopart couldn't find any devices.\n"); + return 1; + } + return do_autopart(); + } + + if (firstdev != nil) { + init_tty(); + clear_screen(); + event(key, curobj); + display(); + mainloop(); + reset_tty(); + } + exit(0); +} diff --git a/commands/ibm/dosread.c b/commands/ibm/dosread.c index bb62f3286..6496980a9 100755 --- a/commands/ibm/dosread.c +++ b/commands/ibm/dosread.c @@ -1118,39 +1118,3 @@ register unsigned bytes; char dosread_c_rcs_id [] = "$Id$"; -/* $Log$ - * Revision 1.1 2005/04/21 14:54:57 beng - * Initial revision - * -/* Revision 1.1.1.1 2005/04/20 13:33:07 beng -/* Initial import of minix 2.0.4 -/* - * Revision 1.8 1994/05/14 21:53:08 hjp - * filenames with more than 3 characters and extension work again. - * removed debugging stuff and b_copy. - * - * Revision 1.7 1994/04/09 03:09:01 hjp - * (posted to comp.os.minix) - * merged branch 1.5.387 with stem. - * changed treatment of drive parameter - * - * Revision 1.5.387.9 1994/04/09 02:07:51 hjp - * Disk full no longer produces lost clusters but a truncated file. - * Truncated file names to 8+3 before comparisons to avoid duplicate - * files and filenames containing dots in the extension. - * Replaced sbrk and brk by malloc and free (mixing brk and malloc causes - * heap corruption which sometimes lead to core dumps. It may also have - * been the cause of data corruption Kees reported). - * Made global variables static and removed some unused ones. - * Error messages now contain program name. - * - * Revision 1.5.387.8 1993/11/13 00:38:45 hjp - * Posted to comp.os.minix and included in Minix-386vm 1.6.25.1. - * Speed optimizations for 1.44 MB disks. - * Replaced lowlevel I/O by stdio. - * Simplified -a: Now only removes resp. adds CRs - * Cleaned up. - * - * Revision 1.5.387.1 1993/01/15 19:32:29 ast - * Released with 1.6.24b - */