Index: head/release/sysinstall/disks.c =================================================================== --- head/release/sysinstall/disks.c (revision 70004) +++ head/release/sysinstall/disks.c (revision 70005) @@ -1,971 +1,971 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_SIZE }; #ifdef PC98 #define SUBTYPE_FREEBSD 50324 #define SUBTYPE_FAT 37218 #else #define SUBTYPE_FREEBSD 165 #define SUBTYPE_FAT 6 #endif /* Where we start displaying chunk information on the screen */ #define CHUNK_START_ROW 5 /* Where we keep track of MBR chunks */ static struct chunk *chunk_info[16]; static int current_chunk; static void diskPartitionNonInteractive(Device *dev); static void record_chunks(Disk *d) { struct chunk *c1 = NULL; int i = 0; int last_free = 0; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == unused && c1->size > last_free) { last_free = c1->size; current_chunk = i; } chunk_info[i++] = c1; } chunk_info[i] = NULL; if (current_chunk >= i) current_chunk = i - 1; } static int Total; static void print_chunks(Disk *d, int u) { int row; int i; int sz; char *szstr; szstr = (u == UNIT_MEG ? "MB" : (u == UNIT_KILO ? "KB" : "ST")); for (i = Total = 0; chunk_info[i]; i++) Total += chunk_info[i]->size; #ifndef PC98 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { dialog_clear_norefresh(); msgConfirm("WARNING: A geometry of %d/%d/%d for %s is incorrect. Using\n" "a more likely geometry. If this geometry is incorrect or you\n" "are unsure as to whether or not it's correct, please consult\n" "the Hardware Guide in the Documentation submenu or use the\n" "(G)eometry command to change it now.\n\n" "Remember: you need to enter whatever your BIOS thinks the\n" "geometry is! For IDE, it's what you were told in the BIOS\n" "setup. For SCSI, it's the translation mode your controller is\n" "using. Do NOT use a ``physical geometry''.", d->bios_cyl, d->bios_hd, d->bios_sect, d->name); Sanitize_Bios_Geom(d); } #endif attrset(A_NORMAL); mvaddstr(0, 0, "Disk name:\t"); clrtobot(); attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); mvprintw(1, 0, "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors (%luMB)", d->bios_cyl, d->bios_hd, d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect * 512 / 1024 / 1024); mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", "Offset", "Size", szstr, "End", "Name", "PType", "Desc", "Subtype", "Flags"); for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { switch(u) { default: /* fall thru */ case UNIT_BLOCKS: sz = chunk_info[i]->size; break; case UNIT_KILO: sz = chunk_info[i]->size * 512 / 1024; break; case UNIT_MEG: sz = chunk_info[i]->size * 512 / 1024 / 1024; break; } if (i == current_chunk) attrset(ATTR_SELECTED); mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", chunk_info[i]->offset, sz, chunk_info[i]->end, chunk_info[i]->name, chunk_info[i]->type, slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); if (i == current_chunk) attrset(A_NORMAL); } } static void print_command_summary() { mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice"); mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable"); mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); if (!RunningAsInit) mvprintw(18, 48, "W = Write Changes"); mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } #ifdef PC98 static void getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, u_char **bootmenu, size_t *bootmenu_size) { extern u_char boot0[]; extern size_t boot0_size; extern u_char boot05[]; extern size_t boot05_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: *bootipl = boot0; *bootipl_size = boot0_size; *bootmenu = boot05; *bootmenu_size = boot05_size; return; case 2: default: break; } } *bootipl = NULL; *bootipl_size = 0; *bootmenu = NULL; *bootmenu_size = 0; } #else static void getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) { #ifndef __alpha__ /* only meaningful on x86 */ extern u_char mbr[], boot0[]; extern size_t mbr_size, boot0_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else if (!strcmp(cp, "standard")) BootMgr = 1; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: *bootCode = boot0; *bootCodeSize = boot0_size; return; case 1: *bootCode = mbr; *bootCodeSize = mbr_size; return; case 2: default: break; } } #endif *bootCode = NULL; *bootCodeSize = 0; } #endif int diskGetSelectCount(Device ***devs) { int i, cnt, enabled; char *cp; Device **dp; cp = variable_get(VAR_DISK); dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(dp); if (!cnt) return -1; for (i = 0, enabled = 0; i < cnt; i++) { if (dp[i]->enabled) ++enabled; } return enabled; } void diskPartition(Device *dev) { char *cp, *p; int rv, key = 0; Boolean chunking; char *msg = NULL; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif WINDOW *w = savescr(); Disk *d = (Disk *)dev->private; int size_unit; size_unit = UNIT_BLOCKS; chunking = TRUE; keypad(stdscr, TRUE); /* Flush both the dialog and curses library views of the screen since we don't always know who called us */ dialog_clear_norefresh(), clear(); current_chunk = 0; /* Set up the chunk array */ record_chunks(d); while (chunking) { char *val, geometry[80]; /* Now print our overall state */ if (d) print_chunks(d, size_unit); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } /* Get command character */ key = getch(); switch (toupper(key)) { case '\014': /* ^L (redraw) */ clear(); msg = NULL; break; case '\020': /* ^P */ case KEY_UP: case '-': if (current_chunk != 0) --current_chunk; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_HOME: current_chunk = 0; break; case KEY_END: while (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_F(1): case '?': systemDisplayHelp("slice"); clear(); break; case 'A': #ifdef __alpha__ rv = 1; #else /* The rest is only relevant on x86 */ cp = variable_get(VAR_DEDICATE_DISK); if (cp && !strcasecmp(cp, "always")) rv = 1; else { rv = msgYesNo("Do you want to do this with a true partition entry\n" "so as to remain cooperative with any future possible\n" "operating systems on the drive(s)?\n" "(See also the section about ``dangerously dedicated''\n" "disks in the FreeBSD FAQ.)"); if (rv == -1) rv = 0; } #endif All_FreeBSD(d, rv); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); clear(); break; case 'C': if (chunk_info[current_chunk]->type != unused) msg = "Slice in use, delete it first or move to an unused one."; else { char *val, tmp[20], *cp; int size; #ifdef PC98 char name[16]; snprintf(name, 16, "%s", "FreeBSD"); val = msgGetInput(name, "Please specify the name for new FreeBSD slice."); if (val) strncpy(name, val, 16); #else int subtype; chunk_e partitiontype; #endif snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" "or append a trailing `M' for megabytes (e.g. 20M)."); if (val && (size = strtol(val, &cp, 0)) > 0) { if (*cp && toupper(*cp) == 'M') size *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') size *= ONE_GIG; #ifdef PC98 Create_Chunk(d, chunk_info[current_chunk]->offset, size, freebsd, 3, (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); #else sprintf(tmp, "%d", SUBTYPE_FREEBSD); val = msgGetInput(tmp, "Enter type of partition to create:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 165). You can choose other types, 6 for a\n" "DOS partition or 131 for a Linux partition, for example.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS FORMAT, to later format\n" "and use the partition."); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else partitiontype = unknown; #ifdef __alpha__ if (partitiontype == freebsd && size == chunk_info[current_chunk]->size) All_FreeBSD(d, 1); else #endif Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } #endif /* PC98 */ } clear(); } break; case KEY_DC: case 'D': if (chunk_info[current_chunk]->type == unused) msg = "Slice is already unused!"; else { Delete_Chunk(d, chunk_info[current_chunk]); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } break; case 'T': if (chunk_info[current_chunk]->type == unused) msg = "Slice is currently unused (use create instead)"; else { char *val, tmp[20]; int subtype; chunk_e partitiontype; sprintf(tmp, "%d", SUBTYPE_FREEBSD); #ifdef PC98 val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 50324). Other popular values are 37218 for\n" "DOS FAT partition.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS format, to later format\n" "and actually use the partition."); #else val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 165). Other popular values are 6 for\n" "DOS FAT partition, 131 for a Linux ext2fs partition or\n" "130 for a Linux swap partition.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS format, to later format\n" "and actually use the partition."); #endif /* PC98 */ if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else partitiontype = unknown; chunk_info[current_chunk]->type = partitiontype; chunk_info[current_chunk]->subtype = subtype; } } break; case 'G': snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" "Don't forget to use the two slash (/) separator characters!\n" "It's not possible to parse the field without them."); if (val) { long nc, nh, ns; nc = strtol(val, &val, 0); nh = strtol(val + 1, &val, 0); ns = strtol(val + 1, 0, 0); Set_Bios_Geom(d, nc, nh, ns); } clear(); break; case 'S': /* Set Bootable */ chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; break; case 'U': if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written this information out - you\n" "can't undo it."); } - else if (!msgYesNo("Are you SURE you want to Undo everything?")) { + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { char cp[BUFSIZ]; sstrncpy(cp, d->name, sizeof cp); Free_Disk(dev->private); d = Open_Disk(cp); if (!d) msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); dev->private = d; variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); if (d) record_chunks(d); } clear(); break; case 'W': - if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" + if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions. If you're adding a disk, you should NOT write\n" "from this screen, you should do it from the label editor.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_PARTITIONED, "yes", 0); /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested booteasy or a "standard" MBR -- both would be * fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ #ifdef PC98 if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); else { bootipl = NULL; bootipl_size = 0; bootmenu = NULL; bootmenu_size = 0; } Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &mbrContents, &mbrSize); else { mbrContents = NULL; mbrSize = 0; } Set_Boot_Mgr(d, mbrContents, mbrSize); #endif if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) msgConfirm("Disk partition write returned an error status!"); else msgConfirm("Wrote FDISK partition information out successfully."); } clear(); break; case '|': - if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" + if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" "No seat belts whatsoever are provided!")) { clear(); refresh(); slice_wizard(d); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } else msg = "Wise choice!"; clear(); break; case '\033': /* ESC */ case 'Q': chunking = FALSE; /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * booteasy or a "standard" MBR -- both would be fatal in this case. */ #if 0 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } #else /* * Don't offer to update the MBR on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } #endif break; case 'Z': size_unit = (size_unit + 1) % UNIT_SIZE; break; default: beep(); msg = "Type F1 or ? for help"; break; } } p = CheckRules(d); if (p) { char buf[FILENAME_MAX]; use_helpline("Press F1 to read more about disk slices."); use_helpfile(systemHelpFile("partition", buf)); if (!variable_get(VAR_NO_WARN)) dialog_mesgbox("Disk slicing warning:", p, -1, -1); free(p); } restorescr(w); } static u_char * bootalloc(char *name) { char buf[FILENAME_MAX]; struct stat sb; snprintf(buf, sizeof buf, "/boot/%s", name); if (stat(buf, &sb) != -1) { int fd; fd = open(buf, O_RDONLY); if (fd != -1) { u_char *cp; cp = malloc(sb.st_size); if (read(fd, cp, sb.st_size) != sb.st_size) { free(cp); close(fd); msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); return NULL; } close(fd); return cp; } msgDebug("bootalloc: couldn't open %s\n", buf); } else msgDebug("bootalloc: can't stat %s\n", buf); return NULL; } static int partitionHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskPartition(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int partitionCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskPartitionEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt, devcnt; cnt = diskGetSelectCount(&devs); devcnt = deviceCount(devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ for (i = 0; i < devcnt; i++) { if (devs[i]->enabled) { if (variable_get(VAR_NONINTERACTIVE)) diskPartitionNonInteractive(devs[i]); else diskPartition(devs[i]); } } } else { /* No disks are selected, fall-back case now */ if (devcnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE)) diskPartitionNonInteractive(devs[0]); else diskPartition(devs[0]); return DITEM_SUCCESS; } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); return DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } return i; } } return DITEM_SUCCESS; } int diskPartitionWrite(dialogMenuItem *self) { Device **devs; int i; char *cp; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find any disks to write to??"); return DITEM_FAILURE; } if (isDebug()) msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); cp = variable_get(DISK_PARTITIONED); if (cp && !strcmp(cp, "written")) return DITEM_SUCCESS; for (i = 0; devs[i]; i++) { Disk *d = (Disk *)devs[i]->private; static u_char *boot1; #ifndef __alpha__ static u_char *boot2; #endif if (!devs[i]->enabled) continue; #ifdef __alpha__ if (!boot1) boot1 = bootalloc("boot1"); Set_Boot_Blocks(d, boot1, NULL); #else if (!boot1) boot1 = bootalloc("boot1"); if (!boot2) boot2 = bootalloc("boot2"); Set_Boot_Blocks(d, boot1, boot2); #endif msgNotify("Writing partition information to drive %s", d->name); if (!Fake && Write_Disk(d)) { msgConfirm("ERROR: Unable to write data to disk %s!", d->name); return DITEM_FAILURE; } /* If we've been through here before, we don't need to do the rest */ if (cp && !strcmp(cp, "written")) return DITEM_SUCCESS; } /* Now it's not "yes", but "written" */ variable_set2(DISK_PARTITIONED, "written", 0); return DITEM_SUCCESS | DITEM_RESTORE; } /* Partition a disk based wholly on which variables are set */ static void diskPartitionNonInteractive(Device *dev) { char *cp; int i, sz, all_disk = 0; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif Disk *d = (Disk *)dev->private; record_chunks(d); cp = variable_get(VAR_GEOMETRY); if (cp) { msgDebug("Setting geometry from script to: %s\n", cp); d->bios_cyl = strtol(cp, &cp, 0); d->bios_hd = strtol(cp + 1, &cp, 0); d->bios_sect = strtol(cp + 1, 0, 0); } cp = variable_get(VAR_PARTITION); if (cp) { if (!strcmp(cp, "free")) { /* Do free disk space case */ for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least 10MB in size, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { #ifdef PC98 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); #else Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); #endif variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find any free space on this disk!"); return; } } else if (!strcmp(cp, "all")) { /* Do all disk space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, FALSE); } else if (!strcmp(cp, "exclusive")) { /* Do really-all-the-disk-space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, all_disk = TRUE); } else if ((sz = strtol(cp, &cp, 0))) { /* Look for sz bytes free */ if (*cp && toupper(*cp) == 'M') sz *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') sz *= ONE_GIG; for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least sz MB, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { #ifdef PC98 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); #else Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); #endif variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find %d free blocks on this disk!", sz); return; } } else if (!strcmp(cp, "existing")) { /* Do existing FreeBSD case */ for (i = 0; chunk_info[i]; i++) { if (chunk_info[i]->type == freebsd) break; } if (!chunk_info[i]) { msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); return; } } else { msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); return; } if (!all_disk) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } variable_set2(DISK_PARTITIONED, "yes", 0); } } Index: head/release/sysinstall/index.c =================================================================== --- head/release/sysinstall/index.c (revision 70004) +++ head/release/sysinstall/index.c (revision 70005) @@ -1,763 +1,763 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include "sysinstall.h" /* Macros and magic values */ #define MAX_MENU 12 #define _MAX_DESC 55 /* A structure holding the root, top and plist pointer at once */ struct ListPtrs { PkgNodePtr root; /* root of tree */ PkgNodePtr top; /* part of tree we handle */ PkgNodePtr plist; /* list of selected packages */ }; typedef struct ListPtrs* ListPtrsPtr; static void index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie); /* Shared between index_initialize() and the various clients of it */ PkgNode Top, Plist; /* Smarter strdup */ inline char * _strdup(char *ptr) { return ptr ? strdup(ptr) : NULL; } static char *descrs[] = { "Package Selection", "To mark a package, move to it and press SPACE. If the package is\n" "already marked, it will be unmarked or deleted (if installed).\n" "Items marked with a `D' are dependencies which will be auto-loaded.\n" "To search for a package by name, press ESC. To select a category,\n" "press RETURN. NOTE: The All category selection creates a very large\n" "submenu! If you select it, please be patient while it comes up.", "Package Targets", "These are the packages you've selected for extraction.\n\n" "If you're sure of these choices, select OK.\n" "If not, select Cancel to go back to the package selection menu.\n", "All", "All available packages in all categories.", "afterstep", "Ports to support the AfterStep window manager.", "applications", "User application software.", "archivers", "Utilities for archiving and unarchiving data.", "astro", "Applications related to astronomy.", "audio", "Audio utilities - most require a supported sound card.", "benchmarks", "Utilities for measuring system performance.", "biology", "Software related to biology.", "cad", "Computer Aided Design utilities.", "chinese", "Ported software for the Chinese market.", "comms", "Communications utilities.", "converters", "Format conversion utilities.", "databases", "Database software.", "deskutils", "Various Desktop utilities.", "devel", "Software development utilities and libraries.", "documentation", "Document preparation utilities.", "editors", "Common text editors.", "elisp", "Things related to Emacs Lisp.", "emulators", "Utilities for emulating other OS types.", "french", "Ported software for French countries.", "ftp", "FTP client and server utilities.", "games", "Various and sundry amusements.", "german", "Ported software for Germanic countries.", "gnome", "Components of the Gnome Desktop environment.", "graphics", "Graphics libraries and utilities.", "ipv6", "IPv6 related software.", "hebrew", "Ported software for Hebrew language.", "irc", "Internet Relay Chat utilities.", "japanese", "Ported software for the Japanese market.", "java", "Java language support.", "kde", "Software for the K Desktop Environment.", "korean", "Ported software for the Korean market.", "lang", "Computer languages.", "languages", "Computer languages.", "libraries", "Software development libraries.", "linux", "Linux programs that can be run under binary compatibility.", "mail", "Electronic mail packages and utilities.", "math", "Mathematical computation software.", "mbone", "Applications and utilities for the MBONE.", "misc", "Miscellaneous utilities.", "net", "Networking utilities.", "news", "USENET News support software.", "numeric", "Mathematical computation software.", "offix", "An office automation suite of sorts.", "orphans", "Packages without a home elsewhere.", "palm", "Software support for the 3Com Palm Pilot(tm) series.", "perl5", "Utilities/modules for the PERL5 language.", "pilot", "Software support for the 3Com Palm Pilot(tm) series.", "plan9", "Software from the Plan9 operating system.", "print", "Utilities for dealing with printing.", "printing", "Utilities for dealing with printing.", "programming", "Software development utilities and libraries.", "python", "Software related to the Python language.", "ruby", "Software related to the Ruby language.", "russian", "Ported software for the Russian market.", "security", "System security software.", "shells", "Various shells (tcsh, bash, etc).", "sysutils", "Various system utilities.", "tcl75", "TCL v7.5 and packages that depend on it.", "tcl76", "TCL v7.6 and packages that depend on it.", "tcl80", "TCL v8.0 and packages that depend on it.", "tcl82", "TCL v8.2 and packages that depend on it.", "tcl83", "TCL v8.3 and packages that depend on it.", "textproc", "Text processing/search utilities.", "tk41", "Tk4.1 and packages that depend on it.", "tk42", "Tk4.2 and packages that depend on it.", "tk80", "Tk8.0 and packages that depend on it.", "tk81", "Tk8.1 and packages that depend on it.", "tk82", "Tk8.2 and packages that depend on it.", "tk83", "Tk8.3 and packages that depend on it.", "tkstep80", "tkstep wm and packages that depend on it.", "troff", "TROFF text formatting utilities.", "vietnamese", "Ported software for the Vietnamese market.", "windowmaker", "Ports to support the WindowMaker window manager.", "www", "WEB utilities (browers, HTTP servers, etc).", "x11", "X Window System based utilities.", "x11-clocks", "X Window System based clocks.", "x11-fm", "X Window System based file managers.", "x11-fonts", "X Window System fonts and font utilities.", "x11-servers", "X Window System servers.", "x11-toolkits", "X Window System based development toolkits.", "x11-wm", "X Window System window managers.", "zope", "Software related to the Zope platform.", NULL, NULL, }; static char * fetch_desc(char *name) { int i; for (i = 0; descrs[i]; i += 2) { if (!strcmp(descrs[i], name)) return descrs[i + 1]; } return "No description provided"; } static PkgNodePtr new_pkg_node(char *name, node_type type) { PkgNodePtr tmp = safe_malloc(sizeof(PkgNode)); tmp->name = _strdup(name); tmp->type = type; return tmp; } static char * strip(char *buf) { int i; for (i = 0; buf[i]; i++) if (buf[i] == '\t' || buf[i] == '\n') buf[i] = ' '; return buf; } static IndexEntryPtr new_index(char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *deps) { IndexEntryPtr tmp = safe_malloc(sizeof(IndexEntry)); tmp->name = _strdup(name); tmp->path = _strdup(pathto); tmp->prefix = _strdup(prefix); tmp->comment = _strdup(comment); tmp->descrfile = strip(_strdup(descr)); tmp->maintainer = _strdup(maint); tmp->deps = _strdup(deps); tmp->depc = 0; tmp->installed = package_exists(name); return tmp; } static void index_register(PkgNodePtr top, char *where, IndexEntryPtr ptr) { PkgNodePtr p, q; for (q = NULL, p = top->kids; p; p = p->next) { if (!strcmp(p->name, where)) { q = p; break; } } if (!p) { /* Add new category */ q = new_pkg_node(where, PLACE); q->desc = fetch_desc(where); q->next = top->kids; top->kids = q; } p = new_pkg_node(ptr->name, PACKAGE); p->desc = ptr->comment; p->data = ptr; p->next = q->kids; q->kids = p; } static int copy_to_sep(char *to, char *from, int sep) { char *tok; tok = strchr(from, sep); if (!tok) { *to = '\0'; return 0; } *tok = '\0'; strcpy(to, from); return tok + 1 - from; } static int readline(FILE *fp, char *buf, int max) { int rv, i = 0; char ch; while ((rv = fread(&ch, 1, 1, fp)) == 1 && ch != '\n' && i < max) buf[i++] = ch; if (i < max) buf[i] = '\0'; return rv; } int index_parse(FILE *fp, char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *cats, char *rdeps) { char line[2048]; char junk[511]; char *cp; int i; i = readline(fp, line, sizeof line); if (i <= 0) return EOF; cp = line; cp += copy_to_sep(name, cp, '|'); cp += copy_to_sep(pathto, cp, '|'); cp += copy_to_sep(prefix, cp, '|'); cp += copy_to_sep(comment, cp, '|'); cp += copy_to_sep(descr, cp, '|'); cp += copy_to_sep(maint, cp, '|'); cp += copy_to_sep(cats, cp, '|'); cp += copy_to_sep(junk, cp, '|'); /* build deps - not used */ if (index(cp, '|')) copy_to_sep(rdeps, cp, '|'); else strncpy(rdeps, cp, 1023); return 0; } int index_read(FILE *fp, PkgNodePtr papa) { char name[127], pathto[255], prefix[255], comment[255], descr[127], maint[127], cats[511], deps[1024]; PkgNodePtr i; while (index_parse(fp, name, pathto, prefix, comment, descr, maint, cats, deps) != EOF) { char *cp, *cp2, tmp[1024]; IndexEntryPtr idx; idx = new_index(name, pathto, prefix, comment, descr, maint, deps); /* For now, we only add things to menus if they're in categories. Keywords are ignored */ for (cp = strcpy(tmp, cats); (cp2 = strchr(cp, ' ')) != NULL; cp = cp2 + 1) { *cp2 = '\0'; index_register(papa, cp, idx); } index_register(papa, cp, idx); /* Add to special "All" category */ index_register(papa, "All", idx); } /* Adjust dependency counts */ for (i = papa->kids; i != NULL; i = i->next) if (strcmp(i->name, "All") == 0) break; for (i = i->kids; i != NULL; i = i->next) if (((IndexEntryPtr)i->data)->installed) index_recorddeps(TRUE, papa, i->data); return 0; } void index_init(PkgNodePtr top, PkgNodePtr plist) { if (top) { top->next = top->kids = NULL; top->name = "Package Selection"; top->type = PLACE; top->desc = fetch_desc(top->name); top->data = NULL; } if (plist) { plist->next = plist->kids = NULL; plist->name = "Package Targets"; plist->type = PLACE; plist->desc = fetch_desc(plist->name); plist->data = NULL; } } void index_print(PkgNodePtr top, int level) { int i; while (top) { for (i = 0; i < level; i++) putchar('\t'); printf("name [%s]: %s\n", top->type == PLACE ? "place" : "package", top->name); for (i = 0; i < level; i++) putchar('\t'); printf("desc: %s\n", top->desc); if (top->kids) index_print(top->kids, level + 1); top = top->next; } } /* Swap one node for another */ static void swap_nodes(PkgNodePtr a, PkgNodePtr b) { PkgNode tmp; tmp = *a; *a = *b; a->next = tmp.next; tmp.next = b->next; *b = tmp; } /* Use a disgustingly simplistic bubble sort to put our lists in order */ void index_sort(PkgNodePtr top) { PkgNodePtr p, q; /* Sort everything at the top level */ for (p = top->kids; p; p = p->next) { for (q = top->kids; q; q = q->next) { if (q->next && strcmp(q->name, q->next->name) > 0) swap_nodes(q, q->next); } } /* Now sub-sort everything n levels down */ for (p = top->kids; p; p = p->next) { if (p->kids) index_sort(p); } } /* Delete an entry out of the list it's in (only the plist, at present) */ void index_delete(PkgNodePtr n) { if (n->next) { PkgNodePtr p = n->next; *n = *(n->next); safe_free(p); } else /* Kludgy end sentinal */ n->name = NULL; } /* * Search for a given node by name, returning the category in if * tp is non-NULL. */ PkgNodePtr index_search(PkgNodePtr top, char *str, PkgNodePtr *tp) { PkgNodePtr p, sp; for (p = top->kids; p && p->name; p = p->next) { if (p->type == PACKAGE) { /* If tp == NULL, we're looking for an exact package match */ if (!tp && !strcmp(p->name, str)) return p; /* If tp, we're looking for both a package and a pointer to the place it's in */ if (tp && !strncmp(p->name, str, strlen(str))) { *tp = top; return p; } } else if (p->kids) { /* The usual recursion-out-of-laziness ploy */ if ((sp = index_search(p, str, tp)) != NULL) return sp; } } if (p && !p->name) p = NULL; return p; } int pkg_checked(dialogMenuItem *self) { ListPtrsPtr lists = (ListPtrsPtr)self->aux; PkgNodePtr kp = self->data, plist = lists->plist; int i; i = index_search(plist, kp->name, NULL) ? TRUE : FALSE; if (kp->type == PACKAGE && plist) { IndexEntryPtr ie = kp->data; int markD, markX; markD = ie->depc > 0; /* needed as dependency */ markX = i || ie->installed; /* selected or installed */ self->mark = markX ? 'X' : 'D'; return markD || markX; } else return FALSE; } int pkg_fire(dialogMenuItem *self) { int ret; ListPtrsPtr lists = (ListPtrsPtr)self->aux; PkgNodePtr sp, kp = self->data, plist = lists->plist; if (!plist) ret = DITEM_FAILURE; else if (kp->type == PACKAGE) { IndexEntryPtr ie = kp->data; sp = index_search(plist, kp->name, NULL); /* Not already selected? */ if (!sp) { if (!ie->installed) { PkgNodePtr np = (PkgNodePtr)safe_malloc(sizeof(PkgNode)); *np = *kp; np->next = plist->kids; plist->kids = np; index_recorddeps(TRUE, lists->root, ie); msgInfo("Added %s to selection list", kp->name); } else if (ie->depc == 0) { - if (!msgYesNo("Do you really want to delete %s from the system?", kp->name)) { + if (!msgNoYes("Do you really want to delete %s from the system?", kp->name)) { if (vsystem("pkg_delete %s %s", isDebug() ? "-v" : "", kp->name)) { msgConfirm("Warning: pkg_delete of %s failed.\n Check debug output for details.", kp->name); } else { ie->installed = 0; index_recorddeps(FALSE, lists->root, ie); } } } else msgConfirm("Warning: Package %s is needed by\n %d other installed package%s.", kp->name, ie->depc, (ie->depc != 1) ? "s" : ""); } else { index_recorddeps(FALSE, lists->root, ie); msgInfo("Removed %s from selection list", kp->name); index_delete(sp); } ret = DITEM_SUCCESS; /* Mark menu for redraw if we had dependencies */ if (strlen(ie->deps) > 0) ret |= DITEM_REDRAW; } else { /* Not a package, must be a directory */ int p, s; p = s = 0; index_menu(lists->root, kp, plist, &p, &s); ret = DITEM_SUCCESS | DITEM_CONTINUE; } return ret; } void pkg_selected(dialogMenuItem *self, int is_selected) { PkgNodePtr kp = self->data; if (!is_selected || kp->type != PACKAGE) return; msgInfo(kp->desc); } int index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll) { struct ListPtrs lists; int n, rval, maxname; int curr, max; PkgNodePtr kp; dialogMenuItem *nitems; Boolean hasPackages; WINDOW *w; lists.root = root; lists.top = top; lists.plist = plist; hasPackages = FALSE; nitems = NULL; n = maxname = 0; /* Figure out if this menu is full of "leaves" or "branches" */ for (kp = top->kids; kp && kp->name; kp = kp->next) { int len; ++n; if (kp->type == PACKAGE && plist) { hasPackages = TRUE; if ((len = strlen(kp->name)) > maxname) maxname = len; } } if (!n && plist) { msgConfirm("The %s menu is empty.", top->name); return DITEM_LEAVE_MENU; } w = savescr(); while (1) { n = 0; curr = max = 0; use_helpline(NULL); use_helpfile(NULL); kp = top->kids; if (!hasPackages && plist) { nitems = item_add(nitems, "OK", NULL, NULL, NULL, NULL, NULL, 0, &curr, &max); nitems = item_add(nitems, "Install", NULL, NULL, NULL, NULL, NULL, 0, &curr, &max); } while (kp && kp->name) { char buf[256]; IndexEntryPtr ie = kp->data; /* Brutally adjust description to fit in menu */ if (kp->type == PACKAGE) snprintf(buf, sizeof buf, "[%s]", ie->path ? ie->path : "External vendor"); else SAFE_STRCPY(buf, kp->desc); if (strlen(buf) > (_MAX_DESC - maxname)) buf[_MAX_DESC - maxname] = '\0'; nitems = item_add(nitems, kp->name, buf, pkg_checked, pkg_fire, pkg_selected, kp, (int)&lists, &curr, &max); ++n; kp = kp->next; } /* NULL delimiter so item_free() knows when to stop later */ nitems = item_add(nitems, NULL, NULL, NULL, NULL, NULL, NULL, 0, &curr, &max); recycle: dialog_clear_norefresh(); if (hasPackages) rval = dialog_checklist(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems, NULL); else rval = dialog_menu(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems + (plist ? 2 : 0), (char *)plist, pos, scroll); if (rval == -1 && plist) { static char *cp; PkgNodePtr menu; /* Search */ if ((cp = msgGetInput(cp, "Search by package name. Please enter search string:")) != NULL) { PkgNodePtr p = index_search(top, cp, &menu); if (p) { int pos, scroll; /* These need to be set to point at the found item, actually. Hmmm! */ pos = scroll = 0; index_menu(root, menu, plist, &pos, &scroll); } else msgConfirm("Search string: %s yielded no hits.", cp); } goto recycle; } items_free(nitems, &curr, &max); restorescr(w); return rval ? DITEM_FAILURE : DITEM_SUCCESS; } } int index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended) { int status = DITEM_SUCCESS; PkgNodePtr tmp2; IndexEntryPtr id = who->data; WINDOW *w = savescr(); if (id && id->deps && strlen(id->deps)) { char t[1024], *cp, *cp2; SAFE_STRCPY(t, id->deps); cp = t; while (cp && DITEM_STATUS(status) == DITEM_SUCCESS) { if ((cp2 = index(cp, ' ')) != NULL) *cp2 = '\0'; if ((tmp2 = index_search(top, cp, NULL)) != NULL) { status = index_extract(dev, top, tmp2, TRUE); if (DITEM_STATUS(status) != DITEM_SUCCESS) { if (variable_get(VAR_NO_CONFIRM)) msgNotify("Loading of dependant package %s failed", cp); else msgConfirm("Loading of dependant package %s failed", cp); } } else if (!package_exists(cp)) { if (variable_get(VAR_NO_CONFIRM)) msgNotify("Warning: %s is a required package but was not found.", cp); else msgConfirm("Warning: %s is a required package but was not found.", cp); } if (cp2) cp = cp2 + 1; else cp = NULL; } } /* Done with the deps? Load the real m'coy */ if (DITEM_STATUS(status) == DITEM_SUCCESS) { status = package_extract(dev, who->name, depended); if (DITEM_STATUS(status) == DITEM_SUCCESS) id->installed = 1; } restorescr(w); return status; } static void index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie) { char depends[1024], *space, *todo; PkgNodePtr found; IndexEntryPtr found_ie; SAFE_STRCPY(depends, ie->deps); for (todo = depends; todo != NULL; ) { space = index(todo, ' '); if (space != NULL) *space = '\0'; if (strlen(todo) > 0) { /* only non-empty dependencies */ found = index_search(root, todo, NULL); if (found != NULL) { found_ie = found->data; if (add) ++found_ie->depc; else --found_ie->depc; } } if (space != NULL) todo = space + 1; else todo = NULL; } } static Boolean index_initted; /* Read and initialize global index */ int index_initialize(char *path) { FILE *fp; WINDOW *w = NULL; if (!index_initted) { w = savescr(); dialog_clear_norefresh(); /* Got any media? */ if (!mediaVerify()) { restorescr(w); return DITEM_FAILURE; } /* Does it move when you kick it? */ if (!mediaDevice->init(mediaDevice)) { restorescr(w); return DITEM_FAILURE; } dialog_clear_norefresh(); msgNotify("Attempting to fetch %s file from selected media.", path); fp = mediaDevice->get(mediaDevice, path, TRUE); if (!fp) { msgConfirm("Unable to get packages/INDEX file from selected media.\n" "This may be because the packages collection is not available at\n" "on the distribution media you've chosen (most likely an FTP site\n" "without the packages collection mirrored). Please verify media\n" "(or path to media) and try again. If your local site does not\n" "carry the packages collection, then we recommend either a CD\n" "distribution or the master distribution on ftp.freebsd.org."); mediaDevice->shutdown(mediaDevice); restorescr(w); return DITEM_FAILURE; } dialog_clear_norefresh(); msgNotify("Located INDEX, now reading package data from it..."); index_init(&Top, &Plist); if (index_read(fp, &Top)) { msgConfirm("I/O or format error on packages/INDEX file.\n" "Please verify media (or path to media) and try again."); fclose(fp); restorescr(w); return DITEM_FAILURE; } fclose(fp); index_sort(&Top); index_initted = TRUE; restorescr(w); } return DITEM_SUCCESS; } Index: head/release/sysinstall/install.c =================================================================== --- head/release/sysinstall/install.c (revision 70004) +++ head/release/sysinstall/install.c (revision 70005) @@ -1,1130 +1,1128 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include #include #include #include #define MSDOSFS #include #include #include #undef MSDOSFS #include #include #include #include /* Hack for rsaref package add, which displays interactive license. * Used by package.c */ int _interactiveHack; int FixItMode = 0; static void create_termcap(void); static void fixit_common(void); #define TERMCAP_FILE "/usr/share/misc/termcap" static void installConfigure(void); Boolean checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev) { Device **devs; Boolean status; Disk *disk; Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; int i; /* Don't allow whinging if noWarn is set */ if (variable_get(VAR_NO_WARN)) whinge = FALSE; status = TRUE; *rdev = *sdev = *udev = *vdev = rootdev = swapdev = usrdev = vardev = NULL; /* We don't need to worry about root/usr/swap if we're already multiuser */ if (!RunningAsInit) return status; devs = deviceFind(NULL, DEVICE_TYPE_DISK); /* First verify that we have a root device */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for root filesystem\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/")) { if (rootdev) { if (whinge) msgConfirm("WARNING: You have more than one root device set?!\n" "Using the first one found."); continue; } else { rootdev = c2; if (isDebug()) msgDebug("Found rootdev at %s!\n", rootdev->name); } } else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) { if (usrdev) { if (whinge) msgConfirm("WARNING: You have more than one /usr filesystem.\n" "Using the first one found."); continue; } else { usrdev = c2; if (isDebug()) msgDebug("Found usrdev at %s!\n", usrdev->name); } } else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/var")) { if (vardev) { if (whinge) msgConfirm("WARNING: You have more than one /var filesystem.\n" "Using the first one found."); continue; } else { vardev = c2; if (isDebug()) msgDebug("Found vardev at %s!\n", vardev->name); } } } } } } } /* Now check for swap devices */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for swap partitions\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) { swapdev = c2; if (isDebug()) msgDebug("Found swapdev at %s!\n", swapdev->name); break; } } } } } /* Copy our values over */ *rdev = rootdev; *sdev = swapdev; *udev = usrdev; *vdev = vardev; if (!rootdev && whinge) { msgConfirm("No root device found - you must label a partition as /\n" "in the label editor."); status = FALSE; } if (!swapdev && whinge) { msgConfirm("No swap devices found - you must create at least one\n" "swap partition."); status = FALSE; } return status; } static int installInitial(void) { static Boolean alreadyDone = FALSE; int status = DITEM_SUCCESS; if (alreadyDone) return DITEM_SUCCESS; if (!variable_get(DISK_LABELLED)) { msgConfirm("You need to assign disk labels before you can proceed with\n" "the installation."); return DITEM_FAILURE; } /* If it's labelled, assume it's also partitioned */ if (!variable_get(DISK_PARTITIONED)) variable_set2(DISK_PARTITIONED, "yes", 0); /* If we refuse to proceed, bail. */ dialog_clear_norefresh(); if (!variable_get(VAR_NO_WARN)) if (msgYesNo( "Last Chance! Are you SURE you want continue the installation?\n\n" "If you're running this on a disk with data you wish to save\n" "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n" "proceeding!\n\n" "We can take no responsibility for lost disk contents!") != 0) return DITEM_FAILURE; if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { msgConfirm("Couldn't make filesystems properly. Aborting."); return DITEM_FAILURE; } if (!copySelf()) { msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n" "root file system. Aborting!"); return DITEM_FAILURE; } if (chroot("/mnt") == -1) { msgConfirm("installInitial: Unable to chroot to %s - this is bad!", "/mnt"); return DITEM_FAILURE; } chdir("/"); variable_set2(RUNNING_ON_ROOT, "yes", 0); /* Configure various files in /etc */ if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; /* stick a helpful shell over on the 4th VTY */ systemCreateHoloshell(); alreadyDone = TRUE; return status; } int installFixitHoloShell(dialogMenuItem *self) { FixItMode = 1; systemCreateHoloshell(); return DITEM_SUCCESS; FixItMode = 0; } int installFixitCDROM(dialogMenuItem *self) { struct stat sb; if (!RunningAsInit) return DITEM_SUCCESS; variable_set2(SYSTEM_STATE, "fixit", 0); (void)unlink("/mnt2"); (void)rmdir("/mnt2"); while (1) { msgConfirm("Please insert a FreeBSD live filesystem CDROM and press return"); if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) { /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */ mediaClose(); if (msgYesNo("Unable to mount the CDROM - do you want to try again?") != 0) return DITEM_FAILURE; } else break; } /* Since the fixit code expects everything to be in /mnt2, and the CDROM mounting stuff /dist, do * a little kludge dance here.. */ if (symlink("/dist", "/mnt2")) { msgConfirm("Unable to symlink /mnt2 to the CDROM mount point. Please report this\n" "unexpected failure to freebsd-bugs@FreeBSD.org."); return DITEM_FAILURE; } /* * If /tmp points to /mnt2/tmp from a previous fixit floppy session, it's * not very good for us if we point it to the CDROM now. Rather make it * a directory in the root MFS then. Experienced admins will still be * able to mount their disk's /tmp over this if they need. */ if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK) (void)unlink("/tmp"); Mkdir("/tmp"); /* * Since setuid binaries ignore LD_LIBRARY_PATH, we indeed need the * ld.so.hints file. Fortunately, it's fairly small (~ 3 KB). */ if (!file_readable("/var/run/ld.so.hints")) { Mkdir("/var/run"); if (vsystem("/mnt2/sbin/ldconfig -s /mnt2/usr/lib")) { msgConfirm("Warning: ldconfig could not create the ld.so hints file.\n" "Dynamic executables from the CDROM likely won't work."); } } /* Yet more iggly hardcoded pathnames. */ Mkdir("/usr/libexec"); if (!file_readable("/usr/libexec/ld.so") && file_readable("/mnt2/usr/libexec/ld.so")) { if (symlink("/mnt2/usr/libexec/ld.so", "/usr/libexec/ld.so")) msgDebug("Couldn't link to ld.so - not necessarily a problem for ELF\n"); } if (!file_readable("/usr/libexec/ld-elf.so.1")) { if (symlink("/mnt2/usr/libexec/ld-elf.so.1", "/usr/libexec/ld-elf.so.1")) { msgConfirm("Warning: could not create the symlink for ld-elf.so.1\n" "Dynamic executables from the CDROM likely won't work."); } } /* optional nicety */ if (!file_readable("/usr/bin/vi")) symlink("/mnt2/usr/bin/vi", "/usr/bin/vi"); fixit_common(); mediaClose(); msgConfirm("Please remove the FreeBSD fixit CDROM now."); return DITEM_SUCCESS; } int installFixitFloppy(dialogMenuItem *self) { struct ufs_args args; extern char *distWanted; if (!RunningAsInit) return DITEM_SUCCESS; /* Try to open the floppy drive */ if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) { msgConfirm("Unable to set media device to floppy."); mediaClose(); return DITEM_FAILURE; } memset(&args, 0, sizeof(args)); args.fspec = mediaDevice->devname; mediaDevice->private = "/mnt2"; distWanted = NULL; Mkdir("/mnt2"); variable_set2(SYSTEM_STATE, "fixit", 0); while (1) { if (!mediaDevice->init(mediaDevice)) { if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n" "or unclean filesystem. Do you want to try again?")) return DITEM_FAILURE; } else break; } if (!directory_exists("/tmp")) (void)symlink("/mnt2/tmp", "/tmp"); fixit_common(); mediaClose(); msgConfirm("Please remove the fixit floppy now."); return DITEM_SUCCESS; } /* * The common code for both fixit variants. */ static void fixit_common(void) { pid_t child; int waitstatus; if (!directory_exists("/var/tmp/vi.recover")) { if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) { msgConfirm("Warning: Was unable to create a /var/tmp/vi.recover directory.\n" "vi will kvetch and moan about it as a result but should still\n" "be essentially usable."); } } if (!directory_exists("/bin")) (void)Mkdir("/bin"); (void)symlink("/stand/sh", "/bin/sh"); /* Link the /etc/ files */ if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS) msgConfirm("Unable to create an /etc directory! Things are weird on this floppy.."); else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST)) msgConfirm("Couldn't symlink the /etc/ files! I'm not sure I like this.."); if (!file_readable(TERMCAP_FILE)) create_termcap(); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if (!(child = fork())) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("fixit: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(0, TCSANOW, &foo) == -1) msgDebug("fixit shell: Unable to set erase character.\n"); } else msgDebug("fixit shell: Unable to get terminal attributes!\n"); setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:" "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1); setenv("MAKEDEVPATH", "/sbin:/bin:/stand:" "/mnt2/sbin:/mnt2/bin:/mnt2/stand", 1); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Waiting for fixit shell to exit.\n" "When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here.\n\n"); fflush(stdout); } /* use the .profile from the fixit medium */ setenv("HOME", "/mnt2", 1); chdir("/mnt2"); execlp("sh", "-sh", 0); msgDebug("fixit shell: Failed to execute shell!\n"); _exit(1);; } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { dialog_clear_norefresh(); msgNotify("Waiting for fixit shell to exit. Go to VTY4 now by\n" "typing ALT-F4. When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here\n."); } (void)waitpid(child, &waitstatus, 0); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemResumeDialog(); } dialog_clear(); } int installExpress(dialogMenuItem *self) { int i; dialog_clear_norefresh(); variable_set2(SYSTEM_STATE, "express", 0); #ifndef __alpha__ if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) return i; #endif if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) return i; if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { i |= DITEM_LEAVE_MENU; /* Set default security level */ configSecurityModerate(NULL); /* Give user the option of one last configuration spree */ installConfigure(); } return i; } /* Standard mode installation */ int installStandard(dialogMenuItem *self) { int i, tries = 0; Device **devs; variable_set2(SYSTEM_STATE, "standard", 0); dialog_clear_norefresh(); #ifndef __alpha__ msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n" "scheme for your hard disk. If you simply wish to devote all disk space\n" "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n" "then use the (A)ll command to select the default partitioning scheme followed\n" "by a (Q)uit. If you wish to allocate only free space to FreeBSD, move to a\n" "partition marked \"unused\" and use the (C)reate command."); nodisks: if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (diskGetSelectCount(&devs) <= 0 && tries < 3) { msgConfirm("You need to select some disks to operate on! Be sure to use SPACE\n" "instead of RETURN in the disk selection menu when selecting a disk."); ++tries; goto nodisks; } #endif #ifdef __alpha__ msgConfirm("Now you need to create BSD partitions on the disk which you are\n" "installing to. If you have a reasonable amount of disk space (200MB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #else msgConfirm("Now you need to create BSD partitions inside of the fdisk partition(s)\n" "just created. If you have a reasonable amount of disk space (200MB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #endif if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { dialog_clear(); msgConfirm("Installation completed with some errors. You may wish to\n" "scroll through the debugging messages on VTY1 with the\n" "scroll-lock feature. You can also choose \"No\" at the next\n" "prompt and go back into the installation menus to try and retry\n" "whichever operations have failed."); return i; } else { dialog_clear(); msgConfirm("Congratulations! You now have FreeBSD installed on your system.\n\n" "We will now move on to the final configuration questions.\n" "For any option you do not wish to configure, simply select\n" "No.\n\n" "If you wish to re-enter this utility after the system is up, you\n" "may do so by typing: /stand/sysinstall."); } if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) { if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) { Device *tmp = tcpDeviceSelect(); if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!tmp->init(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); } dialog_clear_norefresh(); } - if (msgYesNo("Will this machine be a leaf node (e.g. will not forward packets\n" - "between interfaces)?")) + if (!msgNoYes("Do you want this machine to function as a network gateway?")) variable_set2("gateway_enable", "YES", 1); dialog_clear_norefresh(); - if (msgYesNo("Do you want to grant only normal users FTP access to this\n" - "host (e.g. no anonymous FTP connections)?")) + if (!msgNoYes("Do you want to have anonymous FTP access to this machine?")) configAnonFTP(self); dialog_clear_norefresh(); - if (!msgYesNo("Do you want to configure this machine as an NFS server?")) + if (!msgNoYes("Do you want to configure this machine as an NFS server?")) configNFSServer(self); dialog_clear_norefresh(); - if (!msgYesNo("Do you want to configure this machine as an NFS client?")) + if (!msgNoYes("Do you want to configure this machine as an NFS client?")) variable_set2("nfs_client_enable", "YES", 1); - if (!msgYesNo("Do you want to select a default security profile for\n" + if (!msgNoYes("Do you want to select a default security profile for\n" "this host (select No for \"medium\" security)?")) configSecurityProfile(self); else configSecurityModerate(self); dialog_clear_norefresh(); - if (!msgYesNo("Would you like to customize your system console settings?")) + if (!msgNoYes("Would you like to customize your system console settings?")) dmenuOpenSimple(&MenuSyscons, FALSE); dialog_clear_norefresh(); if (!msgYesNo("Would you like to set this machine's time zone now?")) systemExecute("tzsetup"); #ifdef __i386__ dialog_clear_norefresh(); if (!msgYesNo("Would you like to enable Linux binary compatibility?")) (void)configLinux(self); #endif dialog_clear_norefresh(); - if (!msgYesNo("Does this system have a non-USB mouse attached to it?")) + if (!msgNoYes("Does this system have a USB mouse attached to it?")) dmenuOpenSimple(&MenuMouse, FALSE); /* Now would be a good time to checkpoint the configuration data */ configRC_conf(); sync(); if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); if (!msgYesNo("Would you like to configure your X server at this time?")) (void)configXSetup(self); } dialog_clear_norefresh(); if (!msgYesNo("The FreeBSD package collection is a collection of thousands of ready-to-run\n" "applications, from text editors to games to WEB servers and more. Would you\n" "like to browse the collection now?")) { (void)configPackages(self); } if (!msgYesNo("Would you like to add any initial user accounts to the system?\n" "Adding at least one account for yourself at this stage is suggested\n" "since working as the \"root\" user is dangerous (it is easy to do\n" "things which adversely affect the entire system).")) (void)configUsers(self); msgConfirm("Now you must set the system manager's password.\n" "This is the password you'll use to log in as \"root\"."); if (!systemExecute("passwd root")) variable_set2("root_password", "YES", 0); /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */ /* Give user the option of one last configuration spree */ dialog_clear_norefresh(); installConfigure(); return DITEM_LEAVE_MENU; } /* The version of commit we call from the Install Custom menu */ int installCustomCommit(dialogMenuItem *self) { int i; i = installCommit(self); if (DITEM_STATUS(i) == DITEM_SUCCESS) { /* Set default security level */ configSecurityModerate(NULL); /* Give user the option of one last configuration spree */ installConfigure(); return i; } else msgConfirm("The commit operation completed with errors. Not\n" "updating /etc files."); return i; } /* * What happens when we finally decide to going ahead with the installation. * * This is broken into multiple stages so that the user can do a full * installation but come back here again to load more distributions, * perhaps from a different media type. This would allow, for * example, the user to load the majority of the system from CDROM and * then use ftp to load just the CRYPTO dist. */ int installCommit(dialogMenuItem *self) { int i; char *str; dialog_clear_norefresh(); if (!Dists) distConfig(NULL); if (!Dists) { (void)dmenuOpenSimple(&MenuDistributions, FALSE); /* select reasonable defaults if necessary */ if (!Dists) Dists = _DIST_USER; } if (!mediaVerify()) return DITEM_FAILURE; str = variable_get(SYSTEM_STATE); if (isDebug()) msgDebug("installCommit: System state is `%s'\n", str); /* Installation stuff we wouldn't do to a running system */ if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) return i; try_media: if (!mediaDevice->init(mediaDevice)) { if (!msgYesNo("Unable to initialize selected media. Would you like to\n" "adjust your media configuration and try again?")) { mediaDevice = NULL; if (!mediaVerify()) return DITEM_FAILURE; else goto try_media; } else return DITEM_FAILURE; } /* Now go get it all */ i = distExtractAll(self); /* When running as init, *now* it's safe to grab the rc.foo vars */ installEnvironment(); variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0); return i; } static void installConfigure(void) { /* Final menu of last resort */ - if (!msgYesNo("Visit the general configuration menu for a chance to set\n" + if (!msgNoYes("Visit the general configuration menu for a chance to set\n" "any last options?")) dmenuOpenSimple(&MenuConfigure, FALSE); configRC_conf(); sync(); } int installFixupBin(dialogMenuItem *self) { Device **devs; char *cp; int i; FILE *fp; int kstat = 1; /* All of this is done only as init, just to be safe */ if (RunningAsInit) { #ifdef __i386__ /* Snapshot any boot -c changes back to the new kernel */ cp = variable_get(VAR_KGET); if (cp && (*cp == 'Y' || *cp == 'y')) { if ((kstat = kget("/boot/kernel.conf")) != NULL) { msgConfirm("Unable to save boot -c changes to new kernel,\n" "please see the debug screen (ALT-F2) for details."); } } if ((fp = fopen("/boot/loader.conf", "a")) != NULL) { if (!kstat || !OnVTY) fprintf(fp, "# -- sysinstall generated deltas -- #\n"); if (!kstat) fprintf(fp, "userconfig_script_load=\"YES\"\n"); if (!OnVTY) fprintf(fp, "console=\"comconsole\"\n"); fclose(fp); } #endif /* BOGON #1: Resurrect /dev after bin distribution screws it up */ dialog_clear_norefresh(); msgNotify("Remaking all devices.. Please wait!"); if (vsystem("cd /dev; sh MAKEDEV all")) { msgConfirm("MAKEDEV returned non-zero status"); return DITEM_FAILURE | DITEM_RESTORE; } dialog_clear_norefresh(); msgNotify("Resurrecting /dev entries for slices.."); devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) msgFatal("Couldn't get a disk device list!"); /* Resurrect the slices that the former clobbered */ for (i = 0; devs[i]; i++) { Disk *disk = (Disk *)devs[i]->private; Chunk *c1; if (!devs[i]->enabled) continue; if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { dialog_clear_norefresh(); msgNotify("Making slice entries for %s", c1->name); if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) { msgConfirm("Unable to make slice entries for %s!", c1->name); return DITEM_FAILURE | DITEM_RESTORE; } } } } /* BOGON #2: We leave /etc in a bad state */ chmod("/etc", 0755); /* BOGON #3: No /var/db/mountdtab complains */ Mkdir("/var/db"); creat("/var/db/mountdtab", 0644); /* BOGON #4: /compat created by default in root fs */ Mkdir("/usr/compat"); vsystem("ln -s /usr/compat /compat"); /* BOGON #5: aliases database not build for bin */ vsystem("newaliases"); /* Now run all the mtree stuff to fix things up */ vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /"); vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var"); vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr"); /* Do all the last ugly work-arounds here */ } return DITEM_SUCCESS | DITEM_RESTORE; } /* Fix side-effects from the the XFree86 installation */ int installFixupXFree(dialogMenuItem *self) { /* BOGON #1: XFree86 requires various specialized fixups */ if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); msgNotify("Fixing permissions in XFree86 tree.."); vsystem("chmod -R a+r /usr/X11R6"); vsystem("find /usr/X11R6 -type d | xargs chmod a+x"); /* Also do bogus minimal package registration so ports don't whine */ if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) { dialog_clear_norefresh(); msgNotify("Installing package metainfo.."); vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz"); } } return DITEM_SUCCESS | DITEM_RESTORE; } /* Go newfs and/or mount all the filesystems we've been asked to */ int installFilesystems(dialogMenuItem *self) { int i; Disk *disk; Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; Device **devs; PartInfo *root; char dname[80]; extern int MakeDevChunk(Chunk *c, char *n); Boolean upgrade = FALSE; /* If we've already done this, bail out */ if (!variable_cmp(DISK_LABELLED, "written")) return DITEM_SUCCESS; upgrade = !variable_cmp(SYSTEM_STATE, "upgrade"); if (!checkLabels(TRUE, &rootdev, &swapdev, &usrdev, &vardev)) return DITEM_FAILURE; if (rootdev) root = (PartInfo *)rootdev->private_data; else root = NULL; command_clear(); if (swapdev && RunningAsInit) { /* As the very first thing, try to get ourselves some swap space */ sprintf(dname, "/dev/%s", swapdev->name); if (!Fake && (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname))) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE; } if (!Fake) { if (!swapon(dname)) { dialog_clear_norefresh(); msgNotify("Added %s as initial swap device", dname); } else { msgConfirm("WARNING! Unable to swap to %s: %s\n" "This may cause the installation to fail at some point\n" "if you don't have a lot of memory.", dname, strerror(errno)); } } } if (rootdev && RunningAsInit) { /* Next, create and/or mount the root device */ sprintf(dname, "/dev/%s", rootdev->name); if (!Fake && (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname))) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE | DITEM_RESTORE; } if (strcmp(root->mountpoint, "/")) msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint); - if (root->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs the root partition?"))) { + if (root->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs the root partition?"))) { int i; dialog_clear_norefresh(); msgNotify("Making a new root filesystem on %s", dname); i = vsystem("%s %s", root->newfs_cmd, dname); if (i) { msgConfirm("Unable to make new root filesystem on %s!\n" "Command returned status %d", dname, i); return DITEM_FAILURE | DITEM_RESTORE; } } else { if (!upgrade) { msgConfirm("Warning: Using existing root partition. It will be assumed\n" "that you have the appropriate device entries already in /dev."); } dialog_clear_norefresh(); msgNotify("Checking integrity of existing %s filesystem.", dname); i = vsystem("fsck -y %s", dname); if (i) msgConfirm("Warning: fsck returned status of %d for %s.\n" "This partition may be unsafe to use.", i, dname); } /* Switch to block device */ sprintf(dname, "/dev/%s", rootdev->name); if (Mount("/mnt", dname)) { msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); return DITEM_FAILURE | DITEM_RESTORE; } } /* Now buzz through the rest of the partitions and mount them too */ devs = deviceFind(NULL, DEVICE_TYPE_DISK); for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; if (!disk->chunks) { msgConfirm("No chunk list found for %s!", disk->name); return DITEM_FAILURE | DITEM_RESTORE; } if (RunningAsInit && root && (root->newfs || upgrade)) { Mkdir("/mnt/dev"); if (!Fake) MakeDevDisk(disk, "/mnt/dev"); } else if (!RunningAsInit && !Fake) MakeDevDisk(disk, "/dev"); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { PartInfo *tmp = (PartInfo *)c2->private_data; /* Already did root */ if (c2 == rootdev) continue; - if (tmp->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) + if (tmp->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) command_shell_add(tmp->mountpoint, "%s %s/dev/%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name); else command_shell_add(tmp->mountpoint, "fsck -y %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); command_func_add(tmp->mountpoint, Mount, c2->name); } else if (c2->type == part && c2->subtype == FS_SWAP) { char fname[80]; int i; if (c2 == swapdev) continue; sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); i = (Fake || swapon(fname)); if (!i) { dialog_clear_norefresh(); msgNotify("Added %s as an additional swap device", fname); } else { msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); } } } } else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) { char name[FILENAME_MAX]; sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint); Mkdir(name); } } } if (RunningAsInit) { dialog_clear_norefresh(); msgNotify("Copying initial device files.."); /* Copy the boot floppy's dev files */ if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't clone the /dev files!"); return DITEM_FAILURE | DITEM_RESTORE; } } command_sort(); command_execute(); dialog_clear_norefresh(); return DITEM_SUCCESS | DITEM_RESTORE; } static char * getRelname(void) { static char buf[64]; int sz = (sizeof buf) - 1; if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) { buf[sz] = '\0'; return buf; } else return ""; } /* Initialize various user-settable values to their defaults */ int installVarDefaults(dialogMenuItem *self) { char *cp; /* Set default startup options */ variable_set2(VAR_RELNAME, getRelname(), 0); variable_set2(VAR_CPIO_VERBOSITY, "high", 0); variable_set2(VAR_KGET, "YES", 0); variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE, 0); variable_set2(VAR_INSTALL_ROOT, "/", 0); variable_set2(VAR_INSTALL_CFG, "install.cfg", 0); variable_set2(VAR_TRY_DHCP, "NO", 0); /* For now */ variable_set2(VAR_TRY_RTSOL, "NO", 0); /* For now */ cp = getenv("EDITOR"); if (!cp) cp = "/usr/bin/ee"; variable_set2(VAR_EDITOR, cp, 0); variable_set2(VAR_FTP_USER, "ftp", 0); variable_set2(VAR_BROWSER_PACKAGE, "lynx", 0); variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/lynx", 0); variable_set2(VAR_FTP_STATE, "passive", 0); variable_set2(VAR_NFS_SECURE, "NO", -1); if (OnVTY) variable_set2(VAR_FIXIT_TTY, "standard", 0); else variable_set2(VAR_FIXIT_TTY, "serial", 0); variable_set2(VAR_PKG_TMPDIR, "/usr/tmp", 0); variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT), 0); if (getpid() != 1) variable_set2(SYSTEM_STATE, "update", 0); else variable_set2(SYSTEM_STATE, "init", 0); variable_set2(VAR_NEWFS_ARGS, "-b 8192 -f 1024", 0); return DITEM_SUCCESS; } /* Load the environment up from various system configuration files */ void installEnvironment(void) { configEnvironmentRC_conf(); if (file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); } /* Copy the boot floppy contents into /stand */ Boolean copySelf(void) { int i; if (file_readable("/boot.help")) vsystem("cp /boot.help /mnt"); msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (i) { msgConfirm("Copy returned error status of %d!", i); return FALSE; } /* Copy the /etc files into their rightful place */ if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't copy up the /etc files!"); return TRUE; } return TRUE; } static void create_termcap(void) { FILE *fp; const char *caps[] = { termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r, termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, termcap_xterm, NULL, }; const char **cp; if (!file_readable(TERMCAP_FILE)) { Mkdir("/usr/share/misc"); fp = fopen(TERMCAP_FILE, "w"); if (!fp) { msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work."); return; } cp = caps; while (*cp) fprintf(fp, "%s\n", *(cp++)); fclose(fp); } } Index: head/release/sysinstall/label.c =================================================================== --- head/release/sysinstall/label.c (revision 70004) +++ head/release/sysinstall/label.c (revision 70005) @@ -1,1289 +1,1289 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include /* * Everything to do with editing the contents of disk labels. */ /* A nice message we use a lot in the disklabel editor */ #define MSG_NOT_APPLICABLE "That option is not applicable here" /* Where to start printing the freebsd slices */ #define CHUNK_SLICE_START_ROW 2 #define CHUNK_PART_START_ROW 11 /* The smallest filesystem we're willing to create */ #define FS_MIN_SIZE ONE_MEG /* The smallest root filesystem we're willing to create */ #ifdef __alpha__ #define ROOT_MIN_SIZE 40 #else #define ROOT_MIN_SIZE 30 #endif /* The default root filesystem size */ #ifdef __alpha__ #define ROOT_DEFAULT_SIZE 70 #else #define ROOT_DEFAULT_SIZE 50 #endif /* The smallest swap partition we want to create by default */ #define SWAP_MIN_SIZE 32 /* The smallest /usr partition we're willing to create by default */ #define USR_MIN_SIZE 80 /* The smallest /var partition we're willing to create by default */ #define VAR_MIN_SIZE 20 /* The bottom-most row we're allowed to scribble on */ #define CHUNK_ROW_MAX 16 /* All the chunks currently displayed on the screen */ static struct { struct chunk *c; PartType type; } label_chunk_info[MAX_CHUNKS + 1]; static int here; /*** with this value we try to track the most recently added label ***/ static int label_focus = 0, pslice_focus = 0; static int diskLabel(Device *dev); static int diskLabelNonInteractive(Device *dev); static int labelHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskLabel(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int labelCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskLabelEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt; i = 0; cnt = diskGetSelectCount(&devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ if (variable_get(VAR_NONINTERACTIVE)) i = diskLabelNonInteractive(NULL); else i = diskLabel(NULL); } else { /* No disks are selected, fall-back case now */ cnt = deviceCount(devs); if (cnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE)) i = diskLabelNonInteractive(devs[0]); else i = diskLabel(devs[0]); } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); i = DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } } } if (DITEM_STATUS(i) != DITEM_FAILURE) { char *cp; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } return i; } int diskLabelCommit(dialogMenuItem *self) { char *cp; int i; /* Already done? */ if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) i = DITEM_SUCCESS; else if (!cp) { msgConfirm("You must assign disk labels before this option can be used."); i = DITEM_FAILURE; } /* The routine will guard against redundant writes, just as this one does */ else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else { msgInfo("All filesystem information written successfully."); variable_set2(DISK_LABELLED, "written", 0); i = DITEM_SUCCESS; } return i; } /* See if we're already using a desired partition name */ static Boolean check_conflict(char *name) { int i; for (i = 0; label_chunk_info[i].c; i++) if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) && label_chunk_info[i].c->private_data && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) return TRUE; return FALSE; } /* How much space is in this FreeBSD slice? */ static int space_free(struct chunk *c) { struct chunk *c1; int sz = c->size; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != unused) sz -= c1->size; } if (sz < 0) msgFatal("Partitions are larger than actual chunk??"); return sz; } /* Snapshot the current situation into the displayed chunks structure */ static void record_label_chunks(Device **devs, Device *dev) { int i, j, p; struct chunk *c1, *c2; Disk *d; j = p = 0; /* First buzz through and pick up the FreeBSD slices */ for (i = 0; devs[i]; i++) { if ((dev && devs[i] != dev) || !devs[i]->enabled) continue; d = (Disk *)devs[i]->private; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); /* Put the slice entries first */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = c1; ++j; } } } /* Now run through again and get the FreeBSD partition entries */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; d = (Disk *)devs[i]->private; /* Then buzz through and pick up the partitions */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part) { if (c2->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c2; ++j; } } } else if (c1->type == fat) { label_chunk_info[j].type = PART_FAT; label_chunk_info[j].c = c1; ++j; } } } label_chunk_info[j].c = NULL; if (here >= j) { here = j ? j - 1 : 0; } } /* A new partition entry */ static PartInfo * new_part(char *mpoint, Boolean newfs, u_long size) { PartInfo *ret; if (!mpoint) mpoint = "/change_me"; ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); strcpy(ret->newfs_cmd, "newfs "); strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS)); ret->newfs = newfs; if (!size) return ret; return ret; } /* Get the mountpoint for a partition and save it away */ static PartInfo * get_mountpoint(struct chunk *old) { char *val; PartInfo *tmp; if (old && old->private_data) tmp = old->private_data; else tmp = NULL; val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); if (!val || !*val) { if (!old) return NULL; else { free(old->private_data); old->private_data = NULL; } return NULL; } /* Is it just the same value? */ if (tmp && !strcmp(tmp->mountpoint, val)) return NULL; /* Did we use it already? */ if (check_conflict(val)) { msgConfirm("You already have a mount point for %s assigned!", val); return NULL; } /* Is it bogus? */ if (*val != '/') { msgConfirm("Mount point must start with a / character"); return NULL; } /* Is it going to be mounted on root? */ if (!strcmp(val, "/")) { if (old) old->flags |= CHUNK_IS_ROOT; } else if (old) old->flags &= ~CHUNK_IS_ROOT; safe_free(tmp); val = string_skipwhite(string_prune(val)); tmp = new_part(val, TRUE, 0); if (old) { old->private_data = tmp; old->private_free = safe_free; } return tmp; } /* Get the type of the new partiton */ static PartType get_partition_type(void) { char selection[20]; int i; static unsigned char *fs_types[] = { "FS", "A file system", "Swap", "A swap partition.", }; WINDOW *w = savescr(); i = dialog_menu("Please choose a partition type", "If you want to use this partition for swap space, select Swap.\n" "If you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL); restorescr(w); if (!i) { if (!strcmp(selection, "FS")) return PART_FILESYSTEM; else if (!strcmp(selection, "Swap")) return PART_SWAP; } return PART_NONE; } /* If the user wants a special newfs command for this, set it */ static void getNewfsCmd(PartInfo *p) { char *val; val = msgGetInput(p->newfs_cmd, "Please enter the newfs command and options you'd like to use in\n" "creating this file system."); if (val) sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); } #define MAX_MOUNT_NAME 10 #define PART_PART_COL 0 #define PART_MOUNT_COL 10 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) #define PART_NEWFS_COL (PART_SIZE_COL + 8) #define PART_OFF 38 #define TOTAL_AVAIL_LINES (10) #define PSLICE_SHOWABLE (4) /* stick this all up on the screen */ static void print_label_chunks(void) { int i, j, srow, prow, pcol; int sz; char clrmsg[80]; int ChunkPartStartRow; WINDOW *ChunkWin; /********************************************************/ /*** These values are for controling screen resources ***/ /*** Each label line holds up to 2 labels, so beware! ***/ /*** strategy will be to try to always make sure the ***/ /*** highlighted label is in the active display area. ***/ /********************************************************/ int pslice_max, label_max; int pslice_count, label_count, label_focus_found, pslice_focus_found; attrset(A_REVERSE); mvaddstr(0, 25, "FreeBSD Disklabel Editor"); attrset(A_NORMAL); /*** Count the number of parition slices ***/ pslice_count = 0; for (i = 0; label_chunk_info[i].c ; i++) { if (label_chunk_info[i].type == PART_SLICE) ++pslice_count; } pslice_max = pslice_count; /*** 4 line max for partition slices ***/ if (pslice_max > PSLICE_SHOWABLE) { pslice_max = PSLICE_SHOWABLE; } ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; /*** View partition slices modulo pslice_max ***/ label_max = TOTAL_AVAIL_LINES - pslice_max; for (i = 0; i < 2; i++) { mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); } srow = CHUNK_SLICE_START_ROW; prow = 0; pcol = 0; /*** these variables indicate that the focused item is shown currently ***/ label_focus_found = 0; pslice_focus_found = 0; label_count = 0; pslice_count = 0; mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); wclear(ChunkWin); /*** wrefresh(ChunkWin); ***/ for (i = 0; label_chunk_info[i].c; i++) { /* Is it a slice entry displayed at the top? */ if (label_chunk_info[i].type == PART_SLICE) { /*** This causes the new pslice to replace the previous display ***/ /*** focus must remain on the most recently active pslice ***/ if (pslice_count == pslice_max) { if (pslice_focus_found) { /*** This is where we can mark the more following ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); attrset(A_NORMAL); continue; } else { /*** this is where we set the more previous ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); attrset(A_NORMAL); pslice_count = 0; srow = CHUNK_SLICE_START_ROW; } } sz = space_free(label_chunk_info[i].c); if (i == here) attrset(ATTR_SELECTED); if (i == pslice_focus) pslice_focus_found = -1; mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); attrset(A_NORMAL); clrtoeol(); move(0, 0); /*** refresh(); ***/ ++pslice_count; } /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ else { char onestr[PART_OFF], num[10], *mountpoint, *newfs; /* * We copy this into a blank-padded string so that it looks like * a solid bar in reverse-video */ memset(onestr, ' ', PART_OFF - 1); onestr[PART_OFF - 1] = '\0'; /*** Track how many labels have been displayed ***/ if (label_count == ((label_max - 1 ) * 2)) { if (label_focus_found) { continue; } else { label_count = 0; prow = 0; pcol = 0; } } /* Go for two columns if we've written one full columns worth */ /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ if (label_count == label_max - 1) { pcol = PART_OFF; prow = 0; } memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); /* If it's a filesystem, display the mountpoint */ if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; else if (label_chunk_info[i].type == PART_SWAP) mountpoint = "swap"; else mountpoint = ""; /* Now display the newfs field */ if (label_chunk_info[i].type == PART_FAT) newfs = "DOS"; else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; else if (label_chunk_info[i].type == PART_SWAP) newfs = "SWAP"; else newfs = "*"; for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) onestr[PART_MOUNT_COL + j] = mountpoint[j]; snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); memcpy(onestr + PART_SIZE_COL, num, strlen(num)); memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; if (i == label_focus) { label_focus_found = -1; wattrset(ChunkWin, A_BOLD); } if (i == here) wattrset(ChunkWin, ATTR_SELECTED); /*** lazy man's way of padding this string ***/ while (strlen( onestr ) < 37) strcat(onestr, " "); mvwaddstr(ChunkWin, prow, pcol, onestr); wattrset(ChunkWin, A_NORMAL); move(0, 0); ++prow; ++label_count; } } /*** this will erase all the extra stuff ***/ memset(clrmsg, ' ', 37); clrmsg[37] = '\0'; while (pslice_count < pslice_max) { mvprintw(srow++, 0, clrmsg); clrtoeol(); ++pslice_count; } while (label_count < (2 * (label_max - 1))) { mvwaddstr(ChunkWin, prow++, pcol, clrmsg); ++label_count; if (prow == (label_max - 1)) { prow = 0; pcol = PART_OFF; } } refresh(); wrefresh(ChunkWin); } static void print_command_summary(void) { mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); if (!RunningAsInit) mvprintw(18, 49, "W = Write"); mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); mvprintw(20, 0, "A = Auto Defaults for all!"); mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } static void clear_wins(void) { extern void print_label_chunks(); clear(); print_label_chunks(); } #ifdef __alpha__ /* * If there isn't a freebsd chunk already (i.e. there is no label), * dedicate the disk. */ static void maybe_dedicate(Disk* d) { struct chunk *c; for (c = d->chunks->part; c; c = c->next) { if (c->type == freebsd) break; } if (!c) { msgDebug("dedicating disk"); All_FreeBSD(d, 1); } } #endif static int diskLabel(Device *dev) { int sz, key = 0; Boolean labeling; char *msg = NULL; PartInfo *p, *oldp; PartType type; Device **devs; #ifdef __alpha__ int i; #endif WINDOW *w = savescr(); label_focus = 0; pslice_focus = 0; here = 0; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("No disks found!"); restorescr(w); return DITEM_FAILURE; } labeling = TRUE; keypad(stdscr, TRUE); #ifdef __alpha__ for (i = 0; devs[i]; i++) { maybe_dedicate((Disk*) devs[i]->private); } #endif record_label_chunks(devs, dev); clear(); while (labeling) { char *cp; print_label_chunks(); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); clrtoeol(); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } refresh(); key = getch(); switch (toupper(key)) { int i; static char _msg[40]; case '\014': /* ^L */ clear_wins(); break; case '\020': /* ^P */ case KEY_UP: case '-': if (here != 0) --here; else while (label_chunk_info[here + 1].c) ++here; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (label_chunk_info[here + 1].c) ++here; else here = 0; break; case KEY_HOME: here = 0; break; case KEY_END: while (label_chunk_info[here + 1].c) ++here; break; case KEY_F(1): case '?': systemDisplayHelp("partition"); clear_wins(); break; case 'A': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a disk slice (at top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) msg = "Not enough free space to create a new partition in the slice"; else { struct chunk *tmp; int mib[2]; int physmem; size_t size, swsize; char *cp; Chunk *rootdev, *swapdev, *usrdev, *vardev; (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); if (!rootdev) { cp = variable_get(VAR_ROOT_SIZE); tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); if (!tmp) { msgConfirm("Unable to create the root partition. Too big?"); clear_wins(); break; } tmp->private_data = new_part("/", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!swapdev) { cp = variable_get(VAR_SWAP_SIZE); if (cp) swsize = atoi(cp) * ONE_MEG; else { mib[0] = CTL_HW; mib[1] = HW_PHYSMEM; size = sizeof physmem; sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); swsize = 16 * ONE_MEG + (physmem * 2 / 512); } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, swsize, part, FS_SWAP, 0); if (!tmp) { msgConfirm("Unable to create the swap partition. Too big?"); clear_wins(); break; } tmp->private_data = 0; tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!vardev) { cp = variable_get(VAR_VAR_SIZE); if (cp) sz = atoi(cp) * ONE_MEG; else sz = variable_get(VAR_NO_USR) ? space_free(label_chunk_info[here].c) : VAR_MIN_SIZE * ONE_MEG; tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, 0); if (!tmp) { msgConfirm("Less than %dMB free for /var - you will need to\n" "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); clear_wins(); break; } tmp->private_data = new_part("/var", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!usrdev && !variable_get(VAR_NO_USR)) { cp = variable_get(VAR_USR_SIZE); if (cp) sz = atoi(cp) * ONE_MEG; else sz = space_free(label_chunk_info[here].c); if (sz) { if (sz < (USR_MIN_SIZE * ONE_MEG)) { msgConfirm("Less than %dMB free for /usr - you will need to\n" "partition your disk manually with a custom install!", USR_MIN_SIZE); clear_wins(); break; } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, 0); if (!tmp) { msgConfirm("Unable to create the /usr partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"); clear_wins(); break; } tmp->private_data = new_part("/usr", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } } /* At this point, we're reasonably "labelled" */ if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } break; case 'C': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a master partition (see top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) { msg = "Not enough space to create an additional FreeBSD partition"; break; } else { char *val; int size; struct chunk *tmp; char osize[80]; u_long flags = 0; sprintf(osize, "%d", sz); val = msgGetInput(osize, "Please specify the partition size in blocks or append a trailing G for\n" "gigabytes, M for megabytes, or C for cylinders.\n" "%d blocks (%dMB) are free.", sz, sz / ONE_MEG); if (!val || (size = strtol(val, &cp, 0)) <= 0) { clear_wins(); break; } if (*cp) { if (toupper(*cp) == 'M') size *= ONE_MEG; else if (toupper(*cp) == 'G') size *= ONE_GIG; else if (toupper(*cp) == 'C') size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); } if (size <= FS_MIN_SIZE) { msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); clear_wins(); break; } type = get_partition_type(); if (type == PART_NONE) { clear_wins(); beep(); break; } if (type == PART_FILESYSTEM) { if ((p = get_mountpoint(NULL)) == NULL) { clear_wins(); beep(); break; } else if (!strcmp(p->mountpoint, "/")) flags |= CHUNK_IS_ROOT; else flags &= ~CHUNK_IS_ROOT; } else p = NULL; if ((flags & CHUNK_IS_ROOT)) { if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { msgConfirm("This region cannot be used for your root partition as the\n" "FreeBSD boot code cannot deal with a root partition created\n" "in that location. Please choose another location or smaller\n" "size for your root partition and try again!"); clear_wins(); break; } if (size < (ROOT_MIN_SIZE * ONE_MEG)) { msgConfirm("Warning: This is smaller than the recommended size for a\n" "root partition. For a variety of reasons, root\n" "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); } } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, size, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags); if (!tmp) { msgConfirm("Unable to create the partition. Too big?"); clear_wins(); break; } if (type != PART_SWAP) { /* This is needed to tell the newfs -u about the size */ tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); safe_free(p); } else tmp->private_data = p; tmp->private_free = safe_free; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); /*** This is where we assign focus to new label so it shows ***/ { int i; label_focus = -1; for (i = 0; label_chunk_info[i].c; ++i) { if (label_chunk_info[i].c == tmp) { label_focus = i; break; } } if (label_focus == -1) label_focus = i - 1; } } break; case KEY_DC: case 'D': /* delete */ if (label_chunk_info[here].type == PART_SLICE) { msg = MSG_NOT_APPLICABLE; break; } else if (label_chunk_info[here].type == PART_FAT) { msg = "Use the Disk Partition Editor to delete DOS partitions"; break; } Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); break; case 'M': /* mount */ switch(label_chunk_info[here].type) { case PART_SLICE: msg = MSG_NOT_APPLICABLE; break; case PART_SWAP: msg = "You don't need to specify a mountpoint for a swap partition."; break; case PART_FAT: case PART_FILESYSTEM: oldp = label_chunk_info[here].c->private_data; p = get_mountpoint(label_chunk_info[here].c); if (p) { if (!oldp) p->newfs = FALSE; if (label_chunk_info[here].type == PART_FAT && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") || !strcmp(p->mountpoint, "/var"))) { msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); strcpy(p->mountpoint, "/bogus"); } } if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); break; default: msgFatal("Bogus partition under cursor???"); break; } break; case 'N': /* Set newfs options */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) getNewfsCmd(label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; case 'T': /* Toggle newfs state */ if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); label_chunk_info[here].c->private_data = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } else msg = MSG_NOT_APPLICABLE; break; case 'U': clear(); if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written out your changes -\n" "it's too late to undo!"); } - else if (!msgYesNo("Are you SURE you want to Undo everything?")) { + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); for (i = 0; devs[i]; i++) { Disk *d; if (!devs[i]->enabled) continue; else if ((d = Open_Disk(devs[i]->name)) != NULL) { Free_Disk(devs[i]->private); devs[i]->private = d; diskPartition(devs[i]); } } record_label_chunks(devs, dev); } clear_wins(); break; case 'W': if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written out your changes - if you\n" "wish to overwrite them, you'll have to start this\n" "procedure again from the beginning."); } - else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" + else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_LABELLED, "yes", 0); diskLabelCommit(NULL); } clear_wins(); break; case '|': - if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" + if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" "This is an entirely undocumented feature which you are not\n" "expected to understand!")) { int i; Device **devs; dialog_clear(); end_dialog(); DialogActive = FALSE; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Can't find any disk devices!"); break; } for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { if (devs[i]->enabled) slice_wizard(((Disk *)devs[i]->private)); } if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); DialogActive = TRUE; record_label_chunks(devs, dev); clear_wins(); } else msg = "A most prudent choice!"; break; case '\033': /* ESC */ case 'Q': labeling = FALSE; break; default: beep(); sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); msg = _msg; break; } if (label_chunk_info[here].type == PART_SLICE) pslice_focus = here; else label_focus = here; } restorescr(w); return DITEM_SUCCESS; } static int diskLabelNonInteractive(Device *dev) { char *cp; PartType type; PartInfo *p; u_long flags = 0; int i, status; Device **devs; Disk *d; status = DITEM_SUCCESS; cp = variable_get(VAR_DISK); if (!cp) { msgConfirm("diskLabel: No disk selected - can't label automatically."); return DITEM_FAILURE; } devs = deviceFind(cp, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("diskLabel: No disk device %s found!", cp); return DITEM_FAILURE; } if (dev) d = dev->private; else d = devs[0]->private; #ifdef __alpha__ maybe_dedicate(d); #endif record_label_chunks(devs, dev); for (i = 0; label_chunk_info[i].c; i++) { Chunk *c1 = label_chunk_info[i].c; if (label_chunk_info[i].type == PART_SLICE) { char name[512]; int entries = 1; while (entries) { snprintf(name, sizeof name, "%s-%d", c1->name, entries); if ((cp = variable_get(name)) != NULL) { int sz; char typ[10], mpoint[50]; if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; continue; } else { Chunk *tmp; if (!strcmp(typ, "swap")) { type = PART_SWAP; strcpy(mpoint, "SWAP"); } else { type = PART_FILESYSTEM; if (!strcmp(mpoint, "/")) flags |= CHUNK_IS_ROOT; else flags &= ~CHUNK_IS_ROOT; } if (!sz) sz = space_free(c1); if (sz > space_free(c1)) { msgConfirm("Not enough free space to create partition: %s", mpoint); status = DITEM_FAILURE; continue; } if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { msgConfirm("Unable to create from partition spec: %s. Too big?", cp); status = DITEM_FAILURE; break; } else { tmp->private_data = new_part(mpoint, TRUE, sz); tmp->private_free = safe_free; status = DITEM_SUCCESS; } } entries++; } else { /* No more matches, leave the loop */ entries = 0; } } } else { /* Must be something we can set a mountpoint for */ cp = variable_get(c1->name); if (cp) { char mpoint[50], do_newfs[8]; Boolean newfs = FALSE; do_newfs[0] = '\0'; if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; continue; } newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; if (c1->private_data) { p = c1->private_data; p->newfs = newfs; strcpy(p->mountpoint, mpoint); } else { c1->private_data = new_part(mpoint, newfs, 0); c1->private_free = safe_free; } if (!strcmp(mpoint, "/")) c1->flags |= CHUNK_IS_ROOT; else c1->flags &= ~CHUNK_IS_ROOT; } } } if (status == DITEM_SUCCESS) variable_set2(DISK_LABELLED, "yes", 0); return status; } Index: head/release/sysinstall/main.c =================================================================== --- head/release/sysinstall/main.c (revision 70004) +++ head/release/sysinstall/main.c (revision 70005) @@ -1,165 +1,165 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated for what's essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include const char *StartName; /* Initial contents of argv[0] */ static void screech(int sig) { msgDebug("\007Signal %d caught! That's bad!\n", sig); longjmp(BailOut, sig); } int main(int argc, char **argv) { int choice, scroll, curr, max, status; /* Record name to be able to restart */ StartName = argv[0]; /* Catch fatal signals and complain about them if running as init */ if (getpid() == 1) { signal(SIGBUS, screech); signal(SIGSEGV, screech); } signal(SIGPIPE, SIG_IGN); /* We don't work too well when running as non-root anymore */ if (geteuid() != 0) { fprintf(stderr, "Error: This utility should only be run as root.\n"); return 1; } #ifdef PC98 { /* XXX */ char *p = getenv("TERM"); if (p && strcmp(p, "cons25") == 0) putenv("TERM=cons25w"); } #endif /* Set up whatever things need setting up */ systemInitialize(argc, argv); /* Set default flag and variable values */ installVarDefaults(NULL); /* only when multi-user is it reasonable to do this here */ if (!RunningAsInit) installEnvironment(); if (argc > 1 && !strcmp(argv[1], "-fake")) { variable_set2(VAR_DEBUG, "YES", 0); Fake = TRUE; msgConfirm("I'll be just faking it from here on out, OK?"); } /* Try to preserve our scroll-back buffer */ if (OnVTY) { for (curr = 0; curr < 25; curr++) putchar('\n'); } /* Move stderr aside */ if (DebugFD) dup2(DebugFD, 2); /* Initialize driver modules */ moduleInitialize(); /* Initialize PC-card */ pccardInitialize(); /* Initialize USB */ usbInitialize(); /* Probe for all relevant devices on the system */ deviceGetAll(); /* First, see if we have any arguments to process (and argv[0] counts if it's not "sysinstall") */ if (!RunningAsInit) { int i, start_arg; if (!strstr(argv[0], "sysinstall")) start_arg = 0; else if (Fake) start_arg = 2; else start_arg = 1; for (i = start_arg; i < argc; i++) { if (DITEM_STATUS(dispatchCommand(argv[i])) != DITEM_SUCCESS) systemShutdown(1); } if (argc > start_arg) systemShutdown(0); } else dispatch_load_file_int(TRUE); status = setjmp(BailOut); if (status) { msgConfirm("A signal %d was caught - I'm saving what I can and shutting\n" "If you can reproduce the problem, please turn Debug on in\n" "the Options menu for the extra information it provides in\n" "debugging problems like this.", status); systemShutdown(status); } /* Begin user dialog at outer menu */ dialog_clear(); while (1) { choice = scroll = curr = max = 0; dmenuOpen(&MenuInitial, &choice, &scroll, &curr, &max, TRUE); if (getpid() != 1 #ifdef __alpha__ - || !msgYesNo("Are you sure you wish to exit? The system will halt.") + || !msgNoYes("Are you sure you wish to exit? The system will halt.") #else - || !msgYesNo("Are you sure you wish to exit? The system will reboot\n" + || !msgNoYes("Are you sure you wish to exit? The system will reboot\n" "(be sure to remove any floppies/CDROMs from the drives).") #endif ) break; } /* Say goodnight, Gracie */ systemShutdown(0); return 0; /* We should never get here */ } Index: head/release/sysinstall/msg.c =================================================================== --- head/release/sysinstall/msg.c (revision 70004) +++ head/release/sysinstall/msg.c (revision 70005) @@ -1,328 +1,352 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include Boolean isDebug(void) { char *cp; return (cp = variable_get(VAR_DEBUG)) && strcmp(cp, "no"); } /* Whack up an informational message on the status line, in stand-out */ void msgYap(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); attrs = getattrs(stdscr); attrset(A_REVERSE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); } /* Whack up an informational message on the status line */ void msgInfo(char *fmt, ...) { va_list args; char *errstr; int i, attrs; char line[81]; attrs = getattrs(stdscr); /* NULL is a special convention meaning "erase the old stuff" */ if (!fmt) { move(StatusLine, 0); clrtoeol(); return; } errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); memset(line, ' ', 80); for (i = 0; i < 80; i++) { if (errstr[i]) line[i] = errstr[i]; else break; } line[80] = '\0'; attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, line); attrset(attrs); move(StatusLine, 79); refresh(); } /* Whack up a warning on the status line */ void msgWarn(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Warning: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); attrs = getattrs(stdscr); beep(); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); if (OnVTY && isDebug()) msgDebug("Warning message `%s'\n", errstr); } /* Whack up an error on the status line */ void msgError(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Error: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); beep(); attrs = getattrs(stdscr); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); if (OnVTY && isDebug()) msgDebug("Error message `%s'\n", errstr); } /* Whack up a fatal error on the status line */ void msgFatal(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Fatal Error: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); beep(); attrs = getattrs(stdscr); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); addstr(" - "); addstr("PRESS ANY KEY TO "); if (getpid() == 1) addstr("REBOOT"); else addstr("QUIT"); attrset(attrs); refresh(); if (OnVTY) msgDebug("Fatal error `%s'!\n", errstr); getch(); systemShutdown(1); } /* Put up a message in a popup confirmation box */ void msgConfirm(char *fmt, ...) { va_list args; char *errstr; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); msgInfo(NULL); } dialog_notify(errstr); restorescr(w); } /* Put up a message in a popup information box */ void msgNotify(char *fmt, ...) { va_list args; char *errstr; errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (isDebug()) msgDebug("Notify: %s\n", errstr); dialog_msgbox(NULL, errstr, -1, -1, 0); } /* Put up a message in a popup yes/no box and return 1 for YES, 0 for NO */ int msgYesNo(char *fmt, ...) { va_list args; char *errstr; int ret; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } ret = dialog_yesno("User Confirmation Requested", errstr, -1, -1); restorescr(w); return ret; } +/* Put up a message in a popup no/yes box and return 1 for YES, 0 for NO */ +int +msgNoYes(char *fmt, ...) +{ + va_list args; + char *errstr; + int ret; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); /* Switch back */ + msgInfo(NULL); + } + ret = dialog_noyes("User Confirmation Requested", errstr, -1, -1); + restorescr(w); + return ret; +} + /* Put up a message in an input box and return the value */ char * msgGetInput(char *buf, char *fmt, ...) { va_list args; char *errstr; static char input_buffer[256]; int rval; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (buf) SAFE_STRCPY(input_buffer, buf); else input_buffer[0] = '\0'; if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } rval = dialog_inputbox("Value Required", errstr, -1, -1, input_buffer); restorescr(w); if (!rval) return input_buffer; else return NULL; } /* Write something to the debugging port */ void msgDebug(char *fmt, ...) { va_list args; char *dbg; if (DebugFD == -1) return; dbg = (char *)alloca(FILENAME_MAX); strcpy(dbg, "DEBUG: "); va_start(args, fmt); vsnprintf((char *)(dbg + strlen(dbg)), FILENAME_MAX, fmt, args); va_end(args); write(DebugFD, dbg, strlen(dbg)); } /* Tell the user there's some output to go look at */ void msgWeHaveOutput(char *fmt, ...) { va_list args; char *errstr; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); msgDebug("Notify: %s\n", errstr); dialog_clear_norefresh(); sleep(2); dialog_msgbox(NULL, errstr, -1, -1, 0); restorescr(w); } /* Simple versions of msgConfirm() and msgNotify() for calling from scripts */ int msgSimpleConfirm(char *str) { msgConfirm(str); return DITEM_SUCCESS; } int msgSimpleNotify(char *str) { msgNotify(str); return DITEM_SUCCESS; } Index: head/release/sysinstall/sysinstall.h =================================================================== --- head/release/sysinstall/sysinstall.h (revision 70004) +++ head/release/sysinstall/sysinstall.h (revision 70005) @@ -1,771 +1,772 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef _SYSINSTALL_H_INCLUDE #define _SYSINSTALL_H_INCLUDE #include #include #include #include #include #include #include #include #include #include "ui_objects.h" #include "dir.h" #include "colors.h" #include "libdisk.h" #include "dist.h" /*** Defines ***/ /* device limits */ #define DEV_NAME_MAX 64 /* The maximum length of a device name */ #define DEV_MAX 100 /* The maximum number of devices we'll deal with */ #define INTERFACE_MAX 50 /* Maximum number of network interfaces we'll deal with */ #define IO_ERROR -2 /* Status code for I/O error rather than normal EOF */ /* Number of seconds to wait for data to come off even the slowest media */ #define MEDIA_TIMEOUT 300 /* * I make some pretty gross assumptions about having a max of 50 chunks * total - 8 slices and 42 partitions. I can't easily display many more * than that on the screen at once! * * For 2.1 I'll revisit this and try to make it more dynamic, but since * this will catch 99.99% of all possible cases, I'm not too worried. */ #define MAX_CHUNKS 40 /* Internal environment variable names */ #define DISK_PARTITIONED "_diskPartitioned" #define DISK_LABELLED "_diskLabelled" #define DISK_SELECTED "_diskSelected" #define SYSTEM_STATE "_systemState" #define RUNNING_ON_ROOT "_runningOnRoot" #define TCP_CONFIGURED "_tcpConfigured" /* Ones that can be tweaked from config files */ #define VAR_BLANKTIME "blanktime" #define VAR_BOOTMGR "bootManager" #define VAR_BROWSER_BINARY "browserBinary" #define VAR_BROWSER_PACKAGE "browserPackage" #define VAR_CPIO_VERBOSITY "cpioVerbose" #define VAR_DEBUG "debug" #define VAR_DESKSTYLE "_deskStyle" #define VAR_DISK "disk" #define VAR_DISTS "dists" #define VAR_DIST_MAIN "distMain" #define VAR_DIST_CRYPTO "distCRYPTO" #define VAR_DIST_SRC "distSRC" #define VAR_DIST_X11 "distX11" #define VAR_DIST_XSERVER "distXserver" #define VAR_DIST_XFONTS "distXfonts" #define VAR_DEDICATE_DISK "dedicateDisk" #define VAR_DOMAINNAME "domainname" #define VAR_EDITOR "editor" #define VAR_EXTRAS "ifconfig_" #define VAR_COMMAND "command" #define VAR_CONFIG_FILE "configFile" #define VAR_FIXIT_TTY "fixitTty" #define VAR_FTP_DIR "ftpDirectory" #define VAR_FTP_PASS "ftpPass" #define VAR_FTP_PATH "_ftpPath" #define VAR_FTP_PORT "ftpPort" #define VAR_FTP_STATE "ftpState" #define VAR_FTP_USER "ftpUser" #define VAR_FTP_HOST "ftpHost" #define VAR_HTTP_PATH "_httpPath" #define VAR_HTTP_PROXY "httpProxy" #define VAR_HTTP_PORT "httpPort" #define VAR_HTTP_HOST "httpHost" #define VAR_HTTP_FTP_MODE "httpFtpMode" #define VAR_GATEWAY "defaultrouter" #define VAR_GEOMETRY "geometry" #define VAR_HOSTNAME "hostname" #define VAR_IFCONFIG "ifconfig_" #define VAR_INTERFACES "network_interfaces" #define VAR_INSTALL_CFG "installConfig" #define VAR_INSTALL_ROOT "installRoot" #define VAR_IPADDR "ipaddr" #define VAR_IPV6_ENABLE "ipv6_enable" #define VAR_IPV6ADDR "ipv6addr" #define VAR_KEYMAP "keymap" #define VAR_KGET "kget" #define VAR_LABEL "label" #define VAR_LABEL_COUNT "labelCount" #define VAR_LINUX_ENABLE "linux_enable" #define VAR_MEDIA_TYPE "mediaType" #define VAR_MEDIA_TIMEOUT "MEDIA_TIMEOUT" #define VAR_MOUSED "moused_enable" #define VAR_MOUSED_FLAGS "moused_flags" #define VAR_MOUSED_PORT "moused_port" #define VAR_MOUSED_TYPE "moused_type" #define VAR_NAMESERVER "nameserver" #define VAR_NETINTERACTIVE "netInteractive" #define VAR_NETMASK "netmask" #define VAR_NETWORK_DEVICE "netDev" #define VAR_NEWFS_ARGS "newfsArgs" #define VAR_NFS_PATH "nfs" #define VAR_NFS_HOST "nfsHost" #define VAR_NFS_SECURE "nfs_reserved_port_only" #define VAR_NFS_SERVER "nfs_server_enable" #define VAR_NO_CONFIRM "noConfirm" #define VAR_NO_ERROR "noError" #define VAR_NO_WARN "noWarn" #define VAR_NO_USR "noUsr" #define VAR_NONINTERACTIVE "nonInteractive" #define VAR_NOVELL "novell" #define VAR_NTPDATE_FLAGS "ntpdate_flags" #define VAR_PACKAGE "package" #define VAR_PARTITION "partition" #define VAR_PCNFSD "pcnfsd" #define VAR_PKG_TMPDIR "PKG_TMPDIR" #define VAR_PORTS_PATH "ports" #define VAR_PPP_ENABLE "ppp_enable" #define VAR_PPP_PROFILE "ppp_profile" #define VAR_RELNAME "releaseName" #define VAR_ROOT_SIZE "rootSize" #define VAR_ROUTER "router" #define VAR_ROUTER_ENABLE "router_enable" #define VAR_ROUTERFLAGS "router_flags" #define VAR_SERIAL_SPEED "serialSpeed" #define VAR_SLOW_ETHER "slowEthernetCard" #define VAR_SWAP_SIZE "swapSize" #define VAR_TAPE_BLOCKSIZE "tapeBlocksize" #define VAR_TRY_DHCP "tryDHCP" #define VAR_TRY_RTSOL "tryRTSOL" #define VAR_UFS_PATH "ufs" #define VAR_USR_SIZE "usrSize" #define VAR_VAR_SIZE "varSize" #define VAR_XF86_CONFIG "_xf86config" #define DEFAULT_TAPE_BLOCKSIZE "20" /* One MB worth of blocks */ #define ONE_MEG 2048 #define ONE_GIG (ONE_MEG * 1024) /* Which selection attributes to use */ #define ATTR_SELECTED (ColorDisplay ? item_selected_attr : item_attr) #define ATTR_TITLE button_active_attr /* Handy strncpy() macro */ #define SAFE_STRCPY(to, from) sstrncpy((to), (from), sizeof (to) - 1) /*** Types ***/ typedef unsigned int Boolean; typedef struct disk Disk; typedef struct chunk Chunk; /* Bitfields for menu options */ #define DMENU_NORMAL_TYPE 0x1 /* Normal dialog menu */ #define DMENU_RADIO_TYPE 0x2 /* Radio dialog menu */ #define DMENU_CHECKLIST_TYPE 0x4 /* Multiple choice menu */ #define DMENU_SELECTION_RETURNS 0x8 /* Immediate return on item selection */ typedef struct _dmenu { int type; /* What sort of menu we are */ char *title; /* Our title */ char *prompt; /* Our prompt */ char *helpline; /* Line of help at bottom */ char *helpfile; /* Help file for "F1" */ dialogMenuItem items[0]; /* Array of menu items */ } DMenu; /* An rc.conf variable */ typedef struct _variable { struct _variable *next; char *name; char *value; int dirty; } Variable; #define NO_ECHO_OBJ(type) ((type) | (DITEM_NO_ECHO << 16)) #define TYPE_OF_OBJ(type) ((type) & 0xff) #define ATTR_OF_OBJ(type) ((type) >> 16) /* A screen layout structure */ typedef struct _layout { int y; /* x & Y co-ordinates */ int x; int len; /* The size of the dialog on the screen */ int maxlen; /* How much the user can type in ... */ char *prompt; /* The string for the prompt */ char *help; /* The display for the help line */ void *var; /* The var to set when this changes */ int type; /* The type of the dialog to create */ void *obj; /* The obj pointer returned by libdialog */ } Layout; typedef enum { DEVICE_TYPE_NONE, DEVICE_TYPE_DISK, DEVICE_TYPE_FLOPPY, DEVICE_TYPE_FTP, DEVICE_TYPE_NETWORK, DEVICE_TYPE_CDROM, DEVICE_TYPE_TAPE, DEVICE_TYPE_DOS, DEVICE_TYPE_UFS, DEVICE_TYPE_NFS, DEVICE_TYPE_ANY, DEVICE_TYPE_HTTP, } DeviceType; /* CDROM mount codes */ #define CD_UNMOUNTED 0 #define CD_ALREADY_MOUNTED 1 #define CD_WE_MOUNTED_IT 2 /* A "device" from sysinstall's point of view */ typedef struct _device { char name[DEV_NAME_MAX]; char *description; char *devname; DeviceType type; Boolean enabled; Boolean (*init)(struct _device *dev); FILE * (*get)(struct _device *dev, char *file, Boolean probe); void (*shutdown)(struct _device *dev); void *private; unsigned int flags; } Device; /* Some internal representations of partitions */ typedef enum { PART_NONE, PART_SLICE, PART_SWAP, PART_FILESYSTEM, PART_FAT, } PartType; /* The longest newfs command we'll hand to system() */ #define NEWFS_CMD_MAX 256 typedef struct _part_info { Boolean newfs; char mountpoint[FILENAME_MAX]; char newfs_cmd[NEWFS_CMD_MAX]; } PartInfo; /* An option */ typedef struct _opt { char *name; char *desc; enum { OPT_IS_STRING, OPT_IS_INT, OPT_IS_FUNC, OPT_IS_VAR } type; void *data; void *aux; char *(*check)(); } Option; /* Weird index nodey things we use for keeping track of package information */ typedef enum { PACKAGE, PLACE } node_type; /* Types of nodes */ typedef struct _pkgnode { /* A node in the reconstructed hierarchy */ struct _pkgnode *next; /* My next sibling */ node_type type; /* What am I? */ char *name; /* My name */ char *desc; /* My description (Hook) */ struct _pkgnode *kids; /* My little children */ void *data; /* A place to hang my data */ } PkgNode; typedef PkgNode *PkgNodePtr; /* A single package */ typedef struct _indexEntry { /* A single entry in an INDEX file */ char *name; /* name */ char *path; /* full path to port */ char *prefix; /* port prefix */ char *comment; /* one line description */ char *descrfile; /* path to description file */ char *deps; /* packages this depends on */ int depc; /* how many depend on me */ int installed; /* indicates if it is installed */ char *maintainer; /* maintainer */ } IndexEntry; typedef IndexEntry *IndexEntryPtr; typedef int (*commandFunc)(char *key, void *data); #define HOSTNAME_FIELD_LEN 128 #define IPADDR_FIELD_LEN 16 #define EXTRAS_FIELD_LEN 128 /* This is the structure that Network devices carry around in their private, erm, structures */ typedef struct _devPriv { int use_rtsol; int use_dhcp; char ipaddr[IPADDR_FIELD_LEN]; char netmask[IPADDR_FIELD_LEN]; char extras[EXTRAS_FIELD_LEN]; } DevInfo; /*** Externs ***/ extern jmp_buf BailOut; /* Used to get the heck out */ extern int DebugFD; /* Where diagnostic output goes */ extern Boolean Fake; /* Don't actually modify anything - testing */ extern Boolean SystemWasInstalled; /* Did we install it? */ extern Boolean RunningAsInit; /* Are we running stand-alone? */ extern Boolean DialogActive; /* Is the dialog() stuff up? */ extern Boolean ColorDisplay; /* Are we on a color display? */ extern Boolean OnVTY; /* On a syscons VTY? */ extern Variable *VarHead; /* The head of the variable chain */ extern Device *mediaDevice; /* Where we're getting our distribution from */ extern unsigned int Dists; /* Which distributions we want */ extern unsigned int CRYPTODists; /* Which naughty distributions we want */ extern unsigned int SrcDists; /* Which src distributions we want */ extern unsigned int XF86Dists; /* Which XFree86 dists we want */ extern unsigned int XF86ServerDists; /* The XFree86 servers we want */ extern unsigned int XF86FontDists; /* The XFree86 fonts we want */ extern int BootMgr; /* Which boot manager to use */ extern int StatusLine; /* Where to print our status messages */ extern DMenu MenuInitial; /* Initial installation menu */ extern DMenu MenuFixit; /* Fixit repair menu */ extern DMenu MenuMBRType; /* Type of MBR to write on the disk */ extern DMenu MenuConfigure; /* Final configuration menu */ extern DMenu MenuDocumentation; /* Documentation menu */ extern DMenu MenuFTPOptions; /* FTP Installation options */ extern DMenu MenuIndex; /* Index menu */ extern DMenu MenuOptions; /* Installation options */ extern DMenu MenuOptionsLanguage; /* Language options menu */ extern DMenu MenuMedia; /* Media type menu */ extern DMenu MenuMouse; /* Mouse type menu */ extern DMenu MenuMediaCDROM; /* CDROM media menu */ extern DMenu MenuMediaDOS; /* DOS media menu */ extern DMenu MenuMediaFloppy; /* Floppy media menu */ extern DMenu MenuMediaFTP; /* FTP media menu */ extern DMenu MenuMediaTape; /* Tape media menu */ extern DMenu MenuNetworkDevice; /* Network device menu */ extern DMenu MenuNTP; /* NTP time server menu */ extern DMenu MenuSecurityProfile; /* Security profile menu */ extern DMenu MenuStartup; /* Startup services menu */ extern DMenu MenuSyscons; /* System console configuration menu */ extern DMenu MenuSysconsFont; /* System console font configuration menu */ extern DMenu MenuSysconsKeymap; /* System console keymap configuration menu */ extern DMenu MenuSysconsKeyrate; /* System console keyrate configuration menu */ extern DMenu MenuSysconsSaver; /* System console saver configuration menu */ extern DMenu MenuSysconsScrnmap; /* System console screenmap configuration menu */ extern DMenu MenuNetworking; /* Network configuration menu */ extern DMenu MenuInstallCustom; /* Custom Installation menu */ extern DMenu MenuDistributions; /* Distribution menu */ extern DMenu MenuDiskDevices; /* Disk type devices */ extern DMenu MenuSubDistributions; /* Custom distribution menu */ extern DMenu MenuSrcDistributions; /* Source distribution menu */ extern DMenu MenuXF86; /* XFree86 main menu */ extern DMenu MenuXF86Select; /* XFree86 distribution selection menu */ extern DMenu MenuXF86SelectCore; /* XFree86 core distribution menu */ extern DMenu MenuXF86SelectServer; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectPC98Server; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuXDesktops; /* Disk devices menu */ extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ extern DMenu MenuUsermgmt; /* User management menu */ extern DMenu MenuFixit; /* Fixit floppy/CDROM/shell menu */ extern DMenu MenuXF86Config; /* Select XFree86 configuration type */ extern int FixItMode; /* FixItMode starts shell onc urrent device (ie Serial port) */ extern const char * StartName; /* Which name we were started as */ /* Stuff from libdialog which isn't properly declared outside */ extern void display_helpfile(void); extern void display_helpline(WINDOW *w, int y, int width); /*** Prototypes ***/ /* anonFTP.c */ extern int configAnonFTP(dialogMenuItem *self); /* cdrom.c */ extern Boolean mediaInitCDROM(Device *dev); extern FILE *mediaGetCDROM(Device *dev, char *file, Boolean probe); extern void mediaShutdownCDROM(Device *dev); /* command.c */ extern void command_clear(void); extern void command_sort(void); extern void command_execute(void); extern void command_shell_add(char *key, char *fmt, ...); extern void command_func_add(char *key, commandFunc func, void *data); /* config.c */ extern void configEnvironmentRC_conf(void); extern void configEnvironmentResolv(char *config); extern void configRC_conf(void); extern int configFstab(dialogMenuItem *self); extern int configRC(dialogMenuItem *self); extern int configResolv(dialogMenuItem *self); extern int configPackages(dialogMenuItem *self); extern int configSaver(dialogMenuItem *self); extern int configSaverTimeout(dialogMenuItem *self); extern int configLinux(dialogMenuItem *self); extern int configNTP(dialogMenuItem *self); extern int configUsers(dialogMenuItem *self); extern int configXSetup(dialogMenuItem *self); extern int configXDesktop(dialogMenuItem *self); extern int configRouter(dialogMenuItem *self); extern int configPCNFSD(dialogMenuItem *self); extern int configNFSServer(dialogMenuItem *self); extern int configWriteRC_conf(dialogMenuItem *self); extern int configSecurityProfile(dialogMenuItem *self); extern int configSecurityFascist(dialogMenuItem *self); extern int configSecurityHigh(dialogMenuItem *self); extern int configSecurityModerate(dialogMenuItem *self); extern int configSecurityLiberal(dialogMenuItem *self); /* crc.c */ extern int crc(int, unsigned long *, unsigned long *); /* devices.c */ extern DMenu *deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d)); extern void deviceGetAll(void); extern void deviceReset(void); extern void deviceRescan(void); extern Device **deviceFind(char *name, DeviceType type); extern Device **deviceFindDescr(char *name, char *desc, DeviceType class); extern int deviceCount(Device **devs); extern Device *new_device(char *name); extern Device *deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, Boolean (*init)(Device *mediadev), FILE * (*get)(Device *dev, char *file, Boolean probe), void (*shutDown)(Device *mediadev), void *private); extern Boolean dummyInit(Device *dev); extern FILE *dummyGet(Device *dev, char *dist, Boolean probe); extern void dummyShutdown(Device *dev); /* dhcp.c */ extern int dhcpParseLeases(char *file, char *hostname, char *domain, char *nameserver, char *ipaddr, char *gateway, char *netmask); /* disks.c */ extern int diskPartitionEditor(dialogMenuItem *self); extern int diskPartitionWrite(dialogMenuItem *self); extern int diskGetSelectCount(Device ***devs); extern void diskPartition(Device *dev); /* dispatch.c */ extern int dispatchCommand(char *command); extern int dispatch_load_floppy(dialogMenuItem *self); extern int dispatch_load_file_int(int); extern int dispatch_load_file(dialogMenuItem *self); /* dist.c */ extern int distReset(dialogMenuItem *self); extern int distConfig(dialogMenuItem *self); extern int distSetCustom(dialogMenuItem *self); extern int distUnsetCustom(dialogMenuItem *self); extern int distSetDeveloper(dialogMenuItem *self); extern int distSetXDeveloper(dialogMenuItem *self); extern int distSetKernDeveloper(dialogMenuItem *self); extern int distSetXKernDeveloper(dialogMenuItem *self); extern int distSetUser(dialogMenuItem *self); extern int distSetXUser(dialogMenuItem *self); extern int distSetMinimum(dialogMenuItem *self); extern int distSetEverything(dialogMenuItem *self); extern int distSetSrc(dialogMenuItem *self); extern int distSetXF86(dialogMenuItem *self); extern int distExtractAll(dialogMenuItem *self); /* dmenu.c */ extern int dmenuDisplayFile(dialogMenuItem *tmp); extern int dmenuSubmenu(dialogMenuItem *tmp); extern int dmenuSystemCommand(dialogMenuItem *tmp); extern int dmenuSystemCommandBox(dialogMenuItem *tmp); extern int dmenuExit(dialogMenuItem *tmp); extern int dmenuISetVariable(dialogMenuItem *tmp); extern int dmenuSetVariable(dialogMenuItem *tmp); extern int dmenuSetKmapVariable(dialogMenuItem *tmp); extern int dmenuSetVariables(dialogMenuItem *tmp); extern int dmenuToggleVariable(dialogMenuItem *tmp); extern int dmenuSetFlag(dialogMenuItem *tmp); extern int dmenuSetValue(dialogMenuItem *tmp); extern Boolean dmenuOpen(DMenu *menu, int *choice, int *scroll, int *curr, int *max, Boolean buttons); extern Boolean dmenuOpenSimple(DMenu *menu, Boolean buttons); extern int dmenuVarCheck(dialogMenuItem *item); extern int dmenuVarsCheck(dialogMenuItem *item); extern int dmenuFlagCheck(dialogMenuItem *item); extern int dmenuRadioCheck(dialogMenuItem *item); /* doc.c */ extern int docBrowser(dialogMenuItem *self); extern int docShowDocument(dialogMenuItem *self); /* dos.c */ extern Boolean mediaCloseDOS(Device *dev, FILE *fp); extern Boolean mediaInitDOS(Device *dev); extern FILE *mediaGetDOS(Device *dev, char *file, Boolean probe); extern void mediaShutdownDOS(Device *dev); /* floppy.c */ extern int getRootFloppy(void); extern Boolean mediaInitFloppy(Device *dev); extern FILE *mediaGetFloppy(Device *dev, char *file, Boolean probe); extern void mediaShutdownFloppy(Device *dev); /* ftp_strat.c */ extern Boolean mediaCloseFTP(Device *dev, FILE *fp); extern Boolean mediaInitFTP(Device *dev); extern FILE *mediaGetFTP(Device *dev, char *file, Boolean probe); extern void mediaShutdownFTP(Device *dev); /* http.c */ extern Boolean mediaInitHTTP(Device *dev); extern FILE *mediaGetHTTP(Device *dev, char *file, Boolean probe); /* globals.c */ extern void globalsInit(void); /* index.c */ int index_read(FILE *fp, PkgNodePtr papa); int index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll); void index_init(PkgNodePtr top, PkgNodePtr plist); void index_node_free(PkgNodePtr top, PkgNodePtr plist); void index_sort(PkgNodePtr top); void index_print(PkgNodePtr top, int level); int index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended); int index_initialize(char *path); PkgNodePtr index_search(PkgNodePtr top, char *str, PkgNodePtr *tp); /* install.c */ extern Boolean checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev); extern int installCommit(dialogMenuItem *self); extern int installCustomCommit(dialogMenuItem *self); extern int installExpress(dialogMenuItem *self); extern int installStandard(dialogMenuItem *self); extern int installFixitHoloShell(dialogMenuItem *self); extern int installFixitCDROM(dialogMenuItem *self); extern int installFixitFloppy(dialogMenuItem *self); extern int installFixupBin(dialogMenuItem *self); extern int installFixupXFree(dialogMenuItem *self); extern int installUpgrade(dialogMenuItem *self); extern int installFilesystems(dialogMenuItem *self); extern int installVarDefaults(dialogMenuItem *self); extern void installEnvironment(void); extern int installX11package(dialogMenuItem *self); extern Boolean copySelf(void); /* kget.c */ extern int kget(char *out); /* keymap.c */ extern int loadKeymap(const char *lang); /* label.c */ extern int diskLabelEditor(dialogMenuItem *self); extern int diskLabelCommit(dialogMenuItem *self); /* makedevs.c (auto-generated) */ extern const char termcap_ansi[]; extern const char termcap_vt100[]; extern const char termcap_cons25w[]; extern const char termcap_cons25[]; extern const char termcap_cons25_m[]; extern const char termcap_cons25r[]; extern const char termcap_cons25r_m[]; extern const char termcap_cons25l1[]; extern const char termcap_cons25l1_m[]; extern const char termcap_xterm[]; extern const u_char font_iso_8x16[]; extern const u_char font_cp850_8x16[]; extern const u_char font_cp866_8x16[]; extern const u_char koi8_r2cp866[]; extern u_char default_scrnmap[]; /* media.c */ extern char *cpioVerbosity(void); extern void mediaClose(void); extern int mediaTimeout(void); extern int mediaSetCDROM(dialogMenuItem *self); extern int mediaSetFloppy(dialogMenuItem *self); extern int mediaSetDOS(dialogMenuItem *self); extern int mediaSetTape(dialogMenuItem *self); extern int mediaSetFTP(dialogMenuItem *self); extern int mediaSetFTPActive(dialogMenuItem *self); extern int mediaSetFTPPassive(dialogMenuItem *self); extern int mediaSetHTTP(dialogMenuItem *self); extern int mediaSetUFS(dialogMenuItem *self); extern int mediaSetNFS(dialogMenuItem *self); extern int mediaSetFTPUserPass(dialogMenuItem *self); extern int mediaSetCPIOVerbosity(dialogMenuItem *self); extern int mediaGetType(dialogMenuItem *self); extern Boolean mediaExtractDist(char *dir, char *dist, FILE *fp); extern Boolean mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpic); extern Boolean mediaExtractDistEnd(int zpid, int cpid); extern Boolean mediaVerify(void); extern FILE *mediaGenericGet(char *base, const char *file); /* misc.c */ extern Boolean file_readable(char *fname); extern Boolean file_executable(char *fname); extern Boolean directory_exists(const char *dirname); extern char *root_bias(char *path); extern char *itoa(int value); extern char *string_concat(char *p1, char *p2); extern char *string_concat3(char *p1, char *p2, char *p3); extern char *string_prune(char *str); extern char *string_skipwhite(char *str); extern char *string_copy(char *s1, char *s2); extern char *pathBaseName(const char *path); extern void safe_free(void *ptr); extern void *safe_malloc(size_t size); extern void *safe_realloc(void *orig, size_t size); extern dialogMenuItem *item_add(dialogMenuItem *list, char *prompt, char *title, int (*checked)(dialogMenuItem *self), int (*fire)(dialogMenuItem *self), void (*selected)(dialogMenuItem *self, int is_selected), void *data, int aux, int *curr, int *max); extern void items_free(dialogMenuItem *list, int *curr, int *max); extern int Mkdir(char *); extern int Mount(char *, void *data); extern WINDOW *openLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height); extern ComposeObj *initLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max); extern int layoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, int *n, int max, int *cbutton, int *cancel); extern WINDOW *savescr(void); extern void restorescr(WINDOW *w); extern char *sstrncpy(char *dst, const char *src, int size); /* modules.c */ extern void moduleInitialize(void); /* mouse.c */ extern int mousedTest(dialogMenuItem *self); extern int mousedDisable(dialogMenuItem *self); extern int setMouseFlags(dialogMenuItem *self); /* msg.c */ extern Boolean isDebug(void); extern void msgInfo(char *fmt, ...); extern void msgYap(char *fmt, ...); extern void msgWarn(char *fmt, ...); extern void msgDebug(char *fmt, ...); extern void msgError(char *fmt, ...); extern void msgFatal(char *fmt, ...); extern void msgConfirm(char *fmt, ...); extern void msgNotify(char *fmt, ...); extern void msgWeHaveOutput(char *fmt, ...); extern int msgYesNo(char *fmt, ...); +extern int msgNoYes(char *fmt, ...); extern char *msgGetInput(char *buf, char *fmt, ...); extern int msgSimpleConfirm(char *); extern int msgSimpleNotify(char *); /* network.c */ extern Boolean mediaInitNetwork(Device *dev); extern void mediaShutdownNetwork(Device *dev); /* nfs.c */ extern Boolean mediaInitNFS(Device *dev); extern FILE *mediaGetNFS(Device *dev, char *file, Boolean probe); extern void mediaShutdownNFS(Device *dev); /* options.c */ extern int optionsEditor(dialogMenuItem *self); /* package.c */ extern int packageAdd(dialogMenuItem *self); extern int package_add(char *name); extern int package_extract(Device *dev, char *name, Boolean depended); extern Boolean package_exists(char *name); /* pccard.c */ extern void pccardInitialize(void); /* system.c */ extern void systemInitialize(int argc, char **argv); extern void systemShutdown(int status); extern int execExecute(char *cmd, char *name); extern int systemExecute(char *cmd); extern void systemSuspendDialog(void); extern void systemResumeDialog(void); extern int systemDisplayHelp(char *file); extern char *systemHelpFile(char *file, char *buf); extern void systemChangeFont(const u_char font[]); extern void systemChangeLang(char *lang); extern void systemChangeTerminal(char *color, const u_char c_termcap[], char *mono, const u_char m_termcap[]); extern void systemChangeScreenmap(const u_char newmap[]); extern void systemCreateHoloshell(void); extern int vsystem(char *fmt, ...); /* tape.c */ extern char *mediaTapeBlocksize(void); extern Boolean mediaInitTape(Device *dev); extern FILE *mediaGetTape(Device *dev, char *file, Boolean probe); extern void mediaShutdownTape(Device *dev); /* tcpip.c */ extern int tcpOpenDialog(Device *dev); extern int tcpMenuSelect(dialogMenuItem *self); extern Device *tcpDeviceSelect(void); /* termcap.c */ extern int set_termcap(void); /* ufs.c */ extern void mediaShutdownUFS(Device *dev); extern Boolean mediaInitUFS(Device *dev); extern FILE *mediaGetUFS(Device *dev, char *file, Boolean probe); /* usb.c */ extern void usbInitialize(void); /* user.c */ extern int userAddGroup(dialogMenuItem *self); extern int userAddUser(dialogMenuItem *self); /* variable.c */ extern void variable_set(char *var, int dirty); extern void variable_set2(char *name, char *value, int dirty); extern char *variable_get(char *var); extern int variable_cmp(char *var, char *value); extern void variable_unset(char *var); extern char *variable_get_value(char *var, char *prompt, int dirty); extern int variable_check(char *data); extern int dump_variables(dialogMenuItem *self); /* wizard.c */ extern void slice_wizard(Disk *d); #endif /* _SYSINSTALL_H_INCLUDE */ Index: head/release/sysinstall/system.c =================================================================== --- head/release/sysinstall/system.c (revision 70004) +++ head/release/sysinstall/system.c (revision 70005) @@ -1,506 +1,506 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Jordan Hubbard * * My contributions are in the public domain. * * Parts of this file are also blatently stolen from Poul-Henning Kamp's * previous version of sysinstall, and as such fall under his "BEERWARE license" * so buy him a beer if you like it! Buy him a beer for me, too! * Heck, get him completely drunk and send me pictures! :-) */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include /* Where we stick our temporary expanded doc file */ #define DOC_TMP_DIR "/tmp/.doc" #define DOC_TMP_FILE "/tmp/.doc/doc.tmp" static pid_t ehs_pid; /* * Handle interrupt signals - this probably won't work in all cases * due to our having bogotified the internal state of dialog or curses, * but we'll give it a try. */ static int intr_continue(dialogMenuItem *self) { return DITEM_LEAVE_MENU; } static int intr_reboot(dialogMenuItem *self) { systemShutdown(-1); /* NOTREACHED */ return 0; } static int intr_restart(dialogMenuItem *self) { execl(StartName, StartName, NULL); /* NOTREACHED */ return -1; } static dialogMenuItem intrmenu[] = { { "Abort", "Abort the installation", NULL, intr_reboot }, { "Restart", "Restart the installation program", NULL, intr_restart }, { "Continue", "Continue the installation", NULL, intr_continue }, }; static void handle_intr(int sig) { WINDOW *save = savescr(); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } (void)dialog_menu("Installation interrupt", "Do you want to abort the installation?", -1, -1, 3, -3, intrmenu, NULL, NULL, NULL); restorescr(save); } /* Expand a file into a convenient location, nuking it each time */ static char * expand(char *fname) { char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip"; if (!directory_exists(DOC_TMP_DIR)) { Mkdir(DOC_TMP_DIR); if (chown(DOC_TMP_DIR, 0, 0) < 0) return NULL; if (chmod(DOC_TMP_DIR, S_IRWXU) < 0) return NULL; } else unlink(DOC_TMP_FILE); if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE)) return NULL; return DOC_TMP_FILE; } /* Initialize system defaults */ void systemInitialize(int argc, char **argv) { int i, boothowto; sigset_t signalset; signal(SIGINT, SIG_IGN); globalsInit(); i = sizeof(boothowto); if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, NULL) && (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE)) variable_set2(VAR_DEBUG, "YES", 0); /* Are we running as init? */ if (getpid() == 1) { int fd, type; RunningAsInit = 1; setsid(); close(0); fd = open("/dev/ttyv0", O_RDWR); if (fd == -1) { fd = open("/dev/console", O_RDWR); /* fallback */ variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */ } else OnVTY = TRUE; /* * To make _sure_ we're on a VTY and don't have /dev/console switched * away to a serial port or something, attempt to set the cursor appearance. */ type = 0; /* normal */ if (OnVTY) { int fd2; if ((fd2 = open("/dev/console", O_RDWR)) != -1) { if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) { OnVTY = FALSE; variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit the console type */ close(fd); close(fd2); open("/dev/console", O_RDWR); } else close(fd2); } } close(1); dup(0); close(2); dup(0); printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console"); ioctl(0, TIOCSCTTY, (char *)NULL); setlogin("root"); setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1); setbuf(stdin, 0); setbuf(stderr, 0); #ifdef __alpha__ i = 0; sysctlbyname("machdep.unaligned_print", NULL, 0, &i, sizeof(i)); #endif } else { char hname[256]; /* Initalize various things for a multi-user environment */ if (!gethostname(hname, sizeof hname)) variable_set2(VAR_HOSTNAME, hname, 0); } if (set_termcap() == -1) { printf("Can't find terminal entry\n"); exit(-1); } /* XXX - libdialog has particularly bad return value checking */ init_dialog(); /* If we haven't crashed I guess dialog is running ! */ DialogActive = TRUE; /* Make sure HOME is set for those utilities that need it */ if (!getenv("HOME")) setenv("HOME", "/", 1); signal(SIGINT, handle_intr); /* * Make sure we can be interrupted even if we were re-executed * from an interrupt. */ sigemptyset(&signalset); sigaddset(&signalset, SIGINT); sigprocmask(SIG_UNBLOCK, &signalset, NULL); (void)vsystem("rm -rf %s", DOC_TMP_DIR); } /* Close down and prepare to exit */ void systemShutdown(int status) { /* If some media is open, close it down */ if (status >=0) mediaClose(); /* write out any changes to rc.conf .. */ configRC_conf(); /* Shut down the dialog library */ if (DialogActive) { end_dialog(); DialogActive = FALSE; } /* Shut down curses */ endwin(); /* If we have a temporary doc dir lying around, nuke it */ (void)vsystem("rm -rf %s", DOC_TMP_DIR); /* REALLY exit! */ if (RunningAsInit) { /* Put the console back */ ioctl(0, VT_ACTIVATE, 2); #ifdef __alpha__ reboot(RB_HALT); #else reboot(0); #endif } else exit(status); } /* Run some general command */ int systemExecute(char *command) { int status; struct termios foo; WINDOW *w = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; tcsetattr(0, TCSANOW, &foo); } if (!Fake) status = system(command); else { status = 0; msgDebug("systemExecute: Faked execution of `%s'\n", command); } DialogActive = TRUE; restorescr(w); return status; } /* suspend/resume libdialog/curses screen */ static WINDOW *oldW; void systemSuspendDialog(void) { oldW = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; } void systemResumeDialog(void) { DialogActive = TRUE; restorescr(oldW); } /* Display a help file in a filebox */ int systemDisplayHelp(char *file) { char *fname = NULL; char buf[FILENAME_MAX]; int ret = 0; WINDOW *w = savescr(); fname = systemHelpFile(file, buf); if (!fname) { snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file); use_helpfile(NULL); use_helpline(NULL); dialog_mesgbox("Sorry!", buf, -1, -1); ret = 1; } else { use_helpfile(NULL); use_helpline(NULL); dialog_textbox(file, fname, LINES, COLS); } restorescr(w); return ret; } char * systemHelpFile(char *file, char *buf) { if (!file) return NULL; if (file[0] == '/') return file; snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.hlp", file); if (file_readable(buf)) return buf; snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.TXT", file); if (file_readable(buf)) return buf; return NULL; } void systemChangeTerminal(char *color, const u_char c_term[], char *mono, const u_char m_term[]) { if (OnVTY) { int setupterm(char *color, int, int *); if (ColorDisplay) { setenv("TERM", color, 1); setenv("TERMCAP", c_term, 1); reset_shell_mode(); setterm(color); cbreak(); noecho(); } else { setenv("TERM", mono, 1); setenv("TERMCAP", m_term, 1); reset_shell_mode(); setterm(mono); cbreak(); noecho(); } } clear(); refresh(); dialog_clear(); } int vsystem(char *fmt, ...) { va_list args; int pstat; pid_t pid; int omask; sig_t intsave, quitsave; char *cmd; int i; cmd = (char *)alloca(FILENAME_MAX); cmd[0] = '\0'; va_start(args, fmt); vsnprintf(cmd, FILENAME_MAX, fmt, args); va_end(args); omask = sigblock(sigmask(SIGCHLD)); if (Fake) { msgDebug("vsystem: Faked execution of `%s'\n", cmd); return 0; } if (isDebug()) msgDebug("Executing command `%s'\n", cmd); pid = fork(); if (pid == -1) { (void)sigsetmask(omask); i = 127; } else if (!pid) { /* Junior */ (void)sigsetmask(omask); if (DebugFD != -1) { dup2(DebugFD, 0); dup2(DebugFD, 1); dup2(DebugFD, 2); } else { close(1); open("/dev/null", O_WRONLY); dup2(1, 2); } if (!RunningAsInit) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); else execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL); exit(1); } else { intsave = signal(SIGINT, SIG_IGN); quitsave = signal(SIGQUIT, SIG_IGN); pid = waitpid(pid, &pstat, 0); (void)sigsetmask(omask); (void)signal(SIGINT, intsave); (void)signal(SIGQUIT, quitsave); i = (pid == -1) ? -1 : WEXITSTATUS(pstat); if (isDebug()) msgDebug("Command `%s' returns status of %d\n", cmd, i); } return i; } void systemCreateHoloshell(void) { int waitstatus; if ((FixItMode || OnVTY) && RunningAsInit) { if (ehs_pid != 0) { int pstat; if (kill(ehs_pid, 0) == 0) { - if (msgYesNo("There seems to be an emergency holographic shell\n" + if (msgNoYes("There seems to be an emergency holographic shell\n" "already running on VTY 4.\n\n" "Kill it and start a new one?")) return; /* try cleaning up as much as possible */ (void) kill(ehs_pid, SIGHUP); sleep(1); (void) kill(ehs_pid, SIGKILL); } /* avoid too many zombies */ (void) waitpid(ehs_pid, &pstat, WNOHANG); } if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if ((ehs_pid = fork()) == 0) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("Doctor: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(fd, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(fd, TCSANOW, &foo) == -1) msgDebug("Doctor: I'm unable to set the erase character.\n"); } else msgDebug("Doctor: I'm unable to get the terminal attributes!\n"); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n"); fflush(stdout); } execlp("sh", "-sh", 0); msgDebug("Was unable to execute sh for Holographic shell!\n"); exit(1); } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { WINDOW *w = savescr(); msgNotify("Starting an emergency holographic shell on VTY4"); sleep(2); restorescr(w); } else { (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for shell to finish it serial mode since there is no virtual console */ systemResumeDialog(); } } } } Index: head/release/sysinstall/tcpip.c =================================================================== --- head/release/sysinstall/tcpip.c (revision 70004) +++ head/release/sysinstall/tcpip.c (revision 70005) @@ -1,582 +1,582 @@ /* * $FreeBSD$ * * Copyright (c) 1995 * Gary J Palmer. All rights reserved. * Copyright (c) 1996 * Jordan K. Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * All kinds of hacking also performed by jkh on this code. Don't * blame Gary for every bogosity you see here.. :-) * * -jkh */ #include "sysinstall.h" #include #include #include #include #include /* The help file for the TCP/IP setup screen */ #define TCP_HELPFILE "tcp" /* These are nasty, but they make the layout structure a lot easier ... */ static char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN]; static int okbutton, cancelbutton; static char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; static char ipv6addr[INET6_ADDRSTRLEN]; /* What the screen size is meant to be */ #define TCP_DIALOG_Y 0 #define TCP_DIALOG_X 8 #define TCP_DIALOG_WIDTH COLS - 16 #define TCP_DIALOG_HEIGHT LINES - 2 static Layout layout[] = { #define LAYOUT_HOSTNAME 0 { 1, 2, 25, HOSTNAME_FIELD_LEN - 1, "Host:", "Your fully-qualified hostname, e.g. foo.bar.com", hostname, STRINGOBJ, NULL }, #define LAYOUT_DOMAINNAME 1 { 1, 35, 20, HOSTNAME_FIELD_LEN - 1, "Domain:", "The name of the domain that your machine is in, e.g. bar.com", domainname, STRINGOBJ, NULL }, #define LAYOUT_GATEWAY 2 { 5, 2, 18, IPADDR_FIELD_LEN - 1, "IPv4 Gateway:", "IPv4 address of host forwarding packets to non-local destinations", gateway, STRINGOBJ, NULL }, #define LAYOUT_NAMESERVER 3 { 5, 35, 18, INET6_ADDRSTRLEN - 1, "Name server:", "IPv4 or IPv6 address of your local DNS server", nameserver, STRINGOBJ, NULL }, #define LAYOUT_IPADDR 4 { 10, 10, 18, IPADDR_FIELD_LEN - 1, "IPv4 Address:", "The IPv4 address to be used for this interface", ipaddr, STRINGOBJ, NULL }, #define LAYOUT_NETMASK 5 { 10, 35, 18, IPADDR_FIELD_LEN - 1, "Netmask:", "The netmask for this interface, e.g. 0xffffff00 for a class C network", netmask, STRINGOBJ, NULL }, #define LAYOUT_EXTRAS 6 { 14, 10, 37, HOSTNAME_FIELD_LEN - 1, "Extra options to ifconfig:", "Any interface-specific options to ifconfig you would like to add", extras, STRINGOBJ, NULL }, #define LAYOUT_OKBUTTON 7 { 19, 15, 0, 0, "OK", "Select this if you are happy with these settings", &okbutton, BUTTONOBJ, NULL }, #define LAYOUT_CANCELBUTTON 8 { 19, 35, 0, 0, "CANCEL", "Select this if you wish to cancel this screen", &cancelbutton, BUTTONOBJ, NULL }, { NULL }, }; #define _validByte(b) ((b) >= 0 && (b) <= 255) /* whine */ static void feepout(char *msg) { beep(); msgConfirm(msg); } /* Very basic IP address integrity check - could be drastically improved */ static int verifyIP(char *ip) { int a, b, c, d; if (ip && sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d) == 4 && _validByte(a) && _validByte(b) && _validByte(c) && _validByte(d) && (d != 255)) return 1; else return 0; } static int verifyIP6(char *ip) { struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(ip, NULL, &hints, &res) == 0) { freeaddrinfo(res); return 1; } return 0; } /* Check for the settings on the screen - the per-interface stuff is moved to the main handling code now to do it on the fly - sigh */ static int verifySettings(void) { if (!hostname[0]) feepout("Must specify a host name of some sort!"); else if (gateway[0] && strcmp(gateway, "NO") && !verifyIP(gateway)) feepout("Invalid gateway IPv4 address specified"); else if (nameserver[0] && !verifyIP(nameserver) && !verifyIP6(nameserver)) feepout("Invalid name server IP address specified"); else if (netmask[0] && (netmask[0] < '0' && netmask[0] > '3')) feepout("Invalid netmask value"); else if (ipaddr[0] && !verifyIP(ipaddr)) feepout("Invalid IPv4 address"); else return 1; return 0; } static void dhcpGetInfo(Device *devp) { /* If it fails, do it the old-fashioned way */ if (dhcpParseLeases("/var/db/dhclient.leases", hostname, domainname, nameserver, ipaddr, gateway, netmask) == -1) { FILE *ifp; char *cp, cmd[256], data[2048]; int i, j; /* Bah, now we have to kludge getting the information from ifconfig */ snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); ifp = popen(cmd, "r"); if (ifp) { j = fread(data, 1, sizeof(data), ifp); fclose(ifp); if (j < 0) /* paranoia */ j = 0; data[j] = '\0'; if (isDebug()) msgDebug("DHCP configured interface returns %s\n", data); /* XXX This is gross as it assumes a certain ordering to ifconfig's output! XXX */ if ((cp = strstr(data, "inet ")) != NULL) { i = 0; cp += 5; /* move over keyword */ while (*cp != ' ') ipaddr[i++] = *(cp++); ipaddr[i] = '\0'; if (!strncmp(++cp, "netmask", 7)) { i = 0; cp += 8; while (*cp != ' ') netmask[i++] = *(cp++); netmask[i] = '\0'; } } } } /* If we didn't get a name server value, hunt for it in resolv.conf */ if (!nameserver[0] && file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); if (hostname[0]) variable_set2(VAR_HOSTNAME, hostname, 0); } static void rtsolGetInfo(Device *devp) { FILE *ifp; char *cp, cmd[256], data[2048]; int i; snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); if ((ifp = popen(cmd, "r")) == NULL) return; while (fgets(data, sizeof(data), ifp) != NULL) { if (isDebug()) msgDebug("RTSOL configured interface returns %s", data); if ((cp = strstr(data, "inet6 ")) != NULL) { cp += 6; /* move over keyword */ if (strncmp(cp, "fe80:", 5)) { i = 0; while (*cp != ' ') ipv6addr[i++] = *(cp++); ipv6addr[i] = '\0'; } } } fclose(ifp); } /* This is it - how to get TCP setup values */ int tcpOpenDialog(Device *devp) { WINDOW *ds_win, *save = NULL; ComposeObj *obj = NULL; int n = 0, filled = 0, cancel = FALSE; int max, ret = DITEM_SUCCESS; int use_dhcp = FALSE; int use_rtsol = FALSE; char *tmp; char title[80]; save = savescr(); /* Initialise vars from previous device values */ if (devp->private) { DevInfo *di = (DevInfo *)devp->private; SAFE_STRCPY(ipaddr, di->ipaddr); SAFE_STRCPY(netmask, di->netmask); SAFE_STRCPY(extras, di->extras); use_dhcp = di->use_dhcp; use_rtsol = di->use_rtsol; } else { /* See if there are any defaults */ char *cp; /* Try a RTSOL scan if such behavior is desired */ if (!variable_cmp(VAR_TRY_RTSOL, "YES") || - ((!variable_cmp(VAR_TRY_RTSOL, "NO")) && (!msgYesNo("Do you want to try IPv6 configuration of the interface?")))) { + ((!variable_cmp(VAR_TRY_RTSOL, "NO")) && (!msgNoYes("Do you want to try IPv6 configuration of the interface?")))) { int i; int len; i = 0; sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i)); i = 1; sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i)); vsystem("ifconfig %s up", devp->name); len = sizeof(i); sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); sleep(i + 1); Mkdir("/var/run"); msgNotify("Scanning for RA servers..."); if (0 == vsystem("rtsol %s", devp->name)) { len = sizeof(i); sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); sleep(i + 1); rtsolGetInfo(devp); use_rtsol = TRUE; } else use_rtsol = FALSE; } /* First try a DHCP scan if such behavior is desired */ if (!variable_cmp(VAR_TRY_DHCP, "YES") || - ((!variable_cmp(VAR_TRY_DHCP, "NO")) && (!msgYesNo("Do you want to try DHCP configuration of the interface?")))) { + ((!variable_cmp(VAR_TRY_DHCP, "NO")) && (!msgNoYes("Do you want to try DHCP configuration of the interface?")))) { Mkdir("/var/db"); Mkdir("/var/run"); Mkdir("/tmp"); msgNotify("Scanning for DHCP servers..."); if (0 == vsystem("dhclient -1 %s", devp->name)) { dhcpGetInfo(devp); use_dhcp = TRUE; } else use_dhcp = FALSE; } /* Special hack so it doesn't show up oddly in the tcpip setup menu */ if (!strcmp(gateway, "NO")) gateway[0] = '\0'; /* Get old IP address from variable space, if available */ if (!ipaddr[0]) { if ((cp = variable_get(VAR_IPADDR)) != NULL) SAFE_STRCPY(ipaddr, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL) SAFE_STRCPY(ipaddr, cp); } /* Get old netmask from variable space, if available */ if (!netmask[0]) { if ((cp = variable_get(VAR_NETMASK)) != NULL) SAFE_STRCPY(netmask, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL) SAFE_STRCPY(netmask, cp); } /* Get old extras string from variable space, if available */ if (!extras[0]) { if ((cp = variable_get(VAR_EXTRAS)) != NULL) SAFE_STRCPY(extras, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL) SAFE_STRCPY(extras, cp); } } /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ if (!hostname[0]) { tmp = variable_get(VAR_HOSTNAME); if (tmp) SAFE_STRCPY(hostname, tmp); } if (!domainname[0]) { tmp = variable_get(VAR_DOMAINNAME); if (tmp) SAFE_STRCPY(domainname, tmp); } if (!gateway[0]) { tmp = variable_get(VAR_GATEWAY); if (tmp && strcmp(tmp, "NO")) SAFE_STRCPY(gateway, tmp); } if (!nameserver[0]) { tmp = variable_get(VAR_NAMESERVER); if (tmp) SAFE_STRCPY(nameserver, tmp); } /* If non-interactive, jump straight over the dialog crap and into config section */ if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_NETINTERACTIVE)) { if (!hostname[0]) msgConfirm("WARNING: hostname variable not set and is a non-optional\n" "parameter. Please add this to your installation script\n" "or set the netInteractive variable (see sysinstall man page)"); else goto netconfig; } /* Now do all the screen I/O */ dialog_clear_norefresh(); /* We need a curses window */ tmp = " Network Configuration "; if (ipv6addr[0]) tmp = string_concat(tmp, "(IPv6 ready) "); if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp, TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) { beep(); msgConfirm("Cannot open TCP/IP dialog window!!"); restorescr(save); return DITEM_FAILURE; } /* Draw interface configuration box */ draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, dialog_attr, border_attr); wattrset(ds_win, dialog_attr); sprintf(title, " Configuration for Interface %s ", devp->name); mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title); /* Some more initialisation before we go into the main input loop */ obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max); reenter: cancelbutton = okbutton = 0; while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) { /* Prevent this from being irritating if user really means NO */ if (filled < 3) { /* Insert a default value for the netmask, 0xffffff00 is * the most appropriate one (entire class C, or subnetted * class A/B network). */ if (!netmask[0]) { strcpy(netmask, "255.255.255.0"); RefreshStringObj(layout[LAYOUT_NETMASK].obj); ++filled; } if (!index(hostname, '.') && domainname[0]) { strcat(hostname, "."); strcat(hostname, domainname); RefreshStringObj(layout[LAYOUT_HOSTNAME].obj); ++filled; } else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) { SAFE_STRCPY(domainname, tmp + 1); RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj); ++filled; } } } if (!cancel && !verifySettings()) goto reenter; /* Clear this crap off the screen */ delwin(ds_win); dialog_clear_norefresh(); use_helpfile(NULL); /* We actually need to inform the rest of sysinstall about this data now if the user hasn't selected cancel. Save the stuff out to the environment via the variable_set() mechanism */ netconfig: if (!cancel) { DevInfo *di; char temp[512], ifn[255]; char *ifaces; char *pccard; int ipv4_enable = FALSE; if (hostname[0]) { variable_set2(VAR_HOSTNAME, hostname, 1); sethostname(hostname, strlen(hostname)); } if (domainname[0]) variable_set2(VAR_DOMAINNAME, domainname, 0); if (gateway[0]) variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1); if (nameserver[0]) variable_set2(VAR_NAMESERVER, nameserver, 0); if (ipaddr[0]) variable_set2(VAR_IPADDR, ipaddr, 0); if (ipv6addr[0]) variable_set2(VAR_IPV6ADDR, ipv6addr, 0); if (!devp->private) devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo)); di = devp->private; SAFE_STRCPY(di->ipaddr, ipaddr); SAFE_STRCPY(di->netmask, netmask); SAFE_STRCPY(di->extras, extras); di->use_dhcp = use_dhcp; di->use_rtsol = use_rtsol; if (use_dhcp || ipaddr[0]) ipv4_enable = TRUE; if (ipv4_enable) { sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); if (use_dhcp) sprintf(temp, "DHCP"); else sprintf(temp, "inet %s %s netmask %s", ipaddr, extras, netmask); variable_set2(ifn, temp, 1); } pccard = variable_get("_pccard_install"); if (pccard && strcmp(pccard, "YES") == 0 && ipv4_enable) { variable_set2("pccard_ifconfig", temp, 1); } ifaces = variable_get(VAR_INTERFACES); if (!ifaces) variable_set2(VAR_INTERFACES, ifaces = "lo0", 1); /* Only add it if it's not there already */ if (strcmp(ifaces, "auto") && !strstr(ifaces, devp->name)) { sprintf(ifn, "%s %s", devp->name, ifaces); variable_set2(VAR_INTERFACES, ifn, 1); } if (use_rtsol) variable_set2(VAR_IPV6_ENABLE, "YES", 1); if (!use_dhcp) configResolv(NULL); /* XXX this will do it on the MFS copy XXX */ ret = DITEM_SUCCESS; } else ret = DITEM_FAILURE; restorescr(save); return ret; } static Device *NetDev; static int netHook(dialogMenuItem *self) { Device **devs; devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK); if (devs) { if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE) NetDev = devs[0]; else NetDev = NULL; } return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE; } /* Get a network device */ Device * tcpDeviceSelect(void) { DMenu *menu; Device **devs, *rval; int cnt; devs = deviceFind(NULL, DEVICE_TYPE_NETWORK); cnt = deviceCount(devs); rval = NULL; if (!cnt) { msgConfirm("No network devices available!"); return NULL; } else if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) { if (!msgYesNo("Running multi-user, assume that the network is already configured?")) return devs[0]; } if (cnt == 1) { if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) rval = devs[0]; } else if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETWORK_DEVICE)) { devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); cnt = deviceCount(devs); if (cnt) { if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) rval = devs[0]; } } else { int status; menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL); if (!menu) msgFatal("Unable to create network device menu! Argh!"); status = dmenuOpenSimple(menu, FALSE); free(menu); if (status) rval = NetDev; } return rval; } /* Do it from a menu that doesn't care about status */ int tcpMenuSelect(dialogMenuItem *self) { Device *tmp; WINDOW *save; variable_set("NETWORK_CONFIGURED=NO",0); tmp = tcpDeviceSelect(); variable_unset("NETWORK_CONFIGURED"); save = savescr(); if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!tmp->init(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); restorescr(save); return DITEM_SUCCESS; } Index: head/usr.sbin/sade/disks.c =================================================================== --- head/usr.sbin/sade/disks.c (revision 70004) +++ head/usr.sbin/sade/disks.c (revision 70005) @@ -1,971 +1,971 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_SIZE }; #ifdef PC98 #define SUBTYPE_FREEBSD 50324 #define SUBTYPE_FAT 37218 #else #define SUBTYPE_FREEBSD 165 #define SUBTYPE_FAT 6 #endif /* Where we start displaying chunk information on the screen */ #define CHUNK_START_ROW 5 /* Where we keep track of MBR chunks */ static struct chunk *chunk_info[16]; static int current_chunk; static void diskPartitionNonInteractive(Device *dev); static void record_chunks(Disk *d) { struct chunk *c1 = NULL; int i = 0; int last_free = 0; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == unused && c1->size > last_free) { last_free = c1->size; current_chunk = i; } chunk_info[i++] = c1; } chunk_info[i] = NULL; if (current_chunk >= i) current_chunk = i - 1; } static int Total; static void print_chunks(Disk *d, int u) { int row; int i; int sz; char *szstr; szstr = (u == UNIT_MEG ? "MB" : (u == UNIT_KILO ? "KB" : "ST")); for (i = Total = 0; chunk_info[i]; i++) Total += chunk_info[i]->size; #ifndef PC98 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { dialog_clear_norefresh(); msgConfirm("WARNING: A geometry of %d/%d/%d for %s is incorrect. Using\n" "a more likely geometry. If this geometry is incorrect or you\n" "are unsure as to whether or not it's correct, please consult\n" "the Hardware Guide in the Documentation submenu or use the\n" "(G)eometry command to change it now.\n\n" "Remember: you need to enter whatever your BIOS thinks the\n" "geometry is! For IDE, it's what you were told in the BIOS\n" "setup. For SCSI, it's the translation mode your controller is\n" "using. Do NOT use a ``physical geometry''.", d->bios_cyl, d->bios_hd, d->bios_sect, d->name); Sanitize_Bios_Geom(d); } #endif attrset(A_NORMAL); mvaddstr(0, 0, "Disk name:\t"); clrtobot(); attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); mvprintw(1, 0, "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors (%luMB)", d->bios_cyl, d->bios_hd, d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect * 512 / 1024 / 1024); mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", "Offset", "Size", szstr, "End", "Name", "PType", "Desc", "Subtype", "Flags"); for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { switch(u) { default: /* fall thru */ case UNIT_BLOCKS: sz = chunk_info[i]->size; break; case UNIT_KILO: sz = chunk_info[i]->size * 512 / 1024; break; case UNIT_MEG: sz = chunk_info[i]->size * 512 / 1024 / 1024; break; } if (i == current_chunk) attrset(ATTR_SELECTED); mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", chunk_info[i]->offset, sz, chunk_info[i]->end, chunk_info[i]->name, chunk_info[i]->type, slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); if (i == current_chunk) attrset(A_NORMAL); } } static void print_command_summary() { mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice"); mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable"); mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); if (!RunningAsInit) mvprintw(18, 48, "W = Write Changes"); mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } #ifdef PC98 static void getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, u_char **bootmenu, size_t *bootmenu_size) { extern u_char boot0[]; extern size_t boot0_size; extern u_char boot05[]; extern size_t boot05_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: *bootipl = boot0; *bootipl_size = boot0_size; *bootmenu = boot05; *bootmenu_size = boot05_size; return; case 2: default: break; } } *bootipl = NULL; *bootipl_size = 0; *bootmenu = NULL; *bootmenu_size = 0; } #else static void getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) { #ifndef __alpha__ /* only meaningful on x86 */ extern u_char mbr[], boot0[]; extern size_t mbr_size, boot0_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else if (!strcmp(cp, "standard")) BootMgr = 1; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: *bootCode = boot0; *bootCodeSize = boot0_size; return; case 1: *bootCode = mbr; *bootCodeSize = mbr_size; return; case 2: default: break; } } #endif *bootCode = NULL; *bootCodeSize = 0; } #endif int diskGetSelectCount(Device ***devs) { int i, cnt, enabled; char *cp; Device **dp; cp = variable_get(VAR_DISK); dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(dp); if (!cnt) return -1; for (i = 0, enabled = 0; i < cnt; i++) { if (dp[i]->enabled) ++enabled; } return enabled; } void diskPartition(Device *dev) { char *cp, *p; int rv, key = 0; Boolean chunking; char *msg = NULL; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif WINDOW *w = savescr(); Disk *d = (Disk *)dev->private; int size_unit; size_unit = UNIT_BLOCKS; chunking = TRUE; keypad(stdscr, TRUE); /* Flush both the dialog and curses library views of the screen since we don't always know who called us */ dialog_clear_norefresh(), clear(); current_chunk = 0; /* Set up the chunk array */ record_chunks(d); while (chunking) { char *val, geometry[80]; /* Now print our overall state */ if (d) print_chunks(d, size_unit); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } /* Get command character */ key = getch(); switch (toupper(key)) { case '\014': /* ^L (redraw) */ clear(); msg = NULL; break; case '\020': /* ^P */ case KEY_UP: case '-': if (current_chunk != 0) --current_chunk; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_HOME: current_chunk = 0; break; case KEY_END: while (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_F(1): case '?': systemDisplayHelp("slice"); clear(); break; case 'A': #ifdef __alpha__ rv = 1; #else /* The rest is only relevant on x86 */ cp = variable_get(VAR_DEDICATE_DISK); if (cp && !strcasecmp(cp, "always")) rv = 1; else { rv = msgYesNo("Do you want to do this with a true partition entry\n" "so as to remain cooperative with any future possible\n" "operating systems on the drive(s)?\n" "(See also the section about ``dangerously dedicated''\n" "disks in the FreeBSD FAQ.)"); if (rv == -1) rv = 0; } #endif All_FreeBSD(d, rv); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); clear(); break; case 'C': if (chunk_info[current_chunk]->type != unused) msg = "Slice in use, delete it first or move to an unused one."; else { char *val, tmp[20], *cp; int size; #ifdef PC98 char name[16]; snprintf(name, 16, "%s", "FreeBSD"); val = msgGetInput(name, "Please specify the name for new FreeBSD slice."); if (val) strncpy(name, val, 16); #else int subtype; chunk_e partitiontype; #endif snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" "or append a trailing `M' for megabytes (e.g. 20M)."); if (val && (size = strtol(val, &cp, 0)) > 0) { if (*cp && toupper(*cp) == 'M') size *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') size *= ONE_GIG; #ifdef PC98 Create_Chunk(d, chunk_info[current_chunk]->offset, size, freebsd, 3, (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); #else sprintf(tmp, "%d", SUBTYPE_FREEBSD); val = msgGetInput(tmp, "Enter type of partition to create:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 165). You can choose other types, 6 for a\n" "DOS partition or 131 for a Linux partition, for example.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS FORMAT, to later format\n" "and use the partition."); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else partitiontype = unknown; #ifdef __alpha__ if (partitiontype == freebsd && size == chunk_info[current_chunk]->size) All_FreeBSD(d, 1); else #endif Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } #endif /* PC98 */ } clear(); } break; case KEY_DC: case 'D': if (chunk_info[current_chunk]->type == unused) msg = "Slice is already unused!"; else { Delete_Chunk(d, chunk_info[current_chunk]); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } break; case 'T': if (chunk_info[current_chunk]->type == unused) msg = "Slice is currently unused (use create instead)"; else { char *val, tmp[20]; int subtype; chunk_e partitiontype; sprintf(tmp, "%d", SUBTYPE_FREEBSD); #ifdef PC98 val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 50324). Other popular values are 37218 for\n" "DOS FAT partition.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS format, to later format\n" "and actually use the partition."); #else val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 165). Other popular values are 6 for\n" "DOS FAT partition, 131 for a Linux ext2fs partition or\n" "130 for a Linux swap partition.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS format, to later format\n" "and actually use the partition."); #endif /* PC98 */ if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else partitiontype = unknown; chunk_info[current_chunk]->type = partitiontype; chunk_info[current_chunk]->subtype = subtype; } } break; case 'G': snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" "Don't forget to use the two slash (/) separator characters!\n" "It's not possible to parse the field without them."); if (val) { long nc, nh, ns; nc = strtol(val, &val, 0); nh = strtol(val + 1, &val, 0); ns = strtol(val + 1, 0, 0); Set_Bios_Geom(d, nc, nh, ns); } clear(); break; case 'S': /* Set Bootable */ chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; break; case 'U': if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written this information out - you\n" "can't undo it."); } - else if (!msgYesNo("Are you SURE you want to Undo everything?")) { + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { char cp[BUFSIZ]; sstrncpy(cp, d->name, sizeof cp); Free_Disk(dev->private); d = Open_Disk(cp); if (!d) msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); dev->private = d; variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); if (d) record_chunks(d); } clear(); break; case 'W': - if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" + if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions. If you're adding a disk, you should NOT write\n" "from this screen, you should do it from the label editor.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_PARTITIONED, "yes", 0); /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested booteasy or a "standard" MBR -- both would be * fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ #ifdef PC98 if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); else { bootipl = NULL; bootipl_size = 0; bootmenu = NULL; bootmenu_size = 0; } Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &mbrContents, &mbrSize); else { mbrContents = NULL; mbrSize = 0; } Set_Boot_Mgr(d, mbrContents, mbrSize); #endif if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) msgConfirm("Disk partition write returned an error status!"); else msgConfirm("Wrote FDISK partition information out successfully."); } clear(); break; case '|': - if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" + if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" "No seat belts whatsoever are provided!")) { clear(); refresh(); slice_wizard(d); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } else msg = "Wise choice!"; clear(); break; case '\033': /* ESC */ case 'Q': chunking = FALSE; /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * booteasy or a "standard" MBR -- both would be fatal in this case. */ #if 0 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } #else /* * Don't offer to update the MBR on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } #endif break; case 'Z': size_unit = (size_unit + 1) % UNIT_SIZE; break; default: beep(); msg = "Type F1 or ? for help"; break; } } p = CheckRules(d); if (p) { char buf[FILENAME_MAX]; use_helpline("Press F1 to read more about disk slices."); use_helpfile(systemHelpFile("partition", buf)); if (!variable_get(VAR_NO_WARN)) dialog_mesgbox("Disk slicing warning:", p, -1, -1); free(p); } restorescr(w); } static u_char * bootalloc(char *name) { char buf[FILENAME_MAX]; struct stat sb; snprintf(buf, sizeof buf, "/boot/%s", name); if (stat(buf, &sb) != -1) { int fd; fd = open(buf, O_RDONLY); if (fd != -1) { u_char *cp; cp = malloc(sb.st_size); if (read(fd, cp, sb.st_size) != sb.st_size) { free(cp); close(fd); msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); return NULL; } close(fd); return cp; } msgDebug("bootalloc: couldn't open %s\n", buf); } else msgDebug("bootalloc: can't stat %s\n", buf); return NULL; } static int partitionHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskPartition(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int partitionCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskPartitionEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt, devcnt; cnt = diskGetSelectCount(&devs); devcnt = deviceCount(devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ for (i = 0; i < devcnt; i++) { if (devs[i]->enabled) { if (variable_get(VAR_NONINTERACTIVE)) diskPartitionNonInteractive(devs[i]); else diskPartition(devs[i]); } } } else { /* No disks are selected, fall-back case now */ if (devcnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE)) diskPartitionNonInteractive(devs[0]); else diskPartition(devs[0]); return DITEM_SUCCESS; } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); return DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } return i; } } return DITEM_SUCCESS; } int diskPartitionWrite(dialogMenuItem *self) { Device **devs; int i; char *cp; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find any disks to write to??"); return DITEM_FAILURE; } if (isDebug()) msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); cp = variable_get(DISK_PARTITIONED); if (cp && !strcmp(cp, "written")) return DITEM_SUCCESS; for (i = 0; devs[i]; i++) { Disk *d = (Disk *)devs[i]->private; static u_char *boot1; #ifndef __alpha__ static u_char *boot2; #endif if (!devs[i]->enabled) continue; #ifdef __alpha__ if (!boot1) boot1 = bootalloc("boot1"); Set_Boot_Blocks(d, boot1, NULL); #else if (!boot1) boot1 = bootalloc("boot1"); if (!boot2) boot2 = bootalloc("boot2"); Set_Boot_Blocks(d, boot1, boot2); #endif msgNotify("Writing partition information to drive %s", d->name); if (!Fake && Write_Disk(d)) { msgConfirm("ERROR: Unable to write data to disk %s!", d->name); return DITEM_FAILURE; } /* If we've been through here before, we don't need to do the rest */ if (cp && !strcmp(cp, "written")) return DITEM_SUCCESS; } /* Now it's not "yes", but "written" */ variable_set2(DISK_PARTITIONED, "written", 0); return DITEM_SUCCESS | DITEM_RESTORE; } /* Partition a disk based wholly on which variables are set */ static void diskPartitionNonInteractive(Device *dev) { char *cp; int i, sz, all_disk = 0; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif Disk *d = (Disk *)dev->private; record_chunks(d); cp = variable_get(VAR_GEOMETRY); if (cp) { msgDebug("Setting geometry from script to: %s\n", cp); d->bios_cyl = strtol(cp, &cp, 0); d->bios_hd = strtol(cp + 1, &cp, 0); d->bios_sect = strtol(cp + 1, 0, 0); } cp = variable_get(VAR_PARTITION); if (cp) { if (!strcmp(cp, "free")) { /* Do free disk space case */ for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least 10MB in size, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { #ifdef PC98 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); #else Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); #endif variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find any free space on this disk!"); return; } } else if (!strcmp(cp, "all")) { /* Do all disk space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, FALSE); } else if (!strcmp(cp, "exclusive")) { /* Do really-all-the-disk-space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, all_disk = TRUE); } else if ((sz = strtol(cp, &cp, 0))) { /* Look for sz bytes free */ if (*cp && toupper(*cp) == 'M') sz *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') sz *= ONE_GIG; for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least sz MB, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { #ifdef PC98 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); #else Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); #endif variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find %d free blocks on this disk!", sz); return; } } else if (!strcmp(cp, "existing")) { /* Do existing FreeBSD case */ for (i = 0; chunk_info[i]; i++) { if (chunk_info[i]->type == freebsd) break; } if (!chunk_info[i]) { msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); return; } } else { msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); return; } if (!all_disk) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } variable_set2(DISK_PARTITIONED, "yes", 0); } } Index: head/usr.sbin/sade/install.c =================================================================== --- head/usr.sbin/sade/install.c (revision 70004) +++ head/usr.sbin/sade/install.c (revision 70005) @@ -1,1130 +1,1128 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include #include #include #include #define MSDOSFS #include #include #include #undef MSDOSFS #include #include #include #include /* Hack for rsaref package add, which displays interactive license. * Used by package.c */ int _interactiveHack; int FixItMode = 0; static void create_termcap(void); static void fixit_common(void); #define TERMCAP_FILE "/usr/share/misc/termcap" static void installConfigure(void); Boolean checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev) { Device **devs; Boolean status; Disk *disk; Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; int i; /* Don't allow whinging if noWarn is set */ if (variable_get(VAR_NO_WARN)) whinge = FALSE; status = TRUE; *rdev = *sdev = *udev = *vdev = rootdev = swapdev = usrdev = vardev = NULL; /* We don't need to worry about root/usr/swap if we're already multiuser */ if (!RunningAsInit) return status; devs = deviceFind(NULL, DEVICE_TYPE_DISK); /* First verify that we have a root device */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for root filesystem\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/")) { if (rootdev) { if (whinge) msgConfirm("WARNING: You have more than one root device set?!\n" "Using the first one found."); continue; } else { rootdev = c2; if (isDebug()) msgDebug("Found rootdev at %s!\n", rootdev->name); } } else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) { if (usrdev) { if (whinge) msgConfirm("WARNING: You have more than one /usr filesystem.\n" "Using the first one found."); continue; } else { usrdev = c2; if (isDebug()) msgDebug("Found usrdev at %s!\n", usrdev->name); } } else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/var")) { if (vardev) { if (whinge) msgConfirm("WARNING: You have more than one /var filesystem.\n" "Using the first one found."); continue; } else { vardev = c2; if (isDebug()) msgDebug("Found vardev at %s!\n", vardev->name); } } } } } } } /* Now check for swap devices */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for swap partitions\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) { swapdev = c2; if (isDebug()) msgDebug("Found swapdev at %s!\n", swapdev->name); break; } } } } } /* Copy our values over */ *rdev = rootdev; *sdev = swapdev; *udev = usrdev; *vdev = vardev; if (!rootdev && whinge) { msgConfirm("No root device found - you must label a partition as /\n" "in the label editor."); status = FALSE; } if (!swapdev && whinge) { msgConfirm("No swap devices found - you must create at least one\n" "swap partition."); status = FALSE; } return status; } static int installInitial(void) { static Boolean alreadyDone = FALSE; int status = DITEM_SUCCESS; if (alreadyDone) return DITEM_SUCCESS; if (!variable_get(DISK_LABELLED)) { msgConfirm("You need to assign disk labels before you can proceed with\n" "the installation."); return DITEM_FAILURE; } /* If it's labelled, assume it's also partitioned */ if (!variable_get(DISK_PARTITIONED)) variable_set2(DISK_PARTITIONED, "yes", 0); /* If we refuse to proceed, bail. */ dialog_clear_norefresh(); if (!variable_get(VAR_NO_WARN)) if (msgYesNo( "Last Chance! Are you SURE you want continue the installation?\n\n" "If you're running this on a disk with data you wish to save\n" "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n" "proceeding!\n\n" "We can take no responsibility for lost disk contents!") != 0) return DITEM_FAILURE; if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { msgConfirm("Couldn't make filesystems properly. Aborting."); return DITEM_FAILURE; } if (!copySelf()) { msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n" "root file system. Aborting!"); return DITEM_FAILURE; } if (chroot("/mnt") == -1) { msgConfirm("installInitial: Unable to chroot to %s - this is bad!", "/mnt"); return DITEM_FAILURE; } chdir("/"); variable_set2(RUNNING_ON_ROOT, "yes", 0); /* Configure various files in /etc */ if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; /* stick a helpful shell over on the 4th VTY */ systemCreateHoloshell(); alreadyDone = TRUE; return status; } int installFixitHoloShell(dialogMenuItem *self) { FixItMode = 1; systemCreateHoloshell(); return DITEM_SUCCESS; FixItMode = 0; } int installFixitCDROM(dialogMenuItem *self) { struct stat sb; if (!RunningAsInit) return DITEM_SUCCESS; variable_set2(SYSTEM_STATE, "fixit", 0); (void)unlink("/mnt2"); (void)rmdir("/mnt2"); while (1) { msgConfirm("Please insert a FreeBSD live filesystem CDROM and press return"); if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) { /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */ mediaClose(); if (msgYesNo("Unable to mount the CDROM - do you want to try again?") != 0) return DITEM_FAILURE; } else break; } /* Since the fixit code expects everything to be in /mnt2, and the CDROM mounting stuff /dist, do * a little kludge dance here.. */ if (symlink("/dist", "/mnt2")) { msgConfirm("Unable to symlink /mnt2 to the CDROM mount point. Please report this\n" "unexpected failure to freebsd-bugs@FreeBSD.org."); return DITEM_FAILURE; } /* * If /tmp points to /mnt2/tmp from a previous fixit floppy session, it's * not very good for us if we point it to the CDROM now. Rather make it * a directory in the root MFS then. Experienced admins will still be * able to mount their disk's /tmp over this if they need. */ if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK) (void)unlink("/tmp"); Mkdir("/tmp"); /* * Since setuid binaries ignore LD_LIBRARY_PATH, we indeed need the * ld.so.hints file. Fortunately, it's fairly small (~ 3 KB). */ if (!file_readable("/var/run/ld.so.hints")) { Mkdir("/var/run"); if (vsystem("/mnt2/sbin/ldconfig -s /mnt2/usr/lib")) { msgConfirm("Warning: ldconfig could not create the ld.so hints file.\n" "Dynamic executables from the CDROM likely won't work."); } } /* Yet more iggly hardcoded pathnames. */ Mkdir("/usr/libexec"); if (!file_readable("/usr/libexec/ld.so") && file_readable("/mnt2/usr/libexec/ld.so")) { if (symlink("/mnt2/usr/libexec/ld.so", "/usr/libexec/ld.so")) msgDebug("Couldn't link to ld.so - not necessarily a problem for ELF\n"); } if (!file_readable("/usr/libexec/ld-elf.so.1")) { if (symlink("/mnt2/usr/libexec/ld-elf.so.1", "/usr/libexec/ld-elf.so.1")) { msgConfirm("Warning: could not create the symlink for ld-elf.so.1\n" "Dynamic executables from the CDROM likely won't work."); } } /* optional nicety */ if (!file_readable("/usr/bin/vi")) symlink("/mnt2/usr/bin/vi", "/usr/bin/vi"); fixit_common(); mediaClose(); msgConfirm("Please remove the FreeBSD fixit CDROM now."); return DITEM_SUCCESS; } int installFixitFloppy(dialogMenuItem *self) { struct ufs_args args; extern char *distWanted; if (!RunningAsInit) return DITEM_SUCCESS; /* Try to open the floppy drive */ if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) { msgConfirm("Unable to set media device to floppy."); mediaClose(); return DITEM_FAILURE; } memset(&args, 0, sizeof(args)); args.fspec = mediaDevice->devname; mediaDevice->private = "/mnt2"; distWanted = NULL; Mkdir("/mnt2"); variable_set2(SYSTEM_STATE, "fixit", 0); while (1) { if (!mediaDevice->init(mediaDevice)) { if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n" "or unclean filesystem. Do you want to try again?")) return DITEM_FAILURE; } else break; } if (!directory_exists("/tmp")) (void)symlink("/mnt2/tmp", "/tmp"); fixit_common(); mediaClose(); msgConfirm("Please remove the fixit floppy now."); return DITEM_SUCCESS; } /* * The common code for both fixit variants. */ static void fixit_common(void) { pid_t child; int waitstatus; if (!directory_exists("/var/tmp/vi.recover")) { if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) { msgConfirm("Warning: Was unable to create a /var/tmp/vi.recover directory.\n" "vi will kvetch and moan about it as a result but should still\n" "be essentially usable."); } } if (!directory_exists("/bin")) (void)Mkdir("/bin"); (void)symlink("/stand/sh", "/bin/sh"); /* Link the /etc/ files */ if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS) msgConfirm("Unable to create an /etc directory! Things are weird on this floppy.."); else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST)) msgConfirm("Couldn't symlink the /etc/ files! I'm not sure I like this.."); if (!file_readable(TERMCAP_FILE)) create_termcap(); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if (!(child = fork())) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("fixit: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(0, TCSANOW, &foo) == -1) msgDebug("fixit shell: Unable to set erase character.\n"); } else msgDebug("fixit shell: Unable to get terminal attributes!\n"); setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:" "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1); setenv("MAKEDEVPATH", "/sbin:/bin:/stand:" "/mnt2/sbin:/mnt2/bin:/mnt2/stand", 1); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Waiting for fixit shell to exit.\n" "When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here.\n\n"); fflush(stdout); } /* use the .profile from the fixit medium */ setenv("HOME", "/mnt2", 1); chdir("/mnt2"); execlp("sh", "-sh", 0); msgDebug("fixit shell: Failed to execute shell!\n"); _exit(1);; } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { dialog_clear_norefresh(); msgNotify("Waiting for fixit shell to exit. Go to VTY4 now by\n" "typing ALT-F4. When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here\n."); } (void)waitpid(child, &waitstatus, 0); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemResumeDialog(); } dialog_clear(); } int installExpress(dialogMenuItem *self) { int i; dialog_clear_norefresh(); variable_set2(SYSTEM_STATE, "express", 0); #ifndef __alpha__ if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) return i; #endif if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) return i; if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { i |= DITEM_LEAVE_MENU; /* Set default security level */ configSecurityModerate(NULL); /* Give user the option of one last configuration spree */ installConfigure(); } return i; } /* Standard mode installation */ int installStandard(dialogMenuItem *self) { int i, tries = 0; Device **devs; variable_set2(SYSTEM_STATE, "standard", 0); dialog_clear_norefresh(); #ifndef __alpha__ msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n" "scheme for your hard disk. If you simply wish to devote all disk space\n" "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n" "then use the (A)ll command to select the default partitioning scheme followed\n" "by a (Q)uit. If you wish to allocate only free space to FreeBSD, move to a\n" "partition marked \"unused\" and use the (C)reate command."); nodisks: if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (diskGetSelectCount(&devs) <= 0 && tries < 3) { msgConfirm("You need to select some disks to operate on! Be sure to use SPACE\n" "instead of RETURN in the disk selection menu when selecting a disk."); ++tries; goto nodisks; } #endif #ifdef __alpha__ msgConfirm("Now you need to create BSD partitions on the disk which you are\n" "installing to. If you have a reasonable amount of disk space (200MB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #else msgConfirm("Now you need to create BSD partitions inside of the fdisk partition(s)\n" "just created. If you have a reasonable amount of disk space (200MB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #endif if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { dialog_clear(); msgConfirm("Installation completed with some errors. You may wish to\n" "scroll through the debugging messages on VTY1 with the\n" "scroll-lock feature. You can also choose \"No\" at the next\n" "prompt and go back into the installation menus to try and retry\n" "whichever operations have failed."); return i; } else { dialog_clear(); msgConfirm("Congratulations! You now have FreeBSD installed on your system.\n\n" "We will now move on to the final configuration questions.\n" "For any option you do not wish to configure, simply select\n" "No.\n\n" "If you wish to re-enter this utility after the system is up, you\n" "may do so by typing: /stand/sysinstall."); } if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) { if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) { Device *tmp = tcpDeviceSelect(); if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!tmp->init(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); } dialog_clear_norefresh(); } - if (msgYesNo("Will this machine be a leaf node (e.g. will not forward packets\n" - "between interfaces)?")) + if (!msgNoYes("Do you want this machine to function as a network gateway?")) variable_set2("gateway_enable", "YES", 1); dialog_clear_norefresh(); - if (msgYesNo("Do you want to grant only normal users FTP access to this\n" - "host (e.g. no anonymous FTP connections)?")) + if (!msgNoYes("Do you want to have anonymous FTP access to this machine?")) configAnonFTP(self); dialog_clear_norefresh(); - if (!msgYesNo("Do you want to configure this machine as an NFS server?")) + if (!msgNoYes("Do you want to configure this machine as an NFS server?")) configNFSServer(self); dialog_clear_norefresh(); - if (!msgYesNo("Do you want to configure this machine as an NFS client?")) + if (!msgNoYes("Do you want to configure this machine as an NFS client?")) variable_set2("nfs_client_enable", "YES", 1); - if (!msgYesNo("Do you want to select a default security profile for\n" + if (!msgNoYes("Do you want to select a default security profile for\n" "this host (select No for \"medium\" security)?")) configSecurityProfile(self); else configSecurityModerate(self); dialog_clear_norefresh(); - if (!msgYesNo("Would you like to customize your system console settings?")) + if (!msgNoYes("Would you like to customize your system console settings?")) dmenuOpenSimple(&MenuSyscons, FALSE); dialog_clear_norefresh(); if (!msgYesNo("Would you like to set this machine's time zone now?")) systemExecute("tzsetup"); #ifdef __i386__ dialog_clear_norefresh(); if (!msgYesNo("Would you like to enable Linux binary compatibility?")) (void)configLinux(self); #endif dialog_clear_norefresh(); - if (!msgYesNo("Does this system have a non-USB mouse attached to it?")) + if (!msgNoYes("Does this system have a USB mouse attached to it?")) dmenuOpenSimple(&MenuMouse, FALSE); /* Now would be a good time to checkpoint the configuration data */ configRC_conf(); sync(); if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); if (!msgYesNo("Would you like to configure your X server at this time?")) (void)configXSetup(self); } dialog_clear_norefresh(); if (!msgYesNo("The FreeBSD package collection is a collection of thousands of ready-to-run\n" "applications, from text editors to games to WEB servers and more. Would you\n" "like to browse the collection now?")) { (void)configPackages(self); } if (!msgYesNo("Would you like to add any initial user accounts to the system?\n" "Adding at least one account for yourself at this stage is suggested\n" "since working as the \"root\" user is dangerous (it is easy to do\n" "things which adversely affect the entire system).")) (void)configUsers(self); msgConfirm("Now you must set the system manager's password.\n" "This is the password you'll use to log in as \"root\"."); if (!systemExecute("passwd root")) variable_set2("root_password", "YES", 0); /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */ /* Give user the option of one last configuration spree */ dialog_clear_norefresh(); installConfigure(); return DITEM_LEAVE_MENU; } /* The version of commit we call from the Install Custom menu */ int installCustomCommit(dialogMenuItem *self) { int i; i = installCommit(self); if (DITEM_STATUS(i) == DITEM_SUCCESS) { /* Set default security level */ configSecurityModerate(NULL); /* Give user the option of one last configuration spree */ installConfigure(); return i; } else msgConfirm("The commit operation completed with errors. Not\n" "updating /etc files."); return i; } /* * What happens when we finally decide to going ahead with the installation. * * This is broken into multiple stages so that the user can do a full * installation but come back here again to load more distributions, * perhaps from a different media type. This would allow, for * example, the user to load the majority of the system from CDROM and * then use ftp to load just the CRYPTO dist. */ int installCommit(dialogMenuItem *self) { int i; char *str; dialog_clear_norefresh(); if (!Dists) distConfig(NULL); if (!Dists) { (void)dmenuOpenSimple(&MenuDistributions, FALSE); /* select reasonable defaults if necessary */ if (!Dists) Dists = _DIST_USER; } if (!mediaVerify()) return DITEM_FAILURE; str = variable_get(SYSTEM_STATE); if (isDebug()) msgDebug("installCommit: System state is `%s'\n", str); /* Installation stuff we wouldn't do to a running system */ if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) return i; try_media: if (!mediaDevice->init(mediaDevice)) { if (!msgYesNo("Unable to initialize selected media. Would you like to\n" "adjust your media configuration and try again?")) { mediaDevice = NULL; if (!mediaVerify()) return DITEM_FAILURE; else goto try_media; } else return DITEM_FAILURE; } /* Now go get it all */ i = distExtractAll(self); /* When running as init, *now* it's safe to grab the rc.foo vars */ installEnvironment(); variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0); return i; } static void installConfigure(void) { /* Final menu of last resort */ - if (!msgYesNo("Visit the general configuration menu for a chance to set\n" + if (!msgNoYes("Visit the general configuration menu for a chance to set\n" "any last options?")) dmenuOpenSimple(&MenuConfigure, FALSE); configRC_conf(); sync(); } int installFixupBin(dialogMenuItem *self) { Device **devs; char *cp; int i; FILE *fp; int kstat = 1; /* All of this is done only as init, just to be safe */ if (RunningAsInit) { #ifdef __i386__ /* Snapshot any boot -c changes back to the new kernel */ cp = variable_get(VAR_KGET); if (cp && (*cp == 'Y' || *cp == 'y')) { if ((kstat = kget("/boot/kernel.conf")) != NULL) { msgConfirm("Unable to save boot -c changes to new kernel,\n" "please see the debug screen (ALT-F2) for details."); } } if ((fp = fopen("/boot/loader.conf", "a")) != NULL) { if (!kstat || !OnVTY) fprintf(fp, "# -- sysinstall generated deltas -- #\n"); if (!kstat) fprintf(fp, "userconfig_script_load=\"YES\"\n"); if (!OnVTY) fprintf(fp, "console=\"comconsole\"\n"); fclose(fp); } #endif /* BOGON #1: Resurrect /dev after bin distribution screws it up */ dialog_clear_norefresh(); msgNotify("Remaking all devices.. Please wait!"); if (vsystem("cd /dev; sh MAKEDEV all")) { msgConfirm("MAKEDEV returned non-zero status"); return DITEM_FAILURE | DITEM_RESTORE; } dialog_clear_norefresh(); msgNotify("Resurrecting /dev entries for slices.."); devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) msgFatal("Couldn't get a disk device list!"); /* Resurrect the slices that the former clobbered */ for (i = 0; devs[i]; i++) { Disk *disk = (Disk *)devs[i]->private; Chunk *c1; if (!devs[i]->enabled) continue; if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { dialog_clear_norefresh(); msgNotify("Making slice entries for %s", c1->name); if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) { msgConfirm("Unable to make slice entries for %s!", c1->name); return DITEM_FAILURE | DITEM_RESTORE; } } } } /* BOGON #2: We leave /etc in a bad state */ chmod("/etc", 0755); /* BOGON #3: No /var/db/mountdtab complains */ Mkdir("/var/db"); creat("/var/db/mountdtab", 0644); /* BOGON #4: /compat created by default in root fs */ Mkdir("/usr/compat"); vsystem("ln -s /usr/compat /compat"); /* BOGON #5: aliases database not build for bin */ vsystem("newaliases"); /* Now run all the mtree stuff to fix things up */ vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /"); vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var"); vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr"); /* Do all the last ugly work-arounds here */ } return DITEM_SUCCESS | DITEM_RESTORE; } /* Fix side-effects from the the XFree86 installation */ int installFixupXFree(dialogMenuItem *self) { /* BOGON #1: XFree86 requires various specialized fixups */ if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); msgNotify("Fixing permissions in XFree86 tree.."); vsystem("chmod -R a+r /usr/X11R6"); vsystem("find /usr/X11R6 -type d | xargs chmod a+x"); /* Also do bogus minimal package registration so ports don't whine */ if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) { dialog_clear_norefresh(); msgNotify("Installing package metainfo.."); vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz"); } } return DITEM_SUCCESS | DITEM_RESTORE; } /* Go newfs and/or mount all the filesystems we've been asked to */ int installFilesystems(dialogMenuItem *self) { int i; Disk *disk; Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; Device **devs; PartInfo *root; char dname[80]; extern int MakeDevChunk(Chunk *c, char *n); Boolean upgrade = FALSE; /* If we've already done this, bail out */ if (!variable_cmp(DISK_LABELLED, "written")) return DITEM_SUCCESS; upgrade = !variable_cmp(SYSTEM_STATE, "upgrade"); if (!checkLabels(TRUE, &rootdev, &swapdev, &usrdev, &vardev)) return DITEM_FAILURE; if (rootdev) root = (PartInfo *)rootdev->private_data; else root = NULL; command_clear(); if (swapdev && RunningAsInit) { /* As the very first thing, try to get ourselves some swap space */ sprintf(dname, "/dev/%s", swapdev->name); if (!Fake && (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname))) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE; } if (!Fake) { if (!swapon(dname)) { dialog_clear_norefresh(); msgNotify("Added %s as initial swap device", dname); } else { msgConfirm("WARNING! Unable to swap to %s: %s\n" "This may cause the installation to fail at some point\n" "if you don't have a lot of memory.", dname, strerror(errno)); } } } if (rootdev && RunningAsInit) { /* Next, create and/or mount the root device */ sprintf(dname, "/dev/%s", rootdev->name); if (!Fake && (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname))) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE | DITEM_RESTORE; } if (strcmp(root->mountpoint, "/")) msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint); - if (root->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs the root partition?"))) { + if (root->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs the root partition?"))) { int i; dialog_clear_norefresh(); msgNotify("Making a new root filesystem on %s", dname); i = vsystem("%s %s", root->newfs_cmd, dname); if (i) { msgConfirm("Unable to make new root filesystem on %s!\n" "Command returned status %d", dname, i); return DITEM_FAILURE | DITEM_RESTORE; } } else { if (!upgrade) { msgConfirm("Warning: Using existing root partition. It will be assumed\n" "that you have the appropriate device entries already in /dev."); } dialog_clear_norefresh(); msgNotify("Checking integrity of existing %s filesystem.", dname); i = vsystem("fsck -y %s", dname); if (i) msgConfirm("Warning: fsck returned status of %d for %s.\n" "This partition may be unsafe to use.", i, dname); } /* Switch to block device */ sprintf(dname, "/dev/%s", rootdev->name); if (Mount("/mnt", dname)) { msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); return DITEM_FAILURE | DITEM_RESTORE; } } /* Now buzz through the rest of the partitions and mount them too */ devs = deviceFind(NULL, DEVICE_TYPE_DISK); for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; if (!disk->chunks) { msgConfirm("No chunk list found for %s!", disk->name); return DITEM_FAILURE | DITEM_RESTORE; } if (RunningAsInit && root && (root->newfs || upgrade)) { Mkdir("/mnt/dev"); if (!Fake) MakeDevDisk(disk, "/mnt/dev"); } else if (!RunningAsInit && !Fake) MakeDevDisk(disk, "/dev"); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { PartInfo *tmp = (PartInfo *)c2->private_data; /* Already did root */ if (c2 == rootdev) continue; - if (tmp->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) + if (tmp->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) command_shell_add(tmp->mountpoint, "%s %s/dev/%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name); else command_shell_add(tmp->mountpoint, "fsck -y %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); command_func_add(tmp->mountpoint, Mount, c2->name); } else if (c2->type == part && c2->subtype == FS_SWAP) { char fname[80]; int i; if (c2 == swapdev) continue; sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); i = (Fake || swapon(fname)); if (!i) { dialog_clear_norefresh(); msgNotify("Added %s as an additional swap device", fname); } else { msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); } } } } else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) { char name[FILENAME_MAX]; sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint); Mkdir(name); } } } if (RunningAsInit) { dialog_clear_norefresh(); msgNotify("Copying initial device files.."); /* Copy the boot floppy's dev files */ if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't clone the /dev files!"); return DITEM_FAILURE | DITEM_RESTORE; } } command_sort(); command_execute(); dialog_clear_norefresh(); return DITEM_SUCCESS | DITEM_RESTORE; } static char * getRelname(void) { static char buf[64]; int sz = (sizeof buf) - 1; if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) { buf[sz] = '\0'; return buf; } else return ""; } /* Initialize various user-settable values to their defaults */ int installVarDefaults(dialogMenuItem *self) { char *cp; /* Set default startup options */ variable_set2(VAR_RELNAME, getRelname(), 0); variable_set2(VAR_CPIO_VERBOSITY, "high", 0); variable_set2(VAR_KGET, "YES", 0); variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE, 0); variable_set2(VAR_INSTALL_ROOT, "/", 0); variable_set2(VAR_INSTALL_CFG, "install.cfg", 0); variable_set2(VAR_TRY_DHCP, "NO", 0); /* For now */ variable_set2(VAR_TRY_RTSOL, "NO", 0); /* For now */ cp = getenv("EDITOR"); if (!cp) cp = "/usr/bin/ee"; variable_set2(VAR_EDITOR, cp, 0); variable_set2(VAR_FTP_USER, "ftp", 0); variable_set2(VAR_BROWSER_PACKAGE, "lynx", 0); variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/lynx", 0); variable_set2(VAR_FTP_STATE, "passive", 0); variable_set2(VAR_NFS_SECURE, "NO", -1); if (OnVTY) variable_set2(VAR_FIXIT_TTY, "standard", 0); else variable_set2(VAR_FIXIT_TTY, "serial", 0); variable_set2(VAR_PKG_TMPDIR, "/usr/tmp", 0); variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT), 0); if (getpid() != 1) variable_set2(SYSTEM_STATE, "update", 0); else variable_set2(SYSTEM_STATE, "init", 0); variable_set2(VAR_NEWFS_ARGS, "-b 8192 -f 1024", 0); return DITEM_SUCCESS; } /* Load the environment up from various system configuration files */ void installEnvironment(void) { configEnvironmentRC_conf(); if (file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); } /* Copy the boot floppy contents into /stand */ Boolean copySelf(void) { int i; if (file_readable("/boot.help")) vsystem("cp /boot.help /mnt"); msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (i) { msgConfirm("Copy returned error status of %d!", i); return FALSE; } /* Copy the /etc files into their rightful place */ if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't copy up the /etc files!"); return TRUE; } return TRUE; } static void create_termcap(void) { FILE *fp; const char *caps[] = { termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r, termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, termcap_xterm, NULL, }; const char **cp; if (!file_readable(TERMCAP_FILE)) { Mkdir("/usr/share/misc"); fp = fopen(TERMCAP_FILE, "w"); if (!fp) { msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work."); return; } cp = caps; while (*cp) fprintf(fp, "%s\n", *(cp++)); fclose(fp); } } Index: head/usr.sbin/sade/label.c =================================================================== --- head/usr.sbin/sade/label.c (revision 70004) +++ head/usr.sbin/sade/label.c (revision 70005) @@ -1,1289 +1,1289 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include /* * Everything to do with editing the contents of disk labels. */ /* A nice message we use a lot in the disklabel editor */ #define MSG_NOT_APPLICABLE "That option is not applicable here" /* Where to start printing the freebsd slices */ #define CHUNK_SLICE_START_ROW 2 #define CHUNK_PART_START_ROW 11 /* The smallest filesystem we're willing to create */ #define FS_MIN_SIZE ONE_MEG /* The smallest root filesystem we're willing to create */ #ifdef __alpha__ #define ROOT_MIN_SIZE 40 #else #define ROOT_MIN_SIZE 30 #endif /* The default root filesystem size */ #ifdef __alpha__ #define ROOT_DEFAULT_SIZE 70 #else #define ROOT_DEFAULT_SIZE 50 #endif /* The smallest swap partition we want to create by default */ #define SWAP_MIN_SIZE 32 /* The smallest /usr partition we're willing to create by default */ #define USR_MIN_SIZE 80 /* The smallest /var partition we're willing to create by default */ #define VAR_MIN_SIZE 20 /* The bottom-most row we're allowed to scribble on */ #define CHUNK_ROW_MAX 16 /* All the chunks currently displayed on the screen */ static struct { struct chunk *c; PartType type; } label_chunk_info[MAX_CHUNKS + 1]; static int here; /*** with this value we try to track the most recently added label ***/ static int label_focus = 0, pslice_focus = 0; static int diskLabel(Device *dev); static int diskLabelNonInteractive(Device *dev); static int labelHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskLabel(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int labelCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskLabelEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt; i = 0; cnt = diskGetSelectCount(&devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ if (variable_get(VAR_NONINTERACTIVE)) i = diskLabelNonInteractive(NULL); else i = diskLabel(NULL); } else { /* No disks are selected, fall-back case now */ cnt = deviceCount(devs); if (cnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE)) i = diskLabelNonInteractive(devs[0]); else i = diskLabel(devs[0]); } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); i = DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } } } if (DITEM_STATUS(i) != DITEM_FAILURE) { char *cp; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } return i; } int diskLabelCommit(dialogMenuItem *self) { char *cp; int i; /* Already done? */ if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) i = DITEM_SUCCESS; else if (!cp) { msgConfirm("You must assign disk labels before this option can be used."); i = DITEM_FAILURE; } /* The routine will guard against redundant writes, just as this one does */ else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else { msgInfo("All filesystem information written successfully."); variable_set2(DISK_LABELLED, "written", 0); i = DITEM_SUCCESS; } return i; } /* See if we're already using a desired partition name */ static Boolean check_conflict(char *name) { int i; for (i = 0; label_chunk_info[i].c; i++) if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) && label_chunk_info[i].c->private_data && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) return TRUE; return FALSE; } /* How much space is in this FreeBSD slice? */ static int space_free(struct chunk *c) { struct chunk *c1; int sz = c->size; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != unused) sz -= c1->size; } if (sz < 0) msgFatal("Partitions are larger than actual chunk??"); return sz; } /* Snapshot the current situation into the displayed chunks structure */ static void record_label_chunks(Device **devs, Device *dev) { int i, j, p; struct chunk *c1, *c2; Disk *d; j = p = 0; /* First buzz through and pick up the FreeBSD slices */ for (i = 0; devs[i]; i++) { if ((dev && devs[i] != dev) || !devs[i]->enabled) continue; d = (Disk *)devs[i]->private; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); /* Put the slice entries first */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = c1; ++j; } } } /* Now run through again and get the FreeBSD partition entries */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; d = (Disk *)devs[i]->private; /* Then buzz through and pick up the partitions */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part) { if (c2->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c2; ++j; } } } else if (c1->type == fat) { label_chunk_info[j].type = PART_FAT; label_chunk_info[j].c = c1; ++j; } } } label_chunk_info[j].c = NULL; if (here >= j) { here = j ? j - 1 : 0; } } /* A new partition entry */ static PartInfo * new_part(char *mpoint, Boolean newfs, u_long size) { PartInfo *ret; if (!mpoint) mpoint = "/change_me"; ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); strcpy(ret->newfs_cmd, "newfs "); strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS)); ret->newfs = newfs; if (!size) return ret; return ret; } /* Get the mountpoint for a partition and save it away */ static PartInfo * get_mountpoint(struct chunk *old) { char *val; PartInfo *tmp; if (old && old->private_data) tmp = old->private_data; else tmp = NULL; val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); if (!val || !*val) { if (!old) return NULL; else { free(old->private_data); old->private_data = NULL; } return NULL; } /* Is it just the same value? */ if (tmp && !strcmp(tmp->mountpoint, val)) return NULL; /* Did we use it already? */ if (check_conflict(val)) { msgConfirm("You already have a mount point for %s assigned!", val); return NULL; } /* Is it bogus? */ if (*val != '/') { msgConfirm("Mount point must start with a / character"); return NULL; } /* Is it going to be mounted on root? */ if (!strcmp(val, "/")) { if (old) old->flags |= CHUNK_IS_ROOT; } else if (old) old->flags &= ~CHUNK_IS_ROOT; safe_free(tmp); val = string_skipwhite(string_prune(val)); tmp = new_part(val, TRUE, 0); if (old) { old->private_data = tmp; old->private_free = safe_free; } return tmp; } /* Get the type of the new partiton */ static PartType get_partition_type(void) { char selection[20]; int i; static unsigned char *fs_types[] = { "FS", "A file system", "Swap", "A swap partition.", }; WINDOW *w = savescr(); i = dialog_menu("Please choose a partition type", "If you want to use this partition for swap space, select Swap.\n" "If you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL); restorescr(w); if (!i) { if (!strcmp(selection, "FS")) return PART_FILESYSTEM; else if (!strcmp(selection, "Swap")) return PART_SWAP; } return PART_NONE; } /* If the user wants a special newfs command for this, set it */ static void getNewfsCmd(PartInfo *p) { char *val; val = msgGetInput(p->newfs_cmd, "Please enter the newfs command and options you'd like to use in\n" "creating this file system."); if (val) sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); } #define MAX_MOUNT_NAME 10 #define PART_PART_COL 0 #define PART_MOUNT_COL 10 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) #define PART_NEWFS_COL (PART_SIZE_COL + 8) #define PART_OFF 38 #define TOTAL_AVAIL_LINES (10) #define PSLICE_SHOWABLE (4) /* stick this all up on the screen */ static void print_label_chunks(void) { int i, j, srow, prow, pcol; int sz; char clrmsg[80]; int ChunkPartStartRow; WINDOW *ChunkWin; /********************************************************/ /*** These values are for controling screen resources ***/ /*** Each label line holds up to 2 labels, so beware! ***/ /*** strategy will be to try to always make sure the ***/ /*** highlighted label is in the active display area. ***/ /********************************************************/ int pslice_max, label_max; int pslice_count, label_count, label_focus_found, pslice_focus_found; attrset(A_REVERSE); mvaddstr(0, 25, "FreeBSD Disklabel Editor"); attrset(A_NORMAL); /*** Count the number of parition slices ***/ pslice_count = 0; for (i = 0; label_chunk_info[i].c ; i++) { if (label_chunk_info[i].type == PART_SLICE) ++pslice_count; } pslice_max = pslice_count; /*** 4 line max for partition slices ***/ if (pslice_max > PSLICE_SHOWABLE) { pslice_max = PSLICE_SHOWABLE; } ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; /*** View partition slices modulo pslice_max ***/ label_max = TOTAL_AVAIL_LINES - pslice_max; for (i = 0; i < 2; i++) { mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); } srow = CHUNK_SLICE_START_ROW; prow = 0; pcol = 0; /*** these variables indicate that the focused item is shown currently ***/ label_focus_found = 0; pslice_focus_found = 0; label_count = 0; pslice_count = 0; mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); wclear(ChunkWin); /*** wrefresh(ChunkWin); ***/ for (i = 0; label_chunk_info[i].c; i++) { /* Is it a slice entry displayed at the top? */ if (label_chunk_info[i].type == PART_SLICE) { /*** This causes the new pslice to replace the previous display ***/ /*** focus must remain on the most recently active pslice ***/ if (pslice_count == pslice_max) { if (pslice_focus_found) { /*** This is where we can mark the more following ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); attrset(A_NORMAL); continue; } else { /*** this is where we set the more previous ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); attrset(A_NORMAL); pslice_count = 0; srow = CHUNK_SLICE_START_ROW; } } sz = space_free(label_chunk_info[i].c); if (i == here) attrset(ATTR_SELECTED); if (i == pslice_focus) pslice_focus_found = -1; mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); attrset(A_NORMAL); clrtoeol(); move(0, 0); /*** refresh(); ***/ ++pslice_count; } /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ else { char onestr[PART_OFF], num[10], *mountpoint, *newfs; /* * We copy this into a blank-padded string so that it looks like * a solid bar in reverse-video */ memset(onestr, ' ', PART_OFF - 1); onestr[PART_OFF - 1] = '\0'; /*** Track how many labels have been displayed ***/ if (label_count == ((label_max - 1 ) * 2)) { if (label_focus_found) { continue; } else { label_count = 0; prow = 0; pcol = 0; } } /* Go for two columns if we've written one full columns worth */ /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ if (label_count == label_max - 1) { pcol = PART_OFF; prow = 0; } memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); /* If it's a filesystem, display the mountpoint */ if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; else if (label_chunk_info[i].type == PART_SWAP) mountpoint = "swap"; else mountpoint = ""; /* Now display the newfs field */ if (label_chunk_info[i].type == PART_FAT) newfs = "DOS"; else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; else if (label_chunk_info[i].type == PART_SWAP) newfs = "SWAP"; else newfs = "*"; for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) onestr[PART_MOUNT_COL + j] = mountpoint[j]; snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); memcpy(onestr + PART_SIZE_COL, num, strlen(num)); memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; if (i == label_focus) { label_focus_found = -1; wattrset(ChunkWin, A_BOLD); } if (i == here) wattrset(ChunkWin, ATTR_SELECTED); /*** lazy man's way of padding this string ***/ while (strlen( onestr ) < 37) strcat(onestr, " "); mvwaddstr(ChunkWin, prow, pcol, onestr); wattrset(ChunkWin, A_NORMAL); move(0, 0); ++prow; ++label_count; } } /*** this will erase all the extra stuff ***/ memset(clrmsg, ' ', 37); clrmsg[37] = '\0'; while (pslice_count < pslice_max) { mvprintw(srow++, 0, clrmsg); clrtoeol(); ++pslice_count; } while (label_count < (2 * (label_max - 1))) { mvwaddstr(ChunkWin, prow++, pcol, clrmsg); ++label_count; if (prow == (label_max - 1)) { prow = 0; pcol = PART_OFF; } } refresh(); wrefresh(ChunkWin); } static void print_command_summary(void) { mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); if (!RunningAsInit) mvprintw(18, 49, "W = Write"); mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); mvprintw(20, 0, "A = Auto Defaults for all!"); mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } static void clear_wins(void) { extern void print_label_chunks(); clear(); print_label_chunks(); } #ifdef __alpha__ /* * If there isn't a freebsd chunk already (i.e. there is no label), * dedicate the disk. */ static void maybe_dedicate(Disk* d) { struct chunk *c; for (c = d->chunks->part; c; c = c->next) { if (c->type == freebsd) break; } if (!c) { msgDebug("dedicating disk"); All_FreeBSD(d, 1); } } #endif static int diskLabel(Device *dev) { int sz, key = 0; Boolean labeling; char *msg = NULL; PartInfo *p, *oldp; PartType type; Device **devs; #ifdef __alpha__ int i; #endif WINDOW *w = savescr(); label_focus = 0; pslice_focus = 0; here = 0; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("No disks found!"); restorescr(w); return DITEM_FAILURE; } labeling = TRUE; keypad(stdscr, TRUE); #ifdef __alpha__ for (i = 0; devs[i]; i++) { maybe_dedicate((Disk*) devs[i]->private); } #endif record_label_chunks(devs, dev); clear(); while (labeling) { char *cp; print_label_chunks(); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); clrtoeol(); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } refresh(); key = getch(); switch (toupper(key)) { int i; static char _msg[40]; case '\014': /* ^L */ clear_wins(); break; case '\020': /* ^P */ case KEY_UP: case '-': if (here != 0) --here; else while (label_chunk_info[here + 1].c) ++here; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (label_chunk_info[here + 1].c) ++here; else here = 0; break; case KEY_HOME: here = 0; break; case KEY_END: while (label_chunk_info[here + 1].c) ++here; break; case KEY_F(1): case '?': systemDisplayHelp("partition"); clear_wins(); break; case 'A': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a disk slice (at top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) msg = "Not enough free space to create a new partition in the slice"; else { struct chunk *tmp; int mib[2]; int physmem; size_t size, swsize; char *cp; Chunk *rootdev, *swapdev, *usrdev, *vardev; (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); if (!rootdev) { cp = variable_get(VAR_ROOT_SIZE); tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); if (!tmp) { msgConfirm("Unable to create the root partition. Too big?"); clear_wins(); break; } tmp->private_data = new_part("/", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!swapdev) { cp = variable_get(VAR_SWAP_SIZE); if (cp) swsize = atoi(cp) * ONE_MEG; else { mib[0] = CTL_HW; mib[1] = HW_PHYSMEM; size = sizeof physmem; sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); swsize = 16 * ONE_MEG + (physmem * 2 / 512); } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, swsize, part, FS_SWAP, 0); if (!tmp) { msgConfirm("Unable to create the swap partition. Too big?"); clear_wins(); break; } tmp->private_data = 0; tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!vardev) { cp = variable_get(VAR_VAR_SIZE); if (cp) sz = atoi(cp) * ONE_MEG; else sz = variable_get(VAR_NO_USR) ? space_free(label_chunk_info[here].c) : VAR_MIN_SIZE * ONE_MEG; tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, 0); if (!tmp) { msgConfirm("Less than %dMB free for /var - you will need to\n" "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); clear_wins(); break; } tmp->private_data = new_part("/var", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!usrdev && !variable_get(VAR_NO_USR)) { cp = variable_get(VAR_USR_SIZE); if (cp) sz = atoi(cp) * ONE_MEG; else sz = space_free(label_chunk_info[here].c); if (sz) { if (sz < (USR_MIN_SIZE * ONE_MEG)) { msgConfirm("Less than %dMB free for /usr - you will need to\n" "partition your disk manually with a custom install!", USR_MIN_SIZE); clear_wins(); break; } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, 0); if (!tmp) { msgConfirm("Unable to create the /usr partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"); clear_wins(); break; } tmp->private_data = new_part("/usr", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } } /* At this point, we're reasonably "labelled" */ if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } break; case 'C': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a master partition (see top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) { msg = "Not enough space to create an additional FreeBSD partition"; break; } else { char *val; int size; struct chunk *tmp; char osize[80]; u_long flags = 0; sprintf(osize, "%d", sz); val = msgGetInput(osize, "Please specify the partition size in blocks or append a trailing G for\n" "gigabytes, M for megabytes, or C for cylinders.\n" "%d blocks (%dMB) are free.", sz, sz / ONE_MEG); if (!val || (size = strtol(val, &cp, 0)) <= 0) { clear_wins(); break; } if (*cp) { if (toupper(*cp) == 'M') size *= ONE_MEG; else if (toupper(*cp) == 'G') size *= ONE_GIG; else if (toupper(*cp) == 'C') size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); } if (size <= FS_MIN_SIZE) { msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); clear_wins(); break; } type = get_partition_type(); if (type == PART_NONE) { clear_wins(); beep(); break; } if (type == PART_FILESYSTEM) { if ((p = get_mountpoint(NULL)) == NULL) { clear_wins(); beep(); break; } else if (!strcmp(p->mountpoint, "/")) flags |= CHUNK_IS_ROOT; else flags &= ~CHUNK_IS_ROOT; } else p = NULL; if ((flags & CHUNK_IS_ROOT)) { if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { msgConfirm("This region cannot be used for your root partition as the\n" "FreeBSD boot code cannot deal with a root partition created\n" "in that location. Please choose another location or smaller\n" "size for your root partition and try again!"); clear_wins(); break; } if (size < (ROOT_MIN_SIZE * ONE_MEG)) { msgConfirm("Warning: This is smaller than the recommended size for a\n" "root partition. For a variety of reasons, root\n" "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); } } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, size, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags); if (!tmp) { msgConfirm("Unable to create the partition. Too big?"); clear_wins(); break; } if (type != PART_SWAP) { /* This is needed to tell the newfs -u about the size */ tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); safe_free(p); } else tmp->private_data = p; tmp->private_free = safe_free; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); /*** This is where we assign focus to new label so it shows ***/ { int i; label_focus = -1; for (i = 0; label_chunk_info[i].c; ++i) { if (label_chunk_info[i].c == tmp) { label_focus = i; break; } } if (label_focus == -1) label_focus = i - 1; } } break; case KEY_DC: case 'D': /* delete */ if (label_chunk_info[here].type == PART_SLICE) { msg = MSG_NOT_APPLICABLE; break; } else if (label_chunk_info[here].type == PART_FAT) { msg = "Use the Disk Partition Editor to delete DOS partitions"; break; } Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); break; case 'M': /* mount */ switch(label_chunk_info[here].type) { case PART_SLICE: msg = MSG_NOT_APPLICABLE; break; case PART_SWAP: msg = "You don't need to specify a mountpoint for a swap partition."; break; case PART_FAT: case PART_FILESYSTEM: oldp = label_chunk_info[here].c->private_data; p = get_mountpoint(label_chunk_info[here].c); if (p) { if (!oldp) p->newfs = FALSE; if (label_chunk_info[here].type == PART_FAT && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") || !strcmp(p->mountpoint, "/var"))) { msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); strcpy(p->mountpoint, "/bogus"); } } if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); break; default: msgFatal("Bogus partition under cursor???"); break; } break; case 'N': /* Set newfs options */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) getNewfsCmd(label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; case 'T': /* Toggle newfs state */ if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); label_chunk_info[here].c->private_data = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } else msg = MSG_NOT_APPLICABLE; break; case 'U': clear(); if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written out your changes -\n" "it's too late to undo!"); } - else if (!msgYesNo("Are you SURE you want to Undo everything?")) { + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); for (i = 0; devs[i]; i++) { Disk *d; if (!devs[i]->enabled) continue; else if ((d = Open_Disk(devs[i]->name)) != NULL) { Free_Disk(devs[i]->private); devs[i]->private = d; diskPartition(devs[i]); } } record_label_chunks(devs, dev); } clear_wins(); break; case 'W': if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written out your changes - if you\n" "wish to overwrite them, you'll have to start this\n" "procedure again from the beginning."); } - else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" + else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_LABELLED, "yes", 0); diskLabelCommit(NULL); } clear_wins(); break; case '|': - if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" + if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" "This is an entirely undocumented feature which you are not\n" "expected to understand!")) { int i; Device **devs; dialog_clear(); end_dialog(); DialogActive = FALSE; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Can't find any disk devices!"); break; } for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { if (devs[i]->enabled) slice_wizard(((Disk *)devs[i]->private)); } if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); DialogActive = TRUE; record_label_chunks(devs, dev); clear_wins(); } else msg = "A most prudent choice!"; break; case '\033': /* ESC */ case 'Q': labeling = FALSE; break; default: beep(); sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); msg = _msg; break; } if (label_chunk_info[here].type == PART_SLICE) pslice_focus = here; else label_focus = here; } restorescr(w); return DITEM_SUCCESS; } static int diskLabelNonInteractive(Device *dev) { char *cp; PartType type; PartInfo *p; u_long flags = 0; int i, status; Device **devs; Disk *d; status = DITEM_SUCCESS; cp = variable_get(VAR_DISK); if (!cp) { msgConfirm("diskLabel: No disk selected - can't label automatically."); return DITEM_FAILURE; } devs = deviceFind(cp, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("diskLabel: No disk device %s found!", cp); return DITEM_FAILURE; } if (dev) d = dev->private; else d = devs[0]->private; #ifdef __alpha__ maybe_dedicate(d); #endif record_label_chunks(devs, dev); for (i = 0; label_chunk_info[i].c; i++) { Chunk *c1 = label_chunk_info[i].c; if (label_chunk_info[i].type == PART_SLICE) { char name[512]; int entries = 1; while (entries) { snprintf(name, sizeof name, "%s-%d", c1->name, entries); if ((cp = variable_get(name)) != NULL) { int sz; char typ[10], mpoint[50]; if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; continue; } else { Chunk *tmp; if (!strcmp(typ, "swap")) { type = PART_SWAP; strcpy(mpoint, "SWAP"); } else { type = PART_FILESYSTEM; if (!strcmp(mpoint, "/")) flags |= CHUNK_IS_ROOT; else flags &= ~CHUNK_IS_ROOT; } if (!sz) sz = space_free(c1); if (sz > space_free(c1)) { msgConfirm("Not enough free space to create partition: %s", mpoint); status = DITEM_FAILURE; continue; } if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { msgConfirm("Unable to create from partition spec: %s. Too big?", cp); status = DITEM_FAILURE; break; } else { tmp->private_data = new_part(mpoint, TRUE, sz); tmp->private_free = safe_free; status = DITEM_SUCCESS; } } entries++; } else { /* No more matches, leave the loop */ entries = 0; } } } else { /* Must be something we can set a mountpoint for */ cp = variable_get(c1->name); if (cp) { char mpoint[50], do_newfs[8]; Boolean newfs = FALSE; do_newfs[0] = '\0'; if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; continue; } newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; if (c1->private_data) { p = c1->private_data; p->newfs = newfs; strcpy(p->mountpoint, mpoint); } else { c1->private_data = new_part(mpoint, newfs, 0); c1->private_free = safe_free; } if (!strcmp(mpoint, "/")) c1->flags |= CHUNK_IS_ROOT; else c1->flags &= ~CHUNK_IS_ROOT; } } } if (status == DITEM_SUCCESS) variable_set2(DISK_LABELLED, "yes", 0); return status; } Index: head/usr.sbin/sade/main.c =================================================================== --- head/usr.sbin/sade/main.c (revision 70004) +++ head/usr.sbin/sade/main.c (revision 70005) @@ -1,165 +1,165 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated for what's essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include const char *StartName; /* Initial contents of argv[0] */ static void screech(int sig) { msgDebug("\007Signal %d caught! That's bad!\n", sig); longjmp(BailOut, sig); } int main(int argc, char **argv) { int choice, scroll, curr, max, status; /* Record name to be able to restart */ StartName = argv[0]; /* Catch fatal signals and complain about them if running as init */ if (getpid() == 1) { signal(SIGBUS, screech); signal(SIGSEGV, screech); } signal(SIGPIPE, SIG_IGN); /* We don't work too well when running as non-root anymore */ if (geteuid() != 0) { fprintf(stderr, "Error: This utility should only be run as root.\n"); return 1; } #ifdef PC98 { /* XXX */ char *p = getenv("TERM"); if (p && strcmp(p, "cons25") == 0) putenv("TERM=cons25w"); } #endif /* Set up whatever things need setting up */ systemInitialize(argc, argv); /* Set default flag and variable values */ installVarDefaults(NULL); /* only when multi-user is it reasonable to do this here */ if (!RunningAsInit) installEnvironment(); if (argc > 1 && !strcmp(argv[1], "-fake")) { variable_set2(VAR_DEBUG, "YES", 0); Fake = TRUE; msgConfirm("I'll be just faking it from here on out, OK?"); } /* Try to preserve our scroll-back buffer */ if (OnVTY) { for (curr = 0; curr < 25; curr++) putchar('\n'); } /* Move stderr aside */ if (DebugFD) dup2(DebugFD, 2); /* Initialize driver modules */ moduleInitialize(); /* Initialize PC-card */ pccardInitialize(); /* Initialize USB */ usbInitialize(); /* Probe for all relevant devices on the system */ deviceGetAll(); /* First, see if we have any arguments to process (and argv[0] counts if it's not "sysinstall") */ if (!RunningAsInit) { int i, start_arg; if (!strstr(argv[0], "sysinstall")) start_arg = 0; else if (Fake) start_arg = 2; else start_arg = 1; for (i = start_arg; i < argc; i++) { if (DITEM_STATUS(dispatchCommand(argv[i])) != DITEM_SUCCESS) systemShutdown(1); } if (argc > start_arg) systemShutdown(0); } else dispatch_load_file_int(TRUE); status = setjmp(BailOut); if (status) { msgConfirm("A signal %d was caught - I'm saving what I can and shutting\n" "If you can reproduce the problem, please turn Debug on in\n" "the Options menu for the extra information it provides in\n" "debugging problems like this.", status); systemShutdown(status); } /* Begin user dialog at outer menu */ dialog_clear(); while (1) { choice = scroll = curr = max = 0; dmenuOpen(&MenuInitial, &choice, &scroll, &curr, &max, TRUE); if (getpid() != 1 #ifdef __alpha__ - || !msgYesNo("Are you sure you wish to exit? The system will halt.") + || !msgNoYes("Are you sure you wish to exit? The system will halt.") #else - || !msgYesNo("Are you sure you wish to exit? The system will reboot\n" + || !msgNoYes("Are you sure you wish to exit? The system will reboot\n" "(be sure to remove any floppies/CDROMs from the drives).") #endif ) break; } /* Say goodnight, Gracie */ systemShutdown(0); return 0; /* We should never get here */ } Index: head/usr.sbin/sade/msg.c =================================================================== --- head/usr.sbin/sade/msg.c (revision 70004) +++ head/usr.sbin/sade/msg.c (revision 70005) @@ -1,328 +1,352 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include Boolean isDebug(void) { char *cp; return (cp = variable_get(VAR_DEBUG)) && strcmp(cp, "no"); } /* Whack up an informational message on the status line, in stand-out */ void msgYap(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); attrs = getattrs(stdscr); attrset(A_REVERSE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); } /* Whack up an informational message on the status line */ void msgInfo(char *fmt, ...) { va_list args; char *errstr; int i, attrs; char line[81]; attrs = getattrs(stdscr); /* NULL is a special convention meaning "erase the old stuff" */ if (!fmt) { move(StatusLine, 0); clrtoeol(); return; } errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); memset(line, ' ', 80); for (i = 0; i < 80; i++) { if (errstr[i]) line[i] = errstr[i]; else break; } line[80] = '\0'; attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, line); attrset(attrs); move(StatusLine, 79); refresh(); } /* Whack up a warning on the status line */ void msgWarn(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Warning: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); attrs = getattrs(stdscr); beep(); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); if (OnVTY && isDebug()) msgDebug("Warning message `%s'\n", errstr); } /* Whack up an error on the status line */ void msgError(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Error: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); beep(); attrs = getattrs(stdscr); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); if (OnVTY && isDebug()) msgDebug("Error message `%s'\n", errstr); } /* Whack up a fatal error on the status line */ void msgFatal(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Fatal Error: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); beep(); attrs = getattrs(stdscr); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); addstr(" - "); addstr("PRESS ANY KEY TO "); if (getpid() == 1) addstr("REBOOT"); else addstr("QUIT"); attrset(attrs); refresh(); if (OnVTY) msgDebug("Fatal error `%s'!\n", errstr); getch(); systemShutdown(1); } /* Put up a message in a popup confirmation box */ void msgConfirm(char *fmt, ...) { va_list args; char *errstr; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); msgInfo(NULL); } dialog_notify(errstr); restorescr(w); } /* Put up a message in a popup information box */ void msgNotify(char *fmt, ...) { va_list args; char *errstr; errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (isDebug()) msgDebug("Notify: %s\n", errstr); dialog_msgbox(NULL, errstr, -1, -1, 0); } /* Put up a message in a popup yes/no box and return 1 for YES, 0 for NO */ int msgYesNo(char *fmt, ...) { va_list args; char *errstr; int ret; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } ret = dialog_yesno("User Confirmation Requested", errstr, -1, -1); restorescr(w); return ret; } +/* Put up a message in a popup no/yes box and return 1 for YES, 0 for NO */ +int +msgNoYes(char *fmt, ...) +{ + va_list args; + char *errstr; + int ret; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); /* Switch back */ + msgInfo(NULL); + } + ret = dialog_noyes("User Confirmation Requested", errstr, -1, -1); + restorescr(w); + return ret; +} + /* Put up a message in an input box and return the value */ char * msgGetInput(char *buf, char *fmt, ...) { va_list args; char *errstr; static char input_buffer[256]; int rval; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (buf) SAFE_STRCPY(input_buffer, buf); else input_buffer[0] = '\0'; if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } rval = dialog_inputbox("Value Required", errstr, -1, -1, input_buffer); restorescr(w); if (!rval) return input_buffer; else return NULL; } /* Write something to the debugging port */ void msgDebug(char *fmt, ...) { va_list args; char *dbg; if (DebugFD == -1) return; dbg = (char *)alloca(FILENAME_MAX); strcpy(dbg, "DEBUG: "); va_start(args, fmt); vsnprintf((char *)(dbg + strlen(dbg)), FILENAME_MAX, fmt, args); va_end(args); write(DebugFD, dbg, strlen(dbg)); } /* Tell the user there's some output to go look at */ void msgWeHaveOutput(char *fmt, ...) { va_list args; char *errstr; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); msgDebug("Notify: %s\n", errstr); dialog_clear_norefresh(); sleep(2); dialog_msgbox(NULL, errstr, -1, -1, 0); restorescr(w); } /* Simple versions of msgConfirm() and msgNotify() for calling from scripts */ int msgSimpleConfirm(char *str) { msgConfirm(str); return DITEM_SUCCESS; } int msgSimpleNotify(char *str) { msgNotify(str); return DITEM_SUCCESS; } Index: head/usr.sbin/sade/sade.h =================================================================== --- head/usr.sbin/sade/sade.h (revision 70004) +++ head/usr.sbin/sade/sade.h (revision 70005) @@ -1,771 +1,772 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef _SYSINSTALL_H_INCLUDE #define _SYSINSTALL_H_INCLUDE #include #include #include #include #include #include #include #include #include #include "ui_objects.h" #include "dir.h" #include "colors.h" #include "libdisk.h" #include "dist.h" /*** Defines ***/ /* device limits */ #define DEV_NAME_MAX 64 /* The maximum length of a device name */ #define DEV_MAX 100 /* The maximum number of devices we'll deal with */ #define INTERFACE_MAX 50 /* Maximum number of network interfaces we'll deal with */ #define IO_ERROR -2 /* Status code for I/O error rather than normal EOF */ /* Number of seconds to wait for data to come off even the slowest media */ #define MEDIA_TIMEOUT 300 /* * I make some pretty gross assumptions about having a max of 50 chunks * total - 8 slices and 42 partitions. I can't easily display many more * than that on the screen at once! * * For 2.1 I'll revisit this and try to make it more dynamic, but since * this will catch 99.99% of all possible cases, I'm not too worried. */ #define MAX_CHUNKS 40 /* Internal environment variable names */ #define DISK_PARTITIONED "_diskPartitioned" #define DISK_LABELLED "_diskLabelled" #define DISK_SELECTED "_diskSelected" #define SYSTEM_STATE "_systemState" #define RUNNING_ON_ROOT "_runningOnRoot" #define TCP_CONFIGURED "_tcpConfigured" /* Ones that can be tweaked from config files */ #define VAR_BLANKTIME "blanktime" #define VAR_BOOTMGR "bootManager" #define VAR_BROWSER_BINARY "browserBinary" #define VAR_BROWSER_PACKAGE "browserPackage" #define VAR_CPIO_VERBOSITY "cpioVerbose" #define VAR_DEBUG "debug" #define VAR_DESKSTYLE "_deskStyle" #define VAR_DISK "disk" #define VAR_DISTS "dists" #define VAR_DIST_MAIN "distMain" #define VAR_DIST_CRYPTO "distCRYPTO" #define VAR_DIST_SRC "distSRC" #define VAR_DIST_X11 "distX11" #define VAR_DIST_XSERVER "distXserver" #define VAR_DIST_XFONTS "distXfonts" #define VAR_DEDICATE_DISK "dedicateDisk" #define VAR_DOMAINNAME "domainname" #define VAR_EDITOR "editor" #define VAR_EXTRAS "ifconfig_" #define VAR_COMMAND "command" #define VAR_CONFIG_FILE "configFile" #define VAR_FIXIT_TTY "fixitTty" #define VAR_FTP_DIR "ftpDirectory" #define VAR_FTP_PASS "ftpPass" #define VAR_FTP_PATH "_ftpPath" #define VAR_FTP_PORT "ftpPort" #define VAR_FTP_STATE "ftpState" #define VAR_FTP_USER "ftpUser" #define VAR_FTP_HOST "ftpHost" #define VAR_HTTP_PATH "_httpPath" #define VAR_HTTP_PROXY "httpProxy" #define VAR_HTTP_PORT "httpPort" #define VAR_HTTP_HOST "httpHost" #define VAR_HTTP_FTP_MODE "httpFtpMode" #define VAR_GATEWAY "defaultrouter" #define VAR_GEOMETRY "geometry" #define VAR_HOSTNAME "hostname" #define VAR_IFCONFIG "ifconfig_" #define VAR_INTERFACES "network_interfaces" #define VAR_INSTALL_CFG "installConfig" #define VAR_INSTALL_ROOT "installRoot" #define VAR_IPADDR "ipaddr" #define VAR_IPV6_ENABLE "ipv6_enable" #define VAR_IPV6ADDR "ipv6addr" #define VAR_KEYMAP "keymap" #define VAR_KGET "kget" #define VAR_LABEL "label" #define VAR_LABEL_COUNT "labelCount" #define VAR_LINUX_ENABLE "linux_enable" #define VAR_MEDIA_TYPE "mediaType" #define VAR_MEDIA_TIMEOUT "MEDIA_TIMEOUT" #define VAR_MOUSED "moused_enable" #define VAR_MOUSED_FLAGS "moused_flags" #define VAR_MOUSED_PORT "moused_port" #define VAR_MOUSED_TYPE "moused_type" #define VAR_NAMESERVER "nameserver" #define VAR_NETINTERACTIVE "netInteractive" #define VAR_NETMASK "netmask" #define VAR_NETWORK_DEVICE "netDev" #define VAR_NEWFS_ARGS "newfsArgs" #define VAR_NFS_PATH "nfs" #define VAR_NFS_HOST "nfsHost" #define VAR_NFS_SECURE "nfs_reserved_port_only" #define VAR_NFS_SERVER "nfs_server_enable" #define VAR_NO_CONFIRM "noConfirm" #define VAR_NO_ERROR "noError" #define VAR_NO_WARN "noWarn" #define VAR_NO_USR "noUsr" #define VAR_NONINTERACTIVE "nonInteractive" #define VAR_NOVELL "novell" #define VAR_NTPDATE_FLAGS "ntpdate_flags" #define VAR_PACKAGE "package" #define VAR_PARTITION "partition" #define VAR_PCNFSD "pcnfsd" #define VAR_PKG_TMPDIR "PKG_TMPDIR" #define VAR_PORTS_PATH "ports" #define VAR_PPP_ENABLE "ppp_enable" #define VAR_PPP_PROFILE "ppp_profile" #define VAR_RELNAME "releaseName" #define VAR_ROOT_SIZE "rootSize" #define VAR_ROUTER "router" #define VAR_ROUTER_ENABLE "router_enable" #define VAR_ROUTERFLAGS "router_flags" #define VAR_SERIAL_SPEED "serialSpeed" #define VAR_SLOW_ETHER "slowEthernetCard" #define VAR_SWAP_SIZE "swapSize" #define VAR_TAPE_BLOCKSIZE "tapeBlocksize" #define VAR_TRY_DHCP "tryDHCP" #define VAR_TRY_RTSOL "tryRTSOL" #define VAR_UFS_PATH "ufs" #define VAR_USR_SIZE "usrSize" #define VAR_VAR_SIZE "varSize" #define VAR_XF86_CONFIG "_xf86config" #define DEFAULT_TAPE_BLOCKSIZE "20" /* One MB worth of blocks */ #define ONE_MEG 2048 #define ONE_GIG (ONE_MEG * 1024) /* Which selection attributes to use */ #define ATTR_SELECTED (ColorDisplay ? item_selected_attr : item_attr) #define ATTR_TITLE button_active_attr /* Handy strncpy() macro */ #define SAFE_STRCPY(to, from) sstrncpy((to), (from), sizeof (to) - 1) /*** Types ***/ typedef unsigned int Boolean; typedef struct disk Disk; typedef struct chunk Chunk; /* Bitfields for menu options */ #define DMENU_NORMAL_TYPE 0x1 /* Normal dialog menu */ #define DMENU_RADIO_TYPE 0x2 /* Radio dialog menu */ #define DMENU_CHECKLIST_TYPE 0x4 /* Multiple choice menu */ #define DMENU_SELECTION_RETURNS 0x8 /* Immediate return on item selection */ typedef struct _dmenu { int type; /* What sort of menu we are */ char *title; /* Our title */ char *prompt; /* Our prompt */ char *helpline; /* Line of help at bottom */ char *helpfile; /* Help file for "F1" */ dialogMenuItem items[0]; /* Array of menu items */ } DMenu; /* An rc.conf variable */ typedef struct _variable { struct _variable *next; char *name; char *value; int dirty; } Variable; #define NO_ECHO_OBJ(type) ((type) | (DITEM_NO_ECHO << 16)) #define TYPE_OF_OBJ(type) ((type) & 0xff) #define ATTR_OF_OBJ(type) ((type) >> 16) /* A screen layout structure */ typedef struct _layout { int y; /* x & Y co-ordinates */ int x; int len; /* The size of the dialog on the screen */ int maxlen; /* How much the user can type in ... */ char *prompt; /* The string for the prompt */ char *help; /* The display for the help line */ void *var; /* The var to set when this changes */ int type; /* The type of the dialog to create */ void *obj; /* The obj pointer returned by libdialog */ } Layout; typedef enum { DEVICE_TYPE_NONE, DEVICE_TYPE_DISK, DEVICE_TYPE_FLOPPY, DEVICE_TYPE_FTP, DEVICE_TYPE_NETWORK, DEVICE_TYPE_CDROM, DEVICE_TYPE_TAPE, DEVICE_TYPE_DOS, DEVICE_TYPE_UFS, DEVICE_TYPE_NFS, DEVICE_TYPE_ANY, DEVICE_TYPE_HTTP, } DeviceType; /* CDROM mount codes */ #define CD_UNMOUNTED 0 #define CD_ALREADY_MOUNTED 1 #define CD_WE_MOUNTED_IT 2 /* A "device" from sysinstall's point of view */ typedef struct _device { char name[DEV_NAME_MAX]; char *description; char *devname; DeviceType type; Boolean enabled; Boolean (*init)(struct _device *dev); FILE * (*get)(struct _device *dev, char *file, Boolean probe); void (*shutdown)(struct _device *dev); void *private; unsigned int flags; } Device; /* Some internal representations of partitions */ typedef enum { PART_NONE, PART_SLICE, PART_SWAP, PART_FILESYSTEM, PART_FAT, } PartType; /* The longest newfs command we'll hand to system() */ #define NEWFS_CMD_MAX 256 typedef struct _part_info { Boolean newfs; char mountpoint[FILENAME_MAX]; char newfs_cmd[NEWFS_CMD_MAX]; } PartInfo; /* An option */ typedef struct _opt { char *name; char *desc; enum { OPT_IS_STRING, OPT_IS_INT, OPT_IS_FUNC, OPT_IS_VAR } type; void *data; void *aux; char *(*check)(); } Option; /* Weird index nodey things we use for keeping track of package information */ typedef enum { PACKAGE, PLACE } node_type; /* Types of nodes */ typedef struct _pkgnode { /* A node in the reconstructed hierarchy */ struct _pkgnode *next; /* My next sibling */ node_type type; /* What am I? */ char *name; /* My name */ char *desc; /* My description (Hook) */ struct _pkgnode *kids; /* My little children */ void *data; /* A place to hang my data */ } PkgNode; typedef PkgNode *PkgNodePtr; /* A single package */ typedef struct _indexEntry { /* A single entry in an INDEX file */ char *name; /* name */ char *path; /* full path to port */ char *prefix; /* port prefix */ char *comment; /* one line description */ char *descrfile; /* path to description file */ char *deps; /* packages this depends on */ int depc; /* how many depend on me */ int installed; /* indicates if it is installed */ char *maintainer; /* maintainer */ } IndexEntry; typedef IndexEntry *IndexEntryPtr; typedef int (*commandFunc)(char *key, void *data); #define HOSTNAME_FIELD_LEN 128 #define IPADDR_FIELD_LEN 16 #define EXTRAS_FIELD_LEN 128 /* This is the structure that Network devices carry around in their private, erm, structures */ typedef struct _devPriv { int use_rtsol; int use_dhcp; char ipaddr[IPADDR_FIELD_LEN]; char netmask[IPADDR_FIELD_LEN]; char extras[EXTRAS_FIELD_LEN]; } DevInfo; /*** Externs ***/ extern jmp_buf BailOut; /* Used to get the heck out */ extern int DebugFD; /* Where diagnostic output goes */ extern Boolean Fake; /* Don't actually modify anything - testing */ extern Boolean SystemWasInstalled; /* Did we install it? */ extern Boolean RunningAsInit; /* Are we running stand-alone? */ extern Boolean DialogActive; /* Is the dialog() stuff up? */ extern Boolean ColorDisplay; /* Are we on a color display? */ extern Boolean OnVTY; /* On a syscons VTY? */ extern Variable *VarHead; /* The head of the variable chain */ extern Device *mediaDevice; /* Where we're getting our distribution from */ extern unsigned int Dists; /* Which distributions we want */ extern unsigned int CRYPTODists; /* Which naughty distributions we want */ extern unsigned int SrcDists; /* Which src distributions we want */ extern unsigned int XF86Dists; /* Which XFree86 dists we want */ extern unsigned int XF86ServerDists; /* The XFree86 servers we want */ extern unsigned int XF86FontDists; /* The XFree86 fonts we want */ extern int BootMgr; /* Which boot manager to use */ extern int StatusLine; /* Where to print our status messages */ extern DMenu MenuInitial; /* Initial installation menu */ extern DMenu MenuFixit; /* Fixit repair menu */ extern DMenu MenuMBRType; /* Type of MBR to write on the disk */ extern DMenu MenuConfigure; /* Final configuration menu */ extern DMenu MenuDocumentation; /* Documentation menu */ extern DMenu MenuFTPOptions; /* FTP Installation options */ extern DMenu MenuIndex; /* Index menu */ extern DMenu MenuOptions; /* Installation options */ extern DMenu MenuOptionsLanguage; /* Language options menu */ extern DMenu MenuMedia; /* Media type menu */ extern DMenu MenuMouse; /* Mouse type menu */ extern DMenu MenuMediaCDROM; /* CDROM media menu */ extern DMenu MenuMediaDOS; /* DOS media menu */ extern DMenu MenuMediaFloppy; /* Floppy media menu */ extern DMenu MenuMediaFTP; /* FTP media menu */ extern DMenu MenuMediaTape; /* Tape media menu */ extern DMenu MenuNetworkDevice; /* Network device menu */ extern DMenu MenuNTP; /* NTP time server menu */ extern DMenu MenuSecurityProfile; /* Security profile menu */ extern DMenu MenuStartup; /* Startup services menu */ extern DMenu MenuSyscons; /* System console configuration menu */ extern DMenu MenuSysconsFont; /* System console font configuration menu */ extern DMenu MenuSysconsKeymap; /* System console keymap configuration menu */ extern DMenu MenuSysconsKeyrate; /* System console keyrate configuration menu */ extern DMenu MenuSysconsSaver; /* System console saver configuration menu */ extern DMenu MenuSysconsScrnmap; /* System console screenmap configuration menu */ extern DMenu MenuNetworking; /* Network configuration menu */ extern DMenu MenuInstallCustom; /* Custom Installation menu */ extern DMenu MenuDistributions; /* Distribution menu */ extern DMenu MenuDiskDevices; /* Disk type devices */ extern DMenu MenuSubDistributions; /* Custom distribution menu */ extern DMenu MenuSrcDistributions; /* Source distribution menu */ extern DMenu MenuXF86; /* XFree86 main menu */ extern DMenu MenuXF86Select; /* XFree86 distribution selection menu */ extern DMenu MenuXF86SelectCore; /* XFree86 core distribution menu */ extern DMenu MenuXF86SelectServer; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectPC98Server; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuXDesktops; /* Disk devices menu */ extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ extern DMenu MenuUsermgmt; /* User management menu */ extern DMenu MenuFixit; /* Fixit floppy/CDROM/shell menu */ extern DMenu MenuXF86Config; /* Select XFree86 configuration type */ extern int FixItMode; /* FixItMode starts shell onc urrent device (ie Serial port) */ extern const char * StartName; /* Which name we were started as */ /* Stuff from libdialog which isn't properly declared outside */ extern void display_helpfile(void); extern void display_helpline(WINDOW *w, int y, int width); /*** Prototypes ***/ /* anonFTP.c */ extern int configAnonFTP(dialogMenuItem *self); /* cdrom.c */ extern Boolean mediaInitCDROM(Device *dev); extern FILE *mediaGetCDROM(Device *dev, char *file, Boolean probe); extern void mediaShutdownCDROM(Device *dev); /* command.c */ extern void command_clear(void); extern void command_sort(void); extern void command_execute(void); extern void command_shell_add(char *key, char *fmt, ...); extern void command_func_add(char *key, commandFunc func, void *data); /* config.c */ extern void configEnvironmentRC_conf(void); extern void configEnvironmentResolv(char *config); extern void configRC_conf(void); extern int configFstab(dialogMenuItem *self); extern int configRC(dialogMenuItem *self); extern int configResolv(dialogMenuItem *self); extern int configPackages(dialogMenuItem *self); extern int configSaver(dialogMenuItem *self); extern int configSaverTimeout(dialogMenuItem *self); extern int configLinux(dialogMenuItem *self); extern int configNTP(dialogMenuItem *self); extern int configUsers(dialogMenuItem *self); extern int configXSetup(dialogMenuItem *self); extern int configXDesktop(dialogMenuItem *self); extern int configRouter(dialogMenuItem *self); extern int configPCNFSD(dialogMenuItem *self); extern int configNFSServer(dialogMenuItem *self); extern int configWriteRC_conf(dialogMenuItem *self); extern int configSecurityProfile(dialogMenuItem *self); extern int configSecurityFascist(dialogMenuItem *self); extern int configSecurityHigh(dialogMenuItem *self); extern int configSecurityModerate(dialogMenuItem *self); extern int configSecurityLiberal(dialogMenuItem *self); /* crc.c */ extern int crc(int, unsigned long *, unsigned long *); /* devices.c */ extern DMenu *deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d)); extern void deviceGetAll(void); extern void deviceReset(void); extern void deviceRescan(void); extern Device **deviceFind(char *name, DeviceType type); extern Device **deviceFindDescr(char *name, char *desc, DeviceType class); extern int deviceCount(Device **devs); extern Device *new_device(char *name); extern Device *deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, Boolean (*init)(Device *mediadev), FILE * (*get)(Device *dev, char *file, Boolean probe), void (*shutDown)(Device *mediadev), void *private); extern Boolean dummyInit(Device *dev); extern FILE *dummyGet(Device *dev, char *dist, Boolean probe); extern void dummyShutdown(Device *dev); /* dhcp.c */ extern int dhcpParseLeases(char *file, char *hostname, char *domain, char *nameserver, char *ipaddr, char *gateway, char *netmask); /* disks.c */ extern int diskPartitionEditor(dialogMenuItem *self); extern int diskPartitionWrite(dialogMenuItem *self); extern int diskGetSelectCount(Device ***devs); extern void diskPartition(Device *dev); /* dispatch.c */ extern int dispatchCommand(char *command); extern int dispatch_load_floppy(dialogMenuItem *self); extern int dispatch_load_file_int(int); extern int dispatch_load_file(dialogMenuItem *self); /* dist.c */ extern int distReset(dialogMenuItem *self); extern int distConfig(dialogMenuItem *self); extern int distSetCustom(dialogMenuItem *self); extern int distUnsetCustom(dialogMenuItem *self); extern int distSetDeveloper(dialogMenuItem *self); extern int distSetXDeveloper(dialogMenuItem *self); extern int distSetKernDeveloper(dialogMenuItem *self); extern int distSetXKernDeveloper(dialogMenuItem *self); extern int distSetUser(dialogMenuItem *self); extern int distSetXUser(dialogMenuItem *self); extern int distSetMinimum(dialogMenuItem *self); extern int distSetEverything(dialogMenuItem *self); extern int distSetSrc(dialogMenuItem *self); extern int distSetXF86(dialogMenuItem *self); extern int distExtractAll(dialogMenuItem *self); /* dmenu.c */ extern int dmenuDisplayFile(dialogMenuItem *tmp); extern int dmenuSubmenu(dialogMenuItem *tmp); extern int dmenuSystemCommand(dialogMenuItem *tmp); extern int dmenuSystemCommandBox(dialogMenuItem *tmp); extern int dmenuExit(dialogMenuItem *tmp); extern int dmenuISetVariable(dialogMenuItem *tmp); extern int dmenuSetVariable(dialogMenuItem *tmp); extern int dmenuSetKmapVariable(dialogMenuItem *tmp); extern int dmenuSetVariables(dialogMenuItem *tmp); extern int dmenuToggleVariable(dialogMenuItem *tmp); extern int dmenuSetFlag(dialogMenuItem *tmp); extern int dmenuSetValue(dialogMenuItem *tmp); extern Boolean dmenuOpen(DMenu *menu, int *choice, int *scroll, int *curr, int *max, Boolean buttons); extern Boolean dmenuOpenSimple(DMenu *menu, Boolean buttons); extern int dmenuVarCheck(dialogMenuItem *item); extern int dmenuVarsCheck(dialogMenuItem *item); extern int dmenuFlagCheck(dialogMenuItem *item); extern int dmenuRadioCheck(dialogMenuItem *item); /* doc.c */ extern int docBrowser(dialogMenuItem *self); extern int docShowDocument(dialogMenuItem *self); /* dos.c */ extern Boolean mediaCloseDOS(Device *dev, FILE *fp); extern Boolean mediaInitDOS(Device *dev); extern FILE *mediaGetDOS(Device *dev, char *file, Boolean probe); extern void mediaShutdownDOS(Device *dev); /* floppy.c */ extern int getRootFloppy(void); extern Boolean mediaInitFloppy(Device *dev); extern FILE *mediaGetFloppy(Device *dev, char *file, Boolean probe); extern void mediaShutdownFloppy(Device *dev); /* ftp_strat.c */ extern Boolean mediaCloseFTP(Device *dev, FILE *fp); extern Boolean mediaInitFTP(Device *dev); extern FILE *mediaGetFTP(Device *dev, char *file, Boolean probe); extern void mediaShutdownFTP(Device *dev); /* http.c */ extern Boolean mediaInitHTTP(Device *dev); extern FILE *mediaGetHTTP(Device *dev, char *file, Boolean probe); /* globals.c */ extern void globalsInit(void); /* index.c */ int index_read(FILE *fp, PkgNodePtr papa); int index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll); void index_init(PkgNodePtr top, PkgNodePtr plist); void index_node_free(PkgNodePtr top, PkgNodePtr plist); void index_sort(PkgNodePtr top); void index_print(PkgNodePtr top, int level); int index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended); int index_initialize(char *path); PkgNodePtr index_search(PkgNodePtr top, char *str, PkgNodePtr *tp); /* install.c */ extern Boolean checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev); extern int installCommit(dialogMenuItem *self); extern int installCustomCommit(dialogMenuItem *self); extern int installExpress(dialogMenuItem *self); extern int installStandard(dialogMenuItem *self); extern int installFixitHoloShell(dialogMenuItem *self); extern int installFixitCDROM(dialogMenuItem *self); extern int installFixitFloppy(dialogMenuItem *self); extern int installFixupBin(dialogMenuItem *self); extern int installFixupXFree(dialogMenuItem *self); extern int installUpgrade(dialogMenuItem *self); extern int installFilesystems(dialogMenuItem *self); extern int installVarDefaults(dialogMenuItem *self); extern void installEnvironment(void); extern int installX11package(dialogMenuItem *self); extern Boolean copySelf(void); /* kget.c */ extern int kget(char *out); /* keymap.c */ extern int loadKeymap(const char *lang); /* label.c */ extern int diskLabelEditor(dialogMenuItem *self); extern int diskLabelCommit(dialogMenuItem *self); /* makedevs.c (auto-generated) */ extern const char termcap_ansi[]; extern const char termcap_vt100[]; extern const char termcap_cons25w[]; extern const char termcap_cons25[]; extern const char termcap_cons25_m[]; extern const char termcap_cons25r[]; extern const char termcap_cons25r_m[]; extern const char termcap_cons25l1[]; extern const char termcap_cons25l1_m[]; extern const char termcap_xterm[]; extern const u_char font_iso_8x16[]; extern const u_char font_cp850_8x16[]; extern const u_char font_cp866_8x16[]; extern const u_char koi8_r2cp866[]; extern u_char default_scrnmap[]; /* media.c */ extern char *cpioVerbosity(void); extern void mediaClose(void); extern int mediaTimeout(void); extern int mediaSetCDROM(dialogMenuItem *self); extern int mediaSetFloppy(dialogMenuItem *self); extern int mediaSetDOS(dialogMenuItem *self); extern int mediaSetTape(dialogMenuItem *self); extern int mediaSetFTP(dialogMenuItem *self); extern int mediaSetFTPActive(dialogMenuItem *self); extern int mediaSetFTPPassive(dialogMenuItem *self); extern int mediaSetHTTP(dialogMenuItem *self); extern int mediaSetUFS(dialogMenuItem *self); extern int mediaSetNFS(dialogMenuItem *self); extern int mediaSetFTPUserPass(dialogMenuItem *self); extern int mediaSetCPIOVerbosity(dialogMenuItem *self); extern int mediaGetType(dialogMenuItem *self); extern Boolean mediaExtractDist(char *dir, char *dist, FILE *fp); extern Boolean mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpic); extern Boolean mediaExtractDistEnd(int zpid, int cpid); extern Boolean mediaVerify(void); extern FILE *mediaGenericGet(char *base, const char *file); /* misc.c */ extern Boolean file_readable(char *fname); extern Boolean file_executable(char *fname); extern Boolean directory_exists(const char *dirname); extern char *root_bias(char *path); extern char *itoa(int value); extern char *string_concat(char *p1, char *p2); extern char *string_concat3(char *p1, char *p2, char *p3); extern char *string_prune(char *str); extern char *string_skipwhite(char *str); extern char *string_copy(char *s1, char *s2); extern char *pathBaseName(const char *path); extern void safe_free(void *ptr); extern void *safe_malloc(size_t size); extern void *safe_realloc(void *orig, size_t size); extern dialogMenuItem *item_add(dialogMenuItem *list, char *prompt, char *title, int (*checked)(dialogMenuItem *self), int (*fire)(dialogMenuItem *self), void (*selected)(dialogMenuItem *self, int is_selected), void *data, int aux, int *curr, int *max); extern void items_free(dialogMenuItem *list, int *curr, int *max); extern int Mkdir(char *); extern int Mount(char *, void *data); extern WINDOW *openLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height); extern ComposeObj *initLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max); extern int layoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, int *n, int max, int *cbutton, int *cancel); extern WINDOW *savescr(void); extern void restorescr(WINDOW *w); extern char *sstrncpy(char *dst, const char *src, int size); /* modules.c */ extern void moduleInitialize(void); /* mouse.c */ extern int mousedTest(dialogMenuItem *self); extern int mousedDisable(dialogMenuItem *self); extern int setMouseFlags(dialogMenuItem *self); /* msg.c */ extern Boolean isDebug(void); extern void msgInfo(char *fmt, ...); extern void msgYap(char *fmt, ...); extern void msgWarn(char *fmt, ...); extern void msgDebug(char *fmt, ...); extern void msgError(char *fmt, ...); extern void msgFatal(char *fmt, ...); extern void msgConfirm(char *fmt, ...); extern void msgNotify(char *fmt, ...); extern void msgWeHaveOutput(char *fmt, ...); extern int msgYesNo(char *fmt, ...); +extern int msgNoYes(char *fmt, ...); extern char *msgGetInput(char *buf, char *fmt, ...); extern int msgSimpleConfirm(char *); extern int msgSimpleNotify(char *); /* network.c */ extern Boolean mediaInitNetwork(Device *dev); extern void mediaShutdownNetwork(Device *dev); /* nfs.c */ extern Boolean mediaInitNFS(Device *dev); extern FILE *mediaGetNFS(Device *dev, char *file, Boolean probe); extern void mediaShutdownNFS(Device *dev); /* options.c */ extern int optionsEditor(dialogMenuItem *self); /* package.c */ extern int packageAdd(dialogMenuItem *self); extern int package_add(char *name); extern int package_extract(Device *dev, char *name, Boolean depended); extern Boolean package_exists(char *name); /* pccard.c */ extern void pccardInitialize(void); /* system.c */ extern void systemInitialize(int argc, char **argv); extern void systemShutdown(int status); extern int execExecute(char *cmd, char *name); extern int systemExecute(char *cmd); extern void systemSuspendDialog(void); extern void systemResumeDialog(void); extern int systemDisplayHelp(char *file); extern char *systemHelpFile(char *file, char *buf); extern void systemChangeFont(const u_char font[]); extern void systemChangeLang(char *lang); extern void systemChangeTerminal(char *color, const u_char c_termcap[], char *mono, const u_char m_termcap[]); extern void systemChangeScreenmap(const u_char newmap[]); extern void systemCreateHoloshell(void); extern int vsystem(char *fmt, ...); /* tape.c */ extern char *mediaTapeBlocksize(void); extern Boolean mediaInitTape(Device *dev); extern FILE *mediaGetTape(Device *dev, char *file, Boolean probe); extern void mediaShutdownTape(Device *dev); /* tcpip.c */ extern int tcpOpenDialog(Device *dev); extern int tcpMenuSelect(dialogMenuItem *self); extern Device *tcpDeviceSelect(void); /* termcap.c */ extern int set_termcap(void); /* ufs.c */ extern void mediaShutdownUFS(Device *dev); extern Boolean mediaInitUFS(Device *dev); extern FILE *mediaGetUFS(Device *dev, char *file, Boolean probe); /* usb.c */ extern void usbInitialize(void); /* user.c */ extern int userAddGroup(dialogMenuItem *self); extern int userAddUser(dialogMenuItem *self); /* variable.c */ extern void variable_set(char *var, int dirty); extern void variable_set2(char *name, char *value, int dirty); extern char *variable_get(char *var); extern int variable_cmp(char *var, char *value); extern void variable_unset(char *var); extern char *variable_get_value(char *var, char *prompt, int dirty); extern int variable_check(char *data); extern int dump_variables(dialogMenuItem *self); /* wizard.c */ extern void slice_wizard(Disk *d); #endif /* _SYSINSTALL_H_INCLUDE */ Index: head/usr.sbin/sade/system.c =================================================================== --- head/usr.sbin/sade/system.c (revision 70004) +++ head/usr.sbin/sade/system.c (revision 70005) @@ -1,506 +1,506 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Jordan Hubbard * * My contributions are in the public domain. * * Parts of this file are also blatently stolen from Poul-Henning Kamp's * previous version of sysinstall, and as such fall under his "BEERWARE license" * so buy him a beer if you like it! Buy him a beer for me, too! * Heck, get him completely drunk and send me pictures! :-) */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include /* Where we stick our temporary expanded doc file */ #define DOC_TMP_DIR "/tmp/.doc" #define DOC_TMP_FILE "/tmp/.doc/doc.tmp" static pid_t ehs_pid; /* * Handle interrupt signals - this probably won't work in all cases * due to our having bogotified the internal state of dialog or curses, * but we'll give it a try. */ static int intr_continue(dialogMenuItem *self) { return DITEM_LEAVE_MENU; } static int intr_reboot(dialogMenuItem *self) { systemShutdown(-1); /* NOTREACHED */ return 0; } static int intr_restart(dialogMenuItem *self) { execl(StartName, StartName, NULL); /* NOTREACHED */ return -1; } static dialogMenuItem intrmenu[] = { { "Abort", "Abort the installation", NULL, intr_reboot }, { "Restart", "Restart the installation program", NULL, intr_restart }, { "Continue", "Continue the installation", NULL, intr_continue }, }; static void handle_intr(int sig) { WINDOW *save = savescr(); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } (void)dialog_menu("Installation interrupt", "Do you want to abort the installation?", -1, -1, 3, -3, intrmenu, NULL, NULL, NULL); restorescr(save); } /* Expand a file into a convenient location, nuking it each time */ static char * expand(char *fname) { char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip"; if (!directory_exists(DOC_TMP_DIR)) { Mkdir(DOC_TMP_DIR); if (chown(DOC_TMP_DIR, 0, 0) < 0) return NULL; if (chmod(DOC_TMP_DIR, S_IRWXU) < 0) return NULL; } else unlink(DOC_TMP_FILE); if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE)) return NULL; return DOC_TMP_FILE; } /* Initialize system defaults */ void systemInitialize(int argc, char **argv) { int i, boothowto; sigset_t signalset; signal(SIGINT, SIG_IGN); globalsInit(); i = sizeof(boothowto); if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, NULL) && (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE)) variable_set2(VAR_DEBUG, "YES", 0); /* Are we running as init? */ if (getpid() == 1) { int fd, type; RunningAsInit = 1; setsid(); close(0); fd = open("/dev/ttyv0", O_RDWR); if (fd == -1) { fd = open("/dev/console", O_RDWR); /* fallback */ variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */ } else OnVTY = TRUE; /* * To make _sure_ we're on a VTY and don't have /dev/console switched * away to a serial port or something, attempt to set the cursor appearance. */ type = 0; /* normal */ if (OnVTY) { int fd2; if ((fd2 = open("/dev/console", O_RDWR)) != -1) { if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) { OnVTY = FALSE; variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit the console type */ close(fd); close(fd2); open("/dev/console", O_RDWR); } else close(fd2); } } close(1); dup(0); close(2); dup(0); printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console"); ioctl(0, TIOCSCTTY, (char *)NULL); setlogin("root"); setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1); setbuf(stdin, 0); setbuf(stderr, 0); #ifdef __alpha__ i = 0; sysctlbyname("machdep.unaligned_print", NULL, 0, &i, sizeof(i)); #endif } else { char hname[256]; /* Initalize various things for a multi-user environment */ if (!gethostname(hname, sizeof hname)) variable_set2(VAR_HOSTNAME, hname, 0); } if (set_termcap() == -1) { printf("Can't find terminal entry\n"); exit(-1); } /* XXX - libdialog has particularly bad return value checking */ init_dialog(); /* If we haven't crashed I guess dialog is running ! */ DialogActive = TRUE; /* Make sure HOME is set for those utilities that need it */ if (!getenv("HOME")) setenv("HOME", "/", 1); signal(SIGINT, handle_intr); /* * Make sure we can be interrupted even if we were re-executed * from an interrupt. */ sigemptyset(&signalset); sigaddset(&signalset, SIGINT); sigprocmask(SIG_UNBLOCK, &signalset, NULL); (void)vsystem("rm -rf %s", DOC_TMP_DIR); } /* Close down and prepare to exit */ void systemShutdown(int status) { /* If some media is open, close it down */ if (status >=0) mediaClose(); /* write out any changes to rc.conf .. */ configRC_conf(); /* Shut down the dialog library */ if (DialogActive) { end_dialog(); DialogActive = FALSE; } /* Shut down curses */ endwin(); /* If we have a temporary doc dir lying around, nuke it */ (void)vsystem("rm -rf %s", DOC_TMP_DIR); /* REALLY exit! */ if (RunningAsInit) { /* Put the console back */ ioctl(0, VT_ACTIVATE, 2); #ifdef __alpha__ reboot(RB_HALT); #else reboot(0); #endif } else exit(status); } /* Run some general command */ int systemExecute(char *command) { int status; struct termios foo; WINDOW *w = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; tcsetattr(0, TCSANOW, &foo); } if (!Fake) status = system(command); else { status = 0; msgDebug("systemExecute: Faked execution of `%s'\n", command); } DialogActive = TRUE; restorescr(w); return status; } /* suspend/resume libdialog/curses screen */ static WINDOW *oldW; void systemSuspendDialog(void) { oldW = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; } void systemResumeDialog(void) { DialogActive = TRUE; restorescr(oldW); } /* Display a help file in a filebox */ int systemDisplayHelp(char *file) { char *fname = NULL; char buf[FILENAME_MAX]; int ret = 0; WINDOW *w = savescr(); fname = systemHelpFile(file, buf); if (!fname) { snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file); use_helpfile(NULL); use_helpline(NULL); dialog_mesgbox("Sorry!", buf, -1, -1); ret = 1; } else { use_helpfile(NULL); use_helpline(NULL); dialog_textbox(file, fname, LINES, COLS); } restorescr(w); return ret; } char * systemHelpFile(char *file, char *buf) { if (!file) return NULL; if (file[0] == '/') return file; snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.hlp", file); if (file_readable(buf)) return buf; snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.TXT", file); if (file_readable(buf)) return buf; return NULL; } void systemChangeTerminal(char *color, const u_char c_term[], char *mono, const u_char m_term[]) { if (OnVTY) { int setupterm(char *color, int, int *); if (ColorDisplay) { setenv("TERM", color, 1); setenv("TERMCAP", c_term, 1); reset_shell_mode(); setterm(color); cbreak(); noecho(); } else { setenv("TERM", mono, 1); setenv("TERMCAP", m_term, 1); reset_shell_mode(); setterm(mono); cbreak(); noecho(); } } clear(); refresh(); dialog_clear(); } int vsystem(char *fmt, ...) { va_list args; int pstat; pid_t pid; int omask; sig_t intsave, quitsave; char *cmd; int i; cmd = (char *)alloca(FILENAME_MAX); cmd[0] = '\0'; va_start(args, fmt); vsnprintf(cmd, FILENAME_MAX, fmt, args); va_end(args); omask = sigblock(sigmask(SIGCHLD)); if (Fake) { msgDebug("vsystem: Faked execution of `%s'\n", cmd); return 0; } if (isDebug()) msgDebug("Executing command `%s'\n", cmd); pid = fork(); if (pid == -1) { (void)sigsetmask(omask); i = 127; } else if (!pid) { /* Junior */ (void)sigsetmask(omask); if (DebugFD != -1) { dup2(DebugFD, 0); dup2(DebugFD, 1); dup2(DebugFD, 2); } else { close(1); open("/dev/null", O_WRONLY); dup2(1, 2); } if (!RunningAsInit) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); else execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL); exit(1); } else { intsave = signal(SIGINT, SIG_IGN); quitsave = signal(SIGQUIT, SIG_IGN); pid = waitpid(pid, &pstat, 0); (void)sigsetmask(omask); (void)signal(SIGINT, intsave); (void)signal(SIGQUIT, quitsave); i = (pid == -1) ? -1 : WEXITSTATUS(pstat); if (isDebug()) msgDebug("Command `%s' returns status of %d\n", cmd, i); } return i; } void systemCreateHoloshell(void) { int waitstatus; if ((FixItMode || OnVTY) && RunningAsInit) { if (ehs_pid != 0) { int pstat; if (kill(ehs_pid, 0) == 0) { - if (msgYesNo("There seems to be an emergency holographic shell\n" + if (msgNoYes("There seems to be an emergency holographic shell\n" "already running on VTY 4.\n\n" "Kill it and start a new one?")) return; /* try cleaning up as much as possible */ (void) kill(ehs_pid, SIGHUP); sleep(1); (void) kill(ehs_pid, SIGKILL); } /* avoid too many zombies */ (void) waitpid(ehs_pid, &pstat, WNOHANG); } if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if ((ehs_pid = fork()) == 0) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("Doctor: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(fd, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(fd, TCSANOW, &foo) == -1) msgDebug("Doctor: I'm unable to set the erase character.\n"); } else msgDebug("Doctor: I'm unable to get the terminal attributes!\n"); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n"); fflush(stdout); } execlp("sh", "-sh", 0); msgDebug("Was unable to execute sh for Holographic shell!\n"); exit(1); } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { WINDOW *w = savescr(); msgNotify("Starting an emergency holographic shell on VTY4"); sleep(2); restorescr(w); } else { (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for shell to finish it serial mode since there is no virtual console */ systemResumeDialog(); } } } } Index: head/usr.sbin/sysinstall/disks.c =================================================================== --- head/usr.sbin/sysinstall/disks.c (revision 70004) +++ head/usr.sbin/sysinstall/disks.c (revision 70005) @@ -1,971 +1,971 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_SIZE }; #ifdef PC98 #define SUBTYPE_FREEBSD 50324 #define SUBTYPE_FAT 37218 #else #define SUBTYPE_FREEBSD 165 #define SUBTYPE_FAT 6 #endif /* Where we start displaying chunk information on the screen */ #define CHUNK_START_ROW 5 /* Where we keep track of MBR chunks */ static struct chunk *chunk_info[16]; static int current_chunk; static void diskPartitionNonInteractive(Device *dev); static void record_chunks(Disk *d) { struct chunk *c1 = NULL; int i = 0; int last_free = 0; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == unused && c1->size > last_free) { last_free = c1->size; current_chunk = i; } chunk_info[i++] = c1; } chunk_info[i] = NULL; if (current_chunk >= i) current_chunk = i - 1; } static int Total; static void print_chunks(Disk *d, int u) { int row; int i; int sz; char *szstr; szstr = (u == UNIT_MEG ? "MB" : (u == UNIT_KILO ? "KB" : "ST")); for (i = Total = 0; chunk_info[i]; i++) Total += chunk_info[i]->size; #ifndef PC98 if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64) { dialog_clear_norefresh(); msgConfirm("WARNING: A geometry of %d/%d/%d for %s is incorrect. Using\n" "a more likely geometry. If this geometry is incorrect or you\n" "are unsure as to whether or not it's correct, please consult\n" "the Hardware Guide in the Documentation submenu or use the\n" "(G)eometry command to change it now.\n\n" "Remember: you need to enter whatever your BIOS thinks the\n" "geometry is! For IDE, it's what you were told in the BIOS\n" "setup. For SCSI, it's the translation mode your controller is\n" "using. Do NOT use a ``physical geometry''.", d->bios_cyl, d->bios_hd, d->bios_sect, d->name); Sanitize_Bios_Geom(d); } #endif attrset(A_NORMAL); mvaddstr(0, 0, "Disk name:\t"); clrtobot(); attrset(A_REVERSE); addstr(d->name); attrset(A_NORMAL); attrset(A_REVERSE); mvaddstr(0, 55, "FDISK Partition Editor"); attrset(A_NORMAL); mvprintw(1, 0, "DISK Geometry:\t%lu cyls/%lu heads/%lu sectors = %lu sectors (%luMB)", d->bios_cyl, d->bios_hd, d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect * 512 / 1024 / 1024); mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s", "Offset", "Size", szstr, "End", "Name", "PType", "Desc", "Subtype", "Flags"); for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { switch(u) { default: /* fall thru */ case UNIT_BLOCKS: sz = chunk_info[i]->size; break; case UNIT_KILO: sz = chunk_info[i]->size * 512 / 1024; break; case UNIT_MEG: sz = chunk_info[i]->size * 512 / 1024 / 1024; break; } if (i == current_chunk) attrset(ATTR_SELECTED); mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", chunk_info[i]->offset, sz, chunk_info[i]->end, chunk_info[i]->name, chunk_info[i]->type, slice_type_name(chunk_info[i]->type, chunk_info[i]->subtype), chunk_info[i]->subtype, ShowChunkFlags(chunk_info[i])); if (i == current_chunk) attrset(A_NORMAL); } } static void print_command_summary() { mvprintw(14, 0, "The following commands are supported (in upper or lower case):"); mvprintw(16, 0, "A = Use Entire Disk G = set Drive Geometry C = Create Slice"); mvprintw(17, 0, "D = Delete Slice Z = Toggle Size Units S = Set Bootable"); mvprintw(18, 0, "T = Change Type U = Undo All Changes Q = Finish"); if (!RunningAsInit) mvprintw(18, 48, "W = Write Changes"); mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } #ifdef PC98 static void getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size, u_char **bootmenu, size_t *bootmenu_size) { extern u_char boot0[]; extern size_t boot0_size; extern u_char boot05[]; extern size_t boot05_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: *bootipl = boot0; *bootipl_size = boot0_size; *bootmenu = boot05; *bootmenu_size = boot05_size; return; case 2: default: break; } } *bootipl = NULL; *bootipl_size = 0; *bootmenu = NULL; *bootmenu_size = 0; } #else static void getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize) { #ifndef __alpha__ /* only meaningful on x86 */ extern u_char mbr[], boot0[]; extern size_t mbr_size, boot0_size; char str[80]; char *cp; int i = 0; cp = variable_get(VAR_BOOTMGR); if (!cp) { /* Figure out what kind of MBR the user wants */ sprintf(str, "Install Boot Manager for drive %s?", dname); MenuMBRType.title = str; i = dmenuOpenSimple(&MenuMBRType, FALSE); } else { if (!strncmp(cp, "boot", 4)) BootMgr = 0; else if (!strcmp(cp, "standard")) BootMgr = 1; else BootMgr = 2; } if (cp || i) { switch (BootMgr) { case 0: *bootCode = boot0; *bootCodeSize = boot0_size; return; case 1: *bootCode = mbr; *bootCodeSize = mbr_size; return; case 2: default: break; } } #endif *bootCode = NULL; *bootCodeSize = 0; } #endif int diskGetSelectCount(Device ***devs) { int i, cnt, enabled; char *cp; Device **dp; cp = variable_get(VAR_DISK); dp = *devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(dp); if (!cnt) return -1; for (i = 0, enabled = 0; i < cnt; i++) { if (dp[i]->enabled) ++enabled; } return enabled; } void diskPartition(Device *dev) { char *cp, *p; int rv, key = 0; Boolean chunking; char *msg = NULL; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif WINDOW *w = savescr(); Disk *d = (Disk *)dev->private; int size_unit; size_unit = UNIT_BLOCKS; chunking = TRUE; keypad(stdscr, TRUE); /* Flush both the dialog and curses library views of the screen since we don't always know who called us */ dialog_clear_norefresh(), clear(); current_chunk = 0; /* Set up the chunk array */ record_chunks(d); while (chunking) { char *val, geometry[80]; /* Now print our overall state */ if (d) print_chunks(d, size_unit); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } /* Get command character */ key = getch(); switch (toupper(key)) { case '\014': /* ^L (redraw) */ clear(); msg = NULL; break; case '\020': /* ^P */ case KEY_UP: case '-': if (current_chunk != 0) --current_chunk; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_HOME: current_chunk = 0; break; case KEY_END: while (chunk_info[current_chunk + 1]) ++current_chunk; break; case KEY_F(1): case '?': systemDisplayHelp("slice"); clear(); break; case 'A': #ifdef __alpha__ rv = 1; #else /* The rest is only relevant on x86 */ cp = variable_get(VAR_DEDICATE_DISK); if (cp && !strcasecmp(cp, "always")) rv = 1; else { rv = msgYesNo("Do you want to do this with a true partition entry\n" "so as to remain cooperative with any future possible\n" "operating systems on the drive(s)?\n" "(See also the section about ``dangerously dedicated''\n" "disks in the FreeBSD FAQ.)"); if (rv == -1) rv = 0; } #endif All_FreeBSD(d, rv); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); clear(); break; case 'C': if (chunk_info[current_chunk]->type != unused) msg = "Slice in use, delete it first or move to an unused one."; else { char *val, tmp[20], *cp; int size; #ifdef PC98 char name[16]; snprintf(name, 16, "%s", "FreeBSD"); val = msgGetInput(name, "Please specify the name for new FreeBSD slice."); if (val) strncpy(name, val, 16); #else int subtype; chunk_e partitiontype; #endif snprintf(tmp, 20, "%lu", chunk_info[current_chunk]->size); val = msgGetInput(tmp, "Please specify the size for new FreeBSD slice in blocks\n" "or append a trailing `M' for megabytes (e.g. 20M)."); if (val && (size = strtol(val, &cp, 0)) > 0) { if (*cp && toupper(*cp) == 'M') size *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') size *= ONE_GIG; #ifdef PC98 Create_Chunk(d, chunk_info[current_chunk]->offset, size, freebsd, 3, (chunk_info[current_chunk]->flags & CHUNK_ALIGN), name); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); #else sprintf(tmp, "%d", SUBTYPE_FREEBSD); val = msgGetInput(tmp, "Enter type of partition to create:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 165). You can choose other types, 6 for a\n" "DOS partition or 131 for a Linux partition, for example.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS FORMAT, to later format\n" "and use the partition."); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else partitiontype = unknown; #ifdef __alpha__ if (partitiontype == freebsd && size == chunk_info[current_chunk]->size) All_FreeBSD(d, 1); else #endif Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } #endif /* PC98 */ } clear(); } break; case KEY_DC: case 'D': if (chunk_info[current_chunk]->type == unused) msg = "Slice is already unused!"; else { Delete_Chunk(d, chunk_info[current_chunk]); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } break; case 'T': if (chunk_info[current_chunk]->type == unused) msg = "Slice is currently unused (use create instead)"; else { char *val, tmp[20]; int subtype; chunk_e partitiontype; sprintf(tmp, "%d", SUBTYPE_FREEBSD); #ifdef PC98 val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 50324). Other popular values are 37218 for\n" "DOS FAT partition.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS format, to later format\n" "and actually use the partition."); #else val = msgGetInput(tmp, "New partition type:\n\n" "Pressing Enter will choose the default, a native FreeBSD\n" "slice (type 165). Other popular values are 6 for\n" "DOS FAT partition, 131 for a Linux ext2fs partition or\n" "130 for a Linux swap partition.\n\n" "Note: If you choose a non-FreeBSD partition type, it will not\n" "be formatted or otherwise prepared, it will simply reserve space\n" "for you to use another tool, such as DOS format, to later format\n" "and actually use the partition."); #endif /* PC98 */ if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == SUBTYPE_FREEBSD) partitiontype = freebsd; else if (subtype == SUBTYPE_FAT) partitiontype = fat; else partitiontype = unknown; chunk_info[current_chunk]->type = partitiontype; chunk_info[current_chunk]->subtype = subtype; } } break; case 'G': snprintf(geometry, 80, "%lu/%lu/%lu", d->bios_cyl, d->bios_hd, d->bios_sect); val = msgGetInput(geometry, "Please specify the new geometry in cyl/hd/sect format.\n" "Don't forget to use the two slash (/) separator characters!\n" "It's not possible to parse the field without them."); if (val) { long nc, nh, ns; nc = strtol(val, &val, 0); nh = strtol(val + 1, &val, 0); ns = strtol(val + 1, 0, 0); Set_Bios_Geom(d, nc, nh, ns); } clear(); break; case 'S': /* Set Bootable */ chunk_info[current_chunk]->flags |= CHUNK_ACTIVE; break; case 'U': if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written this information out - you\n" "can't undo it."); } - else if (!msgYesNo("Are you SURE you want to Undo everything?")) { + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { char cp[BUFSIZ]; sstrncpy(cp, d->name, sizeof cp); Free_Disk(dev->private); d = Open_Disk(cp); if (!d) msgConfirm("Can't reopen disk %s! Internal state is probably corrupted", cp); dev->private = d; variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); if (d) record_chunks(d); } clear(); break; case 'W': - if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" + if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions. If you're adding a disk, you should NOT write\n" "from this screen, you should do it from the label editor.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_PARTITIONED, "yes", 0); /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has * requested booteasy or a "standard" MBR -- both would be * fatal in this case. */ /* * Don't offer to update the MBR on this disk if the first * "real" chunk looks like a FreeBSD "all disk" partition, * or the disk is entirely FreeBSD. */ #ifdef PC98 if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); else { bootipl = NULL; bootipl_size = 0; bootmenu = NULL; bootmenu_size = 0; } Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) getBootMgr(d->name, &mbrContents, &mbrSize); else { mbrContents = NULL; mbrSize = 0; } Set_Boot_Mgr(d, mbrContents, mbrSize); #endif if (DITEM_STATUS(diskPartitionWrite(NULL)) != DITEM_SUCCESS) msgConfirm("Disk partition write returned an error status!"); else msgConfirm("Wrote FDISK partition information out successfully."); } clear(); break; case '|': - if (!msgYesNo("Are you SURE you want to go into Wizard mode?\n" + if (!msgNoYes("Are you SURE you want to go into Wizard mode?\n" "No seat belts whatsoever are provided!")) { clear(); refresh(); slice_wizard(d); variable_set2(DISK_PARTITIONED, "yes", 0); record_chunks(d); } else msg = "Wise choice!"; clear(); break; case '\033': /* ESC */ case 'Q': chunking = FALSE; /* * Don't trash the MBR if the first (and therefore only) chunk * is marked for a truly dedicated disk (i.e., the disklabel * starts at sector 0), even in cases where the user has requested * booteasy or a "standard" MBR -- both would be fatal in this case. */ #if 0 if ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } #else /* * Don't offer to update the MBR on this disk if the first "real" * chunk looks like a FreeBSD "all disk" partition, or the disk is * entirely FreeBSD. */ if ((d->chunks->part->type != freebsd) || (d->chunks->part->offset > 1)) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); if (bootipl != NULL && bootmenu != NULL) Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); if (mbrContents != NULL) Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } #endif break; case 'Z': size_unit = (size_unit + 1) % UNIT_SIZE; break; default: beep(); msg = "Type F1 or ? for help"; break; } } p = CheckRules(d); if (p) { char buf[FILENAME_MAX]; use_helpline("Press F1 to read more about disk slices."); use_helpfile(systemHelpFile("partition", buf)); if (!variable_get(VAR_NO_WARN)) dialog_mesgbox("Disk slicing warning:", p, -1, -1); free(p); } restorescr(w); } static u_char * bootalloc(char *name) { char buf[FILENAME_MAX]; struct stat sb; snprintf(buf, sizeof buf, "/boot/%s", name); if (stat(buf, &sb) != -1) { int fd; fd = open(buf, O_RDONLY); if (fd != -1) { u_char *cp; cp = malloc(sb.st_size); if (read(fd, cp, sb.st_size) != sb.st_size) { free(cp); close(fd); msgDebug("bootalloc: couldn't read %d bytes from %s\n", sb.st_size, buf); return NULL; } close(fd); return cp; } msgDebug("bootalloc: couldn't open %s\n", buf); } else msgDebug("bootalloc: can't stat %s\n", buf); return NULL; } static int partitionHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskPartition(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int partitionCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskPartitionEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt, devcnt; cnt = diskGetSelectCount(&devs); devcnt = deviceCount(devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ for (i = 0; i < devcnt; i++) { if (devs[i]->enabled) { if (variable_get(VAR_NONINTERACTIVE)) diskPartitionNonInteractive(devs[i]); else diskPartition(devs[i]); } } } else { /* No disks are selected, fall-back case now */ if (devcnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE)) diskPartitionNonInteractive(devs[0]); else diskPartition(devs[0]); return DITEM_SUCCESS; } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, partitionHook, partitionCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); return DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } return i; } } return DITEM_SUCCESS; } int diskPartitionWrite(dialogMenuItem *self) { Device **devs; int i; char *cp; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find any disks to write to??"); return DITEM_FAILURE; } if (isDebug()) msgDebug("diskPartitionWrite: Examining %d devices\n", deviceCount(devs)); cp = variable_get(DISK_PARTITIONED); if (cp && !strcmp(cp, "written")) return DITEM_SUCCESS; for (i = 0; devs[i]; i++) { Disk *d = (Disk *)devs[i]->private; static u_char *boot1; #ifndef __alpha__ static u_char *boot2; #endif if (!devs[i]->enabled) continue; #ifdef __alpha__ if (!boot1) boot1 = bootalloc("boot1"); Set_Boot_Blocks(d, boot1, NULL); #else if (!boot1) boot1 = bootalloc("boot1"); if (!boot2) boot2 = bootalloc("boot2"); Set_Boot_Blocks(d, boot1, boot2); #endif msgNotify("Writing partition information to drive %s", d->name); if (!Fake && Write_Disk(d)) { msgConfirm("ERROR: Unable to write data to disk %s!", d->name); return DITEM_FAILURE; } /* If we've been through here before, we don't need to do the rest */ if (cp && !strcmp(cp, "written")) return DITEM_SUCCESS; } /* Now it's not "yes", but "written" */ variable_set2(DISK_PARTITIONED, "written", 0); return DITEM_SUCCESS | DITEM_RESTORE; } /* Partition a disk based wholly on which variables are set */ static void diskPartitionNonInteractive(Device *dev) { char *cp; int i, sz, all_disk = 0; #ifdef PC98 u_char *bootipl; size_t bootipl_size; u_char *bootmenu; size_t bootmenu_size; #else u_char *mbrContents; size_t mbrSize; #endif Disk *d = (Disk *)dev->private; record_chunks(d); cp = variable_get(VAR_GEOMETRY); if (cp) { msgDebug("Setting geometry from script to: %s\n", cp); d->bios_cyl = strtol(cp, &cp, 0); d->bios_hd = strtol(cp + 1, &cp, 0); d->bios_sect = strtol(cp + 1, 0, 0); } cp = variable_get(VAR_PARTITION); if (cp) { if (!strcmp(cp, "free")) { /* Do free disk space case */ for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least 10MB in size, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size > (10 * ONE_MEG)) { #ifdef PC98 Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); #else Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); #endif variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find any free space on this disk!"); return; } } else if (!strcmp(cp, "all")) { /* Do all disk space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, FALSE); } else if (!strcmp(cp, "exclusive")) { /* Do really-all-the-disk-space case */ msgDebug("Warning: Devoting all of disk %s to FreeBSD.\n", d->name); All_FreeBSD(d, all_disk = TRUE); } else if ((sz = strtol(cp, &cp, 0))) { /* Look for sz bytes free */ if (*cp && toupper(*cp) == 'M') sz *= ONE_MEG; else if (*cp && toupper(*cp) == 'G') sz *= ONE_GIG; for (i = 0; chunk_info[i]; i++) { /* If a chunk is at least sz MB, use it. */ if (chunk_info[i]->type == unused && chunk_info[i]->size >= sz) { #ifdef PC98 Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN), "FreeBSD"); #else Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); #endif variable_set2(DISK_PARTITIONED, "yes", 0); break; } } if (!chunk_info[i]) { msgConfirm("Unable to find %d free blocks on this disk!", sz); return; } } else if (!strcmp(cp, "existing")) { /* Do existing FreeBSD case */ for (i = 0; chunk_info[i]; i++) { if (chunk_info[i]->type == freebsd) break; } if (!chunk_info[i]) { msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); return; } } else { msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); return; } if (!all_disk) { #ifdef PC98 getBootMgr(d->name, &bootipl, &bootipl_size, &bootmenu, &bootmenu_size); Set_Boot_Mgr(d, bootipl, bootipl_size, bootmenu, bootmenu_size); #else getBootMgr(d->name, &mbrContents, &mbrSize); Set_Boot_Mgr(d, mbrContents, mbrSize); #endif } variable_set2(DISK_PARTITIONED, "yes", 0); } } Index: head/usr.sbin/sysinstall/index.c =================================================================== --- head/usr.sbin/sysinstall/index.c (revision 70004) +++ head/usr.sbin/sysinstall/index.c (revision 70005) @@ -1,763 +1,763 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include "sysinstall.h" /* Macros and magic values */ #define MAX_MENU 12 #define _MAX_DESC 55 /* A structure holding the root, top and plist pointer at once */ struct ListPtrs { PkgNodePtr root; /* root of tree */ PkgNodePtr top; /* part of tree we handle */ PkgNodePtr plist; /* list of selected packages */ }; typedef struct ListPtrs* ListPtrsPtr; static void index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie); /* Shared between index_initialize() and the various clients of it */ PkgNode Top, Plist; /* Smarter strdup */ inline char * _strdup(char *ptr) { return ptr ? strdup(ptr) : NULL; } static char *descrs[] = { "Package Selection", "To mark a package, move to it and press SPACE. If the package is\n" "already marked, it will be unmarked or deleted (if installed).\n" "Items marked with a `D' are dependencies which will be auto-loaded.\n" "To search for a package by name, press ESC. To select a category,\n" "press RETURN. NOTE: The All category selection creates a very large\n" "submenu! If you select it, please be patient while it comes up.", "Package Targets", "These are the packages you've selected for extraction.\n\n" "If you're sure of these choices, select OK.\n" "If not, select Cancel to go back to the package selection menu.\n", "All", "All available packages in all categories.", "afterstep", "Ports to support the AfterStep window manager.", "applications", "User application software.", "archivers", "Utilities for archiving and unarchiving data.", "astro", "Applications related to astronomy.", "audio", "Audio utilities - most require a supported sound card.", "benchmarks", "Utilities for measuring system performance.", "biology", "Software related to biology.", "cad", "Computer Aided Design utilities.", "chinese", "Ported software for the Chinese market.", "comms", "Communications utilities.", "converters", "Format conversion utilities.", "databases", "Database software.", "deskutils", "Various Desktop utilities.", "devel", "Software development utilities and libraries.", "documentation", "Document preparation utilities.", "editors", "Common text editors.", "elisp", "Things related to Emacs Lisp.", "emulators", "Utilities for emulating other OS types.", "french", "Ported software for French countries.", "ftp", "FTP client and server utilities.", "games", "Various and sundry amusements.", "german", "Ported software for Germanic countries.", "gnome", "Components of the Gnome Desktop environment.", "graphics", "Graphics libraries and utilities.", "ipv6", "IPv6 related software.", "hebrew", "Ported software for Hebrew language.", "irc", "Internet Relay Chat utilities.", "japanese", "Ported software for the Japanese market.", "java", "Java language support.", "kde", "Software for the K Desktop Environment.", "korean", "Ported software for the Korean market.", "lang", "Computer languages.", "languages", "Computer languages.", "libraries", "Software development libraries.", "linux", "Linux programs that can be run under binary compatibility.", "mail", "Electronic mail packages and utilities.", "math", "Mathematical computation software.", "mbone", "Applications and utilities for the MBONE.", "misc", "Miscellaneous utilities.", "net", "Networking utilities.", "news", "USENET News support software.", "numeric", "Mathematical computation software.", "offix", "An office automation suite of sorts.", "orphans", "Packages without a home elsewhere.", "palm", "Software support for the 3Com Palm Pilot(tm) series.", "perl5", "Utilities/modules for the PERL5 language.", "pilot", "Software support for the 3Com Palm Pilot(tm) series.", "plan9", "Software from the Plan9 operating system.", "print", "Utilities for dealing with printing.", "printing", "Utilities for dealing with printing.", "programming", "Software development utilities and libraries.", "python", "Software related to the Python language.", "ruby", "Software related to the Ruby language.", "russian", "Ported software for the Russian market.", "security", "System security software.", "shells", "Various shells (tcsh, bash, etc).", "sysutils", "Various system utilities.", "tcl75", "TCL v7.5 and packages that depend on it.", "tcl76", "TCL v7.6 and packages that depend on it.", "tcl80", "TCL v8.0 and packages that depend on it.", "tcl82", "TCL v8.2 and packages that depend on it.", "tcl83", "TCL v8.3 and packages that depend on it.", "textproc", "Text processing/search utilities.", "tk41", "Tk4.1 and packages that depend on it.", "tk42", "Tk4.2 and packages that depend on it.", "tk80", "Tk8.0 and packages that depend on it.", "tk81", "Tk8.1 and packages that depend on it.", "tk82", "Tk8.2 and packages that depend on it.", "tk83", "Tk8.3 and packages that depend on it.", "tkstep80", "tkstep wm and packages that depend on it.", "troff", "TROFF text formatting utilities.", "vietnamese", "Ported software for the Vietnamese market.", "windowmaker", "Ports to support the WindowMaker window manager.", "www", "WEB utilities (browers, HTTP servers, etc).", "x11", "X Window System based utilities.", "x11-clocks", "X Window System based clocks.", "x11-fm", "X Window System based file managers.", "x11-fonts", "X Window System fonts and font utilities.", "x11-servers", "X Window System servers.", "x11-toolkits", "X Window System based development toolkits.", "x11-wm", "X Window System window managers.", "zope", "Software related to the Zope platform.", NULL, NULL, }; static char * fetch_desc(char *name) { int i; for (i = 0; descrs[i]; i += 2) { if (!strcmp(descrs[i], name)) return descrs[i + 1]; } return "No description provided"; } static PkgNodePtr new_pkg_node(char *name, node_type type) { PkgNodePtr tmp = safe_malloc(sizeof(PkgNode)); tmp->name = _strdup(name); tmp->type = type; return tmp; } static char * strip(char *buf) { int i; for (i = 0; buf[i]; i++) if (buf[i] == '\t' || buf[i] == '\n') buf[i] = ' '; return buf; } static IndexEntryPtr new_index(char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *deps) { IndexEntryPtr tmp = safe_malloc(sizeof(IndexEntry)); tmp->name = _strdup(name); tmp->path = _strdup(pathto); tmp->prefix = _strdup(prefix); tmp->comment = _strdup(comment); tmp->descrfile = strip(_strdup(descr)); tmp->maintainer = _strdup(maint); tmp->deps = _strdup(deps); tmp->depc = 0; tmp->installed = package_exists(name); return tmp; } static void index_register(PkgNodePtr top, char *where, IndexEntryPtr ptr) { PkgNodePtr p, q; for (q = NULL, p = top->kids; p; p = p->next) { if (!strcmp(p->name, where)) { q = p; break; } } if (!p) { /* Add new category */ q = new_pkg_node(where, PLACE); q->desc = fetch_desc(where); q->next = top->kids; top->kids = q; } p = new_pkg_node(ptr->name, PACKAGE); p->desc = ptr->comment; p->data = ptr; p->next = q->kids; q->kids = p; } static int copy_to_sep(char *to, char *from, int sep) { char *tok; tok = strchr(from, sep); if (!tok) { *to = '\0'; return 0; } *tok = '\0'; strcpy(to, from); return tok + 1 - from; } static int readline(FILE *fp, char *buf, int max) { int rv, i = 0; char ch; while ((rv = fread(&ch, 1, 1, fp)) == 1 && ch != '\n' && i < max) buf[i++] = ch; if (i < max) buf[i] = '\0'; return rv; } int index_parse(FILE *fp, char *name, char *pathto, char *prefix, char *comment, char *descr, char *maint, char *cats, char *rdeps) { char line[2048]; char junk[511]; char *cp; int i; i = readline(fp, line, sizeof line); if (i <= 0) return EOF; cp = line; cp += copy_to_sep(name, cp, '|'); cp += copy_to_sep(pathto, cp, '|'); cp += copy_to_sep(prefix, cp, '|'); cp += copy_to_sep(comment, cp, '|'); cp += copy_to_sep(descr, cp, '|'); cp += copy_to_sep(maint, cp, '|'); cp += copy_to_sep(cats, cp, '|'); cp += copy_to_sep(junk, cp, '|'); /* build deps - not used */ if (index(cp, '|')) copy_to_sep(rdeps, cp, '|'); else strncpy(rdeps, cp, 1023); return 0; } int index_read(FILE *fp, PkgNodePtr papa) { char name[127], pathto[255], prefix[255], comment[255], descr[127], maint[127], cats[511], deps[1024]; PkgNodePtr i; while (index_parse(fp, name, pathto, prefix, comment, descr, maint, cats, deps) != EOF) { char *cp, *cp2, tmp[1024]; IndexEntryPtr idx; idx = new_index(name, pathto, prefix, comment, descr, maint, deps); /* For now, we only add things to menus if they're in categories. Keywords are ignored */ for (cp = strcpy(tmp, cats); (cp2 = strchr(cp, ' ')) != NULL; cp = cp2 + 1) { *cp2 = '\0'; index_register(papa, cp, idx); } index_register(papa, cp, idx); /* Add to special "All" category */ index_register(papa, "All", idx); } /* Adjust dependency counts */ for (i = papa->kids; i != NULL; i = i->next) if (strcmp(i->name, "All") == 0) break; for (i = i->kids; i != NULL; i = i->next) if (((IndexEntryPtr)i->data)->installed) index_recorddeps(TRUE, papa, i->data); return 0; } void index_init(PkgNodePtr top, PkgNodePtr plist) { if (top) { top->next = top->kids = NULL; top->name = "Package Selection"; top->type = PLACE; top->desc = fetch_desc(top->name); top->data = NULL; } if (plist) { plist->next = plist->kids = NULL; plist->name = "Package Targets"; plist->type = PLACE; plist->desc = fetch_desc(plist->name); plist->data = NULL; } } void index_print(PkgNodePtr top, int level) { int i; while (top) { for (i = 0; i < level; i++) putchar('\t'); printf("name [%s]: %s\n", top->type == PLACE ? "place" : "package", top->name); for (i = 0; i < level; i++) putchar('\t'); printf("desc: %s\n", top->desc); if (top->kids) index_print(top->kids, level + 1); top = top->next; } } /* Swap one node for another */ static void swap_nodes(PkgNodePtr a, PkgNodePtr b) { PkgNode tmp; tmp = *a; *a = *b; a->next = tmp.next; tmp.next = b->next; *b = tmp; } /* Use a disgustingly simplistic bubble sort to put our lists in order */ void index_sort(PkgNodePtr top) { PkgNodePtr p, q; /* Sort everything at the top level */ for (p = top->kids; p; p = p->next) { for (q = top->kids; q; q = q->next) { if (q->next && strcmp(q->name, q->next->name) > 0) swap_nodes(q, q->next); } } /* Now sub-sort everything n levels down */ for (p = top->kids; p; p = p->next) { if (p->kids) index_sort(p); } } /* Delete an entry out of the list it's in (only the plist, at present) */ void index_delete(PkgNodePtr n) { if (n->next) { PkgNodePtr p = n->next; *n = *(n->next); safe_free(p); } else /* Kludgy end sentinal */ n->name = NULL; } /* * Search for a given node by name, returning the category in if * tp is non-NULL. */ PkgNodePtr index_search(PkgNodePtr top, char *str, PkgNodePtr *tp) { PkgNodePtr p, sp; for (p = top->kids; p && p->name; p = p->next) { if (p->type == PACKAGE) { /* If tp == NULL, we're looking for an exact package match */ if (!tp && !strcmp(p->name, str)) return p; /* If tp, we're looking for both a package and a pointer to the place it's in */ if (tp && !strncmp(p->name, str, strlen(str))) { *tp = top; return p; } } else if (p->kids) { /* The usual recursion-out-of-laziness ploy */ if ((sp = index_search(p, str, tp)) != NULL) return sp; } } if (p && !p->name) p = NULL; return p; } int pkg_checked(dialogMenuItem *self) { ListPtrsPtr lists = (ListPtrsPtr)self->aux; PkgNodePtr kp = self->data, plist = lists->plist; int i; i = index_search(plist, kp->name, NULL) ? TRUE : FALSE; if (kp->type == PACKAGE && plist) { IndexEntryPtr ie = kp->data; int markD, markX; markD = ie->depc > 0; /* needed as dependency */ markX = i || ie->installed; /* selected or installed */ self->mark = markX ? 'X' : 'D'; return markD || markX; } else return FALSE; } int pkg_fire(dialogMenuItem *self) { int ret; ListPtrsPtr lists = (ListPtrsPtr)self->aux; PkgNodePtr sp, kp = self->data, plist = lists->plist; if (!plist) ret = DITEM_FAILURE; else if (kp->type == PACKAGE) { IndexEntryPtr ie = kp->data; sp = index_search(plist, kp->name, NULL); /* Not already selected? */ if (!sp) { if (!ie->installed) { PkgNodePtr np = (PkgNodePtr)safe_malloc(sizeof(PkgNode)); *np = *kp; np->next = plist->kids; plist->kids = np; index_recorddeps(TRUE, lists->root, ie); msgInfo("Added %s to selection list", kp->name); } else if (ie->depc == 0) { - if (!msgYesNo("Do you really want to delete %s from the system?", kp->name)) { + if (!msgNoYes("Do you really want to delete %s from the system?", kp->name)) { if (vsystem("pkg_delete %s %s", isDebug() ? "-v" : "", kp->name)) { msgConfirm("Warning: pkg_delete of %s failed.\n Check debug output for details.", kp->name); } else { ie->installed = 0; index_recorddeps(FALSE, lists->root, ie); } } } else msgConfirm("Warning: Package %s is needed by\n %d other installed package%s.", kp->name, ie->depc, (ie->depc != 1) ? "s" : ""); } else { index_recorddeps(FALSE, lists->root, ie); msgInfo("Removed %s from selection list", kp->name); index_delete(sp); } ret = DITEM_SUCCESS; /* Mark menu for redraw if we had dependencies */ if (strlen(ie->deps) > 0) ret |= DITEM_REDRAW; } else { /* Not a package, must be a directory */ int p, s; p = s = 0; index_menu(lists->root, kp, plist, &p, &s); ret = DITEM_SUCCESS | DITEM_CONTINUE; } return ret; } void pkg_selected(dialogMenuItem *self, int is_selected) { PkgNodePtr kp = self->data; if (!is_selected || kp->type != PACKAGE) return; msgInfo(kp->desc); } int index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll) { struct ListPtrs lists; int n, rval, maxname; int curr, max; PkgNodePtr kp; dialogMenuItem *nitems; Boolean hasPackages; WINDOW *w; lists.root = root; lists.top = top; lists.plist = plist; hasPackages = FALSE; nitems = NULL; n = maxname = 0; /* Figure out if this menu is full of "leaves" or "branches" */ for (kp = top->kids; kp && kp->name; kp = kp->next) { int len; ++n; if (kp->type == PACKAGE && plist) { hasPackages = TRUE; if ((len = strlen(kp->name)) > maxname) maxname = len; } } if (!n && plist) { msgConfirm("The %s menu is empty.", top->name); return DITEM_LEAVE_MENU; } w = savescr(); while (1) { n = 0; curr = max = 0; use_helpline(NULL); use_helpfile(NULL); kp = top->kids; if (!hasPackages && plist) { nitems = item_add(nitems, "OK", NULL, NULL, NULL, NULL, NULL, 0, &curr, &max); nitems = item_add(nitems, "Install", NULL, NULL, NULL, NULL, NULL, 0, &curr, &max); } while (kp && kp->name) { char buf[256]; IndexEntryPtr ie = kp->data; /* Brutally adjust description to fit in menu */ if (kp->type == PACKAGE) snprintf(buf, sizeof buf, "[%s]", ie->path ? ie->path : "External vendor"); else SAFE_STRCPY(buf, kp->desc); if (strlen(buf) > (_MAX_DESC - maxname)) buf[_MAX_DESC - maxname] = '\0'; nitems = item_add(nitems, kp->name, buf, pkg_checked, pkg_fire, pkg_selected, kp, (int)&lists, &curr, &max); ++n; kp = kp->next; } /* NULL delimiter so item_free() knows when to stop later */ nitems = item_add(nitems, NULL, NULL, NULL, NULL, NULL, NULL, 0, &curr, &max); recycle: dialog_clear_norefresh(); if (hasPackages) rval = dialog_checklist(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems, NULL); else rval = dialog_menu(top->name, top->desc, -1, -1, n > MAX_MENU ? MAX_MENU : n, -n, nitems + (plist ? 2 : 0), (char *)plist, pos, scroll); if (rval == -1 && plist) { static char *cp; PkgNodePtr menu; /* Search */ if ((cp = msgGetInput(cp, "Search by package name. Please enter search string:")) != NULL) { PkgNodePtr p = index_search(top, cp, &menu); if (p) { int pos, scroll; /* These need to be set to point at the found item, actually. Hmmm! */ pos = scroll = 0; index_menu(root, menu, plist, &pos, &scroll); } else msgConfirm("Search string: %s yielded no hits.", cp); } goto recycle; } items_free(nitems, &curr, &max); restorescr(w); return rval ? DITEM_FAILURE : DITEM_SUCCESS; } } int index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended) { int status = DITEM_SUCCESS; PkgNodePtr tmp2; IndexEntryPtr id = who->data; WINDOW *w = savescr(); if (id && id->deps && strlen(id->deps)) { char t[1024], *cp, *cp2; SAFE_STRCPY(t, id->deps); cp = t; while (cp && DITEM_STATUS(status) == DITEM_SUCCESS) { if ((cp2 = index(cp, ' ')) != NULL) *cp2 = '\0'; if ((tmp2 = index_search(top, cp, NULL)) != NULL) { status = index_extract(dev, top, tmp2, TRUE); if (DITEM_STATUS(status) != DITEM_SUCCESS) { if (variable_get(VAR_NO_CONFIRM)) msgNotify("Loading of dependant package %s failed", cp); else msgConfirm("Loading of dependant package %s failed", cp); } } else if (!package_exists(cp)) { if (variable_get(VAR_NO_CONFIRM)) msgNotify("Warning: %s is a required package but was not found.", cp); else msgConfirm("Warning: %s is a required package but was not found.", cp); } if (cp2) cp = cp2 + 1; else cp = NULL; } } /* Done with the deps? Load the real m'coy */ if (DITEM_STATUS(status) == DITEM_SUCCESS) { status = package_extract(dev, who->name, depended); if (DITEM_STATUS(status) == DITEM_SUCCESS) id->installed = 1; } restorescr(w); return status; } static void index_recorddeps(Boolean add, PkgNodePtr root, IndexEntryPtr ie) { char depends[1024], *space, *todo; PkgNodePtr found; IndexEntryPtr found_ie; SAFE_STRCPY(depends, ie->deps); for (todo = depends; todo != NULL; ) { space = index(todo, ' '); if (space != NULL) *space = '\0'; if (strlen(todo) > 0) { /* only non-empty dependencies */ found = index_search(root, todo, NULL); if (found != NULL) { found_ie = found->data; if (add) ++found_ie->depc; else --found_ie->depc; } } if (space != NULL) todo = space + 1; else todo = NULL; } } static Boolean index_initted; /* Read and initialize global index */ int index_initialize(char *path) { FILE *fp; WINDOW *w = NULL; if (!index_initted) { w = savescr(); dialog_clear_norefresh(); /* Got any media? */ if (!mediaVerify()) { restorescr(w); return DITEM_FAILURE; } /* Does it move when you kick it? */ if (!mediaDevice->init(mediaDevice)) { restorescr(w); return DITEM_FAILURE; } dialog_clear_norefresh(); msgNotify("Attempting to fetch %s file from selected media.", path); fp = mediaDevice->get(mediaDevice, path, TRUE); if (!fp) { msgConfirm("Unable to get packages/INDEX file from selected media.\n" "This may be because the packages collection is not available at\n" "on the distribution media you've chosen (most likely an FTP site\n" "without the packages collection mirrored). Please verify media\n" "(or path to media) and try again. If your local site does not\n" "carry the packages collection, then we recommend either a CD\n" "distribution or the master distribution on ftp.freebsd.org."); mediaDevice->shutdown(mediaDevice); restorescr(w); return DITEM_FAILURE; } dialog_clear_norefresh(); msgNotify("Located INDEX, now reading package data from it..."); index_init(&Top, &Plist); if (index_read(fp, &Top)) { msgConfirm("I/O or format error on packages/INDEX file.\n" "Please verify media (or path to media) and try again."); fclose(fp); restorescr(w); return DITEM_FAILURE; } fclose(fp); index_sort(&Top); index_initted = TRUE; restorescr(w); } return DITEM_SUCCESS; } Index: head/usr.sbin/sysinstall/install.c =================================================================== --- head/usr.sbin/sysinstall/install.c (revision 70004) +++ head/usr.sbin/sysinstall/install.c (revision 70005) @@ -1,1130 +1,1128 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include #include #include #include #define MSDOSFS #include #include #include #undef MSDOSFS #include #include #include #include /* Hack for rsaref package add, which displays interactive license. * Used by package.c */ int _interactiveHack; int FixItMode = 0; static void create_termcap(void); static void fixit_common(void); #define TERMCAP_FILE "/usr/share/misc/termcap" static void installConfigure(void); Boolean checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev) { Device **devs; Boolean status; Disk *disk; Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; int i; /* Don't allow whinging if noWarn is set */ if (variable_get(VAR_NO_WARN)) whinge = FALSE; status = TRUE; *rdev = *sdev = *udev = *vdev = rootdev = swapdev = usrdev = vardev = NULL; /* We don't need to worry about root/usr/swap if we're already multiuser */ if (!RunningAsInit) return status; devs = deviceFind(NULL, DEVICE_TYPE_DISK); /* First verify that we have a root device */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for root filesystem\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/")) { if (rootdev) { if (whinge) msgConfirm("WARNING: You have more than one root device set?!\n" "Using the first one found."); continue; } else { rootdev = c2; if (isDebug()) msgDebug("Found rootdev at %s!\n", rootdev->name); } } else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) { if (usrdev) { if (whinge) msgConfirm("WARNING: You have more than one /usr filesystem.\n" "Using the first one found."); continue; } else { usrdev = c2; if (isDebug()) msgDebug("Found usrdev at %s!\n", usrdev->name); } } else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/var")) { if (vardev) { if (whinge) msgConfirm("WARNING: You have more than one /var filesystem.\n" "Using the first one found."); continue; } else { vardev = c2; if (isDebug()) msgDebug("Found vardev at %s!\n", vardev->name); } } } } } } } /* Now check for swap devices */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; msgDebug("Scanning disk %s for swap partitions\n", disk->name); if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) { swapdev = c2; if (isDebug()) msgDebug("Found swapdev at %s!\n", swapdev->name); break; } } } } } /* Copy our values over */ *rdev = rootdev; *sdev = swapdev; *udev = usrdev; *vdev = vardev; if (!rootdev && whinge) { msgConfirm("No root device found - you must label a partition as /\n" "in the label editor."); status = FALSE; } if (!swapdev && whinge) { msgConfirm("No swap devices found - you must create at least one\n" "swap partition."); status = FALSE; } return status; } static int installInitial(void) { static Boolean alreadyDone = FALSE; int status = DITEM_SUCCESS; if (alreadyDone) return DITEM_SUCCESS; if (!variable_get(DISK_LABELLED)) { msgConfirm("You need to assign disk labels before you can proceed with\n" "the installation."); return DITEM_FAILURE; } /* If it's labelled, assume it's also partitioned */ if (!variable_get(DISK_PARTITIONED)) variable_set2(DISK_PARTITIONED, "yes", 0); /* If we refuse to proceed, bail. */ dialog_clear_norefresh(); if (!variable_get(VAR_NO_WARN)) if (msgYesNo( "Last Chance! Are you SURE you want continue the installation?\n\n" "If you're running this on a disk with data you wish to save\n" "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n" "proceeding!\n\n" "We can take no responsibility for lost disk contents!") != 0) return DITEM_FAILURE; if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { msgConfirm("Couldn't make filesystems properly. Aborting."); return DITEM_FAILURE; } if (!copySelf()) { msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n" "root file system. Aborting!"); return DITEM_FAILURE; } if (chroot("/mnt") == -1) { msgConfirm("installInitial: Unable to chroot to %s - this is bad!", "/mnt"); return DITEM_FAILURE; } chdir("/"); variable_set2(RUNNING_ON_ROOT, "yes", 0); /* Configure various files in /etc */ if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE) status = DITEM_FAILURE; /* stick a helpful shell over on the 4th VTY */ systemCreateHoloshell(); alreadyDone = TRUE; return status; } int installFixitHoloShell(dialogMenuItem *self) { FixItMode = 1; systemCreateHoloshell(); return DITEM_SUCCESS; FixItMode = 0; } int installFixitCDROM(dialogMenuItem *self) { struct stat sb; if (!RunningAsInit) return DITEM_SUCCESS; variable_set2(SYSTEM_STATE, "fixit", 0); (void)unlink("/mnt2"); (void)rmdir("/mnt2"); while (1) { msgConfirm("Please insert a FreeBSD live filesystem CDROM and press return"); if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) { /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */ mediaClose(); if (msgYesNo("Unable to mount the CDROM - do you want to try again?") != 0) return DITEM_FAILURE; } else break; } /* Since the fixit code expects everything to be in /mnt2, and the CDROM mounting stuff /dist, do * a little kludge dance here.. */ if (symlink("/dist", "/mnt2")) { msgConfirm("Unable to symlink /mnt2 to the CDROM mount point. Please report this\n" "unexpected failure to freebsd-bugs@FreeBSD.org."); return DITEM_FAILURE; } /* * If /tmp points to /mnt2/tmp from a previous fixit floppy session, it's * not very good for us if we point it to the CDROM now. Rather make it * a directory in the root MFS then. Experienced admins will still be * able to mount their disk's /tmp over this if they need. */ if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK) (void)unlink("/tmp"); Mkdir("/tmp"); /* * Since setuid binaries ignore LD_LIBRARY_PATH, we indeed need the * ld.so.hints file. Fortunately, it's fairly small (~ 3 KB). */ if (!file_readable("/var/run/ld.so.hints")) { Mkdir("/var/run"); if (vsystem("/mnt2/sbin/ldconfig -s /mnt2/usr/lib")) { msgConfirm("Warning: ldconfig could not create the ld.so hints file.\n" "Dynamic executables from the CDROM likely won't work."); } } /* Yet more iggly hardcoded pathnames. */ Mkdir("/usr/libexec"); if (!file_readable("/usr/libexec/ld.so") && file_readable("/mnt2/usr/libexec/ld.so")) { if (symlink("/mnt2/usr/libexec/ld.so", "/usr/libexec/ld.so")) msgDebug("Couldn't link to ld.so - not necessarily a problem for ELF\n"); } if (!file_readable("/usr/libexec/ld-elf.so.1")) { if (symlink("/mnt2/usr/libexec/ld-elf.so.1", "/usr/libexec/ld-elf.so.1")) { msgConfirm("Warning: could not create the symlink for ld-elf.so.1\n" "Dynamic executables from the CDROM likely won't work."); } } /* optional nicety */ if (!file_readable("/usr/bin/vi")) symlink("/mnt2/usr/bin/vi", "/usr/bin/vi"); fixit_common(); mediaClose(); msgConfirm("Please remove the FreeBSD fixit CDROM now."); return DITEM_SUCCESS; } int installFixitFloppy(dialogMenuItem *self) { struct ufs_args args; extern char *distWanted; if (!RunningAsInit) return DITEM_SUCCESS; /* Try to open the floppy drive */ if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) { msgConfirm("Unable to set media device to floppy."); mediaClose(); return DITEM_FAILURE; } memset(&args, 0, sizeof(args)); args.fspec = mediaDevice->devname; mediaDevice->private = "/mnt2"; distWanted = NULL; Mkdir("/mnt2"); variable_set2(SYSTEM_STATE, "fixit", 0); while (1) { if (!mediaDevice->init(mediaDevice)) { if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n" "or unclean filesystem. Do you want to try again?")) return DITEM_FAILURE; } else break; } if (!directory_exists("/tmp")) (void)symlink("/mnt2/tmp", "/tmp"); fixit_common(); mediaClose(); msgConfirm("Please remove the fixit floppy now."); return DITEM_SUCCESS; } /* * The common code for both fixit variants. */ static void fixit_common(void) { pid_t child; int waitstatus; if (!directory_exists("/var/tmp/vi.recover")) { if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) { msgConfirm("Warning: Was unable to create a /var/tmp/vi.recover directory.\n" "vi will kvetch and moan about it as a result but should still\n" "be essentially usable."); } } if (!directory_exists("/bin")) (void)Mkdir("/bin"); (void)symlink("/stand/sh", "/bin/sh"); /* Link the /etc/ files */ if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS) msgConfirm("Unable to create an /etc directory! Things are weird on this floppy.."); else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) || (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST)) msgConfirm("Couldn't symlink the /etc/ files! I'm not sure I like this.."); if (!file_readable(TERMCAP_FILE)) create_termcap(); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if (!(child = fork())) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("fixit: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(0, TCSANOW, &foo) == -1) msgDebug("fixit shell: Unable to set erase character.\n"); } else msgDebug("fixit shell: Unable to get terminal attributes!\n"); setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:" "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1); setenv("MAKEDEVPATH", "/sbin:/bin:/stand:" "/mnt2/sbin:/mnt2/bin:/mnt2/stand", 1); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Waiting for fixit shell to exit.\n" "When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here.\n\n"); fflush(stdout); } /* use the .profile from the fixit medium */ setenv("HOME", "/mnt2", 1); chdir("/mnt2"); execlp("sh", "-sh", 0); msgDebug("fixit shell: Failed to execute shell!\n"); _exit(1);; } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { dialog_clear_norefresh(); msgNotify("Waiting for fixit shell to exit. Go to VTY4 now by\n" "typing ALT-F4. When you are done, type ``exit'' to exit\n" "the fixit shell and be returned here\n."); } (void)waitpid(child, &waitstatus, 0); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemResumeDialog(); } dialog_clear(); } int installExpress(dialogMenuItem *self) { int i; dialog_clear_norefresh(); variable_set2(SYSTEM_STATE, "express", 0); #ifndef __alpha__ if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) return i; #endif if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) return i; if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { i |= DITEM_LEAVE_MENU; /* Set default security level */ configSecurityModerate(NULL); /* Give user the option of one last configuration spree */ installConfigure(); } return i; } /* Standard mode installation */ int installStandard(dialogMenuItem *self) { int i, tries = 0; Device **devs; variable_set2(SYSTEM_STATE, "standard", 0); dialog_clear_norefresh(); #ifndef __alpha__ msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n" "scheme for your hard disk. If you simply wish to devote all disk space\n" "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n" "then use the (A)ll command to select the default partitioning scheme followed\n" "by a (Q)uit. If you wish to allocate only free space to FreeBSD, move to a\n" "partition marked \"unused\" and use the (C)reate command."); nodisks: if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (diskGetSelectCount(&devs) <= 0 && tries < 3) { msgConfirm("You need to select some disks to operate on! Be sure to use SPACE\n" "instead of RETURN in the disk selection menu when selecting a disk."); ++tries; goto nodisks; } #endif #ifdef __alpha__ msgConfirm("Now you need to create BSD partitions on the disk which you are\n" "installing to. If you have a reasonable amount of disk space (200MB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #else msgConfirm("Now you need to create BSD partitions inside of the fdisk partition(s)\n" "just created. If you have a reasonable amount of disk space (200MB or more)\n" "and don't have any special requirements, simply use the (A)uto command to\n" "allocate space automatically. If you have more specific needs or just don't\n" "care for the layout chosen by (A)uto, press F1 for more information on\n" "manual layout."); #endif if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { dialog_clear(); msgConfirm("Installation completed with some errors. You may wish to\n" "scroll through the debugging messages on VTY1 with the\n" "scroll-lock feature. You can also choose \"No\" at the next\n" "prompt and go back into the installation menus to try and retry\n" "whichever operations have failed."); return i; } else { dialog_clear(); msgConfirm("Congratulations! You now have FreeBSD installed on your system.\n\n" "We will now move on to the final configuration questions.\n" "For any option you do not wish to configure, simply select\n" "No.\n\n" "If you wish to re-enter this utility after the system is up, you\n" "may do so by typing: /stand/sysinstall."); } if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) { if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) { Device *tmp = tcpDeviceSelect(); if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!tmp->init(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); } dialog_clear_norefresh(); } - if (msgYesNo("Will this machine be a leaf node (e.g. will not forward packets\n" - "between interfaces)?")) + if (!msgNoYes("Do you want this machine to function as a network gateway?")) variable_set2("gateway_enable", "YES", 1); dialog_clear_norefresh(); - if (msgYesNo("Do you want to grant only normal users FTP access to this\n" - "host (e.g. no anonymous FTP connections)?")) + if (!msgNoYes("Do you want to have anonymous FTP access to this machine?")) configAnonFTP(self); dialog_clear_norefresh(); - if (!msgYesNo("Do you want to configure this machine as an NFS server?")) + if (!msgNoYes("Do you want to configure this machine as an NFS server?")) configNFSServer(self); dialog_clear_norefresh(); - if (!msgYesNo("Do you want to configure this machine as an NFS client?")) + if (!msgNoYes("Do you want to configure this machine as an NFS client?")) variable_set2("nfs_client_enable", "YES", 1); - if (!msgYesNo("Do you want to select a default security profile for\n" + if (!msgNoYes("Do you want to select a default security profile for\n" "this host (select No for \"medium\" security)?")) configSecurityProfile(self); else configSecurityModerate(self); dialog_clear_norefresh(); - if (!msgYesNo("Would you like to customize your system console settings?")) + if (!msgNoYes("Would you like to customize your system console settings?")) dmenuOpenSimple(&MenuSyscons, FALSE); dialog_clear_norefresh(); if (!msgYesNo("Would you like to set this machine's time zone now?")) systemExecute("tzsetup"); #ifdef __i386__ dialog_clear_norefresh(); if (!msgYesNo("Would you like to enable Linux binary compatibility?")) (void)configLinux(self); #endif dialog_clear_norefresh(); - if (!msgYesNo("Does this system have a non-USB mouse attached to it?")) + if (!msgNoYes("Does this system have a USB mouse attached to it?")) dmenuOpenSimple(&MenuMouse, FALSE); /* Now would be a good time to checkpoint the configuration data */ configRC_conf(); sync(); if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); if (!msgYesNo("Would you like to configure your X server at this time?")) (void)configXSetup(self); } dialog_clear_norefresh(); if (!msgYesNo("The FreeBSD package collection is a collection of thousands of ready-to-run\n" "applications, from text editors to games to WEB servers and more. Would you\n" "like to browse the collection now?")) { (void)configPackages(self); } if (!msgYesNo("Would you like to add any initial user accounts to the system?\n" "Adding at least one account for yourself at this stage is suggested\n" "since working as the \"root\" user is dangerous (it is easy to do\n" "things which adversely affect the entire system).")) (void)configUsers(self); msgConfirm("Now you must set the system manager's password.\n" "This is the password you'll use to log in as \"root\"."); if (!systemExecute("passwd root")) variable_set2("root_password", "YES", 0); /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */ /* Give user the option of one last configuration spree */ dialog_clear_norefresh(); installConfigure(); return DITEM_LEAVE_MENU; } /* The version of commit we call from the Install Custom menu */ int installCustomCommit(dialogMenuItem *self) { int i; i = installCommit(self); if (DITEM_STATUS(i) == DITEM_SUCCESS) { /* Set default security level */ configSecurityModerate(NULL); /* Give user the option of one last configuration spree */ installConfigure(); return i; } else msgConfirm("The commit operation completed with errors. Not\n" "updating /etc files."); return i; } /* * What happens when we finally decide to going ahead with the installation. * * This is broken into multiple stages so that the user can do a full * installation but come back here again to load more distributions, * perhaps from a different media type. This would allow, for * example, the user to load the majority of the system from CDROM and * then use ftp to load just the CRYPTO dist. */ int installCommit(dialogMenuItem *self) { int i; char *str; dialog_clear_norefresh(); if (!Dists) distConfig(NULL); if (!Dists) { (void)dmenuOpenSimple(&MenuDistributions, FALSE); /* select reasonable defaults if necessary */ if (!Dists) Dists = _DIST_USER; } if (!mediaVerify()) return DITEM_FAILURE; str = variable_get(SYSTEM_STATE); if (isDebug()) msgDebug("installCommit: System state is `%s'\n", str); /* Installation stuff we wouldn't do to a running system */ if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) return i; try_media: if (!mediaDevice->init(mediaDevice)) { if (!msgYesNo("Unable to initialize selected media. Would you like to\n" "adjust your media configuration and try again?")) { mediaDevice = NULL; if (!mediaVerify()) return DITEM_FAILURE; else goto try_media; } else return DITEM_FAILURE; } /* Now go get it all */ i = distExtractAll(self); /* When running as init, *now* it's safe to grab the rc.foo vars */ installEnvironment(); variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0); return i; } static void installConfigure(void) { /* Final menu of last resort */ - if (!msgYesNo("Visit the general configuration menu for a chance to set\n" + if (!msgNoYes("Visit the general configuration menu for a chance to set\n" "any last options?")) dmenuOpenSimple(&MenuConfigure, FALSE); configRC_conf(); sync(); } int installFixupBin(dialogMenuItem *self) { Device **devs; char *cp; int i; FILE *fp; int kstat = 1; /* All of this is done only as init, just to be safe */ if (RunningAsInit) { #ifdef __i386__ /* Snapshot any boot -c changes back to the new kernel */ cp = variable_get(VAR_KGET); if (cp && (*cp == 'Y' || *cp == 'y')) { if ((kstat = kget("/boot/kernel.conf")) != NULL) { msgConfirm("Unable to save boot -c changes to new kernel,\n" "please see the debug screen (ALT-F2) for details."); } } if ((fp = fopen("/boot/loader.conf", "a")) != NULL) { if (!kstat || !OnVTY) fprintf(fp, "# -- sysinstall generated deltas -- #\n"); if (!kstat) fprintf(fp, "userconfig_script_load=\"YES\"\n"); if (!OnVTY) fprintf(fp, "console=\"comconsole\"\n"); fclose(fp); } #endif /* BOGON #1: Resurrect /dev after bin distribution screws it up */ dialog_clear_norefresh(); msgNotify("Remaking all devices.. Please wait!"); if (vsystem("cd /dev; sh MAKEDEV all")) { msgConfirm("MAKEDEV returned non-zero status"); return DITEM_FAILURE | DITEM_RESTORE; } dialog_clear_norefresh(); msgNotify("Resurrecting /dev entries for slices.."); devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) msgFatal("Couldn't get a disk device list!"); /* Resurrect the slices that the former clobbered */ for (i = 0; devs[i]; i++) { Disk *disk = (Disk *)devs[i]->private; Chunk *c1; if (!devs[i]->enabled) continue; if (!disk->chunks) msgFatal("No chunk list found for %s!", disk->name); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { dialog_clear_norefresh(); msgNotify("Making slice entries for %s", c1->name); if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) { msgConfirm("Unable to make slice entries for %s!", c1->name); return DITEM_FAILURE | DITEM_RESTORE; } } } } /* BOGON #2: We leave /etc in a bad state */ chmod("/etc", 0755); /* BOGON #3: No /var/db/mountdtab complains */ Mkdir("/var/db"); creat("/var/db/mountdtab", 0644); /* BOGON #4: /compat created by default in root fs */ Mkdir("/usr/compat"); vsystem("ln -s /usr/compat /compat"); /* BOGON #5: aliases database not build for bin */ vsystem("newaliases"); /* Now run all the mtree stuff to fix things up */ vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /"); vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var"); vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr"); /* Do all the last ugly work-arounds here */ } return DITEM_SUCCESS | DITEM_RESTORE; } /* Fix side-effects from the the XFree86 installation */ int installFixupXFree(dialogMenuItem *self) { /* BOGON #1: XFree86 requires various specialized fixups */ if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); msgNotify("Fixing permissions in XFree86 tree.."); vsystem("chmod -R a+r /usr/X11R6"); vsystem("find /usr/X11R6 -type d | xargs chmod a+x"); /* Also do bogus minimal package registration so ports don't whine */ if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) { dialog_clear_norefresh(); msgNotify("Installing package metainfo.."); vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz"); } } return DITEM_SUCCESS | DITEM_RESTORE; } /* Go newfs and/or mount all the filesystems we've been asked to */ int installFilesystems(dialogMenuItem *self) { int i; Disk *disk; Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev; Device **devs; PartInfo *root; char dname[80]; extern int MakeDevChunk(Chunk *c, char *n); Boolean upgrade = FALSE; /* If we've already done this, bail out */ if (!variable_cmp(DISK_LABELLED, "written")) return DITEM_SUCCESS; upgrade = !variable_cmp(SYSTEM_STATE, "upgrade"); if (!checkLabels(TRUE, &rootdev, &swapdev, &usrdev, &vardev)) return DITEM_FAILURE; if (rootdev) root = (PartInfo *)rootdev->private_data; else root = NULL; command_clear(); if (swapdev && RunningAsInit) { /* As the very first thing, try to get ourselves some swap space */ sprintf(dname, "/dev/%s", swapdev->name); if (!Fake && (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname))) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE; } if (!Fake) { if (!swapon(dname)) { dialog_clear_norefresh(); msgNotify("Added %s as initial swap device", dname); } else { msgConfirm("WARNING! Unable to swap to %s: %s\n" "This may cause the installation to fail at some point\n" "if you don't have a lot of memory.", dname, strerror(errno)); } } } if (rootdev && RunningAsInit) { /* Next, create and/or mount the root device */ sprintf(dname, "/dev/%s", rootdev->name); if (!Fake && (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname))) { msgConfirm("Unable to make device node for %s in /dev!\n" "The creation of filesystems will be aborted.", dname); return DITEM_FAILURE | DITEM_RESTORE; } if (strcmp(root->mountpoint, "/")) msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint); - if (root->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs the root partition?"))) { + if (root->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs the root partition?"))) { int i; dialog_clear_norefresh(); msgNotify("Making a new root filesystem on %s", dname); i = vsystem("%s %s", root->newfs_cmd, dname); if (i) { msgConfirm("Unable to make new root filesystem on %s!\n" "Command returned status %d", dname, i); return DITEM_FAILURE | DITEM_RESTORE; } } else { if (!upgrade) { msgConfirm("Warning: Using existing root partition. It will be assumed\n" "that you have the appropriate device entries already in /dev."); } dialog_clear_norefresh(); msgNotify("Checking integrity of existing %s filesystem.", dname); i = vsystem("fsck -y %s", dname); if (i) msgConfirm("Warning: fsck returned status of %d for %s.\n" "This partition may be unsafe to use.", i, dname); } /* Switch to block device */ sprintf(dname, "/dev/%s", rootdev->name); if (Mount("/mnt", dname)) { msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); return DITEM_FAILURE | DITEM_RESTORE; } } /* Now buzz through the rest of the partitions and mount them too */ devs = deviceFind(NULL, DEVICE_TYPE_DISK); for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; disk = (Disk *)devs[i]->private; if (!disk->chunks) { msgConfirm("No chunk list found for %s!", disk->name); return DITEM_FAILURE | DITEM_RESTORE; } if (RunningAsInit && root && (root->newfs || upgrade)) { Mkdir("/mnt/dev"); if (!Fake) MakeDevDisk(disk, "/mnt/dev"); } else if (!RunningAsInit && !Fake) MakeDevDisk(disk, "/dev"); for (c1 = disk->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) { PartInfo *tmp = (PartInfo *)c2->private_data; /* Already did root */ if (c2 == rootdev) continue; - if (tmp->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) + if (tmp->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name))) command_shell_add(tmp->mountpoint, "%s %s/dev/%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name); else command_shell_add(tmp->mountpoint, "fsck -y %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); command_func_add(tmp->mountpoint, Mount, c2->name); } else if (c2->type == part && c2->subtype == FS_SWAP) { char fname[80]; int i; if (c2 == swapdev) continue; sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name); i = (Fake || swapon(fname)); if (!i) { dialog_clear_norefresh(); msgNotify("Added %s as an additional swap device", fname); } else { msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno)); } } } } else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) { char name[FILENAME_MAX]; sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint); Mkdir(name); } } } if (RunningAsInit) { dialog_clear_norefresh(); msgNotify("Copying initial device files.."); /* Copy the boot floppy's dev files */ if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't clone the /dev files!"); return DITEM_FAILURE | DITEM_RESTORE; } } command_sort(); command_execute(); dialog_clear_norefresh(); return DITEM_SUCCESS | DITEM_RESTORE; } static char * getRelname(void) { static char buf[64]; int sz = (sizeof buf) - 1; if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) { buf[sz] = '\0'; return buf; } else return ""; } /* Initialize various user-settable values to their defaults */ int installVarDefaults(dialogMenuItem *self) { char *cp; /* Set default startup options */ variable_set2(VAR_RELNAME, getRelname(), 0); variable_set2(VAR_CPIO_VERBOSITY, "high", 0); variable_set2(VAR_KGET, "YES", 0); variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE, 0); variable_set2(VAR_INSTALL_ROOT, "/", 0); variable_set2(VAR_INSTALL_CFG, "install.cfg", 0); variable_set2(VAR_TRY_DHCP, "NO", 0); /* For now */ variable_set2(VAR_TRY_RTSOL, "NO", 0); /* For now */ cp = getenv("EDITOR"); if (!cp) cp = "/usr/bin/ee"; variable_set2(VAR_EDITOR, cp, 0); variable_set2(VAR_FTP_USER, "ftp", 0); variable_set2(VAR_BROWSER_PACKAGE, "lynx", 0); variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/lynx", 0); variable_set2(VAR_FTP_STATE, "passive", 0); variable_set2(VAR_NFS_SECURE, "NO", -1); if (OnVTY) variable_set2(VAR_FIXIT_TTY, "standard", 0); else variable_set2(VAR_FIXIT_TTY, "serial", 0); variable_set2(VAR_PKG_TMPDIR, "/usr/tmp", 0); variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT), 0); if (getpid() != 1) variable_set2(SYSTEM_STATE, "update", 0); else variable_set2(SYSTEM_STATE, "init", 0); variable_set2(VAR_NEWFS_ARGS, "-b 8192 -f 1024", 0); return DITEM_SUCCESS; } /* Load the environment up from various system configuration files */ void installEnvironment(void) { configEnvironmentRC_conf(); if (file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); } /* Copy the boot floppy contents into /stand */ Boolean copySelf(void) { int i; if (file_readable("/boot.help")) vsystem("cp /boot.help /mnt"); msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem"); i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (i) { msgConfirm("Copy returned error status of %d!", i); return FALSE; } /* Copy the /etc files into their rightful place */ if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) { msgConfirm("Couldn't copy up the /etc files!"); return TRUE; } return TRUE; } static void create_termcap(void) { FILE *fp; const char *caps[] = { termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r, termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, termcap_xterm, NULL, }; const char **cp; if (!file_readable(TERMCAP_FILE)) { Mkdir("/usr/share/misc"); fp = fopen(TERMCAP_FILE, "w"); if (!fp) { msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work."); return; } cp = caps; while (*cp) fprintf(fp, "%s\n", *(cp++)); fclose(fp); } } Index: head/usr.sbin/sysinstall/label.c =================================================================== --- head/usr.sbin/sysinstall/label.c (revision 70004) +++ head/usr.sbin/sysinstall/label.c (revision 70005) @@ -1,1289 +1,1289 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include /* * Everything to do with editing the contents of disk labels. */ /* A nice message we use a lot in the disklabel editor */ #define MSG_NOT_APPLICABLE "That option is not applicable here" /* Where to start printing the freebsd slices */ #define CHUNK_SLICE_START_ROW 2 #define CHUNK_PART_START_ROW 11 /* The smallest filesystem we're willing to create */ #define FS_MIN_SIZE ONE_MEG /* The smallest root filesystem we're willing to create */ #ifdef __alpha__ #define ROOT_MIN_SIZE 40 #else #define ROOT_MIN_SIZE 30 #endif /* The default root filesystem size */ #ifdef __alpha__ #define ROOT_DEFAULT_SIZE 70 #else #define ROOT_DEFAULT_SIZE 50 #endif /* The smallest swap partition we want to create by default */ #define SWAP_MIN_SIZE 32 /* The smallest /usr partition we're willing to create by default */ #define USR_MIN_SIZE 80 /* The smallest /var partition we're willing to create by default */ #define VAR_MIN_SIZE 20 /* The bottom-most row we're allowed to scribble on */ #define CHUNK_ROW_MAX 16 /* All the chunks currently displayed on the screen */ static struct { struct chunk *c; PartType type; } label_chunk_info[MAX_CHUNKS + 1]; static int here; /*** with this value we try to track the most recently added label ***/ static int label_focus = 0, pslice_focus = 0; static int diskLabel(Device *dev); static int diskLabelNonInteractive(Device *dev); static int labelHook(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Unable to find disk %s!", selected->prompt); return DITEM_FAILURE; } /* Toggle enabled status? */ if (!devs[0]->enabled) { devs[0]->enabled = TRUE; diskLabel(devs[0]); } else devs[0]->enabled = FALSE; return DITEM_SUCCESS; } static int labelCheck(dialogMenuItem *selected) { Device **devs = NULL; devs = deviceFind(selected->prompt, DEVICE_TYPE_DISK); if (!devs || devs[0]->enabled == FALSE) return FALSE; return TRUE; } int diskLabelEditor(dialogMenuItem *self) { DMenu *menu; Device **devs; int i, cnt; i = 0; cnt = diskGetSelectCount(&devs); if (cnt == -1) { msgConfirm("No disks found! Please verify that your disk controller is being\n" "properly probed at boot time. See the Hardware Guide on the\n" "Documentation menu for clues on diagnosing this type of problem."); return DITEM_FAILURE; } else if (cnt) { /* Some are already selected */ if (variable_get(VAR_NONINTERACTIVE)) i = diskLabelNonInteractive(NULL); else i = diskLabel(NULL); } else { /* No disks are selected, fall-back case now */ cnt = deviceCount(devs); if (cnt == 1) { devs[0]->enabled = TRUE; if (variable_get(VAR_NONINTERACTIVE)) i = diskLabelNonInteractive(devs[0]); else i = diskLabel(devs[0]); } else { menu = deviceCreateMenu(&MenuDiskDevices, DEVICE_TYPE_DISK, labelHook, labelCheck); if (!menu) { msgConfirm("No devices suitable for installation found!\n\n" "Please verify that your disk controller (and attached drives)\n" "were detected properly. This can be done by pressing the\n" "[Scroll Lock] key and using the Arrow keys to move back to\n" "the boot messages. Press [Scroll Lock] again to return."); i = DITEM_FAILURE; } else { i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; free(menu); } } } if (DITEM_STATUS(i) != DITEM_FAILURE) { char *cp; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } return i; } int diskLabelCommit(dialogMenuItem *self) { char *cp; int i; /* Already done? */ if ((cp = variable_get(DISK_LABELLED)) && strcmp(cp, "yes")) i = DITEM_SUCCESS; else if (!cp) { msgConfirm("You must assign disk labels before this option can be used."); i = DITEM_FAILURE; } /* The routine will guard against redundant writes, just as this one does */ else if (DITEM_STATUS(diskPartitionWrite(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else if (DITEM_STATUS(installFilesystems(self)) != DITEM_SUCCESS) i = DITEM_FAILURE; else { msgInfo("All filesystem information written successfully."); variable_set2(DISK_LABELLED, "written", 0); i = DITEM_SUCCESS; } return i; } /* See if we're already using a desired partition name */ static Boolean check_conflict(char *name) { int i; for (i = 0; label_chunk_info[i].c; i++) if ((label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT) && label_chunk_info[i].c->private_data && !strcmp(((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint, name)) return TRUE; return FALSE; } /* How much space is in this FreeBSD slice? */ static int space_free(struct chunk *c) { struct chunk *c1; int sz = c->size; for (c1 = c->part; c1; c1 = c1->next) { if (c1->type != unused) sz -= c1->size; } if (sz < 0) msgFatal("Partitions are larger than actual chunk??"); return sz; } /* Snapshot the current situation into the displayed chunks structure */ static void record_label_chunks(Device **devs, Device *dev) { int i, j, p; struct chunk *c1, *c2; Disk *d; j = p = 0; /* First buzz through and pick up the FreeBSD slices */ for (i = 0; devs[i]; i++) { if ((dev && devs[i] != dev) || !devs[i]->enabled) continue; d = (Disk *)devs[i]->private; if (!d->chunks) msgFatal("No chunk list found for %s!", d->name); /* Put the slice entries first */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { label_chunk_info[j].type = PART_SLICE; label_chunk_info[j].c = c1; ++j; } } } /* Now run through again and get the FreeBSD partition entries */ for (i = 0; devs[i]; i++) { if (!devs[i]->enabled) continue; d = (Disk *)devs[i]->private; /* Then buzz through and pick up the partitions */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->type == freebsd) { for (c2 = c1->part; c2; c2 = c2->next) { if (c2->type == part) { if (c2->subtype == FS_SWAP) label_chunk_info[j].type = PART_SWAP; else label_chunk_info[j].type = PART_FILESYSTEM; label_chunk_info[j].c = c2; ++j; } } } else if (c1->type == fat) { label_chunk_info[j].type = PART_FAT; label_chunk_info[j].c = c1; ++j; } } } label_chunk_info[j].c = NULL; if (here >= j) { here = j ? j - 1 : 0; } } /* A new partition entry */ static PartInfo * new_part(char *mpoint, Boolean newfs, u_long size) { PartInfo *ret; if (!mpoint) mpoint = "/change_me"; ret = (PartInfo *)safe_malloc(sizeof(PartInfo)); sstrncpy(ret->mountpoint, mpoint, FILENAME_MAX); strcpy(ret->newfs_cmd, "newfs "); strcat(ret->newfs_cmd, variable_get(VAR_NEWFS_ARGS)); ret->newfs = newfs; if (!size) return ret; return ret; } /* Get the mountpoint for a partition and save it away */ static PartInfo * get_mountpoint(struct chunk *old) { char *val; PartInfo *tmp; if (old && old->private_data) tmp = old->private_data; else tmp = NULL; val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); if (!val || !*val) { if (!old) return NULL; else { free(old->private_data); old->private_data = NULL; } return NULL; } /* Is it just the same value? */ if (tmp && !strcmp(tmp->mountpoint, val)) return NULL; /* Did we use it already? */ if (check_conflict(val)) { msgConfirm("You already have a mount point for %s assigned!", val); return NULL; } /* Is it bogus? */ if (*val != '/') { msgConfirm("Mount point must start with a / character"); return NULL; } /* Is it going to be mounted on root? */ if (!strcmp(val, "/")) { if (old) old->flags |= CHUNK_IS_ROOT; } else if (old) old->flags &= ~CHUNK_IS_ROOT; safe_free(tmp); val = string_skipwhite(string_prune(val)); tmp = new_part(val, TRUE, 0); if (old) { old->private_data = tmp; old->private_free = safe_free; } return tmp; } /* Get the type of the new partiton */ static PartType get_partition_type(void) { char selection[20]; int i; static unsigned char *fs_types[] = { "FS", "A file system", "Swap", "A swap partition.", }; WINDOW *w = savescr(); i = dialog_menu("Please choose a partition type", "If you want to use this partition for swap space, select Swap.\n" "If you want to put a filesystem on it, choose FS.", -1, -1, 2, 2, fs_types, selection, NULL, NULL); restorescr(w); if (!i) { if (!strcmp(selection, "FS")) return PART_FILESYSTEM; else if (!strcmp(selection, "Swap")) return PART_SWAP; } return PART_NONE; } /* If the user wants a special newfs command for this, set it */ static void getNewfsCmd(PartInfo *p) { char *val; val = msgGetInput(p->newfs_cmd, "Please enter the newfs command and options you'd like to use in\n" "creating this file system."); if (val) sstrncpy(p->newfs_cmd, val, NEWFS_CMD_MAX); } #define MAX_MOUNT_NAME 10 #define PART_PART_COL 0 #define PART_MOUNT_COL 10 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) #define PART_NEWFS_COL (PART_SIZE_COL + 8) #define PART_OFF 38 #define TOTAL_AVAIL_LINES (10) #define PSLICE_SHOWABLE (4) /* stick this all up on the screen */ static void print_label_chunks(void) { int i, j, srow, prow, pcol; int sz; char clrmsg[80]; int ChunkPartStartRow; WINDOW *ChunkWin; /********************************************************/ /*** These values are for controling screen resources ***/ /*** Each label line holds up to 2 labels, so beware! ***/ /*** strategy will be to try to always make sure the ***/ /*** highlighted label is in the active display area. ***/ /********************************************************/ int pslice_max, label_max; int pslice_count, label_count, label_focus_found, pslice_focus_found; attrset(A_REVERSE); mvaddstr(0, 25, "FreeBSD Disklabel Editor"); attrset(A_NORMAL); /*** Count the number of parition slices ***/ pslice_count = 0; for (i = 0; label_chunk_info[i].c ; i++) { if (label_chunk_info[i].type == PART_SLICE) ++pslice_count; } pslice_max = pslice_count; /*** 4 line max for partition slices ***/ if (pslice_max > PSLICE_SHOWABLE) { pslice_max = PSLICE_SHOWABLE; } ChunkPartStartRow = CHUNK_SLICE_START_ROW + 3 + pslice_max; /*** View partition slices modulo pslice_max ***/ label_max = TOTAL_AVAIL_LINES - pslice_max; for (i = 0; i < 2; i++) { mvaddstr(ChunkPartStartRow - 2, PART_PART_COL + (i * PART_OFF), "Part"); mvaddstr(ChunkPartStartRow - 1, PART_PART_COL + (i * PART_OFF), "----"); mvaddstr(ChunkPartStartRow - 2, PART_MOUNT_COL + (i * PART_OFF), "Mount"); mvaddstr(ChunkPartStartRow - 1, PART_MOUNT_COL + (i * PART_OFF), "-----"); mvaddstr(ChunkPartStartRow - 2, PART_SIZE_COL + (i * PART_OFF) + 3, "Size"); mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 3, "----"); mvaddstr(ChunkPartStartRow - 2, PART_NEWFS_COL + (i * PART_OFF), "Newfs"); mvaddstr(ChunkPartStartRow - 1, PART_NEWFS_COL + (i * PART_OFF), "-----"); } srow = CHUNK_SLICE_START_ROW; prow = 0; pcol = 0; /*** these variables indicate that the focused item is shown currently ***/ label_focus_found = 0; pslice_focus_found = 0; label_count = 0; pslice_count = 0; mvprintw(CHUNK_SLICE_START_ROW - 1, 0, " "); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, " "); ChunkWin = newwin(CHUNK_ROW_MAX - ChunkPartStartRow, 76, ChunkPartStartRow, 0); wclear(ChunkWin); /*** wrefresh(ChunkWin); ***/ for (i = 0; label_chunk_info[i].c; i++) { /* Is it a slice entry displayed at the top? */ if (label_chunk_info[i].type == PART_SLICE) { /*** This causes the new pslice to replace the previous display ***/ /*** focus must remain on the most recently active pslice ***/ if (pslice_count == pslice_max) { if (pslice_focus_found) { /*** This is where we can mark the more following ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW + pslice_max, 0, "***MORE***"); attrset(A_NORMAL); continue; } else { /*** this is where we set the more previous ***/ attrset(A_BOLD); mvprintw(CHUNK_SLICE_START_ROW - 1, 0, "***MORE***"); attrset(A_NORMAL); pslice_count = 0; srow = CHUNK_SLICE_START_ROW; } } sz = space_free(label_chunk_info[i].c); if (i == here) attrset(ATTR_SELECTED); if (i == pslice_focus) pslice_focus_found = -1; mvprintw(srow++, 0, "Disk: %s\tPartition name: %s\tFree: %d blocks (%dMB)", label_chunk_info[i].c->disk->name, label_chunk_info[i].c->name, sz, (sz / ONE_MEG)); attrset(A_NORMAL); clrtoeol(); move(0, 0); /*** refresh(); ***/ ++pslice_count; } /* Otherwise it's a DOS, swap or filesystem entry in the Chunk window */ else { char onestr[PART_OFF], num[10], *mountpoint, *newfs; /* * We copy this into a blank-padded string so that it looks like * a solid bar in reverse-video */ memset(onestr, ' ', PART_OFF - 1); onestr[PART_OFF - 1] = '\0'; /*** Track how many labels have been displayed ***/ if (label_count == ((label_max - 1 ) * 2)) { if (label_focus_found) { continue; } else { label_count = 0; prow = 0; pcol = 0; } } /* Go for two columns if we've written one full columns worth */ /*** if (prow == (CHUNK_ROW_MAX - ChunkPartStartRow)) ***/ if (label_count == label_max - 1) { pcol = PART_OFF; prow = 0; } memcpy(onestr + PART_PART_COL, label_chunk_info[i].c->name, strlen(label_chunk_info[i].c->name)); /* If it's a filesystem, display the mountpoint */ if (label_chunk_info[i].c->private_data && (label_chunk_info[i].type == PART_FILESYSTEM || label_chunk_info[i].type == PART_FAT)) mountpoint = ((PartInfo *)label_chunk_info[i].c->private_data)->mountpoint; else if (label_chunk_info[i].type == PART_SWAP) mountpoint = "swap"; else mountpoint = ""; /* Now display the newfs field */ if (label_chunk_info[i].type == PART_FAT) newfs = "DOS"; else if (label_chunk_info[i].c->private_data && label_chunk_info[i].type == PART_FILESYSTEM) newfs = ((PartInfo *)label_chunk_info[i].c->private_data)->newfs ? "UFS Y" : "UFS N"; else if (label_chunk_info[i].type == PART_SWAP) newfs = "SWAP"; else newfs = "*"; for (j = 0; j < MAX_MOUNT_NAME && mountpoint[j]; j++) onestr[PART_MOUNT_COL + j] = mountpoint[j]; snprintf(num, 10, "%5ldMB", label_chunk_info[i].c->size ? label_chunk_info[i].c->size / ONE_MEG : 0); memcpy(onestr + PART_SIZE_COL, num, strlen(num)); memcpy(onestr + PART_NEWFS_COL, newfs, strlen(newfs)); onestr[PART_NEWFS_COL + strlen(newfs)] = '\0'; if (i == label_focus) { label_focus_found = -1; wattrset(ChunkWin, A_BOLD); } if (i == here) wattrset(ChunkWin, ATTR_SELECTED); /*** lazy man's way of padding this string ***/ while (strlen( onestr ) < 37) strcat(onestr, " "); mvwaddstr(ChunkWin, prow, pcol, onestr); wattrset(ChunkWin, A_NORMAL); move(0, 0); ++prow; ++label_count; } } /*** this will erase all the extra stuff ***/ memset(clrmsg, ' ', 37); clrmsg[37] = '\0'; while (pslice_count < pslice_max) { mvprintw(srow++, 0, clrmsg); clrtoeol(); ++pslice_count; } while (label_count < (2 * (label_max - 1))) { mvwaddstr(ChunkWin, prow++, pcol, clrmsg); ++label_count; if (prow == (label_max - 1)) { prow = 0; pcol = PART_OFF; } } refresh(); wrefresh(ChunkWin); } static void print_command_summary(void) { mvprintw(17, 0, "The following commands are valid here (upper or lower case):"); mvprintw(18, 0, "C = Create D = Delete M = Mount pt."); if (!RunningAsInit) mvprintw(18, 49, "W = Write"); mvprintw(19, 0, "N = Newfs Opts T = Newfs Toggle U = Undo Q = Finish"); mvprintw(20, 0, "A = Auto Defaults for all!"); mvprintw(22, 0, "Use F1 or ? to get more help, arrow keys to select."); move(0, 0); } static void clear_wins(void) { extern void print_label_chunks(); clear(); print_label_chunks(); } #ifdef __alpha__ /* * If there isn't a freebsd chunk already (i.e. there is no label), * dedicate the disk. */ static void maybe_dedicate(Disk* d) { struct chunk *c; for (c = d->chunks->part; c; c = c->next) { if (c->type == freebsd) break; } if (!c) { msgDebug("dedicating disk"); All_FreeBSD(d, 1); } } #endif static int diskLabel(Device *dev) { int sz, key = 0; Boolean labeling; char *msg = NULL; PartInfo *p, *oldp; PartType type; Device **devs; #ifdef __alpha__ int i; #endif WINDOW *w = savescr(); label_focus = 0; pslice_focus = 0; here = 0; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("No disks found!"); restorescr(w); return DITEM_FAILURE; } labeling = TRUE; keypad(stdscr, TRUE); #ifdef __alpha__ for (i = 0; devs[i]; i++) { maybe_dedicate((Disk*) devs[i]->private); } #endif record_label_chunks(devs, dev); clear(); while (labeling) { char *cp; print_label_chunks(); print_command_summary(); if (msg) { attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL); clrtoeol(); beep(); msg = NULL; } else { move(23, 0); clrtoeol(); } refresh(); key = getch(); switch (toupper(key)) { int i; static char _msg[40]; case '\014': /* ^L */ clear_wins(); break; case '\020': /* ^P */ case KEY_UP: case '-': if (here != 0) --here; else while (label_chunk_info[here + 1].c) ++here; break; case '\016': /* ^N */ case KEY_DOWN: case '+': case '\r': case '\n': if (label_chunk_info[here + 1].c) ++here; else here = 0; break; case KEY_HOME: here = 0; break; case KEY_END: while (label_chunk_info[here + 1].c) ++here; break; case KEY_F(1): case '?': systemDisplayHelp("partition"); clear_wins(); break; case 'A': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a disk slice (at top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) msg = "Not enough free space to create a new partition in the slice"; else { struct chunk *tmp; int mib[2]; int physmem; size_t size, swsize; char *cp; Chunk *rootdev, *swapdev, *usrdev, *vardev; (void)checkLabels(FALSE, &rootdev, &swapdev, &usrdev, &vardev); if (!rootdev) { cp = variable_get(VAR_ROOT_SIZE); tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, (cp ? atoi(cp) : ROOT_DEFAULT_SIZE) * ONE_MEG, part, FS_BSDFFS, CHUNK_IS_ROOT); if (!tmp) { msgConfirm("Unable to create the root partition. Too big?"); clear_wins(); break; } tmp->private_data = new_part("/", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!swapdev) { cp = variable_get(VAR_SWAP_SIZE); if (cp) swsize = atoi(cp) * ONE_MEG; else { mib[0] = CTL_HW; mib[1] = HW_PHYSMEM; size = sizeof physmem; sysctl(mib, 2, &physmem, &size, (void *)0, (size_t)0); swsize = 16 * ONE_MEG + (physmem * 2 / 512); } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, swsize, part, FS_SWAP, 0); if (!tmp) { msgConfirm("Unable to create the swap partition. Too big?"); clear_wins(); break; } tmp->private_data = 0; tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!vardev) { cp = variable_get(VAR_VAR_SIZE); if (cp) sz = atoi(cp) * ONE_MEG; else sz = variable_get(VAR_NO_USR) ? space_free(label_chunk_info[here].c) : VAR_MIN_SIZE * ONE_MEG; tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, 0); if (!tmp) { msgConfirm("Less than %dMB free for /var - you will need to\n" "partition your disk manually with a custom install!", (cp ? atoi(cp) : VAR_MIN_SIZE)); clear_wins(); break; } tmp->private_data = new_part("/var", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } if (!usrdev && !variable_get(VAR_NO_USR)) { cp = variable_get(VAR_USR_SIZE); if (cp) sz = atoi(cp) * ONE_MEG; else sz = space_free(label_chunk_info[here].c); if (sz) { if (sz < (USR_MIN_SIZE * ONE_MEG)) { msgConfirm("Less than %dMB free for /usr - you will need to\n" "partition your disk manually with a custom install!", USR_MIN_SIZE); clear_wins(); break; } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, sz, part, FS_BSDFFS, 0); if (!tmp) { msgConfirm("Unable to create the /usr partition. Not enough space?\n" "You will need to partition your disk manually with a custom install!"); clear_wins(); break; } tmp->private_data = new_part("/usr", TRUE, tmp->size); tmp->private_free = safe_free; record_label_chunks(devs, dev); } } /* At this point, we're reasonably "labelled" */ if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } break; case 'C': if (label_chunk_info[here].type != PART_SLICE) { msg = "You can only do this in a master partition (see top of screen)"; break; } sz = space_free(label_chunk_info[here].c); if (sz <= FS_MIN_SIZE) { msg = "Not enough space to create an additional FreeBSD partition"; break; } else { char *val; int size; struct chunk *tmp; char osize[80]; u_long flags = 0; sprintf(osize, "%d", sz); val = msgGetInput(osize, "Please specify the partition size in blocks or append a trailing G for\n" "gigabytes, M for megabytes, or C for cylinders.\n" "%d blocks (%dMB) are free.", sz, sz / ONE_MEG); if (!val || (size = strtol(val, &cp, 0)) <= 0) { clear_wins(); break; } if (*cp) { if (toupper(*cp) == 'M') size *= ONE_MEG; else if (toupper(*cp) == 'G') size *= ONE_GIG; else if (toupper(*cp) == 'C') size *= (label_chunk_info[here].c->disk->bios_hd * label_chunk_info[here].c->disk->bios_sect); } if (size <= FS_MIN_SIZE) { msgConfirm("The minimum filesystem size is %dMB", FS_MIN_SIZE / ONE_MEG); clear_wins(); break; } type = get_partition_type(); if (type == PART_NONE) { clear_wins(); beep(); break; } if (type == PART_FILESYSTEM) { if ((p = get_mountpoint(NULL)) == NULL) { clear_wins(); beep(); break; } else if (!strcmp(p->mountpoint, "/")) flags |= CHUNK_IS_ROOT; else flags &= ~CHUNK_IS_ROOT; } else p = NULL; if ((flags & CHUNK_IS_ROOT)) { if (!(label_chunk_info[here].c->flags & CHUNK_BSD_COMPAT)) { msgConfirm("This region cannot be used for your root partition as the\n" "FreeBSD boot code cannot deal with a root partition created\n" "in that location. Please choose another location or smaller\n" "size for your root partition and try again!"); clear_wins(); break; } if (size < (ROOT_MIN_SIZE * ONE_MEG)) { msgConfirm("Warning: This is smaller than the recommended size for a\n" "root partition. For a variety of reasons, root\n" "partitions should usually be at least %dMB in size", ROOT_MIN_SIZE); } } tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, size, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags); if (!tmp) { msgConfirm("Unable to create the partition. Too big?"); clear_wins(); break; } if (type != PART_SWAP) { /* This is needed to tell the newfs -u about the size */ tmp->private_data = new_part(p->mountpoint, p->newfs, tmp->size); safe_free(p); } else tmp->private_data = p; tmp->private_free = safe_free; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); /*** This is where we assign focus to new label so it shows ***/ { int i; label_focus = -1; for (i = 0; label_chunk_info[i].c; ++i) { if (label_chunk_info[i].c == tmp) { label_focus = i; break; } } if (label_focus == -1) label_focus = i - 1; } } break; case KEY_DC: case 'D': /* delete */ if (label_chunk_info[here].type == PART_SLICE) { msg = MSG_NOT_APPLICABLE; break; } else if (label_chunk_info[here].type == PART_FAT) { msg = "Use the Disk Partition Editor to delete DOS partitions"; break; } Delete_Chunk(label_chunk_info[here].c->disk, label_chunk_info[here].c); if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); break; case 'M': /* mount */ switch(label_chunk_info[here].type) { case PART_SLICE: msg = MSG_NOT_APPLICABLE; break; case PART_SWAP: msg = "You don't need to specify a mountpoint for a swap partition."; break; case PART_FAT: case PART_FILESYSTEM: oldp = label_chunk_info[here].c->private_data; p = get_mountpoint(label_chunk_info[here].c); if (p) { if (!oldp) p->newfs = FALSE; if (label_chunk_info[here].type == PART_FAT && (!strcmp(p->mountpoint, "/") || !strcmp(p->mountpoint, "/usr") || !strcmp(p->mountpoint, "/var"))) { msgConfirm("%s is an invalid mount point for a DOS partition!", p->mountpoint); strcpy(p->mountpoint, "/bogus"); } } if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); record_label_chunks(devs, dev); clear_wins(); break; default: msgFatal("Bogus partition under cursor???"); break; } break; case 'N': /* Set newfs options */ if (label_chunk_info[here].c->private_data && ((PartInfo *)label_chunk_info[here].c->private_data)->newfs) getNewfsCmd(label_chunk_info[here].c->private_data); else msg = MSG_NOT_APPLICABLE; clear_wins(); break; case 'T': /* Toggle newfs state */ if (label_chunk_info[here].type == PART_FILESYSTEM) { PartInfo *pi = ((PartInfo *)label_chunk_info[here].c->private_data); label_chunk_info[here].c->private_data = new_part(pi ? pi->mountpoint : NULL, pi ? !pi->newfs : TRUE, label_chunk_info[here].c->size); safe_free(pi); label_chunk_info[here].c->private_free = safe_free; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); } else msg = MSG_NOT_APPLICABLE; break; case 'U': clear(); if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written out your changes -\n" "it's too late to undo!"); } - else if (!msgYesNo("Are you SURE you want to Undo everything?")) { + else if (!msgNoYes("Are you SURE you want to Undo everything?")) { variable_unset(DISK_PARTITIONED); variable_unset(DISK_LABELLED); for (i = 0; devs[i]; i++) { Disk *d; if (!devs[i]->enabled) continue; else if ((d = Open_Disk(devs[i]->name)) != NULL) { Free_Disk(devs[i]->private); devs[i]->private = d; diskPartition(devs[i]); } } record_label_chunks(devs, dev); } clear_wins(); break; case 'W': if ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written out your changes - if you\n" "wish to overwrite them, you'll have to start this\n" "procedure again from the beginning."); } - else if (!msgYesNo("WARNING: This should only be used when modifying an EXISTING\n" + else if (!msgNoYes("WARNING: This should only be used when modifying an EXISTING\n" "installation. If you are installing FreeBSD for the first time\n" "then you should simply type Q when you're finished here and your\n" "changes will be committed in one batch automatically at the end of\n" "these questions.\n\n" "Are you absolutely sure you want to do this now?")) { variable_set2(DISK_LABELLED, "yes", 0); diskLabelCommit(NULL); } clear_wins(); break; case '|': - if (!msgYesNo("Are you sure you want to go into Wizard mode?\n\n" + if (!msgNoYes("Are you sure you want to go into Wizard mode?\n\n" "This is an entirely undocumented feature which you are not\n" "expected to understand!")) { int i; Device **devs; dialog_clear(); end_dialog(); DialogActive = FALSE; devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("Can't find any disk devices!"); break; } for (i = 0; devs[i] && ((Disk *)devs[i]->private); i++) { if (devs[i]->enabled) slice_wizard(((Disk *)devs[i]->private)); } if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes", 0); DialogActive = TRUE; record_label_chunks(devs, dev); clear_wins(); } else msg = "A most prudent choice!"; break; case '\033': /* ESC */ case 'Q': labeling = FALSE; break; default: beep(); sprintf(_msg, "Invalid key %d - Type F1 or ? for help", key); msg = _msg; break; } if (label_chunk_info[here].type == PART_SLICE) pslice_focus = here; else label_focus = here; } restorescr(w); return DITEM_SUCCESS; } static int diskLabelNonInteractive(Device *dev) { char *cp; PartType type; PartInfo *p; u_long flags = 0; int i, status; Device **devs; Disk *d; status = DITEM_SUCCESS; cp = variable_get(VAR_DISK); if (!cp) { msgConfirm("diskLabel: No disk selected - can't label automatically."); return DITEM_FAILURE; } devs = deviceFind(cp, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("diskLabel: No disk device %s found!", cp); return DITEM_FAILURE; } if (dev) d = dev->private; else d = devs[0]->private; #ifdef __alpha__ maybe_dedicate(d); #endif record_label_chunks(devs, dev); for (i = 0; label_chunk_info[i].c; i++) { Chunk *c1 = label_chunk_info[i].c; if (label_chunk_info[i].type == PART_SLICE) { char name[512]; int entries = 1; while (entries) { snprintf(name, sizeof name, "%s-%d", c1->name, entries); if ((cp = variable_get(name)) != NULL) { int sz; char typ[10], mpoint[50]; if (sscanf(cp, "%s %d %s", typ, &sz, mpoint) != 3) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; continue; } else { Chunk *tmp; if (!strcmp(typ, "swap")) { type = PART_SWAP; strcpy(mpoint, "SWAP"); } else { type = PART_FILESYSTEM; if (!strcmp(mpoint, "/")) flags |= CHUNK_IS_ROOT; else flags &= ~CHUNK_IS_ROOT; } if (!sz) sz = space_free(c1); if (sz > space_free(c1)) { msgConfirm("Not enough free space to create partition: %s", mpoint); status = DITEM_FAILURE; continue; } if (!(tmp = Create_Chunk_DWIM(d, c1, sz, part, (type == PART_SWAP) ? FS_SWAP : FS_BSDFFS, flags))) { msgConfirm("Unable to create from partition spec: %s. Too big?", cp); status = DITEM_FAILURE; break; } else { tmp->private_data = new_part(mpoint, TRUE, sz); tmp->private_free = safe_free; status = DITEM_SUCCESS; } } entries++; } else { /* No more matches, leave the loop */ entries = 0; } } } else { /* Must be something we can set a mountpoint for */ cp = variable_get(c1->name); if (cp) { char mpoint[50], do_newfs[8]; Boolean newfs = FALSE; do_newfs[0] = '\0'; if (sscanf(cp, "%s %s", mpoint, do_newfs) != 2) { msgConfirm("For slice entry %s, got an invalid detail entry of: %s", c1->name, cp); status = DITEM_FAILURE; continue; } newfs = toupper(do_newfs[0]) == 'Y' ? TRUE : FALSE; if (c1->private_data) { p = c1->private_data; p->newfs = newfs; strcpy(p->mountpoint, mpoint); } else { c1->private_data = new_part(mpoint, newfs, 0); c1->private_free = safe_free; } if (!strcmp(mpoint, "/")) c1->flags |= CHUNK_IS_ROOT; else c1->flags &= ~CHUNK_IS_ROOT; } } } if (status == DITEM_SUCCESS) variable_set2(DISK_LABELLED, "yes", 0); return status; } Index: head/usr.sbin/sysinstall/main.c =================================================================== --- head/usr.sbin/sysinstall/main.c (revision 70004) +++ head/usr.sbin/sysinstall/main.c (revision 70005) @@ -1,165 +1,165 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated for what's essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include const char *StartName; /* Initial contents of argv[0] */ static void screech(int sig) { msgDebug("\007Signal %d caught! That's bad!\n", sig); longjmp(BailOut, sig); } int main(int argc, char **argv) { int choice, scroll, curr, max, status; /* Record name to be able to restart */ StartName = argv[0]; /* Catch fatal signals and complain about them if running as init */ if (getpid() == 1) { signal(SIGBUS, screech); signal(SIGSEGV, screech); } signal(SIGPIPE, SIG_IGN); /* We don't work too well when running as non-root anymore */ if (geteuid() != 0) { fprintf(stderr, "Error: This utility should only be run as root.\n"); return 1; } #ifdef PC98 { /* XXX */ char *p = getenv("TERM"); if (p && strcmp(p, "cons25") == 0) putenv("TERM=cons25w"); } #endif /* Set up whatever things need setting up */ systemInitialize(argc, argv); /* Set default flag and variable values */ installVarDefaults(NULL); /* only when multi-user is it reasonable to do this here */ if (!RunningAsInit) installEnvironment(); if (argc > 1 && !strcmp(argv[1], "-fake")) { variable_set2(VAR_DEBUG, "YES", 0); Fake = TRUE; msgConfirm("I'll be just faking it from here on out, OK?"); } /* Try to preserve our scroll-back buffer */ if (OnVTY) { for (curr = 0; curr < 25; curr++) putchar('\n'); } /* Move stderr aside */ if (DebugFD) dup2(DebugFD, 2); /* Initialize driver modules */ moduleInitialize(); /* Initialize PC-card */ pccardInitialize(); /* Initialize USB */ usbInitialize(); /* Probe for all relevant devices on the system */ deviceGetAll(); /* First, see if we have any arguments to process (and argv[0] counts if it's not "sysinstall") */ if (!RunningAsInit) { int i, start_arg; if (!strstr(argv[0], "sysinstall")) start_arg = 0; else if (Fake) start_arg = 2; else start_arg = 1; for (i = start_arg; i < argc; i++) { if (DITEM_STATUS(dispatchCommand(argv[i])) != DITEM_SUCCESS) systemShutdown(1); } if (argc > start_arg) systemShutdown(0); } else dispatch_load_file_int(TRUE); status = setjmp(BailOut); if (status) { msgConfirm("A signal %d was caught - I'm saving what I can and shutting\n" "If you can reproduce the problem, please turn Debug on in\n" "the Options menu for the extra information it provides in\n" "debugging problems like this.", status); systemShutdown(status); } /* Begin user dialog at outer menu */ dialog_clear(); while (1) { choice = scroll = curr = max = 0; dmenuOpen(&MenuInitial, &choice, &scroll, &curr, &max, TRUE); if (getpid() != 1 #ifdef __alpha__ - || !msgYesNo("Are you sure you wish to exit? The system will halt.") + || !msgNoYes("Are you sure you wish to exit? The system will halt.") #else - || !msgYesNo("Are you sure you wish to exit? The system will reboot\n" + || !msgNoYes("Are you sure you wish to exit? The system will reboot\n" "(be sure to remove any floppies/CDROMs from the drives).") #endif ) break; } /* Say goodnight, Gracie */ systemShutdown(0); return 0; /* We should never get here */ } Index: head/usr.sbin/sysinstall/msg.c =================================================================== --- head/usr.sbin/sysinstall/msg.c (revision 70004) +++ head/usr.sbin/sysinstall/msg.c (revision 70005) @@ -1,328 +1,352 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include Boolean isDebug(void) { char *cp; return (cp = variable_get(VAR_DEBUG)) && strcmp(cp, "no"); } /* Whack up an informational message on the status line, in stand-out */ void msgYap(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); attrs = getattrs(stdscr); attrset(A_REVERSE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); } /* Whack up an informational message on the status line */ void msgInfo(char *fmt, ...) { va_list args; char *errstr; int i, attrs; char line[81]; attrs = getattrs(stdscr); /* NULL is a special convention meaning "erase the old stuff" */ if (!fmt) { move(StatusLine, 0); clrtoeol(); return; } errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); memset(line, ' ', 80); for (i = 0; i < 80; i++) { if (errstr[i]) line[i] = errstr[i]; else break; } line[80] = '\0'; attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, line); attrset(attrs); move(StatusLine, 79); refresh(); } /* Whack up a warning on the status line */ void msgWarn(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Warning: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); attrs = getattrs(stdscr); beep(); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); if (OnVTY && isDebug()) msgDebug("Warning message `%s'\n", errstr); } /* Whack up an error on the status line */ void msgError(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Error: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); beep(); attrs = getattrs(stdscr); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); attrset(attrs); refresh(); if (OnVTY && isDebug()) msgDebug("Error message `%s'\n", errstr); } /* Whack up a fatal error on the status line */ void msgFatal(char *fmt, ...) { va_list args; char *errstr; int attrs; errstr = (char *)alloca(FILENAME_MAX); strcpy(errstr, "Fatal Error: "); va_start(args, fmt); vsnprintf((char *)(errstr + strlen(errstr)), FILENAME_MAX, fmt, args); va_end(args); beep(); attrs = getattrs(stdscr); attrset(ATTR_TITLE); mvaddstr(StatusLine, 0, errstr); addstr(" - "); addstr("PRESS ANY KEY TO "); if (getpid() == 1) addstr("REBOOT"); else addstr("QUIT"); attrset(attrs); refresh(); if (OnVTY) msgDebug("Fatal error `%s'!\n", errstr); getch(); systemShutdown(1); } /* Put up a message in a popup confirmation box */ void msgConfirm(char *fmt, ...) { va_list args; char *errstr; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); msgInfo(NULL); } dialog_notify(errstr); restorescr(w); } /* Put up a message in a popup information box */ void msgNotify(char *fmt, ...) { va_list args; char *errstr; errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (isDebug()) msgDebug("Notify: %s\n", errstr); dialog_msgbox(NULL, errstr, -1, -1, 0); } /* Put up a message in a popup yes/no box and return 1 for YES, 0 for NO */ int msgYesNo(char *fmt, ...) { va_list args; char *errstr; int ret; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } ret = dialog_yesno("User Confirmation Requested", errstr, -1, -1); restorescr(w); return ret; } +/* Put up a message in a popup no/yes box and return 1 for YES, 0 for NO */ +int +msgNoYes(char *fmt, ...) +{ + va_list args; + char *errstr; + int ret; + WINDOW *w = savescr(); + + errstr = (char *)alloca(FILENAME_MAX); + va_start(args, fmt); + vsnprintf(errstr, FILENAME_MAX, fmt, args); + va_end(args); + use_helpline(NULL); + use_helpfile(NULL); + if (OnVTY) { + ioctl(0, VT_ACTIVATE, 1); /* Switch back */ + msgInfo(NULL); + } + ret = dialog_noyes("User Confirmation Requested", errstr, -1, -1); + restorescr(w); + return ret; +} + /* Put up a message in an input box and return the value */ char * msgGetInput(char *buf, char *fmt, ...) { va_list args; char *errstr; static char input_buffer[256]; int rval; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); if (buf) SAFE_STRCPY(input_buffer, buf); else input_buffer[0] = '\0'; if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } rval = dialog_inputbox("Value Required", errstr, -1, -1, input_buffer); restorescr(w); if (!rval) return input_buffer; else return NULL; } /* Write something to the debugging port */ void msgDebug(char *fmt, ...) { va_list args; char *dbg; if (DebugFD == -1) return; dbg = (char *)alloca(FILENAME_MAX); strcpy(dbg, "DEBUG: "); va_start(args, fmt); vsnprintf((char *)(dbg + strlen(dbg)), FILENAME_MAX, fmt, args); va_end(args); write(DebugFD, dbg, strlen(dbg)); } /* Tell the user there's some output to go look at */ void msgWeHaveOutput(char *fmt, ...) { va_list args; char *errstr; WINDOW *w = savescr(); errstr = (char *)alloca(FILENAME_MAX); va_start(args, fmt); vsnprintf(errstr, FILENAME_MAX, fmt, args); va_end(args); use_helpline(NULL); use_helpfile(NULL); msgDebug("Notify: %s\n", errstr); dialog_clear_norefresh(); sleep(2); dialog_msgbox(NULL, errstr, -1, -1, 0); restorescr(w); } /* Simple versions of msgConfirm() and msgNotify() for calling from scripts */ int msgSimpleConfirm(char *str) { msgConfirm(str); return DITEM_SUCCESS; } int msgSimpleNotify(char *str) { msgNotify(str); return DITEM_SUCCESS; } Index: head/usr.sbin/sysinstall/sysinstall.h =================================================================== --- head/usr.sbin/sysinstall/sysinstall.h (revision 70004) +++ head/usr.sbin/sysinstall/sysinstall.h (revision 70005) @@ -1,771 +1,772 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef _SYSINSTALL_H_INCLUDE #define _SYSINSTALL_H_INCLUDE #include #include #include #include #include #include #include #include #include #include "ui_objects.h" #include "dir.h" #include "colors.h" #include "libdisk.h" #include "dist.h" /*** Defines ***/ /* device limits */ #define DEV_NAME_MAX 64 /* The maximum length of a device name */ #define DEV_MAX 100 /* The maximum number of devices we'll deal with */ #define INTERFACE_MAX 50 /* Maximum number of network interfaces we'll deal with */ #define IO_ERROR -2 /* Status code for I/O error rather than normal EOF */ /* Number of seconds to wait for data to come off even the slowest media */ #define MEDIA_TIMEOUT 300 /* * I make some pretty gross assumptions about having a max of 50 chunks * total - 8 slices and 42 partitions. I can't easily display many more * than that on the screen at once! * * For 2.1 I'll revisit this and try to make it more dynamic, but since * this will catch 99.99% of all possible cases, I'm not too worried. */ #define MAX_CHUNKS 40 /* Internal environment variable names */ #define DISK_PARTITIONED "_diskPartitioned" #define DISK_LABELLED "_diskLabelled" #define DISK_SELECTED "_diskSelected" #define SYSTEM_STATE "_systemState" #define RUNNING_ON_ROOT "_runningOnRoot" #define TCP_CONFIGURED "_tcpConfigured" /* Ones that can be tweaked from config files */ #define VAR_BLANKTIME "blanktime" #define VAR_BOOTMGR "bootManager" #define VAR_BROWSER_BINARY "browserBinary" #define VAR_BROWSER_PACKAGE "browserPackage" #define VAR_CPIO_VERBOSITY "cpioVerbose" #define VAR_DEBUG "debug" #define VAR_DESKSTYLE "_deskStyle" #define VAR_DISK "disk" #define VAR_DISTS "dists" #define VAR_DIST_MAIN "distMain" #define VAR_DIST_CRYPTO "distCRYPTO" #define VAR_DIST_SRC "distSRC" #define VAR_DIST_X11 "distX11" #define VAR_DIST_XSERVER "distXserver" #define VAR_DIST_XFONTS "distXfonts" #define VAR_DEDICATE_DISK "dedicateDisk" #define VAR_DOMAINNAME "domainname" #define VAR_EDITOR "editor" #define VAR_EXTRAS "ifconfig_" #define VAR_COMMAND "command" #define VAR_CONFIG_FILE "configFile" #define VAR_FIXIT_TTY "fixitTty" #define VAR_FTP_DIR "ftpDirectory" #define VAR_FTP_PASS "ftpPass" #define VAR_FTP_PATH "_ftpPath" #define VAR_FTP_PORT "ftpPort" #define VAR_FTP_STATE "ftpState" #define VAR_FTP_USER "ftpUser" #define VAR_FTP_HOST "ftpHost" #define VAR_HTTP_PATH "_httpPath" #define VAR_HTTP_PROXY "httpProxy" #define VAR_HTTP_PORT "httpPort" #define VAR_HTTP_HOST "httpHost" #define VAR_HTTP_FTP_MODE "httpFtpMode" #define VAR_GATEWAY "defaultrouter" #define VAR_GEOMETRY "geometry" #define VAR_HOSTNAME "hostname" #define VAR_IFCONFIG "ifconfig_" #define VAR_INTERFACES "network_interfaces" #define VAR_INSTALL_CFG "installConfig" #define VAR_INSTALL_ROOT "installRoot" #define VAR_IPADDR "ipaddr" #define VAR_IPV6_ENABLE "ipv6_enable" #define VAR_IPV6ADDR "ipv6addr" #define VAR_KEYMAP "keymap" #define VAR_KGET "kget" #define VAR_LABEL "label" #define VAR_LABEL_COUNT "labelCount" #define VAR_LINUX_ENABLE "linux_enable" #define VAR_MEDIA_TYPE "mediaType" #define VAR_MEDIA_TIMEOUT "MEDIA_TIMEOUT" #define VAR_MOUSED "moused_enable" #define VAR_MOUSED_FLAGS "moused_flags" #define VAR_MOUSED_PORT "moused_port" #define VAR_MOUSED_TYPE "moused_type" #define VAR_NAMESERVER "nameserver" #define VAR_NETINTERACTIVE "netInteractive" #define VAR_NETMASK "netmask" #define VAR_NETWORK_DEVICE "netDev" #define VAR_NEWFS_ARGS "newfsArgs" #define VAR_NFS_PATH "nfs" #define VAR_NFS_HOST "nfsHost" #define VAR_NFS_SECURE "nfs_reserved_port_only" #define VAR_NFS_SERVER "nfs_server_enable" #define VAR_NO_CONFIRM "noConfirm" #define VAR_NO_ERROR "noError" #define VAR_NO_WARN "noWarn" #define VAR_NO_USR "noUsr" #define VAR_NONINTERACTIVE "nonInteractive" #define VAR_NOVELL "novell" #define VAR_NTPDATE_FLAGS "ntpdate_flags" #define VAR_PACKAGE "package" #define VAR_PARTITION "partition" #define VAR_PCNFSD "pcnfsd" #define VAR_PKG_TMPDIR "PKG_TMPDIR" #define VAR_PORTS_PATH "ports" #define VAR_PPP_ENABLE "ppp_enable" #define VAR_PPP_PROFILE "ppp_profile" #define VAR_RELNAME "releaseName" #define VAR_ROOT_SIZE "rootSize" #define VAR_ROUTER "router" #define VAR_ROUTER_ENABLE "router_enable" #define VAR_ROUTERFLAGS "router_flags" #define VAR_SERIAL_SPEED "serialSpeed" #define VAR_SLOW_ETHER "slowEthernetCard" #define VAR_SWAP_SIZE "swapSize" #define VAR_TAPE_BLOCKSIZE "tapeBlocksize" #define VAR_TRY_DHCP "tryDHCP" #define VAR_TRY_RTSOL "tryRTSOL" #define VAR_UFS_PATH "ufs" #define VAR_USR_SIZE "usrSize" #define VAR_VAR_SIZE "varSize" #define VAR_XF86_CONFIG "_xf86config" #define DEFAULT_TAPE_BLOCKSIZE "20" /* One MB worth of blocks */ #define ONE_MEG 2048 #define ONE_GIG (ONE_MEG * 1024) /* Which selection attributes to use */ #define ATTR_SELECTED (ColorDisplay ? item_selected_attr : item_attr) #define ATTR_TITLE button_active_attr /* Handy strncpy() macro */ #define SAFE_STRCPY(to, from) sstrncpy((to), (from), sizeof (to) - 1) /*** Types ***/ typedef unsigned int Boolean; typedef struct disk Disk; typedef struct chunk Chunk; /* Bitfields for menu options */ #define DMENU_NORMAL_TYPE 0x1 /* Normal dialog menu */ #define DMENU_RADIO_TYPE 0x2 /* Radio dialog menu */ #define DMENU_CHECKLIST_TYPE 0x4 /* Multiple choice menu */ #define DMENU_SELECTION_RETURNS 0x8 /* Immediate return on item selection */ typedef struct _dmenu { int type; /* What sort of menu we are */ char *title; /* Our title */ char *prompt; /* Our prompt */ char *helpline; /* Line of help at bottom */ char *helpfile; /* Help file for "F1" */ dialogMenuItem items[0]; /* Array of menu items */ } DMenu; /* An rc.conf variable */ typedef struct _variable { struct _variable *next; char *name; char *value; int dirty; } Variable; #define NO_ECHO_OBJ(type) ((type) | (DITEM_NO_ECHO << 16)) #define TYPE_OF_OBJ(type) ((type) & 0xff) #define ATTR_OF_OBJ(type) ((type) >> 16) /* A screen layout structure */ typedef struct _layout { int y; /* x & Y co-ordinates */ int x; int len; /* The size of the dialog on the screen */ int maxlen; /* How much the user can type in ... */ char *prompt; /* The string for the prompt */ char *help; /* The display for the help line */ void *var; /* The var to set when this changes */ int type; /* The type of the dialog to create */ void *obj; /* The obj pointer returned by libdialog */ } Layout; typedef enum { DEVICE_TYPE_NONE, DEVICE_TYPE_DISK, DEVICE_TYPE_FLOPPY, DEVICE_TYPE_FTP, DEVICE_TYPE_NETWORK, DEVICE_TYPE_CDROM, DEVICE_TYPE_TAPE, DEVICE_TYPE_DOS, DEVICE_TYPE_UFS, DEVICE_TYPE_NFS, DEVICE_TYPE_ANY, DEVICE_TYPE_HTTP, } DeviceType; /* CDROM mount codes */ #define CD_UNMOUNTED 0 #define CD_ALREADY_MOUNTED 1 #define CD_WE_MOUNTED_IT 2 /* A "device" from sysinstall's point of view */ typedef struct _device { char name[DEV_NAME_MAX]; char *description; char *devname; DeviceType type; Boolean enabled; Boolean (*init)(struct _device *dev); FILE * (*get)(struct _device *dev, char *file, Boolean probe); void (*shutdown)(struct _device *dev); void *private; unsigned int flags; } Device; /* Some internal representations of partitions */ typedef enum { PART_NONE, PART_SLICE, PART_SWAP, PART_FILESYSTEM, PART_FAT, } PartType; /* The longest newfs command we'll hand to system() */ #define NEWFS_CMD_MAX 256 typedef struct _part_info { Boolean newfs; char mountpoint[FILENAME_MAX]; char newfs_cmd[NEWFS_CMD_MAX]; } PartInfo; /* An option */ typedef struct _opt { char *name; char *desc; enum { OPT_IS_STRING, OPT_IS_INT, OPT_IS_FUNC, OPT_IS_VAR } type; void *data; void *aux; char *(*check)(); } Option; /* Weird index nodey things we use for keeping track of package information */ typedef enum { PACKAGE, PLACE } node_type; /* Types of nodes */ typedef struct _pkgnode { /* A node in the reconstructed hierarchy */ struct _pkgnode *next; /* My next sibling */ node_type type; /* What am I? */ char *name; /* My name */ char *desc; /* My description (Hook) */ struct _pkgnode *kids; /* My little children */ void *data; /* A place to hang my data */ } PkgNode; typedef PkgNode *PkgNodePtr; /* A single package */ typedef struct _indexEntry { /* A single entry in an INDEX file */ char *name; /* name */ char *path; /* full path to port */ char *prefix; /* port prefix */ char *comment; /* one line description */ char *descrfile; /* path to description file */ char *deps; /* packages this depends on */ int depc; /* how many depend on me */ int installed; /* indicates if it is installed */ char *maintainer; /* maintainer */ } IndexEntry; typedef IndexEntry *IndexEntryPtr; typedef int (*commandFunc)(char *key, void *data); #define HOSTNAME_FIELD_LEN 128 #define IPADDR_FIELD_LEN 16 #define EXTRAS_FIELD_LEN 128 /* This is the structure that Network devices carry around in their private, erm, structures */ typedef struct _devPriv { int use_rtsol; int use_dhcp; char ipaddr[IPADDR_FIELD_LEN]; char netmask[IPADDR_FIELD_LEN]; char extras[EXTRAS_FIELD_LEN]; } DevInfo; /*** Externs ***/ extern jmp_buf BailOut; /* Used to get the heck out */ extern int DebugFD; /* Where diagnostic output goes */ extern Boolean Fake; /* Don't actually modify anything - testing */ extern Boolean SystemWasInstalled; /* Did we install it? */ extern Boolean RunningAsInit; /* Are we running stand-alone? */ extern Boolean DialogActive; /* Is the dialog() stuff up? */ extern Boolean ColorDisplay; /* Are we on a color display? */ extern Boolean OnVTY; /* On a syscons VTY? */ extern Variable *VarHead; /* The head of the variable chain */ extern Device *mediaDevice; /* Where we're getting our distribution from */ extern unsigned int Dists; /* Which distributions we want */ extern unsigned int CRYPTODists; /* Which naughty distributions we want */ extern unsigned int SrcDists; /* Which src distributions we want */ extern unsigned int XF86Dists; /* Which XFree86 dists we want */ extern unsigned int XF86ServerDists; /* The XFree86 servers we want */ extern unsigned int XF86FontDists; /* The XFree86 fonts we want */ extern int BootMgr; /* Which boot manager to use */ extern int StatusLine; /* Where to print our status messages */ extern DMenu MenuInitial; /* Initial installation menu */ extern DMenu MenuFixit; /* Fixit repair menu */ extern DMenu MenuMBRType; /* Type of MBR to write on the disk */ extern DMenu MenuConfigure; /* Final configuration menu */ extern DMenu MenuDocumentation; /* Documentation menu */ extern DMenu MenuFTPOptions; /* FTP Installation options */ extern DMenu MenuIndex; /* Index menu */ extern DMenu MenuOptions; /* Installation options */ extern DMenu MenuOptionsLanguage; /* Language options menu */ extern DMenu MenuMedia; /* Media type menu */ extern DMenu MenuMouse; /* Mouse type menu */ extern DMenu MenuMediaCDROM; /* CDROM media menu */ extern DMenu MenuMediaDOS; /* DOS media menu */ extern DMenu MenuMediaFloppy; /* Floppy media menu */ extern DMenu MenuMediaFTP; /* FTP media menu */ extern DMenu MenuMediaTape; /* Tape media menu */ extern DMenu MenuNetworkDevice; /* Network device menu */ extern DMenu MenuNTP; /* NTP time server menu */ extern DMenu MenuSecurityProfile; /* Security profile menu */ extern DMenu MenuStartup; /* Startup services menu */ extern DMenu MenuSyscons; /* System console configuration menu */ extern DMenu MenuSysconsFont; /* System console font configuration menu */ extern DMenu MenuSysconsKeymap; /* System console keymap configuration menu */ extern DMenu MenuSysconsKeyrate; /* System console keyrate configuration menu */ extern DMenu MenuSysconsSaver; /* System console saver configuration menu */ extern DMenu MenuSysconsScrnmap; /* System console screenmap configuration menu */ extern DMenu MenuNetworking; /* Network configuration menu */ extern DMenu MenuInstallCustom; /* Custom Installation menu */ extern DMenu MenuDistributions; /* Distribution menu */ extern DMenu MenuDiskDevices; /* Disk type devices */ extern DMenu MenuSubDistributions; /* Custom distribution menu */ extern DMenu MenuSrcDistributions; /* Source distribution menu */ extern DMenu MenuXF86; /* XFree86 main menu */ extern DMenu MenuXF86Select; /* XFree86 distribution selection menu */ extern DMenu MenuXF86SelectCore; /* XFree86 core distribution menu */ extern DMenu MenuXF86SelectServer; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectPC98Server; /* XFree86 server distribution menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuXF86SelectFonts; /* XFree86 font selection menu */ extern DMenu MenuXDesktops; /* Disk devices menu */ extern DMenu MenuHTMLDoc; /* HTML Documentation menu */ extern DMenu MenuUsermgmt; /* User management menu */ extern DMenu MenuFixit; /* Fixit floppy/CDROM/shell menu */ extern DMenu MenuXF86Config; /* Select XFree86 configuration type */ extern int FixItMode; /* FixItMode starts shell onc urrent device (ie Serial port) */ extern const char * StartName; /* Which name we were started as */ /* Stuff from libdialog which isn't properly declared outside */ extern void display_helpfile(void); extern void display_helpline(WINDOW *w, int y, int width); /*** Prototypes ***/ /* anonFTP.c */ extern int configAnonFTP(dialogMenuItem *self); /* cdrom.c */ extern Boolean mediaInitCDROM(Device *dev); extern FILE *mediaGetCDROM(Device *dev, char *file, Boolean probe); extern void mediaShutdownCDROM(Device *dev); /* command.c */ extern void command_clear(void); extern void command_sort(void); extern void command_execute(void); extern void command_shell_add(char *key, char *fmt, ...); extern void command_func_add(char *key, commandFunc func, void *data); /* config.c */ extern void configEnvironmentRC_conf(void); extern void configEnvironmentResolv(char *config); extern void configRC_conf(void); extern int configFstab(dialogMenuItem *self); extern int configRC(dialogMenuItem *self); extern int configResolv(dialogMenuItem *self); extern int configPackages(dialogMenuItem *self); extern int configSaver(dialogMenuItem *self); extern int configSaverTimeout(dialogMenuItem *self); extern int configLinux(dialogMenuItem *self); extern int configNTP(dialogMenuItem *self); extern int configUsers(dialogMenuItem *self); extern int configXSetup(dialogMenuItem *self); extern int configXDesktop(dialogMenuItem *self); extern int configRouter(dialogMenuItem *self); extern int configPCNFSD(dialogMenuItem *self); extern int configNFSServer(dialogMenuItem *self); extern int configWriteRC_conf(dialogMenuItem *self); extern int configSecurityProfile(dialogMenuItem *self); extern int configSecurityFascist(dialogMenuItem *self); extern int configSecurityHigh(dialogMenuItem *self); extern int configSecurityModerate(dialogMenuItem *self); extern int configSecurityLiberal(dialogMenuItem *self); /* crc.c */ extern int crc(int, unsigned long *, unsigned long *); /* devices.c */ extern DMenu *deviceCreateMenu(DMenu *menu, DeviceType type, int (*hook)(dialogMenuItem *d), int (*check)(dialogMenuItem *d)); extern void deviceGetAll(void); extern void deviceReset(void); extern void deviceRescan(void); extern Device **deviceFind(char *name, DeviceType type); extern Device **deviceFindDescr(char *name, char *desc, DeviceType class); extern int deviceCount(Device **devs); extern Device *new_device(char *name); extern Device *deviceRegister(char *name, char *desc, char *devname, DeviceType type, Boolean enabled, Boolean (*init)(Device *mediadev), FILE * (*get)(Device *dev, char *file, Boolean probe), void (*shutDown)(Device *mediadev), void *private); extern Boolean dummyInit(Device *dev); extern FILE *dummyGet(Device *dev, char *dist, Boolean probe); extern void dummyShutdown(Device *dev); /* dhcp.c */ extern int dhcpParseLeases(char *file, char *hostname, char *domain, char *nameserver, char *ipaddr, char *gateway, char *netmask); /* disks.c */ extern int diskPartitionEditor(dialogMenuItem *self); extern int diskPartitionWrite(dialogMenuItem *self); extern int diskGetSelectCount(Device ***devs); extern void diskPartition(Device *dev); /* dispatch.c */ extern int dispatchCommand(char *command); extern int dispatch_load_floppy(dialogMenuItem *self); extern int dispatch_load_file_int(int); extern int dispatch_load_file(dialogMenuItem *self); /* dist.c */ extern int distReset(dialogMenuItem *self); extern int distConfig(dialogMenuItem *self); extern int distSetCustom(dialogMenuItem *self); extern int distUnsetCustom(dialogMenuItem *self); extern int distSetDeveloper(dialogMenuItem *self); extern int distSetXDeveloper(dialogMenuItem *self); extern int distSetKernDeveloper(dialogMenuItem *self); extern int distSetXKernDeveloper(dialogMenuItem *self); extern int distSetUser(dialogMenuItem *self); extern int distSetXUser(dialogMenuItem *self); extern int distSetMinimum(dialogMenuItem *self); extern int distSetEverything(dialogMenuItem *self); extern int distSetSrc(dialogMenuItem *self); extern int distSetXF86(dialogMenuItem *self); extern int distExtractAll(dialogMenuItem *self); /* dmenu.c */ extern int dmenuDisplayFile(dialogMenuItem *tmp); extern int dmenuSubmenu(dialogMenuItem *tmp); extern int dmenuSystemCommand(dialogMenuItem *tmp); extern int dmenuSystemCommandBox(dialogMenuItem *tmp); extern int dmenuExit(dialogMenuItem *tmp); extern int dmenuISetVariable(dialogMenuItem *tmp); extern int dmenuSetVariable(dialogMenuItem *tmp); extern int dmenuSetKmapVariable(dialogMenuItem *tmp); extern int dmenuSetVariables(dialogMenuItem *tmp); extern int dmenuToggleVariable(dialogMenuItem *tmp); extern int dmenuSetFlag(dialogMenuItem *tmp); extern int dmenuSetValue(dialogMenuItem *tmp); extern Boolean dmenuOpen(DMenu *menu, int *choice, int *scroll, int *curr, int *max, Boolean buttons); extern Boolean dmenuOpenSimple(DMenu *menu, Boolean buttons); extern int dmenuVarCheck(dialogMenuItem *item); extern int dmenuVarsCheck(dialogMenuItem *item); extern int dmenuFlagCheck(dialogMenuItem *item); extern int dmenuRadioCheck(dialogMenuItem *item); /* doc.c */ extern int docBrowser(dialogMenuItem *self); extern int docShowDocument(dialogMenuItem *self); /* dos.c */ extern Boolean mediaCloseDOS(Device *dev, FILE *fp); extern Boolean mediaInitDOS(Device *dev); extern FILE *mediaGetDOS(Device *dev, char *file, Boolean probe); extern void mediaShutdownDOS(Device *dev); /* floppy.c */ extern int getRootFloppy(void); extern Boolean mediaInitFloppy(Device *dev); extern FILE *mediaGetFloppy(Device *dev, char *file, Boolean probe); extern void mediaShutdownFloppy(Device *dev); /* ftp_strat.c */ extern Boolean mediaCloseFTP(Device *dev, FILE *fp); extern Boolean mediaInitFTP(Device *dev); extern FILE *mediaGetFTP(Device *dev, char *file, Boolean probe); extern void mediaShutdownFTP(Device *dev); /* http.c */ extern Boolean mediaInitHTTP(Device *dev); extern FILE *mediaGetHTTP(Device *dev, char *file, Boolean probe); /* globals.c */ extern void globalsInit(void); /* index.c */ int index_read(FILE *fp, PkgNodePtr papa); int index_menu(PkgNodePtr root, PkgNodePtr top, PkgNodePtr plist, int *pos, int *scroll); void index_init(PkgNodePtr top, PkgNodePtr plist); void index_node_free(PkgNodePtr top, PkgNodePtr plist); void index_sort(PkgNodePtr top); void index_print(PkgNodePtr top, int level); int index_extract(Device *dev, PkgNodePtr top, PkgNodePtr who, Boolean depended); int index_initialize(char *path); PkgNodePtr index_search(PkgNodePtr top, char *str, PkgNodePtr *tp); /* install.c */ extern Boolean checkLabels(Boolean whinge, Chunk **rdev, Chunk **sdev, Chunk **udev, Chunk **vdev); extern int installCommit(dialogMenuItem *self); extern int installCustomCommit(dialogMenuItem *self); extern int installExpress(dialogMenuItem *self); extern int installStandard(dialogMenuItem *self); extern int installFixitHoloShell(dialogMenuItem *self); extern int installFixitCDROM(dialogMenuItem *self); extern int installFixitFloppy(dialogMenuItem *self); extern int installFixupBin(dialogMenuItem *self); extern int installFixupXFree(dialogMenuItem *self); extern int installUpgrade(dialogMenuItem *self); extern int installFilesystems(dialogMenuItem *self); extern int installVarDefaults(dialogMenuItem *self); extern void installEnvironment(void); extern int installX11package(dialogMenuItem *self); extern Boolean copySelf(void); /* kget.c */ extern int kget(char *out); /* keymap.c */ extern int loadKeymap(const char *lang); /* label.c */ extern int diskLabelEditor(dialogMenuItem *self); extern int diskLabelCommit(dialogMenuItem *self); /* makedevs.c (auto-generated) */ extern const char termcap_ansi[]; extern const char termcap_vt100[]; extern const char termcap_cons25w[]; extern const char termcap_cons25[]; extern const char termcap_cons25_m[]; extern const char termcap_cons25r[]; extern const char termcap_cons25r_m[]; extern const char termcap_cons25l1[]; extern const char termcap_cons25l1_m[]; extern const char termcap_xterm[]; extern const u_char font_iso_8x16[]; extern const u_char font_cp850_8x16[]; extern const u_char font_cp866_8x16[]; extern const u_char koi8_r2cp866[]; extern u_char default_scrnmap[]; /* media.c */ extern char *cpioVerbosity(void); extern void mediaClose(void); extern int mediaTimeout(void); extern int mediaSetCDROM(dialogMenuItem *self); extern int mediaSetFloppy(dialogMenuItem *self); extern int mediaSetDOS(dialogMenuItem *self); extern int mediaSetTape(dialogMenuItem *self); extern int mediaSetFTP(dialogMenuItem *self); extern int mediaSetFTPActive(dialogMenuItem *self); extern int mediaSetFTPPassive(dialogMenuItem *self); extern int mediaSetHTTP(dialogMenuItem *self); extern int mediaSetUFS(dialogMenuItem *self); extern int mediaSetNFS(dialogMenuItem *self); extern int mediaSetFTPUserPass(dialogMenuItem *self); extern int mediaSetCPIOVerbosity(dialogMenuItem *self); extern int mediaGetType(dialogMenuItem *self); extern Boolean mediaExtractDist(char *dir, char *dist, FILE *fp); extern Boolean mediaExtractDistBegin(char *dir, int *fd, int *zpid, int *cpic); extern Boolean mediaExtractDistEnd(int zpid, int cpid); extern Boolean mediaVerify(void); extern FILE *mediaGenericGet(char *base, const char *file); /* misc.c */ extern Boolean file_readable(char *fname); extern Boolean file_executable(char *fname); extern Boolean directory_exists(const char *dirname); extern char *root_bias(char *path); extern char *itoa(int value); extern char *string_concat(char *p1, char *p2); extern char *string_concat3(char *p1, char *p2, char *p3); extern char *string_prune(char *str); extern char *string_skipwhite(char *str); extern char *string_copy(char *s1, char *s2); extern char *pathBaseName(const char *path); extern void safe_free(void *ptr); extern void *safe_malloc(size_t size); extern void *safe_realloc(void *orig, size_t size); extern dialogMenuItem *item_add(dialogMenuItem *list, char *prompt, char *title, int (*checked)(dialogMenuItem *self), int (*fire)(dialogMenuItem *self), void (*selected)(dialogMenuItem *self, int is_selected), void *data, int aux, int *curr, int *max); extern void items_free(dialogMenuItem *list, int *curr, int *max); extern int Mkdir(char *); extern int Mount(char *, void *data); extern WINDOW *openLayoutDialog(char *helpfile, char *title, int x, int y, int width, int height); extern ComposeObj *initLayoutDialog(WINDOW *win, Layout *layout, int x, int y, int *max); extern int layoutDialogLoop(WINDOW *win, Layout *layout, ComposeObj **obj, int *n, int max, int *cbutton, int *cancel); extern WINDOW *savescr(void); extern void restorescr(WINDOW *w); extern char *sstrncpy(char *dst, const char *src, int size); /* modules.c */ extern void moduleInitialize(void); /* mouse.c */ extern int mousedTest(dialogMenuItem *self); extern int mousedDisable(dialogMenuItem *self); extern int setMouseFlags(dialogMenuItem *self); /* msg.c */ extern Boolean isDebug(void); extern void msgInfo(char *fmt, ...); extern void msgYap(char *fmt, ...); extern void msgWarn(char *fmt, ...); extern void msgDebug(char *fmt, ...); extern void msgError(char *fmt, ...); extern void msgFatal(char *fmt, ...); extern void msgConfirm(char *fmt, ...); extern void msgNotify(char *fmt, ...); extern void msgWeHaveOutput(char *fmt, ...); extern int msgYesNo(char *fmt, ...); +extern int msgNoYes(char *fmt, ...); extern char *msgGetInput(char *buf, char *fmt, ...); extern int msgSimpleConfirm(char *); extern int msgSimpleNotify(char *); /* network.c */ extern Boolean mediaInitNetwork(Device *dev); extern void mediaShutdownNetwork(Device *dev); /* nfs.c */ extern Boolean mediaInitNFS(Device *dev); extern FILE *mediaGetNFS(Device *dev, char *file, Boolean probe); extern void mediaShutdownNFS(Device *dev); /* options.c */ extern int optionsEditor(dialogMenuItem *self); /* package.c */ extern int packageAdd(dialogMenuItem *self); extern int package_add(char *name); extern int package_extract(Device *dev, char *name, Boolean depended); extern Boolean package_exists(char *name); /* pccard.c */ extern void pccardInitialize(void); /* system.c */ extern void systemInitialize(int argc, char **argv); extern void systemShutdown(int status); extern int execExecute(char *cmd, char *name); extern int systemExecute(char *cmd); extern void systemSuspendDialog(void); extern void systemResumeDialog(void); extern int systemDisplayHelp(char *file); extern char *systemHelpFile(char *file, char *buf); extern void systemChangeFont(const u_char font[]); extern void systemChangeLang(char *lang); extern void systemChangeTerminal(char *color, const u_char c_termcap[], char *mono, const u_char m_termcap[]); extern void systemChangeScreenmap(const u_char newmap[]); extern void systemCreateHoloshell(void); extern int vsystem(char *fmt, ...); /* tape.c */ extern char *mediaTapeBlocksize(void); extern Boolean mediaInitTape(Device *dev); extern FILE *mediaGetTape(Device *dev, char *file, Boolean probe); extern void mediaShutdownTape(Device *dev); /* tcpip.c */ extern int tcpOpenDialog(Device *dev); extern int tcpMenuSelect(dialogMenuItem *self); extern Device *tcpDeviceSelect(void); /* termcap.c */ extern int set_termcap(void); /* ufs.c */ extern void mediaShutdownUFS(Device *dev); extern Boolean mediaInitUFS(Device *dev); extern FILE *mediaGetUFS(Device *dev, char *file, Boolean probe); /* usb.c */ extern void usbInitialize(void); /* user.c */ extern int userAddGroup(dialogMenuItem *self); extern int userAddUser(dialogMenuItem *self); /* variable.c */ extern void variable_set(char *var, int dirty); extern void variable_set2(char *name, char *value, int dirty); extern char *variable_get(char *var); extern int variable_cmp(char *var, char *value); extern void variable_unset(char *var); extern char *variable_get_value(char *var, char *prompt, int dirty); extern int variable_check(char *data); extern int dump_variables(dialogMenuItem *self); /* wizard.c */ extern void slice_wizard(Disk *d); #endif /* _SYSINSTALL_H_INCLUDE */ Index: head/usr.sbin/sysinstall/system.c =================================================================== --- head/usr.sbin/sysinstall/system.c (revision 70004) +++ head/usr.sbin/sysinstall/system.c (revision 70005) @@ -1,506 +1,506 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Jordan Hubbard * * My contributions are in the public domain. * * Parts of this file are also blatently stolen from Poul-Henning Kamp's * previous version of sysinstall, and as such fall under his "BEERWARE license" * so buy him a beer if you like it! Buy him a beer for me, too! * Heck, get him completely drunk and send me pictures! :-) */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include /* Where we stick our temporary expanded doc file */ #define DOC_TMP_DIR "/tmp/.doc" #define DOC_TMP_FILE "/tmp/.doc/doc.tmp" static pid_t ehs_pid; /* * Handle interrupt signals - this probably won't work in all cases * due to our having bogotified the internal state of dialog or curses, * but we'll give it a try. */ static int intr_continue(dialogMenuItem *self) { return DITEM_LEAVE_MENU; } static int intr_reboot(dialogMenuItem *self) { systemShutdown(-1); /* NOTREACHED */ return 0; } static int intr_restart(dialogMenuItem *self) { execl(StartName, StartName, NULL); /* NOTREACHED */ return -1; } static dialogMenuItem intrmenu[] = { { "Abort", "Abort the installation", NULL, intr_reboot }, { "Restart", "Restart the installation program", NULL, intr_restart }, { "Continue", "Continue the installation", NULL, intr_continue }, }; static void handle_intr(int sig) { WINDOW *save = savescr(); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } (void)dialog_menu("Installation interrupt", "Do you want to abort the installation?", -1, -1, 3, -3, intrmenu, NULL, NULL, NULL); restorescr(save); } /* Expand a file into a convenient location, nuking it each time */ static char * expand(char *fname) { char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip"; if (!directory_exists(DOC_TMP_DIR)) { Mkdir(DOC_TMP_DIR); if (chown(DOC_TMP_DIR, 0, 0) < 0) return NULL; if (chmod(DOC_TMP_DIR, S_IRWXU) < 0) return NULL; } else unlink(DOC_TMP_FILE); if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE)) return NULL; return DOC_TMP_FILE; } /* Initialize system defaults */ void systemInitialize(int argc, char **argv) { int i, boothowto; sigset_t signalset; signal(SIGINT, SIG_IGN); globalsInit(); i = sizeof(boothowto); if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, NULL) && (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE)) variable_set2(VAR_DEBUG, "YES", 0); /* Are we running as init? */ if (getpid() == 1) { int fd, type; RunningAsInit = 1; setsid(); close(0); fd = open("/dev/ttyv0", O_RDWR); if (fd == -1) { fd = open("/dev/console", O_RDWR); /* fallback */ variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */ } else OnVTY = TRUE; /* * To make _sure_ we're on a VTY and don't have /dev/console switched * away to a serial port or something, attempt to set the cursor appearance. */ type = 0; /* normal */ if (OnVTY) { int fd2; if ((fd2 = open("/dev/console", O_RDWR)) != -1) { if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) { OnVTY = FALSE; variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit the console type */ close(fd); close(fd2); open("/dev/console", O_RDWR); } else close(fd2); } } close(1); dup(0); close(2); dup(0); printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console"); ioctl(0, TIOCSCTTY, (char *)NULL); setlogin("root"); setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1); setbuf(stdin, 0); setbuf(stderr, 0); #ifdef __alpha__ i = 0; sysctlbyname("machdep.unaligned_print", NULL, 0, &i, sizeof(i)); #endif } else { char hname[256]; /* Initalize various things for a multi-user environment */ if (!gethostname(hname, sizeof hname)) variable_set2(VAR_HOSTNAME, hname, 0); } if (set_termcap() == -1) { printf("Can't find terminal entry\n"); exit(-1); } /* XXX - libdialog has particularly bad return value checking */ init_dialog(); /* If we haven't crashed I guess dialog is running ! */ DialogActive = TRUE; /* Make sure HOME is set for those utilities that need it */ if (!getenv("HOME")) setenv("HOME", "/", 1); signal(SIGINT, handle_intr); /* * Make sure we can be interrupted even if we were re-executed * from an interrupt. */ sigemptyset(&signalset); sigaddset(&signalset, SIGINT); sigprocmask(SIG_UNBLOCK, &signalset, NULL); (void)vsystem("rm -rf %s", DOC_TMP_DIR); } /* Close down and prepare to exit */ void systemShutdown(int status) { /* If some media is open, close it down */ if (status >=0) mediaClose(); /* write out any changes to rc.conf .. */ configRC_conf(); /* Shut down the dialog library */ if (DialogActive) { end_dialog(); DialogActive = FALSE; } /* Shut down curses */ endwin(); /* If we have a temporary doc dir lying around, nuke it */ (void)vsystem("rm -rf %s", DOC_TMP_DIR); /* REALLY exit! */ if (RunningAsInit) { /* Put the console back */ ioctl(0, VT_ACTIVATE, 2); #ifdef __alpha__ reboot(RB_HALT); #else reboot(0); #endif } else exit(status); } /* Run some general command */ int systemExecute(char *command) { int status; struct termios foo; WINDOW *w = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; tcsetattr(0, TCSANOW, &foo); } if (!Fake) status = system(command); else { status = 0; msgDebug("systemExecute: Faked execution of `%s'\n", command); } DialogActive = TRUE; restorescr(w); return status; } /* suspend/resume libdialog/curses screen */ static WINDOW *oldW; void systemSuspendDialog(void) { oldW = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; } void systemResumeDialog(void) { DialogActive = TRUE; restorescr(oldW); } /* Display a help file in a filebox */ int systemDisplayHelp(char *file) { char *fname = NULL; char buf[FILENAME_MAX]; int ret = 0; WINDOW *w = savescr(); fname = systemHelpFile(file, buf); if (!fname) { snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file); use_helpfile(NULL); use_helpline(NULL); dialog_mesgbox("Sorry!", buf, -1, -1); ret = 1; } else { use_helpfile(NULL); use_helpline(NULL); dialog_textbox(file, fname, LINES, COLS); } restorescr(w); return ret; } char * systemHelpFile(char *file, char *buf) { if (!file) return NULL; if (file[0] == '/') return file; snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.hlp", file); if (file_readable(buf)) return buf; snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.TXT", file); if (file_readable(buf)) return buf; return NULL; } void systemChangeTerminal(char *color, const u_char c_term[], char *mono, const u_char m_term[]) { if (OnVTY) { int setupterm(char *color, int, int *); if (ColorDisplay) { setenv("TERM", color, 1); setenv("TERMCAP", c_term, 1); reset_shell_mode(); setterm(color); cbreak(); noecho(); } else { setenv("TERM", mono, 1); setenv("TERMCAP", m_term, 1); reset_shell_mode(); setterm(mono); cbreak(); noecho(); } } clear(); refresh(); dialog_clear(); } int vsystem(char *fmt, ...) { va_list args; int pstat; pid_t pid; int omask; sig_t intsave, quitsave; char *cmd; int i; cmd = (char *)alloca(FILENAME_MAX); cmd[0] = '\0'; va_start(args, fmt); vsnprintf(cmd, FILENAME_MAX, fmt, args); va_end(args); omask = sigblock(sigmask(SIGCHLD)); if (Fake) { msgDebug("vsystem: Faked execution of `%s'\n", cmd); return 0; } if (isDebug()) msgDebug("Executing command `%s'\n", cmd); pid = fork(); if (pid == -1) { (void)sigsetmask(omask); i = 127; } else if (!pid) { /* Junior */ (void)sigsetmask(omask); if (DebugFD != -1) { dup2(DebugFD, 0); dup2(DebugFD, 1); dup2(DebugFD, 2); } else { close(1); open("/dev/null", O_WRONLY); dup2(1, 2); } if (!RunningAsInit) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); else execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL); exit(1); } else { intsave = signal(SIGINT, SIG_IGN); quitsave = signal(SIGQUIT, SIG_IGN); pid = waitpid(pid, &pstat, 0); (void)sigsetmask(omask); (void)signal(SIGINT, intsave); (void)signal(SIGQUIT, quitsave); i = (pid == -1) ? -1 : WEXITSTATUS(pstat); if (isDebug()) msgDebug("Command `%s' returns status of %d\n", cmd, i); } return i; } void systemCreateHoloshell(void) { int waitstatus; if ((FixItMode || OnVTY) && RunningAsInit) { if (ehs_pid != 0) { int pstat; if (kill(ehs_pid, 0) == 0) { - if (msgYesNo("There seems to be an emergency holographic shell\n" + if (msgNoYes("There seems to be an emergency holographic shell\n" "already running on VTY 4.\n\n" "Kill it and start a new one?")) return; /* try cleaning up as much as possible */ (void) kill(ehs_pid, SIGHUP); sleep(1); (void) kill(ehs_pid, SIGKILL); } /* avoid too many zombies */ (void) waitpid(ehs_pid, &pstat, WNOHANG); } if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) systemSuspendDialog(); /* must be before the fork() */ if ((ehs_pid = fork()) == 0) { int i, fd; struct termios foo; extern int login_tty(int); ioctl(0, TIOCNOTTY, NULL); for (i = getdtablesize(); i >= 0; --i) close(i); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) fd = open("/dev/console", O_RDWR); else fd = open("/dev/ttyv3", O_RDWR); ioctl(0, TIOCSCTTY, &fd); dup2(0, 1); dup2(0, 2); DebugFD = 2; if (login_tty(fd) == -1) msgDebug("Doctor: I can't set the controlling terminal.\n"); signal(SIGTTOU, SIG_IGN); if (tcgetattr(fd, &foo) != -1) { foo.c_cc[VERASE] = '\010'; if (tcsetattr(fd, TCSANOW, &foo) == -1) msgDebug("Doctor: I'm unable to set the erase character.\n"); } else msgDebug("Doctor: I'm unable to get the terminal attributes!\n"); if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) { printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n"); fflush(stdout); } execlp("sh", "-sh", 0); msgDebug("Was unable to execute sh for Holographic shell!\n"); exit(1); } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { WINDOW *w = savescr(); msgNotify("Starting an emergency holographic shell on VTY4"); sleep(2); restorescr(w); } else { (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for shell to finish it serial mode since there is no virtual console */ systemResumeDialog(); } } } } Index: head/usr.sbin/sysinstall/tcpip.c =================================================================== --- head/usr.sbin/sysinstall/tcpip.c (revision 70004) +++ head/usr.sbin/sysinstall/tcpip.c (revision 70005) @@ -1,582 +1,582 @@ /* * $FreeBSD$ * * Copyright (c) 1995 * Gary J Palmer. All rights reserved. * Copyright (c) 1996 * Jordan K. Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * All kinds of hacking also performed by jkh on this code. Don't * blame Gary for every bogosity you see here.. :-) * * -jkh */ #include "sysinstall.h" #include #include #include #include #include /* The help file for the TCP/IP setup screen */ #define TCP_HELPFILE "tcp" /* These are nasty, but they make the layout structure a lot easier ... */ static char hostname[HOSTNAME_FIELD_LEN], domainname[HOSTNAME_FIELD_LEN], gateway[IPADDR_FIELD_LEN], nameserver[INET6_ADDRSTRLEN]; static int okbutton, cancelbutton; static char ipaddr[IPADDR_FIELD_LEN], netmask[IPADDR_FIELD_LEN], extras[EXTRAS_FIELD_LEN]; static char ipv6addr[INET6_ADDRSTRLEN]; /* What the screen size is meant to be */ #define TCP_DIALOG_Y 0 #define TCP_DIALOG_X 8 #define TCP_DIALOG_WIDTH COLS - 16 #define TCP_DIALOG_HEIGHT LINES - 2 static Layout layout[] = { #define LAYOUT_HOSTNAME 0 { 1, 2, 25, HOSTNAME_FIELD_LEN - 1, "Host:", "Your fully-qualified hostname, e.g. foo.bar.com", hostname, STRINGOBJ, NULL }, #define LAYOUT_DOMAINNAME 1 { 1, 35, 20, HOSTNAME_FIELD_LEN - 1, "Domain:", "The name of the domain that your machine is in, e.g. bar.com", domainname, STRINGOBJ, NULL }, #define LAYOUT_GATEWAY 2 { 5, 2, 18, IPADDR_FIELD_LEN - 1, "IPv4 Gateway:", "IPv4 address of host forwarding packets to non-local destinations", gateway, STRINGOBJ, NULL }, #define LAYOUT_NAMESERVER 3 { 5, 35, 18, INET6_ADDRSTRLEN - 1, "Name server:", "IPv4 or IPv6 address of your local DNS server", nameserver, STRINGOBJ, NULL }, #define LAYOUT_IPADDR 4 { 10, 10, 18, IPADDR_FIELD_LEN - 1, "IPv4 Address:", "The IPv4 address to be used for this interface", ipaddr, STRINGOBJ, NULL }, #define LAYOUT_NETMASK 5 { 10, 35, 18, IPADDR_FIELD_LEN - 1, "Netmask:", "The netmask for this interface, e.g. 0xffffff00 for a class C network", netmask, STRINGOBJ, NULL }, #define LAYOUT_EXTRAS 6 { 14, 10, 37, HOSTNAME_FIELD_LEN - 1, "Extra options to ifconfig:", "Any interface-specific options to ifconfig you would like to add", extras, STRINGOBJ, NULL }, #define LAYOUT_OKBUTTON 7 { 19, 15, 0, 0, "OK", "Select this if you are happy with these settings", &okbutton, BUTTONOBJ, NULL }, #define LAYOUT_CANCELBUTTON 8 { 19, 35, 0, 0, "CANCEL", "Select this if you wish to cancel this screen", &cancelbutton, BUTTONOBJ, NULL }, { NULL }, }; #define _validByte(b) ((b) >= 0 && (b) <= 255) /* whine */ static void feepout(char *msg) { beep(); msgConfirm(msg); } /* Very basic IP address integrity check - could be drastically improved */ static int verifyIP(char *ip) { int a, b, c, d; if (ip && sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d) == 4 && _validByte(a) && _validByte(b) && _validByte(c) && _validByte(d) && (d != 255)) return 1; else return 0; } static int verifyIP6(char *ip) { struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; if (getaddrinfo(ip, NULL, &hints, &res) == 0) { freeaddrinfo(res); return 1; } return 0; } /* Check for the settings on the screen - the per-interface stuff is moved to the main handling code now to do it on the fly - sigh */ static int verifySettings(void) { if (!hostname[0]) feepout("Must specify a host name of some sort!"); else if (gateway[0] && strcmp(gateway, "NO") && !verifyIP(gateway)) feepout("Invalid gateway IPv4 address specified"); else if (nameserver[0] && !verifyIP(nameserver) && !verifyIP6(nameserver)) feepout("Invalid name server IP address specified"); else if (netmask[0] && (netmask[0] < '0' && netmask[0] > '3')) feepout("Invalid netmask value"); else if (ipaddr[0] && !verifyIP(ipaddr)) feepout("Invalid IPv4 address"); else return 1; return 0; } static void dhcpGetInfo(Device *devp) { /* If it fails, do it the old-fashioned way */ if (dhcpParseLeases("/var/db/dhclient.leases", hostname, domainname, nameserver, ipaddr, gateway, netmask) == -1) { FILE *ifp; char *cp, cmd[256], data[2048]; int i, j; /* Bah, now we have to kludge getting the information from ifconfig */ snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); ifp = popen(cmd, "r"); if (ifp) { j = fread(data, 1, sizeof(data), ifp); fclose(ifp); if (j < 0) /* paranoia */ j = 0; data[j] = '\0'; if (isDebug()) msgDebug("DHCP configured interface returns %s\n", data); /* XXX This is gross as it assumes a certain ordering to ifconfig's output! XXX */ if ((cp = strstr(data, "inet ")) != NULL) { i = 0; cp += 5; /* move over keyword */ while (*cp != ' ') ipaddr[i++] = *(cp++); ipaddr[i] = '\0'; if (!strncmp(++cp, "netmask", 7)) { i = 0; cp += 8; while (*cp != ' ') netmask[i++] = *(cp++); netmask[i] = '\0'; } } } } /* If we didn't get a name server value, hunt for it in resolv.conf */ if (!nameserver[0] && file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); if (hostname[0]) variable_set2(VAR_HOSTNAME, hostname, 0); } static void rtsolGetInfo(Device *devp) { FILE *ifp; char *cp, cmd[256], data[2048]; int i; snprintf(cmd, sizeof cmd, "ifconfig %s", devp->name); if ((ifp = popen(cmd, "r")) == NULL) return; while (fgets(data, sizeof(data), ifp) != NULL) { if (isDebug()) msgDebug("RTSOL configured interface returns %s", data); if ((cp = strstr(data, "inet6 ")) != NULL) { cp += 6; /* move over keyword */ if (strncmp(cp, "fe80:", 5)) { i = 0; while (*cp != ' ') ipv6addr[i++] = *(cp++); ipv6addr[i] = '\0'; } } } fclose(ifp); } /* This is it - how to get TCP setup values */ int tcpOpenDialog(Device *devp) { WINDOW *ds_win, *save = NULL; ComposeObj *obj = NULL; int n = 0, filled = 0, cancel = FALSE; int max, ret = DITEM_SUCCESS; int use_dhcp = FALSE; int use_rtsol = FALSE; char *tmp; char title[80]; save = savescr(); /* Initialise vars from previous device values */ if (devp->private) { DevInfo *di = (DevInfo *)devp->private; SAFE_STRCPY(ipaddr, di->ipaddr); SAFE_STRCPY(netmask, di->netmask); SAFE_STRCPY(extras, di->extras); use_dhcp = di->use_dhcp; use_rtsol = di->use_rtsol; } else { /* See if there are any defaults */ char *cp; /* Try a RTSOL scan if such behavior is desired */ if (!variable_cmp(VAR_TRY_RTSOL, "YES") || - ((!variable_cmp(VAR_TRY_RTSOL, "NO")) && (!msgYesNo("Do you want to try IPv6 configuration of the interface?")))) { + ((!variable_cmp(VAR_TRY_RTSOL, "NO")) && (!msgNoYes("Do you want to try IPv6 configuration of the interface?")))) { int i; int len; i = 0; sysctlbyname("net.inet6.ip6.forwarding", NULL, 0, &i, sizeof(i)); i = 1; sysctlbyname("net.inet6.ip6.accept_rtadv", NULL, 0, &i, sizeof(i)); vsystem("ifconfig %s up", devp->name); len = sizeof(i); sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); sleep(i + 1); Mkdir("/var/run"); msgNotify("Scanning for RA servers..."); if (0 == vsystem("rtsol %s", devp->name)) { len = sizeof(i); sysctlbyname("net.inet6.ip6.dad_count", &i, &len, NULL, 0); sleep(i + 1); rtsolGetInfo(devp); use_rtsol = TRUE; } else use_rtsol = FALSE; } /* First try a DHCP scan if such behavior is desired */ if (!variable_cmp(VAR_TRY_DHCP, "YES") || - ((!variable_cmp(VAR_TRY_DHCP, "NO")) && (!msgYesNo("Do you want to try DHCP configuration of the interface?")))) { + ((!variable_cmp(VAR_TRY_DHCP, "NO")) && (!msgNoYes("Do you want to try DHCP configuration of the interface?")))) { Mkdir("/var/db"); Mkdir("/var/run"); Mkdir("/tmp"); msgNotify("Scanning for DHCP servers..."); if (0 == vsystem("dhclient -1 %s", devp->name)) { dhcpGetInfo(devp); use_dhcp = TRUE; } else use_dhcp = FALSE; } /* Special hack so it doesn't show up oddly in the tcpip setup menu */ if (!strcmp(gateway, "NO")) gateway[0] = '\0'; /* Get old IP address from variable space, if available */ if (!ipaddr[0]) { if ((cp = variable_get(VAR_IPADDR)) != NULL) SAFE_STRCPY(ipaddr, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_IPADDR))) != NULL) SAFE_STRCPY(ipaddr, cp); } /* Get old netmask from variable space, if available */ if (!netmask[0]) { if ((cp = variable_get(VAR_NETMASK)) != NULL) SAFE_STRCPY(netmask, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_NETMASK))) != NULL) SAFE_STRCPY(netmask, cp); } /* Get old extras string from variable space, if available */ if (!extras[0]) { if ((cp = variable_get(VAR_EXTRAS)) != NULL) SAFE_STRCPY(extras, cp); else if ((cp = variable_get(string_concat3(devp->name, "_", VAR_EXTRAS))) != NULL) SAFE_STRCPY(extras, cp); } } /* Look up values already recorded with the system, or blank the string variables ready to accept some new data */ if (!hostname[0]) { tmp = variable_get(VAR_HOSTNAME); if (tmp) SAFE_STRCPY(hostname, tmp); } if (!domainname[0]) { tmp = variable_get(VAR_DOMAINNAME); if (tmp) SAFE_STRCPY(domainname, tmp); } if (!gateway[0]) { tmp = variable_get(VAR_GATEWAY); if (tmp && strcmp(tmp, "NO")) SAFE_STRCPY(gateway, tmp); } if (!nameserver[0]) { tmp = variable_get(VAR_NAMESERVER); if (tmp) SAFE_STRCPY(nameserver, tmp); } /* If non-interactive, jump straight over the dialog crap and into config section */ if (variable_get(VAR_NONINTERACTIVE) && !variable_get(VAR_NETINTERACTIVE)) { if (!hostname[0]) msgConfirm("WARNING: hostname variable not set and is a non-optional\n" "parameter. Please add this to your installation script\n" "or set the netInteractive variable (see sysinstall man page)"); else goto netconfig; } /* Now do all the screen I/O */ dialog_clear_norefresh(); /* We need a curses window */ tmp = " Network Configuration "; if (ipv6addr[0]) tmp = string_concat(tmp, "(IPv6 ready) "); if (!(ds_win = openLayoutDialog(TCP_HELPFILE, tmp, TCP_DIALOG_X, TCP_DIALOG_Y, TCP_DIALOG_WIDTH, TCP_DIALOG_HEIGHT))) { beep(); msgConfirm("Cannot open TCP/IP dialog window!!"); restorescr(save); return DITEM_FAILURE; } /* Draw interface configuration box */ draw_box(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 8, TCP_DIALOG_HEIGHT - 13, TCP_DIALOG_WIDTH - 17, dialog_attr, border_attr); wattrset(ds_win, dialog_attr); sprintf(title, " Configuration for Interface %s ", devp->name); mvwaddstr(ds_win, TCP_DIALOG_Y + 9, TCP_DIALOG_X + 14, title); /* Some more initialisation before we go into the main input loop */ obj = initLayoutDialog(ds_win, layout, TCP_DIALOG_X, TCP_DIALOG_Y, &max); reenter: cancelbutton = okbutton = 0; while (layoutDialogLoop(ds_win, layout, &obj, &n, max, &cancelbutton, &cancel)) { /* Prevent this from being irritating if user really means NO */ if (filled < 3) { /* Insert a default value for the netmask, 0xffffff00 is * the most appropriate one (entire class C, or subnetted * class A/B network). */ if (!netmask[0]) { strcpy(netmask, "255.255.255.0"); RefreshStringObj(layout[LAYOUT_NETMASK].obj); ++filled; } if (!index(hostname, '.') && domainname[0]) { strcat(hostname, "."); strcat(hostname, domainname); RefreshStringObj(layout[LAYOUT_HOSTNAME].obj); ++filled; } else if (((tmp = index(hostname, '.')) != NULL) && !domainname[0]) { SAFE_STRCPY(domainname, tmp + 1); RefreshStringObj(layout[LAYOUT_DOMAINNAME].obj); ++filled; } } } if (!cancel && !verifySettings()) goto reenter; /* Clear this crap off the screen */ delwin(ds_win); dialog_clear_norefresh(); use_helpfile(NULL); /* We actually need to inform the rest of sysinstall about this data now if the user hasn't selected cancel. Save the stuff out to the environment via the variable_set() mechanism */ netconfig: if (!cancel) { DevInfo *di; char temp[512], ifn[255]; char *ifaces; char *pccard; int ipv4_enable = FALSE; if (hostname[0]) { variable_set2(VAR_HOSTNAME, hostname, 1); sethostname(hostname, strlen(hostname)); } if (domainname[0]) variable_set2(VAR_DOMAINNAME, domainname, 0); if (gateway[0]) variable_set2(VAR_GATEWAY, gateway, use_dhcp ? 0 : 1); if (nameserver[0]) variable_set2(VAR_NAMESERVER, nameserver, 0); if (ipaddr[0]) variable_set2(VAR_IPADDR, ipaddr, 0); if (ipv6addr[0]) variable_set2(VAR_IPV6ADDR, ipv6addr, 0); if (!devp->private) devp->private = (DevInfo *)safe_malloc(sizeof(DevInfo)); di = devp->private; SAFE_STRCPY(di->ipaddr, ipaddr); SAFE_STRCPY(di->netmask, netmask); SAFE_STRCPY(di->extras, extras); di->use_dhcp = use_dhcp; di->use_rtsol = use_rtsol; if (use_dhcp || ipaddr[0]) ipv4_enable = TRUE; if (ipv4_enable) { sprintf(ifn, "%s%s", VAR_IFCONFIG, devp->name); if (use_dhcp) sprintf(temp, "DHCP"); else sprintf(temp, "inet %s %s netmask %s", ipaddr, extras, netmask); variable_set2(ifn, temp, 1); } pccard = variable_get("_pccard_install"); if (pccard && strcmp(pccard, "YES") == 0 && ipv4_enable) { variable_set2("pccard_ifconfig", temp, 1); } ifaces = variable_get(VAR_INTERFACES); if (!ifaces) variable_set2(VAR_INTERFACES, ifaces = "lo0", 1); /* Only add it if it's not there already */ if (strcmp(ifaces, "auto") && !strstr(ifaces, devp->name)) { sprintf(ifn, "%s %s", devp->name, ifaces); variable_set2(VAR_INTERFACES, ifn, 1); } if (use_rtsol) variable_set2(VAR_IPV6_ENABLE, "YES", 1); if (!use_dhcp) configResolv(NULL); /* XXX this will do it on the MFS copy XXX */ ret = DITEM_SUCCESS; } else ret = DITEM_FAILURE; restorescr(save); return ret; } static Device *NetDev; static int netHook(dialogMenuItem *self) { Device **devs; devs = deviceFindDescr(self->prompt, self->title, DEVICE_TYPE_NETWORK); if (devs) { if (DITEM_STATUS(tcpOpenDialog(devs[0])) != DITEM_FAILURE) NetDev = devs[0]; else NetDev = NULL; } return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE; } /* Get a network device */ Device * tcpDeviceSelect(void) { DMenu *menu; Device **devs, *rval; int cnt; devs = deviceFind(NULL, DEVICE_TYPE_NETWORK); cnt = deviceCount(devs); rval = NULL; if (!cnt) { msgConfirm("No network devices available!"); return NULL; } else if ((!RunningAsInit) && (variable_check("NETWORK_CONFIGURED=NO") != TRUE)) { if (!msgYesNo("Running multi-user, assume that the network is already configured?")) return devs[0]; } if (cnt == 1) { if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) rval = devs[0]; } else if (variable_get(VAR_NONINTERACTIVE) && variable_get(VAR_NETWORK_DEVICE)) { devs = deviceFind(variable_get(VAR_NETWORK_DEVICE), DEVICE_TYPE_NETWORK); cnt = deviceCount(devs); if (cnt) { if (DITEM_STATUS(tcpOpenDialog(devs[0]) == DITEM_SUCCESS)) rval = devs[0]; } } else { int status; menu = deviceCreateMenu(&MenuNetworkDevice, DEVICE_TYPE_NETWORK, netHook, NULL); if (!menu) msgFatal("Unable to create network device menu! Argh!"); status = dmenuOpenSimple(menu, FALSE); free(menu); if (status) rval = NetDev; } return rval; } /* Do it from a menu that doesn't care about status */ int tcpMenuSelect(dialogMenuItem *self) { Device *tmp; WINDOW *save; variable_set("NETWORK_CONFIGURED=NO",0); tmp = tcpDeviceSelect(); variable_unset("NETWORK_CONFIGURED"); save = savescr(); if (tmp && tmp->private && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name)) if (!tmp->init(tmp)) msgConfirm("Initialization of %s device failed.", tmp->name); restorescr(save); return DITEM_SUCCESS; }