<commit_before>/*
 * The new sysinstall program.
 *
 * This is probably the last program in the `sysinstall' line - the next
 * generation being essentially a complete rewrite.
 *
 * $FreeBSD$
 *
 * Copyright (c) 1995
 *	<NAME>.  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 <NAME> ``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 <NAME> 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 <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libdisk.h>
#include <sys/stat.h>
#include <sys/disklabel.h>

#ifdef WITH_SLICES
enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE };

#ifdef PC98
#define	SUBTYPE_FREEBSD		50324
#define	SUBTYPE_FAT		37218
#else
#define	SUBTYPE_FREEBSD		165
#define	SUBTYPE_FAT		6
#endif
#define	SUBTYPE_EFI		239

#ifdef PC98
#define	OTHER_SLICE_VALUES						\
	"Other popular values are 37218 for a\n"			\
	"DOS FAT partition.\n\n"
#else
#define	OTHER_SLICE_VALUES						\
	"Other popular values are 6 for a\n"				\
	"DOS FAT partition, 131 for a Linux ext2fs partition, or\n"	\
	"130 for a Linux swap partition.\n\n"
#endif
#define	NON_FREEBSD_NOTE						\
	"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."

/* Where we start displaying chunk information on the screen */
#define CHUNK_START_ROW		5

/* Where we keep track of MBR chunks */
#define	CHUNK_INFO_ENTRIES	16
static struct chunk *chunk_info[CHUNK_INFO_ENTRIES];
static int current_chunk;

static void	diskPartitionNonInteractive(Device *dev);
static u_char *	bootalloc(char *name, size_t *size);

