Exemplo n.º 1
0
void
loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
{
	static char mallocbuf[MALLOCSZ];
	const char *var;
	int i;

	if (version < USERBOOT_VERSION)
		abort();

	callbacks = cb;
	callbacks_arg = arg;
	userboot_disk_maxunit = ndisks;

	/*
	 * initialise the heap as early as possible.  Once this is done,
	 * alloc() is usable.
	 */
	setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf)));

	/*
	 * Hook up the console
	 */
	cons_probe();

	printf("\n");
	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
#if 0
	printf("Memory: %ld k\n", memsize() / 1024);
#endif

	setenv("LINES", "24", 1);	/* optional */

	/*
	 * Set custom environment variables
	 */
	i = 0;
	while (1) {
		var = CALLBACK(getenv, i++);
		if (var == NULL)
			break;
		putenv(var);
	}

	archsw.arch_autoload = userboot_autoload;
	archsw.arch_getdev = userboot_getdev;
	archsw.arch_copyin = userboot_copyin;
	archsw.arch_copyout = userboot_copyout;
	archsw.arch_readin = userboot_readin;
#if defined(USERBOOT_ZFS_SUPPORT)
	archsw.arch_zfs_probe = userboot_zfs_probe;
#endif

	/*
	 * Initialise the block cache. Set the upper limit.
	 */
	bcache_init(32768, 512);
	/*
	 * March through the device switch probing for things.
	 */
	for (i = 0; devsw[i] != NULL; i++)
		if (devsw[i]->dv_init != NULL)
			(devsw[i]->dv_init)();

	extract_currdev();

	if (setjmp(jb))
		return;

	interact(NULL);			/* doesn't return */

	exit(0);
}
Exemplo n.º 2
0
int
main(int (*openfirm)(void *))
{
	char bootpath[64];
	struct devsw **dp;
	phandle_t chosenh;

	/*
	 * Tell the OpenFirmware functions where they find the ofw gate.
	 */
	OF_init(openfirm);

	archsw.arch_getdev = ofw_getdev;
	archsw.arch_copyin = sparc64_copyin;
	archsw.arch_copyout = ofw_copyout;
	archsw.arch_readin = sparc64_readin;
	archsw.arch_autoload = sparc64_autoload;

	init_heap();
	setheap((void *)heapva, (void *)(heapva + HEAPSZ));

	/*
	 * Probe for a console.
	 */
	cons_probe();

	tlb_init();

	bcache_init(32, 512);

	/*
	 * Initialize devices.
	 */
	for (dp = devsw; *dp != 0; dp++) {
		if ((*dp)->dv_init != 0)
			(*dp)->dv_init();
	}

	/*
	 * Set up the current device.
	 */
	chosenh = OF_finddevice("/chosen");
	OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));

	/*
	 * Sun compatible bootable CD-ROMs have a disk label placed
	 * before the cd9660 data, with the actual filesystem being
	 * in the first partition, while the other partitions contain
	 * pseudo disk labels with embedded boot blocks for different
	 * architectures, which may be followed by UFS filesystems.
	 * The firmware will set the boot path to the partition it
	 * boots from ('f' in the sun4u case), but we want the kernel
	 * to be loaded from the cd9660 fs ('a'), so the boot path
	 * needs to be altered.
	 */
	if (bootpath[strlen(bootpath) - 2] == ':' &&
	    bootpath[strlen(bootpath) - 1] == 'f') {
		bootpath[strlen(bootpath) - 1] = 'a';
		printf("Boot path set to %s\n", bootpath);
	}

	env_setenv("currdev", EV_VOLATILE, bootpath,
	    ofw_setcurrdev, env_nounset);
	env_setenv("loaddev", EV_VOLATILE, bootpath,
	    env_noset, env_nounset);

	printf("\n");
	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
	printf("bootpath=\"%s\"\n", bootpath);

	/* Give control to the machine independent loader code. */
	interact();
	return 1;
}
Exemplo n.º 3
0
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
	EFI_LOADED_IMAGE *img;
	int i;

	/* 
	 * XXX Chicken-and-egg problem; we want to have console output
	 * early, but some console attributes may depend on reading from
	 * eg. the boot device, which we can't do yet.  We can use
	 * printf() etc. once this is done.
	 */
	cons_probe();

	/*
	 * Initialise the block cache
	 */
	bcache_init(32, 512);		/* 16k XXX tune this */

	find_pal_proc();

	/*
	 * March through the device switch probing for things.
	 */
	for (i = 0; devsw[i] != NULL; i++)
		if (devsw[i]->dv_init != NULL)
			(devsw[i]->dv_init)();

	efinet_init_driver();

	/* Get our loaded image protocol interface structure. */
	BS->HandleProtocol(IH, &imgid, (VOID**)&img);

	printf("Image base: 0x%016lx\n", (u_long)img->ImageBase);

	printf("\n");
	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
	printf("(%s, %s)\n", bootprog_maker, bootprog_date);

	i = efifs_get_unit(img->DeviceHandle);
	if (i >= 0) {
		currdev.d_dev = devsw[0];		/* XXX disk */
		currdev.d_kind.efidisk.unit = i;
		/* XXX should be able to detect this, default to autoprobe */
		currdev.d_kind.efidisk.slice = -1;
		currdev.d_kind.efidisk.partition = 0;
	} else {
		currdev.d_dev = devsw[1];		/* XXX net */
		currdev.d_kind.netif.unit = 0;		/* XXX */
	}
	currdev.d_type = currdev.d_dev->dv_type;

	/*
	 * Disable the watchdog timer. By default the boot manager sets
	 * the timer to 5 minutes before invoking a boot option. If we
	 * want to return to the boot manager, we have to disable the
	 * watchdog timer and since we're an interactive program, we don't
	 * want to wait until the user types "quit". The timer may have
	 * fired by then. We don't care if this fails. It does not prevent
	 * normal functioning in any way...
	 */
	BS->SetWatchdogTimer(0, 0, 0, NULL);

	env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
	    efi_setcurrdev, env_nounset);
	env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
	    env_nounset);

	setenv("LINES", "24", 1);	/* optional */
    
	archsw.arch_autoload = efi_autoload;
	archsw.arch_getdev = efi_getdev;
	archsw.arch_copyin = efi_copyin;
	archsw.arch_copyout = efi_copyout;
	archsw.arch_readin = efi_readin;

	interact();			/* doesn't return */

	return (EFI_SUCCESS);		/* keep compiler happy */
}
Exemplo n.º 4
0
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
	char var[128];
	EFI_LOADED_IMAGE *img;
	EFI_GUID *guid;
	int i, j, vargood, unit, howto;
	struct devsw *dev;
	uint64_t pool_guid;
	UINTN k;
	int has_kbd;

	archsw.arch_autoload = efi_autoload;
	archsw.arch_getdev = efi_getdev;
	archsw.arch_copyin = efi_copyin;
	archsw.arch_copyout = efi_copyout;
	archsw.arch_readin = efi_readin;
