459851af42b47f9704b3d1f0b30410b96b533aed
[rrq/maintain_lilo.git] / src / device.c
1 /* device.c  -  Device access
2  * 
3  * Copyright 1992-1997 Werner Almesberger
4  * Copyright 1999-2006 John Coffman
5  * Copyright 2009-2014 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 <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <dirent.h>
20 #include <limits.h>
21 #include <time.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25
26 #include "config.h"
27 #include "lilo.h"
28 #include "common.h"
29 #include "temp.h"
30 #include "device.h"
31 #include "geometry.h"
32 #include "partition.h"
33 #include "cfg.h"
34 #include "probe.h"
35 #include "md-int.h"
36
37
38 typedef struct _cache_entry {
39     const char *name;
40     int number;
41     struct _cache_entry *next;
42 } CACHE_ENTRY;
43
44 typedef struct _st_buf {
45     struct _st_buf *next;
46     struct stat st;
47 } ST_BUF;
48
49
50 static CACHE_ENTRY *cache = NULL;
51
52
53 #if 1
54 int yesno(char *prompt, int expect)
55 {
56     char *line, *pr2;
57     int i;
58     size_t n;
59     int ret;
60     if (expect) pr2 = "[Y/n]";
61     else pr2 = "[N/y]";
62     
63     fflush(stdout);
64     do {
65         fprintf(stderr, "%s%s", prompt, pr2);
66         fflush(stderr);
67         n = ret = 0;
68         line = NULL;
69         i = getline(&line, &n, stdin);
70         if (i<0) exit(1);
71         if (i==1) ret=expect|2;
72         if (i>1) {
73                 if (*line=='y'||*line=='Y') ret=1;
74                 if (*line=='n'||*line=='N') ret=2;
75         }
76         if (ret) break;
77         if (line) free(line);
78     } while(1);
79
80     return ret&1;
81 }
82 #endif
83
84 static int scan_dir(ST_BUF *next,DEVICE *dev,char *parent,int number)
85 {
86     DIR *dp;
87     struct dirent *dir;
88     ST_BUF st,*walk;
89     char *start;
90
91     if (verbose >= 5) printf("scan_dir: %s\n", parent);
92     st.next = next;
93     if ((dp = opendir(parent)) == NULL)
94     die("opendir %s: %s",parent,strerror(errno));
95     *(start = strchr(parent,0)) = '/';
96     while ((dir = readdir(dp))) {
97        strcpy(start+1,dir->d_name);
98        if (stat(parent,&st.st) >= 0) {
99           dev->st = st.st;
100           if (S_ISBLK(dev->st.st_mode) && dev->st.st_rdev == number) {
101               (void) closedir(dp);
102               return 1;
103               }
104 #if 0
105           if (S_ISDIR(dev->st.st_mode) && strcmp(dir->d_name,".") &&
106             strcmp(dir->d_name,"..")) {
107 #else
108           /* stay out of all hidden directories (good for 2.6 kernel) */
109           if (S_ISDIR(dev->st.st_mode) && (dir->d_name)[0] != '.' &&
110             strcmp(dir->d_name, ".udev") && strcmp(dir->d_name, "fd")) {
111 #endif
112           for (walk = next; walk; walk = walk->next)
113               if (stat_equal(&walk->st,&st.st)) break;
114           if (!walk && scan_dir(&st,dev,parent,number)) {
115               (void) closedir(dp);
116               return 1;
117               }
118           }
119        }
120     }
121     (void) closedir(dp);
122     *start = 0;
123     return 0;
124 }
125
126
127 static int lookup_dev(char *name,DEVICE *dev,int number)
128 {
129     CACHE_ENTRY **walk;
130
131     if (verbose>=5) printf("lookup_dev:  number=%04X\n", number);
132     for (walk = &cache; *walk; walk = &(*walk)->next)
133         if ((*walk)->number == number) {
134 #if 0
135             CACHE_ENTRY *here;
136
137             if (stat((*walk)->name,&dev->st) >= 0)
138                 if (S_ISBLK(dev->st.st_mode) && dev->st.st_rdev == number) {
139                     strcpy(name,(*walk)->name);
140                     return 1;
141                 }
142             here = *walk; /* remove entry from cache */
143             if (verbose >= 2)
144                 printf("Invalidating cache entry for %s (0x%04X)\n",here->name,
145                   here->number);
146             *walk = here->next;
147             free((char *) here->name);
148             free(here);
149             return 0;
150 #else
151             strcpy(name,(*walk)->name);
152             return 1;
153 #endif
154         }
155     return 0;
156 }
157
158
159 static int is_devfs(void)
160 {
161 static int yesno = 0;
162     struct stat st;
163    
164     if (!yesno) {
165         if (stat(DEV_DIR "/.devfsd", &st) < 0)  yesno=1;
166         else yesno=2;
167     }
168    
169    return yesno-1;
170 }
171
172
173
174 static void cache_add(const char *name,int number)
175 {
176     CACHE_ENTRY *entry;
177
178     entry = cache;
179     while (entry) {
180         if (strcmp(entry->name, name) == 0) {
181             if (entry->number != number) die("cache_add: LILO internal error");
182             return;
183         }
184         entry = entry->next;
185     }
186     if (verbose >= 5) printf("Caching device %s (0x%04X)\n",name,number);
187     entry = alloc_t(CACHE_ENTRY);
188     entry->name = stralloc(name);
189     entry->number = number;
190     entry->next = cache;
191     cache = entry;
192 }
193
194
195 int dev_open(DEVICE *dev,int number,int flags)
196 {
197     char name[PATH_MAX];
198     ST_BUF st;
199     int count;
200     int err;
201
202     if (lookup_dev(name,dev,number)) dev->delete = 0;
203     else {
204         if (stat(DEV_DIR,&st.st) < 0)
205             die("stat " DEV_DIR ": %s",strerror(errno));
206         st.next = NULL;
207         dev->delete = !scan_dir(&st,dev,strcpy(name,DEV_DIR),number);
208         if (dev->delete) {
209             for (count = 0; count <= MAX_TMP_DEV; count++) {
210 #ifdef LCF_USE_TMPDIR
211                 if (!strncmp(TMP_DEV,"/tmp/",5) && getenv("TMPDIR")) {
212                     strcpy(name,getenv("TMPDIR"));
213                     sprintf(name+strlen(name),TMP_DEV+4,count);
214                 }
215                 else
216 #endif
217                     sprintf(name,TMP_DEV,count);
218                 if (stat(name,&dev->st) < 0) break;
219             }
220             if (count > MAX_TMP_DEV)
221                 die("Failed to create a temporary device");
222             if (mknod(name,0600 | S_IFBLK,number) < 0)
223                 die("mknod %s: %s",name,strerror(errno));
224             if (stat(name,&dev->st) < 0)
225                 die("stat %s: %s",name,strerror(errno));
226             if (verbose > 1)
227                 printf("Created temporary device %s (0x%04X)\n",name,number);
228             temp_register(name);
229         }
230         else cache_add(name,number);
231     }
232 #if BETA_TEST
233         if (verbose >= 4) printf("stat-ing %s\n", name);
234         fflush(stdout);
235         stat(name, &st.st);
236 #endif
237     if (flags == O_BYPASS) dev->fd = -1;
238     else if ((dev->fd = open(name,flags)) < 0) {
239         err = errno;
240         fprintf (errstd, "Cannot proceed. Maybe you need to add "
241                         "this to your lilo.conf:\n"
242                          "\tdisk=%s inaccessible\n"
243                         "(real error shown below)\n", name);
244             die("open %s: %s",name,strerror(err));
245     }
246     dev->name = stralloc(name);
247     return dev->fd;
248 }
249
250
251 void dev_close(DEVICE *dev)
252 {
253     if (dev->fd != -1)
254         if (close(dev->fd) < 0) die("close %s: %s",dev->name,strerror(errno));
255     if (dev->delete) {
256         if (verbose > 1)
257             printf("Removed temporary device %s (0x%04X)\n",dev->name,
258               (unsigned int) dev->st.st_rdev);
259         (void) remove(dev->name);
260         temp_unregister(dev->name);
261     }
262     free(dev->name);
263 }
264
265 #define MAX 15
266
267 void cache_scsi (char *name, int major)
268 {
269     char tem[PATH_MAX], format[PATH_MAX];
270     int i, j, dev;
271     int k = strlen(DEV_DISK_DIR) + 3;
272     
273     for (i=15; i>=0; i--) {
274         dev = MKDEV(major,(i<<4));
275 #if 0
276         if (is_devfs()) {
277             sprintf(tem,"/dev/scsi/host%d/bus0/target0/lun0/", i);
278             strcat(strcpy(format,tem),"disc");
279             cache_add(format, dev);
280             strcat(strcpy(format,tem),"part%d");
281         }
282         else
283 #endif
284         {
285             strcpy(format, name);
286             format[k] += i;
287             cache_add(format, dev);
288             strcat(format, "%d");
289         }
290         for (j = MAX; j; j--) {
291             sprintf(tem, format, j);
292             cache_add(tem, dev | j);
293         }
294     }
295 }
296
297
298 void cache_ide (char *name, int major)
299 {
300     char tem[PATH_MAX], tem2[PATH_MAX];
301     char format[PATH_MAX];
302     char *disc;
303     int i, dev, minor, host, bus, target;
304     int j = strlen(DEV_DISK_DIR) + 3;
305     
306     i = name[j] - 'a';
307     target = i&1;
308     minor = target<<6;
309     i >>= 1;
310     bus = i&1;
311     host = i&(-2);
312     if (is_devfs()) {
313         sprintf(tem2, DEV_DIR "/ide/host%d/bus%d/target%d/lun0/", host, bus, target);
314         strcat(strcpy(format,tem2), "part%d");
315         disc = strcat(tem2, "disc");
316     }
317     else {
318         strcat(strcpy(format, name), "%d");
319         disc = name;
320     }
321     dev = MKDEV(major,minor);
322     for (i = MAX; i; i--) {
323         sprintf(tem, format, i);
324         cache_add(tem, dev | i);
325     }
326     cache_add(disc, dev);
327 }
328
329 void preload_dev_cache(void)
330 {
331     char tmp[PATH_MAX];
332     int i;
333     int vsave;
334
335
336     vsave = verbose;
337 #if !BETA_TEST
338     if (verbose>0) verbose--;
339 #endif
340
341     if (is_devfs()) {
342         cache_add(DEV_DIR "/floppy/0", 0x0200);
343         cache_add(DEV_DIR "/floppy/1", 0x0201);
344     }
345     else {
346         cache_add(DEV_DIR "/fd0", 0x0200);
347         cache_add(DEV_DIR "/fd1", 0x0201);
348     }
349     
350     cache_ide(DEV_DISK_DIR "/hdt", MAJOR_IDE10);
351     cache_ide(DEV_DISK_DIR "/hds", MAJOR_IDE10);
352     cache_ide(DEV_DISK_DIR "/hdr", MAJOR_IDE9);
353     cache_ide(DEV_DISK_DIR "/hdq", MAJOR_IDE9);
354
355     cache_ide(DEV_DISK_DIR "/hdp", MAJOR_IDE8);
356     cache_ide(DEV_DISK_DIR "/hdo", MAJOR_IDE8);
357     cache_ide(DEV_DISK_DIR "/hdn", MAJOR_IDE7);
358     cache_ide(DEV_DISK_DIR "/hdm", MAJOR_IDE7);
359     
360     cache_ide(DEV_DISK_DIR "/hdl", MAJOR_IDE6);
361     cache_ide(DEV_DISK_DIR "/hdk", MAJOR_IDE6);
362
363     cache_ide(DEV_DISK_DIR "/hdj", MAJOR_IDE5);
364     cache_ide(DEV_DISK_DIR "/hdi", MAJOR_IDE5);
365     
366     for (i = MAX; i >= 0; i--) {
367         sprintf(tmp, is_devfs() ? DEV_DISK_DIR "/md/%d" : DEV_DISK_DIR "/md%d", i);
368         cache_add(tmp, MKDEV(MAJOR_MD,i));
369     }
370
371     if (!is_devfs()) cache_scsi(DEV_DISK_DIR "/sda", MAJOR_SD);
372     
373     cache_ide(DEV_DISK_DIR "/hdh", MAJOR_IDE4);
374     cache_ide(DEV_DISK_DIR "/hdg", MAJOR_IDE4);
375     cache_ide(DEV_DISK_DIR "/hdf", MAJOR_IDE3);
376     cache_ide(DEV_DISK_DIR "/hde", MAJOR_IDE3);
377
378     for (i = 0; i <= 7; i++) {
379         sprintf(tmp, is_devfs() ? DEV_DIR "/loop/%d" : DEV_DIR "/loop%d", i);
380         cache_add(tmp,0x700+i);
381     }
382
383     cache_ide(DEV_DISK_DIR "/hdd", MAJOR_IDE2);
384     cache_ide(DEV_DISK_DIR "/hdc", MAJOR_IDE2);
385     cache_ide(DEV_DISK_DIR "/hdb", MAJOR_IDE);
386     cache_ide(DEV_DISK_DIR "/hda", MAJOR_IDE);
387     
388     verbose = vsave;
389 }
390
391 #undef MAX
392
393 #define NDEVICE 256
394 static unsigned int idevices[NDEVICE];
395 static int maxdev = 0;
396
397 /* return 0 if device has not been backed up,           */
398 /*        1 if it has been backed up                    */
399
400 static int dev_listed(unsigned short dev)
401 {
402     int i;
403
404 /* scan the device list */
405     for (i=0; i<maxdev; i++) {
406         if (dev==idevices[i]) return 1;         /* already backed up */
407     }
408     
409     if (maxdev < NDEVICE-1) idevices[maxdev++] = dev;
410
411     return 0;   /* new to the list, not listed if too many devices */
412 }
413
414
415 /* make a backup, returning the timestamp of the backup file */
416 /* 0 if no timestamp returned, and no backup file created */
417
418 int make_backup(char *backup_file, int force_backup, BOOT_SECTOR *bsect,
419         unsigned int device, char *id)
420 {
421     struct stat st;
422     char temp_name[PATH_MAX];
423     int bck_file;
424     int timestamp=0;
425     char *filename = "boot";
426
427     char *cp = NULL;
428     int force = 0;
429
430
431     if ((cp=cfg_get_strg(cf_options,"force-backup"))) force=1;
432     else cp=cfg_get_strg(cf_options,"backup");
433     if (!backup_file) {
434         backup_file = cp;
435         force_backup = force;
436     }
437
438     if (backup_file && stat(backup_file, &st) >= 0) {
439 /* file or directory exists */
440         if (S_ISDIR(st.st_mode)) {
441             if (strcmp(backup_file,"/")==0) backup_file = "";
442             sprintf(temp_name, "%s/%s.%04X", backup_file, filename, device);
443             backup_file = temp_name;
444         }
445     /* test for /dev/null */
446         else if (S_ISCHR(st.st_mode) && st.st_rdev==0x0103) return 0;
447         else if (!S_ISREG(st.st_mode))
448             die("make_backup: %s not a directory or regular file", backup_file);
449     }
450
451 /* could not stat it, or it was a directory, or it was a regular file */
452
453     if (backup_file) {
454         char *name, *dir, suffix[16];
455         
456         backup_file = strcpy(temp_name, backup_file);
457         sprintf(suffix, "%04X", device);
458         dir = strrchr(backup_file, '/');
459         if (!dir) dir = backup_file;
460         name = strrchr(dir, '.');
461         if (name) {  /* there is a '.' in the name */
462             if (strcmp(name+1, suffix)==0) ; /* do nothing */
463             else if (strlen(name+1)==4) {  /* && the suffix doesn't match */
464                 strcpy(name+1,suffix);
465             }
466             else if (name[1]==0) strcat(name,suffix);   /* ended with '.' */
467             else {
468                 strcat(name+1,".");
469                 strcat(backup_file,suffix);
470             }
471           /* we now have the filename with the correct suffix */
472         }
473         else {
474     /* no '.' in the name, take it as a template */
475             strcat(backup_file,".");
476             strcat(backup_file,suffix);
477         }
478     }
479     else
480   /*  if (!backup_file) */ {
481         sprintf(temp_name, BACKUP_DIR "/%s.%04X", filename, device);
482         backup_file = temp_name;
483     }
484     
485     bck_file = open(backup_file, O_RDONLY);
486     if (bck_file >= 0 && force_backup) {
487         (void) close(bck_file);
488         bck_file = -1;
489     }
490     if (bck_file >= 0) {
491         if (verbose)
492             printf("%s exists - no %s backup copy made.\n", backup_file, id);
493     }
494     else {
495         if (dev_listed(device)) {
496             if (verbose)
497                 printf("Backup copy of %s has already been made in %s\n",
498                         id, backup_file);
499         }
500         else if (!test) {
501             if ((bck_file = creat(backup_file, 0644)) < 0)
502                 die("creat %s: %s",backup_file, strerror(errno));
503             if (write(bck_file, (char *)bsect, SECTOR_SIZE) != SECTOR_SIZE)
504                 die("write %s: %s", backup_file, strerror(errno));
505             if (verbose)
506                 printf("Backup copy of %s in %s\n", id, backup_file);
507             if (fstat(bck_file, &st) < 0)
508                 die("fstat %s: %s",backup_file,strerror(errno));
509             timestamp = st.st_mtime;
510         }
511         else {
512             if (verbose)
513                 printf("Backup copy of %s in %s (test mode)\n", id, backup_file);
514         }
515     }
516     if (bck_file >= 0 && close(bck_file) < 0) die("close %s: %s",backup_file,strerror(errno));
517     
518     return timestamp;
519 }
520
521
522
523
524 int serial_valid(unsigned int serial, int disk_bios)
525 {
526 #if 1
527     return (serial != 0);
528 #elif 1
529     if (serial == -1 || serial == 0) return 0;
530     return 1;
531 #else
532 /* if ID is replicated characters, it is invalid */
533 /*      Examples of invalid Volume ID's are:
534                 00000000
535                 6C6C6C6C
536                 FFFFFFFF
537 BUT: any Volume ID (except 0 or -1) is valid on drive C:
538  - - - - - - - - - - - - - - - - - - - - - - - - - - */
539     unsigned int temp;
540     
541     temp = serial & 0xFF;
542     temp |= temp << 8;
543     temp |= temp << 16;
544
545     return (serial != temp ||
546                 (serial!=0 && serial!=0xFFFFFFFFUL && disk_bios==0x80));
547 #endif
548 }
549
550 int new_serial(int dev)
551 {
552 static int inited = 0;
553    
554     if (!inited) {
555         struct stat st;
556         int fd, random;
557 #define RANDOM DEV_DIR "/urandom"       
558
559         inited = time(NULL);
560         if ( stat(RANDOM, &st)==0 && S_ISCHR(st.st_mode)
561             && (fd = open(RANDOM, O_RDONLY)) > 0
562             && read(fd, &random, sizeof(random)) == sizeof(random) )  {
563 #if BETA_TEST
564 if(verbose>=5) printf("Using " RANDOM " for seeding random number generator\n");            
565 #endif
566                 close(fd);
567                 inited ^= random;
568         }
569
570         srand(inited);
571     }
572     dev = dev % PRIME + SMALL_PRIME;
573     while(dev--) inited = rand();
574     
575     return inited;
576 #undef RANDOM
577 }
578
579
580
581
582 static int inited = 0;
583 unsigned int serial_no[MAX_BIOS_DEVICES];
584 static int device_code[MAX_BIOS_DEVICES];
585
586 /*  register references to various bios devices
587  *  compiles the list of volume IDs
588  *    returns volume ID on success
589  *      0 = no volume ID
590  *      -1 = error
591  */
592 unsigned int register_bios(int bios, int device)
593 {
594     int i, fd, valid, disk_bios;
595     DEVICE dev;
596     BOOT_SECTOR buff;
597     unsigned int serial = -1;
598     
599 #if 0
600     if (!inited) {
601         for (i=0; i<MAX_BIOS_DEVICES; i++) {
602             device_code[i] = 0;
603             serial_no[i] = 0;
604         }
605         inited = 1;
606         srand(time(NULL));
607     }
608 #else
609     inited = 1;
610 #endif
611     if (!do_md_install && cfg_get_flag(cf_options, "static-bios-codes")) return 0;
612     
613     if (verbose>=4) {
614         printf("registering bios=0x%02X  device=0x%04X\n", bios, device);
615     }
616     
617     disk_bios = bios;
618     if (bios>=0x80 && bios<0x80+MAX_BIOS_DEVICES &&
619                                 (i=has_partitions(device))) {
620         bios &= 0x7F;   /* mask to index */
621         device &= i;    /* mask to master device */
622         if (device_code[bios]==0 && serial_no[bios]==0) {  /* slot empty */
623             fd = dev_open(&dev, device, O_RDWR);
624             if (lseek(fd, 0L, SEEK_SET) < 0)
625                 die("master boot record seek %04X: %s", device, strerror(errno));
626             if (read(fd, (char*)&buff, SECTOR_SIZE)!=SECTOR_SIZE)
627                 die("read master boot record %04X: %s", device, strerror(errno));
628             serial = *(int*)&buff.sector[PART_TABLE_OFFSET-6];
629             valid = serial_valid(serial, disk_bios);
630             if ((!valid || (VERSION_MINOR>=50)) && !test)
631                     make_backup(NULL, 0, &buff, device,
632                                         "master disk volume ID record");
633             if (!valid) {
634                 i = device % PRIME + SMALL_PRIME;
635                 while(i--) serial = rand();
636                 for (; i<5 && !serial_valid(serial, disk_bios); i++) serial = rand();
637                 if (!serial_valid(serial, disk_bios)) die("Volume ID generation error");
638
639                 *(int*)&buff.sector[PART_TABLE_OFFSET-6] = serial;
640                 if (*(short*)&buff.sector[PART_TABLE_OFFSET - 2] == 0)
641                     *(unsigned short*)&buff.sector[PART_TABLE_OFFSET - 2] = MAGIC_SERIAL;
642                 if (verbose)
643                     printf("Assigning new Volume ID to (%04X) '%s'  ID = %08X\n",
644                                         device, dev.name, (int)serial);
645                 if (!test) {
646                     i = lseek(fd, 0L, SEEK_SET);
647                     if (i<0) die("master boot record2 seek %04X: %s", device, strerror(errno));
648                     if (write(fd, (char*)&buff, SECTOR_SIZE)!=SECTOR_SIZE)
649                         die("write master boot record %04X: %s", device, strerror(errno));
650                 }
651             }
652             dev_close(&dev);
653             for (i=0; i<MAX_BIOS_DEVICES; i++) {
654                 if (device_code[i]==device)
655                     die("register_bios: device code duplicated: %04X", device);
656                 if (serial_no[i]==serial)
657                     die("register_bios: volume ID serial no. duplicated: %08X", serial);
658             }
659             device_code[bios] = device;
660             serial_no[bios] = serial;
661         }
662
663
664         if (device_code[bios]==device) serial = serial_no[bios];
665         else {
666             DEVICE dev, deva;
667             
668             dev_open(&dev, device_code[bios], O_BYPASS);
669             dev_open(&deva, device, O_BYPASS);
670
671             die("Bios device code 0x%02X is being used by two disks\n\t%s (0x%04X)  and  %s (0x%04X)",
672                 bios|0x80, dev.name, device_code[bios], deva.name, device);
673         }
674         if (verbose>=3) {
675             printf("Using Volume ID %08X on bios %02X\n", (int)serial, bios+0x80);
676         }
677     }
678     else if (bios>=0 && bios <=3) serial = 0;
679     else serial = -1;
680     
681     return serial;
682 }
683
684
685 void dump_serial_nos(void)
686 {
687     int i,j;
688     
689     printf(" BIOS   VolumeID   Device\n");
690     if (!inited) return;
691     for (j=nelem(serial_no); serial_no[--j]==0; )   ;
692     for (i=0; i<=j; i++)
693         printf("  %02X    %08X    %04X\n",
694                 i+0x80,
695                 (int)serial_no[i],
696                 (int)device_code[i]
697         );
698 }
699
700
701 enum {ID_GET=0, ID_SET};
702
703 static int volid_get_set(int device, int vol_in, int option)
704 {
705     BOOT_SECTOR buf;
706     DEVICE dev;
707     int fd;
708     int temp;
709     unsigned short word;
710     
711     if (!has_partitions(device) && (device & P_MASK(device)) )
712         die("VolumeID set/get bad device %04X\n", device);
713         
714     fd = dev_open(&dev, device, option ? O_RDWR : O_RDONLY);
715     if (read(fd, &buf, sizeof(buf)) != sizeof(buf)) {
716       fprintf (errstd, "Cannot proceed. Maybe you need to add "
717                         "this to your lilo.conf:\n"
718                          "\tdisk=%s inaccessible\n"
719                         "(real error shown below)\n", dev.name);
720       die("VolumeID read error: sector 0 of %s not readable", dev.name);
721     }
722     if (option==ID_SET) {
723         make_backup(NULL, 0, &buf, device,
724                                         "master disk volume ID record");
725         word = temp = buf.boot.volume_id & 0xFF;        /* one char */
726         word |= word << 8;
727         temp = word;
728         temp |= temp << 16;
729         if (buf.boot.mbz==word 
730                 && buf.boot.volume_id==temp
731                 && buf.boot.marker==word) {
732             buf.boot.mbz = buf.boot.marker = 0;
733         }
734         buf.boot.volume_id = vol_in;
735         if (buf.boot.marker == 0) buf.boot.marker = MAGIC_SERIAL;
736         if (!test) {
737             if (lseek(fd, 0L, SEEK_SET) != 0L  ||
738                     write(fd, &buf, PART_TABLE_OFFSET) != PART_TABLE_OFFSET )
739                 die("volid write error");
740         }
741     }
742     dev_close(&dev);
743     sync(); /* critical that this be done here */
744     
745     return buf.boot.volume_id;
746 }
747
748
749
750
751 /* count the number of slashes in a pathname */
752 static int slashes(char *cp)
753 {
754     int n = 0;
755     
756     while ( (cp=strchr(++cp,'/')) )  n++;
757     
758     return n;
759 }
760
761
762 static int ndevs=0;
763 enum {INVALID=1, DUPLICATE=2, REGENERATE=3, NTCAUTION=4};
764
765 struct VolumeMgmt {
766     char *name;         /* the name of the disk; e.g.  "/dev/hda" */
767     unsigned int device;        /* the device number (major, minor) */
768     int sort;           /* the device number used for sorting */
769     int flag;           /* various flag bits */
770     char nt[PART_MAX];  /* flag partitions which might be NT */
771     DT_ENTRY *dt;       /* pointer to any disktab entry */
772     struct {
773         int kernel;     /* volume ID as read using kernel I/O */
774         int probe;      /* volume ID as probed */
775     } vol_id;
776     struct {
777         int user;       /* user used a disk= bios= section */
778         int probe;      /* passed in from the BIOS data check */
779         int actual;     /* this is what we finally decide upon */
780     } bios;             /* BIOS device codes */
781 };
782
783
784 #ifdef LCF_MDPRAID
785 /* return boolean if VM is a component drive of MDP-RAID */
786
787 static int is_mdp(struct VolumeMgmt *vm, struct VolumeMgmt *mdp)
788 {
789     int mdp_fd;
790     DEVICE dev;
791     struct md_version md_version_info;
792     md_array_info_t raid;
793     int ret=0;
794
795     if (verbose>=2) printf("is_mdp:   %04X : %04X\n",
796           vm->device, mdp->device);
797     
798     if ((mdp_fd=dev_open(&dev, mdp->device, O_NOACCESS) ) < 0)
799         die("Unable to open %s", mdp->name);
800
801     if (ioctl(mdp_fd, RAID_VERSION, &md_version_info) < 0) ret = -1;
802     else if (md_version_info.major > 0  || 
803                           md_version_info.minor < 90) {
804         
805         ret = -2;
806         warn("RAID versions other than 0.90 are not supported");
807     }
808     else if (ioctl(mdp_fd, GET_ARRAY_INFO, &raid) < 0) ret = -1;
809     else if (raid.level == 1) {
810         md_disk_info_t disk;
811         int i;
812         
813         for (i=0; ret==0 && i<raid.active_disks; i++) {
814             disk.number = i;
815             if (ioctl(mdp_fd, GET_DISK_INFO, &disk) < 0) ret = -1;
816             if (vm->device == MKDEV(disk.major, disk.minor)) ret = 1;
817         }
818     }
819     /* else ret = 0;  already */
820     dev_close(&dev);
821
822     if (verbose>=2) printf("is_mdp: returns %d\n", ret);
823     
824     return ret;
825 }
826 #endif
827
828 /* 
829    Returns 0 if not an NT, 2000, or XP boot disk (query user)
830    returns 1 if it is an NT ... boot disk; abort if fatal set
831 */
832 static int winnt_check(struct VolumeMgmt *vm, int fatal)
833 {
834     int dev, ret;
835     
836     if ( !(vm->flag & NTCAUTION) ) return 0;
837     
838     dev = vm->device;
839
840     fflush(stdout);
841     fflush(stderr);
842     
843     fprintf(stderr, "\n\nReference:  disk \"%s\"  (%d,%d)  %04X\n\n"
844 "LILO wants to assign a new Volume ID to this disk drive.  However, changing\n"
845 "the Volume ID of a Windows NT, 2000, or XP boot disk is a fatal Windows error.\n"
846 "This caution does not apply to Windows 95 or 98, or to NT data disks.\n"
847                                 , vm->name, MAJOR(dev), MINOR(dev), dev);
848                                         
849                                         
850     ret = yesno("\nIs the above disk an NT boot disk? ", 1);
851
852     if (ret && fatal) {
853         fprintf(stderr, "Aborting ...\n");
854         exit(0);
855     }
856     
857     return ret;
858 }
859
860
861
862 #ifdef LCF_MDPRAID
863 #define SORT(d) (MAJOR(d)==MAJOR_SD?MKDEV(MAJOR_SD_SORT,MINOR(d)):\
864                  MAJOR(d)==MAJOR_MDP?MKDEV(MAJOR_MDP_SORT,MINOR(d)):\
865                  MAJOR(d)==MAJOR_EMD?MKDEV(MAJOR_EMD_SORT,MINOR(d)):\
866                  MAJOR(d)==MAJOR_HPT370?MKDEV(MAJOR_HPT370_SORT,MINOR(d)):\
867                  (d))
868 #else
869 #define SORT(d) (MAJOR(d)==MAJOR_SD?MKDEV(MAJOR_SD_SORT,MINOR(d)):\
870                  MAJOR(d)==MAJOR_EMD?MKDEV(MAJOR_EMD_SORT,MINOR(d)):\
871                  MAJOR(d)==MAJOR_HPT370?MKDEV(MAJOR_HPT370_SORT,MINOR(d)):\
872                  (d))
873 #endif
874
875 int pf_hard_disk_scan(void)
876 {
877     struct VolumeMgmt vm [MAX_DEVICES];
878 static int warned = 0, called = 0;
879     char *line, *next, *name;
880     int major, minor, i, ipart;
881     int dev, mask, bios;
882     unsigned int device;
883     size_t n;
884     DEVICE Dev;
885     DT_ENTRY *walk;
886     struct stat st;
887     int duplicate = 0, invalid = 0, ret = 0, ntcaution = 0;
888     int raidcaution = 0;
889     long codes = 0L;
890
891 /* called from  raid_setup  &  from  geo_open */
892 /* allow only 1 call */
893     if (called || cfg_get_flag(cf_options,"static-bios-codes")) return ret;
894     called = 1;
895     memset(vm,0,sizeof(vm));    /* for consistency */
896             
897 #if 1
898     if (!pp_fd  &&  (pp_fd = fopen(PARTITIONS, "r"))==NULL) {
899 #else
900     if ((pp_fd = fopen(PARTITIONS, "r"))==NULL || fetch()) {
901 #endif
902         warn("'" PARTITIONS "' does not exist, disk scan bypassed");
903         return 1;
904     }
905
906     n = 0;
907     line = NULL;
908     while (!feof(pp_fd)) {
909         if (line) {
910             free(line);
911             line = NULL;
912             n = 0;
913         }
914         if (getline(&line, &n, pp_fd) <= 0) break;
915
916         major = strtoul(line, &next, 10);
917         if (major==0 || line==next) continue;
918
919         if (is_dm_major(major)) {
920 #ifndef LCF_DEVMAPPER
921             warn("device-mapper (%d) referenced in " PARTITIONS ",\n"
922                  "   but LILO is configured without DEVMAPPER option.  Skipping device.", major);
923             continue;
924 #endif
925         }
926         else if ((major>=60 && major<=63) || (major>=120 && major<=127) ) {
927             warn(PARTITIONS " references Experimental major device %d.", major);
928         }
929         else if (major==255) {
930             warn(PARTITIONS " references Reserved device 255.");
931             continue;
932         }
933         else if (major>=240 && major<255) {
934             warn(PARTITIONS " references Experimental major device %d.", major);
935         }
936
937         minor = strtoul(next, &name, 10);
938         if (next==name) continue;
939         /* skip */ strtoull(name,&next,10);
940
941         while (isspace(*next)) next++;
942         name = next;
943         while (*name && !isspace(*name)) name++;
944         *name = 0;
945         if (strncmp(DEV_DISK_DIR "/", next, strlen(DEV_DISK_DIR)+1) != 0) name = next-(strlen(DEV_DISK_DIR)+1);
946         else name = next;
947         if (*name=='/') name++;
948         strncpy(name, DEV_DISK_DIR "/", strlen(DEV_DISK_DIR)+1);
949         if (verbose>=5) {
950             printf("pf_hard_disk_scan: (%d,%d) %s\n", major, minor, name);
951         }
952
953         device = MKDEV(major, minor);
954
955         Dev.delete = 0;
956         if (stat(name, &st) < 0) {
957             dev_open(&Dev, device, O_BYPASS);
958             if (!warned) {
959                 warn("'" PARTITIONS "' does not match '" DEV_DISK_DIR "' directory structure.\n"
960                                 "    Name change: '%s' -> '%s'%s"
961                                 ,       name, Dev.name,
962                                 slashes(name) > 3 && slashes(Dev.name) < 3 ? "\n"
963                                 "    The kernel was compiled with DEVFS_FS, but 'devfs=mount' was omitted\n"
964                                 "        as a kernel command-line boot parameter; hence, the '" DEV_DISK_DIR "' directory\n"
965                                 "        structure does not reflect DEVFS_FS device names."
966                         :       slashes(name) < 3 && slashes(Dev.name) > 3 ? "\n"
967                                 "    The kernel was compiled without DEVFS, but the '" DEV_DISK_DIR "' directory structure\n"
968                                 "        implements the DEVFS filesystem."
969                         :
970                                 ""
971                                 );
972                 warned++;
973             }
974             else {
975                 warn("Name change: '%s' -> '%s'", name, Dev.name);
976             }
977             name = Dev.name;
978             if (Dev.delete) {
979                 warn("'" DEV_DISK_DIR "' directory structure is incomplete; device (%d, %d) is missing.",
980                                 major, minor);
981                 cache_add(name, device);
982             }
983         }
984         else cache_add(name, device);
985                 
986         mask = has_partitions(device);
987         dev = device & mask;    /* dev is the master device */
988         ipart = device & P_MASK(device); /* ipart is the partition number */
989         
990 #if 1
991         for (walk=disktab; walk; walk=walk->next) {
992             if (walk->device == dev) {
993                 if (walk->heads == 0 /* inaccessible */) {
994                     if (ipart==0 && !identify)
995                         warn("bypassing VolumeID scan of drive flagged INACCESSIBLE:  %s", name);
996                     ipart = -1; /* causes skip below */
997                 }
998                 break;
999             }
1000         }
1001 #endif
1002         if (mask && ipart>0) {
1003             int found;
1004             int serial;
1005            
1006             for (found=i=0; i<ndevs && !found; i++) {
1007                 if (dev==vm[i].device) found = i+1;
1008             }
1009             if (!found) {
1010                 DEVICE Dev2;
1011                 serial = volid_get_set(dev, 0, ID_GET);
1012
1013 #if 0
1014 /* take care of uninitialized Volume IDs with no fanfare */
1015                 if (serial==0) {
1016                     serial = volid_get_set(dev, new_serial(dev), ID_SET);
1017                 }
1018 #endif
1019 #if BETA_TEST
1020                 if (verbose>=3) printf("**ndevs=%d\n", ndevs);
1021 #endif
1022                 if (ndevs>=MAX_DEVICES) {
1023                     die("More than %d hard disks are listed in '" PARTITIONS "'.\n"
1024                         "    Disks beyond the %dth must be marked:\n"
1025                         "        disk=" DEV_DISK_DIR "/XXXX  inaccessible\n"
1026                         "    in the configuration file (" DFL_CONFIG ").\n"
1027                         , MAX_DEVICES, MAX_DEVICES);
1028                 }
1029                 else
1030                 {
1031                     GEOMETRY geo;
1032                     
1033                     dev_open(&Dev2,dev,O_BYPASS);
1034
1035                     vm[ndevs].device = dev;
1036
1037                     vm[ndevs].sort = SORT(dev);
1038                     
1039                     vm[ndevs].vol_id.kernel = serial;
1040                     
1041                     vm[ndevs].name = stralloc(Dev2.name);
1042
1043                     if (verbose >= 4)
1044                         printf("pf:  dev=%04X  id=%08X  name=%s\n", dev, (int)serial, Dev2.name);
1045
1046                     for (walk = disktab; walk; walk = walk->next) {
1047                         if (walk->device == dev) {
1048                             bios = walk->bios;
1049                             vm[ndevs].dt = walk;        /* record disktab link */
1050                             if (bios >= 0x80 && bios <= DEV_MASK) {
1051                                 vm[ndevs].bios.actual =
1052                                         vm[ndevs].bios.user = bios;
1053                                 bios &= 0x7F;
1054                                 if (codes & (1L<<bios)) {
1055                                     i = ndevs-1;
1056                                     bios += 0x80;
1057                                     while (vm[i].bios.user != bios) i--;
1058                                     die("Disks '%s' and '%s' are both assigned 'bios=0x%02X'",
1059                                                 vm[ndevs].name, vm[i].name, bios);
1060                                 }
1061                                 codes |= 1L << bios;    /* mark BIOS code in use */
1062                             } 
1063                             else if (bios != -1)
1064                                 die("Hard disk '%s' bios= specification out of the range [0x80..0x%02X]", Dev2.name, DEV_MASK);
1065
1066                             break;
1067                         }
1068                     }
1069
1070                     dev_close(&Dev2);
1071
1072                     geo_query_dev(&geo, dev,
1073                               MAJOR(dev)!=MAJOR_LOOP
1074 #ifdef LCF_ATARAID
1075                                && MAJOR(dev)!=MAJOR_DM
1076 #endif
1077                                                 );
1078
1079                     vm[ndevs].bios.probe = bios_device(&geo, dev);
1080
1081                     if (serial_valid(serial, DEV_MASK)) {
1082                         for (i=0; i<ndevs; i++) {
1083                             if (vm[i].vol_id.kernel==serial) {
1084                                 duplicate++;
1085                                 vm[i].flag |= DUPLICATE;
1086                                 vm[ndevs].flag |= DUPLICATE;    /* mark both of them */
1087                             } /* if */
1088                         } /* for */
1089                     }
1090                     else {
1091                         vm[ndevs].flag |= INVALID;
1092                         invalid++;
1093                     }
1094                     found = ++ndevs;
1095                 } /* if (open, lseek, read ) */
1096                                 
1097             } /* if (!found)  */
1098
1099             if (ipart>0 && ipart<=PART_MAX) {
1100                 found--;
1101                 if (part_nowrite(name) & PTW_NTFS) {
1102                     vm[found].flag |= NTCAUTION;
1103                     vm[found].nt[ipart-1] = NTCAUTION;
1104                     ntcaution++;
1105                     if (verbose>=4) printf("NT partition: %s %d %s\n",
1106                                         vm[found].name, ipart, name);
1107                 }
1108             }
1109
1110         } /* if (mask && (device & P_MASK(device)) ) */
1111
1112     } /* while (!feof())  */
1113    
1114     if (line) free(line);
1115     fclose(pp_fd);
1116
1117
1118
1119         if (verbose>=5) {
1120             int i;
1121             for (i=0; i<ndevs; i++)
1122                 printf("  %04X  %08X  %s\n", vm[i].device, vm[i].vol_id.kernel, vm[i].name);
1123         }
1124
1125     if (verbose>=2) printf("pf_hard_disk_scan: ndevs=%d\n", ndevs);
1126
1127 /* now sort the volumes into canonical order */
1128   {
1129         int i,j,k;
1130         
1131         for (j=ndevs-1; j>0; j--)
1132         for (i=0; i<j; i++)
1133         if (vm[i].sort > vm[i+1].sort) {
1134             struct VolumeMgmt temp;
1135             temp = vm[i];       
1136             vm[i] = vm[i+1];
1137             vm[i+1] = temp;
1138         }
1139
1140 /* now automatically treat MDP-RAID devices as inaccessible */
1141     for (k=0; k<ndevs; k++) {
1142 #ifdef LCF_MDPRAID
1143       if (MAJOR(vm[k].device) == MAJOR_MDP  ||
1144           MAJOR(vm[k].device) == MAJOR_EMD   ) {
1145
1146         if (verbose>=2) printf("MDP-RAID detected,   k=%d\n", k);
1147         if (cfg_get_flag(cf_options, "noraid") ) {
1148             raidcaution = 1;
1149             warn("RAID controller present, with \"noraid\" keyword used.\n"
1150                 "    Underlying drives individually must be marked INACCESSIBLE." );
1151         } else {
1152             for (j=0; j<ndevs; j++) {
1153                 if (j==k) break;        /* skip ourselves */
1154
1155                 if ((i=is_mdp(&vm[j], &vm[k]))<0) {
1156                     if (!identify) warn("(MDP-RAID driver) the kernel does not support underlying\n"
1157                         "    device inquiries.  Each underlying drive of  %s  must\n"
1158                         "    individually be marked INACCESSIBLE.", vm[k].name
1159                         );
1160                     j=ndevs;    /* terminate loop */
1161                 }
1162                 else if (i) {
1163                     if (!vm[j].dt) {
1164                         walk = alloc_t(DT_ENTRY);
1165                         walk->device = vm[j].device;
1166                         walk->cylinders = walk->heads = walk->sectors = walk->start = -1;
1167                         walk->next = disktab;
1168                         vm[j].dt = disktab = walk;
1169 #if BETA_TEST
1170                         if (verbose >= 4) printf("Allocated DT entry for device %04X  ptr=%08lx\n", vm[j].device, (long)walk);
1171 #endif
1172                     }
1173
1174                     if (vm[j].dt->heads != 0) {
1175                         vm[j].dt->heads = 0;
1176                         warn("(MDP-RAID) underlying device flagged INACCESSIBLE: %s",
1177                                 vm[j].name);
1178                     }
1179                     --ndevs;
1180                     warn("bypassing VolumeID check of underlying MDP-RAID drive:\n"
1181                         "\t%04X  %08X  %s",
1182                                 vm[j].device, vm[j].vol_id.kernel, vm[j].name);
1183                     for (i=j; i<ndevs; i++) vm[i] = vm[i+1];
1184                     if (j < k) k--;
1185                     j--;
1186                 }
1187             } /* for j   ... */
1188         }
1189       }
1190 #else
1191       if (MAJOR(vm[k].device) == MAJOR_EMD  ||
1192           MAJOR(vm[k].device) == MAJOR_MDP   ) {
1193           raidcaution = 1;
1194           warn("MDP-RAID controller present; underlying drives individually\n"
1195                 "    must be marked INACCESSIBLE." );
1196 #if BETA_TEST
1197 {
1198         int mdp_fd;
1199         DEVICE dev;
1200
1201         if ((mdp_fd=dev_open(&dev, vm[k].device, O_NOACCESS) ) < 0)
1202             die("Unable to open %s",vm[k].name);
1203
1204         dev_close(&dev);
1205 }
1206 #endif
1207       }
1208 #endif
1209 #ifdef LCF_ATARAID
1210       if ( MAJOR(vm[k].device) == MAJOR_DM ) {
1211           if (verbose>=2) printf("ATA-RAID detected,   k=%d\n", k);
1212           raidcaution = 1;
1213           warn("ATA-RAID controller present;\n"
1214               "    Underlying drives individually must be marked INACCESSIBLE." );
1215       }
1216 #endif
1217     } /* for (k ... */
1218   } /* end sort */
1219
1220         if (verbose>=3) {
1221             for (i=0; i<ndevs; i++)
1222                 printf("  %04X  %08X  %s\n", vm[i].device, vm[i].vol_id.kernel, vm[i].name);
1223             printf("Resolve invalid VolumeIDs\n");
1224         }
1225
1226 /* now go thru and resolve any invalid VolumeIDs */
1227
1228     if (invalid)
1229     for (i=0; i<ndevs; i++)
1230     if (vm[i].flag & INVALID) {
1231         if (ndevs>1) winnt_check(&vm[i], 1);
1232         else if (vm[i].flag & NTCAUTION) break;
1233         
1234         dev = vm[i].device;
1235         vm[i].vol_id.kernel = volid_get_set(dev, new_serial(dev), ID_SET);
1236         vm[i].flag &= ~INVALID;
1237     }
1238
1239         if (verbose>=3)
1240             printf("Resolve duplicate VolumeIDs\n");
1241     
1242 /* now check for duplicates */
1243
1244     while (duplicate) {         /* loop until there are none */
1245         int j, k;
1246         
1247         if (raidcaution) {
1248             raidcaution = 0;    /* print comment only once */
1249             warn("Duplicated VolumeID's will be overwritten;\n"
1250                 "   With RAID present, this may defeat all boot redundancy.\n"
1251                 "   Underlying RAID-1 drives should be marked INACCESSIBLE.\n"
1252                 "   Check 'man lilo.conf' under 'disk=', 'inaccessible' option."
1253                 );
1254         }
1255         duplicate = 0;
1256         for (j=ndevs-1; j>0; j--) {
1257             for (i=0; i<j; i++) {
1258                 if (vm[i].vol_id.kernel == vm[j].vol_id.kernel) {
1259                     if (vm[i].flag & vm[j].flag & NTCAUTION) {
1260                         if (!winnt_check(&vm[j], 0)) k = j;
1261                         else winnt_check(&vm[k=i], 1);
1262                     }
1263                     else if (vm[i].flag & NTCAUTION) k = j;
1264                     else if (vm[j].flag & NTCAUTION) k = i;
1265                     else k = j;
1266                     
1267                     dev = vm[k].device;
1268                     vm[k].vol_id.kernel = volid_get_set(dev, new_serial(dev), ID_SET);
1269                     duplicate++;
1270                 }
1271             }
1272         }
1273     } /* while (duplicate) */
1274
1275
1276
1277         if (verbose>=2) {
1278             for (i=0; i<ndevs; i++)
1279                 printf("  %04X  %08X  %s\n", vm[i].device, vm[i].vol_id.kernel, vm[i].name);
1280         }
1281
1282
1283
1284     if (verbose>=2) printf("device codes (user assigned pf) = %lX\n", codes);
1285
1286 /* mark those BIOS codes that are already used in the disk=/bios= table */
1287
1288     for (walk=disktab; walk; walk=walk->next) {
1289         if (walk->bios >= 0x80) {   /* eliminate -1 and floppies */
1290             if (MAJOR(walk->device)==MAJOR_MD) continue;
1291             bios = walk->bios & 0x7F;
1292             if (bios >= 8*sizeof(codes) || bios >= MAX_BIOS_DEVICES)
1293                 die("BIOS code %02X is too big (device %04X)", bios+0x80, walk->device);
1294             if (codes & (1L<<bios)) {
1295                 int j = -1;
1296                 int k = -1;
1297
1298                 for (i=0; i<ndevs; i++) {
1299                     if (vm[i].device == walk->device) j = i;
1300                     else if (vm[i].bios.user == bios+0x80) k = i;
1301                 }
1302 #if BETA_TEST
1303                 if (verbose>=3) printf("J=%d  K=%d\n", j, k);
1304 #endif
1305                 if (j<0 && k>=0) {
1306                     die("Devices %04X and %04X are assigned to BIOS 0x%02X",
1307                         vm[k].device, walk->device, bios+0x80);
1308                 }
1309             }
1310             codes |= 1L << bios;        
1311         }
1312     }
1313
1314     if (verbose>=2) printf("device codes (user assigned) = %lX\n", codes);
1315
1316     for (i=0; i<ndevs; i++) {
1317         bios = vm[i].bios.probe;
1318         if (bios >= 0x80) {
1319             if (vm[i].bios.actual < 0x80 && !(codes & (1L<<(bios&0x7F)))) {
1320                 vm[i].bios.actual = bios;
1321                 bios &= 0x7F;
1322                 codes |= 1L << bios;
1323             }
1324         }
1325     }
1326
1327     if (verbose>=2) printf("device codes (BIOS assigned) = %lX\n", codes);
1328
1329     for (bios=i=0; i<ndevs; i++) {
1330         int j;
1331         
1332         
1333         if (vm[i].bios.actual < 0x80) {
1334             while ( codes & (1L<<bios) ) bios++;
1335             if (bios < MAX_BIOS_DEVICES) {
1336                 codes |= 1L<<bios;
1337                 vm[i].bios.actual = 0x80+bios;
1338                 if (verbose>=3) printf("Filling in '%s' = 0x%02X\n", vm[i].name, bios+0x80);
1339             }
1340             else vm[i].bios.actual = -1;
1341         }
1342         if (!vm[i].dt) {
1343             walk = alloc_t(DT_ENTRY);
1344             walk->device = vm[i].device;
1345             walk->cylinders = walk->bios = walk->heads = walk->sectors = walk->start = -1;
1346             walk->next = disktab;
1347             vm[i].dt = disktab = walk;
1348 #if BETA_TEST
1349             if (verbose >= 4) printf("Allocated DT entry for device %04X  ptr=%08lx\n", vm[i].device, (long)walk);
1350 #endif
1351         }
1352         j = vm[i].dt->bios = vm[i].bios.actual;
1353         j &= 0x7F;
1354
1355         if (j < MAX_BIOS_DEVICES) {     
1356             serial_no[j] = vm[i].vol_id.kernel;
1357             device_code[j] = vm[i].device;
1358 #if BETA_TEST
1359             if (verbose >= 5) {
1360                 printf("Generated: %02X  %04X  %08X\n", j+0x80, device_code[j], (int)serial_no[j]);
1361             }
1362 #endif
1363         }
1364         else {
1365             vm[i].dt->heads = 0;        /* mark inaccessible */
1366             {
1367                 static int i=0;
1368                 if (!(i++)) warn("Internal implementation restriction. Boot may occur from the first\n"
1369                     "    %d disks only. Disks beyond the %dth will be flagged INACCESSIBLE."
1370                     , MAX_BIOS_DEVICES, MAX_BIOS_DEVICES);
1371                 warn("'disk=%s  inaccessible' is being assumed.  (%04X)",
1372                 vm[i].name, vm[i].device);
1373             }
1374         }
1375         
1376         inited = 1;
1377     }
1378
1379     if (verbose>=2) printf("device codes (canonical) = %lX\n", codes);
1380
1381     for (bios=8*sizeof(codes)-1; !(codes&(1L<<bios)) && bios>=0; ) bios--;
1382
1383     if (bios > ndevs)
1384         warn("BIOS device code 0x%02X is used (>0x%02X).  It indicates more disks\n"
1385                         "  than those represented in '/proc/partitions' having actual partitions.\n"
1386                         "  Booting results may be unpredictable.", bios+0x80, ndevs+0x80-1);
1387
1388
1389
1390     return ret;
1391 }
1392