/*
 * The new sysinstall program.
 *
 * This is probably the last attempt in the `sysinstall' line, the next
 * generation being slated to essentially a complete rewrite.
 *
 * $FreeBSD: src/release/sysinstall/floppy.c,v 1.31.2.3 1999/08/29 15:54:00 peter Exp $
 *
 * Copyright (c) 1995
 *	Jordan Hubbard.  All rights reserved.
 * Copyright (c) 1995
 * 	Gary J Palmer. 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.
 *
 */

/* These routines deal with getting things off of floppy media */

#include "sysinstall.h"
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <unistd.h>
#include <grp.h>

#define MSDOSFS
#include <sys/mount.h>
#include <msdosfs/msdosfsmount.h>
#undef MSDOSFS

#include <ufs/ufs/ufsmount.h>
static Boolean floppyMounted;

char *distWanted;
static char mountpoint[] = "/dist";

#ifdef PC98
#if 0
/* static Boolean mountFloppy(Device *dev); */

static Device *floppyDev;

/* For finding floppies */
static int
floppyChoiceHook(dialogMenuItem *self)
{
    Device **devs;

    devs = deviceFind(self->prompt, DEVICE_TYPE_FLOPPY);
    if (devs)
	floppyDev = devs[0];
    return devs ? DITEM_LEAVE_MENU : DITEM_FAILURE;
}

/* Our last-ditch routine for getting HELP file from a floppy */
int
getHelpFloppy(void)
{
    Device **devs;
    int cnt;
    int fd = -1;
    int r;
    char devname[24];
    char rdevname[24];
    char buff[512];

    msgDebug("getHelpFloppy:A\n");
retry:
    dialog_clear();
    if (msgYesNo("これから HELP.FLP フロッピーディスクを入力します.\n"
    	         "HELP.FLP は BOOT.FLP に入り切らなかったメッセージ\n"
    	         "ファイルが入っています.\n\n"
    	         "HELP.FLP を入力しなくてもインストールを継続すること\n"
    	         "ができます.\nHELP.FLP フロッピーディスクを入力しますか?")) {
	 goto skip;
    }

    devs = deviceFind(NULL, DEVICE_TYPE_FLOPPY);
    cnt = deviceCount(devs);
    if (!cnt) {
	KANJI_MESSAGE("フロッピーデバイスが見つかりません! 何か深刻な問題があります!");
	msgConfirm(KM("No floppy devices found!  Something is seriously wrong!"));
	return -1;
    }
    else if (cnt == 1) {
	floppyDev = devs[0];
	msgDebug("getHelpFloppy:B1 %s\n", floppyDev->devname);
    }
    else {
	DMenu *menu;
	int ret;
	WINDOW *save = savescr();

	msgDebug("getHelpFloppy:B\n");
	menu = deviceCreateMenu(&MenuMediaFloppy, DEVICE_TYPE_FLOPPY, floppyChoiceHook, NULL);
	KANJI_MESSAGE("HELP.FLPフロッピーを入れてください");
	menu->title = KM("Please insert the HELP.FLP floppy");
	ret = dmenuOpenSimple(menu, FALSE);
	restorescr(save);
	if (!ret)
	    return -1;
    }

    msgDebug("getHelpFloppy:C\n");
    /* raw デバイスに変更する */
    if (strcmp(floppyDev->devname, "/dev/fd0") == 0)
    	strcpy(rdevname, "/dev/rfd0");
    else if (strcmp(floppyDev->devname, "/dev/fd1") == 0)
    	strcpy(rdevname, "/dev/rfd1");
    else
    	strcpy(rdevname, floppyDev->devname);	/* そのままとする */

    while (fd == -1) {
	dialog_clear();
	KANJI_MESSAGE("HELP.FLP フロッピーを %s に入れて [RETURN] を押してください");
	msgConfirm(KM("Please insert the HELP.FLP floppy in %s and press [RETURN]"), floppyDev->description);

	strcpy(devname, rdevname);
	msgDebug("getHelpFloppy: %s\n", devname);
	fd = open(devname, O_RDONLY);
	if (fd != -1) {
	    /* フロッピーデバイスは読んで見ないとタイプがあっているどうか */
	    /* わからない */
	    r = read(fd, buff, 512);
	    close(fd);
	    if (r == -1)
		fd = -1;
	}
	/* sprintf(devname, "%s.1232", rdevname); */
	/* /dev/rfdX.1232 はブロックサイズが異なるので入力できない */
	if (fd == -1) {
	    sprintf(devname, "%s.1440", rdevname);
	    msgDebug("getHelpFloppy: %s\n", devname);
	    fd = open(devname, O_RDONLY);
	    if (fd != -1) {
		/* フロッピーデバイスは読んで見ないとタイプがあっているどうか */
		/* わからない */
		r = read(fd, buff, 512);
		close(fd);
		if (r == -1)
		    fd = -1;
	    }
	}
	KANJI_MESSAGE("フロッピーをオープンできませんでした - 再試行しますか?");
	if (fd == -1 && msgYesNo(KM("Couldn't open the floppy - do you want to try again?")) == 0)
	    break;
    }
    if (fd == -1) {
skip:
	dialog_clear();
	KANJI_MESSAGE("OK! 表示できないメッセージがありますが継続します");
	msgConfirm(KM("OK! some messages can't display, but continue"));
	return -1;
    }
    msgNotify("メッセージファイルを読み込んでいます…");
    if (vsystem("cd /stand; cpio -ivdu <%s", devname)) {
	dialog_clear();
	KANJI_MESSAGE("フロッピーを正常に読み込めませんでした - 再試行しますか?");
	if (msgYesNo(KM("Couldn't read the floppy - do you want to try again?")) != 0)
	    goto retry;
	return -1;
    }
    unlink("/stand/help.JP/miss");
    return 0;
}
#endif
#endif

