From d4ceab0aa7ece6ab924f18f7275aae70645c4df6 Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Sun, 21 Apr 2013 11:03:11 +0000 Subject: Install GRUB --- install | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 163 insertions(+), 20 deletions(-) (limited to 'install') diff --git a/install b/install index bb2eec0..a1d8bb4 100755 --- a/install +++ b/install @@ -12,13 +12,14 @@ from __future__ import print_function from DysonInstaller.hdd import HDD from DysonInstaller.snack import * +from DysonInstaller.Network import * from snack import * from subprocess import Popen, PIPE, call from pprint import pprint from tempfile import mkstemp, mkdtemp from urllib2 import urlopen, URLError, HTTPError from time import sleep -from os.path import basename +from os.path import basename, exists import os import re import sys @@ -27,6 +28,9 @@ import math # Snack screen screen = None +# Physical network interfaces +physlinks = [] + # List of disks installed on the system: hdds = [] @@ -40,12 +44,20 @@ imported_zpools = [] rpool = None # Name of the root slice, where ZFS root pool will be created (e. g. c0t0d0s0) +# Used for installing GRUB rslice = None +# Object, describing solaris partition +solaris_partition = None + +# XXX rslice and solaris_partition aare known only +# on new clean installations, so we allow installing GRUB +# only on new installations + # Created boot environment, e. g. rpoot/ROOT/osdy-0 bootenv = None -# Install root dir +# Install root dir, mount point for bootenv rootdir = None # Version to install: @@ -62,6 +74,26 @@ mirrors = [ ('http://mirror-us.osdyson.org/apt/', 'USA'), ] +# Top of /rpool/boot/grub/menu.lst, if creating new file: +grub_top = r''' +foreground 343434 +background F7FbFF +default 0 +timeout 5 +''' + +# Entry in /rpool/boot/grub/menu.lst for newly created boot environment +# This string must be formatted. +# 0 is the partition number, +# a is the slice number; both are not used +grub_entry = r''' +title Dyson at {bootenv} +findroot (pool_{rpool},0,a) +bootfs {bootenv} +kernel$ /platform/i86pc/kernel/amd64/unix -B $ZFS-BOOTFS +module$ /platform/i86pc/amd64/boot_archive +''' + # Stages of debootstraping in order. Debootstrap gives # progress for each stage, but we need entire progress. @@ -294,7 +326,7 @@ def zfs_create(fs, zvol=None, options={}): out, err = zfs_cmd.communicate() if 0 != zfs_cmd.returncode: ButtonChoiceWindow(screen, - title='Creating of ZFS dataset failed', + title='Creating of ZFS filesystem failed', text=err, buttons = ['Ok'], width=70) return False return True @@ -347,9 +379,10 @@ def configure_zfs(): zfs_create(p, options=fs['options']) progress.advance() + # Will rollback if debootstrap fails call(['zfs', 'snapshot', '-r', bootenv + '@empty']) -def choose_hdd(number_of_zpools = 0): +def choose_hdd(number_of_zpools=0): hdd_items = map(lambda x: '{}: {} {}'.format(x.name, x.capacity, x.description), hdds) choice = None @@ -382,7 +415,8 @@ def choose_hdd(number_of_zpools = 0): return None raise Abort('HDD choosing') -def configure_partitions(hdd, number_of_disks = 1): +def configure_partitions(hdd, number_of_disks=1): + global solaris_partition choice = None top_text = 'For the root ZFS pool you need a disk containing a Solaris partition (id 0xbf). \ If this disk includes such a partition and you are happy with it, use this disk. \ @@ -394,8 +428,8 @@ will be used.' part_info += '\n\n' have_partitions = len(hdd.partitions) > 0 - have_solaris_partition = False have_gpt = False + solaris_partition = None buttons = [] if have_partitions: @@ -405,8 +439,8 @@ will be used.' n = 0 for p in hdd.partitions: n = n + 1 - if p.id == 0xBF: - have_solaris_partition = True + if p.id == 0xBF and solaris_partition == None: + solaris_partition = p if p.id == 0xEE: have_gpt = True part_info += '#{n:<2} {primary} {id:#04x} {system:25} {capacity:10}\n'.format( @@ -415,7 +449,7 @@ will be used.' else: part_info += 'This disk is not partitioned.\n' - if have_solaris_partition: + if solaris_partition != None: buttons.append(('Use this disk', 'ok')) if have_gpt: @@ -471,6 +505,26 @@ def get_mirror(): if choice == 'cancel': raise Abort('Entering an APT mirror') +def choose_physlink(): + pass + +def configure_network(): + global physlinks + if not physlinks: + physlinks = dladm_show_phys() + if not physlinks: + choice = ButtonChoiceWindow(screen, title='Network is unreachable', + text='No network interfaces found on this system. ' + 'This mean that public APT repositories cannot be used ' + 'to install Dyson.', + buttons=['Ok']) + return + while True: + if len(physlinks) > 1: + link = choose_physlink() + else: + link = physlinks[0] + break def valid_mirror(mirror): progress = ProgressMessage(screen, title='Please wait...', @@ -521,7 +575,7 @@ def configure_mirror(): for m in mirrors: if len(m[0]) > maxlen: maxlen = len(m[0]) - items = map(lambda x: '{url: <{0}} ({info})'.format(maxlen, url=x[0], info=x[1]), mirrors) + items = map(lambda x: '{url: <{0}} - {info}'.format(maxlen, url=x[0], info=x[1]), mirrors) items.append(('Enter another mirror', None)) mirror = None while not mirror: @@ -547,7 +601,7 @@ def configure_mirror(): def debootstrap(): progress = ProgressBar(screen, title='Installing base system, please wait...', - width=76) + width=70) progress.text = ' ' @@ -568,9 +622,9 @@ def debootstrap(): os.execl('/usr/sbin/debootstrap', 'debootstrap', '--debian-installer', '--no-check-gpg', '--exclude=gawk,aptitude,aptitude-common,libboost-iostreams1.48.0,libboost-iostreams1.49.0,libcwidget3', - '--include=illumos-grub,illumos-kernel,locales', + '--include=installgrub,illumos-grub,illumos-kernel,locales', codename, rootdir, mirror) - except OSError as e: + except EnvironmentError as e: sys.exit(e.errno) else: os.close(write) @@ -667,7 +721,9 @@ def umount_in_bootenv(): def in_bootenv(cmd): chroot = ['chroot', rootdir] chroot += cmd - return call(chroot, stderr=PIPE, stdout=PIPE) + pobject = Popen(chroot, stderr=PIPE, stdout=PIPE) + out, err = pobject.communicate() + return (pobject.returncode, out, err) def write_vfstab(): @@ -712,9 +768,6 @@ def configure_nodename(): except: pass -def configure_network(): - configure_nodename() - def configure_packages(): screen.suspend() call(['chroot', rootdir, '/usr/sbin/dpkg-reconfigure', 'tzdata', 'locales'], stderr=PIPE) @@ -750,12 +803,101 @@ def set_root_password(): def configure_bootenv(): write_vfstab() mount_in_bootenv() - in_bootenv(['/sbin/devfsadm']) + in_bootenv(['/usr/sbin/devfsadm']) configure_packages() - configure_network() + configure_nodename() set_root_password() create_bootarchive() +def configure_grub(): + entry = grub_entry.format(rpool=rpool, bootenv=bootenv) + # write grub menu for references: + try: + menu = open(rootdir + '/boot/grub/menu.lst', 'w') + print('# This file is just for references. It is not used by GRUB', file=menu) + print('# Actual menu.lst used by GRUB is {}/boot/grub/menu.lst'.format(rpool), file=menu) + print('# where {} is the name of root ZFS pool'.format(rpool), file=menu) + print(grub_top, file=menu) + print(entry, file=menu) + menu.close() + except: + pass + + items = [] + text = '' + if solaris_partition != None: # New installation: + items.append(('Install GRUB to MBR', 'mbr')) + text += 'Installing GRUB on the master boot sector (MBR) ' + text += 'overrides any boot manager currently installed: ' + text += 'the system will always boot the GRUB in the solaris partition' + if not solaris_partition.logical: + items.append(('Install GRUB to a partition only', 'partition')) + else: + text += 'It looks like root ZFS pool "{rpool}" was not created during this installation, '.format(rpool=rpool) + text += 'so installing GRUB is not supported. ' + text += 'You can only update GRUB menu, or completely skip ' + text += 'this step. Laterly you can configure GRUB using installgrub(1m) ' + text += 'utility and using /boot/grub/menu.lst as an example.' + items.append(('Only update GRUB menu', 'menu')) + items.append(('Do nothing', 'skip')) + button, install = ListboxChoiceWindow(screen, title='Configure GRUB', + text=text, items=items, buttons=['Ok'], width=50) + if install == 'skip': + return + rpool_path = '/mnt/{rpool}/{rpool}'.format(rpool=rpool) + try: + if not exists(rpool_path + '/boot'): + os.mkdir(rpool_path + '/boot') + if not exists(rpool_path + '/boot/grub'): + os.mkdir(rpool_path + '/boot/grub') + if not exists(rpool_path + '/boot/grub/bootsign'): + os.mkdir(rpool_path + '/boot/grub/bootsign') + if not exists(rpool_path + '/boot/grub/bootsign/pool_'+rpool): + open(rpool_path + '/boot/grub/bootsign/pool_'+rpool, 'w').close() + if not exists(rpool_path + '/boot/grub/menu.lst'): + menu = open(rpool_path + '/boot/grub/menu.lst', 'w') + print(grub_top, file=menu) + menu.close() + re_bootfs = re.compile(r'^bootfs\s+' + bootenv) + have_this_bootenv = False + menu = open(rpool_path + '/boot/grub/menu.lst', 'r+') + for line in menu: + if re_bootfs.match(line): + have_this_bootenv = True + break + if not have_this_bootenv: + print(entry, file=menu) + menu.close() + except EnvironmentError as e: + text = 'Failed to write GRUB configuration: ' + if e.filename: + text += e.filename + ': ' + text += e.strerror + ButtonChoiceWindow(screen, title='Error', + text=text, buttons=['Ok'], width=60) + if install == 'menu': + return + + # solaris_partition is not known - installing on existing pool, + # installing GRUB is not supported. + if solaris_partition == None: + return + + progress = ProgressMessage(screen, title='Installing GRUB', width=50) + installgrub_cmd = ['/usr/sbin/installgrub'] + if install == 'mbr': + progress.text = 'Installing GRUB to the master boot record...' + installgrub_cmd += ['-f', '-m'] + else: + progress.text = 'Installing GRUB to partition...' + + installgrub_cmd += ['/boot/grub/stage1', '/boot/grub/stage2', + '/dev/rdsk/' + rslice] + rc, out, err = in_bootenv(installgrub_cmd) + if rc != 0: + ButtonChoiceWindow(screen, title='Error', + text='Installing of GRUB failed: ' + err, buttons=['Ok'], width=60) + def cleanup(destroy_bootenv=False): global bootenv @@ -765,7 +907,7 @@ def cleanup(destroy_bootenv=False): umount_in_bootenv() call(['umount', rootdir], stdout=PIPE, stderr=PIPE) if destroy_bootenv: - progress.text='Destroying "{}", please wait ...'.format(bootenv) + progress.text='Destroying {}, please wait ...'.format(bootenv) call(['zfs', 'destroy', '-r', bootenv], stdout=PIPE, stderr=PIPE) else: progress.text = 'Adjusting boot environment "{}" ...'.format(bootenv) @@ -798,6 +940,7 @@ try: configure_zfs() install() configure_bootenv() + configure_grub() cleanup() goodbye() -- cgit v1.2.3