Index: stable/2.2/release/sysinstall/disks.c =================================================================== --- stable/2.2/release/sysinstall/disks.c (revision 30347) +++ stable/2.2/release/sysinstall/disks.c (revision 30348) @@ -1,705 +1,731 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: disks.c,v 1.70.2.18 1997/09/11 17:21:12 jkh Exp $ + * $Id: disks.c,v 1.70.2.19 1997/09/17 16:35:33 pst Exp $ * * 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 /* 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, Disk *d); +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 row; int i; for (i = Total = 0; chunk_info[i]; i++) Total += chunk_info[i]->size; 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); } 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", d->bios_cyl, d->bios_hd, d->bios_sect, d->bios_cyl * d->bios_hd * d->bios_sect); mvprintw(3, 0, "%10s %10s %10s %8s %6s %10s %8s %8s", "Offset", "Size", "End", "Name", "PType", "Desc", "Subtype", "Flags"); for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) { if (i == current_chunk) attrset(ATTR_SELECTED); mvprintw(row, 0, "%10ld %10lu %10lu %8s %6d %10s %8d\t%-6s", chunk_info[i]->offset, chunk_info[i]->size, 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 B = Bad Block Scan C = Create Slice"); mvprintw(17, 0, "D = Delete Slice G = Set Drive Geometry 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); } static u_char * getBootMgr(char *dname) { extern u_char mbr[], bteasy17[]; 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: return bteasy17; case 1: return mbr; case 2: default: break; } } return NULL; } +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, Disk *d) +diskPartition(Device *dev) { char *cp, *p; int rv, key = 0; Boolean chunking; char *msg = NULL; u_char *mbrContents; WINDOW *w = savescr(); + Disk *d = (Disk *)dev->private; 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); 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': 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; } All_FreeBSD(d, rv); variable_set2(DISK_PARTITIONED, "yes"); record_chunks(d); clear(); break; case 'B': if (chunk_info[current_chunk]->type != freebsd) msg = "Can only scan for bad blocks in FreeBSD slice."; else if (strncmp(d->name, "sd", 2) || !msgYesNo("This typically makes sense only for ESDI, IDE or MFM drives.\n" "Are you sure you want to do this on a SCSI disk?")) { if (chunk_info[current_chunk]->flags & CHUNK_BAD144) chunk_info[current_chunk]->flags &= ~CHUNK_BAD144; else chunk_info[current_chunk]->flags |= CHUNK_BAD144; } 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, subtype; chunk_e partitiontype; snprintf(tmp, 20, "%d", 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; strcpy(tmp, "165"); 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 == 165) partitiontype = freebsd; else if (subtype == 6) partitiontype = fat; else partitiontype = unknown; Create_Chunk(d, chunk_info[current_chunk]->offset, size, partitiontype, subtype, (chunk_info[current_chunk]->flags & CHUNK_ALIGN)); variable_set2(DISK_PARTITIONED, "yes"); record_chunks(d); } } 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"); 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; WINDOW *save = savescr(); strcpy(tmp, "165"); 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 PAT 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."); if (val && (subtype = strtol(val, NULL, 0)) > 0) { if (subtype == 165) partitiontype = freebsd; else if (subtype == 6) partitiontype = fat; else partitiontype = unknown; chunk_info[current_chunk]->type = partitiontype; chunk_info[current_chunk]->subtype = subtype; } restorescr(save); } 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?")) { 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 ((cp = variable_get(DISK_LABELLED)) && !strcmp(cp, "written")) { msgConfirm("You've already written this information out - if\n" "you wish to overwrite it, you'll have to restart."); } else if (!msgYesNo("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" + "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"); /* 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 (!(d->chunks->part->flags & CHUNK_FORCE_ALL) && (mbrContents = getBootMgr(d->name)) != NULL) Set_Boot_Mgr(d, mbrContents); 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" "No seat belts whatsoever are provided!")) { clear(); refresh(); slice_wizard(d); variable_set2(DISK_PARTITIONED, "yes"); 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 ((d->chunks->part->flags & CHUNK_FORCE_ALL) != CHUNK_FORCE_ALL && (mbrContents = getBootMgr(d->name)) != NULL) Set_Boot_Mgr(d, mbrContents); break; default: beep(); msg = "Type F1 or ? for help"; break; } } p = CheckRules(d); if (p) { char buf[FILENAME_MAX]; dialog_clear_norefresh(); 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 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], (Disk *)devs[0]->private); + diskPartition(devs[0]); } else devs[0]->enabled = FALSE; - return DITEM_SUCCESS | DITEM_REDRAW; + return DITEM_SUCCESS | DITEM_RESTORE; } 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; - char *cp; - cp = variable_get(VAR_DISK); - devs = deviceFind(cp, DEVICE_TYPE_DISK); - cnt = deviceCount(devs); - if (!cnt) { + 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."); - i = DITEM_FAILURE; + return DITEM_FAILURE; } - else if (cnt == 1) { - devs[0]->enabled = TRUE; - if (variable_get(VAR_NONINTERACTIVE)) - diskPartitionNonInteractive(devs[0], (Disk *)devs[0]->private); - else - diskPartition(devs[0], (Disk *)devs[0]->private); - i = DITEM_SUCCESS; + else if (cnt) { + /* Some are already selected */ + for (i = 0; i < cnt; i++) { + if (devs[i]->enabled) { + if (variable_get(VAR_NONINTERACTIVE)) + diskPartitionNonInteractive(devs[i]); + else + diskPartition(devs[i]); + } + } } 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."); - i = DITEM_FAILURE; + /* No disks are selected, fall-back case now */ + cnt = deviceCount(devs); + if (cnt == 1) { + devs[0]->enabled = TRUE; + if (variable_get(VAR_NONINTERACTIVE)) + diskPartitionNonInteractive(devs[0]); + else + diskPartition(devs[0]); + return DITEM_SUCCESS; } else { - i = dmenuOpenSimple(menu, FALSE) ? DITEM_SUCCESS : DITEM_FAILURE; - free(menu); + 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 | DITEM_RESTORE; } - i = i | DITEM_RESTORE; } - return i; + return DITEM_FAILURE; } int diskPartitionWrite(dialogMenuItem *self) { Device **devs; - char *cp; int i; - if ((cp = variable_get(DISK_PARTITIONED)) && strcmp(cp, "yes")) - return DITEM_SUCCESS; - else if (!cp) { - msgConfirm("You must partition the disk(s) before this option can be used."); - return DITEM_FAILURE; - } - 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)); for (i = 0; devs[i]; i++) { Chunk *c1; Disk *d = (Disk *)devs[i]->private; if (!devs[i]->enabled) continue; Set_Boot_Blocks(d, boot1, boot2); 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; } /* Now scan for bad blocks, if necessary */ for (c1 = d->chunks->part; c1; c1 = c1->next) { if (c1->flags & CHUNK_BAD144) { int ret; msgNotify("Running bad block scan on slice %s", c1->name); if (!Fake) { ret = vsystem("bad144 -v /dev/r%s 1234", c1->name); if (ret) msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret); ret = vsystem("bad144 -v -s /dev/r%s", c1->name); if (ret) msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret); } } } } /* Now it's not "yes", but "written" */ variable_set2(DISK_PARTITIONED, "written"); return DITEM_SUCCESS; } /* Partition a disk based wholly on which variables are set */ static void -diskPartitionNonInteractive(Device *dev, Disk *d) +diskPartitionNonInteractive(Device *dev) { char *cp; int i, sz, all_disk = 0; u_char *mbrContents; + 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)) { Create_Chunk(d, chunk_info[i]->offset, chunk_info[i]->size, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); variable_set2(DISK_PARTITIONED, "yes"); break; } } if (!chunk_info[i]) { dialog_clear(); 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; 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) { Create_Chunk(d, chunk_info[i]->offset, sz, freebsd, 3, (chunk_info[i]->flags & CHUNK_ALIGN)); variable_set2(DISK_PARTITIONED, "yes"); break; } } if (!chunk_info[i]) { dialog_clear(); 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]) { dialog_clear(); msgConfirm("Unable to find any existing FreeBSD partitions on this disk!"); return; } } else { dialog_clear(); msgConfirm("`%s' is an invalid value for %s - is config file valid?", cp, VAR_PARTITION); return; } if (!all_disk) { mbrContents = getBootMgr(d->name); Set_Boot_Mgr(d, mbrContents); } variable_set2(DISK_PARTITIONED, "yes"); } } Index: stable/2.2/release/sysinstall/help/register.hlp =================================================================== --- stable/2.2/release/sysinstall/help/register.hlp (revision 30347) +++ stable/2.2/release/sysinstall/help/register.hlp (revision 30348) @@ -1,75 +1,76 @@ This screen allows you to register yourself with the FreeBSD Project's user counter & statistics database. ** IT IS VERY IMPORTANT THAT YOU DO THIS! ** Believe me, I hate filling out forms as much as anyone, and most people's understandable reaction to a registration form is to say "Eh, what's this? They want to send me junk mail and then on top of that they expect me to go to *extra* trouble in order to make it easy for them?! Forget it!" This is not that kind of registration, and I strongly urge you to take just a few minutes to read this and find out how much the simple act of registering can help both you and FreeBSD. 1. It is very much in your best interest, as a FreeBSD user, to stand up and be counted so that various software vendors will begin to take you and your operating system seriously. There are numerous ISVs (Independent Software Vendors) who would be only too happy to port the kinds of applications that many FreeBSD users are currently screaming for (everything from spreadsheets and word processing packages to games) if they only had some idea that it might be worth the trouble. The only way to convince the ISVs that FreeBSD is worth their trouble is to show them how many users we have, and to do that we need your registration! At this time we literally do not know how many users FreeBSD has, and that's hardly helpful when you're trying to convince someone to port software to it. 2. We will not send you *anything* you do not ask for. Some people are genuinely interested in new product announcements for FreeBSD or want to hear about security issues & other important advisories as they come up, and for such people we've added registration options for selecting various types of additional material they might be interested in receiving as a side-effect of registration. The default behavior is to NOT put the user on any special mailing lists or provide their names in mailing list data sent to (carefully screened) FreeBSD product advertisers - all of that must be specifically requested during the registration. Most fields in the form are fairly self-explanatory. At the minimum, you should enter your first and last name as well as your email address so that we can weed obvious duplicates from the counter. You will NOT be sent any mail at this address unless you also sign up for one of the additional notification services, and it's only used to provide us with a way of differentiating "John Smith " from "John Smith " in the simple, no-frills registration case. If you do not have an email address, some sort of postal address will serve the same purpose. -If you also wish to receive the upcoming FreeBSD Newsletter (soon to -published and distributed free of charge by Walnut Creek CDROM) in -printed form, then you must specify some sort of postal address. -Likewise, if you elect to receive the email version then you should -specify a valid Email address. +If you also wish to receive the FreeBSD Newsletter, published and +distributed free of charge by Walnut Creek CDROM in printed form, +then you must specify some sort of postal address. Likewise, if you +elect to receive notification on the email version then you should +specify a valid Email address. Back-issues of the FreeBSD newsletter +are available at http://ftp.freebsd.org/pub/FreeBSD/newsletter/ Should you wish to unsubscribe to the FreeBSD Newsletter or otherwise de-register yourself at a later time, you can simply send mail to register-request@freebsd.org. If you subscribe to the announce mailing list (and it's a good idea) then you can modify your subscription at any time by sending mail to majordomo@freebsd.org Your cooperation with this new registration service is greatly appreciated, and by taking just 5 minutes to fill this out now you will be helping us to gather data which will greatly assist FreeBSD in firmly establishing a position as a serious UN*X operating system contender. Regards, Jordan Hubbard, FreeBSD PR Officer Index: stable/2.2/release/sysinstall/help/upgrade.hlp =================================================================== --- stable/2.2/release/sysinstall/help/upgrade.hlp (revision 30347) +++ stable/2.2/release/sysinstall/help/upgrade.hlp (revision 30348) @@ -1,38 +1,38 @@ -Welcome to the 2.1.x (or 2.0.5) -> 2.2 upgrade procedure! +Welcome to the 2.2.5 upgrade procedure! It must first be said that this upgrade DOES NOT take a particularly sophisticated approach to the upgrade problem, it being more a question of providing what seemed "good enough" at the time. A truly polished upgrade that deals properly with the broad spectrum of -installed 2.0.5 / 2.1.x systems would be nice to have, but until that -gets written what you get is this - the brute-force approach! +installed 2.x systems would be nice to have, but until that gets +written what you get is this - the brute-force approach! What this upgrade will attempt to do is best summarized thusly: 1. fsck and mount all file systems chosen in the label editor. - 2. Ask for a location to preserve your /etc directory into and do so. + 2. Ask for a location to preserve your /etc directory into. 3. Extract all selected distributions on top of your existing system. 4. Copy certain obvious files back from the preserved /etc, leaving the rest of the /etc file merge up to the user. 5. Drop user in a shell so that they may perform that merge before rebooting into the new system. -And that's it! This "upgrade" is not going to hold your hand in all -major respects, it's simply provided to make one PART of the upgrade +And that's it! This "upgrade" is not going to hold your hand to any +major degree, it's simply provided to make one PART of the upgrade easier. IMPORTANT NOTE: What this upgrade procedure may also do, in fact, is completely destroy your system (though much more quickly than you would have been able to destroy it yourself). It is simply impossible to guarantee that this procedure's crude form of upgrade automation will work in all cases and if you do this upgrade without proper BACKUPS for any important data then you really must like living life close to the edge, that's all we can say! NOTE to 2.0 users: We're sorry, but the "slice" changes that were added in FreeBSD 2.0.5 made automated upgrades pretty difficult due to the fact that a complete reinstall is pretty much called for. Things may still *work* after an upgrade, but you will also no doubt receive many warnings at boot time about non-aligned slices and such; we really do recommend a fresh installation for 2.0 systems! (But back up your user data first :-). Index: stable/2.2/release/sysinstall/install.c =================================================================== --- stable/2.2/release/sysinstall/install.c (revision 30347) +++ stable/2.2/release/sysinstall/install.c (revision 30348) @@ -1,1128 +1,1134 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: install.c,v 1.134.2.59 1997/10/06 08:35:15 jkh Exp $ + * $Id: install.c,v 1.134.2.60 1997/10/06 08:37:40 jkh Exp $ * * 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 "uc_main.h" #include #include #include #include #include #include #include #define MSDOSFS #include #undef MSDOSFS #include #include static void create_termcap(void); static void fixit_common(void); #ifdef SAVE_USERCONFIG static void save_userconfig_to_kernel(char *); #endif #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 (c2->flags & CHUNK_IS_ROOT) { 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; } if (!usrdev && whinge) { msgConfirm("WARNING: No /usr filesystem found. This is not technically\n" "an error if your root filesystem is big enough (or you later\n" "intend to mount your /usr filesystem over NFS), but it may otherwise\n" "cause you trouble if you're not exactly sure what you are doing!"); } - if (!vardev && whinge) { + if (!vardev && whinge && variable_cmp(SYSTEM_STATE, "upgrade")) { msgConfirm("WARNING: No /var filesystem found. This is not technically\n" "an error if your root filesystem is big enough (or you later\n" "intend to link /var to someplace else), but it may otherwise\n" "cause your root filesystem to fill up if you receive lots of mail\n" "or edit large temporary files."); } return status; } static int installInitial(void) { static Boolean alreadyDone = FALSE; 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"); /* If we refuse to proceed, bail. */ dialog_clear_norefresh(); 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 | DITEM_RESTORE; if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) { msgConfirm("Couldn't make filesystems properly. Aborting."); return DITEM_FAILURE; } else if (isDebug()) msgDebug("installInitial: Scribbled successfully on the disk(s)\n"); if (!copySelf()) { msgConfirm("Couldn't clone the boot floppy onto the root file system.\n" "Aborting."); return DITEM_FAILURE; } if (chroot("/mnt") == -1) { msgConfirm("Unable to chroot to %s - this is bad!", "/mnt"); return DITEM_FAILURE; } chdir("/"); variable_set2(RUNNING_ON_ROOT, "yes"); configResolv(); /* stick a helpful shell over on the 4th VTY */ systemCreateHoloshell(); alreadyDone = TRUE; return DITEM_SUCCESS; } int installFixitHoloShell(dialogMenuItem *self) { systemCreateHoloshell(); return DITEM_SUCCESS; } int installFixitCDROM(dialogMenuItem *self) { struct stat sb; if (!RunningAsInit) return DITEM_SUCCESS; variable_set2(SYSTEM_STATE, "fixit"); (void)unlink("/mnt2"); (void)rmdir("/mnt2"); while (1) { msgConfirm("Please insert the second FreeBSD 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 */ if (mediaDevice) { mediaDevice->shutdown(mediaDevice); mediaDevice = NULL; } 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 another iggly hardcoded pathname. */ if (!file_readable("/usr/libexec/ld.so")) { Mkdir("/usr/libexec"); if (symlink("/mnt2/usr/libexec/ld.so", "/usr/libexec/ld.so")) { msgConfirm("Warning: could not create the symlink for ld.so.\n" "Dynamic executables from the CDROM likely won't work."); } } fixit_common(); mediaDevice->shutdown(mediaDevice); msgConfirm("Please remove the FreeBSD CDROM now."); return DITEM_SUCCESS; } int installFixitFloppy(dialogMenuItem *self) { struct ufs_args args; if (!RunningAsInit) return DITEM_SUCCESS; variable_set2(SYSTEM_STATE, "fixit"); memset(&args, 0, sizeof(args)); args.fspec = "/dev/fd0"; Mkdir("/mnt2"); while (1) { msgConfirm("Please insert a writable fixit floppy and press return"); if (mount(MOUNT_UFS, "/mnt2", 0, (caddr_t)&args) != -1) break; msgConfirm("An attempt to mount the fixit floppy failed, maybe the filesystem\n" "is unclean. Trying a forcible mount as a last resort..."); if (mount(MOUNT_UFS, "/mnt2", MNT_FORCE, (caddr_t)&args) != -1) break; if (msgYesNo("Unable to mount the fixit floppy - do you want to try again?") != 0) return DITEM_FAILURE; } if (!directory_exists("/tmp")) (void)symlink("/mnt2/tmp", "/tmp"); fixit_common(); unmount("/mnt2", MNT_FORCE); 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 (!(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); 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); /* 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 { 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."); (void)waitpid(child, &waitstatus, 0); } dialog_clear(); } int installExpress(dialogMenuItem *self) { int i; variable_set2(SYSTEM_STATE, "express"); if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE) return i; if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE) return i; dialog_clear_norefresh(); if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) { i |= DITEM_LEAVE_MENU; /* Give user the option of one last configuration spree */ installConfigure(); } return i | DITEM_RESTORE; } /* Novice mode installation */ int installNovice(dialogMenuItem *self) { - int i; + int i, tries = 0; + Device **devs; variable_set2(SYSTEM_STATE, "novice"); dialog_clear_norefresh(); 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; + } + dialog_clear_norefresh(); msgConfirm("Next, 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."); if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) return DITEM_FAILURE; dialog_clear_norefresh(); if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) { dialog_clear_norefresh(); 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 chose \"No\" at the next\n" "prompt and go back into the installation menus to try and retry\n" "whichever operations have failed."); return i | DITEM_RESTORE; } else { dialog_clear_norefresh(); 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; dialog_clear_norefresh(); tmp = tcpDeviceSelect(); dialog_clear_norefresh(); if (tmp && !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 an IP gateway (e.g. will it forward packets\n" "between interfaces)?")) variable_set2("gateway", "YES"); dialog_clear_norefresh(); if (!msgYesNo("Do you want to allow anonymous FTP connections to this machine?")) configAnonFTP(self); dialog_clear_norefresh(); if (!msgYesNo("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?")) variable_set2("nfs_client", "YES"); dialog_clear_norefresh(); if (!msgYesNo("Would you like to customize your system console settings?")) { WINDOW *w = savescr(); dmenuOpenSimple(&MenuSyscons, FALSE); restorescr(w); } dialog_clear_norefresh(); if (!msgYesNo("Would you like to set this machine's time zone now?")) { WINDOW *w = savescr(); dialog_clear(); systemExecute("tzsetup"); restorescr(w); } dialog_clear_norefresh(); if (!msgYesNo("Does this system have a mouse attached to it?")) { WINDOW *w = savescr(); dmenuOpenSimple(&MenuMouse, FALSE); restorescr(w); } /* Now would be a good time to checkpoint the configuration data */ configRC_conf("/etc/rc.conf"); sync(); #ifndef USE_XIG_ENVIRONMENT if (directory_exists("/usr/X11R6")) { dialog_clear_norefresh(); if (!msgYesNo("Would you like to configure your X server at this time?")) configXEnvironment(self); } #endif dialog_clear_norefresh(); if (!msgYesNo("The FreeBSD package collection is a collection of hundreds 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?")) configPackages(self); dialog_clear_norefresh(); 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).")) configUsers(self); dialog_clear_norefresh(); msgConfirm("Now you must set the system manager's password.\n" "This is the password you'll use to log in as \"root\"."); { WINDOW *w = savescr(); if (!systemExecute("passwd root")) variable_set2("root_password", "YES"); restorescr(w); } dialog_clear_norefresh(); if (!msgYesNo("Would you like to register your FreeBSD system at this time?\n\n" "PLEASE, take just 5 minutes to do this. If we're ever to get any\n" "significant base of commercial software for FreeBSD, we need to\n" "be able to provide more information about the size of our user community.\n" "This is where your registration can really help us, and you can also\n" "sign up for the new FreeBSD newsletter (its free!) at the same time.\n")) configRegister(NULL); else { dialog_clear_norefresh(); msgConfirm("OK, but if you should change your mind then you always can register\n" "later by typing ``/stand/sysinstall register'' or by simply visiting our\n" "web site at http://www.freebsd.org/register.html"); } /* 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 | DITEM_RESTORE; } /* The version of commit we call from the Install Custom menu */ int installCustomCommit(dialogMenuItem *self) { int i; dialog_clear_norefresh(); i = installCommit(self); if (DITEM_STATUS(i) == DITEM_SUCCESS) { /* 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 DES dist. */ int installCommit(dialogMenuItem *self) { int i; char *str; Boolean need_bin; if (!Dists) distConfig(NULL); if (!Dists) if (!dmenuOpenSimple(&MenuDistributions, FALSE) && !Dists) return DITEM_FAILURE | DITEM_RESTORE; if (!mediaVerify()) return DITEM_FAILURE | DITEM_RESTORE; str = variable_get(SYSTEM_STATE); if (isDebug()) msgDebug("installCommit: System state is `%s'\n", str); if (RunningAsInit) { /* Do things we wouldn't do to a multi-user system */ if (DITEM_STATUS((i = installInitial())) == DITEM_FAILURE) return i; if (DITEM_STATUS((i = configFstab())) == 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 | DITEM_RESTORE; else goto try_media; } else return DITEM_FAILURE | DITEM_RESTORE; } need_bin = Dists & DIST_BIN; i = distExtractAll(self); if (DITEM_STATUS(i) == DITEM_SUCCESS) { if (need_bin && !(Dists & DIST_BIN)) i = installFixup(self); } variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install"); /* We always try to install X with the XiG product */ #ifdef USE_XIG_ENVIRONMENT if (directory_exists("/usr/X11R6")) configXEnvironment(self); #endif return i | DITEM_RESTORE; } static void installConfigure(void) { /* Final menu of last resort */ dialog_clear_norefresh(); if (!msgYesNo("Visit the general configuration menu for a chance to set\n" "any last options?")) { WINDOW *w = savescr(); dmenuOpenSimple(&MenuConfigure, FALSE); restorescr(w); } configRC_conf("/etc/rc.conf"); sync(); } int installFixup(dialogMenuItem *self) { Device **devs; int i; if (!file_readable("/kernel")) { if (file_readable("/kernel.GENERIC")) { #ifdef SAVE_USERCONFIG /* Snapshot any boot -c changes back to the GENERIC kernel */ - if (!strcmp(variable_get(VAR_RELNAME), RELEASE_NAME)) + if (!variable_cmp(VAR_RELNAME, RELEASE_NAME)) save_userconfig_to_kernel("/kernel.GENERIC"); #endif if (vsystem("cp -p /kernel.GENERIC /kernel")) { msgConfirm("Unable to link /kernel into place!"); return DITEM_FAILURE; } } else { msgConfirm("Can't find a kernel image to link to on the root file system!\n" "You're going to have a hard time getting this system to\n" "boot from the hard disk, I'm afraid!"); return DITEM_FAILURE; } } /* Resurrect /dev after bin distribution screws it up */ if (RunningAsInit) { msgNotify("Remaking all devices.. Please wait!"); if (vsystem("cd /dev; sh MAKEDEV all")) { msgConfirm("MAKEDEV returned non-zero status"); return DITEM_FAILURE; } 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) { 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; } } } } /* XXX Do all the last ugly work-arounds here which we'll try and excise someday right?? XXX */ msgNotify("Fixing permissions.."); /* BOGON #1: XFree86 extracting /usr/X11R6 with root-only perms */ if (directory_exists("/usr/X11R6")) { vsystem("chmod -R a+r /usr/X11R6"); vsystem("find /usr/X11R6 -type d | xargs chmod a+x"); } /* 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"); /* BOGON #6: deal with new boot files */ vsystem("touch /kernel.config"); vsystem("touch /boot.config"); if (file_readable("/stand/boot.help") && !file_readable("/boot.help")) vsystem("mv /stand/boot.help /"); /* 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"); } return DITEM_SUCCESS; } /* 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], *str; + char dname[80]; extern int MakeDevChunk(Chunk *c, char *n); Boolean upgrade = FALSE; /* If we've already done this, bail out */ - if ((str = variable_get(DISK_LABELLED)) && !strcmp(str, "written")) + if (!variable_cmp(DISK_LABELLED, "written")) return DITEM_SUCCESS; - str = variable_get(SYSTEM_STATE); - + 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(); - upgrade = str && !strcmp(str, "upgrade"); - 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)) 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/r%sa", rootdev->disk->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; } 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) { int i; 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; } } else { if (!upgrade) { msgConfirm("Warning: Using existing root partition. It will be assumed\n" "that you have the appropriate device entries already in /dev."); } 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/%sa", rootdev->disk->name); if (Mount("/mnt", dname)) { msgConfirm("Unable to mount the root file system on %s! Giving up.", dname); return DITEM_FAILURE; } } /* 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; } 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) command_shell_add(tmp->mountpoint, "%s %s/dev/r%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name); else command_shell_add(tmp->mountpoint, "fsck -y %s/dev/r%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) 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) { 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; } } command_sort(); command_execute(); return DITEM_SUCCESS; } /* Initialize various user-settable values to their defaults */ int installVarDefaults(dialogMenuItem *self) { char *cp; /* Set default startup options */ variable_set2(VAR_ROUTER_ENABLE, "NO"); variable_set2(VAR_RELNAME, RELEASE_NAME); variable_set2(VAR_CPIO_VERBOSITY, "high"); variable_set2(VAR_TAPE_BLOCKSIZE, DEFAULT_TAPE_BLOCKSIZE); variable_set2(VAR_INSTALL_ROOT, "/"); variable_set2(VAR_INSTALL_CFG, "install.cfg"); cp = getenv("EDITOR"); if (!cp) cp = "/usr/bin/ee"; variable_set2(VAR_EDITOR, cp); variable_set2(VAR_FTP_USER, "ftp"); variable_set2(VAR_BROWSER_PACKAGE, PACKAGE_LYNX); variable_set2(VAR_BROWSER_BINARY, "/usr/local/bin/lynx"); variable_set2(VAR_FTP_STATE, "passive"); variable_set2(VAR_NFS_SECURE, "YES"); variable_set2(VAR_PKG_TMPDIR, "/usr/tmp"); variable_set2(VAR_GATED_PKG, PACKAGE_GATED); variable_set2(VAR_PCNFSD_PKG, PACKAGE_PCNFSD); variable_set2(VAR_MEDIA_TIMEOUT, itoa(MEDIA_TIMEOUT)); if (getpid() != 1) variable_set2(SYSTEM_STATE, "update"); else variable_set2(SYSTEM_STATE, "init"); return DITEM_SUCCESS; } /* Load the environment up from various system configuration files */ void installEnvironment(void) { if (file_readable("/etc/rc.conf")) configEnvironmentRC_conf("/etc/rc.conf"); if (file_readable("/etc/resolv.conf")) configEnvironmentResolv("/etc/resolv.conf"); } /* Copy the boot floppy contents into /stand */ Boolean copySelf(void) { int i; 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, 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); } } #ifdef SAVE_USERCONFIG static void save_userconfig_to_kernel(char *kern) { struct kernel *core, *boot; struct list *c_isa, *b_isa, *c_dev, *b_dev; int i, d; if ((core = uc_open("-incore")) == NULL) { msgDebug("save_userconf: Can't read in-core information for kernel.\n"); return; } if ((boot = uc_open(kern)) == NULL) { msgDebug("save_userconf: Can't read device information for kernel image %s\n", kern); return; } msgNotify("Saving any boot -c changes to new kernel..."); c_isa = uc_getdev(core, "-isa"); b_isa = uc_getdev(boot, "-isa"); if (isDebug()) msgDebug("save_userconf: got %d ISA device entries from core, %d from boot.\n", c_isa->ac, b_isa->ac); for (d = 0; d < c_isa->ac; d++) { if (isDebug()) msgDebug("save_userconf: ISA device loop, c_isa->av[%d] = %s\n", d, c_isa->av[d]); if (strcmp(c_isa->av[d], "npx0")) { /* special case npx0, which mucks with its id_irq member */ c_dev = uc_getdev(core, c_isa->av[d]); b_dev = uc_getdev(boot, b_isa->av[d]); if (!c_dev || !b_dev) { msgDebug("save_userconf: c_dev: %x b_dev: %x\n", c_dev, b_dev); continue; } if (isDebug()) msgDebug("save_userconf: ISA device %s: %d config parameters (core), %d (boot)\n", c_isa->av[d], c_dev->ac, b_dev->ac); for (i = 0; i < c_dev->ac; i++) { if (isDebug()) msgDebug("save_userconf: c_dev->av[%d] = %s, b_dev->av[%d] = %s\n", i, c_dev->av[i], i, b_dev->av[i]); if (strcmp(c_dev->av[i], b_dev->av[i])) { if (isDebug()) msgDebug("save_userconf: %s (boot) -> %s (core)\n", c_dev->av[i], b_dev->av[i]); isa_setdev(boot, c_dev); } } } else { if (isDebug()) msgDebug("skipping npx0\n"); } } if (isDebug()) msgDebug("Closing kernels\n"); uc_close(core, 0); uc_close(boot, 1); } #endif Index: stable/2.2/release/sysinstall/installUpgrade.c =================================================================== --- stable/2.2/release/sysinstall/installUpgrade.c (revision 30347) +++ stable/2.2/release/sysinstall/installUpgrade.c (revision 30348) @@ -1,494 +1,495 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: installUpgrade.c,v 1.33.2.14 1997/09/09 09:19:59 jkh Exp $ + * $Id: installUpgrade.c,v 1.33.2.15 1997/10/01 01:30:57 jkh Exp $ * * 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 #include #include static int installUpgradeNonInteractive(dialogMenuItem *self); typedef struct _hitList { enum { JUST_COPY, CALL_HANDLER } action ; char *name; Boolean optional; void (*handler)(struct _hitList *self); } HitList; /* These are the only meaningful files I know about */ static HitList etc_files [] = { { JUST_COPY, "Xaccel.ini", TRUE, NULL }, { JUST_COPY, "adduser.conf", TRUE, NULL }, { JUST_COPY, "aliases", TRUE, NULL }, { JUST_COPY, "aliases.db", TRUE, NULL }, { JUST_COPY, "amd.map", TRUE, NULL }, { JUST_COPY, "crontab", TRUE, NULL }, { JUST_COPY, "csh.cshrc", TRUE, NULL }, { JUST_COPY, "csh.login", TRUE, NULL }, { JUST_COPY, "csh.logout", TRUE, NULL }, { JUST_COPY, "daily", TRUE, NULL }, { JUST_COPY, "disktab", TRUE, NULL }, { JUST_COPY, "dm.conf", TRUE, NULL }, { JUST_COPY, "exports", TRUE, NULL }, { JUST_COPY, "fbtab", TRUE, NULL }, { JUST_COPY, "fstab", FALSE, NULL }, { JUST_COPY, "ftpusers", TRUE, NULL }, { JUST_COPY, "gettytab", TRUE, NULL }, { JUST_COPY, "gnats", TRUE, NULL }, { JUST_COPY, "group", FALSE, NULL }, { JUST_COPY, "host.conf", TRUE, NULL }, { JUST_COPY, "hosts", TRUE, NULL }, { JUST_COPY, "hosts.equiv", TRUE, NULL }, { JUST_COPY, "hosts.lpd", TRUE, NULL }, { JUST_COPY, "inetd.conf", TRUE, NULL }, { JUST_COPY, "kerberosIV", TRUE, NULL }, { JUST_COPY, "localtime", TRUE, NULL }, { JUST_COPY, "login.access", TRUE, NULL }, { JUST_COPY, "mail.rc", TRUE, NULL }, { JUST_COPY, "make.conf", TRUE, NULL }, { JUST_COPY, "manpath.config", TRUE, NULL }, { JUST_COPY, "master.passwd", TRUE, NULL }, { JUST_COPY, "mib.txt", TRUE, NULL }, { JUST_COPY, "modems", TRUE, NULL }, { JUST_COPY, "monthly", TRUE, NULL }, { JUST_COPY, "motd", TRUE, NULL }, { JUST_COPY, "namedb", TRUE, NULL }, { JUST_COPY, "networks", TRUE, NULL }, { JUST_COPY, "passwd", FALSE, NULL }, { JUST_COPY, "phones", TRUE, NULL }, { JUST_COPY, "ppp", TRUE, NULL }, { JUST_COPY, "printcap", TRUE, NULL }, { JUST_COPY, "profile", TRUE, NULL }, { JUST_COPY, "protocols", TRUE, NULL }, { JUST_COPY, "pwd.db", TRUE, NULL }, { JUST_COPY, "rc.local", TRUE, NULL }, { JUST_COPY, "rc.conf", FALSE, NULL }, { JUST_COPY, "remote", TRUE, NULL }, { JUST_COPY, "resolv.conf", TRUE, NULL }, { JUST_COPY, "rmt", TRUE, NULL }, { JUST_COPY, "security", TRUE, NULL }, { JUST_COPY, "sendmail.cf", TRUE, NULL }, { JUST_COPY, "services", TRUE, NULL }, { JUST_COPY, "shells", TRUE, NULL }, { JUST_COPY, "skeykeys", TRUE, NULL }, { JUST_COPY, "spwd.db", TRUE, NULL }, { JUST_COPY, "supfile", TRUE, NULL }, { JUST_COPY, "syslog.conf", TRUE, NULL }, { JUST_COPY, "termcap", TRUE, NULL }, { JUST_COPY, "ttys", TRUE, NULL }, { JUST_COPY, "uucp", TRUE, NULL }, { JUST_COPY, "weekly", TRUE, NULL }, { 0 }, }; void traverseHitlist(HitList *h) { system("rm -rf /etc/upgrade"); Mkdir("/etc/upgrade"); while (h->name) { if (!file_readable(h->name)) { if (!h->optional) msgConfirm("Unable to find an old /etc/%s file! That is decidedly non-standard and\n" "your upgraded system may function a little strangely as a result.", h->name); } else { if (h->action == JUST_COPY) { /* Move the just-loaded copy aside */ vsystem("mv /etc/%s /etc/upgrade/%s", h->name, h->name); /* Copy the old one into its place */ msgNotify("Resurrecting %s..", h->name); /* Do this with tar so that symlinks and such are preserved */ if (vsystem("tar cf - %s | tar xpf - -C /etc", h->name)) msgConfirm("Unable to resurrect your old /etc/%s! Hmmmm.", h->name); } else /* call handler */ h->handler(h); } ++h; } } int installUpgrade(dialogMenuItem *self) { - char *saved_etc; + char saved_etc[FILENAME_MAX]; Boolean extractingBin = TRUE; if (variable_get(VAR_NONINTERACTIVE)) return installUpgradeNonInteractive(self); variable_set2(SYSTEM_STATE, "upgrade"); systemDisplayHelp("upgrade"); dialog_clear_norefresh(); if (msgYesNo("Given all that scary stuff you just read, are you sure you want to\n" "risk it all and proceed with this upgrade?") != 0) return DITEM_FAILURE | DITEM_RESTORE; if (!Dists) { - msgConfirm("You haven't specified any distributions yet. The upgrade procedure will\n" - "only upgrade those portions of the system for which a distribution has\n" - "been selected. In the next screen, we'll go to the Distributions menu\n" - "to select those portions of the new system you wish to install on top of\n" - "the old."); + msgConfirm("First, you must select some distribution components. The upgrade procedure\n" + "will only upgrade the distributions you select in the next set of menus."); if (!dmenuOpenSimple(&MenuDistributions, FALSE) || !Dists) return DITEM_FAILURE | DITEM_RESTORE; dialog_clear_norefresh(); } else if (!(Dists & DIST_BIN)) { /* No bin selected? Not much of an upgrade.. */ if (msgYesNo("You didn't select the bin distribution as one of the distributons to load.\n" "This one is pretty vital to a successful upgrade. Are you SURE you don't\n" "want to select the bin distribution? Chose No to bring up the Distributions\n" - "menu.") != 0) { + "menu again.") != 0) { if (!dmenuOpenSimple(&MenuDistributions, FALSE)) return DITEM_FAILURE | DITEM_RESTORE; dialog_clear_norefresh(); } } /* Still?! OK! They must know what they're doing.. */ if (!(Dists & DIST_BIN)) extractingBin = FALSE; if (RunningAsInit) { Device **devs; int i, cnt; char *cp; cp = variable_get(VAR_DISK); devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(devs); if (!cnt) { 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 { /* Enable all the drives befor we start */ for (i = 0; i < cnt; i++) devs[i]->enabled = TRUE; } msgConfirm("OK. First, we're going to go to the disk label editor. In this editor\n" "you will be expected to Mount any partitions you're interested in\n" "upgrading. DO NOT set the Newfs flag to Y on anything in the label editor\n" "unless you're absolutely sure you know what you're doing! In this\n" "instance, you'll be using the label editor as little more than a fancy\n" "screen-oriented partition mounting tool.\n\n" "Once you're done in the label editor, press Q to return here for the next\n" "step."); if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) { msgConfirm("The disk label editor returned an error status. Upgrade operation\n" "aborted."); return DITEM_FAILURE | DITEM_RESTORE; } /* Don't write out MBR info */ variable_set2(DISK_PARTITIONED, "written"); if (DITEM_STATUS(diskLabelCommit(self)) == DITEM_FAILURE) { msgConfirm("Not all file systems were properly mounted. Upgrade operation\n" "aborted."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE | DITEM_RESTORE; } if (extractingBin) { msgNotify("chflags'ing old binaries - please wait."); (void)vsystem("chflags -R noschg /mnt/"); } msgNotify("Updating /stand on root filesystem"); (void)vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (DITEM_STATUS(chroot("/mnt")) == DITEM_FAILURE) { msgConfirm("Unable to chroot to /mnt - something is wrong with the\n" "root partition or the way it's mounted if this doesn't work."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE | DITEM_RESTORE; } chdir("/"); systemCreateHoloshell(); } - saved_etc = NULL; + saved_etc[0] = '\0'; if (extractingBin) { - while (!saved_etc) { - saved_etc = msgGetInput("/usr/tmp/etc", "Under which directory do you wish to save your current /etc?"); - if (!saved_etc || !*saved_etc || Mkdir(saved_etc)) { - saved_etc = NULL; + while (!*saved_etc) { + char *cp = msgGetInput("/usr/tmp/etc", "Under which directory do you wish to save your current /etc?"); + + if (!cp || !*cp || Mkdir(cp)) { if (msgYesNo("Directory was not specified, was invalid or user selected Cancel.\n\n" "Doing an upgrade without first backing up your /etc directory is a very\n" "bad idea! Do you want to go back and specify the save directory again?") != 0) break; } + else { + SAFE_STRCPY(saved_etc, cp); + } } - if (saved_etc) { + if (saved_etc[0]) { msgNotify("Preserving /etc directory.."); if (vsystem("tar -cBpf - -C /etc . | tar --unlink -xBpf - -C %s", saved_etc)) if (msgYesNo("Unable to backup your /etc into %s.\n" "Do you want to continue anyway?", saved_etc) != 0) return DITEM_FAILURE | DITEM_RESTORE; } if (file_readable("/kernel")) { msgNotify("Moving old kernel to /kernel.prev"); if (system("chflags noschg /kernel && mv /kernel /kernel.prev")) { if (!msgYesNo("Hmmm! I couldn't move the old kernel over! Do you want to\n" "treat this as a big problem and abort the upgrade? Due to the\n" "way that this upgrade process works, you will have to reboot\n" "and start over from the beginning. Select Yes to reboot now")) systemShutdown(1); } else /* Give us a working kernel in case we crash and reboot */ system("cp /kernel.prev /kernel"); } } media: + /* We do this very late, but we unfortunately need to back up /etc first */ if (!mediaVerify()) return DITEM_FAILURE | DITEM_RESTORE; if (!mediaDevice->init(mediaDevice)) { if (!msgYesNo("Couldn't initialize the media. Would you like\n" "to adjust your media selection and try again?")) { mediaDevice = NULL; goto media; } else return DITEM_FAILURE | DITEM_REDRAW; } msgNotify("Beginning extraction of distributions.."); if (DITEM_STATUS(distExtractAll(self)) == DITEM_FAILURE) { msgConfirm("Hmmmm. We couldn't even extract the bin distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } else if (Dists) { if (!extractingBin || !(Dists & DIST_BIN)) { msgNotify("The extraction process seems to have had some problems, but we got most\n" "of the essentials. We'll treat this as a warning since it may have been\n" "only non-essential distributions which failed to load."); } else { msgConfirm("Hmmmm. We couldn't even extract the bin distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } } if (extractingBin) { msgNotify("OK, now it's time to go pound on your root a little bit to create all the\n" "/dev entries and such that a new system expects to see. I'll also perform a\n" "few \"fixup\" operations to repair the effects of splatting a bin distribution\n" "on top of an existing system.."); if (DITEM_STATUS(installFixup(self)) == DITEM_FAILURE) { msgConfirm("Hmmmmm. The fixups don't seem to have been very happy.\n" "You may wish to examine the system a little more closely when\n" "it comes time to merge your /etc customizations back."); } } msgNotify("First stage of upgrade completed successfully!\n\n" "Next comes stage 2, where we attempt to resurrect your /etc\n" "directory!"); if (saved_etc && chdir(saved_etc)) { msgConfirm("Unable to go to your saved /etc directory in %s?! Argh!\n" "Something went seriously wrong! It's quite possible that\n" "your former /etc is toast. I hope you didn't have any\n" "important customizations you wanted to keep in there.. :(", saved_etc); } else { /* Now try to resurrect the /etc files */ traverseHitlist(etc_files); } msgConfirm("OK! At this stage, we've resurrected all the /etc files\n" "and moved each new copy over to /etc/upgrade/ in case you want\n" "to see what the new versions look like. If you want to wander over\n" "to the Emergency Holographic Shell [ALT-F4] at this point to do\n" "that, now would be a good time. When you're ready to reboot into\n" "the new system, just exit the installation."); return DITEM_SUCCESS | DITEM_REDRAW; } static int installUpgradeNonInteractive(dialogMenuItem *self) { char *saved_etc; Boolean extractingBin = TRUE; variable_set2(SYSTEM_STATE, "upgrade"); /* Make sure at least BIN is selected */ Dists |= DIST_BIN; if (RunningAsInit) { Device **devs; int i, cnt; char *cp; cp = variable_get(VAR_DISK); devs = deviceFind(cp, DEVICE_TYPE_DISK); cnt = deviceCount(devs); if (!cnt) { 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 { /* Enable all the drives befor we start */ for (i = 0; i < cnt; i++) devs[i]->enabled = TRUE; } msgConfirm("OK. First, we're going to go to the disk label editor. In this editor\n" "you will be expected to Mount any partitions you're interested in\n" "upgrading. DO NOT set the Newfs flag to Y on anything in the label editor\n" "unless you're absolutely sure you know what you're doing! In this\n" "instance, you'll be using the label editor as little more than a fancy\n" "screen-oriented partition mounting tool.\n\n" "Once you're done in the label editor, press Q to return here for the next\n" "step."); if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) { msgConfirm("The disk label editor returned an error status. Upgrade operation\n" "aborted."); return DITEM_FAILURE | DITEM_RESTORE; } /* Don't write out MBR info */ variable_set2(DISK_PARTITIONED, "written"); if (DITEM_STATUS(diskLabelCommit(self)) == DITEM_FAILURE) { msgConfirm("Not all file systems were properly mounted. Upgrade operation\n" "aborted."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE | DITEM_RESTORE; } if (extractingBin) { msgNotify("chflags'ing old binaries - please wait."); (void)vsystem("chflags -R noschg /mnt/"); } msgNotify("Updating /stand on root filesystem"); (void)vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity()); if (DITEM_STATUS(chroot("/mnt")) == DITEM_FAILURE) { msgConfirm("Unable to chroot to /mnt - something is wrong with the\n" "root partition or the way it's mounted if this doesn't work."); variable_unset(DISK_PARTITIONED); return DITEM_FAILURE | DITEM_RESTORE; } chdir("/"); systemCreateHoloshell(); } if (!mediaVerify() || !mediaDevice->init(mediaDevice)) { msgNotify("Upgrade: Couldn't initialize media."); return DITEM_FAILURE | DITEM_RESTORE; } saved_etc = "/usr/tmp/etc"; Mkdir(saved_etc); msgNotify("Preserving /etc directory.."); if (vsystem("tar -cpBf - -C /etc . | tar -xpBf - -C %s", saved_etc)) { msgNotify("Unable to backup your /etc into %s.", saved_etc); return DITEM_FAILURE | DITEM_RESTORE; } if (file_readable("/kernel")) { msgNotify("Moving old kernel to /kernel.prev"); if (!system("chflags noschg /kernel && mv /kernel /kernel.prev")) { /* Give us a working kernel in case we crash and reboot */ system("cp /kernel.prev /kernel"); } } msgNotify("Beginning extraction of distributions.."); if (DITEM_STATUS(distExtractAll(self)) == DITEM_FAILURE) { msgConfirm("Hmmmm. We couldn't even extract the bin distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } else if (Dists) { if (!(Dists & DIST_BIN)) { msgNotify("The extraction process seems to have had some problems, but we got most\n" "of the essentials. We'll treat this as a warning since it may have been\n" "only non-essential distributions which failed to upgrade."); } else { msgConfirm("Hmmmm. We couldn't even extract the bin distribution. This upgrade\n" "should be considered a failure and started from the beginning, sorry!\n" "The system will reboot now."); dialog_clear(); systemShutdown(1); } } msgNotify("OK, now it's time to go pound on your root a little bit to create all the\n" "/dev entries and such that a new system expects to see. I'll also perform a\n" "few \"fixup\" operations to repair the effects of splatting a bin distribution\n" "on top of an existing system.."); if (DITEM_STATUS(installFixup(self)) == DITEM_FAILURE) { msgNotify("Hmmmmm. The fixups don't seem to have been very happy.\n" "You may wish to examine the system a little more closely when\n" "it comes time to merge your /etc customizations back."); } msgNotify("First stage of upgrade completed successfully."); if (vsystem("tar -cpBf - -C %s . | tar --unlink -xpBf - -C /etc", saved_etc)) { msgNotify("Unable to resurrect your old /etc!"); return DITEM_FAILURE | DITEM_RESTORE; } return DITEM_SUCCESS | DITEM_REDRAW; } Index: stable/2.2/release/sysinstall/label.c =================================================================== --- stable/2.2/release/sysinstall/label.c (revision 30347) +++ stable/2.2/release/sysinstall/label.c (revision 30348) @@ -1,1194 +1,1253 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: label.c,v 1.63.2.10 1997/09/20 02:49:13 jkh Exp $ + * $Id: label.c,v 1.63.2.11 1997/09/20 06:24:29 jkh Exp $ * * 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 */ #define ROOT_MIN_SIZE 20 /* The smallest swap partition we want to create by default */ #define SWAP_MIN_SIZE 16 /* 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 30 /* 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(char *str); -static int diskLabelNonInteractive(char *str); +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 | DITEM_RESTORE; +} + +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, enabled; - char *cp; + int i, cnt; - cp = variable_get(VAR_DISK); - devs = deviceFind(cp, DEVICE_TYPE_DISK); - cnt = deviceCount(devs); - if (!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; } - for (i = 0, enabled = 0; i < cnt; i++) { - if (devs[i]->enabled) - ++enabled; + else if (cnt) { + int j; + + /* Some are already selected */ + for (j = 0; j < cnt; j++) { + if (devs[j]->enabled) { + if (variable_get(VAR_NONINTERACTIVE)) + i |= diskLabelNonInteractive(devs[j]); + else + i |= diskLabel(devs[j]); + } + } } - if (!enabled) { - msgConfirm("No disks have been selected. Please visit the Partition\n" - "editor first to specify which disks you wish to operate on."); - return DITEM_FAILURE; + 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); + } + i |= DITEM_RESTORE; + } } - if (variable_get(VAR_NONINTERACTIVE)) - i = diskLabelNonInteractive(devs[0]->name); - else - i = diskLabel(devs[0]->name); if (DITEM_STATUS(i) != DITEM_FAILURE) { char *cp; if (((cp = variable_get(DISK_LABELLED)) == NULL) || (strcmp(cp, "written"))) variable_set2(DISK_LABELLED, "yes"); } 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"); 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) +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 (!devs[i]->enabled) + 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 -b 8192 -f 1024"); 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; if (!old) { DialogX = 14; DialogY = 16; } val = msgGetInput(tmp ? tmp->mountpoint : NULL, "Please specify a mount point for the partition"); DialogX = DialogY = 0; 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); 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.", }; DialogX = 7; DialogY = 8; 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); DialogX = DialogY = 0; 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 12 #define PART_PART_COL 0 #define PART_MOUNT_COL 8 #define PART_SIZE_COL (PART_MOUNT_COL + MAX_MOUNT_NAME + 3) #define PART_NEWFS_COL (PART_SIZE_COL + 7) #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) + 2, "Size"); mvaddstr(ChunkPartStartRow - 1, PART_SIZE_COL + (i * PART_OFF) + 2, "----"); 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, "%4ldMB", 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, 47, "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(); } static int -diskLabel(char *str) +diskLabel(Device *dev) { int sz, key = 0; Boolean labeling; char *msg = NULL; PartInfo *p, *oldp; PartType type; Device **devs; label_focus = 0; pslice_focus = 0; here = 0; + devs = deviceFind(NULL, DEVICE_TYPE_DISK); if (!devs) { msgConfirm("No disks found!"); return DITEM_FAILURE; } - labeling = TRUE; keypad(stdscr, TRUE); - record_label_chunks(devs); + 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) : 32) * 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); + 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); + record_label_chunks(devs, dev); } if (!vardev) { cp = variable_get(VAR_VAR_SIZE); tmp = Create_Chunk_DWIM(label_chunk_info[here].c->disk, label_chunk_info[here].c, (cp ? atoi(cp) : VAR_MIN_SIZE) * ONE_MEG, 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); + record_label_chunks(devs, dev); } if (!usrdev) { 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); + 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"); } 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); DialogX = 3; DialogY = 2; val = msgGetInput(osize, "Please specify the partition size in blocks or append a trailing M for\n" "megabytes or C for cylinders. %d blocks (%dMB) are free.", sz, sz / ONE_MEG); DialogX = DialogY = 0; if (!val || (size = strtol(val, &cp, 0)) <= 0) { clear_wins(); break; } if (*cp) { if (toupper(*cp) == 'M') size *= ONE_MEG; 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 ((flags & CHUNK_IS_ROOT) && (tmp->flags & CHUNK_PAST_1024)) { msgConfirm("This region cannot be used for your root partition as it starts\n" "or extends past the 1024'th cylinder mark and is thus a\n" "poor location to boot from. Please choose another\n" "location (or smaller size) for your root partition and try again!"); Delete_Chunk(label_chunk_info[here].c->disk, tmp); 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"); - record_label_chunks(devs); + 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"); - record_label_chunks(devs); + 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"); - record_label_chunks(devs); + 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"); } 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?")) { 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], d); + diskPartition(devs[i]); } } - record_label_chunks(devs); + 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" "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"); diskLabelCommit(NULL); } clear_wins(); break; case '|': if (!msgYesNo("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"); DialogActive = TRUE; - record_label_chunks(devs); + 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; } return DITEM_SUCCESS | DITEM_RESTORE; } static int -diskLabelNonInteractive(char *str) +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) { dialog_clear(); 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; } - d = devs[0]->private; - - record_label_chunks(devs); + if (dev) + d = dev->private; + else + d = devs[0]->private; + 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; } 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) { dialog_clear(); 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"); return status; } Index: stable/2.2/release/sysinstall/sysinstall.h =================================================================== --- stable/2.2/release/sysinstall/sysinstall.h (revision 30347) +++ stable/2.2/release/sysinstall/sysinstall.h (revision 30348) @@ -1,722 +1,724 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated to essentially a complete rewrite. * - * $Id: sysinstall.h,v 1.82.2.45 1997/09/16 18:59:00 jkh Exp $ + * $Id: sysinstall.h,v 1.82.2.46 1997/09/17 16:35:37 pst Exp $ * * 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 "ui_objects.h" #include "dir.h" #include "colors.h" #include "libdisk.h" #include "dist.h" #include "version.h" /*** Defines ***/ /* Different packages we depend on - update this when package version change! */ #define PACKAGE_GATED "gated-3.5b3" #define PACKAGE_NETCON "commerce/netcon/bsd61" #define PACKAGE_PCNFSD "pcnfsd-93.02.16" #define PACKAGE_LYNX "lynx-2.7.1" /* 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_DISK "disk" #define VAR_DISTS "dists" #define VAR_DIST_MAIN "distMain" #define VAR_DIST_DES "distDES" #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_FTP_DIR "ftpDirectory" #define VAR_FTP_PASS "ftpPass" #define VAR_FTP_PATH "ftp" #define VAR_FTP_PORT "ftpPort" #define VAR_FTP_STATE "ftpState" #define VAR_FTP_USER "ftpUser" #define VAR_FTP_HOST "ftpHost" #define VAR_GATED_PKG "gated_pkg" #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_KEYMAP "keymap" #define VAR_LABEL "label" #define VAR_LABEL_COUNT "labelCount" #define VAR_MEDIA_TYPE "mediaType" #define VAR_MEDIA_TIMEOUT "MEDIA_TIMEOUT" #define VAR_NAMESERVER "nameserver" #define VAR_NETINTERACTIVE "netInteractive" #define VAR_NETMASK "netmask" #define VAR_NETWORK_DEVICE "netDev" #define VAR_NFS_PATH "nfs" #define VAR_NFS_HOST "nfsHost" #define VAR_NFS_SECURE "nfsSecure" #define VAR_NFS_SERVER "nfs_server_enable" #define VAR_NO_CONFIRM "noConfirm" #define VAR_NO_ERROR "noError" #define VAR_NO_WARN "noWarn" #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_PCNFSD_PKG "pcnfsd_pkg" #define VAR_PKG_TMPDIR "PKG_TMPDIR" #define VAR_PORTS_PATH "ports" #define VAR_RELNAME "releaseName" #define VAR_ROOT_SIZE "rootSize" #define VAR_ROUTER "router" #define VAR_ROUTER_ENABLE "router_enable" #define VAR_ROUTERFLAGS "routerflags" #define VAR_SERIAL_SPEED "serialSpeed" #define VAR_SLOW_ETHER "slowEthernetCard" #define VAR_SWAP_SIZE "swapSize" #define VAR_TAPE_BLOCKSIZE "tapeBlocksize" #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 /* 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; } 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; /* For attribs */ #define MAX_ATTRIBS 200 #define MAX_NAME 64 #define MAX_VALUE 256 typedef struct _attribs { char name[MAX_NAME]; char value[MAX_VALUE]; } Attribs; 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, } 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 */ 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 { 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 DESDists; /* 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 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 MenuSubDistributions; /* Custom distribution menu */ extern DMenu MenuDESDistributions; /* DES 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 MenuDiskDevices; /* 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 */ /* 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); /* attrs.c */ extern char *attr_match(Attribs *attr, char *name); extern int attr_parse_file(Attribs *attr, char *file); extern int attr_parse(Attribs *attr, FILE *fp); /* 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 int configFstab(void); extern void configEnvironmentRC_conf(char *config); extern void configEnvironmentResolv(char *config); extern void configRC_conf(char *config); extern int configRC(dialogMenuItem *self); extern int configRegister(dialogMenuItem *self); extern void configResolv(void); extern int configPackages(dialogMenuItem *self); extern int configSaver(dialogMenuItem *self); extern int configSaverTimeout(dialogMenuItem *self); extern int configNTP(dialogMenuItem *self); extern int configUsers(dialogMenuItem *self); extern int configXEnvironment(dialogMenuItem *self); extern int configRouter(dialogMenuItem *self); extern int configPCNFSD(dialogMenuItem *self); extern int configNFSServer(dialogMenuItem *self); extern int configWriteRC_conf(dialogMenuItem *self); #ifdef NETCON_EXTENTIONS extern int configNovell(dialogMenuItem *self); #endif /* 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 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); /* disks.c */ extern int diskPartitionEditor(dialogMenuItem *self); extern int diskPartitionWrite(dialogMenuItem *self); -extern void diskPartition(Device *dev, Disk *d); +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 distSetDeveloper(dialogMenuItem *self); extern int distSetXDeveloper(dialogMenuItem *self); extern int distSetKernDeveloper(dialogMenuItem *self); extern int distSetUser(dialogMenuItem *self); extern int distSetXUser(dialogMenuItem *self); extern int distSetMinimum(dialogMenuItem *self); extern int distSetEverything(dialogMenuItem *self); extern int distSetDES(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 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); /* globals.c */ extern void globalsInit(void); /* index.c */ int index_read(FILE *fp, PkgNodePtr papa); int index_menu(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 plist); /* 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 installNovice(dialogMenuItem *self); extern int installFixitHoloShell(dialogMenuItem *self); extern int installFixitCDROM(dialogMenuItem *self); extern int installFixitFloppy(dialogMenuItem *self); extern int installFixup(dialogMenuItem *self); extern int installUpgrade(dialogMenuItem *self); extern int installFilesystems(dialogMenuItem *self); extern int installVarDefaults(dialogMenuItem *self); extern void installEnvironment(void); extern Boolean copySelf(void); /* keymap.c */ extern int loadKeymap(const char *lang); /* label.c */ extern int diskLabelEditor(dialogMenuItem *self); extern int diskLabelCommit(dialogMenuItem *self); /* lndir.c */ extern int lndir(char *from, char *to); /* makedevs.c (auto-generated) */ extern const char termcap_ansi[]; extern const char termcap_vt100[]; 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 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 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); /* 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); /* 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 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); /* register.c */ extern int registerOpenDialog(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 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); /* user.c */ extern int userAddGroup(dialogMenuItem *self); extern int userAddUser(dialogMenuItem *self); /* variable.c */ extern void variable_set(char *var); extern void variable_set2(char *name, char *value); 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); extern int variable_check(char *data); /* wizard.c */ extern void slice_wizard(Disk *d); #endif /* _SYSINSTALL_H_INCLUDE */ Index: stable/2.2/release/sysinstall/variable.c =================================================================== --- stable/2.2/release/sysinstall/variable.c (revision 30347) +++ stable/2.2/release/sysinstall/variable.c (revision 30348) @@ -1,183 +1,193 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * - * $Id: variable.c,v 1.11.2.5 1997/06/11 08:39:27 jkh Exp $ + * $Id: variable.c,v 1.11.2.6 1997/06/13 14:18:47 jkh Exp $ * * 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" /* Routines for dealing with variable lists */ static void make_variable(char *var, char *value) { Variable *vp; /* Trim leading and trailing whitespace */ var = string_skipwhite(string_prune(var)); if (!var || !*var) return; /* Put it in the environment in any case */ setenv(var, value, 1); /* Now search to see if it's already in the list */ for (vp = VarHead; vp; vp = vp->next) { if (!strcmp(vp->name, var)) { if (isDebug()) msgDebug("variable %s was %s, now %s\n", vp->name, vp->value, value); free(vp->value); vp->value = strdup(value); return; } } /* No? Create a new one */ vp = (Variable *)safe_malloc(sizeof(Variable)); vp->name = strdup(var); vp->value = strdup(value); vp->next = VarHead; VarHead = vp; if (isDebug()) msgDebug("Setting variable %s to %s\n", vp->name, vp->value); } void variable_set(char *var) { char tmp[1024], *cp; if (!var) msgFatal("NULL variable name & value passed."); else if (!*var) msgDebug("Warning: Zero length name & value passed to variable_set()\n"); SAFE_STRCPY(tmp, var); if ((cp = index(tmp, '=')) == NULL) msgFatal("Invalid variable format: %s", var); *(cp++) = '\0'; make_variable(tmp, string_skipwhite(cp)); } void variable_set2(char *var, char *value) { if (!var || !value) msgFatal("Null name or value passed to set_variable2!"); else if (!*var || !*value) msgDebug("Warning: Zero length name or value passed to variable_set2()\n"); make_variable(var, value); } char * variable_get(char *var) { return getenv(var); +} + +int +variable_cmp(char *var, char *value) +{ + char *val; + + if ((val = variable_get(var))) + return strcmp(val, value); + return -1; } void variable_unset(char *var) { Variable *vp; char name[512], *cp; if ((cp = index(var, '=')) != NULL) sstrncpy(name, var, cp - var); else SAFE_STRCPY(name, var); unsetenv(name); /* Now search to see if it's in our list, if we have one.. */ if (!VarHead) return; else if (!VarHead->next && !strcmp(VarHead->name, name)) { safe_free(VarHead->name); safe_free(VarHead->value); free(VarHead); VarHead = NULL; } else { for (vp = VarHead; vp; vp = vp->next) { if (!strcmp(vp->name, name)) { Variable *save = vp->next; safe_free(vp->name); safe_free(vp->value); *vp = *save; safe_free(save); break; } } } } /* Prompt user for the name of a variable */ char * variable_get_value(char *var, char *prompt) { char *cp; cp = variable_get(var); if (cp && variable_get(VAR_NONINTERACTIVE)) return cp; else if ((cp = msgGetInput(cp, prompt)) != NULL) variable_set2(var, cp); else cp = NULL; return cp; } /* Check if value passed in data (in the form "variable=value") is equal to value of variable stored in env */ int variable_check(char *data) { char *w, *cp, *cp2, *cp3, tmp[256]; w = data; if (!w) return FALSE; SAFE_STRCPY(tmp, w); if ((cp = index(tmp, '=')) != NULL) { *(cp++) = '\0'; if ((cp3 = index(cp, ',')) != NULL) *cp3 = '\0'; cp2 = getenv(tmp); if (cp2) return !strcmp(cp, cp2); else return FALSE; } else return (int)getenv(tmp); }