| /* silo - bootblock installation program |
| |
| Copyright (C) 1996 Maurizio Plaza |
| 1996,98,99,2000 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. */ |
| |
| #if !defined(VERSION) || !defined(IMGVERSION) |
| #error VERSION and IMGVERSION must be defined |
| #endif |
| #define DFL_CONFIG "/etc/silo.conf" |
| #define DFL_BACKUP "/boot/old.b" |
| #define DFL_PRIMARY "/boot/first.b" |
| #define DFL_PRIMARY_U "/boot/ultra.b" |
| #define DFL_SECONDARY "/boot/second.b" |
| |
| #ifdef __sun__ |
| #include "../second/fs/ufs.c" |
| #endif |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <features.h> |
| #include <unistd.h> |
| #include <sys/ioctl.h> |
| #ifdef __GLIBC__ |
| # include <sys/stat.h> |
| # include <sys/types.h> |
| # include <sys/time.h> |
| # define _LINUX_STAT_H |
| # define _LINUX_VFS_H |
| # define _LINUX_TIME_H |
| # define _LINUX_STRING_H_ |
| #endif |
| #ifdef __linux__ |
| # include <linux/fs.h> |
| # include <ext2fs/ext2_fs.h> |
| # include <ext2fs/ext2fs.h> |
| # include <scsi/scsi.h> |
| # include <sys/vfs.h> |
| # ifdef __GLIBC__ |
| # include <sys/sysmacros.h> |
| # define mmajor(x) major(x) |
| # define mminor(x) minor(x) |
| # define mmakedev(x,y) makedev(x,y) |
| # else |
| # define mmajor(x) (int)((x) >> 8) |
| # define mminor(x) (int)((x) & 0xff) |
| # define mmakedev(major, minor) (((major) << 8) | (minor)) |
| # endif |
| # include <md-int.h> |
| #elif defined (__sun__) |
| # include <sys/types.h> |
| # include <sys/stat.h> |
| # include <non-linux/ext2_fs.h> |
| # include <ext2fs/ext2fs.h> |
| # include "ufs.h" |
| # include <limits.h> |
| struct hwdevice; |
| static int ufs_blocks (struct hwdevice *, ino_t); |
| #else |
| # error "Unknown system" |
| #endif |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #include <sys/utsname.h> |
| #include <dirent.h> |
| #include <ctype.h> |
| #include "floppy.h" |
| #ifndef __intel__ |
| #include "prom.h" |
| #endif |
| #include "../first/first.h" |
| #include "../first/ultra.h" |
| #include "../first/fd.h" |
| #include "../first/ieee32.h" |
| |
| #define DIGIT_OFFSET (DIGIT_OFFSET_TMP + 0x223) |
| #define LETTER_OFFSET (LETTER_OFFSET_TMP + 0x223) |
| #define NUMBER_OFFSET (NUMBER_OFFSET_TMP + 0x223) |
| #define ULTRA_LETTER_OFFSET (ULTRA_LETTER_OFFSET_TMP + 0x223) |
| #define ULTRA_NUMBER_OFFSET (ULTRA_NUMBER_OFFSET_TMP + 0x223) |
| #define FD_DIGIT_OFFSET (FD_DIGIT_OFFSET_TMP + 0x223) |
| #define FD_LETTER_OFFSET (FD_LETTER_OFFSET_TMP + 0x223) |
| |
| /* Checks our config file for errors */ |
| int confcheck(char*); |
| char *cfg_get_strg (char *, char *); |
| int cfg_get_flag (char *, char *); |
| static int allow_confchk_fail = 0; |
| |
| /* This is just so that we don't have to fight with incompatible ufs_fs.h headers */ |
| #define SILO_UFS_MAGIC 0x00011954 |
| struct silo_ufs_super_block { |
| unsigned char xxx1[36]; |
| unsigned int fs_fsize; |
| unsigned char xxx2[1332]; |
| unsigned int fs_magic; |
| }; |
| |
| 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 */ |
| }; |
| |
| enum typeenum { TYPE_UNKNOWN, TYPE_SCSI, TYPE_IDE }; |
| |
| struct hwdevice { |
| char *wholedev; |
| char *dev; |
| enum typeenum type; |
| int id; |
| int part; |
| int partat0; |
| unsigned char nsect; |
| unsigned short bs; |
| unsigned long doff; |
| __u32 blocks[512]; |
| struct hwdevice *next; |
| } *hwdevs = NULL; |
| |
| __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) |
| |
| int ultra = 0; |
| int prombug = 1; /* Number of gigabytes PROM is able to boot from. if ultra, it is always inf. */ |
| int raid1 = 0; |
| int second_b_len; |
| int masterboot = 1; |
| int floppy_image = 0; /* Calculate cross checksums. */ |
| char *flash_image = NULL; /* Open this and calculate flash checksum. */ |
| char *first, *second, *old; /* File names */ |
| int promver = -1; |
| int oldroot = -1; |
| enum fs_type { unknownfs, ext2fs, ufsfs, romfs } fstype = unknownfs; |
| |
| static void silo_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 devopen (const char *name, int flags) |
| { |
| int fd = open (name, flags); |
| if (fd < 0 && errno == ENOENT) { |
| if (oldroot != -1) { |
| fchdir(oldroot); |
| if (*name == '/') name++; |
| fd = open (name, flags); |
| chdir("/"); |
| } |
| } |
| return fd; |
| } |
| |
| int check_fs (int fd) |
| { |
| struct silo_ufs_super_block ufs; |
| struct ext2_super_block sb; /* Super Block Info */ |
| struct romfs_super_block { |
| __u32 word0; |
| __u32 word1; |
| __u32 size; |
| __u32 checksum; |
| } rsd; |
| |
| if (lseek (fd, 1024, 0) != 1024 || read (fd, &sb, sizeof (sb)) != sizeof (sb)) |
| silo_fatal("Cannot read Super Block!"); |
| if (swab16 (sb.s_magic) == EXT2_SUPER_MAGIC) { |
| if (fstype == unknownfs) fstype = ext2fs; |
| return 1024 << swab32 (sb.s_log_block_size); |
| } |
| if (lseek (fd, 0, 0) != 0 || read (fd, &rsd, sizeof(rsd)) != sizeof (rsd)) |
| return -1; |
| if (!strncmp ((char *)&rsd, "-rom1fs-", 8)) { |
| if (fstype == unknownfs) fstype = romfs; |
| return 512; |
| } |
| if (lseek (fd, 8192, 0) != 8192 || read (fd, &ufs, sizeof (ufs)) != sizeof (ufs)) |
| return -1; |
| if (bswab32 (ufs.fs_magic) == SILO_UFS_MAGIC) { |
| if (fstype == unknownfs) fstype = ufsfs; |
| return ufs.fs_fsize; |
| } |
| return -1; |
| } |
| |
| void read_sb (struct hwdevice *hwdev) |
| { |
| int fd; |
| char buff[512]; |
| struct sun_disklabel *sdl; |
| char *p; |
| int i; |
| |
| hwdev->partat0 = 0; |
| if ((fd = devopen ((char *)hwdev->dev, O_RDONLY)) == -1) |
| silo_fatal("Cannot open superblock on %s", hwdev->dev); |
| hwdev->bs = check_fs (fd); |
| if (hwdev->bs == (unsigned short)-1) |
| silo_fatal("File systems other than ext2, ext3, ufs and romfs " |
| "not yet supported", hwdev->dev); |
| close (fd); |
| hwdev->nsect = hwdev->bs / 512; |
| if (hwdev->part == -1) |
| return; |
| sdl = (struct sun_disklabel *) &buff; |
| if ((fd = devopen (hwdev->wholedev, O_RDONLY)) == -1) |
| silo_fatal("Error opening %s", hwdev->wholedev); |
| if (read (fd, buff, sizeof (buff)) != sizeof (buff)) |
| silo_fatal("Error reading %s's label", hwdev->wholedev); |
| for (i = 0; i < 8; i++) { |
| if (i == 2) continue; |
| if (!sdl->partitions[i].start_cylinder && sdl->partitions[i].num_sectors) { |
| hwdev->partat0 = i; |
| #ifdef __linux__ |
| p = strchr (hwdev->wholedev, 0); |
| *p++ = '1' + hwdev->partat0; |
| *p = 0; |
| #endif |
| break; |
| } |
| } |
| if (i == 8 && !sdl->partitions[2].start_cylinder && sdl->partitions[2].num_sectors) { |
| i = 2; |
| hwdev->partat0 = 2; |
| #ifdef __linux__ |
| p = strchr (hwdev->wholedev, 0); |
| *p++ = '1' + hwdev->partat0; |
| *p = 0; |
| #endif |
| } |
| if (i == 8) { |
| for (i = 0; i < 8; i++) { |
| if (!sdl->partitions[i].start_cylinder) { |
| hwdev->partat0 = i; |
| break; |
| } |
| } |
| } |
| if (i == 8) { |
| silo_fatal("In order to install SILO you must start at least " |
| "one partition on cylinder\n" |
| "0. Consider setting %s3 as WHOLE_DISK (starting at 0 " |
| "and ending at disk end)\n" |
| "and %s1 starting on cylinder 0 (both will make your " |
| "life easier)\n", hwdev->wholedev, hwdev->wholedev); |
| } |
| hwdev->doff = bswab16(sdl->ntrks) * bswab16(sdl->nsect) * bswab32(sdl->partitions[hwdev->part].start_cylinder); |
| 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); |
| } |
| } |
| |
| void make_room_for_raid1 (struct hwdevice *hwdev, char *name) |
| { |
| char buf[512]; |
| int len, i; |
| int fd; |
| struct stat st; |
| |
| if (raid1 <= 1) |
| return; |
| if ((fd = open (name, O_RDWR)) == -1) |
| silo_fatal("Cannot open %s", name); |
| if (fstat (fd, &st) < 0) |
| silo_fatal("Couldn't stat %s", name); |
| if (lseek (fd, 0x90c, 0) != 0x90c || read(fd, buf, 12) != 12) |
| silo_fatal("Could not read %s version and length header", name); |
| if (memcmp (buf, "SILO", 4)) |
| silo_fatal("Second stage %s too old", name); |
| len = *(int *)&buf[8]; |
| if (len % 512 || st.st_size < len || (st.st_size - len) % 2048) |
| silo_fatal("Second stage %s has wrong size", name); |
| i = raid1 - 1 - (st.st_size - len) / 2048; |
| if (i > 0) { |
| if (lseek (fd, len, 0) != len) |
| silo_fatal("Could not seek in %s", name); |
| memset(buf, 0, 512); |
| /* Should not use ftruncate here, because we cannot have fs |
| holes in */ |
| for (i = 4 * i; i > 0; i--) { |
| if (write (fd, buf, 512) != 512) |
| silo_fatal("Could not write to %s", name); |
| } |
| } |
| second_b_len = len; |
| close (fd); |
| } |
| |
| int get_partition_blocks (struct hwdevice *hwdev, char *filename) |
| { |
| int fd; |
| int block, i, j, k; |
| struct stat st; |
| int movecount = 0; |
| char buffer[1024]; |
| char *name = filename; |
| char *buf = NULL; |
| int size = 0; |
| |
| again: |
| if ((fd = open (name, O_RDONLY)) == -1) { |
| gpb_cleanup(filename, movecount); |
| silo_fatal("Cannot find %s", name); |
| } |
| if (fstat (fd, &st) < 0) { |
| gpb_cleanup(filename, movecount); |
| silo_fatal("Couldn't stat %s", name); |
| } |
| #ifdef __linux__ |
| if (!movecount) |
| size = st.st_size; |
| if (fstype == romfs) { |
| char *p = strrchr (name, '/'); |
| long start; |
| if (p) p++; else p = name; |
| start = (long)st.st_ino + 16 + ((strlen(p) + 16) & ~15); |
| if (start & 511) |
| silo_fatal("File %s on romfs not aligned on 512B boundary. " |
| "Use genromfs -a to generate the image", name); |
| start = hwdev->doff + start / 512; |
| if (flash_image) start += 1024 / 512; /* make room for ieee32 */ |
| for (j = 0; j * 512 < size; j++) |
| hwdev->blocks[j] = start + j; |
| hwdev->blocks[j] = 0; |
| close(fd); |
| return 0; |
| } |
| for (i = 0, j = 0;; i++) { |
| block = i; |
| if ((j << 9) >= size || ioctl (fd, FIBMAP, &block) < 0) |
| break; |
| if (!block) { |
| if ((j << 9) < size) |
| silo_fatal("Filesystem holes are not yet supported for " |
| "second stage loader. Mail " |
| "silo-general@lists.sparc-boot.org"); |
| else |
| break; |
| } |
| if (prombug && block * hwdev->nsect + hwdev->doff >= 0x200000 * prombug) { |
| if (movecount < 5) { |
| if (!movecount) { |
| if (hwdev->id) |
| silo_fatal("Your %s is located above the " |
| "magic %dGB boundary from the " |
| "start of the disk\n" |
| "on one of the RAID1 mirrors. " |
| "Please make sure it is below the " |
| "limit on all\n" |
| "mirrors.", filename, prombug); |
| buf = malloc (size); |
| if (!buf) |
| silo_fatal("Not enough memory"); |
| if (read (fd, buf, size) != size) |
| silo_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); |
| silo_fatal("Your %s is located above the magic %dGB " |
| "boundary from the start of the disk.\n" |
| "Please move it down, so that SILO first " |
| "stage loader can load it.", |
| filename, prombug); |
| } |
| close (fd); |
| goto again; |
| } |
| gpb_cleanup(filename, movecount); |
| silo_fatal("Your %s is located above the magic %dGB boundary " |
| "from the start of the disk.\n" |
| "Please move it down, so that SILO first stage loader can load it.", filename, prombug); |
| } |
| for (k = 0; k < hwdev->nsect; k++) |
| hwdev->blocks[j++] = block * hwdev->nsect + hwdev->doff + k; |
| } |
| hwdev->blocks[j] = 0; |
| if (raid1 > 1) { |
| if (hwdev->id) { |
| if (!masterboot) { |
| /* As current RAID1 does not reserve any space for bootblocks, non-masterboot |
| would resync away the bootblock unless second.b starts on exactly the same |
| offsets in each device */ |
| if (memcmp (hwdevs->blocks, hwdev->blocks, sizeof(hwdev->blocks))) |
| silo_fatal("With silo -t on RAID1 all mirrors must " |
| "start at the same offset\n" |
| "from the start of the disk."); |
| } else |
| for (i = 0; i < 4; i++) |
| hwdev->blocks[i] = hwdev->blocks[second_b_len / 512 + (hwdev->id - 1) * 4 + i]; |
| } |
| } |
| if (buf) free (buf); |
| if (movecount) { |
| if (rename (name, filename) < 0) { |
| gpb_cleanup(filename, movecount - 1); |
| silo_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(__sun__) |
| ufs_blocks (hwdev, st.st_ino); |
| #endif |
| close (fd); |
| return 0; |
| } |
| |
| char *new_root = NULL; |
| |
| void write_block_device (struct hwdevice *hwdev) |
| { |
| int fd, rc; |
| int offset, off; |
| __u32 tmp; |
| unsigned char part; |
| |
| if ((fd = devopen (masterboot ? hwdev->wholedev : hwdev->dev, |
| O_RDWR)) == -1) |
| silo_fatal("Cannot open %s", hwdev->dev); |
| if (flash_image) off = IEEE32_OFFSET; |
| else if (floppy_image) off = 1020 + 512 - 4; |
| else off = 1020; |
| if (lseek (fd, off, SEEK_SET) != off) |
| silo_fatal("Seek error on %s", hwdev->dev); |
| if (floppy_image) { |
| int j; |
| for (j = 0; j < 512 && hwdev->blocks[j]; j++); |
| j *= 512; |
| tmp = bswab32 (j); |
| rc = write (fd, &tmp, 4); |
| if (rc != 4) |
| silo_fatal("Couldn't write to %s", hwdev->dev); |
| } |
| tmp = bswab32 (hwdev->blocks[0]); |
| rc = write (fd, &tmp, 4); |
| if (rc != 4) |
| silo_fatal("Couldn't write to %s", hwdev->dev); |
| if (!flash_image) { |
| if (!ultra || floppy_image) { |
| if (floppy_image) |
| offset = FD_DIGIT_OFFSET; |
| else |
| offset = DIGIT_OFFSET; |
| if (lseek (fd, offset, SEEK_SET) != offset) |
| silo_fatal("Seek error on %s", hwdev->dev); |
| part = hwdev->partat0 + '0'; |
| rc = write (fd, &part, 1); |
| if (rc != 1) |
| silo_fatal("Couldn't write to %s", hwdev->dev); |
| } |
| if (floppy_image) |
| offset = FD_LETTER_OFFSET; |
| else if (ultra) |
| offset = ULTRA_LETTER_OFFSET; |
| else |
| offset = LETTER_OFFSET; |
| if (lseek (fd, offset, SEEK_SET) != offset) |
| silo_fatal("Seek error on %s", hwdev->dev); |
| part = hwdev->partat0 + 'a'; |
| rc = write (fd, &part, 1); |
| if (rc != 1) |
| silo_fatal("Couldn't write to %s", hwdev->dev); |
| if (!floppy_image) { |
| if (ultra) |
| offset = ULTRA_NUMBER_OFFSET; |
| else |
| offset = NUMBER_OFFSET; |
| if (lseek (fd, offset, SEEK_SET) != offset) |
| silo_fatal("Seek error on %s", hwdev->dev); |
| part = 0; |
| if (raid1) |
| part = hwdev->id + 1; |
| rc = write (fd, &part, 1); |
| if (rc != 1) |
| silo_fatal("Couldn't write to %s", hwdev->dev); |
| } |
| } |
| close (fd); |
| } |
| |
| void write_block_tables (struct hwdevice *hwdev, char *filename, char *config_file, int partno) |
| { |
| int fd, rc, i; |
| struct { |
| unsigned char l; |
| unsigned char partno; |
| unsigned char partat0; |
| unsigned char raid_dsk_number; |
| char silo_conf[256]; |
| unsigned char silover[8]; |
| unsigned int len; |
| unsigned char partnos[32]; |
| unsigned char partat0s[32]; |
| } buffer; |
| int tordonly = 0; |
| struct hwdevice *d; |
| |
| if ((fd = open (filename, O_RDWR)) == -1) { |
| if (raid1) |
| silo_fatal("Cannot open %s", filename); |
| if ((fd = open (filename, O_RDONLY)) >= 0) { |
| close (fd); /* Maybe it is romfs */ |
| if ((fd = devopen (hwdev->wholedev, O_RDWR)) == -1) |
| silo_fatal("Cannot open %s", hwdev->wholedev); |
| tordonly = 1; |
| } else |
| silo_fatal("Cannot open %s", filename); |
| } |
| if (tordonly) { |
| char *p = (char *)hwdev->blocks, *pend = p + sizeof (hwdev->blocks); |
| |
| if (raid1) |
| silo_fatal("RAID1 not supported with read-only filesystems"); |
| for (i = 0, rc = 0; p < pend; i++, p+=512) { |
| if (lseek (fd, hwdev->blocks [i] * 512, SEEK_SET) != hwdev->blocks [i] * 512) |
| silo_fatal("Cannot seek in %s", filename); |
| rc += write (fd, p, 512); |
| } |
| } else { |
| if (lseek (fd, 0, SEEK_SET) != 0) |
| silo_fatal("Cannot seek in %s", filename); |
| rc = write (fd, hwdev->blocks, sizeof (hwdev->blocks)); |
| if (raid1 > 1) { |
| if (rc != sizeof (hwdev->blocks)) |
| silo_fatal("Couldn't write to %s", filename); |
| if (lseek (fd, second_b_len, SEEK_SET) != second_b_len) |
| silo_fatal("Cannot seek in %s", filename); |
| for (d = hwdev->next; d; d = d->next) |
| rc = write (fd, d->blocks, sizeof (d->blocks)); |
| } |
| } |
| if (rc != sizeof (hwdev->blocks)) |
| silo_fatal("Couldn't write to %s", filename); |
| if (tordonly) |
| i = hwdev->blocks [0x808/512] * 512 + 0x808 % 512; |
| else |
| i = 0x808; |
| if (lseek (fd, i, SEEK_SET) != i) |
| silo_fatal("Cannot seek in %s", filename); |
| if (read (fd, &buffer, sizeof(buffer)) != sizeof(buffer)) |
| silo_fatal("Couldn't read from %s", filename); |
| if (lseek (fd, i, SEEK_SET) != i) |
| silo_fatal("Cannot seek in %s", filename); |
| if (buffer.l != 'L' || memcmp(buffer.silover, "SILO", 4)) |
| silo_fatal("Corrupted %s or second stage with incorrect version", |
| filename); |
| buffer.partno = partno; |
| buffer.partat0 = hwdev->partat0; |
| buffer.raid_dsk_number = 0; |
| strncpy (buffer.silo_conf, config_file, 255); |
| buffer.silo_conf[255] = 0; |
| if (raid1) { |
| for (d = hwdev; d; d = d->next) { |
| buffer.partnos[d->id] = d->part + 1; |
| buffer.partat0s[d->id] = d->partat0; |
| } |
| } |
| if (write (fd, &buffer, sizeof(buffer)) != sizeof(buffer)) |
| silo_fatal("Couldn't write to %s", filename); |
| close (fd); |
| for (d = hwdev; d; d = d->next) |
| write_block_device (d); |
| } |
| |
| 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" |
| " -p 0|2 force prom version to be 0 or 2 (default is auto-detection)\n" |
| " -t store bootblock on the same partition as second stage loader\n" |
| " (default is into the bootblock of the whole disk)\n" |
| " -f force overwriting of bootblock\n" |
| " -V show version\n" |
| " -v print your PROM major version (0 or 2) and exit\n" |
| " -u force v9 (ultrasparc) target, even on v8\n" |
| " -U force v8 target, even on v9\n" |
| " -F make a romfs bootable floppy\n" |
| " -J image make a romfs bootable flash image\n" |
| " -J and -F are incompatible\n" |
| " -a Allow silo.conf syntax check to fail\n" |
| ,s); |
| exit (1); |
| } |
| |
| int examine_bootblock (char *device, char *filename, int do_backup) |
| { |
| char buffer[512 * 15]; |
| int fd, rc; |
| FILE *fp; |
| int ret = 0; |
| |
| if ((fd = devopen (device, O_RDONLY)) == -1) |
| silo_fatal("Cannot open %s", device); |
| if (lseek (fd, 512, 0) != 512) |
| silo_fatal("Couldn't seek on %s", device); |
| if (read (fd, buffer, sizeof (buffer)) != sizeof(buffer)) |
| silo_fatal("Couldn't read your old bootblock"); |
| close (fd); |
| if (memcmp (buffer + 24, "SILO" IMGVERSION, 8)) |
| ret = 1; |
| |
| if (do_backup) { |
| if ((fp = fopen (filename, "w")) == NULL) { |
| if (do_backup >= 2) |
| return ret; |
| silo_fatal("Cannot open file for saving backup of your bootblock"); |
| } |
| if ((rc = fwrite (buffer, 1, sizeof (buffer), fp)) != sizeof (buffer)) |
| silo_fatal("Couldn't write to %s backup of your bootblock", |
| filename); |
| fclose (fp); |
| } |
| return ret; |
| } |
| |
| void flash_check_sum (char *data, unsigned int dsize) |
| { |
| unsigned int sum; |
| |
| for (sum = 0; dsize-- != 0; data++) |
| sum += *((unsigned char *)data); |
| |
| data[0] = sum >> 24; |
| data[1] = sum >> 16; |
| data[2] = sum >> 8; |
| data[3] = sum; |
| } |
| |
| void install_first_stage (char *device, char *filename) |
| { |
| char buff[1024]; |
| int rc; |
| int fd; |
| FILE *fp; |
| struct sun_disklabel sdl; |
| |
| if ((fd = devopen (device, floppy_image ? O_RDWR : O_WRONLY)) == -1) |
| silo_fatal("Couldn't open device %s for writing", device); |
| if ((fp = fopen (filename, "r")) == NULL) |
| silo_fatal("Couldn't open file %s", filename); |
| rc = fread (buff, 1, (floppy_image || flash_image) ? 1024 : 512, fp); |
| if (rc <= 0) |
| silo_fatal("Couldn't read new silo bootblock from %s", filename); |
| if (floppy_image) { |
| unsigned short *ush; |
| unsigned short x; |
| unsigned int s, d; |
| int i; |
| |
| if (lseek (fd, 0, 0)) |
| silo_fatal("Couldn't seek on %s", device); |
| if (read(fd, (char *)&sdl, 512) != 512) |
| silo_fatal("Couldn't read on %s", device); |
| if (lseek (fd, 0, 0)) |
| silo_fatal("Couldn't seek on %s", device); |
| if (strncmp ((char *)&sdl, "-rom1fs-", 8)) |
| silo_fatal("Couldn't find romfs image on %s", device); |
| memcpy (((char *)&sdl) + 128, floppy_label + 128, 512 - 128); |
| ush = (unsigned short *)&sdl; |
| |
| /* This is a bit difficult, since we have to make two checksums right: |
| partition table expects xor of all u16 in the first 512 bytes to be 0, |
| romfs expects sum of all u32 in the first 512 bytes to be 0. |
| Algorithm written by Gert-jan Los (los@lsdb.bwl.uni-mannheim.de). */ |
| sdl.csum = 0xdead; /* Could be zero... */ |
| ush[6] = 0; ush[7] = 0; |
| memset (ush + 60, 0, 8); |
| for (i = 0, d = 0; i < 256; i+=2) |
| d += *(unsigned int *)(ush + i); |
| for (i = 0, x = 0; i < 256; i++) |
| x ^= ush[i]; |
| if (d & 1) |
| s = (x ^ 1) << 16 ^ 1; |
| else |
| s = x << 16; |
| *(unsigned int *)(ush + 6) = s; |
| d += s; |
| *(unsigned int *)(ush + 60) = (-d/2); |
| *(unsigned int *)(ush + 62) = (-d/2); |
| |
| if (write (fd, &sdl, 512) != 512) |
| silo_fatal("Couldn't write new partition table to %s", device); |
| } else if (flash_image) { |
| /* |
| * Make sure that both block table address and checksum fit. |
| */ |
| if (rc > 1016) |
| silo_fatal("Flash bootblock is too large"); |
| /* |
| * Here we do an assumption which is not quite safe. |
| * PROM gets the size looking at section headers, |
| * we use the file size for that. If there is any padding, |
| * these sizes will diverge. So far everything was ok. |
| */ |
| flash_check_sum (buff, rc); |
| rc += 4; |
| } else if (lseek (fd, 512, 0) != 512) |
| silo_fatal("Couldn't seek on %s", device); |
| if (write (fd, buff, rc) != rc) |
| silo_fatal("Couldn't write new silo bootblock to %s", device); |
| close (fd); |
| fclose (fp); |
| } |
| |
| int get_prom_ver(int use_prom) |
| { |
| #if 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'; |
| } |
| } |
| } else if (!strncmp (buffer, "prom", 4) && |
| isspace(buffer[4])) { |
| p = strchr (buffer, ':'); |
| if (p) { |
| p++; |
| while (isspace (*p)) p++; |
| switch (*p) { |
| case '2': if (p[1] == '.' && isdigit(p[2]) && |
| (p[2] >= '6' || isdigit(p[3]))) |
| prombug = 2; break; |
| case '3': prombug = 0; break; |
| } |
| } |
| } |
| } |
| } |
| return ver; |
| #elif defined(__sun__) |
| int ver = -1; |
| |
| if (use_prom) |
| ver = prom_getversion (); |
| 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(dev_t number) |
| { |
| #ifdef __linux__ |
| # define DEVNAME "/dev" |
| #else |
| # define DEVNAME "/dev/dsk" |
| #endif |
| DIR *dp; |
| char *p; |
| struct dirent *dir; |
| static char name[PATH_MAX+2]; |
| struct stat s; |
| char *ret = NULL; |
| int i; |
| |
| if (!number) return NULL; |
| for (i = 0; i < 2; i++) { |
| p = DEVNAME; |
| if (i == 1 && oldroot != -1) { |
| fchdir(oldroot); |
| p++; |
| } |
| if ((dp = opendir(p)) == NULL) continue; |
| strcpy(name + 1,p); |
| p = strchr (name + 1, 0); |
| *p++ = '/'; |
| while ((dir = readdir(dp))) { |
| strcpy(p,dir->d_name); |
| if (stat(name + 1,&s) < 0) continue; |
| if (S_ISBLK(s.st_mode) && s.st_rdev == number) { |
| ret = name + 1; |
| if (i == 1 && oldroot != -1) { |
| name[0] = '/'; |
| ret--; |
| } |
| break; |
| } |
| } |
| if (ret) break; |
| } |
| if (i && oldroot != -1) |
| chdir("/"); |
| return ret; |
| } |
| |
| struct hwdevice *get_device(int majno, int minno) |
| { |
| char dev[1024], wholedev[1024]; |
| struct hwdevice *hwdev; |
| int unit, part = -1; |
| enum typeenum type = TYPE_UNKNOWN; |
| switch (majno) { |
| #ifdef __linux__ |
| case 8: |
| case 65: |
| case 66: |
| case 67: |
| case 68: |
| case 69: |
| case 70: |
| case 71: |
| unit = (majno & 7) * 16 + ((minno & 0xf0) >> 4); |
| part = minno & 0xf; |
| if (unit < 26) { |
| sprintf (dev, "/dev/sd%c%c", unit + 'a', part + '0'); |
| strcpy (wholedev, dev); |
| wholedev [8] = 0; |
| } else { |
| sprintf (dev, "/dev/sd%c%c%c", (unit / 26) + 'a' - 1, (unit % 26) + 'a', part + '0'); |
| strcpy (wholedev, dev); |
| wholedev [9] = 0; |
| } |
| part--; |
| type = TYPE_SCSI; |
| break; |
| case 3: type = TYPE_IDE; unit = 0; goto do_ide; |
| case 22:type = TYPE_IDE; unit = 2; goto do_ide; |
| case 33: |
| case 34:type = TYPE_IDE; unit = 2*(majno - 33) + 4; |
| do_ide: |
| unit += ((minno & 64) >> 6); |
| part = (minno & 0x3f) - 1; |
| sprintf (dev, "/dev/hd%c%d", unit + 'a', part + 1); |
| strcpy (wholedev, dev); |
| wholedev [8] = 0; |
| break; |
| case 7: /* Loop device */ |
| unit = minno; |
| sprintf (dev, "/dev/loop%d", unit); |
| dev [1023] = 0; |
| strcpy (wholedev, dev); |
| break; |
| case 9: /* RAID device */ |
| { |
| md_array_info_t md_array_info; |
| md_disk_info_t md_disk_info; |
| int md_fd, i, id = 0; |
| struct hwdevice *d, *last; |
| |
| sprintf (dev, "/dev/md%d", minno); |
| md_fd = devopen (dev, O_RDONLY); |
| if (md_fd < 0) |
| silo_fatal("Could not open RAID device"); |
| if (ioctl (md_fd, GET_ARRAY_INFO, &md_array_info) < 0) |
| silo_fatal("Could not get RAID array info"); |
| if (md_array_info.major_version == 0 && md_array_info.minor_version < 90) |
| silo_fatal("Raid versions < 0.90 are not " |
| "supported"); |
| if (md_array_info.level != 1) |
| silo_fatal("Only RAID1 supported"); |
| hwdev = NULL; |
| last = NULL; |
| for (i = 0; i < md_array_info.raid_disks; i++) { |
| md_disk_info.number = i; |
| if (ioctl (md_fd, GET_DISK_INFO, &md_disk_info) < 0) |
| silo_fatal("Could not get RAID disk " |
| "info for disk %d\n", i); |
| if(md_disk_info.majorno != 0 && md_disk_info.minorno != 0) { |
| d = get_device (md_disk_info.majorno, md_disk_info.minorno); |
| if (md_disk_info.state == MD_DISK_FAULTY) { |
| printf ("disk %s marked as faulty, skipping\n", d->dev); |
| continue; |
| } |
| if (hwdev) |
| last->next = d; |
| else |
| hwdev = d; |
| while (d->next != NULL) d = d->next; |
| last = d; |
| } |
| } |
| if (!hwdev) |
| silo_fatal("No non-faulty disks found " |
| "in RAID1"); |
| for (d = hwdev; d; d = d->next) |
| d->id = id++; |
| raid1 = id; |
| close (md_fd); |
| return hwdev; |
| } |
| #endif |
| default: { |
| char *p = find_dev (makedev (majno, minno)); |
| |
| if (!p) |
| silo_fatal("Couldn't find out what device is second " |
| "stage on"); |
| strcpy (dev, p); |
| strcpy (wholedev, p); |
| #ifdef __sun__ |
| if (strlen (p) == strlen ("/dev/dsk/c0t0d0s0")) { |
| p = strchr (p, 0) - 2; |
| if (*p == 's' && p[1] >= '0' && p[1] <= '7') { |
| p = strchr (wholedev, 0) - 1; |
| *p = '2'; |
| type = TYPE_SCSI; |
| part = p[1] - '0'; |
| } |
| } |
| #endif |
| } |
| break; |
| } |
| hwdev = malloc(sizeof(struct hwdevice) + strlen(dev) + strlen(wholedev) + 4); |
| if (!hwdev) |
| silo_fatal("Not enough memory"); |
| memset(hwdev, 0, sizeof(*hwdev)); |
| hwdev->dev = (char *)(hwdev + 1); |
| strcpy (hwdev->dev, dev); |
| hwdev->wholedev = strchr(hwdev->dev, 0) + 2; |
| strcpy (hwdev->wholedev, wholedev); |
| hwdev->part = part; |
| hwdev->partat0 = -1; |
| hwdev->type = type; |
| return hwdev; |
| } |
| |
| int main(int argc,char **argv) |
| { |
| char *name = NULL, *config_file, *install = NULL, *secondary = NULL, *backup, *p; |
| struct utsname uts; |
| int version = 0; |
| struct stat st1, st2, st3; |
| int force_backup = 0; |
| int config_file_partno = 1; |
| int force = 0, f; |
| struct hwdevice *hwdev; |
| |
| int use_prom = 0; |
| int print_prom_version = 0; |
| |
| #ifdef __sun__ |
| if (prom_init () >= 0) |
| use_prom = 1; |
| #endif |
| if (uname (&uts) >= 0 && !strcmp (uts.machine, "sparc64")) |
| ultra = 1; |
| config_file = DFL_CONFIG; |
| backup = DFL_BACKUP; |
| 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 'F': |
| floppy_image = 1; |
| 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 '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 'r': |
| if (!argc) usage(name); |
| new_root = *argv++; |
| argc--; |
| break; |
| case 'V': |
| version = 1; |
| break; |
| case 't': |
| masterboot = 0; |
| break; |
| case 'v': |
| print_prom_version = 1; |
| break; |
| case 'u': |
| ultra = 1; |
| break; |
| case 'U': |
| ultra = 0; |
| break; |
| case 'J': |
| if (!argc) usage(name); |
| flash_image = *argv++; |
| argc--; |
| break; |
| case 'a': |
| allow_confchk_fail = 1; |
| break; |
| default: |
| usage(name); |
| } |
| } |
| if (promver == -1 && !ultra) |
| promver = get_prom_ver(use_prom); |
| else if (!ultra) |
| prombug = 1; |
| else |
| prombug = 0; |
| if (print_prom_version) { |
| if (ultra) |
| printf("IEEE 1275\n"); |
| else |
| printf ("%d\n", promver); |
| return 0; |
| } |
| if (!new_root) new_root = getenv("ROOT"); |
| if (version) { |
| fprintf(stderr, "SILO version " VERSION "\n"); |
| return 0; |
| } |
| if (argc) usage(name); |
| if (floppy_image && flash_image) usage(name); |
| |
| if (flash_image) { |
| char *p, *q; |
| if (*flash_image == '/') { |
| p = malloc(strlen(flash_image) + 2); |
| strcpy(p, flash_image); |
| } else { |
| #ifdef __linux__ |
| q = getcwd(NULL, 0); |
| p = malloc(strlen(flash_image) + 3 + strlen(q)); |
| strcpy(p, q); |
| free(q); |
| #else |
| p = malloc(PATH_MAX + 3 + strlen(flash_image)); |
| getcwd(p, PATH_MAX); |
| #endif |
| strcat(p, "/"); |
| strcat(p, flash_image); |
| } |
| flash_image = p; |
| } |
| |
| if (new_root && strcmp("/", new_root)) { |
| if (stat (new_root, &st1) < 0 || !S_ISDIR(st1.st_mode)) { |
| silo_fatal("New root %s is not a directory", new_root); |
| } |
| oldroot = open("/", O_RDONLY); |
| chroot(new_root); |
| chdir("/"); |
| } |
| |
| /* This _must_ be done after chrooting */ |
| if (!confcheck(config_file) && !allow_confchk_fail) |
| return 1; |
| |
| /* Check for some values in the config that override defaults */ |
| if (cfg_get_flag(NULL, "partition-boot")) |
| masterboot = 0; |
| |
| if (!secondary) { |
| if (cfg_get_strg(NULL, "secondary")) |
| secondary = cfg_get_strg(NULL, "secondary"); |
| else |
| secondary = DFL_SECONDARY; |
| } |
| |
| secondary = strdup (secondary); |
| if (stat (secondary, &st1) < 0) |
| silo_fatal("Cannot open second stage loader %s", secondary); |
| hwdevs = get_device (mmajor(st1.st_dev), mminor(st1.st_dev)); |
| if (raid1 > 32) |
| silo_fatal("SILO supports at most 32 disks in the RAID1 array"); |
| if (raid1 && masterboot) { |
| struct hwdevice *d, *d1; |
| /* Check if we have to remove some RAID1 mirrors, because |
| we can support only one RAID1 mirror per physical device |
| if masterboot. */ |
| for (d = hwdevs; d; d = d->next) |
| for (d1 = d; d1->next; d1 = d1->next) |
| if (!strcmp (d->wholedev, d1->next->wholedev)) { |
| d1->next = d1->next->next; |
| raid1--; |
| } |
| } |
| if (flash_image) { |
| /* |
| * The filesystem starts at offset 1024 into the flash. This |
| * makes it impossible to patch the first stage through /dev/loopN. |
| * We use argument to -J as a way to access the whole flash image. |
| * |
| * XXX There is no good way to ensure that argument to -J |
| * is what we have mounted off a loopback or a ramdisk. |
| * So we do not bother trying. |
| */ |
| if (raid1) |
| silo_fatal("-J cannot be used with RAID1"); |
| hwdevs->wholedev = flash_image; |
| } |
| p = backup; |
| backup = malloc (strlen(backup) + 20); |
| config_file = strdup (config_file); |
| strcpy (backup, p); |
| if (!backup || !config_file) |
| silo_fatal("Not enough memory"); |
| if (stat (config_file, &st2) >= 0) { |
| if (raid1 && st1.st_dev != st2.st_dev) |
| silo_fatal("Config file %s has to be on the same RAID1 device " |
| "as second stage bootblock", config_file); |
| else if (hwdevs->type == TYPE_UNKNOWN && st1.st_dev != st2.st_dev) |
| silo_fatal("Config file %s has to be on the %s device", |
| config_file, hwdevs->dev); |
| #ifdef __linux__ |
| else if ((hwdevs->type == TYPE_SCSI && (mmajor(st2.st_dev) != mmajor(st1.st_dev) || (mminor(st2.st_dev) & (~0xf)) != (mminor(st1.st_dev) & (~0xf)))) || |
| (hwdevs->type == TYPE_IDE && (mmajor(st2.st_dev) != mmajor(st1.st_dev) || (mminor(st2.st_dev) & (~0x3f)) != (mminor(st1.st_dev) & (~0x3f))))) |
| #elif defined(__sun__) |
| else if (hwdevs->type == TYPE_SCSI && (st2.st_dev & (~0x7)) != (st1.st_dev & (~0x7))) |
| #else |
| # error "Unknown system" |
| #endif |
| silo_fatal("Config file %s has to be on the %s device " |
| "(on any partition there)", config_file, |
| hwdevs->wholedev); |
| 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) |
| silo_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) |
| silo_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 { |
| r = strrchr (buffer, '/'); |
| memcpy (buffer2, buffer, r - buffer + 1); |
| strcpy (buffer2 + (r - buffer + 1), readlinkbuf); |
| if (c) { |
| strcat (buffer2, "/"); |
| strcat (buffer2, q + 1); |
| } |
| strcpy (buffer, buffer2); |
| p = buffer + 1; |
| continue; |
| } |
| } else { |
| *q = c; |
| p = q + 1; |
| if (!c) |
| silo_fatal("Internal error\n"); |
| } |
| } |
| } |
| if (raid1) |
| config_file_partno = -1; |
| else if (hwdevs->type == TYPE_SCSI) |
| #ifdef __linux__ |
| config_file_partno = (mminor(st2.st_dev) & 0x0f); |
| #elif defined(__sun__) |
| config_file_partno = (st2.st_dev & 7) + 1; |
| #else |
| # error "Unknown system" |
| #endif |
| #ifdef __linux__ |
| else if (hwdevs->type == TYPE_IDE) |
| config_file_partno = (mminor(st2.st_dev) & 0x3f); |
| #endif |
| else |
| config_file_partno = 1; |
| } |
| for (hwdev = hwdevs; hwdev; hwdev = hwdev->next) |
| read_sb (hwdev); |
| for (hwdev = hwdevs, f = 0; hwdev; hwdev = hwdev->next) { |
| int fb = force_backup; |
| |
| p = NULL; |
| if (raid1) { |
| p = strchr (backup, 0); |
| sprintf (p, "-raid1-%d", hwdev->id); |
| } |
| if (!force_backup) { |
| if (stat (backup, &st2) < 0) |
| fb = 2; |
| } |
| f |= examine_bootblock (masterboot ? hwdev->wholedev : hwdev->dev, backup, fb); |
| if (p) |
| *p = 0; |
| } |
| if (f || install || force) { |
| if (!install) |
| install = strdup (ultra ? DFL_PRIMARY_U : DFL_PRIMARY); |
| else if (*install == '/') |
| install = strdup (install); |
| for (hwdev = hwdevs; hwdev; hwdev = hwdev->next) |
| install_first_stage (masterboot ? hwdev->wholedev : hwdev->dev, install); |
| } |
| make_room_for_raid1(hwdevs, secondary); |
| for (hwdev = hwdevs; hwdev; hwdev = hwdev->next) |
| get_partition_blocks (hwdev, secondary); |
| write_block_tables (hwdevs, secondary, config_file, config_file_partno); |
| sync(); |
| exit(0); |
| } |
| |
| #ifdef __sun__ |
| |
| 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 = devopen (name, O_RDONLY); |
| if (std_fd < 0) |
| silo_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) |
| silo_fatal("Cannot seek"); |
| if (read (std_fd, data, size) != size) |
| silo_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; |
| struct hwdevice *hwdev = (struct hwdevice *)private; |
| for (j = 0; j < hwdev->nsect; j++) |
| blocks [ufs_block_idx++] = *block * hwdev->nsect + hwdev->doff + j; |
| return 0; |
| } |
| |
| static int ufs_blocks (struct hwdevice *hwdev, ino_t inode) |
| { |
| if (ufs_open (hwdev->dev, std_io_manager, &fs)) |
| silo_fatal("Cannot open ufs filesystem containing second stage"); |
| hwdev->nsect = cbs / 512; |
| if (ufs_block_iterate (fs, inode, ufs_blocks_dump, hwdev)) |
| silo_fatal("Block iterating error on second stage"); |
| blocks [ufs_block_idx] = 0; |
| return 0; |
| } |
| |
| #endif |