freebsd-dev/sbin/sysinstall/label.c

380 lines
10 KiB
C
Raw Normal View History

/*
* $Id: label.c,v 1.31 1994/12/27 23:26:51 jkh Exp $
*/
#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"
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
static int
AskWhichPartition(char *prompt)
{
char buf[10];
int i;
*buf = 0;
i = AskEm(stdscr, prompt, buf, 2);
if (i != '\n' && i != '\r') return -1;
if (!strchr("abefghABEFGH",*buf)) return -1;
return tolower(*buf) - 'a';
}
void
DiskLabel()
{
int i, j, done = 0, diskno, k;
char buf[128],*p;
struct disklabel *lbl, olbl;
struct dos_partition dp[NDOSPART];
u_long cyl, hd, sec, tsec;
u_long l1, l2, l3, l4;
char *yip = NULL;
u_long allocated_space, ourpart_size, ourpart_offset;
*buf = 0;
i = AskEm(stdscr, "Enter number of disk to Disklabel> ", buf, 3);
Debug("%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;
for (i = lbl->d_npartitions; i < MAXPARTITIONS; i++) {
lbl->d_partitions[i].p_offset = 0;
lbl->d_partitions[i].p_size = 0;
lbl->d_partitions[i].p_fstype = 0;
}
lbl->d_npartitions = MAXPARTITIONS;
if(Dname[diskno][0] == 's' && Dname[diskno][1] == 'd')
lbl->d_type = DTYPE_SCSI;
else
lbl->d_type = DTYPE_ST506;
while(!done) {
clear(); standend();
if (yip) {
standout();
mvprintw(24, 0, yip);
standend();
beep();
yip = NULL;
}
j = 0;
mvprintw(j++, 0, "%s -- Diskspace editor -- DISKLABEL", TITLE);
j++;
allocated_space = 0;
ourpart_size = lbl->d_partitions[OURPART].p_size;
ourpart_offset = lbl->d_partitions[OURPART].p_offset;
mvprintw(j++, 0, "Part Start End Blocks MB Type Action Mountpoint");
for (i = 0; i < MAXPARTITIONS; i++) {
refresh();
mvprintw(j++, 0, "%c ", 'a'+i);
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("%-7.7s ", fstypenames[k]);
if(!MP[diskno][i])
printw(" ");
else if(!strcmp(Ftype[MP[diskno][i]],"swap"))
printw("swap ");
else if(Faction[MP[diskno][i]])
printw("newfs ");
else
printw("mount ");
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]]);
if ((lbl->d_partitions[i].p_offset >= ourpart_offset) &&
((lbl->d_partitions[i].p_offset +
lbl->d_partitions[i].p_size) <=
(ourpart_offset + ourpart_size)))
allocated_space += lbl->d_partitions[i].p_size;
}
}
mvprintw(17, 0, "Total size: %8lu blocks %5luMb",
ourpart_size, (ourpart_size + 1024)/2048);
mvprintw(18, 0, "Space allocated: %8lu blocks %5luMb",
allocated_space, (allocated_space + 1024)/2048);
mvprintw(20, 0, "Commands available: ");
if (memcmp(lbl, Dlbl[diskno], sizeof *lbl)) {
standout();
printw("Use (W)rite to save changes to disk");
standend();
}
mvprintw(21, 0, "(H)elp (T)utorial (E)dit (A)ssign (D)elete (R)eread (W)rite (Q)uit");
mvprintw(22, 0, "(P)reserve (S)lice");
mvprintw(23, 0, "Enter Command> ");
i=getch();
switch(i) {
case 'h': case 'H': case '?':
clear();
mvprintw(0, 0,
"%s -- Diskspace editor -- DISKLABEL -- Command Help
Basic commands:
(H)elp - This screen
(T)utorial - More detailed information on MBRs, disklabels, etc.
(E)dit - Edit an existing disklabel entry
(A)ssign - Assign a filesystem (or swap) to a partition
(D)elete - Delete an existing disklabel entry
(R)eread - Re-read disklabel from disk, discarding any changes
(W)rite - Write updated disklabel information to disk
(P)reserve - Don't newfs the filesystem (preserve old contents)
(S)lice - Import foreign slice from MBR (for example, DOS)
(Q)uit - Exit from the disklabel editor
Press any key to return to Disklabel editor...
", TITLE);
getch();
break;
case 't': case 'T':
ShowFile(HELPME_FILE,"Help file for disklayout");
break;
case 'd': case 'D':
j = AskWhichPartition("Delete which partition> ");
if (j < 0) {
yip = "Invalid partition";
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 'p': case 'P':
j = AskWhichPartition("Preserve which partition> ");
if (j < 0) {
yip = "Invalid partition";
break;
}
if (!MP[diskno][j]) {
yip = "Unmounted partitions are preserved by default";
break;
}
if (lbl->d_partitions[j].p_fstype == FS_SWAP) {
yip = "swap partitions cannot be preserved.";
break;
}
if (lbl->d_partitions[j].p_fstype != FS_BSDFFS) {
yip = "All non-ufs partitions are preserved by default.";
break;
}
if (!fixit && !strcmp(Fmount[MP[diskno][j]],"/")) {
yip = "/ cannot be preserved.";
break;
}
if (!fixit && !strcmp(Fmount[MP[diskno][j]],"/usr")) {
yip = "/usr cannot be preserved.";
break;
}
if (!fixit && !strcmp(Fmount[MP[diskno][j]],"/var")) {
yip = "/var cannot be preserved.";
break;
}
Faction[MP[diskno][j]] = 1 - Faction[MP[diskno][j]];
break;
case 's': case 'S':
read_dospart(Dfd[diskno],&dp[0]);
*buf = 0;
j = AskEm(stdscr,"Import which fdisk slice> ",buf,4);
if(j != '\n' && j != '\r')
break;
i = strtoul(buf,0,0);
if (i < 1 || i > 4) {
yip = "Invalid slice, must be '1' to '4'";
break;
}
if (!dp[i-1].dp_size) {
yip = "empty slice cannot be imported";
break;
}
j = AskWhichPartition("Import on which partition> ");
if (j < 0) {
yip = "Invalid partition";
break;
}
CleanMount(diskno, j);
lbl->d_partitions[j].p_offset = dp[i-1].dp_start;
lbl->d_partitions[j].p_size = dp[i-1].dp_size;
switch (dp[i-1].dp_typ) {
case 0x01:
case 0x04:
case 0x06:
lbl->d_partitions[j].p_fstype=FS_MSDOS;
break;
default:
lbl->d_partitions[j].p_fstype=FS_OTHER;
break;
}
break;
case 'e': case 'E':
j = AskWhichPartition("Change size of which partition> ");
if (j < 0) {
yip = "Invalid partition";
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) {
yip = "Invalid partition type";
break;
}
if (lbl->d_partitions[OURPART].p_size == 0) {
yip = "No FreeBSD partition defined?";
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)) {
yip = "Sizes unchanged - couldn't find room";
break;
}
sprintf(buf, "%lu", (l2-l1+1024L)/2048L);
i = AskEm(stdscr, "Size of partition in MB> ", buf, 10);
l3= strtol(buf, 0, 0) * 2048L;
if (!l3) {
yip = "Invalid size given";
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 'a': case 'A':
j = AskWhichPartition("Assign which partition> ");
if (j < 0) {
yip = "Invalid partition";
break;
}
k = lbl->d_partitions[j].p_fstype;
if (k != FS_BSDFFS && k != FS_MSDOS && k != FS_SWAP) {
yip = "Invalid partition type";
break;
}
if (!lbl->d_partitions[j].p_size) {
yip = "Zero partition 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, "Directory mountpoint> ", buf, 28);
if (i != '\n' && i != '\r')
break;
p = buf + strlen(buf) - 1;
while (isspace(*p) && p >= buf)
*p-- = '\0';
if (*buf && *buf != '/') {
yip = "Mountpoint must start with a '/'";
break;
}
}
CleanMount(diskno, j);
if (!*buf)
break;
p = SetMount(diskno,j,buf);
yip = p;
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];
enable_label(Dfd[diskno]);
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));
disable_label(Dfd[diskno]);
yip = "Label written successfully.";
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;
}
}
}