/* lilo.c  -  LILO command-line parameter processing
 * 
 * Copyright 1992-1998 Werner Almesberger
 * Copyright 1999-2007 John Coffman
 * Copyright 2009-2015 Joachim Wiedorn
 * All rights reserved.
 * 
 * Licensed under the terms contained in the file 'COPYING'
 * in the source directory.
 */

#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <limits.h>
#include <dirent.h>
/*#include <asm/page.h>*/

#include "config.h"
#include "lilo.h"
#include "common.h"
#include "cfg.h"

#if !__MSDOS__
#include "raid.h"
#include "boot.h"
#include "device.h"
#include "flags.i"
#include "geometry.h"
#endif /* !__MSDOS__ */
#include "map.h"
#if !__MSDOS__
#include "bsect.h"
#include "identify.h"
#include "partition.h"
#include "probe.h"
#include "temp.h"
#include "loader.h"
#include "md-int.h"
#include "edit.h"
#endif /* !__MSDOS__ */


char *config_file;		/* actual name of the config file */
int config_read;		/* readable by other than root */
FILE *errstd;

static void configuration(void)
{
#if VERSION_MINOR>=50 && !__MSDOS__
{
		printf(
		"-DBOOT_PARAMS_1=%d -DBOOT_PARAMS_2=%d  PATH_MAX=%d"
		  "\n"
		  ,
		  (int)sizeof(BOOT_PARAMS_1),
		  (int)sizeof(BOOT_PARAMS_2),
		  PATH_MAX
		     );
}
{
#include "bitmap.h"
	RGB pal[16];
	RGB2 pal2[16];
	
	printf("\nBMFH=%d BMH=%d BMH2=%d RGB=%d(%d) RGB2=%d(%d) LH=%d\n",
	(int)sizeof(BITMAPFILEHEADER),
	(int)sizeof(BITMAPHEADER),
	(int)sizeof(BITMAPHEADER2),
	(int)sizeof(RGB),
	(int)sizeof(pal),
	(int)sizeof(RGB2),
	(int)sizeof(pal2),
	(int)sizeof(BITMAPLILOHEADER) );
	printf("\nBPB=%d BP_DOS=%d\n",
		(int)sizeof(BIOS_PARAMETER_BLOCK),
		(int)sizeof(BOOT_PARAMS_DOS)
		  );
}
#ifdef LCF_FIRST6
	printf("\nSECTOR_ADDR6=%d\n", (int)sizeof(SECTOR_ADDR6));
#endif

#endif /* VERSION_MINOR>=50 && !__MSDOS__ */

#if !__MSDOS__
{
  unsigned int j;
  if (verbose>=5) {
    if (crc(First.data,First.size)) {
	j = crc(First.data,First.size-4);
	brev(j);
	printf("1=0x%x\n", j);
    }
    if (crc(Second.data,Second.size)) {
	j = crc(Second.data,Second.size-4);
	brev(j);
	printf("2=0x%x\n", j);
    }
    if (crc(Third.data,Third.size)) {
	j = crc(Third.data,Third.size-4);
	brev(j);
	printf("3=0x%x\n", j);
    }
    if (crc(Bitmap.data,Bitmap.size)) {
	j = crc(Bitmap.data,Bitmap.size-4);
	brev(j);
	printf("B=0x%x\n", j);
    }
    if (crc(Chain.data,Chain.size)) {
	j = crc(Chain.data,Chain.size-4);
	brev(j);
	printf("C=0x%x\n", j);
    }
    if (crc(Mbr.data,Mbr.size)) {
	j = crc(Mbr.data,Mbr.size-4);
	brev(j);
	printf("M=0x%x\n", j);
    }
    if (crc(Mbr2.data,Mbr2.size)) {
	j = crc(Mbr2.data,Mbr2.size-4);
	brev(j);
	printf("N=0x%x\n\n", j);
    }
  }
}

#if BETA_TEST
{
    int i, j, k=0;
extern int has_partitions_beta(dev_t dev);	/* defined in geometry.c */


    printf("\n");
    for (i=0; i<256; i++) {
	if ( has_partitions_beta(MKDEV(i,0)) != has_partitions(MKDEV(i,0)) ) {
	    printf("Major device = %d is not configured.\n", i);
	    k ++;
	}
    }
    printf("%sk = %d (should be 0)\n\n", k?"ERROR: ":"", k);
    for (i=0, j=0; i<40960; i+=17) {
        dev_t dev;
        int major, minor;
        for (k=0; k<81920; k+=19) {
            dev = MKDEV(i,k);
            major = MAJOR(dev);
            minor = MINOR(dev);
            if (major != i  ||  minor != k) {
                printf("ERROR: (%d,%d) -> (%d,%d)\n",
                    i, k, major, minor);
                j++;
            }
        }
    }
    if (j==0) printf("MKDEV check passed\n");
}
#endif

#if VERSION_MINOR>=50
{
	dev_t dev; int i;
	BOOT_VOLID x;
	BOOT_SECTOR b;
	dev = 0xFFF0;
	i = dev;
	printf("dev_t is %ssigned size=%d  i=%08X\n", i==0xFFF0 ? "un" : "", (int)sizeof(dev_t), i);
	printf("size of BOOT_VOLID = %d   BOOT_SECTOR = %d\n", (int)sizeof(x), (int)sizeof(b));
	printf("Size of MENUTABLE = %d\n", (int)sizeof(MENUTABLE));
}
#endif
		printf("\nCFLAGS = " CFLAGS "\n");
#if defined(LCF_DEVMAPPER) && defined(HAS_LIBDEVMAPPER_H)
                printf("With");
#else
                printf("Without");
#endif
                printf(" device-mapper\n");
		printf("\nglibc version %d.%d\n", __GLIBC__, __GLIBC_MINOR__);
		printf("Kernel Headers included from  %d.%d.%d\n",
			LINUX_VERSION_CODE>>16,
			LINUX_VERSION_CODE>>8 & 255,
			LINUX_VERSION_CODE & 255);
		printf("Maximum Major Device = %d\n", MAJOR(~0UL));
#endif /* !__MSDOS__ */
		printf("MAX_IMAGES = %d\t\tc=%d, s=%d, i=%d, "
				"l=%d, ll=%d, f=%d, d=%d, ld=%d\n",
			MAX_IMAGES, (int)sizeof(char),
			(int)sizeof(short), (int)sizeof(int),
			(int)sizeof(int32_t), (int)sizeof(
#if !__MSDOS__
			int64_t),
#else
			int32_t),
#endif /* !__MSDOS__ */
			(int)sizeof(float), (int)sizeof(double),
			(int)sizeof(long double)
			);
		printf("IMAGE_DESCR = %d   DESCR_SECTORS = %d\n\n",
			(int)sizeof(IMAGE_DESCR), (int)sizeof(DESCR_SECTORS));
}

