a4e4522776d3b8677ed3d1f185d5b573bb0980c1
[rrq/maintain_lilo.git] / src / lilo.c
1 /* lilo.c  -  LILO command-line parameter processing
2  * 
3  * Copyright 1992-1998 Werner Almesberger
4  * Copyright 1999-2007 John Coffman
5  * Copyright 2009-2010 Joachim Wiedorn
6  * All rights reserved.
7  * 
8  * Licensed under the terms contained in the file 'COPYING'
9  * in the source directory.
10  */
11
12 #define _GNU_SOURCE
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <time.h>
21 #include <limits.h>
22 #include <dirent.h>
23 /*#include <asm/page.h>*/
24
25 #include "config.h"
26 #include "lilo.h"
27 #include "common.h"
28 #include "cfg.h"
29
30 #if !__MSDOS__
31 #include "raid.h"
32 #include "boot.h"
33 #include "device.h"
34 #include "flags.i"
35 #include "geometry.h"
36 #endif /* !__MSDOS__ */
37 #include "map.h"
38 #if !__MSDOS__
39 #include "bsect.h"
40 #include "identify.h"
41 #include "partition.h"
42 #include "probe.h"
43 #include "temp.h"
44 #include "loader.h"
45 #include "md-int.h"
46 #include "edit.h"
47 #endif /* !__MSDOS__ */
48
49
50 char *config_file;              /* actual name of the config file */
51 int config_read;                /* readable by other than root */
52 FILE *errstd;
53
54 static void configuration(void)
55 {
56 #if VERSION_MINOR>=50 && !__MSDOS__
57 {
58                 printf(
59                 "-DBOOT_PARAMS_1=%d -DBOOT_PARAMS_2=%d  PATH_MAX=%d"
60                   "\n"
61                   ,
62                   (int)sizeof(BOOT_PARAMS_1),
63                   (int)sizeof(BOOT_PARAMS_2),
64                   PATH_MAX
65                      );
66 }
67 {
68 #include "bitmap.h"
69         RGB pal[16];
70         RGB2 pal2[16];
71         
72         printf("\nBMFH=%d BMH=%d BMH2=%d RGB=%d(%d) RGB2=%d(%d) LH=%d\n",
73         (int)sizeof(BITMAPFILEHEADER),
74         (int)sizeof(BITMAPHEADER),
75         (int)sizeof(BITMAPHEADER2),
76         (int)sizeof(RGB),
77         (int)sizeof(pal),
78         (int)sizeof(RGB2),
79         (int)sizeof(pal2),
80         (int)sizeof(BITMAPLILOHEADER) );
81         printf("\nBPB=%d BP_DOS=%d\n",
82                 (int)sizeof(BIOS_PARAMETER_BLOCK),
83                 (int)sizeof(BOOT_PARAMS_DOS)
84                   );
85 }
86 #ifdef LCF_FIRST6
87         printf("\nSECTOR_ADDR6=%d\n", (int)sizeof(SECTOR_ADDR6));
88 #endif
89
90 #endif /* VERSION_MINOR>=50 && !__MSDOS__ */
91
92 #if !__MSDOS__
93 {
94   unsigned int j;
95   if (verbose>=5) {
96     if (crc(First.data,First.size)) {
97         j = crc(First.data,First.size-4);
98         brev(j);
99         printf("1=0x%x\n", j);
100     }
101     if (crc(Second.data,Second.size)) {
102         j = crc(Second.data,Second.size-4);
103         brev(j);
104         printf("2=0x%x\n", j);
105     }
106     if (crc(Third.data,Third.size)) {
107         j = crc(Third.data,Third.size-4);
108         brev(j);
109         printf("3=0x%x\n", j);
110     }
111     if (crc(Bitmap.data,Bitmap.size)) {
112         j = crc(Bitmap.data,Bitmap.size-4);
113         brev(j);
114         printf("B=0x%x\n", j);
115     }
116     if (crc(Chain.data,Chain.size)) {
117         j = crc(Chain.data,Chain.size-4);
118         brev(j);
119         printf("C=0x%x\n", j);
120     }
121     if (crc(Mbr.data,Mbr.size)) {
122         j = crc(Mbr.data,Mbr.size-4);
123         brev(j);
124         printf("M=0x%x\n", j);
125     }
126     if (crc(Mbr2.data,Mbr2.size)) {
127         j = crc(Mbr2.data,Mbr2.size-4);
128         brev(j);
129         printf("N=0x%x\n\n", j);
130     }
131   }
132 }
133
134 #if BETA_TEST
135 {
136     int i, j, k=0;
137 extern int has_partitions_beta(dev_t dev);      /* defined in geometry.c */
138
139
140     printf("\n");
141     for (i=0; i<256; i++) {
142         if ( has_partitions_beta(MKDEV(i,0)) != has_partitions(MKDEV(i,0)) ) {
143             printf("Major device = %d is not configured.\n", i);
144             k ++;
145         }
146     }
147     printf("%sk = %d (should be 0)\n\n", k?"ERROR: ":"", k);
148     for (i=0, j=0; i<40960; i+=17) {
149         dev_t dev;
150         int major, minor;
151         for (k=0; k<81920; k+=19) {
152             dev = MKDEV(i,k);
153             major = MAJOR(dev);
154             minor = MINOR(dev);
155             if (major != i  ||  minor != k) {
156                 printf("ERROR: (%d,%d) -> (%d,%d)\n",
157                     i, k, major, minor);
158                 j++;
159             }
160         }
161     }
162     if (j==0) printf("MKDEV check passed\n");
163 }
164 #endif
165
166 #if VERSION_MINOR>=50
167 {
168         dev_t dev; int i;
169         BOOT_VOLID x;
170         BOOT_SECTOR b;
171         dev = 0xFFF0;
172         i = dev;
173         printf("dev_t is %ssigned size=%d  i=%08X\n", i==0xFFF0 ? "un" : "", (int)sizeof(dev_t), i);
174         printf("size of BOOT_VOLID = %d   BOOT_SECTOR = %d\n", (int)sizeof(x), (int)sizeof(b));
175         printf("Size of MENUTABLE = %d\n", (int)sizeof(MENUTABLE));
176 }
177 #endif
178                 printf("\nCFLAGS = " CFLAGS "\n");
179 #if defined(LCF_DEVMAPPER) && defined(HAS_LIBDEVMAPPER_H)
180                 printf("With");
181 #else
182                 printf("Without");
183 #endif
184                 printf(" device-mapper\n");
185                 printf("\nglibc version %d.%d\n", __GLIBC__, __GLIBC_MINOR__);
186                 printf("Kernel Headers included from  %d.%d.%d\n",
187                         LINUX_VERSION_CODE>>16,
188                         LINUX_VERSION_CODE>>8 & 255,
189                         LINUX_VERSION_CODE & 255);
190                 printf("Maximum Major Device = %d\n", MAJOR(~0UL));
191 #endif /* !__MSDOS__ */
192                 printf("MAX_IMAGES = %d\t\tc=%d, s=%d, i=%d, "
193                                 "l=%d, ll=%d, f=%d, d=%d, ld=%d\n",
194                         MAX_IMAGES, (int)sizeof(char),
195                         (int)sizeof(short), (int)sizeof(int),
196                         (int)sizeof(long), (int)sizeof(
197 #if !__MSDOS__
198                         long
199 #endif /* !__MSDOS__ */
200                              long),
201                         (int)sizeof(float), (int)sizeof(double),
202                         (int)sizeof(long double)
203                         );
204                 printf("IMAGE_DESCR = %d   DESCR_SECTORS = %d\n\n",
205                         (int)sizeof(IMAGE_DESCR), (int)sizeof(DESCR_SECTORS));
206 }
207
208 #if !__MSDOS__
209
210 static void show_other(int fd)
211 {
212     BOOT_SECTOR buf[SETUPSECS-1];
213     const unsigned char *drvmap;
214     const unsigned char *prtmap;
215
216     if (read(fd,buf,sizeof(buf)) != sizeof(buf))
217         die("Read on map file failed (access conflict ?) 1");
218     if (!strncmp(buf[0].par_c.signature-4,"LILO",4)) {
219         printf("    Pre-21 signature (0x%02x,0x%02x,0x%02x,0x%02x)\n",
220           buf[0].par_c.signature[0],buf[0].par_c.signature[1],
221           buf[0].par_c.signature[2],buf[0].par_c.signature[3]);
222         return;
223     }
224     if (strncmp(buf[0].par_c.signature,"LILO",4)) {
225         printf("    Bad signature (0x%02x,0x%02x,0x%02x,0x%02x)\n",
226           buf[0].par_c.signature[0],buf[0].par_c.signature[1],
227           buf[0].par_c.signature[2],buf[0].par_c.signature[3]);
228         return;
229     }
230     drvmap = ((unsigned char *) buf+buf[0].par_c.drvmap);
231     prtmap = drvmap+2*(DRVMAP_SIZE+1);
232     while (drvmap[0] && drvmap[1]) {
233         if (drvmap[0]==0xFF && drvmap[1]==0xFF) {
234             if (drvmap[3]==0xFF) printf("    Master-Boot:  This BIOS drive will always appear as 0x80 (or 0x00)\n");
235             else printf("    Boot-As:  This BIOS drive will always appear as 0x%02X\n", drvmap[3]);
236             drvmap += 4;
237         } else {
238             printf("    BIOS drive 0x%02X is mapped to 0x%02X\n",drvmap[0],
239                                                 drvmap[1]);
240             drvmap += 2;
241         }
242     }
243     /* fix VERY old bug -- offset of 0 in PT is okay */
244     while (prtmap[0] /*** && prtmap[1] ***/ ) {
245         printf("    BIOS drive 0x%02x, offset 0x%x: 0x%02x -> 0x%02x\n",
246           prtmap[0],prtmap[1]+PART_TABLE_OFFSET,prtmap[2],prtmap[3]);
247         prtmap += 4;
248     }
249 }
250 #endif /* !__MSDOS__ */
251
252 static void show_images(char *map_file)
253 {
254 #if !__MSDOS__
255     DESCR_SECTORS descrs;
256     BOOT_SECTOR boot;
257     MENUTABLE menu;
258     BOOT_PARAMS_2 param2;
259     GEOMETRY geo;
260     SECTOR_ADDR addr[4];
261     char buffer[SECTOR_SIZE];
262 #else /* __MSDOS */
263 static DESCR_SECTORS descrs;
264 static char buffer[SECTOR_SIZE];
265 #endif /*__MSDOS__ */
266     char *name;
267     int fd,image;
268     int tsecs;
269     int tlinear, tlba32;
270     unsigned short flags;
271     time_t Time;
272
273 #if !__MSDOS__
274     fd = geo_open(&geo,map_file,O_RDONLY);
275 #else  /* __MSDOS__ */
276     if ((fd = open(map_file,O_RDONLY))<=0)
277         die("Cannot open map file: %s", map_file);
278 #endif /* __MSDOS__ */
279     if (read(fd,buffer,SECTOR_SIZE) != SECTOR_SIZE)
280         die("read cmdline %s: %s",map_file,strerror(errno));
281     if (read(fd,(char*)&descrs,sizeof(descrs)) != sizeof(descrs))
282         die("read descrs %s: %s",map_file,strerror(errno));
283 #if !__MSDOS__
284     if (lseek(fd, SECTOR_SIZE, SEEK_CUR) <= 0)  /* skip zero sector */
285         die("lseek over zero sector %s: %s",map_file,strerror(errno));
286     if (read(fd,(char*)&param2,sizeof(param2)) != sizeof(param2))
287         die("read second params %s: %s",map_file,strerror(errno));
288     if (lseek(fd, - sizeof(menu), SEEK_END) <= 0)
289         die("lseek keytable %s: %s",map_file,strerror(errno));
290     if (read(fd,(char*)&menu,sizeof(menu)) != sizeof(menu))
291         die("read keytable %s: %s",map_file,strerror(errno));
292     tlba32  = (descrs.d.descr[0].start.device & LBA32_FLAG) != 0;
293     tlinear = !tlba32 && (descrs.d.descr[0].start.device & LINEAR_FLAG);
294     if (tlinear != linear  ||  tlba32 != lba32) {
295         printf("Warning: mapfile created with %s option\n",
296                tlinear?"linear":tlba32?"lba32":"no linear/lba32");
297         linear = tlinear;  lba32 = tlba32;
298     }
299     if (verbose) {
300         bsect_read(cfg_get_strg(cf_options,"boot"),&boot);
301 #if 1
302         if (boot.par_1.cli != 0xFA) {   /* relocation happened */
303             int len, offset=0;
304             if (boot.sector[0] == 0xEB)         /* jmp short */
305                 offset = boot.sector[1]+2;
306             else if (boot.sector[0] == 0xE9)    /* jmp near */
307                 offset = *(short*)&boot.sector[1] + 3;
308             else die("Cannot undo boot sector relocation.");
309             len = SECTOR_SIZE - offset;
310             memmove(&boot, &boot.sector[offset], len);
311             if (boot.par_1.cli != 0xFA)
312                 die("Cannot recognize boot sector.");
313         }
314 #endif
315 #if 1
316         Time = boot.par_1.map_stamp;
317         printf("Installed:  %s\n", ctime(&Time));
318 #else
319         printf("Installed:  %s\n", ctime((time_t*)&boot.par_1.map_stamp));
320 #endif
321         printf("Global settings:\n");
322         tsecs = (param2.delay*2197+3999)/4000;
323         printf("  Delay before booting: %d.%d seconds\n",tsecs/10,tsecs % 10);
324         if (param2.timeout == 0xffff) printf("  No command-line timeout\n");
325         else {
326             tsecs = (param2.timeout*2197+3999)/4000;
327             printf("  Command-line timeout: %d.%d seconds\n",tsecs/10,
328               tsecs % 10);
329         }
330         printf("  %snattended booting\n", param2.flag2&FLAG2_UNATTENDED ? "U" : "No u");
331         printf("  %sPC/AT keyboard hardware prescence check\n", param2.flag2&FLAG2_NOKBD ? "" : "No ");
332         if (boot.par_1.prompt & FLAG_PROMPT) printf("  Always enter boot prompt\n");
333         else printf("  Enter boot prompt only on demand\n");
334         printf("  Boot-time BIOS data%s saved\n",
335                 boot.par_1.prompt & FLAG_NOBD ? " NOT" : "");
336         printf("  Boot-time BIOS data auto-suppress write%s bypassed\n",
337                 boot.par_1.prompt & FLAG_BD_OKAY ? "" : " NOT");
338         printf("  Large memory (>15M) is%s used to load initial ramdisk\n", 
339                 boot.par_1.prompt & FLAG_LARGEMEM ? "" : " NOT");
340         printf("  %sRAID installation\n",
341                 boot.par_1.prompt & FLAG_RAID ? "" : "Non-");
342         printf("  Boot device %s be used for the Map file\n",
343                 boot.par_1.prompt & FLAG_MAP_ON_BOOT ? "WILL" : "will not");
344         if (!param2.port) printf("  Serial line access is disabled\n");
345         else printf("  Boot prompt can be accessed from COM%d\n",
346               param2.port);
347         if (!param2.msg_len) printf("  No message for boot prompt\n");
348         else if (!cfg_get_strg(cf_options,"bitmap"))
349             printf("  Boot prompt message is %d bytes\n",param2.msg_len);
350         else printf("  Bitmap file is %d paragraphs (%d bytes)\n",
351                         param2.msg_len, 16*param2.msg_len);
352 /* 22.6.2 begin */
353         if (*(unsigned short *) buffer != DC_MAGIC /* || !buffer[2] */)
354 /* 22.6.2 end */
355             printf("  No default boot command line\n");
356         else printf("  Default boot command line: \"%s\"\n",buffer+2);
357         if (verbose>=3) {
358             printf("Serial numbers %08X\n", menu.serial_no[0]);
359         }
360         printf("Images:\n");
361     }
362 /* 22.7 begin */
363     else        /* verbose==0 */
364 #endif /* !__MSDOS__ */
365     {
366         if (*(unsigned short *) buffer == DC_MAGIC)
367             printf("Default boot command line: \"%s\"\n",buffer+2);
368     }
369 /* 22.7 end */
370     for (image = 0; image < MAX_IMAGES; image++) {
371         if (*(name = descrs.d.descr[image].name)) {
372 #if __MSDOS__
373             printf("%s\n", name
374 #else /* !__MSDOS__ */
375             printf("%s%-" SA(MAX_IMAGE_NAME) "s %s%s%s",verbose > 0 ? "  " : "",name,
376               image ? "" : "*",
377 #ifdef LCF_VIRTUAL
378               descrs.d.descr[image].flags & FLAG_VMDEFAULT ? "@" :
379 #endif
380               "",
381 #ifdef LCF_NOKEYBOARD
382               descrs.d.descr[image].flags & FLAG_NOKBDEFAULT ? "&" :
383 #endif
384               ""
385 #endif /* !__MSDOS__ */
386               );
387 #if !__MSDOS__
388             if (verbose >= 2) {
389                 if (descrs.d.descr[image].start.device & (LINEAR_FLAG|LBA32_FLAG)) {
390                    unsigned int sector;
391                    sector = (descrs.d.descr[image].start.device & LBA32_FLAG)
392                       && (descrs.d.descr[image].start.device & LBA32_NOCOUNT)
393                         ? descrs.d.descr[image].start.num_sect : 0;
394                    sector = (sector<<8)+descrs.d.descr[image].start.head;
395                    sector = (sector<<8)+descrs.d.descr[image].start.track;
396                    sector = (sector<<8)+descrs.d.descr[image].start.sector;
397                    printf(" <dev=0x%02x,%s=%d>",
398                      descrs.d.descr[image].start.device&DEV_MASK,
399                      descrs.d.descr[image].start.device&LBA32_FLAG ? "lba32" : "linear",
400                      sector);
401                 }
402                 else { /*  CHS addressing */
403                     printf(" <dev=0x%02x,hd=%d,cyl=%d,sct=%d>",
404                       descrs.d.descr[image].start.device,
405                       descrs.d.descr[image].start.head,
406                       descrs.d.descr[image].start.track,
407                       descrs.d.descr[image].start.sector);
408                 }
409             }
410             printf("\n");
411             if (verbose >= 1) {
412                 flags = descrs.d.descr[image].flags;
413 #ifdef LCF_VIRTUAL
414                 if (flags & FLAG_VMDISABLE)
415                     printf("    Virtual Boot is disabled\n");
416                 if (flags & FLAG_VMWARN)
417                     printf("    Warn on Virtual boot\n");
418 #endif          
419 #ifdef LCF_NOKEYBOARD
420                 if (flags & FLAG_NOKBDISABLE)
421                     printf("    NoKeyboard Boot is disabled\n");
422 #endif          
423                 if ( !(flags & FLAG_PASSWORD) )
424                     printf("    No password\n");
425                 else printf("    Password is required for %s\n",flags &
426                       FLAG_RESTR ? "specifying options" : "booting this image");
427                 printf("    Boot command-line %s be locked\n",flags &
428                   FLAG_LOCK ? "WILL" : "won't");
429                 printf("    %single-key activation\n",flags & FLAG_SINGLE ?
430                   "S" : "No s");
431                 if (flags & FLAG_KERNEL) {
432 #ifdef NORMAL_VGA
433                     if (!(flags & FLAG_VGA))
434                        printf("    VGA mode is taken from boot image\n");
435                     else {
436                         printf("    VGA mode: ");
437                         switch (descrs.d.descr[image].vga_mode) {
438                             case NORMAL_VGA:
439                                 printf("NORMAL\n");
440                                 break;
441                             case EXTENDED_VGA:
442                                 printf("EXTENDED\n");
443                                 break;
444                             case ASK_VGA:
445                                 printf("ASK\n");
446                                 break;
447                             default:
448                                 printf("%d (0x%04x)\n",
449                                   descrs.d.descr[image].vga_mode,
450                                   descrs.d.descr[image].vga_mode);
451                         }
452                     }
453 #endif
454                     if (!(flags & FLAG_LOADHI))
455                         printf("    Kernel is loaded \"low\"\n");
456                     else printf("    Kernel is loaded \"high\"\n");
457                     if (!*(unsigned int *) descrs.d.descr[image].rd_size)
458                         printf("    No initial RAM disk\n");
459                     else printf("    Initial RAM disk is %d bytes\n",
460                           *(unsigned int *) descrs.d.descr[image].rd_size);
461                     if (flags & FLAG_TOOBIG)
462                         printf("       and is too big to fit between 4M-15M\n");
463                 }
464                 if (!geo_find(&geo,descrs.d.descr[image].start)) {
465                     printf("    Map sector not found\n");
466                     continue;
467                 }
468                 if (read(fd,addr,4*sizeof(SECTOR_ADDR)) !=
469                   4*sizeof(SECTOR_ADDR))
470                         die("Read on map file failed (access conflict ?) 2");
471                 if (!geo_find(&geo,addr[0]))
472                     printf("    Fallback sector not found\n");
473                 else {
474                     if (read(fd,buffer,SECTOR_SIZE) != SECTOR_SIZE)
475                         die("Read on map file failed (access conflict ?) 3");
476                     if (*(unsigned short *) buffer != DC_MAGIC)
477                         printf("    No fallback\n");
478                     else printf("    Fallback: \"%s\"\n",buffer+2);
479                 }
480 #define OTHER 0
481 #if OTHER
482                 if (flags & FLAG_KERNEL)
483 #endif
484                     if (!geo_find(&geo,addr[1]))
485                         printf("    Options sector not found\n");
486                     else {
487                         if (read(fd,buffer,SECTOR_SIZE) != SECTOR_SIZE)
488                             die("Read on map file failed (access conflict ?) 4");
489                         if (*buffer) printf("    Options: \"%s\"\n",buffer);
490                         else printf("    No options\n");
491                     }
492 #if OTHER
493                 else {
494 #else
495                 if (!(flags & FLAG_KERNEL)) {
496 #endif
497                     if (geo_find(&geo,addr[3])) show_other(fd);
498                     else printf("    Image data not found\n");
499                 }
500             }
501 #endif /*  !__MSDOS__ */
502         } /* if */
503     } /* for */
504 #undef OTHER
505     (void) close(fd);
506 #if !__MSDOS__
507     if (descrs.l.checksum ==
508           crc32(descrs.sector, sizeof(descrs.l.sector), CRC_POLY1) )
509 #endif /* !__MSDOS__ */
510                 exit(0);
511 #if !__MSDOS__
512     fflush(stdout);
513     fprintf(errstd,"Checksum error\n");
514     exit(1);
515 #endif /* !__MSDOS__ */
516 }
517
518
519 static void usage(char *name)
520 {
521     char *here;
522
523 #if !__MSDOS__
524     here = strrchr(name,'/');
525 #else /* __MSDOS__ */
526     here = strrchr(name,'\\');
527 #endif /* __MSDOS__ */
528     if (here) name = here+1;
529     fprintf(errstd,"usage: %s [ -C config_file ] -q [ -m map_file ] "
530       "[ -v N | -v ... ]\n",name);
531 #if !__MSDOS__
532     fprintf(errstd,"%7s%s [ -C config_file ] [ -b boot_device ] [ -c ] "
533       "[ -g | -l | -L ]\n","",name);
534     fprintf(errstd,"%12s[ -F ] [ -i boot_loader ] [ -m map_file ] [ -d delay ]\n","");
535     fprintf(errstd,"%12s[ -v N | -v ... ] [ -t ] [ -s save_file | -S save_file ]\n",
536       "");
537     fprintf(errstd,"%12s[ -p ][ -P fix | -P ignore ] [ -r root_dir ] [ -w | -w+ ]\n","");
538 #endif /* !__MSDOS__ */
539     fprintf(errstd,"%7s%s [ -C config_file ] [ -m map_file ] "
540       "-R [ word ... ]\n","",name);
541 #if !__MSDOS__
542     fprintf(errstd,"%7s%s [ -C config_file ] -I name [ options ]\n","",name);
543     fprintf(errstd,"%7s%s [ -C config_file ] [ -s save_file ] "
544       "-u | -U [ boot_device ]\n","",name);
545     fprintf(errstd,"%7s%s -A /dev/XXX [ N ]\t\tinquire/activate a partition\n","",name);
546     fprintf(errstd,"%7s%s -M /dev/XXX [ mbr | ext ]\tinstall master boot record\n","",name);
547     fprintf(errstd,"%7s%s -T help \t\t\tlist additional options\n", "", name);
548     fprintf(errstd,"%7s%s -X\t\t\t\tinternal compile-time options\n", "", name);
549 #endif /* !__MSDOS__ */
550     fprintf(errstd,"%7s%s -V [ -v ]\t\t\tversion information\n\n","",name);
551     exit(1);
552 }
553
554
555 int main(int argc,char **argv)
556 {
557     char *name,*reboot_arg,*ident_opt,*new_root;
558     char *tell_param, *uninst_dev, *param, *act1, *act2, ch;
559 static char *bitmap_file;
560     int more,version,uninstall,validate,activate,instmbr,geom;
561     int fd, temp=0, tell_early=0;
562     int raid_offset;
563 #if !__MSDOS__
564     struct stat st;
565 #endif /* !__MSDOS__ */
566
567     errstd = stderr;
568 #if VERSION_MINOR>=50
569     if (sizeof(MENUTABLE)!=256) die("MENUTABLE is not 256 bytes (common.h)");
570 #if !__MSDOS__
571     cfg_alpha_check();
572 #endif /* !__MSDOS__ */
573 #endif
574     config_file = DFL_CONFIG;
575     act1 = act2 = tell_param = 
576             reboot_arg = identify = ident_opt = new_root = uninst_dev = NULL;
577     do_md_install = zflag =
578             version = uninstall = validate = activate = instmbr = 0;
579     verbose = -1;
580 #if !__MSDOS__
581     name = *argv;
582 #else  /* __MSDOS__ */
583     name = "lilo";
584 #endif /* __MSDOS__ */
585     argc--;
586
587 #if !__MSDOS__    
588     if (atexit( (void(*)(void)) sync)) die("atexit(sync)");
589     if (atexit( (void(*)(void)) purge)) die("atexit(purge)");
590 #endif /* !__MSDOS__ */
591     
592     cfg_init(cf_options);
593     while (argc && **++argv == '-') {
594         argc--;
595       /* first those options with a mandatory parameter */
596       /* Notably absent are "RuUvw" */
597         if (strchr("AbBCdDEfiImMPrsSTxZ", ch=(*argv)[1])) {
598             if ((*argv)[2]) param = (*argv)+2;
599             else {
600                 param = *++argv;
601                 if(argc-- <= 0) usage(name);
602             }
603         } else { 
604             param = NULL;
605             if (strchr("cFglLpqtVXz", ch)       /* those with no args */
606                 && (*argv)[2]) usage(name);
607         }
608 #if 0
609 fprintf(errstd,"argc=%d, *argv=%s, ch=%c param=%s\n", argc, *argv, ch, param);
610 #endif
611         switch (ch) {
612 #if !__MSDOS__
613             case 'A':
614                 activate = 1;
615                 act1 = param;
616                 if (argc && argv[1][0] != '-') {
617                     act2 = *++argv;
618                     argc--;
619                 }
620                 break;
621             case 'b':
622                 cfg_set(cf_options,"boot",param,NULL);
623                 break;
624             case 'B':
625                 cfg_set(cf_options,"bitmap",param,NULL);
626                 break;
627             case 'c':
628                 cfg_set(cf_options,"compact",NULL,NULL);
629                 compact = 1;
630                 break;
631 #endif /* !__MSDOS */
632             case 'C':
633                 config_file = param;
634                 break;
635 #if !__MSDOS__
636             case 'd':
637                 cfg_set(cf_options,"delay",param,NULL);
638                 break;
639             case 'D':
640                 cfg_set(cf_options,"default",param,NULL);
641                 break;
642             case 'E':
643                 eflag=1;
644                 bitmap_file = param;
645                 break;
646             case 'f':
647                 cfg_set(cf_options,"disktab",param,NULL);
648                 break;
649             case 'F':
650                 force_fs=1;
651                 break;
652             case 'g':
653                 geometric |= AD_GEOMETRIC;
654                 break;
655             case 'H':
656                 force_raid=1;
657                 break;
658             case 'i':
659                 cfg_set(cf_options,"install",param,NULL);
660                 break;
661             case 'I':
662                 identify = param;
663                 if (argc && *argv[1] != '-') {
664                     ident_opt = *++argv;
665                     argc--;
666                 } else {
667                     ident_opt = "i";
668                 }
669                 break;
670             case 'l':
671                 geometric |= AD_LINEAR;
672                 break;
673             case 'L':
674                 geometric |= AD_LBA32;
675                 break;
676 #endif /* !__MSDOS__ */
677             case 'm':
678                 cfg_set(cf_options,"map",param,NULL);
679                 break;
680 #if !__MSDOS__
681             case 'M':
682                 instmbr = 1;
683                 act1 = param;
684 #if !defined LCF_BUILTIN        || 1
685                 if (argc && argv[1][0] != '-') {
686                     act2 = *++argv;
687                     argc--;
688                 }
689 #endif
690                 break;
691             case 'p':
692                 passw = 1;      /* force re-gen of password file */
693                 break;
694             case 'P':
695                 if ((act1=strchr(param,'='))) {
696                     *act1++ = 0;        /* null terminate */
697                     cfg_set(cf_options,param,act1,NULL);
698                 }
699                 else if (!strcasecmp(param,"fix"))
700                     cfg_set(cf_options,"fix-table",NULL,NULL);
701                 else if (!strcasecmp(param,"ignore"))
702                     cfg_set(cf_options,"ignore-table",NULL,NULL);
703                 else if (!strcasecmp(param,"x"))
704                     extended_pt = 1;
705                 else
706                     cfg_set(cf_options,param,NULL,NULL);
707                 break;
708 #endif /* !__MSDOS__ */
709             case 'q':
710                 query = 1;
711                 break;
712 #if !__MSDOS__
713             case 'r':
714                 new_root = param;
715                 break;
716 #endif /* !__MSDOS__ */
717             case 'R':
718                 if (*(param = (*argv)+2)) argc++;
719                 else if (argc) param = *++argv;
720                 else reboot_arg = "";
721                 
722                 while (argc) {
723                         if (!reboot_arg)
724                             *(reboot_arg = alloc(strlen(param)+1)) = 0;
725                         else {
726                             param = *++argv;
727                             strcat(reboot_arg = ralloc(reboot_arg,
728                                 strlen(reboot_arg)+strlen(param)+2)," ");
729                         }
730                         strcat(reboot_arg, param);
731                         argc--;
732                     }
733 #if 0
734 fprintf(errstd,"REBOOT=\"%s\"\n", reboot_arg);              
735 #endif
736                 break;
737 #if !__MSDOS__
738             case 's':
739                 cfg_set(cf_options,"backup",param,NULL);
740                 break;
741             case 'S':
742                 cfg_set(cf_options,"force-backup",param,NULL);
743                 break;
744             case 't':
745                 test = 1;
746                 break;
747             case 'T':
748                 tell_param = param;
749                 break;
750             case 'u':
751                 validate = 1;
752                 /* fall through */
753             case 'U':   /* argument to -u or -U is optional */
754                 uninstall = 1;
755                 if ((*argv)[2]) param = (*argv)+2;
756                 else if (argc && argv[1][0] != '-') {
757                     param = *++argv;
758                     argc--;
759                 }
760                 uninst_dev = param;
761                 break;
762 #endif /* !__MSDOS__ */
763             case 'v':
764                 if ((*argv)[2]) param = (*argv)+2;
765                 else if (argc && argv[1][0]>='0' && argv[1][0]<='9') {
766                     param = *++argv;
767                     argc--;
768                 }
769                 if (param) 
770                     verbose = to_number(param);
771                 else
772                     if (verbose<0) verbose = 1;
773                     else verbose++;
774                 if (verbose) errstd = stdout;
775                 break;
776             case 'V':
777                 version = 1;
778                 break;
779 #if !__MSDOS__
780             case 'w':
781                 cfg_set(cf_options,"nowarn",NULL,NULL);
782                 nowarn = 1;
783                 if ( (*argv)[2] == '+' ) nowarn = -1;
784                 break;
785             case 'x':
786                 cfg_set(cf_options,RAID_EXTRA_BOOT,param,NULL);
787                 break;
788 #endif /* !__MSDOS__ */
789             case 'X':
790                 configuration();
791                 exit(0);
792 #if !__MSDOS__
793             case 'z':
794                 zflag++;        /* force zero of MBR 8-byte area */
795                 break;
796             case 'Z':
797                 cfg_set(cf_options,"bios-passes-dl",param,NULL);
798                 break;
799 #endif /* !__MSDOS__ */
800             default:
801                 usage(name);
802         }
803     }
804     if (argc) usage(name);
805 #if !__MSDOS__
806     if (!new_root) new_root = getenv("ROOT");
807     if (new_root && *new_root) {
808         pp_fd = fopen(PARTITIONS, "r");
809         if (chroot(new_root) < 0) die("chroot %s: %s",new_root,strerror(errno));
810         if (chdir("/dev") < 0)
811                 warn("root at %s has no /dev directory", new_root);
812         if (chdir("/") < 0) die("chdir /: %s",strerror(errno));
813     }
814     if (atexit(temp_remove)) die("atexit() failed");
815     if (version+activate+instmbr+(tell_param!=NULL) > 1) usage(name);
816     if (activate) do_activate(act1, act2);
817 #endif /* !__MSDOS__ */
818     if (verbose > 0 || version) {
819        printf("LILO version %d.%d%s%s", VERSION_MAJOR, VERSION_MINOR,
820               VERSION_EDIT, test ? " (test mode)" : "");
821         if (version && verbose<=0) {
822             printf("\n");
823             return 0;
824         }
825         printf("\n * Copyright (C) 1992-1998 Werner Almesberger  (until v20)\n"
826                         " * Copyright (C) 1999-2007 John Coffman  (until v22)\n"
827                         " * Copyright (C) 2009-2010 Joachim Wiedorn  (since v23)\n"
828                         "This program comes with ABSOLUTELY NO WARRANTY. This is free software \n"
829                         "distributed under the BSD License (3-clause). Details can be found in \n"
830                         "the file COPYING, which is distributed with this software.\n"
831                );
832         if (verbose>0) {
833 #if !__MSDOS__
834 #include <sys/utsname.h>
835             struct utsname buf;
836 #endif
837             printf("Released %s%s and compiled at %s on %s%s\n",
838                 VERSION_DATE, comma ? "," : "", __TIME__, __DATE__, semi);
839 #if !__MSDOS__
840             if (verbose>=2 && uname(&buf)==0) {
841                 printf("Running %s kernel %s on %s\n",
842                         buf.sysname, buf.release, buf.machine);
843             }
844 #endif
845         }
846         printf("\n");
847         if (version) {
848             if (verbose>=2) configuration();
849             return 0;
850         }
851     }
852
853     if (verbose > 0) errstd = stdout;
854 #if !__MSDOS__
855     preload_types();
856     if (geometric & (geometric-1))
857         die ("Only one of '-g', '-l', or '-L' may be specified");
858
859     if (tell_param) tell_early = strcasecmp(tell_param, "chrul")
860                                 && strcasecmp(tell_param, "ebda");
861     if (eflag) do_bitmap_edit(bitmap_file);
862     if (tell_param && tell_early) probe_tell(tell_param);
863     if (instmbr) do_install_mbr(act1, act2);
864 #endif /* !__MSDOS__ */    
865
866     fd = cfg_open(config_file);
867     more = fd<0 ? 0 : cfg_parse(cf_options);
868     
869 #if !__MSDOS__
870     temp = cfg_get_flag(cf_options,"nowarn");
871     if (nowarn < 0) nowarn = 0;
872     else nowarn = temp;
873 /* All warnings appear if very verbose modes used */
874     if (verbose>=3) nowarn = 0;
875 #endif /* !__MSDOS__ */
876
877     if (verbose>=6) printf("main: cfg_parse returns %d\n", more);
878
879 #if !__MSDOS__
880     if (tell_param && !tell_early) probe_tell(tell_param);
881
882     if (fstat(fd,&st) < 0)
883             die("fstat %s: %s", config_file, strerror(errno) );
884
885     if (S_ISREG(st.st_mode)) {
886         if (st.st_uid)
887             warn("%s should be owned by root", config_file);
888         else if (st.st_mode & (S_IWGRP | S_IWOTH))
889             warn("%s should be writable only for root", config_file);
890         config_read = !!(st.st_mode & (S_IRGRP | S_IROTH));
891     }
892
893     if (!cfg_get_flag(cf_options,"nodevcache"))  preload_dev_cache();
894     
895     if (verbose<0 && cfg_get_strg(cf_options,"verbose"))
896         verbose = to_number(cfg_get_strg(cf_options,"verbose"));
897     if (verbose<0) verbose = 0;
898     if (verbose) errstd = stdout;
899
900     compact = cfg_get_flag(cf_options,"compact");
901     geom = cfg_get_flag(cf_options,"geometric");
902     linear = cfg_get_flag(cf_options,"linear");
903     lba32  = cfg_get_flag(cf_options,"lba32");
904     
905     if (geom+linear+lba32 > 1)
906         die("May specify only one of GEOMETRIC, LINEAR or LBA32");
907     if (geometric) {
908         if (geom+linear+lba32 > 0)  
909             warn("Ignoring entry '%s'", geom ? "geometric" :
910                       linear ? "linear" : "lba32");
911         geom = linear = lba32 = 0;
912         if (geometric==AD_LBA32) lba32 = 1;
913         else if (geometric==AD_LINEAR) linear = 1;
914         else if (geometric==AD_GEOMETRIC) geom = 1;
915     }    
916     if (geom+linear+lba32 == 0) {
917         warn("LBA32 addressing assumed");
918         lba32 = 1;
919     }
920     if (linear) warn(
921         "LINEAR is deprecated in favor of LBA32:  LINEAR specifies 24-bit\n"
922         "  disk addresses below the 1024 cylinder limit; LBA32 specifies 32-bit disk\n"
923         "  addresses not subject to cylinder limits on systems with EDD-BIOS extensions;\n"
924         "  use LINEAR only if you are aware of its limitations.");
925     
926     if (identify) identify_image(identify,ident_opt);
927
928     if (uninstall)
929         bsect_uninstall(uninst_dev ? uninst_dev : cfg_get_strg(cf_options,
930               "boot"),cfg_get_strg(cf_options,"backup"),validate);
931 #endif /* !__MSDOS__ */
932
933     if (reboot_arg) {
934         map_patch_first(cfg_get_strg(cf_options,"map") ? cfg_get_strg(
935               cf_options,"map") : MAP_FILE, reboot_arg);
936         exit(0);
937     }
938
939 #if !__MSDOS__
940     if ( (param = cfg_get_strg(cf_options,"bios-passes-dl")) ) {
941         if (strchr("YyTt1", *param)) bios_passes_dl = DL_GOOD;
942         if (strchr("NnFf0", *param)) bios_passes_dl = DL_BAD;
943     }
944     if (bios_passes_dl == DL_NOT_SET)   check_bios();   /* in probe.c */
945
946     if (compact && (linear || lba32) && verbose>=4)
947         warn("COMPACT may conflict with %s on some "
948                 "systems", lba32 ? "LBA32" : "LINEAR");
949
950     geo_init(cfg_get_strg(cf_options,"disktab"));
951 #endif /* !__MSDOS__ */
952     if (query)
953         show_images(!cfg_get_strg(cf_options,"map") ? MAP_FILE :
954               cfg_get_strg(cf_options,"map"));
955
956 #if !__MSDOS__
957 /*************************************************/
958 /*  Doing a real install (may be test mode)      */
959 /*************************************************/
960
961 /* test for a RAID installation */
962         raid_offset = raid_setup();
963         if (verbose >= 2) {
964             printf("raid_setup returns offset = %08X  ndisk = %d\n", raid_offset, ndisk);
965             dump_serial_nos();    
966         }
967
968         if (verbose >=2 && do_md_install)
969             printf("raid flags: at bsect_open  0x%02X\n", raid_flags);
970
971         bsect_open(
972                 cfg_get_strg(cf_options,"boot"),
973                 cfg_get_strg(cf_options,"map") ?
974                         cfg_get_strg(cf_options,"map") : MAP_FILE,
975                 cfg_get_strg(cf_options,"install"),
976                 cfg_get_strg(cf_options,"delay") ?
977                         timer_number(cfg_get_strg(cf_options,"delay")) : 0,
978                 cfg_get_strg(cf_options,"timeout") ?
979                         timer_number(cfg_get_strg(cf_options,"timeout")) : -1,
980                 raid_offset );
981         if (more) {
982             cfg_init(cf_top);
983             if (cfg_parse(cf_top)) cfg_error("Syntax error");
984         }
985         
986         temp = bsect_number();
987         if (temp==0) die("No images have been defined.");
988         else if (temp<0) die("Default image doesn't exist.");
989
990 #ifdef LCF_VIRTUAL
991         check_vmdefault();
992 #endif
993 #ifdef LCF_NOKEYBOARD
994         check_nokbdefault();
995 #endif
996         check_fallback();
997         check_unattended();
998         
999         if (verbose>=2) dump_serial_nos();
1000         if (do_md_install) raid_final();
1001         else if (!test) {
1002             char *cp;
1003             
1004             if (verbose) printf("Writing boot sector.\n");
1005
1006             cp = cfg_get_strg(cf_options,"force-backup");
1007             if (cp) bsect_update(cp,1,0);
1008             else bsect_update(cfg_get_strg(cf_options,"backup"),0,0);
1009
1010         } 
1011         else {
1012             bsect_cancel();
1013             if (passw)
1014                 printf("The password crc file has *NOT* been updated.\n");
1015
1016             printf("The boot sector and the map file have *NOT* been "
1017               "altered.\n");
1018         }
1019         if (verbose>=4) dump_serial_nos();
1020         if (warnings) {
1021             if (warnings>1)
1022                 printf("%d warnings were ", warnings);
1023             else printf("One warning was ");
1024             printf("%sed.\n", nowarn ? "suppress" : "issu");
1025         }
1026 #else  /* __MSDOS__ */
1027         die("No option switches specified:  -q, -R, or -V");
1028 #endif /* __MSDOS__ */
1029         
1030     return 0;
1031 }