/* silo - bootblock installation program Copyright (C) 1996 Maurizio Plaza 1996,1997 Jakub Jelinek This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define VERSION "0.68" #define DFL_CONFIG "/etc/silo.conf" #define DFL_BACKUP "/boot/old.b" #define DFL_BACKUP2 "/boot/old_part1.b" #define DFL_PRIMARY "/boot/first.b" #define DFL_SECONDARY "/boot/second.b" #include #include #include #include #ifdef __linux__ # include # include # include # include # include # include #elif defined (__solaris__) # include # include # include # include # include # include # include "ufs.h" # include # include # ifdef _BIG_ENDIAN # define BYTE_ORDER 4321 # elif defined (_LITTLE_ENDIAN) # define BYTE_ORDER 1234 # else # error "Unknown byteorder" # endif static int ufs_blocks (char *, ino_t); #else # error "Unknown system" #endif #include #include #include #include #include "cdrom.h" #ifndef __intel__ #include "prom.h" #endif #include "../first/first.h" #define DIGIT_OFFSET (DIGIT_OFFSET_TMP + 0x223) #define LETTER_OFFSET (LETTER_OFFSET_TMP + 0x223) struct sun_disklabel { unsigned char info[128]; /* Informative text string */ unsigned char spare[292]; /* Boot information etc. */ unsigned short rspeed; /* Disk rotational speed */ unsigned short pcylcount; /* Physical cylinder count */ unsigned short sparecyl; /* extra sects per cylinder */ unsigned char spare2[4]; /* More magic... */ unsigned short ilfact; /* Interleave factor */ unsigned short ncyl; /* Data cylinder count */ unsigned short nacyl; /* Alt. cylinder count */ unsigned short ntrks; /* Tracks per cylinder */ unsigned short nsect; /* Sectors per track */ unsigned char spare3[4]; /* Even more magic... */ struct sun_partition { unsigned long start_cylinder; unsigned long num_sectors; } partitions[8]; unsigned short magic; /* Magic number */ unsigned short csum; /* Label xor'd checksum */ }; #if BYTE_ORDER == 4321 __u32 swab32 (__u32 value) { return ((value >> 24) | ((value >> 8) & 0xff00) | ((value << 8) & 0xff0000) | (value << 24)); } __u16 swab16 (__u16 value) { return (value >> 8) | (value << 8); } #define bswab32(x) (x) #define bswab16(x) (x) #else #define swab32(x) (x) #define swab16(x) (x) __u32 bswab32 (__u32 value) { return ((value >> 24) | ((value >> 8) & 0xff00) | ((value << 8) & 0xff0000) | (value << 24)); } __u16 bswab16 (__u16 value) { return (value >> 8) | (value << 8); } #endif unsigned char nsect; unsigned short bs; unsigned long doff; int sda1_offset; int zero_based_part; char *cdrom_image = 0; char *cdrom_list = ""; int cd_size = 0; __u32 blocks[512]; __u32 cd_files[31 * 2]; char *first, *second, *old; /* File names */ int promver = -1; int scsi = 0; void fatal (char *fmt,...) { va_list ap; va_start (ap, fmt); fprintf (stderr, "Fatal error: "); vfprintf (stderr, fmt, ap); putc ('\n', stderr); va_end (ap); exit (1); } int check_fs (int fd) { struct ufs_superblock ufs; struct ext2_super_block sb; /* Super Block Info */ struct iso_primary_descriptor isd; if (lseek (fd, 1024, 0) != 1024 || read (fd, &sb, sizeof (sb)) != sizeof (sb)) fatal ("Cannot read Super Block!"); if (swab16 (sb.s_magic) == EXT2_SUPER_MAGIC) return 1024 << swab32 (sb.s_log_block_size); if (lseek (fd, 8192, 0) != 8192 || read (fd, &ufs, sizeof (ufs)) != sizeof (ufs)) return -1; if (bswab32 (ufs.fs_magic) == UFS_MAGIC) return ufs.fs_fsize; if (lseek (fd, 32768, 0) != 32768 || read (fd, &isd, sizeof(isd)) != sizeof(isd)) return -1; if (!strncmp ((char *)&isd, "\001CD001\001", 8)) { cd_size = swab32 (*(unsigned int *)(isd.volume_space_size)) * 2048; return 1024; } return -1; } void read_sb (char *device, char *bootdev, char *device2) { int fd, partno; char buff[512]; struct sun_disklabel *sdl; struct ufs_superblock ufs; struct ext2_super_block sb; /* Super Block Info */ int offset, i; sda1_offset = -1; zero_based_part = 0; if ((fd = open (device, O_RDONLY)) == -1) fatal ("Cannot open superblock on %s", device); bs = check_fs (fd); if (bs == (unsigned short)-1) fatal ("File systems other than ext2, ufs and iso9660 not yet supported", device); close (fd); nsect = bs / 512; doff = 0; if (!scsi) return; #ifdef __linux__ partno = (int) (*(device + strlen (device) - 1) - '0') - 1; #elif defined(__solaris__) partno = (int) (*(device + strlen (device) - 1) - '0'); #endif sdl = (struct sun_disklabel *) &buff; if ((fd = open (bootdev, O_RDONLY)) == -1) fatal ("Error opening %s", bootdev); if (read (fd, buff, sizeof (buff)) != sizeof (buff)) fatal ("Error reading %s's label", bootdev); if (!sdl->partitions[0].start_cylinder) zero_based_part = 0; else if (!sdl->partitions[2].start_cylinder) zero_based_part = 2; else { for (i = 1; i < 8; i++) if (!sdl->partitions[i].start_cylinder) { zero_based_part = i; break; } if (i == 8) fatal ("In order to install SILO you must start at least one partition on cylinder\n" "0. Consider setting sda3 as WHOLE_DISK (starting at 0 and ending at disk end\n" "and sda1 starting on cylinder 0 (both will make you life easier)\n"); } doff = bswab16(sdl->ntrks) * bswab16(sdl->nsect) * bswab32(sdl->partitions[partno].start_cylinder); offset = bswab16(sdl->ntrks) * bswab16(sdl->nsect) * bswab32(sdl->partitions[0].start_cylinder); close (fd); if (offset) { if ((fd = open (device2, O_RDONLY)) == -1) fatal ("Cannot open superblock on %s", device2); if (check_fs (fd) != -1) sda1_offset = offset; close (fd); } } #define SECOND_B_TEMPL "%s___@#$%d___" void gpb_cleanup(char *filename, int n) { char buffer[1024]; int i; for (i = 1; i <= n; i++) { sprintf (buffer, SECOND_B_TEMPL, filename, i); unlink (buffer); } } int get_partition_blocks (char *device, char *filename) { int fd, fd2; int block, i, j, k; struct stat st; int movecount = 0; char buffer[1024]; char *name = filename; char *buf = NULL; int size; again: if ((fd = open (name, O_RDONLY)) == -1) { gpb_cleanup(filename, movecount); fatal ("Cannot find %s", name); } if (fstat (fd, &st) < 0) { gpb_cleanup(filename, movecount); fatal ("Couldn't stat %s", name); } #ifdef __linux__ if (!movecount) size = st.st_size; for (i = 0, j = 0;; i++) { block = i; if ((j << 9) >= size || ioctl (fd, FIBMAP, &block) < 0) break; if (!block) { if ((j << 9) < size) fatal ("Filesystem holes are not yet supported for second stage loader. Mail jj@sunsite.mff.cuni.cz"); else break; } if (block * nsect + doff >= 0x200000) { if (movecount < 5) { if (!movecount) { buf = malloc (size); if (!buf) fatal ("Not enough memory"); if (read (fd, buf, size) != size) fatal ("Cannot read from %s", filename); } close (fd); movecount++; sprintf (buffer, SECOND_B_TEMPL, filename, movecount); name = buffer; fd = creat (name, 0644); if (!fd || write (fd, buf, size) != size) { gpb_cleanup(filename, movecount); fatal ("Your %s is located above the magic 1GB boundary from the start of the disk.\n" "Please move it down, so that SILO first stage loader can load it.", filename); } close (fd); goto again; } gpb_cleanup(filename, movecount); fatal ("Your %s is located above the magic 1GB boundary from the start of the disk.\n" "Please move it down, so that SILO first stage loader can load it.", filename); } for (k = 0; k < nsect; k++) blocks[j++] = block * nsect + doff + k; } blocks[j] = 0; if (buf) free (buf); if (movecount) { if (rename (name, filename) < 0) { gpb_cleanup(filename, movecount - 1); fatal ("Cannot rename a suitably located copy (below 1GB from start of disk) of %s to it's old position.\n" "Please check %s\n", filename, filename); } gpb_cleanup(filename, movecount - 1); } #elif defined(__solaris__) ufs_blocks (device, st.st_ino); #endif close (fd); return 0; } char *new_root = NULL; char *chrootcpy (char *path) { if (new_root && *new_root) { char *buffer = malloc (strlen (new_root) + strlen (path) + 1); strcpy (buffer, new_root); if (new_root [strlen (new_root) - 1] != '/') strcat (buffer, path); else strcat (buffer, path + 1); return buffer; } else return strdup (path); } int get_cdrom_file (int i, char *filename) { #ifdef __linux__ int fd; int block; struct stat st; char *p = chrootcpy (filename); if ((fd = open (p, O_RDONLY)) == -1) { fatal ("Cannot find %s", filename); } free (p); block = 0; if (ioctl (fd, FIBMAP, &block) < 0 || !block) fatal ("Couldn't get block # of %s", filename); if (fstat (fd, &st) < 0) fatal ("Couldn't stat %s", filename); cd_files [2 * i] = block; cd_files [2 * i + 1] = st.st_size; close (fd); #endif return 0; } int get_cdrom_files (char *config_file) { int i; char *p = cdrom_list, *q; get_cdrom_file (0, config_file); for (i = 1; i < 31; i++) { q = strchr (p, ','); if (!q) break; *q = 0; get_cdrom_file (i, p); p = q + 1; } if (i < 31) get_cdrom_file (i, p); } void write_block_device (char *device) { int fd, rc; __u32 tmp; unsigned char part; if ((fd = open (device, O_RDWR)) == -1) fatal ("Cannot open %s", device); if (lseek (fd, 1020, SEEK_SET) != 1020) fatal ("Seek error on %s", device); tmp = bswab32 (blocks[0]); rc = write (fd, &tmp, 4); if (rc != 4) fatal ("Couldn't write to %s", device); if (lseek (fd, DIGIT_OFFSET, SEEK_SET) != DIGIT_OFFSET) fatal ("Seek error on %s", device); part = zero_based_part + '0'; rc = write (fd, &part, 1); if (rc != 1) fatal ("Couldn't write to %s", device); if (lseek (fd, LETTER_OFFSET, SEEK_SET) != LETTER_OFFSET) fatal ("Seek error on %s", device); part = zero_based_part + 'a'; rc = write (fd, &part, 1); if (rc != 1) fatal ("Couldn't write to %s", device); close (fd); } void write_block_table (char *device, char *device2, char *filename, char *config_file, int partno) { int fd, rc, i; char buffer[260]; __u32 blks [sizeof (blocks) / 4]; __u32 *Blocks = blocks; __u32 cdrom_files [sizeof (cd_files) / 4]; int offset = 0; int tordonly = 0; if (cdrom_image) filename = device; if ((fd = open (filename, O_RDWR)) == -1) { if (!cdrom_image && (fd = open (filename, O_RDONLY)) >= 0) { close (fd); /* Maybe it is a not-yet-rw-ufs?? */ if ((fd = open (device, O_RDWR)) == -1) fatal ("Cannot open %s", device); tordonly = 1; } else fatal ("Cannot open %s", filename); } if (cdrom_image) offset = 512 * blocks [0]; if (!tordonly && lseek (fd, offset, SEEK_SET) != offset) fatal ("Cannot seek in %s", filename); #if BYTE_ORDER == 1234 for (i = 0; i < sizeof (blocks) / 4; i++) blks [i] = bswab32 (blocks[i]); if (cdrom_image) { for (i = 0; i < sizeof (cd_files) / 4; i++) cdrom_files [i] = bswab32 (cd_files[i]); memcpy (buffer + 12, cdrom_files, 248); } Blocks = blks; #else if (cdrom_image) memcpy (buffer + 12, cd_files, 248); #endif if (tordonly) { char *p = (char *)Blocks, *pend = p + sizeof (blocks); for (i = 0, rc = 0; p < pend; i++, p+=512) { if (lseek (fd, blocks [i] * 512, SEEK_SET) != blocks [i] * 512) fatal ("Cannot seek in %s", filename); rc += write (fd, p, 512); } } else rc = write (fd, Blocks, sizeof (blocks)); if (rc != sizeof (blocks)) fatal ("Couldn't write to %s", filename); if (tordonly) i = blocks [0x828/512] * 512 + 0x828 % 512; else i = 0x828 + offset; if (lseek (fd, i, SEEK_SET) != i) fatal ("Cannot seek in %s", filename); buffer[0] = 'L'; buffer[1] = partno; buffer[2] = zero_based_part; if (cdrom_image) strcpy (buffer + 4, "!cd0"); else { strncpy (buffer + 4, config_file, 255); buffer[259] = 0; } if (write (fd, buffer, 260) != 260) fatal ("Couldn't write to %s", filename); close (fd); write_block_device (device); if (!cdrom_image && sda1_offset != -1) write_block_device (device2); } void usage (char *s) { fprintf (stderr, "SILO " VERSION " Sparc Improved boot LOader\n" "Usage: %s [options]\n" "Options:\n" " -r root_path chroots into root_path (all paths relative to this)\n" " -b secondary use secondary as second stage loader instead of /boot/second.b\n" " -i primary install primary as first stage loader (instead of\n" " /boot/first.b). If -i is specified, your boot block will be\n" " always overwritten (by default only if it is not SILO or has\n" " wrong version)\n" " -C config specify alternate config file instead of /etc/silo.conf\n" " (your config file has to reside on the same physical disk as\n" " secondary - perhaps on different partitions - on that disk's\n" " bootblock will be primary installed)\n" " -S backup force saving your old bootblock into backup\n" " -s backup save your old bootblock only if backup doesn't exist yet\n" " -o backup save your old bootblock from 1st partition if sdX1 doesn't\n" " start on cylinder 0 and backup doesn't exist yet\n" " -O backup as -o, but force saving of 1st partition bootblock\n" " -p 0|2 force prom version to be 0 or 2 (default is auto-detection)\n" " -f force overwriting of bootblock\n" " -d print PROM device name of the bootblock on stdout\n" " -V show version\n" " -v print your PROM major version (0 or 2) and exit\n" " -c device/file image for silo-bootable cdrom preparation\n" " -l list list is comma separated list of files (relative to -r)\n" " which will be available through !cd1 - !cd30 from cd\n" " this switch makes sense with -c and -r only\n" ,s); exit (1); } int examine_bootblock (char *device, char *filename, int do_backup, int promver) { char buffer[512 * 15]; struct Block_Table *sbt; int fd, rc; FILE *fp; int ret = 0; if ((fd = open (device, O_RDONLY)) == -1) fatal ("Cannot open %s", device); if (lseek (fd, 512, 0) != 512) fatal ("Couldn't seek on %s", device); if (read (fd, buffer, sizeof (buffer)) != sizeof(buffer)) fatal ("Couldn't read your old bootblock"); close (fd); if (memcmp (buffer + 24, "SILO" VERSION, 7) || buffer[31] < '6' || buffer[31] > '9') ret = 1; if (do_backup) { if ((fp = fopen (filename, "w")) == NULL) fatal ("Cannot open file for saving backup of your bootblock"); if (rc = fwrite (buffer, 1, sizeof (buffer), fp) != sizeof (buffer)) fatal ("Couldn't write to %s backup of your bootblock", filename); fclose (fp); } return ret; } void install_first_stage (char *device, char *filename) { char buff[1024]; int rc; int fd; FILE *fp; struct sun_disklabel sdl; if ((fd = open (device, O_WRONLY)) == -1) fatal ("Couldn't open device %s for writing", device); if ((fp = fopen (filename, "r")) == NULL) fatal ("Couldn't open file %s", filename); rc = fread (buff, 1, cdrom_image ? 1024 : 512, fp); if ((!cdrom_image && rc != 512) || rc <= 0) fatal ("Couldn't read new silo bootblock from %s", filename); if (cdrom_image) { int i = ((cd_size + 511) >> 9), csum; unsigned short *ush; memcpy (&sdl, cdrom_label, 512); sdl.pcylcount = bswab16 ((i + 639) / 640); sdl.ncyl = bswab16 ((i + 639) / 640); sdl.partitions[0].num_sectors = i; for (csum = 0, ush = (unsigned short *)&sdl; ush < (unsigned short *)&(sdl.csum); csum ^= *ush++); sdl.csum = csum; if (write (fd, &sdl, 512) != 512) fatal ("Couldn't write to %s your new partition table", device); } else if (lseek (fd, 512, 0) != 512) fatal ("Couldn't seek on %s", device); if (write (fd, buff, rc) != rc) fatal ("Couldn't write to %s your new silo bootblock", device); close (fd); fclose (fp); } int get_prom_ver(int use_prom) { #ifdef __intel__ return 0; #elif defined(__linux__) FILE *f = fopen("/proc/cpuinfo","r"); int ver = -1; char buffer[1024]; char *p; if (f) { while (fgets(buffer, 1024, f)) { if (!strncmp (buffer, "promlib", 7)) { p = strstr (buffer, "Version "); if (p) { p += 8; if (*p == '0' || (*p >= '2' && *p <= '3')) { ver = *p - '0'; } } break; } } } if (ver == -1) fatal ("Couldn't determine your prom version number. Please use options\n" "-p0 (for version 0) and -p2 (for versions 2 and 3)"); return ver; #elif defined(__solaris__) int ver = -1; if (use_prom) ver = prom_getversion (); if (ver == -1) fatal ("Couldn't determine your prom version number. Please use options\n" "-p 0 (for version 0) and -p 2 (for versions 2 and 3)\n" "Your prom is probably version 0, if you use device names of type sd(0,3,0)\n" "and is probaly 2 if you use device names of type /iommu/sbus/espdma/esp/sd@3,0\n"); return ver; #endif } /* Canonicalize path, and return a new path. Do everything in situ. The new path differs from path in: Multiple `/'s are collapsed to a single `/'. Leading `./'s and trailing `/.'s are removed. Trailing `/'s are removed. Non-leading `../'s and trailing `..'s are handled by removing portions of the path. */ char *canonicalize_pathname (char *path) { int i, start; char stub_char; stub_char = (*path == '/') ? '/' : '.'; /* Walk along path looking for things to compact. */ i = 0; for (;;) { if (!path[i]) break; while (path[i] && path[i] != '/') i++; start = i++; /* If we didn't find any slashes, then there is nothing left to do. */ if (!path[start]) break; /* Handle multiple `/'s in a row. */ while (path[i] == '/') i++; if ((start + 1) != i) { strcpy (path + start + 1, path + i); i = start + 1; } /* Handle backquoted `/'. */ if (start > 0 && path[start - 1] == '\\') continue; /* Check for trailing `/'. */ if (start && !path[i]) { zero_last: path[--i] = '\0'; break; } /* Check for `../', `./' or trailing `.' by itself. */ if (path[i] == '.') { /* Handle trailing `.' by itself. */ if (!path[i + 1]) goto zero_last; /* Handle `./'. */ if (path[i + 1] == '/') { strcpy (path + i, path + i + 1); i = start; continue; } /* Handle `../' or trailing `..' by itself. Remove the previous ?/ part with the exception of ../, which we should leave intact. */ if (path[i + 1] == '.' && (path[i + 2] == '/' || !path[i + 2])) { while (--start > -1 && path[start] != '/'); if (!strncmp (path + start + 1, "../", 3)) continue; strcpy (path + start + 1, path + i + 2); i = start; continue; } } } if (!*path) { *path = stub_char; path[1] = '\0'; } return path; } char *find_dev(int number) { #ifdef __linux__ # define DEVNAME "/dev" #else # define DEVNAME "/dev/dsk" #endif DIR *dp; char *p; struct dirent *dir; static char name[PATH_MAX+1]; struct stat s; if (!number) return NULL; if ((dp = opendir(DEVNAME)) == NULL) return NULL; strcpy(name,DEVNAME "/"); p = strchr (name, 0); while (dir = readdir(dp)) { strcpy(p,dir->d_name); if (stat(name,&s) < 0) return NULL; if (S_ISBLK(s.st_mode) && s.st_rdev == number) return name; } return NULL; } char *find_bootpath (char *device) { static char buffer[2048]; int i, part; #ifdef __linux__ #ifdef __intel__ return 0; #else int fd; int id; /* For now assume there is only one SCSI HA in the machine */ if (!scsi) return 0; if (strncmp (device, "/dev/sd", 7) || device[7] < 'a' || device[7] > 'z' || (device[8] && !isdigit(device[8]))) return 0; fd = open (device, O_RDONLY); if (fd < 0) return 0; if (ioctl (fd, SCSI_IOCTL_GET_IDLUN, &i) < 0) return 0; id = i & 0xff; part = device[8] ? (device[8] - '1') : 0; close (fd); if (!promver) { sprintf(buffer, "sd(0,%d,%d)", id, part); return buffer; } else { char *p; sprintf(buffer, "/esp/sd@%d,0:%c", id, part + 'a'); p = prom_canon (buffer); if (!p) return 0; strcpy (buffer, p); return buffer; } #endif #elif defined (__solaris__) if (!promver) { if (strncmp (device, "/dev/dsk/c", 10) || strlen (device) != 17 || !isdigit(device[10]) || !isdigit(device[12]) || !isdigit(device[16])) return 0; sprintf(buffer, "sd(%d,%d,%d)", device[10] - '0', device[12] - '0', device[14] - '0'); return buffer; } else { i = readlink (device, buffer, 512); if (i < 0) return 0; buffer [i] = 0; if (strncmp(buffer, "../../devices/", 14)) return 0; return buffer + 13; } #endif } int main(int argc,char **argv) { char *name = NULL, *config_file, *install = NULL, *secondary, *backup, *backup2; int version = 0; struct stat st1, st2, st3; int fd; int force_backup = 0, force_backup2 = 0; int config_file_partno = 1; char bootdev[1024], spart[1024], bootdev2[1024]; int force = 0; int f; int print_device = 0; int use_prom = 0; int print_prom_version = 0; #ifndef __intel__ if (prom_init () >= 0) use_prom = 1; #endif config_file = DFL_CONFIG; backup = DFL_BACKUP; backup2 = DFL_BACKUP2; secondary = DFL_SECONDARY; new_root = NULL; name = *argv++; argc--; while (argc && **argv == '-') { argc--; if (argv[0][2] && argv[0][1] != 'p') usage(name); switch ((*argv++)[1]) { case 'b': if (!argc) usage(name); secondary = *argv++; argc--; break; case 'i': if (!argc) usage(name); install = *argv++; argc--; break; case 'c': if (!argc) usage(name); #ifndef __linux__ fatal("Please use Linux to build SILO bootable CDROMs"); #endif cdrom_image = *argv++; argc--; break; case 'p': if ((argv[-1])[2] == '0') promver = 0; else if ((argv[-1])[2] == '2') promver = 2; else if (argv[-1][2]) usage(name); else if (argc && **argv == '0') { promver = 0; argv++; argc--; } else if (argc && **argv == '2') { promver = 2; argv++; argc--; } else usage(name); break; case 'd': print_device = 1; break; case 'f': force = 1; break; case 'C': if (!argc) usage(name); config_file = *argv++; argc--; break; case 'S': if (!argc) usage(name); backup = *argv++; force_backup = 1; argc--; break; case 's': if (!argc) usage(name); backup = *argv++; argc--; break; case 'o': if (!argc) usage(name); backup2 = *argv++; argc--; break; case 'O': if (!argc) usage(name); backup2 = *argv++; force_backup2 = 1; argc--; break; case 'r': if (!argc) usage(name); new_root = *argv++; argc--; break; case 'l': if (!argc) usage(name); cdrom_list = *argv++; argc--; break; case 'V': version = 1; break; case 'v': print_prom_version = 1; break; default: usage(name); } } if (!cdrom_image && promver == -1) promver = get_prom_ver(use_prom); if (print_prom_version) { printf ("%d\n", promver); return 0; } if (!new_root) new_root = getenv("ROOT"); if ((!new_root && cdrom_image) || (!cdrom_image && *cdrom_list) || (cdrom_image && !*cdrom_list)) fatal ("When preparing a cdrom image, you have to specify -r with the path\n" "the cdrom image is mounted to, -c with the path of device/file which\n" "holds the image and -l with a comma separated list of files accessible\n" "via !cd1 - !cd30. Example:\n" "silo -r /mnt -c /dev/sda2 -l /vmlinux,/etc/welcome.msg,/initrd.image\n"); if (cdrom_image && (promver != -1 || force || strcmp (backup, DFL_BACKUP) || strcmp (backup2, DFL_BACKUP2))) fatal ("Options -p, -f, -s, -S, -o, -O are not suitable for making cdroms"); if (version) { fprintf(stderr, "SILO version " VERSION "\n"); return 0; } if (argc) usage(name); #ifdef __intel__ if (!cdrom_image) fatal ("intelsilo is suitable for making Sparc bootable CD-ROMS only.\n" "Use -r, -c and -l options for that or run intelsilo -? for help"); #endif secondary = chrootcpy (secondary); if (stat (secondary, &st1) < 0) fatal ("Cannot open second stage loader %s", secondary); if (cdrom_image) { strcpy (spart, cdrom_image); strcpy (bootdev, cdrom_image); #ifdef __linux__ } else if ((st1.st_dev >> 8) == 8) { sprintf (spart, "/dev/sd%c%c", ((st1.st_dev & 0xf0) >> 4) + 'a', (st1.st_dev & 0xf) + '0'); sprintf (bootdev2, "/dev/sd%c1", ((st1.st_dev & 0xf0) >> 4) + 'a'); strcpy (bootdev, spart); bootdev [8] = 0; scsi = 1; #endif } else { char *p = find_dev (st1.st_dev); if (!p) fatal ("Couldn't find out what device is second stage on"); strcpy (spart, p); strcpy (bootdev, p); strcpy (bootdev2, p); #ifdef __solaris__ if (strlen (p) == strlen ("/dev/dsk/c0t0d0s0")) { p = strchr (p, 0) - 2; if (*p == 's' && p[1] >= '0' && p[1] <= '7') { p = strchr (bootdev, 0) - 1; *p = '2'; p = strchr (bootdev2, 0) - 1; *p = '0'; scsi = 1; } } #endif } backup = chrootcpy (backup); backup2 = chrootcpy (backup2); if (!cdrom_image) config_file = chrootcpy (config_file); if (!cdrom_image && stat (config_file, &st2) >= 0) { #ifdef __linux__ if ((scsi && (st2.st_dev & (~0xf)) != (st1.st_dev & (~0xf))) || #elif defined(__solaris__) if ((scsi && (st2.st_dev & (~0x7)) != (st1.st_dev & (~0x7))) || #else # error "Unknown system" #endif (!scsi && st2.st_dev != st1.st_dev)) fatal ("Config file %s has to be on the %s device (on any partition there)", config_file, bootdev); else { char *p, *q, *r, c; char readlinkbuf[2048]; int len; char buffer[2048], buffer2[2048]; strcpy (buffer, config_file); for (p = buffer;;) { q = strchr (p, '/'); if (q) { c = *q; *q = 0; } else c = 0; if (lstat (*buffer ? buffer : "/", &st3) < 0) fatal ("Couldn't stat %s\n", config_file); if (st3.st_dev == st2.st_dev) { *q = c; config_file = q; break; } if (S_ISLNK(st3.st_mode)) { len = readlink (buffer, readlinkbuf, 2048); if (len < 0) fatal ("Couldn't readlink %s\n", config_file); readlinkbuf[len] = 0; if (*readlinkbuf == '/') { if (c) { r = readlinkbuf+len; if (readlinkbuf[len - 1] != '/') *r++ = '/'; strcpy (r, q + 1); } strcpy (buffer, readlinkbuf); p = buffer + 1; continue; } else { strcpy (buffer2, buffer); strcat (buffer2, "/"); strcat (buffer2, readlinkbuf); if (c) { strcat (buffer2, "/"); strcat (buffer2, q + 1); } strcpy (buffer, buffer2); p = buffer + 1; continue; } } else { *q = c; p = q + 1; if (!c) fatal ("Internal error\n"); } } } if (scsi) #ifdef __linux__ config_file_partno = (st2.st_dev & 0x0f); #elif defined(__solaris__) config_file_partno = (st2.st_dev & 7) + 1; #else # error "Unknown system" #endif else config_file_partno = 1; } if (backup && !force_backup) { if (stat (backup, &st2) < 0) force_backup = 1; } read_sb (spart, bootdev, bootdev2); if (sda1_offset == -1) force_backup2 = 0; else if (backup2 && !force_backup2) { if (stat (backup2, &st2) < 0) force_backup2 = 1; } if (!cdrom_image) f = examine_bootblock (bootdev, backup, force_backup, promver); if (cdrom_image || (sda1_offset != -1 && examine_bootblock (bootdev2, backup2, force_backup2, promver)) || f || install || force) { if (!install) install = chrootcpy (DFL_PRIMARY); else if (*install == '/') install = chrootcpy (install); install_first_stage (bootdev, install); if (!cdrom_image && sda1_offset != -1) install_first_stage (bootdev2, install); } get_partition_blocks (spart, secondary); if (cdrom_image) get_cdrom_files (config_file); write_block_table (bootdev, bootdev2, secondary, config_file, config_file_partno); sync(); #ifndef __intel__ if (scsi && use_prom) { char *p = find_bootpath (bootdev2); if (p) { if (print_device) printf ("%s\n", p); else { char *q, buffer[2048], *r; int differ = 0, i, j; if (!promver) { q = prom_getopt ("boot-from"); if (q) { strcpy (buffer, q); q = strchr (buffer, ')'); if (q) { q[1] = 0; q = buffer; if (strcmp (p, q)) differ = 1; } } } else { q = prom_getopt ("boot-device"); if (q) { strcpy (buffer, q); q = prom_canon (buffer); if (q) { if (strcmp (q, p)) { i = strlen (p); j = strlen (q); if (i != j + 2 || p[j] != ':' || p[j+1] != 'a') differ = 1; } } } } if (differ) { fprintf (stderr, "Warning: If you want to boot SILO, please check if you're booting" " from %s\n", p); } } } } #endif exit(0); } #ifdef __solaris__ static errcode_t std_open (const char *name, int flags, io_channel * channel); static errcode_t std_close (io_channel channel); static errcode_t std_set_blksize (io_channel channel, int blksize); static errcode_t std_read_blk (io_channel channel, unsigned long block, int count, void *data); static errcode_t std_write_blk (io_channel channel, unsigned long block, int count, const void *data); static errcode_t std_flush (io_channel channel); static struct struct_io_manager struct_std_manager = { EXT2_ET_MAGIC_IO_MANAGER, "linux I/O Manager", std_open, std_close, std_set_blksize, std_read_blk, std_write_blk, std_flush }; static ufs_filsys fs = NULL; static io_manager std_io_manager = &struct_std_manager; static int std_fd = 0; static unsigned int cbs = 1024; /* Block Size */ static errcode_t std_open (const char *name, int flags, io_channel * channel) { int partno; io_channel io; if (!name) return EXT2_ET_BAD_DEVICE_NAME; io = (io_channel) malloc (sizeof (struct struct_io_channel)); if (!io) return EXT2_ET_BAD_DEVICE_NAME; std_fd = open (name, O_RDONLY); if (std_fd < 0) fatal ("Cannot open %s", name); memset (io, 0, sizeof (struct struct_io_channel)); io->magic = EXT2_ET_MAGIC_IO_CHANNEL; io->manager = std_io_manager; io->name = (char *) malloc (strlen (name) + 1); strcpy (io->name, name); io->block_size = cbs; io->read_error = 0; io->write_error = 0; *channel = io; return 0; } static errcode_t std_close (io_channel channel) { close (std_fd); } static errcode_t std_set_blksize (io_channel channel, int blksize) { channel->block_size = cbs = blksize; } static errcode_t std_read_blk (io_channel channel, unsigned long block, int count, void *data) { int size; size = (count < 0) ? -count : count * cbs; if (lseek (std_fd, block * cbs, SEEK_SET) != block * cbs) fatal ("Cannot seek"); if (read (std_fd, data, size) != size) fatal ("Read error on block %d", block); return 0; } static errcode_t std_write_blk (io_channel channel, unsigned long block, int count, const void *data) { } static errcode_t std_flush (io_channel channel) { } static int ufs_block_idx = 0; static int ufs_blocks_dump (ufs_filsys fs, blk_t *block, int i, void *private) { int j; for (j = 0; j < nsect; j++) blocks [ufs_block_idx++] = *block * nsect + doff + j; return 0; } static int ufs_blocks (char *device, ino_t inode) { if (ufs_open (device, std_io_manager, &fs)) fatal ("Cannot open ufs filesystem containing second stage"); nsect = cbs / 512; if (ufs_block_iterate (fs, inode, ufs_blocks_dump, 0)) fatal ("Block iterating error on second stage"); blocks [ufs_block_idx] = 0; return 0; } #endif