Merge lp:~superm1/usb-creator/grub-support into lp:usb-creator

Proposed by Mario Limonciello
Status: Merged
Merged at revision: 323
Proposed branch: lp:~superm1/usb-creator/grub-support
Merge into: lp:usb-creator
Diff against target: 158 lines (+49/-19)
3 files modified
bin/usb-creator-helper (+28/-10)
debian/changelog (+2/-0)
usbcreator/install.py (+19/-9)
To merge this branch: bzr merge lp:~superm1/usb-creator/grub-support
Reviewer Review Type Date Requested Status
Colin Watson Pending
usb-creator hackers Pending
Review via email: mp+34504@code.launchpad.net

Description of the change

This adds early support for installing using grub rather than syslinux (when applicable) to avoid getting into the same situation as had happened with 10.10 changing syntax of the syslinux.cfg.

It makes an assumption that when grub is installed to CDs it will be installed in boot/grub/i386-pc. This assumption was based upon the way that EFI was implemented on AMD64 CDs for 10.10 that modules were in /boot/grub/x86_64-efi. If that's a bad assumption, this can be modified.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

On Thu, Sep 02, 2010 at 11:49:55PM -0000, Mario Limonciello wrote:
> It makes an assumption that when grub is installed to CDs it will be
> installed in boot/grub/i386-pc. This assumption was based upon the
> way that EFI was implemented on AMD64 CDs for 10.10 that modules were
> in /boot/grub/x86_64-efi. If that's a bad assumption, this can be
> modified.

I think this assumption is OK.

> - num = deviceobj.Get(device, 'partition-number',
> - dbus_interface=PROPS_IFACE)
> - try:
> - popen(['/sbin/parted', parent, 'set', str(num), 'boot', 'on'])
> - except USBCreatorProcessException:
> - # Don't worry about not being able to re-read the partition table.
> - # TODO: As this will still be a problem for KVM users, this should
> - # be fixed by unmounting all the partitions before we get to this
> - # point, then remounting the target partition after.
> - pass

We need the parted call for both syslinux and GRUB. Some BIOSes refuse
to boot from a device that doesn't have an active partition.

> + if bootloader == 'grub':
> + core = tempfile.mktemp()
> + popen(['grub-mkimage', '-p', '/boot/grub/i386-pc', '-o', core,
> + 'biosdisk', 'part_msdos', 'fat', 'ntfs'])

This creates a GRUB image based on the version of grub-pc that you have
installed, on the assumption that it will continue to work with the old
configuration file on the CD image. This is not necessarily a sound
assumption. It also hardcodes module names; the set chosen isn't likely
to change all that much, but I feel it's worth mentioning.

If you use the installed version of grub-pc, then you must also copy
over modules from the installed system. The ABI between core.img and
modules changes frequently.

> + popen(['/usr/sbin/grub-setup', '-d', '/', '-b', '/usr/lib/grub/i386-pc/boot.img',
> + '-c', core, parent])

Hardcoded path to grub-setup. Also surely this should be '-d
/usr/lib/grub/i386-pc' rather than using both -d and -b? '-d /' makes
no sense.

In general, I have to say that I'm kind of uneasy with this approach; I
think it will break just as much as syslinux has been breaking, if not
more. I have an alternative suggestion. When we switch to GRUB, we
should arrange that the very same core.img on the CD contains the
necessary modules to boot on USB sticks as well. We can then simply dd
the existing core.img into the space after the MBR, and not have to
worry about these interface issues.

lp:~superm1/usb-creator/grub-support updated
319. By Colin Watson

GTK frontend: don't grey out "Make Startup Disk" when the source is a
physical CD.

Revision history for this message
Mario Limonciello (superm1) wrote :

This should hopefully address all of the concerns that Colin raised (but Launchpad decided to eat).

lp:~superm1/usb-creator/grub-support updated
320. By Mario Limonciello

Grow support for installing GRUB to USB sticks if it's detected in the image
rather than isolinux.

Revision history for this message
Mario Limonciello (superm1) wrote :

I did a couple of tests with handcrafted boot.img and core.img files, and this appears to work properly for them using dd now.

Revision history for this message
Mario Limonciello (superm1) wrote :

After more testing i've merged this in today.

The boot.img was used as it existed on the system.
The handcrafted core.img was generated like this:

#grub-mkimage -c grub.cfg -o core.img biosdisk part_msdos fat search_fs_file iso9660