#ifdef EFI_ZFS_BOOT
	/* Note this needs to be set before ZFS init. */
	archsw.arch_zfs_probe = efi_zfs_probe;
#endif

	has_kbd = has_keyboard();

	/*
	 * XXX Chicken-and-egg problem; we want to have console output
	 * early, but some console attributes may depend on reading from
	 * eg. the boot device, which we can't do yet.  We can use
	 * printf() etc. once this is done.
	 */
	cons_probe();

	/*
	 * Initialise the block cache. Set the upper limit.
	 */
	bcache_init(32768, 512);

	/*
	 * Parse the args to set the console settings, etc
	 * boot1.efi passes these in, if it can read /boot.config or /boot/config
	 * or iPXE may be setup to pass these in.
	 *
	 * Loop through the args, and for each one that contains an '=' that is
	 * not the first character, add it to the environment.  This allows
	 * loader and kernel env vars to be passed on the command line.  Convert
	 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied.
	 */
	howto = 0;
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			for (j = 1; argv[i][j] != 0; j++) {
				int ch;

				ch = argv[i][j];
				switch (ch) {
				case 'a':
					howto |= RB_ASKNAME;
					break;
				case 'd':
					howto |= RB_KDB;
					break;
				case 'D':
					howto |= RB_MULTIPLE;
					break;
				case 'h':
					howto |= RB_SERIAL;
					break;
				case 'm':
					howto |= RB_MUTE;
					break;
				case 'p':
					howto |= RB_PAUSE;
					break;
				case 'P':
					if (!has_kbd)
						howto |= RB_SERIAL | RB_MULTIPLE;
					break;
				case 'r':
					howto |= RB_DFLTROOT;
					break;
				case 's':
					howto |= RB_SINGLE;
					break;
				case 'S':
					if (argv[i][j + 1] == 0) {
						if (i + 1 == argc) {
							setenv("comconsole_speed", "115200", 1);
						} else {
							cp16to8(&argv[i + 1][0], var,
							    sizeof(var));
							setenv("comconsole_speedspeed", var, 1);
						}
						i++;
						break;
					} else {
						cp16to8(&argv[i][j + 1], var,
						    sizeof(var));
						setenv("comconsole_speed", var, 1);
						break;
					}
				case 'v':
					howto |= RB_VERBOSE;
					break;
				}
			}
		} else {
			vargood = 0;
			for (j = 0; argv[i][j] != 0; j++) {
				if (j == sizeof(var)) {
					vargood = 0;
					break;
				}
				if (j > 0 && argv[i][j] == '=')
					vargood = 1;
				var[j] = (char)argv[i][j];
			}
			if (vargood) {
				var[j] = 0;
				putenv(var);
			}
		}
	}
	for (i = 0; howto_names[i].ev != NULL; i++)
		if (howto & howto_names[i].mask)
			setenv(howto_names[i].ev, "YES", 1);
	if (howto & RB_MULTIPLE) {
		if (howto & RB_SERIAL)
			setenv("console", "comconsole efi" , 1);
		else
			setenv("console", "efi comconsole" , 1);
	} else if (howto & RB_SERIAL) {
		setenv("console", "comconsole" , 1);
	}

	if (efi_copy_init()) {
		printf("failed to allocate staging area\n");
		return (EFI_BUFFER_TOO_SMALL);
	}

	/*
	 * March through the device switch probing for things.
	 */
	for (i = 0; devsw[i] != NULL; i++)
		if (devsw[i]->dv_init != NULL)
			(devsw[i]->dv_init)();

	/* Get our loaded image protocol interface structure. */
	BS->HandleProtocol(IH, &imgid, (VOID**)&img);

	printf("Command line arguments:");
	for (i = 0; i < argc; i++) {
		printf(" ");
		print_str16(argv[i]);
	}
	printf("\n");

	printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
	printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
	    ST->Hdr.Revision & 0xffff);
	printf("EFI Firmware: ");
	/* printf doesn't understand EFI Unicode */
	ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor);
	printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16,
	    ST->FirmwareRevision & 0xffff);

	printf("\n");
	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
	printf("(%s, %s)\n", bootprog_maker, bootprog_date);

	/*
	 * Disable the watchdog timer. By default the boot manager sets
	 * the timer to 5 minutes before invoking a boot option. If we
	 * want to return to the boot manager, we have to disable the
	 * watchdog timer and since we're an interactive program, we don't
	 * want to wait until the user types "quit". The timer may have
	 * fired by then. We don't care if this fails. It does not prevent
	 * normal functioning in any way...
	 */
	BS->SetWatchdogTimer(0, 0, 0, NULL);

	if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0)
		return (EFI_NOT_FOUND);

	switch (dev->dv_type) {
#ifdef EFI_ZFS_BOOT
	case DEVT_ZFS: {
		struct zfs_devdesc currdev;

		currdev.d_dev = dev;
		currdev.d_unit = unit;
		currdev.d_type = currdev.d_dev->dv_type;
		currdev.d_opendata = NULL;
		currdev.pool_guid = pool_guid;
		currdev.root_guid = 0;
		env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
			   efi_setcurrdev, env_nounset);
		env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
			   env_nounset);
		init_zfs_bootenv(zfs_fmtdev(&currdev));
		break;
	}