static void
record_chunks(Disk *d)
{
    struct chunk *c1 = NULL;
    int i = 0;
    daddr_t 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 daddr_t Total;

static void
check_geometry(Disk *d)
{
    int sg;

#ifdef PC98
    if (d->bios_cyl >= 65536 || d->bios_hd > 256 || d->bios_sect >= 256)
#else
    if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64)
#endif
    {
	dialog_clear_norefresh();
	sg = msgYesNo("WARNING:  It is safe to use a geometry of %lu/%lu/%lu for %s on\n"
		      "computers with modern BIOS versions.  If this disk is to be used\n"
		      "on an old machine it is recommended that it does not have more\n"
		      "than 65535 cylinders, more than 255 heads, or more than\n"
#ifdef PC98
		      "255"
#else
		      "63"
#endif
		      " sectors per track.\n"
		      "\n"
		      "Would you like to keep using the current geometry?\n",
		      d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
	if (sg == 1) {
	    Sanitize_Bios_Geom(d);
	    msgConfirm("A geometry of %lu/%lu/%lu was calculated for %s.\n"
		       "\n"
		       "If you are not sure about this, please consult the Hardware Guide\n"
		       "in the Documentation submenu or use the (G)eometry command to\n"
		       "change it.  Remember: you need to enter whatever your BIOS thinks\n"
		       "the 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''.\n",
		       d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
	}
    }
}

static void
print_chunks(Disk *d, int u)
{
    int row;
    int i;
    daddr_t sz;
    char *szstr;

    szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" :
	(u == UNIT_KILO ? "KB" : "ST")));

    Total = 0;
    for (i = 0; chunk_info[i]; i++)
	Total += chunk_info[i]->size;
    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 = %jd sectors (%jdMB)",
	     d->bios_cyl, d->bios_hd, d->bios_sect,
	     (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect,
	     (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024);
    mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s",
	     "Offset", "Size", szstr, "End", "Name", "PType", "Desc",
	     "Subtype", "Flags");
    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
	switch(u) {
	default:	/* fall thru */
	case UNIT_BLOCKS:
	    sz = chunk_info[i]->size;
	    break;
	case UNIT_KILO:
	    sz = chunk_info[i]->size / (1024/512);
	    break;
	case UNIT_MEG:
	    sz = chunk_info[i]->size / (1024/512) / 1024;
	    break;
	case UNIT_GIG:
	    sz = chunk_info[i]->size / (1024/512) / 1024 / 1024;
	    break;
	}
	if (i == current_chunk)
	    attrset(ATTR_SELECTED);
	mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s",
		 (intmax_t)chunk_info[i]->offset, (intmax_t)sz,
		 (intmax_t)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(void)
{
    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
    mvprintw(16, 0, "A = Use Entire Disk   G = set Drive Geometry   C = Create Slice   F = `DD' mode");
    mvprintw(17, 0, "D = Delete Slice      Z = Toggle Size Units    S = Set Bootable   | = Wizard m.");
    mvprintw(18, 0, "T = Change Type       U = Undo All Changes     Q = Finish");
    if (!RunningAsInit)
	mvprintw(18, 47, "W = Write Changes");
    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
    move(0, 0);
}

#ifdef PC98
static void
getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size,
	   u_char **bootmenu, size_t *bootmenu_size)
{
    static u_char *boot0;
    static size_t boot0_size;
    static u_char *boot05;
    static size_t boot05_size;

    char str[80];
    char *cp;
    int i = 0;

    cp = variable_get(VAR_BOOTMGR);
    if (!cp) {
	/* Figure out what kind of IPL the user wants */
	sprintf(str, "Install Boot Manager for drive %s?", dname);
	MenuIPLType.title = str;
	i = dmenuOpenSimple(&MenuIPLType, FALSE);
    } else {
	if (!strncmp(cp, "boot", 4))
	    BootMgr = 0;
	else
	    BootMgr = 1;
    }
    if (cp || i) {
	switch (BootMgr) {
	case 0:
	    if (!boot0) boot0 = bootalloc("boot0", &boot0_size);
	    *bootipl = boot0;
	    *bootipl_size = boot0_size;
	    if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size);
	    *bootmenu = boot05;
	    *bootmenu_size = boot05_size;
	    return;
	case 1:
	default:
	    break;
	}
    }
    *bootipl = NULL;
    *bootipl_size = 0;
    *bootmenu = NULL;
    *bootmenu_size = 0;
}
#else
static void
getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize)
{
#if defined(__i386__) || defined(__amd64__)	/* only meaningful on x86 */
    static u_char *mbr, *boot0;
    static size_t mbr_size, boot0_size;
    char str[80];
    char *cp;
    int i = 0;

    cp = variable_get(VAR_BOOTMGR);
    if (!cp) {
	/* Figure out what kind of MBR the user wants */
	sprintf(str, "Install Boot Manager for drive %s?", dname);
	MenuMBRType.title = str;
	i = dmenuOpenSimple(&MenuMBRType, FALSE);
    }
    else {
	if (!strncmp(cp, "boot", 4))
	    BootMgr = 0;
	else if (!strcmp(cp, "standard"))
	    BootMgr = 1;
	else
	    BootMgr = 2;
    }
    if (cp || i) {
	switch (BootMgr) {
	case 0:
	    if (!boot0) boot0 = bootalloc("boot0", &boot0_size);
	    *bootCode = boot0;
	    *bootCodeSize = boot0_size;
	    return;
	case 1:
	    if (!mbr) mbr = bootalloc("mbr", &mbr_size);
	    *bootCode = mbr;
	    *bootCodeSize = mbr_size;
	    return;
	case 2:
	default:
	    break;
	}
    }
#endif
    *bootCode = NULL;
    *bootCodeSize = 0;
}
#endif
#endif /* WITH_SLICES */

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;
}