#if !__MSDOS__

static void show_other(int fd)
{
    BOOT_SECTOR buf[SETUPSECS-1];
    const unsigned char *drvmap;
    const unsigned char *prtmap;

    if (read(fd,buf,sizeof(buf)) != sizeof(buf))
	die("Read on map file failed (access conflict ?) 1");
    if (!strncmp(buf[0].par_c.signature-4,"LILO",4)) {
	printf("    Pre-21 signature (0x%02x,0x%02x,0x%02x,0x%02x)\n",
	  buf[0].par_c.signature[0],buf[0].par_c.signature[1],
	  buf[0].par_c.signature[2],buf[0].par_c.signature[3]);
	return;
    }
    if (strncmp(buf[0].par_c.signature,"LILO",4)) {
	printf("    Bad signature (0x%02x,0x%02x,0x%02x,0x%02x)\n",
	  buf[0].par_c.signature[0],buf[0].par_c.signature[1],
	  buf[0].par_c.signature[2],buf[0].par_c.signature[3]);
	return;
    }
    drvmap = ((unsigned char *) buf+buf[0].par_c.drvmap);
    prtmap = drvmap+2*(DRVMAP_SIZE+1);
    while (drvmap[0] && drvmap[1]) {
	if (drvmap[0]==0xFF && drvmap[1]==0xFF) {
	    if (drvmap[3]==0xFF) printf("    Master-Boot:  This BIOS drive will always appear as 0x80 (or 0x00)\n");
	    else printf("    Boot-As:  This BIOS drive will always appear as 0x%02X\n", drvmap[3]);
	    drvmap += 4;
	} else {
	    printf("    BIOS drive 0x%02X is mapped to 0x%02X\n",drvmap[0],
						drvmap[1]);
	    drvmap += 2;
	}
    }
    /* fix VERY old bug -- offset of 0 in PT is okay */
    while (prtmap[0] /*** && prtmap[1] ***/ ) {
	printf("    BIOS drive 0x%02x, offset 0x%x: 0x%02x -> 0x%02x\n",
	  prtmap[0],prtmap[1]+PART_TABLE_OFFSET,prtmap[2],prtmap[3]);
	prtmap += 4;
    }
}
#endif /* !__MSDOS__ */

