From 54291d325c2eec72ff56ce283398bcf6b3e12361 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Sat, 26 Oct 2013 21:38:20 +0200 Subject: [PATCH] Add support for building "foreign" images, ie non host arch images. This make it possible to use vmdebootstrap to create Raspberry Pi images. It add support for these new options: --bootsize size when not the defautl '0%', create /boot/ partition of the given size --boottype fstype file system type of /boot/ (default ext2) --foreign /path/to/binfmt_handler When set, use foreign support in debootstrap. --variant variant ask debootstrap to build variant, not the default base system. --no-extlinux skip installation of extlinux, depend on customize script to make image bootable. With this patch in place, I got a working Raspberry PI image by adding a small customize script to install the binary blob needed to boot the Raspberry Pi. --- vmdebootstrap | 85 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 11 deletions(-) diff --git a/vmdebootstrap b/vmdebootstrap index a7a67e1..1de3e56 100755 --- a/vmdebootstrap +++ b/vmdebootstrap @@ -37,6 +37,18 @@ class VmDebootstrap(cliapp.Application): 'create a disk image of size SIZE (%default)', metavar='SIZE', default='1G') + self.settings.bytesize(['bootsize'], + 'create boot partition of size SIZE (%default)', + metavar='BOOTSIZE', + default='0%') + self.settings.string(['boottype'], + 'specify file system type for /boot/', + default='ext2') + self.settings.string(['foreign'], + 'set up foreign debootstrap environment using provided program (ie binfmt handler)') + self.settings.string(['variant'], + 'select debootstrap variant it not using the default') + self.settings.boolean(['no-extlinux'], 'do not install extlinux') self.settings.string(['tarball'], "tar up the disk's contents in FILE", metavar='FILE') self.settings.string(['mirror'], @@ -98,9 +110,18 @@ class VmDebootstrap(cliapp.Application): self.create_empty_image() self.partition_image() self.install_mbr() - rootdev = self.setup_kpartx() + (rootdev,bootdev) = self.setup_kpartx() self.mkfs(rootdev) rootdir = self.mount(rootdev) + if bootdev: + if self.settings['boottype']: + fstype = self.settings['boottype'] + else: + fstype = 'ext2' + self.mkfs(bootdev, type=fstype) + bootdir = '%s/%s' % (rootdir, 'boot/') + os.mkdir(bootdir) + bootdir = self.mount(bootdev, bootdir) else: rootdir = self.mkdtemp() self.debootstrap(rootdir) @@ -114,8 +135,14 @@ class VmDebootstrap(cliapp.Application): self.setup_networking(rootdir) self.customize(rootdir) if self.settings['image']: - self.install_extlinux(rootdev, rootdir) + if not self.settings['no-extlinux']: + self.install_extlinux(rootdev, rootdir) self.optimize_image(rootdir) + + if self.settings['foreign']: + os.unlink('%s/usr/bin/%s' % + (rootdir, os.path.basename(self.settings['foreign']))) + if self.settings['tarball']: self.create_tarball(rootdir) except BaseException, e: @@ -149,9 +176,12 @@ class VmDebootstrap(cliapp.Application): logging.debug('mkdir %s' % dirname) return dirname - def mount(self, device): + def mount(self, device, path=None): self.message('Mounting %s' % device) - mount_point = self.mkdtemp() + if not path: + mount_point = self.mkdtemp() + else: + mount_point = path self.runcmd(['mount', device, mount_point]) self.mount_points.append(mount_point) logging.debug('mounted %s on %s' % (device, mount_point)) @@ -167,8 +197,14 @@ class VmDebootstrap(cliapp.Application): self.message('Creating partitions') self.runcmd(['parted', '-s', self.settings['image'], 'mklabel', 'msdos']) + if self.settings['bootsize'] and self.settings['bootsize'] is not '0%': + bootsize=str(self.settings['bootsize']/(1024*1024)) + self.runcmd(['parted', '-s', self.settings['image'], + 'mkpart', 'primary', 'fat16', '0', bootsize]) + else: + bootsize='0%' self.runcmd(['parted', '-s', self.settings['image'], - 'mkpart', 'primary', '0%', '100%']) + 'mkpart', 'primary', bootsize, '100%']) self.runcmd(['parted', '-s', self.settings['image'], 'set', '1', 'boot', 'on']) @@ -178,21 +214,35 @@ class VmDebootstrap(cliapp.Application): def setup_kpartx(self): out = self.runcmd(['kpartx', '-av', self.settings['image']]) + if self.settings['bootsize']: + bootindex = 0 + rootindex = 1 + parts = 2 + else: + rootindex = 0 + parts = 1 + boot = None devices = [line.split()[2] for line in out.splitlines() if line.startswith('add map ')] - if len(devices) != 1: + if len(devices) != parts: raise cliapp.AppException('Surprising number of partitions') - return '/dev/mapper/%s' % devices[0] + root = '/dev/mapper/%s' % devices[rootindex] + if self.settings['bootsize']: + boot = '/dev/mapper/%s' % devices[bootindex] + return (root,boot) - def mkfs(self, device): + def mkfs(self, device, type='ext2'): self.message('Creating filesystem') - self.runcmd(['mkfs', '-t', 'ext2', device]) + self.runcmd(['mkfs', '-t', type, device]) def debootstrap(self, rootdir): self.message('Debootstrapping') - necessary_packages = ['acpid'] + if self.settings['foreign']: + necessary_packages = [] + else: + necessary_packages = ['acpid'] include = self.settings['package'] @@ -210,9 +260,20 @@ class VmDebootstrap(cliapp.Application): args = ['debootstrap', '--arch=%s' % self.settings['arch']] args.append( '--include=%s' % ','.join(necessary_packages + include)) + if self.settings['foreign']: + args.append('--foreign') + if self.settings['variant']: + args.append('--variant') + args.append(self.settings['variant']) args += [self.settings['distribution'], rootdir, self.settings['mirror']] self.runcmd(args) + if self.settings['foreign']: + # First copy the binfmt handler over + shutil.copy(self.settings['foreign'], '%s/usr/bin/' % rootdir) + # Next, run the package install scripts etc. + self.runcmd(['chroot', rootdir, + '/debootstrap/debootstrap', '--second-stage']) def set_hostname(self, rootdir): hostname = self.settings['hostname'] @@ -380,8 +441,10 @@ append initrd=%(initrd)s root=UUID=%(uuid)s ro %(kserial)s self.message('Cleaning up') + # Umount in the reverse mount order if self.settings['image']: - for mount_point in self.mount_points: + for i in xrange(len(self.mount_points) - 1, -1, -1): + mount_point = self.mount_points[i] self.runcmd(['umount', mount_point], ignore_fail=True) self.runcmd(['kpartx', '-d', self.settings['image']], ignore_fail=True) -- 2.39.2