/*
 * Copyright (c)2004 The DragonFly Project.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 *   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.
 * 
 *   Neither the name of the DragonFly Project nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS 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, 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. 
 */

/*
 * fn_install.c
 * Installer Function : Install OS Files.
 * $Id: fn_install.c,v 1.6 2004/07/11 07:37:05 cpressey Exp $
 */

#include <dfui/dfui.h>
#include <dfui/fspred.h>

#include "diskutil.h"
#include "uiutil.h"
#include "commands.h"
#include "pathnames.h"
#include "functions.h"
#include "confed.h"
#include "cmds.h"
#include "flow.h"

extern struct system_storage *ss;
extern struct dfui_connection *c;
extern char dfly_root[];

/*
 * fn_install_os: actually put DragonFly on a disk.
 */
int
fn_install_os(void)
{
	struct subpartition *sp;
	struct commands *cmds;
	struct config_vars *rc_conf;
	char *string;
	int result = 0;

	cmds = commands_new();

	/*
	 * If swap isn't mounted yet, mount it.
	 */
	if (measure_activated_swap() == 0) {
		for (sp = ss->selected_slice->subpartition_head;
		     sp != NULL; sp = sp->next) {
			if (!sp->is_swap)
				continue;
			command_add(cmds, "swapon %sdev/%ss%d%c",
			    dfly_root,
			    ss->selected_disk->device,
			    ss->selected_slice->number,
			    sp->letter);
		}
	}

	/*
	 * Create mount points and mount subpartitions on them.
	 */
	unmount_all_under(NULL, "%smnt", dfly_root);
	for (sp = ss->selected_slice->subpartition_head; sp != NULL; sp = sp->next) {
		if (sp->is_swap) {
			/*
			 * Set this subpartition as the dump device.
			 */
#ifdef AUTOMATICALLY_ENABLE_CRASH_DUMPS
			rc_conf = config_vars_new();
			asprintf(&string, "/dev/%ss%d%c",
			    ss->selected_disk->device,
			    ss->selected_slice->number, sp->letter);
			config_var_set(rc_conf, "dumpdev", string);
			config_var_set(rc_conf, "dumpdir", "/var/crash");
			config_vars_write(rc_conf, CONFIG_TYPE_SH,
			    "%s%setc/rc.conf", dfly_root, "/");
			config_vars_free(rc_conf);
#endif
			continue;
		}
	
		if (strcmp(sp->mountpoint, "/") != 0) {
			command_add(cmds, "mkdir %smnt%s",
				dfly_root, sp->mountpoint);
		}

		command_add(cmds, "mount %sdev/%ss%d%c %smnt%s",
			dfly_root,
			ss->selected_disk->device,
			ss->selected_slice->number,
			sp->letter,
			dfly_root,
			sp->mountpoint);
	}

	/* Copy files */

	for (sp = ss->selected_slice->subpartition_head; sp != NULL; sp = sp->next) {
		if (sp->is_swap)
			continue;
		/*
		 * If the mountpoint doesn't even exist on the LiveCD, don't
		 * try to copy anything from it!
		 */
		if (!is_dir("%s%s", dfly_root, &sp->mountpoint[1]))
			continue;

		/*
		 * If the mountpoint is '/', split up the copy into smaller
		 * chunks - this lets us avoid copying all of /usr/.
		 */
		if (strcmp(sp->mountpoint, "/") == 0) {
			cpdup_dir(cmds, ss->selected_slice, sp->mountpoint,
			    "COPYRIGHT", "bin", "boot", "dev",
			    "etc", "kernel", "modules", "root",
			    "sbin", "sys", "tmp", "usr", "var",
			    NULL);
			continue;
		}

		/*
		 * If the mountpoint is '/usr', split up the copy into smaller
		 * chunks - this lets us avoid copying all of /usr/local.
		 */
		if (strcmp(sp->mountpoint, "/usr") == 0) {
			cpdup_dir(cmds, NULL, "/usr/",
			    "bin", "games", "include", "lib",
#ifdef INSTALL_USR_LOCAL
			    "local",
#endif
			    "libdata", "libexec", "obj", "sbin",
			    "share", "src", NULL);
			continue;
		}
			
		/*
		 * Otherwise, cpdup the subpartition.
		 */
		command_add_logless(cmds, CPDUP_CMD " %s%s %smnt%s",
		    dfly_root, &sp->mountpoint[1],
		    dfly_root, sp->mountpoint);
	}

	/* Create symlinks. */

	/*
	 * If the user has both /var and /tmp subparitions,
	 * symlink /var/tmp to /tmp.
	 */
	if (subpartition_find(ss->selected_slice, "/tmp") != NULL &&
	    subpartition_find(ss->selected_slice, "/var") != NULL) {
		command_add(cmds, "chmod 1777 %smnt/tmp", dfly_root);
		command_add(cmds, "rm -rf %smnt/var/tmp", dfly_root);
		command_add(cmds, "ln -s /tmp %smnt/var/tmp", dfly_root);
	}

	/*
	 * XXX check for other possible combinations too
	 */

	/*
	 * Clean up.  In case some file didn't make it, use rm -f
	 */
	command_add(cmds, "rm -f %smnt/boot/loader.conf", dfly_root);
	command_add(cmds, "rm -f %smnt/etc/rc.d/pfi", dfly_root);
	command_add(cmds, "rm -f %smnt/etc/issue", dfly_root);
	command_add(cmds, "rm -f %smnt/tmp/install.log", dfly_root);

	/*
	 * Copy pristine versions of any files we might have installed
	 * that only have applicability to Live CD boots.
	 */
	command_add_logless(cmds,
	    "%s %susr/local/share/pristine/etc %smnt/etc",
	    CPDUP_CMD, dfly_root, dfly_root);

	/*
	 * Rebuild the user database, to get rid of any extra users
	 * from the LiveCD that aren't supposed to be installed
	 * (copying a pristine master.passwd isn't enough.)
	 */
	command_add(cmds, "pwd_mkdb -p -d %smnt/etc %smnt/etc/master.passwd",
	    dfly_root, dfly_root);

	/* Create missing directories. */
	command_add(cmds, "mkdir %smnt/proc", dfly_root);
	command_add(cmds, "mkdir %smnt/mnt", dfly_root);

	/* Write new fstab. */

	command_add_function(cmds, cmd_write_fstab, (void *)ss,
	    "write_fstab()");

	/* Backup the disklabel and the log. */

	command_add(cmds, "disklabel %ss%d > %smnt/etc/disklabel.%ss%d",
	    ss->selected_disk->device, ss->selected_slice->number, dfly_root,
	    ss->selected_disk->device, ss->selected_slice->number);
	command_add(cmds, "cp %sinstall.log %smnt/var/log/install.log",
	    INSTALLER_TEMP, dfly_root);
	command_add(cmds, "chmod 600 %smnt/var/log/install.log",
	    dfly_root);

	/*
	 * Do it!
	 */
	/* commands_preview(cmds); */
	if (!commands_execute(c, cmds)) {
		inform(	"DragonFly was not fully installed.");
		result = 0;
	} else {
		result = 1;
	}
	commands_free(cmds);

	/*
	 * Unmount the partitions.  This is done in a seperate command
	 * chain, so that partitions are unmounted, even if an error
	 * occurs in one of the preceding commands, or it is cancelled.
	 */
	cmds = commands_new();
	/* cmds->cancellable = 0; */
	for (sp = ss->selected_slice->subpartition_head; sp != NULL; sp = sp->next) {
		if (sp->is_swap)
			continue;
		if (!strcmp(sp->mountpoint, "/"))
			continue;
		command_add(cmds, "umount %smnt%s",
			dfly_root,
			sp->mountpoint);
	}
	command_add(cmds, "umount %smnt/", dfly_root);

	if (!commands_execute(c, cmds)) {
		inform(	"Warning: subpartitions were not correctly unmounted.");
	}
	commands_free(cmds);

	return(result);
}
