Add externs to avoid multiple definitions, and then add missing definitions.
[rrq/maintain_lilo.git] / src / bsect.c
1 /* bsect.c  -  Boot sector handling
2  * 
3  * Copyright 1992-1998 Werner Almesberger
4  * Copyright 1999-2007 John Coffman
5  * Copyright 2009-2011 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 <unistd.h>
14 #include <sys/types.h>
15 #include <sys/statfs.h>
16 #include <sys/stat.h>
17 #include <stdio.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <dirent.h>
21
22 #ifdef  _SYS_STATFS_H
23 #define _I386_STATFS_H  /* two versions of statfs is not good ... */
24 #endif
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <limits.h>
30 #include <assert.h>
31
32 #include "config.h"
33 #include "lilo.h"
34 #include "common.h"
35 #include "raid.h"
36 #include "cfg.h"
37 #include "device.h"
38 #include "geometry.h"
39 #include "map.h"
40 #include "temp.h"
41 #include "partition.h"
42 #include "boot.h"
43 #include "bsect.h"
44 #include "bitmap.h"
45 #include "probe.h"
46 #include "loader.h"
47 #include "edit.h"
48
49 #ifdef SHS_PASSWORDS
50 #include "shs2.h"
51 #endif
52 #if defined(LCF_UNIFY) || defined(LCF_BUILTIN)
53 #define EARLY_MAP
54 #endif
55
56
57 int boot_dev_nr;
58
59 static BOOT_SECTOR bsect,bsect_orig;
60 static MENUTABLE menuparams;
61 static DESCR_SECTORS descrs;
62 static char secondary_map[SECTOR_SIZE];
63 static unsigned char table[SECTOR_SIZE];        /* keytable & params */
64 static DEVICE dev;
65 static char *boot_devnam,*map_name;
66 static int use_dev_close = 0;
67 static int fd;
68 static int image_base = 0,image = 0;
69 static char temp_map[PATH_MAX+1];
70 static char *fallback[MAX_IMAGES];
71 static int fallbacks = 0;
72 static unsigned short stage_flags;
73 static int image_menu_space = MAX_IMAGES;
74 static char *getval_user;
75 static BOOT_PARAMS_2 param2;
76 static off_t here2;             /* sector address of second stage loader */
77 static int adapter = -1;        /* video adapter in use */
78
79 typedef struct Pass {
80     int crc[MAX_PW_CRC];
81     char *unique;
82     char *label;
83     struct Pass *next;
84     } PASSWORD;
85
86 static PASSWORD *pwsave = NULL;
87
88 BUILTIN_FILE *select_loader(void)
89 {
90     BUILTIN_FILE *loader = &Third;      /* MENU interface is the default */
91     char *install = cfg_get_strg(cf_options,"install");
92     char *bitmap  = cfg_get_strg(cf_options,"bitmap");
93
94     if (!install) {
95         if (bitmap) loader = &Bitmap;
96     } 
97     else if (strstr(install,"text")) loader = &Second;  /* text interface */
98     else if (strstr(install,"menu")) loader = &Third;
99     else if (strstr(install,"bmp") || bitmap) loader = &Bitmap;   /* menu interface (MDA, EGA, VGA) */
100         
101     adapter = get_video();      /* from probe.c */
102
103     if (adapter <= VIDEO_UNKNOWN && (verbose>=2 || loader==&Bitmap))
104             warn("Unable to determine video adapter in use in the present system.");
105     if (loader == &Third && adapter == VIDEO_CGA)
106             warn("Video adapter (CGA) is incompatible with the boot loader selected for\n"
107                                 "  installation ('install = menu').");
108     if (loader == &Bitmap && adapter < VIDEO_MCGA && adapter > VIDEO_UNKNOWN)
109             warn("Video adapter (%s) is incompatible with the boot loader selected for\n"
110                                 "  installation ('install = bitmap').", adapter==VIDEO_CGA ? "CGA" :
111                                 adapter==VIDEO_MDA ? "MDA" : "unknown");
112     
113     return loader;
114 }
115
116
117 /* kludge:  'append="..."' may not contain keywords acted upon by 
118    the LILO boot loader -- except "mem=XXX"
119  */
120 #define MEM_OKAY 1
121 static void check_options(char *options)
122 {
123 static char *disallow[] = { 
124 #if !MEM_OKAY
125                         "mem=",
126 #endif
127                                 "vga=", "kbd=", "lock", "nobd", NULL };
128     char *here, **dis = disallow;
129     int error = 0;
130
131     if (verbose >= 5) printf("check_options: \"%s\"\n", options);
132     if (strlen(options) > COMMAND_LINE_SIZE-1) {
133         warn("Command line options > %d will be truncated.", COMMAND_LINE_SIZE-1);
134     }
135     while (*dis) {
136         here = strstr(options, *dis);
137         if (here  &&  (here==options || here[-1] == ' ') ) {
138             if (here[3] == '=') error=2;
139             if (here[3] != '=' && (here[4]==' ' || here[4]==0) ) error=2;
140 #if !MEM_OKAY
141             if (*dis == disallow[0] && here[4]>='0' && here[4]<='9')
142                 error = 1 
143                 /*        + (cfg_get_strg(cf_kernel,"initrd") != NULL ||
144                              cfg_get_strg(cf_options,"initrd") != NULL) */
145                              ;
146 #endif
147         }
148         if (error>1) die ("APPEND or LITERAL may not contain \"%s\"", *dis);
149 #if !MEM_OKAY
150         if (error==1) {
151             warn("APPEND or LITERAL may not contain \"mem=\".");
152             error = 0;
153         }
154 #endif
155         ++dis;
156     }    
157 }
158
159 static int getval(char **cp, int low, int high, int default_value, int factor)
160 {
161     int temp;
162     
163     if (!**cp) {
164         if (factor && eflag) {
165             if (low==1) default_value--;
166             default_value *= factor;
167         }
168     }
169     else if (ispunct(**cp)) {
170         (*cp)++;
171         if (factor && eflag) {
172             if (low==1) default_value--;
173             default_value *= factor;
174         }
175     } else {
176         temp = strtol(*cp, cp, 0);
177         if (!factor) default_value = temp;
178         else {
179             if (**cp == 'p' || **cp == 'P') {
180                 (*cp)++;
181                 default_value = temp;
182                 temp /= factor;
183                 if (low==1) temp++;
184             } else {
185                 default_value = (low==1 ? temp-1 : temp)*factor;
186             }
187         }
188         
189         if (temp < low || temp > high)
190                 die("%s: value out of range [%d,%d]", getval_user, low, high);
191         if (**cp && !ispunct(**cp)) die("Invalid character: \"%c\"", **cp);
192         if (**cp) (*cp)++;
193     }
194     if (verbose>=5) printf("getval: %d\n", default_value);
195     
196     return default_value;
197 }
198
199 void bmp_do_timer(char *cp, MENUTABLE *menu)
200 {
201     if (!cp) {
202         if (eflag) menu->t_row = menu->t_col = -1;  /* there is none, if not specified during edit */
203     } else if (strcasecmp(cp,"none")==0) {
204         menu->t_row = menu->t_col = -1;  /* there is none, if specified as "none" */
205     } else {
206         getval_user = "bmp-timer";
207         menu->t_col = getval(&cp, 1, 76, menu->t_col, 8);
208         menu->t_row = getval(&cp, 1, 30, menu->t_row, 16);
209
210         if (!*cp && !eflag) return;
211         menu->t_fg = getval(&cp, 0, colormax, menu->fg, 0);
212         menu->t_bg = getval(&cp, 0, colormax, eflag?colormax^menu->t_fg:menu->t_bg, 0);
213         menu->t_sh = getval(&cp, 0, colormax, menu->t_fg, 0);
214     }
215 }
216
217
218 void bmp_do_table(char *cp, MENUTABLE *menu)
219 {
220     if (!cp) {
221         if (eflag) cp = "";
222         else return;            /* dont change anything */
223     }
224     
225     getval_user = "bmp-table";
226     menu->col = getval(&cp, 1, 80-MAX_IMAGE_NAME, menu->col/8 + 1, 8);
227     menu->row = getval(&cp, 1, 29, menu->row/16 + 1, 16);
228 #if 0
229     menu->ncol = getval(&cp, 1, 80/(MAX_IMAGE_NAME+2), 1, 0);
230     menu->maxcol = getval(&cp, 3, MAX_IMAGES, (MAX_IMAGES+menu->ncol-1)/menu->ncol, 0);
231     menu->xpitch = getval(&cp, MAX_IMAGE_NAME+2, 80/menu->ncol, MAX_IMAGE_NAME+6, 8);
232 #else
233     menu->ncol = getval(&cp, 1, 80/(MAX_IMAGE_NAME+1), menu->ncol, 0);
234     menu->maxcol = getval(&cp, 2, 30 - menu->row/16, eflag?30 - menu->row/16:menu->maxcol, 0);
235     menu->xpitch = getval(&cp, MAX_IMAGE_NAME+1, menu->ncol==1?80-menu->col/8:(80-menu->col/8-MAX_IMAGE_NAME*menu->ncol)/(menu->ncol-1)+MAX_IMAGE_NAME, menu->xpitch/8, 8);
236     menu->mincol = getval(&cp, 1, menu->maxcol, menu->mincol, 0);
237 #endif
238     if ((menu->row + menu->maxcol*16 > 480 || 
239          menu->col + (MAX_IMAGE_NAME+1)*8 + (menu->ncol-1)*menu->xpitch > 640))  
240                  warn("'bmp-table' may spill off screen");
241 }
242
243
244 void bmp_do_colors(char *cp, MENUTABLE *menu)
245 {
246     if (!cp) {
247         if (eflag) cp = "";
248         else return;            /* dont change anything */
249     }
250
251     getval_user = "bmp-colors";
252     menu->fg = getval(&cp, 0, colormax, menu->fg, 0);
253     if (!*cp && !eflag) return;
254     menu->bg = getval(&cp, 0, colormax, menu->fg, 0);
255     menu->sh = getval(&cp, 0, colormax, menu->fg, 0);
256
257     menu->h_fg = getval(&cp, 0, colormax, menu->h_fg, 0);
258     if (!*cp && !eflag) return;
259     menu->h_bg = getval(&cp, 0, colormax, menu->h_fg, 0);
260     menu->h_sh = getval(&cp, 0, colormax, menu->h_fg, 0);       
261 }
262
263 void pw_file_update(int passw)
264 {
265     PASSWORD *walk;
266     int i;
267     
268     if (verbose>=4) printf("pw_file_update:  passw=%d\n", passw);
269
270     if (passw && !test && pw_file) {
271         if (fseek(pw_file,0L,SEEK_SET)) perror("pw_file_update");
272     
273         for (walk=pwsave; walk; walk=walk->next) {
274             fprintf(pw_file, "label=<\"%s\">", walk->label);
275             for (i=0; i<MAX_PW_CRC; i++) fprintf(pw_file, " 0x%08X", walk->crc[i]);
276             fprintf(pw_file, "\n");
277         }
278     }
279     if (pw_file) fclose(pw_file);
280 }
281
282 void pw_fill_cache(void)
283 {
284     char line[MAX_TOKEN+1];
285     char *brace;
286     char *label;
287     PASSWORD *new;
288     int i;
289      
290     if (verbose>=5) printf("pw_fill_cache\n");    
291     if (fseek(pw_file,0L,SEEK_SET)) perror("pw_fill_cache");
292     
293     while (fgets(line,MAX_TOKEN,pw_file)) {
294         if (verbose>=5) printf("   %s\n", line);
295         brace = strrchr(line,'>');
296         label = strchr(line,'<');
297         if (label && label[1]=='"' && brace && brace[-1]=='"') {
298             brace[-1] = 0;
299             if ( !(new = alloc_t(PASSWORD)) ) pdie("Out of memory");
300             new->next = pwsave;
301             pwsave = new;
302             new->unique = NULL;
303             new->label = stralloc(label+2);
304             if (verbose>=2) printf("Password file: label=%s\n", new->label);
305             brace++;
306             for (i=0; i<MAX_PW_CRC; i++) {
307                 new->crc[i] = strtoul(brace,&label,0);
308                 brace = label;
309             }
310         }
311         else die("Ill-formed line in .crc file");
312     }
313     if (verbose >=5) printf("end pw_fill_cache\n");
314 }
315
316 static void hash_password(char *password, int crcval[])
317 {
318 #ifdef CRC_PASSWORDS
319    static int poly[] = {CRC_POLY1, CRC_POLY2, CRC_POLY3, CRC_POLY4, CRC_POLY5};
320 #endif
321         int crc;
322         int j;
323         int i = strlen(password);
324         
325 #ifdef SHS_PASSWORDS
326         shsInit();
327         shsUpdate((BYTE*)password, i);
328         shsFinal();
329 #endif
330         for (j=0; j<MAX_PW_CRC; j++) {
331             crcval[j] = crc =
332 #ifdef CRC_PASSWORDS
333                                 crc32((unsigned char *)password, i, poly[j]);
334   #define PWTYPE "CRC-32"
335 #else
336                                 shsInfo.digest[j];
337   #define PWTYPE "SHS-160"
338 #endif
339             if(verbose >= 2) {
340                 if (j==0) printf("Password " PWTYPE " =");
341                 printf(" %08X", crc);
342             }
343         }
344         if (verbose >= 2) printf("\n");
345 }
346
347
348 void pw_wipe(char *pass)
349 {
350     int i;
351     
352     if (!pass) return;
353     i = strlen(pass);
354     while (i) pass[--i]=0;
355     free(pass);
356 }
357
358
359 char *pw_input(void)
360 #if 1
361 {
362     char *cp = getpass("");
363     int i = strlen(cp);
364     char *acp = stralloc(cp);
365
366     while (i) cp[i--] = 0;
367     return acp;    
368 }
369 #else
370 {
371     char *pass;
372     char buf[MAX_TOKEN+1];
373     int i, ch;
374     
375     i = 0;
376     fflush(stdout);
377     while((ch=getchar())!='\n') if (i<MAX_TOKEN) buf[i++]=ch;
378     buf[i]=0;
379     pass = stralloc(buf);
380     while (i) buf[--i]=0;
381     return pass;
382 }
383 #endif
384
385 static void pw_get(char *pass, int crcval[], int option)
386 {
387     PASSWORD *walk;
388     char *pass2;
389     char *label;
390     
391     label = cfg_get_strg(cf_all, "label");
392     if (!label) label = cfg_get_strg(cf_top, "image");
393     if (!label) label = cfg_get_strg(cf_top, "other");
394     if (!label) die("Need label to get password");
395     if ((pass2 = strrchr(pass,'/'))) label = pass2+1;
396
397     for (walk=pwsave; walk; walk=walk->next) {
398         if (pass == walk->unique ||
399                 (!walk->unique && !strcmp(walk->label,label) && (walk->unique=pass)) ) {
400             memcpy(crcval, walk->crc, MAX_PW_CRC*sizeof(int));
401             return;
402         }
403     }
404     walk = alloc_t(PASSWORD);
405     if (!walk) die("Out of memory");
406     walk->next = pwsave;
407     pwsave = walk;
408     walk->unique = pass;
409     walk->label = stralloc(label);
410     
411     printf("\nEntry for  %s  used null password\n", label);
412     pass = pass2 = NULL;
413     do {
414         if (pass) {
415             printf("   *** Phrases don't match ***\n");
416             pw_wipe(pass);
417             pw_wipe(pass2);
418         }
419         printf("Type passphrase: ");
420         pass2 = pw_input();
421         printf("Please re-enter: ");
422         pass = pw_input();
423     } while (strcmp(pass,pass2));
424     printf("\n");
425     pw_wipe(pass2);  
426     hash_password(pass, walk->crc);
427     pw_wipe(pass);
428     memcpy(crcval, walk->crc, MAX_PW_CRC*sizeof(int));
429 }
430
431
432 static void retrieve_crc(int crcval[])
433 {
434     int i;
435     char *pass;
436     
437     if (!pwsave) {
438         if (cfg_pw_open()) pw_fill_cache();
439     }
440     pass = cfg_get_strg(cf_all,"password");
441     if (pass) pw_get(pass,crcval,0);
442     else pw_get(cfg_get_strg(cf_options,"password"),crcval,1);
443
444     if (verbose >= 2) {
445         printf("Password found is");
446         for (i=0; i<MAX_PW_CRC; i++) printf(" %08X", crcval[i]);
447         printf("\n");
448     }
449 }
450
451
452
453 static void open_bsect(char *boot_dev)
454 {
455     struct stat st;
456
457     if (verbose > 0)
458         printf("Reading boot sector from %s\n",boot_dev ? boot_dev :
459           "current root.");
460     boot_devnam = boot_dev;
461     if (!boot_dev || !strcmp(boot_dev, "/") ) {
462         if (stat("/",&st) < 0) pdie("stat /");
463         if (MAJOR(st.st_dev) != MAJOR_MD &&
464                 (st.st_dev & P_MASK(st.st_dev)) > PART_MAX)
465             die("Can't put the boot sector on logical partition 0x%04X",
466               (int)st.st_dev);
467         fd = dev_open(&dev,boot_dev_nr = st.st_dev,O_RDWR);
468         boot_devnam = dev.name;
469         use_dev_close = 1;
470     }
471     else {
472         if ((fd = open(boot_dev,O_RDWR)) < 0)
473             die("open %s: %s",boot_dev,strerror(errno));
474         if (fstat(fd,&st) < 0) die("stat %s: %s",boot_dev,strerror(errno));
475         if (!S_ISBLK(st.st_mode)) boot_dev_nr = 0;
476         else boot_dev_nr = st.st_rdev;
477     }
478 /* new code to get boot device code */
479 /* plus geo_open will trigger VolumeMgmt (pf_hard_disk_scan) before the
480    boot sector is actually read; timing is very important */
481 {
482     GEOMETRY geo;
483     geo_open(&geo, boot_devnam, O_RDONLY);
484     bios_boot = geo.device;
485     geo_close(&geo);
486 }
487     
488     if (boot_dev_nr && !is_first(boot_dev_nr) )
489         warn("%s is not on the first disk",boot_dev ?
490           boot_dev : "current root");
491     if (read(fd,(char *) &bsect,SECTOR_SIZE) != SECTOR_SIZE)
492         die("read %s: %s",boot_dev ? boot_dev : dev.name,strerror(errno));
493     bsect_orig = bsect;
494     ireloc = part_nowrite(boot_devnam);
495     if (ireloc == PTW_DOS + PTW_NTFS)  ireloc = PTW_DOS;
496 /* check for override (-F) command line flag */
497     if (ireloc>PTW_DOS && force_fs) {
498         int nowarn2 = nowarn;
499         nowarn = 0;
500
501         warn("'-F' override used. Filesystem on  %s  may be destroyed.", boot_devnam);
502         if (!yesno("\nProceed? ",0)) exit(0);
503
504         nowarn = nowarn2;
505         ireloc=PTW_OKAY;
506     }
507 }
508
509
510 void bsect_read(char *boot_dev,BOOT_SECTOR *buffer)
511 {
512     open_bsect(boot_dev);
513     *buffer = bsect;
514     (void) close(fd);
515 }
516
517
518 static void menu_do_scheme(char *scheme, MENUTABLE *menu)
519 {
520     static char khar[] = "kbgcrmywKBGCRMYW";
521     unsigned int fg, bg;
522     int i;
523     unsigned char *at;
524     /* order of color attributes is:
525           text, hilighted text, border, title
526     */
527 #define color(c) ((int)(strchr(khar,(int)(c))-khar))
528     bg = 0;
529     at = &(menu->at_text);
530     for (i=0; i<4 && *scheme; i++) {
531         fg = color(*scheme);
532         if (fg>=16) die("Invalid menu-scheme color: '%c'", *scheme);
533         if (*++scheme) bg = color(*scheme);
534         else {
535             die("Invalid menu-scheme syntax");
536         }
537         if (bg>=16) die("Invalid menu-scheme color: '%c'", *scheme);
538         if (*++scheme) {
539             if (ispunct(*scheme)) scheme++;
540             else die("Invalid menu-scheme punctuation");
541         }
542         if (bg>=8)
543             warn("menu-scheme BG color may not be intensified");
544         *at++ = ((bg<<4) | fg) & 0x7F;
545     }
546     /* check on the TEXT color */
547     if (menu->at_text == 0) {
548         warn("menu-scheme \"black on black\" changed to \"white on black\"");
549         menu->at_text = 0x07;
550     }
551     /* check on the HIGHLIGHT color */
552     if (menu->at_highlight == 0)  menu->at_highlight = ((menu->at_text<<4)&0x70) | ((menu->at_text>>4)&0x0f);
553     /* check on the BORDER color */
554     if (menu->at_border == 0)  menu->at_border = menu->at_text;
555     /* check on the TITLE color */
556     if (menu->at_title == 0)  menu->at_title = menu->at_border;
557     
558     strncpy(menu->menu_sig, "MENU", 4);
559     if (verbose>=5)
560        printf("Menu attributes: text %02X  highlight %02X  border %02X  title %02X\n",
561                 (int)menu->at_text, (int)menu->at_highlight,
562                 (int)menu->at_border, (int)menu->at_title);
563 #undef color
564 }
565
566
567 void bsect_open(char *boot_dev,char *map_file,char *install,int delay,
568   int timeout, int raid_offset)
569 {
570     static char coms[] = "0123";
571     static char parity[] = "NnOoEe";
572     static char bps[] = 
573         "110\000150\000300\000600\0001200\0002400\0004800\0009600\000"
574         "19200\00038400\00057600\000115200\000?\000?\000?\000?\000"
575         "56000\000";
576     GEOMETRY geo;
577     struct stat st;
578     int i, speed, bitmap, j, dataend;
579     int m_fd=0,kt_fd,sectors;
580     char *message,*colon,*serial,*walk,*this,*keytable,*scheme;
581     MENUTABLE *menu;
582     BITMAPFILEHEADER fhv;
583     BITMAPHEADER bmhv;
584     BITMAPLILOHEADER lhv;
585     unsigned int timestamp;
586 #ifdef LCF_BUILTIN
587     BUILTIN_FILE *loader;
588 #else
589     int i_fd;
590 #endif
591
592 #if 0
593 printf("sizeof(IMAGE_DESCR) = %d\n", sizeof(IMAGE_DESCR));
594 printf("sizeof(DESCR_SECTORS) = %d\n", sizeof(DESCR_SECTORS));
595 printf("MAX_IMAGES = %d\n", MAX_IMAGES);
596 #endif
597     image = image_base = i = 0;
598     memset(&menuparams, 0, sizeof(menuparams));
599     if (stat(map_file,&st) >= 0 && !S_ISREG(st.st_mode))
600         die("Map %s is not a regular file.",map_file);
601     open_bsect(boot_dev);
602     part_verify(boot_dev_nr,1);
603     if (ireloc>PTW_DOS) {
604         die("Filesystem would be destroyed by LILO boot sector: %s", boot_dev);
605     }
606     else if (ireloc==PTW_DOS) {
607         warn("boot record relocation beyond BPB is necessary: %s", boot_dev);
608     }
609
610 #ifdef EARLY_MAP
611     if ((colon = strrchr(map_name = map_file,':')) == NULL)
612         strcat(strcpy(temp_map,map_name),MAP_TMP_APP);
613     else {
614         *colon = 0;
615         strcat(strcat(strcpy(temp_map,map_name),MAP_TMP_APP),colon+1);
616         *colon = ':';
617     }
618     map_create(temp_map);
619     temp_register(temp_map);
620 #endif
621
622     if (!install) {
623 #if !defined(LCF_NOINSTDEF) || defined(LCF_BUILTIN)
624         install = DFL_BOOT;
625 #else
626         die("No boot loader specified ('-i' or 'install =')");
627 #endif
628     } 
629 /*  if (install) */ {
630         timestamp = bsect.par_1.timestamp; /* preserve timestamp */
631
632 /* determine which secondary loader to use */
633
634         loader = select_loader();
635         if (verbose > 0) {
636             printf("Using %s secondary loader\n",
637                 loader==&Bitmap ? "BITMAP" :
638                 loader==&Third  ? "MENU" :
639                 "TEXT" );
640         }
641         memcpy(&bsect, First.data, MAX_BOOT_SIZE);
642
643         bsect.par_1.timestamp = timestamp;
644         map_begin_section(); /* no access to the (not yet open) map file
645                 required, because this map is built in memory */
646         here2 = map_insert_data (loader->data, loader->size);
647         memcpy(&param2,loader->data,sizeof(param2));
648 #ifdef LCF_FIRST6
649         /* write just the 4 bytes (sa6==2) */
650         sectors = map_write((SECTOR_ADDR*)secondary_map, (SECTOR_SIZE-4)/sizeof(SECTOR_ADDR)-2, 1, 2);
651 #else
652         sectors = map_write((SECTOR_ADDR*)secondary_map, (SECTOR_SIZE-4)/sizeof(SECTOR_ADDR)-2, 1);
653 #endif
654         memcpy(secondary_map+SECTOR_SIZE-4, EX_MAG_STRING, 4);
655
656         /* fill in full size of secondary boot loader in paragraphs */
657         /*bsect.par_1.*/dataend = (sectors + 5 + (COMMAND_LINE_SIZE>256) + MAX_DESCR_SECS) * (SECTOR_SIZE/16);
658
659         if (verbose > 1)
660             printf("Secondary loader: %d sector%s (0x%0X dataend).\n",sectors,sectors == 1 ?
661               "" : "s", /*bsect.par_1.*/dataend*16);
662         stage_flags = ((BOOT_SECTOR*)(loader->data)) -> par_2.stage;
663         if ((stage_flags & 0xFF) != STAGE_SECOND)
664             die("Ill-formed boot loader; no second stage section");
665
666         if (verbose>=4) printf("install(2) flags: 0x%04X\n", (int)stage_flags);
667     }
668
669 #ifndef EARLY_MAP
670     if ((colon = strrchr(map_name = map_file,':')) == NULL)
671         strcat(strcpy(temp_map,map_name),MAP_TMP_APP);
672     else {
673         *colon = 0;
674         strcat(strcat(strcpy(temp_map,map_name),MAP_TMP_APP),colon+1);
675         *colon = ':';
676     }
677     map_create(temp_map);
678     temp_register(temp_map);
679 #endif
680
681         map_begin_section();
682         map_add_sector(secondary_map);
683 #ifdef LCF_FIRST6
684         /* write out six byte address */
685         (void) map_write(&bsect.par_1.secondary,1,0,1);
686 #else
687         (void) map_write(&bsect.par_1.secondary,1,0);
688 #endif
689
690 /* if the state of the BIOS is DL_GOOD, always mark when boot==map
691    if the state of the BIOS is < DL_GOOD, never mark */
692    
693         if ( bios_boot == bios_map  &&
694                 (bios_passes_dl == DL_GOOD
695                  || (do_md_install && !(extra==X_MBR_ONLY ))
696                   ) )
697             bsect.par_1.prompt |= FLAG_MAP_ON_BOOT;
698         if (bios_boot!=bios_map)
699             warn("The boot sector and map file are on different disks.");
700         if ( (bios_map & 0x80) && !do_md_install &&
701                 !cfg_get_flag(cf_options, "static-bios-codes") ) /* hard disk & not raid master */
702             bsect.par_1.map_serial_no = serial_no[bios_map - 0x80];
703         if (verbose>=2)
704             printf("bios_boot = 0x%02X  bios_map = 0x%02X  map==boot = %d  map S/N: %08X\n",
705                 bios_boot, bios_map,
706                 !!(bsect.par_1.prompt&FLAG_MAP_ON_BOOT),
707                 bsect.par_1.map_serial_no);
708     
709 /* code to get creation time of map file */
710     if (stat(temp_map, &st) < 0) die("Cannot get map file status");
711     param2.map_stamp = bsect.par_1.map_stamp = st.st_mtime;
712     if (verbose>=4) printf("Map time stamp: %08X\n", (int)bsect.par_1.map_stamp);
713
714     *(unsigned short *) &bsect.sector[BOOT_SIG_OFFSET] = BOOT_SIGNATURE;
715     message = cfg_get_strg(cf_options,"message");
716     scheme = cfg_get_strg(cf_options,"bitmap");
717     if (message && scheme) die("'bitmap' and 'message' are mutually exclusive");
718     param2.msg_len = 0;
719     bitmap = (loader==&Bitmap);
720     if (bitmap) {
721         message = scheme;
722         if (!(stage_flags & STAGE_FLAG_BMP4)) {
723             warn("Non-bitmap capable boot loader; 'bitmap=' ignored.");
724             message = NULL;
725         }
726     }
727     j = -1;
728     if (message) {
729         if (verbose >= 1) {
730             printf("Mapping %s file %s", 
731                         bitmap ? "bitmap" : "message", message);
732             show_link(message);
733             printf("\n");
734         }
735         m_fd = geo_open(&geo,message,O_RDONLY);
736         if (fstat(m_fd,&st) < 0) die("stat %s: %s",message,strerror(errno));
737         /* the -2 below is because of GCC's alignment requirements */
738         i = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPHEADER)+sizeof(RGB)*16+
739                                 sizeof(BITMAPLILOHEADER);
740         if (bitmap || st.st_size>i) {
741             int bits=0;
742             
743             j = get_std_headers(m_fd, &fhv, &bmhv, &lhv);
744             if (j<0) die("read %s: %s", message, strerror(errno));
745             if (j==0 || j>2) { /* definitely a bitmap file */
746                 BITMAPHEADER *bmh = &bmhv;
747                 if (verbose >= 3) {
748                     printf("width=%d height=%d planes=%d bits/plane=%d\n",
749                         (int)bmh->width, (int)bmh->height,
750                         (int)bmh->numBitPlanes, (int)bmh->numBitsPerPlane);
751                 }
752                 if (bmh->size == sizeof(BITMAPHEADER) &&
753                         bmh->width==640 && bmh->height==480 && 
754                         ((bits = bmh->numBitPlanes * bmh->numBitsPerPlane) == 4 ||
755                           bits == 8) ) {
756                     if (!bitmap) die("Message specifies a bitmap file");
757                     if (bits>4 && adapter<VIDEO_VESA)
758                         warn("Video adapter does not support VESA BIOS extensions needed for\n"
759                                        "  display of 256 colors.  Boot loader will fall back to TEXT only operation.");
760                 }
761                 else if (bitmap) die("Unsupported bitmap");
762             } else if (bitmap) die("Not a bitmap file");
763         }
764         i = bitmap ? MAX_KERNEL_SECS*SECTOR_SIZE : MAX_MESSAGE;
765         if (st.st_size > i)
766             die("%s is too big (> %d bytes)",message,i);
767         param2.msg_len = bitmap ? (st.st_size+15)/16 : st.st_size;
768         map_begin_section();
769 #ifndef LCF_UNIFY
770         map_add(&geo,0,((st.st_size)+SECTOR_SIZE-1)/SECTOR_SIZE);
771 #else
772         map_insert_file (&geo,0,(st.st_size+SECTOR_SIZE-1)/SECTOR_SIZE);
773 #endif
774         sectors = map_end_section(&menuparams.msg,0);
775         if (verbose >= 2)
776             printf("%s: %d sector%s.\n",bitmap?"Bitmap":"Message",
777                         sectors,sectors == 1 ?  "" : "s");
778         geo_close(&geo);
779     }
780
781     if (cfg_get_flag(cf_options,"el-torito-bootable-cd"))
782         param2.flag2 |= FLAG2_EL_TORITO;
783     if (cfg_get_flag(cf_options,"unattended")) {
784         param2.flag2 |= FLAG2_UNATTENDED;
785         if (timeout < 0) {
786             warn("UNATTENDED used; setting TIMEOUT to 20s (seconds).");
787             timeout = 200;
788         }
789     }
790         
791     serial = cfg_get_strg(cf_options,"serial");
792     if (serial) {
793         if (!(stage_flags & STAGE_FLAG_SERIAL))
794             die("Serial line not supported by boot loader");
795         if (!*serial || !(this = strchr(coms,*serial)))
796             die("Invalid serial port in \"%s\" (should be 0-3)",serial);
797         else param2.port = (this-coms)+1;
798         param2.ser_param = SER_DFL_PRM;
799         if (serial[1]) {
800             if (serial[1] != ',')
801                 die("Serial syntax is <port>[,<bps>[<parity>[<bits>]]]");
802             walk = bps;
803             speed = 0;
804             while (*walk && strncmp(serial+2,walk,(i=strlen(walk)))) {
805                 speed++;
806                 walk += i+1;
807             }
808             if (!*walk) die("Unsupported baud rate");
809             param2.ser_param &= ~0xE4;
810             if (speed==16) speed -= 6;  /* convert 56000 to 57600 */
811             param2.ser_param |= ((speed<<5) | (speed>>1)) & 0xE4;
812             serial += i+2;
813         /* check for parity specified */
814             if (*serial) {
815                 if (!(this = strchr(parity,*serial)))
816                     die("Serial speed = %s; valid parity values are N, O and E", walk);
817                 i = (int)(this-parity)>>1;
818                 if (i==2) i++; /* N=00, O=01, E=11 */
819                 param2.ser_param &= ~(i&1); /* 7 bits if parity specified */
820                 param2.ser_param |= i<<3;   /* specify parity */
821         /* check if number of bits is there */
822                 if (serial[1]) {
823                     if (serial[1] != '7' && serial[1] != '8')
824                         die("Only 7 or 8 bits supported");
825                     if (serial[1]=='7') param2.ser_param &= 0xFE;
826                     else param2.ser_param |= 0x01;
827                     
828                     if (serial[2]) die("Syntax error in SERIAL");
829                 }
830             }
831             if (verbose>=4) printf("Serial Param = 0x%02X\n", 
832                                                 (int)param2.ser_param);
833         }
834         if (delay < 20 && !cfg_get_flag(cf_options,"prompt")) {
835             warn("no PROMPT with SERIAL; setting DELAY to 20 (2 seconds)");
836             delay = 20;
837         }
838     }
839     bsect.par_1.prompt |= cfg_get_flag(cf_options,"prompt") ? FLAG_PROMPT : 0;
840     if (cfg_get_flag(cf_options,"suppress-boot-time-BIOS-data")) {
841         warn("boot-time BIOS data will not be saved.");
842         bsect.par_1.prompt |= FLAG_NOBD;
843     }
844     if (!fetch() && (bios_map &
845 #if VERSION_MINOR>=50
846                         bios_boot &       /* if 'boot=/dev/fd0', force write */
847 #endif
848                         0x80)) {
849                 bsect.par_1.prompt |= FLAG_BD_OKAY;
850                 if (verbose>=2)
851                         printf("BIOS data check was okay on the last boot\n");
852         }
853         else {
854                 if (verbose>=2)
855                         printf("BIOS data check will include auto-suppress check\n");
856         }
857         /* set to LARGEMEM only if 'large-memory' ist set AND 'small-memory is not set */
858     if (cfg_get_flag(cf_options,"large-memory")
859                         && !cfg_get_flag(cf_options,"small-memory")) {
860 #ifndef LCF_INITRDLOW
861                 bsect.par_1.prompt |= FLAG_LARGEMEM;
862 #else
863                 warn("This LILO is compiled with INITRDLOW option, 'large-memory' ignored.");
864 #endif
865     }
866         bsect.par_1.prompt |= raid_flags;
867         bsect.par_1.raid_offset = raid_offset;  /* to be modified in bsect_raid_update */
868
869 /* convert timeout in tenths of a second to clock ticks    */
870 /* tick interval is 54.925 ms  */
871 /*   54.925 * 40 -> 2197       */
872 /*  100 * 40 -> 4000           */
873 #if 0
874 #define tick(x) ((x)*100/55)
875 #else
876 #define tick(x) ((x)*4000/2197)
877 #endif
878     delay =  delay==36000 ? 0xffff : tick(delay);
879     if (delay > 0xffff) die("Maximum delay is 59:59 (3599.5secs).");
880         else param2.delay = delay;
881
882     timeout =  timeout==36000 ? 0xfffe : tick(timeout); /* -1 -> -1 ticks */
883     if (timeout == -1) param2.timeout = 0xffff;
884     else if (timeout >= 0xffff) die("Maximum timeout is 59:59 (3599.5secs).");
885         else param2.timeout = timeout;
886
887 /* keytable & parameter area setup */
888
889     if (!(keytable = cfg_get_strg(cf_options,"keytable"))) {
890         for (i = 0; i < 256; i++) table[i] = i;
891     }
892     else {
893         if ((kt_fd = open(keytable,O_RDONLY)) < 0)
894             die("open %s: %s",keytable,strerror(errno));
895         if (read(kt_fd,table,256) != 256)
896             die("%s: bad keyboard translation table",keytable);
897         (void) close(kt_fd);
898     }
899 #if 0
900     menu = (MENUTABLE*)&table[256];
901     memset(menu, 0, 256);
902 #else
903     menu = &menuparams;
904 #endif
905     memcpy(&(menu->row), &(lhv.row), sizeof(lhv) - sizeof(lhv.size) - sizeof(lhv.magic));
906
907     if ((scheme = cfg_get_strg(cf_options,"menu-scheme"))) {
908         if (!(stage_flags & STAGE_FLAG_MENU))
909             warn("'menu-scheme' not supported by boot loader");
910         menu_do_scheme(scheme, menu);
911     }
912     if ((scheme = cfg_get_strg(cf_options,"menu-title"))) {
913         if (!(stage_flags & STAGE_FLAG_MENU))
914             warn("'menu-title' not supported by boot loader");
915         if (strlen(scheme) > MAX_MENU_TITLE)
916             warn("menu-title is > %d characters", MAX_MENU_TITLE);
917         strncpy(menu->title, scheme, MAX_MENU_TITLE);
918         menu->len_title = strlen(menu->title);
919     }
920     if ((scheme = cfg_get_strg(cf_options,"bmp-table"))) {
921         if (!(stage_flags & STAGE_FLAG_BMP4))
922             warn("'bmp-table' not supported by boot loader");
923     }
924     bmp_do_table(scheme, menu);
925     if (bitmap) {
926         image_menu_space = menu->ncol * menu->maxcol;
927         if (verbose>=3) printf("image_menu_space = %d\n", image_menu_space);
928     }
929     if ((scheme = cfg_get_strg(cf_options,"bmp-colors"))) {
930         if (!(stage_flags & STAGE_FLAG_BMP4))
931             warn("'bmp-colors' not supported by boot loader");
932     }
933     bmp_do_colors(scheme, menu);
934     if ((scheme = cfg_get_strg(cf_options,"bmp-timer"))) {
935         if (!(stage_flags & STAGE_FLAG_BMP4))
936             warn("'bmp-timer' not supported by boot loader");
937     }
938     bmp_do_timer(scheme, menu);
939 #if 0
940     map_begin_section();
941     map_add_sector(table);
942     (void) map_write(&param2.keytab,1,0);
943 #endif
944     memset(&descrs,0,SECTOR_SIZE*MAX_DESCR_SECS);
945     if (cfg_get_strg(cf_options,"default")) image = image_base = 1;
946     if (verbose > 0) printf("\n");
947 }
948
949
950 static int dev_number(char *dev)
951 {
952     struct stat st;
953
954     if (stat(dev,&st) >= 0) return st.st_rdev;
955     if (!isdigit(*dev)) die("Illegal 'root=' specification: %s", dev);
956     if (verbose >= 1) 
957         printf("Warning: cannot 'stat' device \"%s\"; trying numerical conversion\n", dev);
958     return to_number(dev);
959 }
960
961
962 static int get_image(char *name,char *label,IMAGE_DESCR *descr)
963 {
964     char *here,*deflt,*tmp;
965     int this_image,other,label_is_name=0;
966     unsigned char *uch;
967
968     if (!label) {
969
970         here = strrchr(label = name,'/');
971         if (here)
972         {
973             label_is_name = 1;
974             label = here+1;
975         }
976     }
977     if (label_is_name)
978     {
979         if (strchr(label,' ')) die("Image name, (which is actually the name) contains a blank character: '%s'", label);
980     }
981     if (!label_is_name)
982     {
983         tmp = label;
984         while (*tmp)
985         {
986             if (*tmp == ' ')
987                     *tmp = '_';
988             *tmp++;
989         }
990     } 
991     if (strlen(label) > MAX_IMAGE_NAME) die("Image name, label, or alias is too long: '%s'",label);
992     for (uch=(unsigned char*)label; *uch; uch++) {
993         if (*uch<' ')  die("Image name, label, or alias contains an illegal character: '%s'", label);
994     }
995     for (other = image_base; other <= image; other++) {
996 #ifdef LCF_IGNORECASE
997         if (!strcasecmp(label,descrs.d.descr[other].name))
998 #else
999         if (!strcmp(label,descrs.d.descr[other].name))
1000 #endif
1001             die("Duplicate label \"%s\"",label);
1002         if ((((descr->flags & FLAG_SINGLE) && strlen(label) == 1) ||
1003           (((descrs.d.descr[other].flags) & FLAG_SINGLE) &&
1004           strlen(descrs.d.descr[other].name) == 1)) &&
1005 #ifdef LCF_IGNORECASE
1006           toupper(*label) == toupper(*descrs.d.descr[other].name))
1007 #else
1008           *label == *descrs.d.descr[other].name)
1009 #endif
1010             die("Single-key clash: \"%s\" vs. \"%s\"",label,
1011               descrs.d.descr[other].name);
1012     }
1013
1014     if (image_base && (deflt = cfg_get_strg(cf_options,"default")) &&
1015 #ifdef LCF_IGNORECASE
1016       !strcasecmp(deflt,label))
1017 #else
1018       !strcmp(deflt,label))
1019 #endif
1020         this_image = image_base = 0;
1021     else {
1022         if (image == MAX_IMAGES)
1023             die("Only %d image names can be defined",MAX_IMAGES);
1024         if (image >= image_menu_space)
1025             die("Bitmap table has space for only %d images",
1026                                 image_menu_space);
1027         this_image = image++;
1028     }
1029     descrs.d.descr[this_image] = *descr;
1030     strcpy(descrs.d.descr[this_image].name,label);
1031
1032 #ifdef LCF_VIRTUAL
1033     if ( (deflt = cfg_get_strg(cf_options,"vmdefault")) &&
1034 #ifdef LCF_IGNORECASE
1035                 !strcasecmp(deflt,label))  {
1036 #else
1037                 !strcmp(deflt,label))  {
1038 #endif
1039         descrs.d.descr[this_image].flags |= FLAG_VMDEFAULT;
1040         param2.flag2 |= FLAG2_VIRTUAL;
1041         }
1042 #endif
1043
1044 #ifdef LCF_NOKEYBOARD
1045     if ( (deflt = cfg_get_strg(cf_options,"nokbdefault")) &&
1046 #ifdef LCF_IGNORECASE
1047                 !strcasecmp(deflt,label))  {
1048 #else
1049                 !strcmp(deflt,label))  {
1050 #endif
1051         descrs.d.descr[this_image].flags |= FLAG_NOKBDEFAULT;
1052         param2.flag2 |= FLAG2_NOKBD;
1053         }
1054 #endif
1055
1056     return this_image;
1057 }
1058
1059
1060 static char options[SECTOR_SIZE]; /* this is ugly */
1061
1062
1063 static void bsect_common(IMAGE_DESCR *descr, int image)
1064 {
1065     struct stat st;
1066     char *here,*root,*ram_disk,*vga,*password;
1067     char *literal,*append,*fback;
1068     char fallback_buf[SECTOR_SIZE];
1069
1070     memset(descr, 0, sizeof(IMAGE_DESCR));      /* allocated on stack by caller */
1071     memset(fallback_buf,0,SECTOR_SIZE);
1072     memset(options,0,SECTOR_SIZE);
1073     
1074 if (image) { /* long section specific to 'image=' */
1075     char *append_local;
1076     
1077     if ((cfg_get_flag(cf_kernel,"read-only") && cfg_get_flag(cf_kernel,
1078       "read-write")) || (cfg_get_flag(cf_options,"read-only") && cfg_get_flag(
1079       cf_options,"read-write")))
1080         die("Conflicting READONLY and READ_WRITE settings.");
1081
1082     if (cfg_get_flag(cf_kernel,"read-only") || cfg_get_flag(cf_options,
1083       "read-only")) strcat(options,"ro ");
1084     if (cfg_get_flag(cf_kernel,"read-write") || cfg_get_flag(cf_options,
1085       "read-write")) strcat(options,"rw ");
1086     if ((root = cfg_get_strg(cf_kernel,"root")) || (root = cfg_get_strg(
1087       cf_options,"root")))  {
1088         if (!strcasecmp(root,"current")) {
1089             if (stat("/",&st) < 0) pdie("stat /");
1090             sprintf(strchr(options,0),"root=%x ",(unsigned int) st.st_dev);
1091         }
1092         else if (strlen(root)>12 && !strncmp(root,"/dev/mapper/",12)) {
1093             sprintf(strchr(options,0),"root=%s ", root);
1094         }
1095         else if (strlen(root)>6 && !strncmp(root,"LABEL=",6)) {
1096             sprintf(strchr(options,0),"root=%s ", root);
1097         }
1098         else if (strlen(root)>5 && !strncmp(root,"UUID=",5)) {
1099             sprintf(strchr(options,0),"root=%s ", root);
1100         }
1101         else {
1102             sprintf(strchr(options,0),"root=%x ",dev_number(root));
1103         }
1104       } 
1105     if ((ram_disk = cfg_get_strg(cf_kernel,"ramdisk")) || (ram_disk =
1106       cfg_get_strg(cf_options,"ramdisk")))
1107         sprintf(strchr(options,0),"ramdisk=%d ",to_number(ram_disk));
1108
1109     if ((vga = cfg_get_strg(cf_kernel,"vga")) || (vga = cfg_get_strg(cf_options,
1110       "vga"))) {
1111 #ifndef NORMAL_VGA
1112         warn("VGA mode presetting is not supported; ignoring 'vga='");
1113 #else
1114         descr->flags |= FLAG_VGA;
1115              if (!strcasecmp(vga,"normal")) descr->vga_mode = NORMAL_VGA;
1116         else if (!strcasecmp(vga,"ext") || !strcasecmp(vga,"extended"))
1117                 descr->vga_mode = EXTENDED_VGA;
1118         else if (!strcasecmp(vga,"ask")) descr->vga_mode = ASK_VGA;
1119         else descr->vga_mode = to_number(vga);
1120 #endif
1121     }
1122
1123 #ifdef LCF_BOOT_FILE
1124     if ((append = cfg_get_strg(cf_top, "image"))) {
1125         strcat(options, "BOOT_FILE=");
1126         strcat(options, append);
1127         strcat(options, " ");
1128     }
1129 #endif
1130     append_local = cfg_get_strg(cf_options,"append");   /* global, actually */
1131     if ((append = cfg_get_strg(cf_kernel,"append")) ||
1132         (append = append_local)  ) {
1133                 if (strlen(append) > COMMAND_LINE_SIZE-1) die("Command line options > %d", COMMAND_LINE_SIZE-1);
1134                 strcat(strcat(options,append)," ");
1135     }
1136
1137 #if 1
1138     append = append_local;      /* append == global append */
1139     if ((append_local = cfg_get_strg(cf_kernel,"addappend"))) {
1140         if (!append)
1141             warn("ADDAPPEND used without global APPEND");
1142         if (strlen(options)+strlen(append_local) > SECTOR_SIZE-1) die("Command line options > %d", COMMAND_LINE_SIZE-1);
1143         strcat(options,append_local);
1144     }
1145 #endif
1146
1147 } /* end of section specific to 'image=' */
1148
1149     literal = cfg_get_strg(cf_kernel,"literal");
1150     if (literal) strcpy(options,literal);
1151     if (*options) {
1152         here = strchr(options,0);
1153         if (here[-1] == ' ') here[-1] = 0;
1154     }
1155     check_options(options);
1156
1157     if (cfg_get_flag(cf_kernel,"lock") || cfg_get_flag(cf_options,"lock")) {
1158 #ifdef LCF_READONLY
1159         die("This LILO is compiled READONLY and doesn't support the LOCK "
1160           "option");
1161 #else
1162         descr->flags |= FLAG_LOCK;
1163 #endif
1164     }
1165
1166     if ((cfg_get_flag(cf_options,"restricted") && 
1167              cfg_get_flag(cf_options,"mandatory")) ||
1168         (cfg_get_flag(cf_all,"restricted") && 
1169              cfg_get_flag(cf_all,"mandatory")))
1170          die("MANDATORY and RESTRICTED are mutually exclusive");
1171     if (cfg_get_flag(cf_all,"bypass")) {
1172         if (cfg_get_flag(cf_all,"mandatory"))
1173              die("MANDATORY and BYPASS are mutually exclusive");
1174         if (cfg_get_flag(cf_all,"restricted"))
1175              die("RESTRICTED and BYPASS are mutually exclusive");
1176         if (!cfg_get_strg(cf_options,"password"))
1177              die("BYPASS only valid if global PASSWORD is set");
1178     }
1179     if ((password = cfg_get_strg(cf_all,"password")) && cfg_get_flag(cf_all,"bypass"))
1180         die("PASSWORD and BYPASS not valid together");
1181     if (password || 
1182         ( (password = cfg_get_strg(cf_options,"password")) &&
1183           !cfg_get_flag(cf_all,"bypass")  ) ) {
1184         if (!*password) {       /* null password triggers interaction */
1185             retrieve_crc((int*)descr->password_crc);
1186         } else {
1187             hash_password(password, (int*)descr->password_crc );
1188         }
1189         descr->flags |= FLAG_PASSWORD;
1190     }
1191
1192 #ifdef LCF_VIRTUAL
1193     if (cfg_get_flag(cf_all,"vmwarn")) {
1194         descr->flags |= FLAG_VMWARN;
1195         param2.flag2 |= FLAG2_VIRTUAL;
1196     }
1197     if (cfg_get_flag(cf_all,"vmdisable")) {
1198         descr->flags |= FLAG_VMDISABLE;
1199         param2.flag2 |= FLAG2_VIRTUAL;
1200     }
1201     if ( (descr->flags & FLAG_VMWARN) && (descr->flags & FLAG_VMDISABLE) )
1202         die ("VMWARN and VMDISABLE are not valid together");
1203 #endif
1204 #ifdef LCF_NOKEYBOARD
1205     if (cfg_get_flag(cf_all,"nokbdisable")) {
1206         descr->flags |= FLAG_NOKBDISABLE;
1207         param2.flag2 |= FLAG2_NOKBD;
1208     }
1209 #endif
1210
1211 #if 1
1212     if (cfg_get_flag(cf_all,"mandatory") || cfg_get_flag(cf_options,
1213       "mandatory")) {
1214         if (!password) die("MANDATORY is only valid if PASSWORD is set.");
1215     }
1216     if (cfg_get_flag(cf_all,"restricted") || cfg_get_flag(cf_options,
1217       "restricted")) {
1218         if (!password) die("RESTRICTED is only valid if PASSWORD is set.");
1219         if ((descr->flags & FLAG_PASSWORD) && !cfg_get_flag(cf_all,"mandatory"))
1220             descr->flags |= FLAG_RESTR;
1221     }
1222     if (password && *password && config_read) {
1223         warn("%s should be readable only "
1224           "for root if using PASSWORD", config_file);
1225         config_read = 0;        /* suppress further warnings */
1226     }
1227 #else
1228     if (cfg_get_flag(cf_all,"restricted") || cfg_get_flag(cf_options,
1229       "restricted")) {
1230         if (!password) die("RESTRICTED is only valid if PASSWORD is set.");
1231         descr->flags |= FLAG_RESTR;
1232     }
1233 #endif
1234     if (cfg_get_flag(cf_all,"bmp-retain") ||
1235       cfg_get_flag(cf_options,"bmp-retain")) descr->flags |= FLAG_RETAIN;
1236
1237     if (cfg_get_flag(cf_all,"single-key") ||
1238       cfg_get_flag(cf_options,"single-key")) descr->flags |= FLAG_SINGLE;
1239
1240     fback = cfg_get_strg(cf_kernel,"fallback");
1241     if (fback) {
1242 #ifdef LCF_READONLY
1243         die("This LILO is compiled READONLY and doesn't support the FALLBACK "
1244           "option");
1245 #else
1246         if (descr->flags & FLAG_LOCK)
1247             die("LOCK and FALLBACK are mutually exclusive");
1248         else descr->flags |= FLAG_FALLBACK;
1249         *(unsigned short *) fallback_buf = DC_MAGIC;
1250         strcpy(fallback_buf+2,fback);
1251         fallback[fallbacks++] = stralloc(fback);
1252 #endif
1253     }
1254 #if 0
1255 #if 1
1256     *(unsigned int *) descr->rd_size = 0; /* no RAM disk */
1257 #else
1258     descr->rd_size = 0; /* no RAM disk */
1259 #endif
1260     descr->start_page = 0; /* load low */
1261 #endif
1262     map_begin_section();
1263     map_add_sector(fallback_buf);
1264     map_add_sector(options);
1265 }
1266
1267
1268 static void bsect_done(char *name,IMAGE_DESCR *descr)
1269 {
1270     char *alias;
1271     int this_image,this;
1272
1273     if (!*name) die("Invalid image name.");
1274     alias = cfg_get_strg(cf_all,"alias");
1275     this = alias ? get_image(NULL,alias,descr) : -1;
1276     this_image = get_image(name,cfg_get_strg(cf_all,"label"),descr);
1277     if ((descr->flags & FLAG_SINGLE) &&
1278       strlen(descrs.d.descr[this_image].name) > 1 &&
1279       (!alias || strlen(alias) > 1))
1280         die("SINGLE-KEYSTROKE requires the label or the alias to be only "
1281           "a single character");
1282     if (verbose >= 0) {
1283         printf("Added %s",descrs.d.descr[this_image].name);
1284         if (alias) printf(" (alias %s)",alias);
1285 #ifdef LCF_VIRTUAL
1286         if (descrs.d.descr[this_image].flags & FLAG_VMDEFAULT ||
1287                 (this>=0 && (descrs.d.descr[this].flags & FLAG_VMDEFAULT)) )
1288             printf("  @");
1289 #endif
1290 #ifdef LCF_NOKEYBOARD
1291         if (descrs.d.descr[this_image].flags & FLAG_NOKBDEFAULT ||
1292                 (this>=0 && (descrs.d.descr[this].flags & FLAG_NOKBDEFAULT)) )
1293             printf("  &");
1294 #endif
1295         if ( descrs.d.descr[this_image].flags & FLAG_TOOBIG ||
1296                 (this>=0 && (descrs.d.descr[this].flags & FLAG_TOOBIG)) ) {
1297                 /* show a question mark if small-memory is configured */
1298 #ifndef LCF_INITRDLOW
1299                 if (!cfg_get_flag(cf_options,"small-memory")) 
1300                         printf("  +");
1301                 else
1302 #endif
1303                 printf("  ?");
1304         }
1305         /* here the default boot image can be set */
1306         if (this_image && this) putchar('\n');
1307         else printf("  *\n");
1308     }
1309     if (verbose >= 3) {
1310         printf("%4s<dev=0x%02x,hd=%d,cyl=%d,sct=%d>\n","",
1311           descr->start.device,
1312           descr->start.head,
1313           descr->start.track,
1314           descr->start.sector);
1315         if (*options) printf("%4s\"%s\"\n","",options);
1316     }
1317     if (verbose >= 1) putchar('\n');   /* makes for nicer spacing */
1318 }
1319
1320
1321 int bsect_number(void)
1322 {
1323  /* -1 means default= did not exist */
1324     return image_base ? -1 : image;
1325 }
1326
1327
1328 static void unbootable(void)
1329 {
1330 #if 0
1331     fflush(stdout);
1332     fprintf(errstd,"\nCAUTION: The system is unbootable !\n");
1333     fprintf(errstd,"%9sRun LILO again to correct this.","");
1334 #else
1335     warn("The system is unbootable !\n"
1336           "\t Run LILO again to correct this.");
1337 #endif    
1338 }
1339
1340
1341 #ifdef LCF_VIRTUAL
1342 void check_vmdefault(void)
1343 {
1344     char * deflt;
1345     int i;
1346     
1347     if ( (deflt = cfg_get_strg(cf_options,"vmdefault")) ) {
1348         for (i=0; i<image; ++i) {
1349             if (descrs.d.descr[i].flags & FLAG_VMDEFAULT) {
1350                 if (descrs.d.descr[i].flags & FLAG_VMDISABLE)
1351                     die("VMDEFAULT image cannot have VMDISABLE flag set");
1352
1353                 return;
1354             }
1355         }
1356         die("VMDEFAULT image does not exist.");
1357     }
1358 }
1359 #endif
1360
1361 #ifdef LCF_NOKEYBOARD
1362 void check_nokbdefault(void)
1363 {
1364     char * deflt;
1365     int i;
1366     
1367     if ( (deflt = cfg_get_strg(cf_options,"nokbdefault")) ) {
1368         for (i=0; i<image; ++i) {
1369             if (descrs.d.descr[i].flags & FLAG_NOKBDEFAULT) {
1370                 if (descrs.d.descr[i].flags & FLAG_NOKBDISABLE)
1371                     die("NOKBDEFAULT image cannot have NOKBDISABLE flag set");
1372
1373                 return;
1374             }
1375         }
1376         die("NOKBDEFAULT image does not exist.");
1377     }
1378 }
1379 #endif
1380
1381
1382 void check_fallback(void)
1383 {
1384     char *start,*end;
1385     int i,image;
1386
1387     for (i = 0; i < fallbacks; i++) {
1388         for (start = fallback[i]; *start && *start == ' '; start++);
1389         if (*start) {
1390             for (end = start; *end && *end != ' '; end++);
1391             if (*end) *end = 0;
1392             for (image = 0; image < MAX_IMAGES; image++)
1393 #ifdef LCF_IGNORECASE
1394                 if (!strcasecmp(descrs.d.descr[image].name,start)) break;
1395 #else
1396                 if (!strcmp(descrs.d.descr[image].name,start)) break;
1397 #endif
1398             if (image == MAX_IMAGES) die("No image \"%s\" is defined",start);
1399         }
1400     }
1401 }
1402
1403 void check_unattended(void)
1404 {
1405     if ( (descrs.d.descr[0].flags & (FLAG_PASSWORD + FLAG_RESTR) )
1406                                                         == FLAG_PASSWORD
1407                 &&  cfg_get_flag(cf_options,"unattended") )
1408         die("Mandatory PASSWORD on default=\"%s\" defeats UNATTENDED",
1409                 descrs.d.descr[0].name);
1410 }
1411
1412
1413 void bsect_update(char *backup_file, int force_backup, int pass)
1414 {
1415     BOOT_SECTOR bsect_wr;
1416     int temp;
1417 static int timestamp = 0;
1418
1419     if (pass>=0) {
1420         temp = make_backup(backup_file, force_backup, &bsect_orig,
1421                                                 boot_dev_nr, "boot sector");
1422         if (temp && !timestamp) bsect.par_1.timestamp = timestamp = temp;
1423     }
1424
1425 #ifndef LCF_UNIFY
1426 # error "Bios Translation algorithms require '-DUNIFY' in Makefile"
1427 #endif
1428     if (pass<1) {       /* BIOS_TT logic */
1429         MENUTABLE *menu = &menuparams;
1430         map_descrs(&descrs, menu->mt_descr, &menuparams.dflcmd);
1431         menuparams.raid_dev_mask = raid_mask((int*)menuparams.raid_offset);
1432         memcpy(menuparams.serial_no, serial_no, sizeof(serial_no));
1433         memcpy(table+256, &menuparams, sizeof(menuparams));
1434         ((int*)table)[SECTOR_SIZE/sizeof(int)-2] = crc32(table, SECTOR_SIZE-2*sizeof(int), CRC_POLY1);
1435         map_begin_section();
1436         map_add_sector(table);
1437 #ifdef LCF_FIRST6
1438         /* still use 5 byte address */
1439         (void) map_write(&param2.keytab,1,0,0);
1440 #else
1441         (void) map_write(&param2.keytab,1,0);
1442 #endif
1443         map_close(&param2, here2);
1444     }   /* if (pass<1) ...      */
1445
1446 if (pass>=0) {
1447     if (lseek(fd,0,SEEK_SET) < 0)
1448         die("lseek %s: %s",
1449                 boot_devnam ? boot_devnam : dev.name,
1450                 strerror(errno));
1451
1452 #if 1
1453     if (ireloc &&
1454           bsect.par_1.cli == 0xFA
1455                                                          ) {
1456 /* perform the relocation of the boot sector */
1457         int len = bsect.par_1.code_length;
1458         int space = BOOT_SIG_OFFSET - len;
1459         
1460         if (len==0) die ("First stage loader is not relocatable.");
1461         
1462         space &= 0xFFF0;        /* roll back to paragraph boundary */
1463         bsect_wr = bsect_orig;
1464         memcpy(&bsect_wr.sector[space], &bsect, len);
1465         if (space <= 0x80) {
1466             bsect_wr.sector[0] = 0xEB;          /* jmp short */
1467             bsect_wr.sector[1] = space - 2;
1468             bsect_wr.sector[2] = 0x90;          /* nop */
1469         } else {
1470             bsect_wr.sector[0] = 0xE9;          /* jmp near */
1471             *(short*)&bsect_wr.sector[1] = space - 3;
1472         }
1473         if (bsect_wr.sector[space+1] == 0xEB)   {  /* jmp short */
1474             len = space>>4;
1475             space += (signed)bsect_wr.sector[space+2] + 3;
1476             if (bsect_wr.sector[space] == 0xB8) /* mov ax,#07C0 */
1477                 *(short*)&bsect_wr.sector[space+1] += len;
1478         }
1479 /***    bsect = bsect_orig;  ***/
1480         if (verbose >= 1) printf("Boot sector relocation performed\n");
1481     }
1482     else bsect_wr = bsect;
1483 #endif          
1484
1485  /* failsafe check */
1486 #if 1
1487     if (verbose >= 3) {
1488         printf("Failsafe check:  boot_dev_nr = 0x%04x 0x%04x\n", boot_dev_nr, has_partitions(boot_dev_nr));
1489         /*** if (do_md_install) ***/ {
1490             printf("map==boot = %d    map s/n = %08X\n",
1491                 !!(bsect_wr.par_1.prompt & FLAG_MAP_ON_BOOT),
1492                 bsect_wr.par_1.map_serial_no
1493             );
1494         }
1495     }
1496 #endif
1497     if (
1498       has_partitions(boot_dev_nr) &&
1499       (P_MASK(boot_dev_nr)&boot_dev_nr)==0 &&
1500       memcmp(bsect.sector+MAX_BOOT_SIZE, bsect_wr.sector+MAX_BOOT_SIZE, 64+8)
1501       )
1502         die("LILO internal error:  Would overwrite Partition Table");
1503  /* failsafe check */
1504         
1505     sync();             /* this may solve possible kernel buffer problem */
1506         
1507     if (!test && write(fd, (char *)&bsect_wr, SECTOR_SIZE) != SECTOR_SIZE)
1508         die("write %s: %s",boot_devnam ? boot_devnam : dev.name,
1509           strerror(errno));
1510
1511 } /* if (pass>=0) ... */
1512
1513     if (use_dev_close) dev_close(&dev);
1514     else if (close(fd) < 0) {
1515             unbootable();
1516             die("close %s: %s",boot_devnam,strerror(errno));
1517         }
1518
1519 #if 0
1520     if (pass==0) {
1521 #else
1522     if (pass<1) {
1523 #endif
1524         pw_file_update(passw);
1525         temp_unregister(temp_map);
1526         if (rename(temp_map,map_name) < 0) {
1527             unbootable();
1528             die("rename %s %s: %s",temp_map,map_name,strerror(errno));
1529         }
1530     }
1531 /*  (void) sync();   Now handled in lilo.c (atexit(sync)) */
1532         if (verbose>=6) printf("End  bsect_update\n");
1533         fflush(stdout);
1534 }
1535
1536
1537 void bsect_cancel(void)
1538 {
1539 #if 0
1540     map_descrs(&descrs, bsect.par_1.descr, &bsect.par_1.dflcmd);
1541 #endif
1542     map_close(NULL,0);
1543     if (!use_dev_close) (void) close(fd);
1544     else dev_close(&dev);
1545     temp_unregister(temp_map);
1546     if (verbose<9) (void) remove(temp_map);
1547 }
1548
1549
1550 static int present(char *var)
1551 {
1552     char *path;
1553
1554     if (!(path = cfg_get_strg(cf_top,var))) die("No variable \"%s\"",var);
1555     if (!access(path,F_OK)) return 1;
1556     if (!cfg_get_flag(cf_all,"optional") && !cfg_get_flag(cf_options,
1557       "optional")) return 1;
1558     if (verbose >= 0) printf("Skipping %s\n",path);
1559     return 0;
1560 }
1561
1562
1563 static int initrd_present(void)
1564 {
1565     char *path;
1566
1567     path = cfg_get_strg(cf_kernel, "initrd");
1568     if (!path) path = cfg_get_strg(cf_options, "initrd");
1569     if (!path) return 1;
1570     if (!access(path,F_OK)) return 1;
1571     if (!cfg_get_flag(cf_all,"optional") && !cfg_get_flag(cf_options,
1572       "optional")) return 1;
1573     if (verbose >= 0) printf("Skipping %s\n", cfg_get_strg(cf_top, "image"));
1574     return 0;
1575 }
1576
1577
1578 void do_image(void)
1579 {
1580     IMAGE_DESCR descr;
1581     char *name;
1582
1583 /*    memset(&descr, 0, sizeof(descr));         Done in "bsect_common" */
1584     cfg_init(cf_image);
1585     (void) cfg_parse(cf_image);
1586     if (present("image") && initrd_present()) {
1587         bsect_common(&descr, 1);
1588         descr.flags |= FLAG_KERNEL;
1589         name = cfg_get_strg(cf_top,"image");
1590         if (!cfg_get_strg(cf_image,"range")) boot_image(name,&descr);
1591         else boot_device(name,cfg_get_strg(cf_image,"range"),&descr);
1592         bsect_done(name,&descr);
1593     }
1594     cfg_init(cf_top);
1595 }
1596
1597
1598 void do_other(void)
1599 {
1600     IMAGE_DESCR descr;
1601     char *name, *loader;
1602
1603 /*    memset(&descr, 0, sizeof(descr));         Done in "bsect_common" */
1604     cfg_init(cf_other);
1605     cfg_init(cf_kernel); /* clear kernel parameters */
1606     curr_drv_map = curr_prt_map = 0;
1607     (void) cfg_parse(cf_other);
1608     if (present("other")) {
1609         bsect_common(&descr, 0);
1610         name = cfg_get_strg(cf_top,"other");
1611         loader = cfg_get_strg(cf_other,"loader");
1612         if (!loader) loader = cfg_get_strg(cf_options,"loader");
1613         boot_other(loader,name,cfg_get_strg(cf_other,"table"),&descr);
1614         bsect_done(name,&descr);
1615     }
1616     cfg_init(cf_top);
1617 }
1618
1619
1620 void bsect_uninstall(char *boot_dev,char *backup_file,int validate)
1621 {
1622     struct stat st;
1623     char temp_name[PATH_MAX+1];
1624     int bck_file;
1625
1626     open_bsect(boot_dev);
1627     if (*(unsigned short *) &bsect.sector[BOOT_SIG_OFFSET] != BOOT_SIGNATURE)
1628         die("Boot sector of %s does not have a boot signature",boot_dev ?
1629           boot_dev : dev.name);
1630     if (!strncmp(bsect.par_1.signature-4,"LILO",4))
1631         die("Boot sector of %s has a pre-21 LILO signature",boot_dev ?
1632           boot_dev : dev.name);
1633     if (strncmp(bsect.par_1.signature,"LILO",4))
1634         die("Boot sector of %s doesn't have a LILO signature",boot_dev ?
1635           boot_dev : dev.name);
1636     if (!backup_file) {
1637         sprintf(temp_name,BACKUP_DIR "/boot.%04X",boot_dev_nr);
1638         backup_file = temp_name;
1639     }
1640     if ((bck_file = open(backup_file,O_RDONLY)) < 0)
1641         die("open %s: %s",backup_file,strerror(errno));
1642     if (fstat(bck_file,&st) < 0)
1643         die("fstat %s: %s",backup_file,strerror(errno));
1644     if (validate && st.st_mtime != bsect.par_1.timestamp)
1645         die("Timestamp in boot sector of %s differs from date of %s\n"
1646           "Try using the -U option if you know what you're doing.",boot_dev ?
1647           boot_dev : dev.name,backup_file);
1648     if (verbose > 0) printf("Reading old boot sector.\n");
1649     if (read(bck_file,(char *) &bsect,PART_TABLE_OFFSET) != PART_TABLE_OFFSET)
1650         die("read %s: %s",backup_file,strerror(errno));
1651     if (lseek(fd,0,SEEK_SET) < 0)
1652         die("lseek %s: %s",boot_dev ? boot_dev : dev.name,strerror(errno));
1653     if (verbose > 0) printf("Restoring old boot sector.\n");
1654     if (write(fd,(char *) &bsect,PART_TABLE_OFFSET) != PART_TABLE_OFFSET)
1655         die("write %s: %s",boot_dev ? boot_dev : dev.name,strerror(errno));
1656     if (use_dev_close) dev_close(&dev);
1657     else if (close(fd) < 0) {
1658             unbootable();
1659             die("close %s: %s",boot_devnam,strerror(errno));
1660         }
1661     exit(0);
1662 }
1663
1664
1665 void bsect_raid_update(char *boot_dev, unsigned int raid_offset, 
1666         char *backup_file, int force_backup, int pass, int mask)
1667 {
1668     BOOT_SECTOR bsect_save;
1669     int bios;
1670     int prompt = bsect.par_1.prompt;
1671
1672     if (pass<0) bsect_update(backup_file, force_backup, pass);
1673
1674     if (pass != 0) {    
1675         bsect_save = bsect;                     /* save the generated boot sector */
1676         open_bsect(boot_dev);
1677         memcpy(&bsect, &bsect_save, MAX_BOOT_SIZE);     /* update the subject boot sector */
1678         bsect.par_1.raid_offset = raid_offset;  /* put in the new partition offset */
1679         bsect.par_1.prompt &= mask;             /* clear all RAID flags */
1680         bsect.par_1.prompt |= raid_flags;       /* update the raid flags */
1681
1682         bios = (raid_flags&FLAG_RAID_DEFEAT) ? bios_map : bios_boot;
1683         if (!cfg_get_flag(cf_options, "static-bios-codes")) {
1684             if (verbose>=2) printf("Using s/n from device 0x%02X\n", bios);
1685             bsect.par_1.map_serial_no = serial_no[bios - 0x80];
1686         }
1687
1688 #ifdef LCF_FIRST6
1689 /* lines added 22.5.7 */
1690         ((SECTOR_ADDR6*)&bsect.par_1.secondary)->device = bios;
1691 #else
1692 /* lines added 22.5.6 */
1693         bsect.par_1.secondary.device &= ~DEV_MASK;
1694         bsect.par_1.secondary.device |= bios;
1695 #endif
1696 /* ************************************ */
1697
1698         *(unsigned short *) &bsect.sector[BOOT_SIG_OFFSET] = BOOT_SIGNATURE;
1699     }
1700     
1701     if (pass<0) pass = -pass;
1702     
1703     bsect_update(backup_file, force_backup, pass);
1704
1705     bsect.par_1.prompt = prompt;        /* restore the flag byte */
1706 }
1707
1708