#endif
	default: {
		struct devdesc currdev;

		currdev.d_dev = dev;
		currdev.d_unit = unit;
		currdev.d_opendata = NULL;
		currdev.d_type = currdev.d_dev->dv_type;
		env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
			   efi_setcurrdev, env_nounset);
		env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
			   env_nounset);
		break;
	}
	}

	setenv("LINES", "24", 1);	/* optional */

	for (k = 0; k < ST->NumberOfTableEntries; k++) {
		guid = &ST->ConfigurationTable[k].VendorGuid;
		if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
			smbios_detect(ST->ConfigurationTable[k].VendorTable);
			break;
		}
	}

	interact(NULL);			/* doesn't return */

	return (EFI_SUCCESS);		/* keep compiler happy */
}
Exemplo n.º 5
0
int
main(void)
{
    char *memend;
    int i;

    WDEBUG_INIT();
    WDEBUG('X');

    /* Pick up arguments */
    kargs = (void *)__args;
    initial_howto = kargs->howto;
    initial_bootdev = kargs->bootdev;
    initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;

#ifdef COMCONSOLE_DEBUG
    printf("args at %p initial_howto = %08x bootdev = %08x bootinfo = %p\n",
	kargs, initial_howto, initial_bootdev, initial_bootinfo);
#endif

    /* Initialize the v86 register set to a known-good state. */
    bzero(&v86, sizeof(v86));
    v86.efl = PSL_RESERVED_DEFAULT | PSL_I;

    /*
     * Initialize the heap as early as possible.  Once this is done,
     * malloc() is usable.
     *
     * Don't include our stack in the heap.  If the stack is in low
     * user memory use {end,bios_basemem}.  If the stack is in high
     * user memory but not extended memory then don't let the heap
     * overlap the stack.  If the stack is in extended memory limit
     * the heap to bios_basemem.
     *
     * Be sure to use the virtual bios_basemem address rather then
     * the physical bios_basemem address or we may overwrite BIOS
     * data.
     */
    bios_getmem();

    memend = (char *)&memend - 0x8000;	/* space for stack (16K) */
    memend = (char *)((uintptr_t)memend & ~(uintptr_t)(0x1000 - 1));

    /*
     * For day to day usage simple memend setup is more than engouh,
     * but bigger heap is a must for loading bzipp'ed kernel/modules
     * "bzf_read: BZ2_bzDecompress returned -3"
     */
#if defined(LOADER_BZIP2_SUPPORT)
    if (high_heap_size > 0) {
	heap_top = PTOV(high_heap_base + high_heap_size);
	heap_bottom = PTOV(high_heap_base);
	if (high_heap_base < memtop_copyin)
	    memtop_copyin = high_heap_base;
    } else
#endif
    if (memend < (char *)_end) {
	heap_top = PTOV(bios_basemem);
	heap_bottom = (void *)_end;
    } else {
	if (memend > (char *)PTOV(bios_basemem))
	    memend = (char *)PTOV(bios_basemem);
	heap_top = memend;
	heap_bottom = (void *)_end;
    }
    setheap(heap_bottom, heap_top);

    /*
     * XXX Chicken-and-egg problem; we want to have console output early,
     * but some console attributes may depend on reading from eg. the boot
     * device, which we can't do yet.
     *
     * We can use printf() etc. once this is done.   The previous boot stage
     * might have requested a video or serial preference, in which case we
     * set it.
     */
    bi_setboothowto(initial_howto);
    if (initial_howto & RB_MUTE) {
	setenv("console", "nullconsole", 1);
    } else if ((initial_howto & (RB_VIDEO|RB_SERIAL)) == (RB_VIDEO|RB_SERIAL)) {
	setenv("console", "vidconsole comconsole", 1);
    } else if (initial_howto & RB_VIDEO) {
	setenv("console", "vidconsole", 1);
    } else if (initial_howto & RB_SERIAL) {
	setenv("console", "comconsole", 1);
    } else {
	/* XXX leave to cons_probe() */
    }
    cons_probe();

    /*
     * Initialise the block cache
     */
    bcache_init(32, 512);	/* 16k cache XXX tune this */

    /*
     * Special handling for PXE and CD booting.
     */
    if (kargs->bootinfo == 0) {
	/*
	 * We only want the PXE disk to try to init itself in the below
	 * walk through devsw if we actually booted off of PXE.
	 */
	if (kargs->bootflags & KARGS_FLAGS_PXE)
	    pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
	else if (kargs->bootflags & KARGS_FLAGS_CD)
	    bc_add(initial_bootdev);
    }

    archsw.arch_autoload = i386_autoload;
    archsw.arch_getdev = i386_getdev;
    archsw.arch_copyin = i386_copyin;
    archsw.arch_copyout = i386_copyout;
    archsw.arch_readin = i386_readin;
    archsw.arch_isainb = isa_inb;
    archsw.arch_isaoutb = isa_outb;

    /*
     * March through the device switch probing for things.
     */
    for (i = 0; devsw[i] != NULL; i++) {
	WDEBUG('M' + i);
	if (devsw[i]->dv_init != NULL)
	    (devsw[i]->dv_init)();
	WDEBUG('M' + i);
    }
    printf("BIOS %dkB/%dkB available memory\n",
	    bios_basemem / 1024, bios_extmem / 1024);
    if (initial_bootinfo != NULL) {
	initial_bootinfo->bi_basemem = bios_basemem / 1024;
	initial_bootinfo->bi_extmem = bios_extmem / 1024;
    }

    /* detect ACPI for future reference */
    biosacpi_detect();

    /* detect SMBIOS for future reference */
    smbios_detect(NULL);

    /* detect PCI BIOS for future reference */
    biospci_detect();

    /* enable EHCI */
    setenv("ehci_load", "YES", 1);

    /* enable XHCI */
    setenv("xhci_load", "YES", 1);

    printf("\n");
    printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
    printf("(%s, %s)\n", bootprog_maker, bootprog_date);

    extract_currdev();				/* set $currdev and $loaddev */
    setenv("LINES", "24", 1);			/* optional */

    bios_getsmap();

    interact();			/* doesn't return */

    /* if we ever get here, it is an error */
    return (1);
}
Exemplo n.º 6
0
int
main(void)
{
    int			i;

    /* Set machine type to PC98_SYSTEM_PARAMETER. */
    set_machine_type();

    /* Pick up arguments */
    kargs = (void *)__args;
    initial_howto = kargs->howto;
    initial_bootdev = kargs->bootdev;
    initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL;

    /* Initialize the v86 register set to a known-good state. */
    bzero(&v86, sizeof(v86));
    v86.efl = PSL_RESERVED_DEFAULT | PSL_I;

    /* 
     * Initialise the heap as early as possible.  Once this is done, malloc() is usable.
     */
    bios_getmem();

#if defined(LOADER_BZIP2_SUPPORT)
    if (high_heap_size > 0) {
	heap_top = PTOV(high_heap_base + high_heap_size);
	heap_bottom = PTOV(high_heap_base);
	if (high_heap_base < memtop_copyin)
	    memtop_copyin = high_heap_base;
    } else
#endif
    {
	heap_top = (void *)PTOV(bios_basemem);
	heap_bottom = (void *)end;
    }
    setheap(heap_bottom, heap_top);

    /* 
     * XXX Chicken-and-egg problem; we want to have console output early, but some
     * console attributes may depend on reading from eg. the boot device, which we
     * can't do yet.
     *
     * We can use printf() etc. once this is done.
     * If the previous boot stage has requested a serial console, prefer that.
     */
    bi_setboothowto(initial_howto);
    if (initial_howto & RB_MULTIPLE) {
	if (initial_howto & RB_SERIAL)
	    setenv("console", "comconsole vidconsole", 1);
	else
	    setenv("console", "vidconsole comconsole", 1);
    } else if (initial_howto & RB_SERIAL)
	setenv("console", "comconsole", 1);
    else if (initial_howto & RB_MUTE)
	setenv("console", "nullconsole", 1);
    cons_probe();

    /*
     * Initialise the block cache
     */
    bcache_init(32, 512);	/* 16k cache XXX tune this */

    /*
     * Special handling for PXE and CD booting.
     */
    if (kargs->bootinfo == 0) {
	/*
	 * We only want the PXE disk to try to init itself in the below
	 * walk through devsw if we actually booted off of PXE.
	 */
	if (kargs->bootflags & KARGS_FLAGS_PXE)
	    pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL);
	else if (kargs->bootflags & KARGS_FLAGS_CD)
	    bc_add(initial_bootdev);
    }

    archsw.arch_autoload = i386_autoload;
    archsw.arch_getdev = i386_getdev;
    archsw.arch_copyin = i386_copyin;
    archsw.arch_copyout = i386_copyout;
    archsw.arch_readin = i386_readin;
    archsw.arch_isainb = isa_inb;
    archsw.arch_isaoutb = isa_outb;
    archsw.arch_loadaddr = pc98_loadaddr;

    /*
     * March through the device switch probing for things.
     */
    for (i = 0; devsw[i] != NULL; i++)
	if (devsw[i]->dv_init != NULL)
	    (devsw[i]->dv_init)();
    printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024);
    if (initial_bootinfo != NULL) {
	initial_bootinfo->bi_basemem = bios_basemem / 1024;
	initial_bootinfo->bi_extmem = bios_extmem / 1024;
    }

    printf("\n");
    printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
    printf("(%s, %s)\n", bootprog_maker, bootprog_date);

    extract_currdev();				/* set $currdev and $loaddev */
    setenv("LINES", "24", 1);			/* optional */

    interact();			/* doesn't return */

    /* if we ever get here, it is an error */
    return (1);
}
Exemplo n.º 7
0
int main(int argc, char **argv)
{
	pthread_t sigth;
	sigset_t sigblock;
	int logflags = 0;
	int ret = 1;

	debug_init();

	sigemptyset(&sigblock);
	sigaddset(&sigblock, SIGHUP);
	sigaddset(&sigblock, SIGINT);
	sigaddset(&sigblock, SIGTERM);
#ifdef ENABLE_VT
	sigaddset(&sigblock, SIGPIPE);
#endif
	pthread_sigmask(SIG_BLOCK, &sigblock, NULL);

	if (conf_parse(&conf, argc, argv))
		return 1;

	if (conf.debug_level > 0)
		logflags = LOG_PERROR;

	openlog(basename(argv[0]), LOG_PID|logflags, LOG_DAEMON);

	syslog(LOG_INFO, "%s v%s started (%s)", PACKAGE_NAME, PACKAGE_VERSION,
	       entity_string[conf.mip6_entity]);
#ifdef ENABLE_VT
	if (vt_init() < 0)
		goto vt_failed;
#endif

	/* if not debugging, detach from tty */
	if (conf.debug_level == 0)
		daemon_start(1);
	else {
		/* if debugging with debug log file, detach from tty */
		if (conf.debug_log_file) {
			daemon_start(1);

			ret = debug_open(conf.debug_log_file);
			if (ret < 0) {
				fprintf(stderr, "can't init debug log:%s\n",
					strerror(-ret));
				goto debug_failed;
			}
			dbg("%s started in debug mode\n", PACKAGE_NAME);
		} else {
			dbg("%s started in debug mode, not detaching from terminal\n",
			    PACKAGE_NAME);
		}
		conf_show(&conf);
	}

	srandom(time(NULL));

	if (rr_cn_init() < 0)
		goto rr_cn_failed;
	if (policy_init() < 0)
		goto policy_failed;
	if (taskqueue_init() < 0)
		goto taskqueue_failed;
	if (bcache_init() < 0)
		goto bcache_failed;
	if (mh_init() < 0)
		goto mh_failed;
	if (icmp6_init() < 0)
		goto icmp6_failed;
	if (xfrm_init() < 0)
		goto xfrm_failed;
	cn_init();
	if ((is_ha() || is_mn()) && tunnelctl_init() < 0)
		goto tunnelctl_failed;
	if (is_ha() && ha_init() < 0) 
		goto ha_failed;
	if (is_mn() && mn_init() < 0)
		goto mn_failed;
#ifdef ENABLE_VT
	if (vt_start(conf.vt_hostname, conf.vt_service) < 0)
		goto vt_start_failed;
#endif
	if (pthread_create(&sigth, NULL, sigh, NULL))
		goto sigth_failed;
	pthread_join(sigth, NULL);
	ret = 0;
sigth_failed:
#ifdef ENABLE_VT
	vt_fini();
vt_start_failed:
#endif
	if (is_mn())
		mn_cleanup();
mn_failed:
	if (is_ha())
		ha_cleanup();
ha_failed:
	if (is_ha() || is_mn())
		tunnelctl_cleanup();
tunnelctl_failed:
	cn_cleanup();
	xfrm_cleanup();
xfrm_failed:
	icmp6_cleanup();
icmp6_failed:
	mh_cleanup();
mh_failed:
	bcache_cleanup();
bcache_failed:
	taskqueue_destroy();
taskqueue_failed:
	policy_cleanup();
policy_failed:
rr_cn_failed:
	debug_close();
debug_failed:
#ifdef ENABLE_VT
vt_failed:
#endif
	syslog(LOG_INFO, "%s v%s stopped (%s)", PACKAGE_NAME, PACKAGE_VERSION,
	       entity_string[conf.mip6_entity]);
	closelog();
	return ret;
}