grub.cfg:
     search.file /boot/grub/i386-pc/grub.cfg root
     set prefix=($root)/boot/grub/i386-pc

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/usb-creator-helper'
2--- bin/usb-creator-helper 2010-04-01 13:11:48 +0000
3+++ bin/usb-creator-helper 2010-09-04 00:08:40 +0000
4@@ -18,6 +18,7 @@
5 import gobject
6 import dbus.service
7 import logging
8+import os
9 logging.basicConfig(level=logging.DEBUG)
10 from dbus.mainloop.glib import DBusGMainLoop
11 from usbcreator.misc import *
12@@ -67,15 +68,23 @@
13 self.polkit = None
14
15 # TODO return boolean success
16- @dbus.service.method(USBCREATOR_IFACE, in_signature='s', out_signature='',
17+ @dbus.service.method(USBCREATOR_IFACE, in_signature='ss', out_signature='',
18 sender_keyword='sender', connection_keyword='conn')
19- def InstallBootloader(self, device, sender=None, conn=None):
20- '''Installs syslinux to the partition boot code area and writes the
21+ def InstallBootloader(self, device, grub_location, sender=None, conn=None):
22+ '''Install a bootloader to the boot code area, either grub or syslinux.
23+
24+ The function takes a partition device file of the form /dev/sda1
25+ and an option grub_location argument for where grub is located
26+
27+ For GRUB, it's expected that GRUB already exists, all that is
28+ installed is the bootsector code from grub-setup.
29+
30+ For syslinux:
31+ Installs syslinux to the partition boot code area and writes the
32 syslinux boot code to the disk code area. The latter is done to
33 handle cases where a bootloader is accidentally installed to the
34- MBR, and to handle some buggy BIOSes.
35+ MBR, and to handle some buggy BIOSes.'''
36
37- The function takes a partition device file of the form /dev/sda1.'''
38
39 self.check_polkit(sender, conn, 'com.ubuntu.usbcreator.bootloader')
40 check_system_internal(device)
41@@ -87,17 +96,26 @@
42 udisks = dbus.Interface(udisks, DISKS_IFACE)
43 device = udisks.FindDeviceByDeviceFile(device)
44 deviceobj = bus.get_object(DISKS_IFACE, device)
45-
46- popen(['syslinux', '-f', device_file])
47+
48 # Find the parent of the partition.
49 parent = deviceobj.Get(device, 'partition-slave',
50 dbus_interface=PROPS_IFACE)
51 parentobj = bus.get_object(DISKS_IFACE, parent)
52 parent = parentobj.Get(parent, 'device-file',
53 dbus_interface=PROPS_IFACE)
54- # Write the syslinux MBR.
55- popen(['dd', 'if=/usr/lib/syslinux/mbr.bin', 'of=%s' % parent,
56- 'bs=446', 'count=1', 'conv=sync'])
57+
58+ if grub_location:
59+ #Expect that boot.img and core.img both pre-built in grub_location
60+ popen(['dd', 'if=%s' % os.path.join(grub_location, 'boot.img'), 'of=%s' % parent,
61+ 'bs=446', 'count=1', 'conv=sync'])
62+ popen(['dd', 'if=%s' % os.path.join(grub_location, 'core.img'), 'of=%s' % parent,
63+ 'bs=512', 'count=62', 'seek=1', 'conv=sync'])
64+ else:
65+ popen(['syslinux', '-f', device_file])
66+ # Write the syslinux MBR.
67+ popen(['dd', 'if=/usr/lib/syslinux/mbr.bin', 'of=%s' % parent,
68+ 'bs=446', 'count=1', 'conv=sync'])
69+
70 num = deviceobj.Get(device, 'partition-number',
71 dbus_interface=PROPS_IFACE)
72 try:
73
74=== modified file 'debian/changelog'
75--- debian/changelog 2010-09-03 16:10:16 +0000
76+++ debian/changelog 2010-09-04 00:08:40 +0000
77@@ -3,6 +3,8 @@
78 [ Mario Limonciello ]
79 * Mangle whether the 'ui' keyword is in syslinux.cfg based on the OS version.
80 (LP: #608382)
81+ * Grow support for installing GRUB to USB sticks if it's detected in the image
82+ rather than isolinux.
83
84 [ Colin Watson ]
85 * GTK frontend: don't grey out "Make Startup Disk" when the source is a
86
87=== modified file 'usbcreator/install.py'
88--- usbcreator/install.py 2010-08-31 18:33:45 +0000
89+++ usbcreator/install.py 2010-09-04 00:08:40 +0000
90@@ -185,7 +185,7 @@
91 if os.path.exists(ldlinux):
92 os.remove(ldlinux)
93
94- def install_bootloader(self):
95+ def install_bootloader(self, grub_location=None):
96 logging.debug('install_bootloader')
97 self.progress_pulse()
98 self.progress_message(_('Installing the bootloader...'))
99@@ -207,7 +207,7 @@
100 bus = dbus.SystemBus()
101 obj = bus.get_object('com.ubuntu.USBCreator',
102 '/com/ubuntu/USBCreator')
103- obj.InstallBootloader(self.device,
104+ obj.InstallBootloader(self.device, grub_location,
105 dbus_interface='com.ubuntu.USBCreator',
106 timeout=MAX_DBUS_TIMEOUT)
107 except dbus.DBusException:
108@@ -419,7 +419,6 @@
109 self.remove_extras()
110
111 self.initialize_progress_thread()
112- self.install_bootloader()
113
114 # Copy.
115
116@@ -476,8 +475,14 @@
117 # and line[1] (HH:MM:SS).
118 logging.debug('mkdir %s' % os.path.join(self.target, line[2]))
119 os.mkdir(os.path.join(self.target, line[2]))
120-
121- self.mangle_syslinux()
122+
123+ grub = os.path.join(self.target, 'boot', 'grub', 'i386-pc')
124+ if os.path.isdir(grub):
125+ self.install_bootloader(grub)
126+ else:
127+ self.install_bootloader()
128+ self.mangle_syslinux()
129+
130 self.create_persistence()
131 self.sync()
132
133@@ -507,8 +512,7 @@
134 self.check()
135
136 self.initialize_progress_thread()
137- self.install_bootloader()
138-
139+
140 self.progress_message(_('Copying files...'))
141 for dirpath, dirnames, filenames in os.walk(self.source):
142 sp = dirpath[len(self.source.rstrip(os.path.sep))+1:]
143@@ -542,8 +546,14 @@
144 if os.path.exists(targetpath):
145 os.unlink(targetpath)
146 self.copy_file(sourcepath, targetpath)
147-
148- self.mangle_syslinux()
149+
150+ grub = os.path.join(self.target, 'boot', 'grub', 'i386-pc')
151+ if os.path.isdir(grub):
152+ self.install_bootloader(grub)
153+ else:
154+ self.install_bootloader()
155+ self.mangle_syslinux()
156+
157 self.create_persistence()
158 self.sync()
159

Subscribers

People subscribed via source and target branches