#ifdef WITH_SLICES
void
diskPartition(Device *dev)
{
    char *cp, *p;
    int rv, key = 0;
    int i;
    Boolean chunking;
    char *msg = NULL;
#ifdef PC98
    u_char *bootipl;
    size_t bootipl_size;
    u_char *bootmenu;
    size_t bootmenu_size;
#else
    u_char *mbrContents;
    size_t mbrSize;
#endif
    WINDOW *w = savescr();
    Disk *d = (Disk *)dev->private;
    int size_unit;

    size_unit = UNIT_BLOCKS;
    chunking = TRUE;
    keypad(stdscr, TRUE);

    /* Flush both the dialog and curses library views of the screen
       since we don't always know who called us */
    dialog_clear_norefresh(), clear();
    current_chunk = 0;

    /* Set up the chunk array */
    record_chunks(d);

    /* Give the user a chance to sanitize the disk geometry, if necessary */
    check_geometry(d);

    while (chunking) {
	char *val, geometry[80];
	    
	/* Now print our overall state */
	if (d)
	    print_chunks(d, size_unit);
	print_command_summary();
	if (msg) {
	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
	    beep();
	    msg = NULL;
	}
	else {
	    move(23, 0);
	    clrtoeol();
	}

	/* Get command character */
	key = getch();
	switch (toupper(key)) {
	case '\014':	/* ^L (redraw) */
	    clear();
	    msg = NULL;
	    break;
	    
	case '\020':	/* ^P */
	case KEY_UP:
	case '-':
	    if (current_chunk != 0)
		--current_chunk;
	    break;
	    
	case '\016':	/* ^N */
	case KEY_DOWN:
	case '+':
	case '\r':
	case '\n':
	    if (chunk_info[current_chunk + 1])
		++current_chunk;
	    break;

	case KEY_HOME:
	    current_chunk = 0;
	    break;

	case KEY_END:
	    while (chunk_info[current_chunk + 1])
		++current_chunk;
	    break;

	case KEY_F(1):
	case '?':
	    systemDisplayHelp("slice");
	    clear();
	    break;

	case 'A':
	case 'F':	/* Undocumented magic Dangerously Dedicated mode */
#if !defined(__i386__) && !defined(__amd64__)
	    rv = 1;
#else	    /* The rest is only relevant on x86 */
	    cp = variable_get(VAR_DEDICATE_DISK);
	    if (cp && !strcasecmp(cp, "always"))
		rv = 1;
	    else if (toupper(key) == 'A')
		rv = 0;
	    else {
		rv = msgYesNo("Do you want to do this with a true partition entry\n"
			      "so as to remain cooperative with any future possible\n"
			      "operating systems on the drive(s)?\n"
			      "(See also the section about ``dangerously dedicated''\n"
			      "disks in the FreeBSD FAQ.)");
		if (rv == -1)
		    rv = 0;
	    }
#endif
	    All_FreeBSD(d, rv);
	    variable_set2(DISK_PARTITIONED, "yes", 0);
	    record_chunks(d);
	    clear();
	    break;
	    
	case 'C':
	    if (chunk_info[current_chunk]->type != unused)
		msg = "Slice in use, delete it first or move to an unused one.";
	    else {
		char *val, tmp[20], name[16], *cp;
		daddr_t size;
		int subtype;
		chunk_e partitiontype;
#ifdef PC98
		snprintf(name, sizeof (name), "%s", "FreeBSD");
		val = msgGetInput(name,
			"Please specify the name for new FreeBSD slice.");
		if (val)
			strncpy(name, val, sizeof (name));
#else
		name[0] = '\0';
#endif
		snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size);<commit_msg>Remove the "dedicated disk mode" partitioning option from sysinstall, in both the disk partitioning screen (the 'F' key) and via install.cfg (the VAR_DEDICATED_DISK option).  This functionality is currently broken in 8.x due to libdisk and geom generating different partition names; this commit merely acts to help steer users away from the breakage.<commit_after>/*
 * The new sysinstall program.
 *
 * This is probably the last program in the `sysinstall' line - the next
 * generation being essentially a complete rewrite.
 *
 * $FreeBSD$
 *
 * Copyright (c) 1995
 *	<NAME>.  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 <NAME> ``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 <NAME> 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 <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libdisk.h>
#include <sys/stat.h>
#include <sys/disklabel.h>

#ifdef WITH_SLICES
enum size_units_t { UNIT_BLOCKS, UNIT_KILO, UNIT_MEG, UNIT_GIG, UNIT_SIZE };

#ifdef PC98
#define	SUBTYPE_FREEBSD		50324
#define	SUBTYPE_FAT		37218
#else
#define	SUBTYPE_FREEBSD		165
#define	SUBTYPE_FAT		6
#endif
#define	SUBTYPE_EFI		239

#ifdef PC98
#define	OTHER_SLICE_VALUES						\
	"Other popular values are 37218 for a\n"			\
	"DOS FAT partition.\n\n"
#else
#define	OTHER_SLICE_VALUES						\
	"Other popular values are 6 for a\n"				\
	"DOS FAT partition, 131 for a Linux ext2fs partition, or\n"	\
	"130 for a Linux swap partition.\n\n"
#endif
#define	NON_FREEBSD_NOTE						\
	"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."

/* Where we start displaying chunk information on the screen */
#define CHUNK_START_ROW		5

/* Where we keep track of MBR chunks */
#define	CHUNK_INFO_ENTRIES	16
static struct chunk *chunk_info[CHUNK_INFO_ENTRIES];
static int current_chunk;

static void	diskPartitionNonInteractive(Device *dev);
static u_char *	bootalloc(char *name, size_t *size);

static void
record_chunks(Disk *d)
{
    struct chunk *c1 = NULL;
    int i = 0;
    daddr_t 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 daddr_t Total;

static void
check_geometry(Disk *d)
{
    int sg;

#ifdef PC98
    if (d->bios_cyl >= 65536 || d->bios_hd > 256 || d->bios_sect >= 256)
#else
    if (d->bios_cyl > 65536 || d->bios_hd > 256 || d->bios_sect >= 64)
#endif
    {
	dialog_clear_norefresh();
	sg = msgYesNo("WARNING:  It is safe to use a geometry of %lu/%lu/%lu for %s on\n"
		      "computers with modern BIOS versions.  If this disk is to be used\n"
		      "on an old machine it is recommended that it does not have more\n"
		      "than 65535 cylinders, more than 255 heads, or more than\n"
#ifdef PC98
		      "255"
#else
		      "63"
#endif
		      " sectors per track.\n"
		      "\n"
		      "Would you like to keep using the current geometry?\n",
		      d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
	if (sg == 1) {
	    Sanitize_Bios_Geom(d);
	    msgConfirm("A geometry of %lu/%lu/%lu was calculated for %s.\n"
		       "\n"
		       "If you are not sure about this, please consult the Hardware Guide\n"
		       "in the Documentation submenu or use the (G)eometry command to\n"
		       "change it.  Remember: you need to enter whatever your BIOS thinks\n"
		       "the 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''.\n",
		       d->bios_cyl, d->bios_hd, d->bios_sect, d->name);
	}
    }
}

static void
print_chunks(Disk *d, int u)
{
    int row;
    int i;
    daddr_t sz;
    char *szstr;

    szstr = (u == UNIT_GIG ? "GB" : (u == UNIT_MEG ? "MB" :
	(u == UNIT_KILO ? "KB" : "ST")));

    Total = 0;
    for (i = 0; chunk_info[i]; i++)
	Total += chunk_info[i]->size;
    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 = %jd sectors (%jdMB)",
	     d->bios_cyl, d->bios_hd, d->bios_sect,
	     (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect,
	     (intmax_t)d->bios_cyl * d->bios_hd * d->bios_sect / (1024/512) / 1024);
    mvprintw(3, 0, "%6s %10s(%s) %10s %8s %6s %10s %8s %8s",
	     "Offset", "Size", szstr, "End", "Name", "PType", "Desc",
	     "Subtype", "Flags");
    for (i = 0, row = CHUNK_START_ROW; chunk_info[i]; i++, row++) {
	switch(u) {
	default:	/* fall thru */
	case UNIT_BLOCKS:
	    sz = chunk_info[i]->size;
	    break;
	case UNIT_KILO:
	    sz = chunk_info[i]->size / (1024/512);
	    break;
	case UNIT_MEG:
	    sz = chunk_info[i]->size / (1024/512) / 1024;
	    break;
	case UNIT_GIG:
	    sz = chunk_info[i]->size / (1024/512) / 1024 / 1024;
	    break;
	}
	if (i == current_chunk)
	    attrset(ATTR_SELECTED);
	mvprintw(row, 0, "%10jd %10jd %10jd %8s %6d %10s %8d\t%-6s",
		 (intmax_t)chunk_info[i]->offset, (intmax_t)sz,
		 (intmax_t)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(void)
{
    mvprintw(14, 0, "The following commands are supported (in upper or lower case):");
    mvprintw(16, 0, "A = Use Entire Disk   G = set Drive Geometry   C = Create Slice");
    mvprintw(17, 0, "D = Delete Slice      Z = Toggle Size Units    S = Set Bootable   | = Wizard m.");
    mvprintw(18, 0, "T = Change Type       U = Undo All Changes     Q = Finish");
    if (!RunningAsInit)
	mvprintw(18, 47, "W = Write Changes");
    mvprintw(21, 0, "Use F1 or ? to get more help, arrow keys to select.");
    move(0, 0);
}

#ifdef PC98
static void
getBootMgr(char *dname, u_char **bootipl, size_t *bootipl_size,
	   u_char **bootmenu, size_t *bootmenu_size)
{
    static u_char *boot0;
    static size_t boot0_size;
    static u_char *boot05;
    static size_t boot05_size;

    char str[80];
    char *cp;
    int i = 0;

    cp = variable_get(VAR_BOOTMGR);
    if (!cp) {
	/* Figure out what kind of IPL the user wants */
	sprintf(str, "Install Boot Manager for drive %s?", dname);
	MenuIPLType.title = str;
	i = dmenuOpenSimple(&MenuIPLType, FALSE);
    } else {
	if (!strncmp(cp, "boot", 4))
	    BootMgr = 0;
	else
	    BootMgr = 1;
    }
    if (cp || i) {
	switch (BootMgr) {
	case 0:
	    if (!boot0) boot0 = bootalloc("boot0", &boot0_size);
	    *bootipl = boot0;
	    *bootipl_size = boot0_size;
	    if (!boot05) boot05 = bootalloc("boot0.5", &boot05_size);
	    *bootmenu = boot05;
	    *bootmenu_size = boot05_size;
	    return;
	case 1:
	default:
	    break;
	}
    }
    *bootipl = NULL;
    *bootipl_size = 0;
    *bootmenu = NULL;
    *bootmenu_size = 0;
}
#else
static void
getBootMgr(char *dname, u_char **bootCode, size_t *bootCodeSize)
{
#if defined(__i386__) || defined(__amd64__)	/* only meaningful on x86 */
    static u_char *mbr, *boot0;
    static size_t mbr_size, boot0_size;
    char str[80];
    char *cp;
    int i = 0;

    cp = variable_get(VAR_BOOTMGR);
    if (!cp) {
	/* Figure out what kind of MBR the user wants */
	sprintf(str, "Install Boot Manager for drive %s?", dname);
	MenuMBRType.title = str;
	i = dmenuOpenSimple(&MenuMBRType, FALSE);
    }
    else {
	if (!strncmp(cp, "boot", 4))
	    BootMgr = 0;
	else if (!strcmp(cp, "standard"))
	    BootMgr = 1;
	else
	    BootMgr = 2;
    }
    if (cp || i) {
	switch (BootMgr) {
	case 0:
	    if (!boot0) boot0 = bootalloc("boot0", &boot0_size);
	    *bootCode = boot0;
	    *bootCodeSize = boot0_size;
	    return;
	case 1:
	    if (!mbr) mbr = bootalloc("mbr", &mbr_size);
	    *bootCode = mbr;
	    *bootCodeSize = mbr_size;
	    return;
	case 2:
	default:
	    break;
	}
    }
#endif
    *bootCode = NULL;
    *bootCodeSize = 0;
}
#endif
#endif /* WITH_SLICES */

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;
}

#ifdef WITH_SLICES
void
diskPartition(Device *dev)
{
    char *cp, *p;
    int rv, key = 0;
    int i;
    Boolean chunking;
    char *msg = NULL;
#ifdef PC98
    u_char *bootipl;
    size_t bootipl_size;
    u_char *bootmenu;
    size_t bootmenu_size;
#else
    u_char *mbrContents;
    size_t mbrSize;
#endif
    WINDOW *w = savescr();
    Disk *d = (Disk *)dev->private;
    int size_unit;

    size_unit = UNIT_BLOCKS;
    chunking = TRUE;
    keypad(stdscr, TRUE);

    /* Flush both the dialog and curses library views of the screen
       since we don't always know who called us */
    dialog_clear_norefresh(), clear();
    current_chunk = 0;

    /* Set up the chunk array */
    record_chunks(d);

    /* Give the user a chance to sanitize the disk geometry, if necessary */
    check_geometry(d);

    while (chunking) {
	char *val, geometry[80];
	    
	/* Now print our overall state */
	if (d)
	    print_chunks(d, size_unit);
	print_command_summary();
	if (msg) {
	    attrset(title_attr); mvprintw(23, 0, msg); attrset(A_NORMAL);
	    beep();
	    msg = NULL;
	}
	else {
	    move(23, 0);
	    clrtoeol();
	}

	/* Get command character */
	key = getch();
	switch (toupper(key)) {
	case '\014':	/* ^L (redraw) */
	    clear();
	    msg = NULL;
	    break;
	    
	case '\020':	/* ^P */
	case KEY_UP:
	case '-':
	    if (current_chunk != 0)
		--current_chunk;
	    break;
	    
	case '\016':	/* ^N */
	case KEY_DOWN:
	case '+':
	case '\r':
	case '\n':
	    if (chunk_info[current_chunk + 1])
		++current_chunk;
	    break;

	case KEY_HOME:
	    current_chunk = 0;
	    break;

	case KEY_END:
	    while (chunk_info[current_chunk + 1])
		++current_chunk;
	    break;

	case KEY_F(1):
	case '?':
	    systemDisplayHelp("slice");
	    clear();
	    break;

	case 'A':
#if !defined(__i386__) && !defined(__amd64__)
	    rv = 1;
#else	    /* The rest is only relevant on x86 */
	    rv = 0;
#endif
	    All_FreeBSD(d, rv);
	    variable_set2(DISK_PARTITIONED, "yes", 0);
	    record_chunks(d);
	    clear();
	    break;
	    
	case 'C':
	    if (chunk_info[current_chunk]->type != unused)
		msg = "Slice in use, delete it first or move to an unused one.";
	    else {
		char *val, tmp[20], name[16], *cp;
		daddr_t size;
		int subtype;
		chunk_e partitiontype;
#ifdef PC98
		snprintf(name, sizeof (name), "%s", "FreeBSD");
		val = msgGetInput(name,
			"Please specify the name for new FreeBSD slice.");
		if (val)
			strncpy(name, val, sizeof (name));
#else
		name[0] = '\0';
#endif
		snprintf(tmp, 20, "%jd", (intmax_t)chunk_info[current_chunk]->size);
{'fraction_non_alphanumeric': 0.13039532865146375, 'fraction_numerical': 0.024461453483784423, 'mean_word_length': 3.0030006317119393, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1753894', 'n_tokens_mistral': 10146, 'n_tokens_neox': 9191, 'n_words': 2856}