freebsd-dev/sbin/sysinstall/label.c
Poul-Henning Kamp 9c354a29e7 Public apology:
I have walked all over Paul Richards code again, and severely lobotomized
some of his stuff, in order to cut some corners for the 2.0-Alpha release.
I belive that we can now manipulate fdisk and disklabel-stuff sufficiently
for the release to actually be produced.
It's not that I don't like Paul and his code, I just need something I
can kick out of the door RSN.

Sysinstall is now under absolute code-freeze, only Jordan has my permission
to commit to this code (stage0 & 5).  I would appreciate if everybody
else would finds problems in sysinstall send patches to me, and I will
commit them. THANKYOU.

The fdisk/disklabel editors are made in pure ncurses, and follow a model
"a`la spreadsheet".

There are some important functions which are missing still, and I would
appreciate if somebody would look at them.
The FDISK part needs a "whole-disk" option, and it needs a "rewrite
MBR-boot code" option.
The DISKLABEL part needs to be able to "import DOS-partition".
Both need a "HELP" function, (display a file "/HELP" using dialog is OK).

It seems to me like the wd.c and sd.c should reread the physical record
when a DIOCGDINFO is made, so that they can pick up changes in the
MBR-data.  Otherwise there will be a couple of weird cases where we
cannot avoid replicating code from the kernel.

If you want to play with this, look at src/release/Makefile.  You may need
to step back to version 1.38 of sys/i386/isa/fd.c to make "rootable"
floppies, it is not clear at this time if that indeed is the problem I
have been having.

Sleep well, my friends, and expect the real Alpha in 24H, if the tree is
still solid.
1994-11-01 10:10:43 +00:00

587 lines
17 KiB
C

