installgrub.c revision 79de7be6b61ea4069f6e2f0ad3fa5b4de2bb6409
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <malloc.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <libintl.h>
#include <locale.h>
#include "message.h"
#include <errno.h>
#include <libfdisk.h>
#include <md5.h>
#ifndef TEXT_DOMAIN
#define TEXT_DOMAIN "SUNW_OST_OSCMD"
#endif
#define SECTOR_SIZE 0x200
#define HASH_SIZE 0x10
#define VERSION_SIZE 0x50
#define STAGE1_BPB_OFFSET 0x3
#define STAGE1_BPB_SIZE 0x3B
#define STAGE1_BOOT_DRIVE 0x40
#define STAGE1_FORCE_LBA 0x41
#define STAGE1_STAGE2_ADDRESS 0x42
#define STAGE1_STAGE2_SECTOR 0x44
#define STAGE1_STAGE2_SEGMENT 0x48
static char extended_sig[] = "\xCC\xCC\xCC\xCC\xAA\xAA\xAA\xAA\xBB\xBB\xBB\xBB"
"\xBB\xBB\xBB\xBB";
static int nowrite = 0;
static int write_mboot = 0;
static int force_mboot = 0;
static int getinfo = 0;
static int do_version = 0;
static int is_floppy = 0;
static int is_bootpar = 0;
static int strip = 0;
static int stage2_fd;
static char *device_p0;
static char bpb_sect[SECTOR_SIZE];
static char boot_sect[SECTOR_SIZE];
static char stage1_buffer[SECTOR_SIZE];
static char verstring[VERSION_SIZE];
static unsigned int blocklist[SECTOR_SIZE / sizeof (unsigned int)];
static int open_device(char *);
static void read_bpb_sect(int);
static void read_boot_sect(char *);
static void write_boot_sect(char *);
static void read_stage1_stage2(char *, char *);
static void modify_and_write_stage1(int);
static void modify_and_write_stage2(int);
static unsigned int get_start_sector(int);
static void copy_stage2(int, char *);
static char *get_raw_partition(char *);
static void usage(char *);
static void print_info();
static int read_stage2_info(int);
static void check_extended_support();
extern int read_stage2_blocklist(int, unsigned int *);
int
{
(void) textdomain(TEXT_DOMAIN);
switch (opt) {
case 'm':
write_mboot = 1;
break;
case 'n':
nowrite = 1;
break;
case 'f':
force_mboot = 1;
break;
case 'i':
getinfo = 1;
params = 1;
break;
case 'e':
strip = 1;
break;
case 's':
do_version = 1;
optarg);
break;
default:
/* fall through to process non-optional args */
break;
}
}
/* check arguments */
}
if (nowrite) {
}
if (params == 1) {
if (!device) {
}
} else if (params == 3) {
}
}
/* open and check device type */
if (getinfo) {
if (read_stage2_info(dev_fd) != 0) {
" from %s\n", device);
exit(1);
}
print_info();
return (0);
}
/* read in stage1 and stage2 into buffer */
/* check if stage2 supports extended versioning */
if (do_version)
/* In the pcfs case, write a fresh stage2 */
if (is_floppy || is_bootpar) {
}
/* read in boot sector */
if (!is_floppy)
/* modify stage1 based on grub needs */
/* modify stage2 and write to media */
if (!is_floppy && write_mboot)
return (0);
}
static unsigned int
get_start_sector(int fd)
{
static unsigned int start_sect = 0;
struct extpart_info edkpi;
if (start_sect)
return (start_sect);
for (i = 0; i < FD_NUMPART; i++) {
if (is_bootpar) {
partition = i;
goto found_part;
}
}
}
/*
* We will not support x86 boot partition on extended partitions
*/
if (is_bootpar) {
exit(-1);
}
/*
* Not an x86 boot partition. Search for Solaris fdisk partition
* Get the solaris partition information from the device
* and compare the offset of S2 with offset of solaris partition
* from fdisk partition table.
*/
exit(-1);
} else {
}
}
for (i = 0; i < FD_NUMPART; i++) {
exit(-1);
}
/* Found the partition */
break;
}
}
if (i == FD_NUMPART) {
/* No solaris fdisk partitions (primary or logical) */
exit(-1);
}
/*
* We have found a Solaris fdisk partition (primary or extended)
* Handle the simple case first: Solaris in a primary partition
*/
partition = i;
goto found_part;
}
/*
* Solaris in a logical partition. Find that partition in the
* extended part.
*/
!= FDISK_SUCCESS) {
switch (rval) {
/*
* The first 2 cases are not an error per-se, just that
* there is no Solaris logical partition
*/
case FDISK_EBADLOGDRIVE:
case FDISK_ENOLOGDRIVE:
exit(-1);
/*NOTREACHED*/
case FDISK_ENOVGEOM:
exit(1);
break;
case FDISK_ENOPGEOM:
exit(1);
break;
case FDISK_ENOLGEOM:
exit(1);
break;
default:
exit(1);
break;
}
}
if (rval != FDISK_SUCCESS) {
/* No solaris logical partition */
exit(-1);
}
libfdisk_fini(&epp);
start_sect = secnum;
log_part = 1;
/* get confirmation for -m */
if (write_mboot && !force_mboot) {
if (getchar() != 'y') {
write_mboot = 0;
}
}
/*
* Currently if Solaris is in an extended partition we need to
* write GRUB to the MBR. Check for this.
*/
if (log_part && !write_mboot) {
exit(-1);
}
/*
* warn, if Solaris in primary partition and GRUB not in MBR and
* partition is not active
*/
}
return (start_sect);
}
static void
{
exit(-1);
}
static int
open_device(char *device)
{
int dev_fd;
char *raw_part;
/* handle boot partition specification */
is_bootpar = 1;
}
if (nowrite)
else
exit(-1);
}
exit(-1);
}
return (dev_fd);
}
static void
{
int fd;
/* read the stage1 file from filesystem */
exit(-1);
}
/* read first two blocks of stage 2 from filesystem */
if (stage2_fd == -1 ||
!= 2 * SECTOR_SIZE) {
exit(-1);
}
/* leave the stage2 file open for later */
}
static void
read_bpb_sect(int dev_fd)
{
exit(-1);
}
}
static void
read_boot_sect(char *device)
{
static int read_mbr = 0;
int i, fd;
char save[2];
if (read_mbr)
return;
read_mbr = 1;
/* get the whole disk (p0) */
if (fd == -1)
perror("open");
else
perror("read");
exit(-1);
}
}
static void
write_boot_sect(char *device)
{
/* make a copy and chop off ":boot" */
if (end)
end[2] = 0;
/* open p0 (whole disk) */
exit(-1);
}
if (!nowrite &&
exit(-1);
}
}
static void
{
if (is_floppy) {
stage2_first_sector = blocklist[0];
/* copy bios parameter block (for fat fs) */
} else if (is_bootpar) {
/* copy bios parameter block (for fat fs) and MBR */
} else {
/* copy MBR to stage1 in case of overwriting MBR sector */
}
/* modify default stage1 file generated by GRUB */
= STAGE2_MEMADDR >> 4;
/*
* XXX the default grub distribution also:
* - Set the boot drive of stage1
*/
if (!nowrite &&
exit(-1);
}
if (is_floppy) {
} else {
}
}
static void check_extended_support(char *stage2)
{
stage2);
do_version = 0;
}
}
static void print_info()
{
int i;
if (strip) {
} else {
}
for (i = 0; i < HASH_SIZE; i++)
}
static int
read_stage2_info(int dev_fd)
{
int ret;
int first_offset, second_offset;
char *sign;
if (is_floppy || is_bootpar) {
if (ret != SECTOR_SIZE) {
perror("Error reading stage1 sector");
return (1);
}
/* Start reading in the first sector of stage 2 */
if (ret != SECTOR_SIZE) {
perror("Error reading stage2 first sector");
return (1);
}
/* From the block list section grab stage2 second sector */
if (ret != SECTOR_SIZE) {
perror("Error reading stage2 second sector");
return (1);
}
} else {
perror("Error reading stage2 sectors");
return (1);
}
}
if (*sign++ != '\xEE')
return (1);
return (0);
}
static int
compute_and_write_md5hash(char *dest)
{
char *buffer;
return (-1);
return (-1);
return (-1);
return (-1);
return (0);
}
static void
{
int nrecord;
char *dest;
if (do_version) {
if (compute_and_write_md5hash(dest) < 0)
perror("MD5 operation");
}
if (is_floppy || is_bootpar) {
int i = 0;
stage2_first_sector = blocklist[0];
/* figure out the second sector */
blocklist[0]++;
blocklist[1]--;
} else {
i += 2;
}
if (is_floppy)
partition_offset = 0;
else /* solaris boot partition */
/* install the blocklist at the end of stage2_buffer */
while (blocklist[i]) {
exit(-1);
}
pos -= 8;
i += 2;
}
} else {
/*
* In a solaris partition, stage2 is written to contiguous
* blocks. So we update the starting block only.
*/
stage2_first_sector + 1;
}
if (is_floppy) {
/* modify the config file to add (fd0) */
while (*config_file++)
;
} else {
/* force lba and set disk partition */
*((long *)(stage2_buffer + STAGE2_INSTALLPART))
}
/* modification done, now do the writing */
if (is_floppy || is_bootpar) {
/* we rewrite block 0 and 1 and that's it */
if (!nowrite &&
exit(-1);
}
return;
}
/* for disk, write stage2 starting at STAGE2_BLKOFF sector */
/* write the modified first two sectors */
exit(-1);
}
/* write the remaining sectors */
nrecord = 2;
offset += 2;
for (;;) {
nrecord * SECTOR_SIZE);
offset * SECTOR_SIZE);
else
break;
}
if (nread > 0) {
nrecord ++;
offset ++;
}
if (nread < SECTOR_SIZE)
break; /* end of file */
}
}
static char *
get_raw_partition(char *device)
{
int len;
if (raw)
return (raw);
if (is_floppy)
return (raw);
if (is_bootpar) {
int i;
for (i = 0; i < FD_NUMPART; i++) {
break;
}
if (i == FD_NUMPART) {
exit(-1);
}
return (raw);
}
/* For disk, remember slice and return whole fdisk partition */
exit(-1);
}
return (raw);
}
#define TMP_MNTPT "/tmp/installgrub_pcfs"
static void
{
int i, pcfs_fp;
char buf[SECTOR_SIZE];
char *cp;
/* convert raw to block device name by removing the first 'r' */
exit(-1);
}
do {
} while (*(++cp));
/* get the mount point, if any */
exit(-1);
}
char cmd[128];
/* not mounted, try remount */
exit(-1);
}
}
if (pcfs_fp == -1) {
perror("open:");
exit(-1);
}
/* write stage2 to pcfs */
for (i = 0; ; i++) {
if (nowrite)
else
break;
}
if (nread < SECTOR_SIZE)
break; /* end of file */
}
/*
* Now, get the blocklist from the device.
*/
exit(-1);
}