Boolean
mediaInitFloppy(Device *dev)
{
    struct msdosfs_args dosargs;
    struct ufs_args u_args;
    char *mp;
#ifdef PC98
    char fd144[24];
    char *devname;
#endif

    if (floppyMounted)
	return TRUE;

    mp = dev->private ? (char *)dev->private : mountpoint;
    if (Mkdir(mp)) {
	KANJI_MESSAGE("%s のための %s ディレクトリーマウントポイントを作れませんでした!");
	msgConfirm(KM("Unable to make %s directory mountpoint for %s!"), mp, dev->devname);
	return FALSE;
    }

    msgDebug("Init floppy called for %s distribution.\n", distWanted ? distWanted : "some");

    if (!variable_get(VAR_NONINTERACTIVE)) {
	if (!distWanted) {
	    KANJI_MESSAGE("%s に次のフロッピーを入れてください");
	    msgConfirm(KM("Please insert floppy in %s"), dev->description);
	}
	else {
	    KANJI_MESSAGE("%s の入っているフロッピーを %s に入れてください");
	    msgConfirm(KM("Please insert floppy containing %s in %s"),
			distWanted, dev->description);
	}
    }

    memset(&dosargs, 0, sizeof dosargs);
    dosargs.fspec = dev->devname;
    dosargs.uid = dosargs.gid = 0;
    dosargs.mask = 0777;

    memset(&u_args, 0, sizeof(u_args));
    u_args.fspec = dev->devname;

#ifndef PC98
    if (mount("msdos", mp, MNT_RDONLY, (caddr_t)&dosargs) == -1) {
	if (mount("ufs", mp, MNT_RDONLY, (caddr_t)&u_args) == -1) {
	    KANJI_MESSAGE("エラー %s (%s) フロッピーを %s にマウントできません : %s");
	    msgConfirm(KM("Error mounting floppy %s (%s) on %s : %s"),
		       dev->name, dev->devname, mp, strerror(errno));
	    return FALSE;
	}
    }
#else
    devname = dev->devname;
    sprintf(fd144, "%s.1232", dev->devname);
    if (mount("msdos", mp, MNT_RDONLY, (caddr_t)&dosargs) == -1) {
	if (mount("ufs", mp, MNT_RDONLY, (caddr_t)&u_args) == -1) {
#if 1	/* 3.2R は 2HD をサポートしている */
	    /* /dev/fd[01] が失敗したら /dev/fd[01].1232 を試みる */
	    devname = dosargs.fspec = u_args.fspec = fd144;
	    if (mount("msdos", mp, MNT_RDONLY, (caddr_t)&dosargs) == -1) {
		if (mount("ufs", mp, MNT_RDONLY, (caddr_t)&u_args) == -1) {
#endif
#if 1	/* fd?.1440 */
		    /* /dev/fd[01].1232 が失敗したら /dev/fd[01].1440 を試みる */
		    sprintf(fd144, "%s.1440", dev->devname);
		    devname = dosargs.fspec = u_args.fspec = fd144;
		    if (mount("msdos", mp, MNT_RDONLY, (caddr_t)&dosargs) == -1) {
			if (mount("ufs", mp, MNT_RDONLY, (caddr_t)&u_args) == -1) {
#endif
			    KANJI_MESSAGE("エラー %s (%s) フロッピーを %s にマウントできません : %s");
			    msgConfirm(KM("Error mounting floppy %s (%s) on %s : %s"),
			       dev->name, devname, mp, strerror(errno));
			    return FALSE;
#if 1	/* fd?.1440 */
			}
		    }
#endif
#if 1	/* 3.2R は 2HD をサポートしている */
		}
	    }
#endif
	}
    }
#endif
    floppyMounted = TRUE;
    distWanted = NULL;
    return TRUE;
}

FILE *
mediaGetFloppy(Device *dev, char *file, Boolean probe)
{
    char	buf[PATH_MAX], *mp;
    FILE	*fp;
    int		nretries = 5;

    /*
     * floppies don't use mediaGenericGet() because it's too expensive
     * to speculatively open files on a floppy disk.  Make user get it
     * right or give up with floppies.
     */
    mp = dev->private ? (char *)dev->private : mountpoint;
    snprintf(buf, PATH_MAX, "%s/%s", mp, file);
    if (!file_readable(buf)) {
	if (probe)
	    return NULL;
	else {
	    while (!file_readable(buf)) {
		if (!--nretries) {
		    KANJI_MESSAGE("GetFloppy: 何度も再試行しましたが %s を取り込めませんでした;\n諦めます.");
		    msgConfirm(KM("GetFloppy: Failed to get %s after retries;\ngiving up."), buf);
		    return NULL;
		}
		distWanted = buf;
		mediaShutdownFloppy(dev);
		if (!mediaInitFloppy(dev))
		    return NULL;
	    }
	}
    }
    fp = fopen(buf, "r");
    return fp;
}

void
mediaShutdownFloppy(Device *dev)
{
    if (floppyMounted) {
    	char *mp = dev->private ? (char *)dev->private : mountpoint;

	if (unmount(mp, MNT_FORCE) != 0)
	    msgDebug("Umount of floppy on %s failed: %s (%d)\n", mp, strerror(errno), errno);
	else {
	    floppyMounted = FALSE;
	    if (!variable_get(VAR_NONINTERACTIVE) && variable_cmp(SYSTEM_STATE, "fixit")) {
		KANJI_MESSAGE("%s からフロッピーを取り除いてください");
		msgConfirm(KM("You may remove the floppy from %s"), dev->description);
	    }
	}
    }
}