static void show_images(char *map_file)
{
#if !__MSDOS__
    DESCR_SECTORS descrs;
    BOOT_SECTOR boot;
    MENUTABLE menu;
    BOOT_PARAMS_2 param2;
    GEOMETRY geo;
    SECTOR_ADDR addr[4];
    char buffer[SECTOR_SIZE];
#else /* __MSDOS */
static DESCR_SECTORS descrs;
static char buffer[SECTOR_SIZE];
#endif /*__MSDOS__ */
    char *name;
    int fd,image;
    int tsecs;
    int tlinear, tlba32;
    unsigned short flags;
    time_t Time;

#if !__MSDOS__
    fd = geo_open(&geo,map_file,O_RDONLY);
#else  /* __MSDOS__ */
    if ((fd = open(map_file,O_RDONLY))<=0)
	die("Cannot open map file: %s", map_file);
#endif /* __MSDOS__ */
    if (read(fd,buffer,SECTOR_SIZE) != SECTOR_SIZE)
	die("read cmdline %s: %s",map_file,strerror(errno));
    if (read(fd,(char*)&descrs,sizeof(descrs)) != sizeof(descrs))
	die("read descrs %s: %s",map_file,strerror(errno));
#if !__MSDOS__
    if (lseek(fd, SECTOR_SIZE, SEEK_CUR) <= 0)	/* skip zero sector */
	die("lseek over zero sector %s: %s",map_file,strerror(errno));
    if (read(fd,(char*)&param2,sizeof(param2)) != sizeof(param2))
	die("read second params %s: %s",map_file,strerror(errno));
    if (lseek(fd, - sizeof(menu), SEEK_END) <= 0)
	die("lseek keytable %s: %s",map_file,strerror(errno));
    if (read(fd,(char*)&menu,sizeof(menu)) != sizeof(menu))
	die("read keytable %s: %s",map_file,strerror(errno));
    tlba32  = (descrs.d.descr[0].start.device & LBA32_FLAG) != 0;
    tlinear = !tlba32 && (descrs.d.descr[0].start.device & LINEAR_FLAG);
    if (tlinear != linear  ||  tlba32 != lba32) {
        printf("Warning: mapfile created with %s option\n",
	       tlinear?"linear":tlba32?"lba32":"no linear/lba32");
        linear = tlinear;  lba32 = tlba32;
    }
    if (verbose) {
	bsect_read(cfg_get_strg(cf_options,"boot"),&boot);
#if 1
	if (boot.par_1.cli != 0xFA) {	/* relocation happened */
	    int len, offset=0;
	    if (boot.sector[0] == 0xEB)		/* jmp short */
		offset = boot.sector[1]+2;
	    else if (boot.sector[0] == 0xE9)	/* jmp near */
		offset = *(short*)&boot.sector[1] + 3;
	    else die("Cannot undo boot sector relocation.");
	    len = SECTOR_SIZE - offset;
	    memmove(&boot, &boot.sector[offset], len);
	    if (boot.par_1.cli != 0xFA)
		die("Cannot recognize boot sector.");
	}
#endif
#if 1
        Time = boot.par_1.map_stamp;
	printf("Installed:  %s\n", ctime(&Time));
#else
	printf("Installed:  %s\n", ctime((time_t*)&boot.par_1.map_stamp));
#endif
	printf("Global settings:\n");
	tsecs = (param2.delay*2197+3999)/4000;
	printf("  Delay before booting: %d.%d seconds\n",tsecs/10,tsecs % 10);
	if (param2.timeout == 0xffff) printf("  No command-line timeout\n");
	else {
	    tsecs = (param2.timeout*2197+3999)/4000;
	    printf("  Command-line timeout: %d.%d seconds\n",tsecs/10,
	      tsecs % 10);
	}
	printf("  %snattended booting\n", param2.flag2&FLAG2_UNATTENDED ? "U" : "No u");
	printf("  %sPC/AT keyboard hardware prescence check\n", param2.flag2&FLAG2_NOKBD ? "" : "No ");
	if (boot.par_1.prompt & FLAG_PROMPT) printf("  Always enter boot prompt\n");
	else printf("  Enter boot prompt only on demand\n");
	printf("  Boot-time BIOS data%s saved\n",
		boot.par_1.prompt & FLAG_NOBD ? " NOT" : "");
	printf("  Boot-time BIOS data auto-suppress write%s bypassed\n",
		boot.par_1.prompt & FLAG_BD_OKAY ? "" : " NOT");
	printf("  Large memory (>15M) is%s used to load initial ramdisk\n", 
		boot.par_1.prompt & FLAG_LARGEMEM ? "" : " NOT");
	printf("  %sRAID installation\n",
		boot.par_1.prompt & FLAG_RAID ? "" : "Non-");
	printf("  Boot device %s be used for the Map file\n",
		boot.par_1.prompt & FLAG_MAP_ON_BOOT ? "WILL" : "will not");
	if (!param2.port) printf("  Serial line access is disabled\n");
	else printf("  Boot prompt can be accessed from COM%d\n",
	      param2.port);
	if (!param2.msg_len) printf("  No message for boot prompt\n");
	else if (!cfg_get_strg(cf_options,"bitmap"))
	    printf("  Boot prompt message is %d bytes\n",param2.msg_len);
	else printf("  Bitmap file is %d paragraphs (%d bytes)\n",
			param2.msg_len, 16*param2.msg_len);
/* 22.6.2 begin */
	if (*(unsigned short *) buffer != DC_MAGIC /* || !buffer[2] */)
/* 22.6.2 end */
	    printf("  No default boot command line\n");
	else printf("  Default boot command line: \"%s\"\n",buffer+2);
	if (verbose>=3) {
	    printf("Serial numbers %08X\n", menu.serial_no[0]);
	}
	printf("Images:\n");
    }
/* 22.7 begin */
    else	/* verbose==0 */
#endif /* !__MSDOS__ */
    {
	if (*(unsigned short *) buffer == DC_MAGIC)
	    printf("Default boot command line: \"%s\"\n",buffer+2);
    }
/* 22.7 end */
    for (image = 0; image < MAX_IMAGES; image++) {
	if (*(name = descrs.d.descr[image].name)) {
#if __MSDOS__
	    printf("%s\n", name
#else /* !__MSDOS__ */
	    printf("%s%-" SA(MAX_IMAGE_NAME) "s %s%s%s",verbose > 0 ? "  " : "",name,
	      image ? "" : "*",
#ifdef LCF_VIRTUAL
	      descrs.d.descr[image].flags & FLAG_VMDEFAULT ? "@" :
#endif
	      "",
#ifdef LCF_NOKEYBOARD
	      descrs.d.descr[image].flags & FLAG_NOKBDEFAULT ? "&" :
#endif
	      ""
#endif /* !__MSDOS__ */
	      );
#if !__MSDOS__
	    if (verbose >= 2) {
	        if (descrs.d.descr[image].start.device & (LINEAR_FLAG|LBA32_FLAG)) {
		   unsigned int sector;
		   sector = (descrs.d.descr[image].start.device & LBA32_FLAG)
		      && (descrs.d.descr[image].start.device & LBA32_NOCOUNT)
		        ? descrs.d.descr[image].start.num_sect : 0;
		   sector = (sector<<8)+descrs.d.descr[image].start.head;
	           sector = (sector<<8)+descrs.d.descr[image].start.track;
		   sector = (sector<<8)+descrs.d.descr[image].start.sector;
		   printf(" <dev=0x%02x,%s=%d>",
		     descrs.d.descr[image].start.device&DEV_MASK,
		     descrs.d.descr[image].start.device&LBA32_FLAG ? "lba32" : "linear",
		     sector);
		}
	        else { /*  CHS addressing */
		    printf(" <dev=0x%02x,hd=%d,cyl=%d,sct=%d>",
		      descrs.d.descr[image].start.device,
		      descrs.d.descr[image].start.head,
		      descrs.d.descr[image].start.track,
		      descrs.d.descr[image].start.sector);
		}
	    }
	    printf("\n");
	    if (verbose >= 1) {
		flags = descrs.d.descr[image].flags;
#ifdef LCF_VIRTUAL
		if (flags & FLAG_VMDISABLE)
		    printf("    Virtual Boot is disabled\n");
		if (flags & FLAG_VMWARN)
		    printf("    Warn on Virtual boot\n");
#endif		
#ifdef LCF_NOKEYBOARD
		if (flags & FLAG_NOKBDISABLE)
		    printf("    NoKeyboard Boot is disabled\n");
#endif		
		if ( !(flags & FLAG_PASSWORD) )
		    printf("    No password\n");
		else printf("    Password is required for %s\n",flags &
		      FLAG_RESTR ? "specifying options" : "booting this image");
		printf("    Boot command-line %s be locked\n",flags &
		  FLAG_LOCK ? "WILL" : "won't");
		printf("    %single-key activation\n",flags & FLAG_SINGLE ?
		  "S" : "No s");
		if (flags & FLAG_KERNEL) {
#ifdef NORMAL_VGA
		    if (!(flags & FLAG_VGA))
		       printf("    VGA mode is taken from boot image\n");
		    else {
			printf("    VGA mode: ");
			switch (descrs.d.descr[image].vga_mode) {
			    case NORMAL_VGA:
				printf("NORMAL\n");
				break;
			    case EXTENDED_VGA:
				printf("EXTENDED\n");
				break;
			    case ASK_VGA:
				printf("ASK\n");
				break;
			    default:
				printf("%d (0x%04x)\n",
				  descrs.d.descr[image].vga_mode,
				  descrs.d.descr[image].vga_mode);
			}
		    }
#endif
		    if (!(flags & FLAG_LOADHI))
			printf("    Kernel is loaded \"low\"\n");
		    else printf("    Kernel is loaded \"high\"\n");
		    if (!*(unsigned int *) descrs.d.descr[image].rd_size)
			printf("    No initial RAM disk\n");
		    else printf("    Initial RAM disk is %d bytes\n",
			  *(unsigned int *) descrs.d.descr[image].rd_size);
		    if (flags & FLAG_TOOBIG)
			printf("       and is too big to fit between 4M-15M\n");
		}
		if (!geo_find(&geo,descrs.d.descr[image].start)) {
		    printf("    Map sector not found\n");
		    continue;
		}
		if (read(fd,addr,4*sizeof(SECTOR_ADDR)) !=
		  4*sizeof(SECTOR_ADDR))
			die("Read on map file failed (access conflict ?) 2");
		if (!geo_find(&geo,addr[0]))
		    printf("    Fallback sector not found\n");
		else {
		    if (read(fd,buffer,SECTOR_SIZE) != SECTOR_SIZE)
			die("Read on map file failed (access conflict ?) 3");
		    if (*(unsigned short *) buffer != DC_MAGIC)
			printf("    No fallback\n");
		    else printf("    Fallback: \"%s\"\n",buffer+2);
		}
#define OTHER 0
#if OTHER
		if (flags & FLAG_KERNEL)
#endif
		    if (!geo_find(&geo,addr[1]))
			printf("    Options sector not found\n");
		    else {
			if (read(fd,buffer,SECTOR_SIZE) != SECTOR_SIZE)
			    die("Read on map file failed (access conflict ?) 4");
			if (*buffer) printf("    Options: \"%s\"\n",buffer);
			else printf("    No options\n");
		    }
#if OTHER
		else {
#else
		if (!(flags & FLAG_KERNEL)) {
#endif
		    if (geo_find(&geo,addr[3])) show_other(fd);
		    else printf("    Image data not found\n");
		}
	    }
#endif /*  !__MSDOS__ */
	} /* if */
    } /* for */
#undef OTHER
    (void) close(fd);
#if !__MSDOS__
    if (descrs.l.checksum ==
    	  crc32(descrs.sector, sizeof(descrs.l.sector), CRC_POLY1) )
#endif /* !__MSDOS__ */
    	  	exit(0);
#if !__MSDOS__
    fflush(stdout);
    fprintf(errstd,"Checksum error\n");
    exit(1);
#endif /* !__MSDOS__ */
}


static void usage(char *name)
{
    char *here;

#if !__MSDOS__
    here = strrchr(name,'/');
#else /* __MSDOS__ */
    here = strrchr(name,'\\');
#endif /* __MSDOS__ */
    if (here) name = here+1;
    fprintf(errstd,"usage: %s [ -C config_file ] -q [ -m map_file ] "
      "[ -v N | -v ... ]\n",name);
#if !__MSDOS__
    fprintf(errstd,"%7s%s [ -C config_file ] [ -b boot_device ] [ -c ] "
      "[ -g | -l | -L ]\n","",name);
    fprintf(errstd,"%12s[ -F ] [ -i boot_loader ] [ -m map_file ] [ -d delay ]\n","");
    fprintf(errstd,"%12s[ -v N | -v ... ] [ -t ] [ -s save_file | -S save_file ]\n",
      "");
    fprintf(errstd,"%12s[ -p ][ -P fix | -P ignore ] [ -r root_dir ] [ -w | -w+ ]\n","");
#endif /* !__MSDOS__ */
    fprintf(errstd,"%7s%s [ -C config_file ] [ -m map_file ] "
      "-R [ word ... ]\n","",name);
#if !__MSDOS__
    fprintf(errstd,"%7s%s [ -C config_file ] -I name [ options ]\n","",name);
    fprintf(errstd,"%7s%s [ -C config_file ] [ -s save_file ] "
      "-u | -U [ boot_device ]\n","",name);
    fprintf(errstd,"%7s%s -H\t\t\t\tinstall only to active discs (RAID-1)\n", "", name);
    fprintf(errstd,"%7s%s -A /dev/XXX [ N ]\t\tinquire/activate a partition\n","",name);
    fprintf(errstd,"%7s%s -M /dev/XXX [ mbr | ext ]\tinstall master boot record\n","",name);
    fprintf(errstd,"%7s%s -T help \t\t\tlist additional options\n", "", name);
    fprintf(errstd,"%7s%s -X\t\t\t\tinternal compile-time options\n", "", name);
#endif /* !__MSDOS__ */
    fprintf(errstd,"%7s%s -V [ -v ]\t\t\tversion information\n\n","",name);
    exit(1);
}


int main(int argc,char **argv)
{
    char *name,*reboot_arg,*ident_opt,*new_root;
    char *tell_param, *uninst_dev, *param, *act1, *act2, ch;
static char *bitmap_file;
    int more,version,uninstall,validate,activate,instmbr,geom;
    int fd, temp=0, tell_early=0;
    int raid_offset;
#if !__MSDOS__
    struct stat st;
#endif /* !__MSDOS__ */

    errstd = stderr;
#if VERSION_MINOR>=50
    if (sizeof(MENUTABLE)!=256) die("MENUTABLE is not 256 bytes (common.h)");
#if !__MSDOS__
    cfg_alpha_check();
#endif /* !__MSDOS__ */
#endif
    config_file = DFL_CONFIG;
    act1 = act2 = tell_param = 
	    reboot_arg = identify = ident_opt = new_root = uninst_dev = NULL;
    do_md_install = zflag =
	    version = uninstall = validate = activate = instmbr = 0;
    verbose = -1;
#if !__MSDOS__
    name = *argv;
#else  /* __MSDOS__ */
    name = "lilo";
#endif /* __MSDOS__ */
    argc--;

#if !__MSDOS__    
    if (atexit( (void(*)(void)) sync)) die("atexit(sync)");
    if (atexit( (void(*)(void)) purge)) die("atexit(purge)");
#endif /* !__MSDOS__ */
    
    cfg_init(cf_options);
    while (argc && **++argv == '-') {
	argc--;
      /* first those options with a mandatory parameter */
      /* Notably absent are "RuUvw" */
	if (strchr("AbBCdDEfiImMPrsSTxZ", ch=(*argv)[1])) {
	    if ((*argv)[2]) param = (*argv)+2;
	    else {
		param = *++argv;
		if(argc-- <= 0) usage(name);
	    }
	} else { 
	    param = NULL;
	    if (strchr("cFglLpqtVXz", ch)	/* those with no args */
	    	&& (*argv)[2]) usage(name);
	}
#if 0
fprintf(errstd,"argc=%d, *argv=%s, ch=%c param=%s\n", argc, *argv, ch, param);
#endif
	switch (ch) {
#if !__MSDOS__
	    case 'A':
		activate = 1;
		act1 = param;
		if (argc && argv[1][0] != '-') {
		    act2 = *++argv;
		    argc--;
		}
		break;
	    case 'b':
		cfg_set(cf_options,"boot",param,NULL);
		break;
	    case 'B':
		cfg_set(cf_options,"bitmap",param,NULL);
		break;
	    case 'c':
		cfg_set(cf_options,"compact",NULL,NULL);
		compact = 1;
		break;
#endif /* !__MSDOS */
	    case 'C':
		config_file = param;
		break;
#if !__MSDOS__
	    case 'd':
		cfg_set(cf_options,"delay",param,NULL);
		break;
	    case 'D':
		cfg_set(cf_options,"default",param,NULL);
		break;
	    case 'E':
	        eflag=1;
	        bitmap_file = param;
	        break;
	    case 'f':
		cfg_set(cf_options,"disktab",param,NULL);
		break;
	    case 'F':
		force_fs=1;
		break;
	    case 'g':
		geometric |= AD_GEOMETRIC;
		break;
	    case 'H':
		force_raid=1;
		break;
	    case 'i':
		cfg_set(cf_options,"install",param,NULL);
		break;
	    case 'I':
		identify = param;
		if (argc && *argv[1] != '-') {
		    ident_opt = *++argv;
		    argc--;
		} else {
		    ident_opt = "i";
		}
		break;
	    case 'l':
		geometric |= AD_LINEAR;
		break;
	    case 'L':
		geometric |= AD_LBA32;
		break;
#endif /* !__MSDOS__ */
	    case 'm':
		cfg_set(cf_options,"map",param,NULL);
		break;
#if !__MSDOS__
	    case 'M':
		instmbr = 1;
		act1 = param;
#if !defined LCF_BUILTIN	|| 1
		if (argc && argv[1][0] != '-') {
		    act2 = *++argv;
		    argc--;
		}
#endif
		break;
	    case 'p':
		passw = 1;	/* force re-gen of password file */
		break;
	    case 'P':
		if ((act1=strchr(param,'='))) {
		    *act1++ = 0;	/* null terminate */
		    cfg_set(cf_options,param,act1,NULL);
		}
		else if (!strcasecmp(param,"fix"))
		    cfg_set(cf_options,"fix-table",NULL,NULL);
		else if (!strcasecmp(param,"ignore"))
		    cfg_set(cf_options,"ignore-table",NULL,NULL);
		else if (!strcasecmp(param,"x"))
		    extended_pt = 1;
		else
		    cfg_set(cf_options,param,NULL,NULL);
		break;
#endif /* !__MSDOS__ */
	    case 'q':
		query = 1;
		break;
#if !__MSDOS__
	    case 'r':
		new_root = param;
		break;
#endif /* !__MSDOS__ */
	    case 'R':
	        if (*(param = (*argv)+2)) argc++;
	        else if (argc) param = *++argv;
	        else reboot_arg = "";

		while (argc) {
			if (!reboot_arg)
			    *(reboot_arg = alloc(strlen(param)+1)) = 0;
			else {
			    param = *++argv;
			    strcat(reboot_arg = ralloc(reboot_arg,
			        strlen(reboot_arg)+strlen(param)+2)," ");
			}
			strcat(reboot_arg, param);
			argc--;
		    }
		break;
#if !__MSDOS__
	    case 's':
		cfg_set(cf_options,"backup",param,NULL);
		break;
	    case 'S':
		cfg_set(cf_options,"force-backup",param,NULL);
		break;
	    case 't':
		test = 1;
		break;
	    case 'T':
	        tell_param = param;
	    	break;
	    case 'u':
		validate = 1;
		/* fall through */
	    case 'U':	/* argument to -u or -U is optional */
		uninstall = 1;
		if ((*argv)[2]) param = (*argv)+2;
		else if (argc && argv[1][0] != '-') {
		    param = *++argv;
		    argc--;
		}
		uninst_dev = param;
		break;
#endif /* !__MSDOS__ */
	    case 'v':
	        if ((*argv)[2]) param = (*argv)+2;
	        else if (argc && argv[1][0]>='0' && argv[1][0]<='9') {
	            param = *++argv;
	            argc--;
	        }
	        if (param)
		    verbose = to_number(param);
		else
	            if (verbose<0) verbose = 1;
	            else verbose++;
	        if (verbose) errstd = stdout;
		break;
	    case 'V':
		version = 1;
		break;
#if !__MSDOS__
	    case 'w':
		cfg_set(cf_options,"nowarn",NULL,NULL);
		nowarn = 1;
		if ( (*argv)[2] == '+' ) nowarn = -1;
		break;
	    case 'x':
		cfg_set(cf_options,RAID_EXTRA_BOOT,param,NULL);
		break;
#endif /* !__MSDOS__ */
	    case 'X':
	        configuration();
		exit(0);
#if !__MSDOS__
	    case 'z':
		zflag++;	/* force zero of MBR 8-byte area */
		break;
	    case 'Z':
		cfg_set(cf_options,"bios-passes-dl",param,NULL);
		break;
#endif /* !__MSDOS__ */
	    default:
		usage(name);
	}
    }
    if (argc) usage(name);
#if !__MSDOS__
    if (!new_root) new_root = getenv("ROOT");
    if (new_root && *new_root) {
	pp_fd = fopen(PARTITIONS, "r");
	if (chroot(new_root) < 0) die("chroot %s: %s",new_root,strerror(errno));
	if (chdir("/dev") < 0)
	        warn("root at %s has no /dev directory", new_root);
	if (chdir("/") < 0) die("chdir /: %s",strerror(errno));
    }
    if (atexit(temp_remove)) die("atexit() failed");
    if (version+activate+instmbr+(tell_param!=NULL) > 1) usage(name);
    if (activate) do_activate(act1, act2);
#endif /* !__MSDOS__ */

    if (verbose > 0 || version) {
        printf("LILO version %d.%d%s", VERSION_MAJOR, VERSION_MINOR, VERSION_EDIT);
        if (test)
          printf(" (test mode)\n");
        else
          printf(" (released %s)\n", VERSION_DATE);
        if (version && verbose<=0) {
          /* exit if user asks for version and no verbose */
          return 0;
        }
        printf("  * Copyright (C) 1992-1998 Werner Almesberger  (until v20)\n"
               "  * Copyright (C) 1999-2007 John Coffman  (until v22)\n"
               "  * Copyright (C) 2009-2015 Joachim Wiedorn  (since v23)\n"
               "This program comes with ABSOLUTELY NO WARRANTY. This is free software \n"
               "distributed under the BSD License (3-clause). Details can be found in \n"
               "the file COPYING, which is distributed with this software.\n"
        );
        if (verbose>0) {
#if !__MSDOS__
  #include <sys/utsname.h>
          struct utsname buf;
          if (verbose>=2 && uname(&buf)==0) {
            printf("Running %s kernel %s on %s\n",
              buf.sysname, buf.release, buf.machine);
          }
#endif
        }
        printf("\n");
        if (version) {
            if (verbose>=2) configuration();
            return 0;
        }
    }

    if (verbose > 0) errstd = stdout;
#if !__MSDOS__
    preload_types();
    if (geometric & (geometric-1))
	die ("Only one of '-g', '-l', or '-L' may be specified");

    if (tell_param) tell_early = strcasecmp(tell_param, "chrul")
    				&& strcasecmp(tell_param, "ebda");
    if (eflag) do_bitmap_edit(bitmap_file);
    if (tell_param && tell_early) probe_tell(tell_param);
    if (instmbr) do_install_mbr(act1, act2);
#endif /* !__MSDOS__ */    

    fd = cfg_open(config_file);
    more = fd<0 ? 0 : cfg_parse(cf_options);
    
#if !__MSDOS__
    temp = cfg_get_flag(cf_options,"nowarn");
    if (nowarn < 0) nowarn = 0;
    else nowarn = temp;
/* All warnings appear if very verbose modes used */
    if (verbose>=3) nowarn = 0;
#endif /* !__MSDOS__ */

    if (verbose>=6) printf("main: cfg_parse returns %d\n", more);

#if !__MSDOS__
    if (tell_param && !tell_early) probe_tell(tell_param);

    if (fstat(fd,&st) < 0)
	    die("fstat %s: %s", config_file, strerror(errno) );

    if (S_ISREG(st.st_mode)) {
        if (st.st_uid)
            warn("%s should be owned by root", config_file);
        else if (st.st_mode & (S_IWGRP | S_IWOTH))
	    warn("%s should be writable only for root", config_file);
        config_read = !!(st.st_mode & (S_IRGRP | S_IROTH));
    }

    if (!cfg_get_flag(cf_options,"nodevcache"))  preload_dev_cache();
    
    if (verbose<0 && cfg_get_strg(cf_options,"verbose"))
	verbose = to_number(cfg_get_strg(cf_options,"verbose"));
    if (verbose<0) verbose = 0;
    if (verbose) errstd = stdout;

    compact = cfg_get_flag(cf_options,"compact");
    geom = cfg_get_flag(cf_options,"geometric");
    linear = cfg_get_flag(cf_options,"linear");
    lba32  = cfg_get_flag(cf_options,"lba32");
    
    if (geom+linear+lba32 > 1)
	die("May specify only one of GEOMETRIC, LINEAR or LBA32");
    if (geometric) {
	if (geom+linear+lba32 > 0)  
	    warn("Ignoring entry '%s'", geom ? "geometric" :
	    	      linear ? "linear" : "lba32");
	geom = linear = lba32 = 0;
	if (geometric==AD_LBA32) lba32 = 1;
	else if (geometric==AD_LINEAR) linear = 1;
	else if (geometric==AD_GEOMETRIC) geom = 1;
    }    
    if (geom+linear+lba32 == 0) {
	warn("LBA32 addressing assumed");
	lba32 = 1;
    }
    if (linear) warn(
    	"LINEAR is deprecated in favor of LBA32:  LINEAR specifies 24-bit\n"
	"  disk addresses below the 1024 cylinder limit; LBA32 specifies 32-bit disk\n"
	"  addresses not subject to cylinder limits on systems with EDD-BIOS extensions;\n"
	"  use LINEAR only if you are aware of its limitations.");
    
    if (identify) identify_image(identify,ident_opt);

    if (uninstall)
	bsect_uninstall(uninst_dev ? uninst_dev : cfg_get_strg(cf_options,
	      "boot"),cfg_get_strg(cf_options,"backup"),validate);
#endif /* !__MSDOS__ */

    if (reboot_arg) {
	map_patch_first(cfg_get_strg(cf_options,"map") ? cfg_get_strg(
	      cf_options,"map") : MAP_FILE, reboot_arg);
	exit(0);
    }

#if !__MSDOS__
    if ( (param = cfg_get_strg(cf_options,"bios-passes-dl")) ) {
	if (strchr("YyTt1", *param)) bios_passes_dl = DL_GOOD;
	if (strchr("NnFf0", *param)) bios_passes_dl = DL_BAD;
    }
    if (bios_passes_dl == DL_NOT_SET) 	check_bios();	/* in probe.c */

    if (compact && (linear || lba32) && verbose>=4)
	warn("COMPACT may conflict with %s on some "
		"systems", lba32 ? "LBA32" : "LINEAR");

    geo_init(cfg_get_strg(cf_options,"disktab"));
#endif /* !__MSDOS__ */
    if (query)
	show_images(!cfg_get_strg(cf_options,"map") ? MAP_FILE :
	      cfg_get_strg(cf_options,"map"));

#if !__MSDOS__
/*************************************************/
/*  Doing a real install (may be test mode)      */
/*************************************************/

/* test for a RAID installation */
	raid_offset = raid_setup();
	if (verbose >= 2) {
	    printf("raid_setup returns offset = %08X  ndisk = %d\n", raid_offset, ndisk);
	    dump_serial_nos();    
	}

	if (verbose >=2 && do_md_install)
	    printf("raid flags: at bsect_open  0x%02X\n", raid_flags);

	bsect_open(
		cfg_get_strg(cf_options,"boot"),
		cfg_get_strg(cf_options,"map") ?
			cfg_get_strg(cf_options,"map") : MAP_FILE,
		cfg_get_strg(cf_options,"install"),
		cfg_get_strg(cf_options,"delay") ?
			timer_number(cfg_get_strg(cf_options,"delay")) : 0,
		cfg_get_strg(cf_options,"timeout") ?
			timer_number(cfg_get_strg(cf_options,"timeout")) : -1,
		raid_offset );
	if (more) {
	    cfg_init(cf_top);
	    if (cfg_parse(cf_top)) cfg_error("Syntax error");
	}
	
	temp = bsect_number();
	if (temp==0) die("No images have been defined.");
	else if (temp<0) die("Default image doesn't exist.");

#ifdef LCF_VIRTUAL
	check_vmdefault();
#endif
#ifdef LCF_NOKEYBOARD
	check_nokbdefault();
#endif
	check_fallback();
	check_unattended();
	
	if (verbose>=2) dump_serial_nos();
	if (do_md_install) raid_final();
	else if (!test) {
	    char *cp;
	    
	    if (verbose) printf("Writing boot sector.\n");

	    cp = cfg_get_strg(cf_options,"force-backup");
	    if (cp) bsect_update(cp,1,0);
	    else bsect_update(cfg_get_strg(cf_options,"backup"),0,0);

	} 
	else {
	    bsect_cancel();
	    if (passw)
	        printf("The password crc file has *NOT* been updated.\n");

	    printf("The boot sector and the map file have *NOT* been "
	      "altered.\n");
	}
	if (verbose>=4) dump_serial_nos();
	if (warnings) {
	    if (warnings>1)
	        printf("%d warnings were ", warnings);
            else printf("One warning was ");
            printf("%sed.\n", nowarn ? "suppress" : "issu");
	}
#else  /* __MSDOS__ */
	die("No option switches specified:  -q, -R, or -V");
#endif /* __MSDOS__ */
	
    return 0;
}