/* Stopgap, until Paul does the right thing */
#define ESC 27
#define TAB 9
#include <stdlib.h>
#include <limits.h>
#define DKTYPENAMES
#include <sys/param.h>
#include <ufs/ffs/fs.h>
#include <sys/types.h>
#include <string.h>
#include <sys/disklabel.h>
#include <ufs/ffs/fs.h>
#include <string.h>
#include <dialog.h>
#include "sysinstall.h"
int sectstoMb(int, int);
char *partname[MAXPARTITIONS] = {"a", "b", "c", "d", "e", "f", "g", "h"};
#define EDITABLES 3
#define FSTYPE 0
#define UPARTSIZES 1
#define MOUNTPOINTS 2
struct field {
int y;
int x;
int width;
char field[80];
} field;
struct field label_fields[MAXPARTITIONS][EDITABLES];
void
setup_label_fields(struct disklabel *lbl)
{
int i;
for (i=0; i < MAXPARTITIONS; i++) {
label_fields[i][0].y = 4 + (i * 2);
label_fields[i][0].x = 15;
label_fields[i][0].width = 15;
sprintf(label_fields[i][0].field, "%s",
fstypenames[lbl->d_partitions[i].p_fstype]);
label_fields[i][1].y = 4 + (i * 2);
label_fields[i][1].x = 35;
label_fields[i][1].width = 9;
sprintf(label_fields[i][1].field, "%d",
sectstoMb(lbl->d_partitions[i].p_size, lbl->d_secsize));
label_fields[i][2].y = 4 + (i * 2);
label_fields[i][2].x = 45;
label_fields[i][2].width = 30;
}
sprintf(label_fields[0][2].field, "%s", "/");
sprintf(label_fields[1][2].field, "%s", "swap");
sprintf(label_fields[4][2].field, "%s", "/usr");
}
void
update_label_form(WINDOW *window, struct disklabel *lbl)
{
int i;
long used = 0,ul;
mvwprintw(window, 2, 2, "Partition");
mvwprintw(window, 2, 15, "Filesystem Type");
mvwprintw(window, 2, 35, "Size");
mvwprintw(window, 2, 45, "Mount point");
for (i=0; i < MAXPARTITIONS; i++) {
mvwprintw(window, 4+(i*2), 6, "%s", partname[i]);
mvwprintw(window, label_fields[i][0].y, label_fields[i][0].x, "%s",
&label_fields[i][0].field);
if(i < 2 || i > 3) {
ul = strtol(label_fields[i][1].field,0,0);
sprintf(label_fields[i][1].field, "%lu",ul);
used += ul;
}
mvwprintw(window, label_fields[i][1].y, label_fields[i][1].x, "%-5s",
&label_fields[i][1].field);
if (label_fields[i][2].field)
mvwprintw(window, label_fields[i][2].y, label_fields[i][2].x, "%s",
&label_fields[i][2].field);
}
mvwprintw(window, 20, 10, "Allocated %5luMb, Unalloacted %5lu Mb",
used, disk_size(lbl) - used);
wrefresh(window);
}
int
disk_size(struct disklabel *lbl)
{
int size;
size = lbl->d_secsize * lbl->d_nsectors *
lbl->d_ntracks * lbl->d_ncylinders;
return (size / 1024 / 1024);
}
int
sectstoMb(int nsects, int secsize)
{
int size;
size = nsects * secsize;
if (size)
size /= 1024 * 1024;
return (size);
}
int
Mbtosects(int Mb, int secsize)
{
int nsects;
nsects = (Mb * 1024 * 1024) / secsize;
return(nsects);
}
int
rndtocylbdry(int size, int secpercyl)
{
int nocyls;
nocyls = size / secpercyl;
if ((nocyls * secpercyl) < size)
nocyls++;
return (nocyls * secpercyl);
}
void
default_disklabel(struct disklabel *lbl, int avail_sects, int offset)
{
int nsects;
/* Fill in default label entries */
lbl->d_magic = DISKMAGIC;
bcopy("INSTALLATION", lbl->d_typename, strlen("INSTALLATION"));
lbl->d_rpm = 3600;
lbl->d_interleave = 1;
lbl->d_trackskew = 0;
lbl->d_cylskew = 0;
lbl->d_magic2 = DISKMAGIC;
lbl->d_checksum = 0;
lbl->d_bbsize = BBSIZE;
lbl->d_sbsize = SBSIZE;
lbl->d_npartitions = 5;
/* Set up c and d as raw partitions for now */
lbl->d_partitions[2].p_size = avail_sects;
lbl->d_partitions[2].p_offset = offset;
lbl->d_partitions[2].p_fsize = DEFFSIZE; /* XXX */
lbl->d_partitions[2].p_fstype = FS_UNUSED;
lbl->d_partitions[2].p_frag = DEFFRAG;
lbl->d_partitions[3].p_size = lbl->d_secperunit;
lbl->d_partitions[3].p_offset = 0;
lbl->d_partitions[3].p_fsize = DEFFSIZE;
lbl->d_partitions[3].p_fstype = FS_UNUSED;
lbl->d_partitions[3].p_frag = DEFFRAG;
/* Default root */
nsects = rndtocylbdry(Mbtosects(DEFROOTSIZE, lbl->d_secsize),
lbl->d_secpercyl);
offset = rndtocylbdry(offset, lbl->d_secpercyl);
lbl->d_partitions[0].p_size = nsects;
lbl->d_partitions[0].p_offset = offset;
lbl->d_partitions[0].p_fsize = DEFFSIZE;
lbl->d_partitions[0].p_fstype = FS_BSDFFS;
lbl->d_partitions[0].p_frag = DEFFRAG;
avail_sects -= nsects;
offset += nsects;
nsects = rndtocylbdry(Mbtosects(DEFSWAPSIZE, lbl->d_secsize),
lbl->d_secpercyl);
lbl->d_partitions[1].p_size = nsects;
lbl->d_partitions[1].p_offset = offset;
lbl->d_partitions[1].p_fsize = DEFFSIZE;
lbl->d_partitions[1].p_fstype = FS_SWAP;
lbl->d_partitions[1].p_frag = DEFFRAG;
avail_sects -= nsects;
offset += nsects;
nsects = rndtocylbdry(Mbtosects(DEFUSRSIZE, lbl->d_secsize),
lbl->d_secpercyl);
if (avail_sects > nsects)
nsects = avail_sects;
lbl->d_partitions[4].p_size = nsects;
lbl->d_partitions[4].p_offset = offset;
lbl->d_partitions[4].p_fsize = DEFFSIZE;
lbl->d_partitions[4].p_fstype = FS_BSDFFS;
lbl->d_partitions[4].p_frag = DEFFRAG;
}
void
edit_disklabel(struct disklabel *lbl)
{
int key=0;
int x_pos = 0;
int y_pos = 0;
WINDOW *window;
if (use_shadow)
draw_shadow(stdscr, 1, 1, LINES-3, COLS-5);
window = newwin(LINES - 2, COLS - 4, 0, 0);
keypad(window, TRUE);
draw_box(window, 1, 1, LINES - 3, COLS - 5, dialog_attr, border_attr);
wattrset(window, dialog_attr);
setup_label_fields(lbl);
do {
update_label_form(window, lbl);
key = edit_line(window, label_fields[y_pos][x_pos].y,
label_fields[y_pos][x_pos].x,
label_fields[y_pos][x_pos].field,
label_fields[y_pos][x_pos].width,
20);
switch(key) {
case KEY_UP:
if (y_pos != 0)
y_pos--;
break;
case KEY_DOWN:
if (++y_pos == MAXPARTITIONS)
y_pos--;
break;
case '\n':
case TAB:
x_pos++;
if (x_pos == EDITABLES) {
x_pos = 0;
if (++y_pos == MAXPARTITIONS)
y_pos--;
}
break;
case KEY_BTAB:
x_pos--;
if (x_pos < 0) {
x_pos = EDITABLES - 1;
if (--y_pos < 0)
y_pos++;
}
break;
default:
break;
}
} while (key != '\033');
dialog_clear();
}
int
build_disklabel(struct disklabel *lbl)
{
int i, offset;
int nsects;
int total_sects;
/* Get start of FreeBSD partition from default label */
offset = lbl->d_partitions[2].p_offset;
for (i=0; i < MAXPARTITIONS; i++) {
if (strlen(label_fields[i][MOUNTPOINTS].field) &&
atoi(label_fields[i][UPARTSIZES].field)) {
sprintf(scratch, "%s%s", avail_disknames[inst_disk], partname[i]);
Fname[Nfs] = StrAlloc(scratch);
Fmount[Nfs] = StrAlloc(label_fields[i][MOUNTPOINTS].field);
Nfs++;
nsects = Mbtosects(atoi(label_fields[i][UPARTSIZES].field),
lbl->d_secsize);
lbl->d_partitions[i].p_size = nsects;
lbl->d_partitions[i].p_offset = offset;
offset += nsects;
total_sects += nsects;
lbl->d_partitions[i].p_fstype =
getfstype(label_fields[i][FSTYPE].field);
lbl->d_npartitions = i+1;
} else if (i < 2 || i > 3) {
lbl->d_partitions[i].p_size = 0;
lbl->d_partitions[i].p_offset = 0;
lbl->d_partitions[i].p_fstype = 0;
}
Debug("Part%d: %d sects, %d offset, %d end, %d type", i,
lbl->d_partitions[i].p_size,
lbl->d_partitions[i].p_offset,
lbl->d_partitions[i].p_size+
lbl->d_partitions[i].p_offset,
lbl->d_partitions[i].p_fstype);
}
return 0;
}
int
getfstype(char *fstype)
{
int i;
for (i=0; i < FSMAXTYPES; i++)
if (!strcasecmp(fstype, fstypenames[i]))
return(i);
return(FS_OTHER);
}
void
display_disklabel(int disk)
{
int i, key=0;
WINDOW *window;
if (use_shadow)
draw_shadow(stdscr, 1, 1, LINES-2, COLS-2);
window = newwin(LINES-2, COLS-2, 1, 1);
keypad(window, TRUE);
draw_box(window, 1, 1, LINES - 2, COLS - 2, dialog_attr, border_attr);
wattrset(window, dialog_attr);
mvwprintw(window, 2, 2, "Dumping label for disk %d, %s\n", disk, avail_disklabels[disk].d_typename);
mvwprintw(window, 3, 2, "magic = %lu",avail_disklabels[disk].d_magic);
mvwprintw(window, 3, 22, "type = %x",avail_disklabels[disk].d_type);
mvwprintw(window, 3, 32, "subtype = %x\n",avail_disklabels[disk].d_subtype);
mvwprintw(window, 4, 2, "Typename = %s",avail_disklabels[disk].d_typename);
mvwprintw(window, 4, 38, "Packname = %s",avail_disklabels[disk].d_packname);
mvwprintw(window, 5, 74, "boot0 = %s",avail_disklabels[disk].d_boot0);
mvwprintw(window, 5, 50, "boot1 = %s\n",avail_disklabels[disk].d_boot1);
mvwprintw(window, 5, 2, "secsize = %ld",avail_disklabels[disk].d_secsize);
mvwprintw(window, 5, 20, "nsectors = %ld",avail_disklabels[disk].d_nsectors);
mvwprintw(window, 5, 30, "ntracks = %ld",avail_disklabels[disk].d_ntracks);
mvwprintw(window, 5, 50, "ncylinders = %ld\n",avail_disklabels[disk].d_ncylinders);
mvwprintw(window, 6, 2, "secpercyl = %ld",avail_disklabels[disk].d_secpercyl);
mvwprintw(window, 6, 40, "secperunit = %ld\n",avail_disklabels[disk].d_secperunit);
mvwprintw(window, 7, 2, "sparespertrack = %d",avail_disklabels[disk].d_sparespertrack);
mvwprintw(window, 7, 20, "sparespercyl = %d",avail_disklabels[disk].d_sparespercyl);
mvwprintw(window, 7, 40, "acylinders = %ld\n",avail_disklabels[disk].d_acylinders);
mvwprintw(window, 8, 2, "rpm = %d",avail_disklabels[disk].d_rpm);
mvwprintw(window, 8, 20, "interleave = %d",avail_disklabels[disk].d_interleave);
mvwprintw(window, 8, 40, "trackskew = %d",avail_disklabels[disk].d_trackskew);
mvwprintw(window, 8, 60, "cylskew = %d\n",avail_disklabels[disk].d_cylskew);
mvwprintw(window, 9, 2, "headswitch = %ld",avail_disklabels[disk].d_headswitch);
mvwprintw(window, 9, 30, "trkseek = %ld",avail_disklabels[disk].d_trkseek);
mvwprintw(window, 9, 55, "flags = %ld\n",avail_disklabels[disk].d_flags);
mvwprintw(window, 10, 2, "Drivedata");
for(i=0; i< NDDATA; i++) {
mvwprintw(window, 10, 11 + (i*10), " : %d = %ld",i,avail_disklabels[disk].d_drivedata[i]);
}
mvwprintw(window, 11, 2, "Spare");
for (i=0; i< NSPARE; i++) {
mvwprintw(window, 11, 7 + (i*10), " : %d = %ld",i,avail_disklabels[disk].d_spare[i]);
}
mvwprintw(window, 12, 2, "magic2 = %lu",avail_disklabels[disk].d_magic2);
mvwprintw(window, 12, 40, "checksum = %d\n",avail_disklabels[disk].d_checksum);
mvwprintw(window, 13, 2, "npartitions = %d",avail_disklabels[disk].d_npartitions);
mvwprintw(window, 13, 25, "bbsize = %lu",avail_disklabels[disk].d_bbsize);
mvwprintw(window, 13, 50, "sbsize = %lu\n",avail_disklabels[disk].d_sbsize);
for (i=0; i< MAXPARTITIONS; i++) {
mvwprintw(window, 14+i, 2, "%d: size: %ld",i,avail_disklabels[disk].d_partitions[i].p_size);
mvwprintw(window, 14+i, 20, "offset: %ld",avail_disklabels[disk].d_partitions[i].p_offset);
mvwprintw(window, 14+i, 36, "fsize: %ld",avail_disklabels[disk].d_partitions[i].p_fsize);
mvwprintw(window, 14+i, 49, "fstype: %d",avail_disklabels[disk].d_partitions[i].p_fstype);
mvwprintw(window, 14+i, 60, "frag: %d",avail_disklabels[disk].d_partitions[i].p_frag);
mvwprintw(window, 14+i, 70, "cpg: %d",avail_disklabels[disk].d_partitions[i].p_cpg);
}
dialog_update();
while (key != '\n' && key != ' ' && key != '\033')
key = wgetch(window);
delwin(window);
dialog_clear();
}
static int
AskWhichPartition(char *prompt)
{
char buf[10];
int i;
*buf = 0;
i = AskEm(stdscr,prompt,buf,1);
if(i != '\n' && i != '\r') return -1;
if(!strchr("abefghABEFGH",*buf)) return -1;
return tolower(*buf) - 'a';
}
static void
CleanMount(int disk, int part)
{
int i = MP[disk][part];
if(Fmount[i]) {
free(Fmount[i]);
Fmount[i] = 0;
}
if(Fname[i]) {
free(Fname[i]);
Fname[i] = 0;
}
if(Ftype[i]) {
free(Ftype[i]);
Ftype[i] = 0;
}
MP[disk][part] = 0;
}
void
DiskLabel()
{
int i,j,done=0,diskno,flag,k;
char buf[128];
struct disklabel *lbl,olbl;
u_long cyl,hd,sec,tsec;
u_long l1,l2,l3,l4;
*buf = 0;
i = AskEm(stdscr,"Enter number of disk to Disklabel ",buf,1);
printf("%d",i);
if(i != '\n' && i != '\r') return;
diskno = atoi(buf);
if(!(diskno >= 0 && diskno < MAX_NO_DISKS && Dname[diskno])) return;
olbl = *Dlbl[diskno];
lbl = &olbl;
cyl = lbl->d_ncylinders;
hd = lbl->d_ntracks;
sec = lbl->d_nsectors;
tsec = lbl->d_secperunit;
while(!done) {
clear(); standend();
j = 0;
mvprintw(j++,0,"%s -- Diskspace editor -- DISKLABEL",TITLE);
j++;
mvprintw(j++,0,"Part Start End Blocks MB Type Mountpoint");
for(i=0;i<MAXPARTITIONS;i++) {
mvprintw(j++,0,"%c ",'a'+i);
if(i>=lbl->d_npartitions) continue;
printw(" %8u %8u %8u %5u ",
lbl->d_partitions[i].p_offset,
lbl->d_partitions[i].p_offset+
(lbl->d_partitions[i].p_size ?
lbl->d_partitions[i].p_size-1 : 0),
lbl->d_partitions[i].p_size,
(lbl->d_partitions[i].p_size + 1024)/2048);
k = lbl->d_partitions[i].p_fstype;
if(k > FSMAXTYPES)
printw(" %04x ",k);
else
printw("%-10s ",fstypenames[k]);
if(i == OURPART)
printw("<Entire FreeBSD slice>");
else if(i == RAWPART)
printw("<Entire Disk>");
else if(Fmount[MP[diskno][i]])
printw(Fmount[MP[diskno][i]]);
}
mvprintw(21,0,"Commands available:");
mvprintw(22,0,"(S)ize (M)ountpoint (D)elete (R)eread (W)rite (Q)uit");
mvprintw(23,0,"Enter Command> ");
i=getch();
switch(i) {
case 'd': case 'D':
j = AskWhichPartition("Delete which partition ? ");
if(j < 0) break;
CleanMount(diskno,j);
lbl->d_partitions[j].p_fstype = FS_UNUSED;
lbl->d_partitions[j].p_size = 0;
lbl->d_partitions[j].p_offset = 0;
break;
case 's': case 'S':
j = AskWhichPartition("Change size of which partition ? ");
if(j < 0) break;
if(lbl->d_partitions[j].p_fstype != FS_BSDFFS &&
lbl->d_partitions[j].p_fstype != FS_UNUSED &&
lbl->d_partitions[j].p_fstype != FS_SWAP) break;
if(lbl->d_partitions[OURPART].p_size == 0) break;
l1=lbl->d_partitions[OURPART].p_offset;
l2=lbl->d_partitions[OURPART].p_offset +
lbl->d_partitions[OURPART].p_size;
for (i=0;i<MAXPARTITIONS;i++) {
if(i == OURPART) continue;
if(i == RAWPART) continue;
if(i == j) continue;
if(lbl->d_partitions[i].p_size == 0) continue;
if(lbl->d_partitions[i].p_offset >= l2) continue;
if((lbl->d_partitions[i].p_offset+
lbl->d_partitions[i].p_size) <= l1) continue;
l3 = lbl->d_partitions[i].p_offset - l1;
l4 = l2 - (lbl->d_partitions[i].p_offset+
lbl->d_partitions[i].p_size);
if(l3 > 0 && l3 >= l4)
l2 = l1+l3;
else if (l4 > 0 && l4 > l3)
l1 = l2-l4;
else
l2 = l1;
}
if(!(l2-l1)) break;
sprintf(buf,"%lu",(l2-l1+1024L)/2048L);
i = AskEm(stdscr,"Size of slice in MB ",buf,10);
l3=strtol(buf,0,0) * 2048L;
if(!l3) break;
if(l3 > l2-l1)
l3 = l2-l1;
lbl->d_partitions[j].p_size = l3;
lbl->d_partitions[j].p_offset = l1;
if(j == 1)
lbl->d_partitions[j].p_fstype = FS_SWAP;
else
lbl->d_partitions[j].p_fstype = FS_BSDFFS;
break;
case 'r': case 'R':
olbl = *Dlbl[diskno];
/* XXX be more selective here */
for(i=0;i<MAXPARTITIONS;i++)
CleanMount(diskno,i);
break;
case 'm': case 'M':
j = AskWhichPartition("Mountpoint of which partition ? ");
if(j < 0) break;
k = lbl->d_partitions[j].p_fstype;
if(k != FS_BSDFFS && k != FS_MSDOS && k != FS_SWAP) break;
if(!lbl->d_partitions[j].p_size) break;
if(k == FS_SWAP)
strcpy(buf,"swap");
else if(Fmount[MP[diskno][j]])
strcpy(buf,Fmount[MP[diskno][j]]);
else
*buf = 0;
if(k != FS_SWAP) {
i = AskEm(stdscr,"Mount on directory ",buf,28);
if(i != '\n' && i != '\r') break;
}
CleanMount(diskno,j);
for(k=1;k<MAX_NO_FS;k++)
if(!Fmount[k])
break;
if(k >= MAX_NO_FS) break;
Fmount[k] = StrAlloc(buf);
MP[diskno][j] = k;
sprintf(buf,"%s%c",Dname[diskno],j+'a');
Fname[MP[diskno][j]] = StrAlloc(buf);
if(lbl->d_partitions[j].p_fstype == FS_BSDFFS)
Ftype[MP[diskno][j]] = StrAlloc("ufs");
else if(lbl->d_partitions[j].p_fstype == FS_MSDOS)
Ftype[MP[diskno][j]] = StrAlloc("msdos");
else if(lbl->d_partitions[j].p_fstype == FS_SWAP)
Ftype[MP[diskno][j]] = StrAlloc("swap");
Fsize[MP[diskno][j]] = (lbl->d_partitions[j].p_size+1024)/2048;
break;
case 'w': case 'W':
*Dlbl[diskno] = *lbl;
Dlbl[diskno]->d_magic = DISKMAGIC;
Dlbl[diskno]->d_magic2 = DISKMAGIC;
Dlbl[diskno]->d_checksum = 0;
Dlbl[diskno]->d_checksum = dkcksum(Dlbl[diskno]);
*lbl= *Dlbl[diskno];
flag=1;
if (ioctl(Dfd[diskno], DIOCWLABEL, &flag) < 0)
Fatal("Couldn't enable writing of labels");
if(ioctl(Dfd[diskno],DIOCSDINFO,Dlbl[diskno]) == -1)
Fatal("Couldn't set label: %s",strerror(errno));
if(ioctl(Dfd[diskno],DIOCWDINFO,Dlbl[diskno]) == -1)
Fatal("Couldn't write label: %s",strerror(errno));
flag=0;
if (ioctl(Dfd[diskno], DIOCWLABEL, &flag) < 0)
Fatal("Couldn't disable writing of labels");
break;
case 'q': case 'Q':
if(!memcmp(lbl,Dlbl[diskno],sizeof *lbl))
return;
/* XXX be more selective here */
for(i=0;i<MAXPARTITIONS;i++)
CleanMount(diskno,i);
return;
break;
}
}
}