text: /* lilo.c  -  LILO command-line parameter processing
   * 
   * Copyright 1992-1998 Werner Almesberger
   * Copyright 1999-2007 John Coffman
   * Copyright 2009-2011 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(long), (int)sizeof(
  #if !__MSDOS__
  				long
  #endif /* !__MSDOS__ */
  				long),
  			(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--;
  					}
  #if 0
  					fprintf(errstd,"REBOOT=\"%s\"\n", reboot_arg);		    
  #endif
  					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-2011 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;
  #endif
  				printf("Compiled at %s on %s%s\n", __TIME__, __DATE__, semi);
  #if !__MSDOS__
  				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;
  	}
  