prototype fast installer.
[invirt/packages/invirt-autoinstaller.git] / files / usr / sbin / sipb-xen-duplicate
diff --git a/files/usr/sbin/sipb-xen-duplicate b/files/usr/sbin/sipb-xen-duplicate
new file mode 100755 (executable)
index 0000000..fa24e23
--- /dev/null
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+import sys
+import os
+import shutil
+import tempfile
+from subprocess import call, Popen
+
+# TODO:
+# . pick a loop device sanely
+# - adapt size of partition to fit volume
+# - fix hostname, root password
+# - (once debugging diminishes) umount, losetup -d, maybe rm -r
+# - avoid race conditions with other loop-device users, too (somehow)
+# - get numbers from actual source partition table rather than
+#   as magic numbers based on what sipb-xen-make-iso does with etch.
+
+def losetup(source, offset=0):
+  # XXX we avoid colliding with other instances of ourself,
+  #     but when it comes to other loop-device users we just
+  #     pick a range things don't seem to use and hope...
+  lockfilename = '/tmp/losetup.lock'
+  os.close(os.open(lockfilename, os.O_CREAT+os.O_EXCL)) #lock
+  try:
+    loopdevice = None
+    for i in xrange(32,60): # totally arbitrary, just looks to be unused on black-mesa
+      filename = '/dev/loop%d'%i
+      if 0 == len(file(filename).read(1)):
+        loopdevice = filename # it's empty
+        break
+    if loopdevice is not None:
+      call(['losetup', '-o', str(offset), loopdevice, source])
+  finally:
+    os.unlink(lockfilename) #unlock
+  return loopdevice
+  # XX this means we can duplicate 9 at once.  since it takes around 30 seconds,
+  # this seems like an adequate capacity.
+
+def duplicate_lv(source, dest):
+  '''duplicate boot record, filesystem from LV source to LV dest
+  
+  source, dest should be device filenames.
+  '''
+  # XXX this is very specific to what the etch sipb-xen-make-iso installer does.
+  # XXXX also, it's specific to four gigs.
+  # step 1: copy the MBR
+  call(['dd', 'if='+source, 'bs=512', 'count=63', 'of='+dest])
+  # step 2: fix up partition table
+  # XX actually do this; this is our opportunity to resize the filesystem
+  # step 3: make the filesystem, and copy its contents in
+  sourcefs = losetup(source, 32256)
+  destfs = losetup(dest, 32256)
+  call(['mkfs.ext3', '-b', '4096', destfs, '987989'])
+  tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')
+  os.mkdir(tmptree+"/source")
+  call(['mount', '-t', 'ext3', '-o', 'ro', sourcefs, tmptree+"/source"])
+  os.mkdir(tmptree+"/dest")
+  call(['mount', '-t', 'ext3', destfs, tmptree+"/dest"])
+  call(['cp', '-aT', tmptree+"/source", tmptree+"/dest"])
+  # step 4: twiddle what we want to twiddle
+  # XX do this
+  # step 5: make the swap area
+  swapfs = losetup(dest, 4046870016)
+  call(['mkswap', swapfs, str(240943)])
+  # call(['losetup', '-d', swapfs])
+  print 'losetup -d '+swapfs
+  # step 6: clean up.
+  # XX actually unmount etc (leaving it is for debugging)
+  print 'umount '+tmptree+'/source'
+  call(['umount', tmptree+"/dest"]) # needed to flush writes
+  print 'losetup -d '+sourcefs
+  print 'losetup -d '+destfs
+
+if __name__ == '__main__':
+  duplicate_lv(*sys.argv[1:])