prototype fast installer.
[invirt/packages/invirt-autoinstaller.git] / files / usr / sbin / sipb-xen-duplicate
1 #!/usr/bin/env python
2
3 import sys
4 import os
5 import shutil
6 import tempfile
7 from subprocess import call, Popen
8
9 # TODO:
10 # . pick a loop device sanely
11 # - adapt size of partition to fit volume
12 # - fix hostname, root password
13 # - (once debugging diminishes) umount, losetup -d, maybe rm -r
14 # - avoid race conditions with other loop-device users, too (somehow)
15 # - get numbers from actual source partition table rather than
16 #   as magic numbers based on what sipb-xen-make-iso does with etch.
17
18 def losetup(source, offset=0):
19   # XXX we avoid colliding with other instances of ourself,
20   #     but when it comes to other loop-device users we just
21   #     pick a range things don't seem to use and hope...
22   lockfilename = '/tmp/losetup.lock'
23   os.close(os.open(lockfilename, os.O_CREAT+os.O_EXCL)) #lock
24   try:
25     loopdevice = None
26     for i in xrange(32,60): # totally arbitrary, just looks to be unused on black-mesa
27       filename = '/dev/loop%d'%i
28       if 0 == len(file(filename).read(1)):
29         loopdevice = filename # it's empty
30         break
31     if loopdevice is not None:
32       call(['losetup', '-o', str(offset), loopdevice, source])
33   finally:
34     os.unlink(lockfilename) #unlock
35   return loopdevice
36   # XX this means we can duplicate 9 at once.  since it takes around 30 seconds,
37   # this seems like an adequate capacity.
38
39 def duplicate_lv(source, dest):
40   '''duplicate boot record, filesystem from LV source to LV dest
41   
42   source, dest should be device filenames.
43   '''
44   # XXX this is very specific to what the etch sipb-xen-make-iso installer does.
45   # XXXX also, it's specific to four gigs.
46   # step 1: copy the MBR
47   call(['dd', 'if='+source, 'bs=512', 'count=63', 'of='+dest])
48   # step 2: fix up partition table
49   # XX actually do this; this is our opportunity to resize the filesystem
50   # step 3: make the filesystem, and copy its contents in
51   sourcefs = losetup(source, 32256)
52   destfs = losetup(dest, 32256)
53   call(['mkfs.ext3', '-b', '4096', destfs, '987989'])
54   tmptree = tempfile.mkdtemp('', 'auto-install.dup.', '/tmp')
55   os.mkdir(tmptree+"/source")
56   call(['mount', '-t', 'ext3', '-o', 'ro', sourcefs, tmptree+"/source"])
57   os.mkdir(tmptree+"/dest")
58   call(['mount', '-t', 'ext3', destfs, tmptree+"/dest"])
59   call(['cp', '-aT', tmptree+"/source", tmptree+"/dest"])
60   # step 4: twiddle what we want to twiddle
61   # XX do this
62   # step 5: make the swap area
63   swapfs = losetup(dest, 4046870016)
64   call(['mkswap', swapfs, str(240943)])
65   # call(['losetup', '-d', swapfs])
66   print 'losetup -d '+swapfs
67   # step 6: clean up.
68   # XX actually unmount etc (leaving it is for debugging)
69   print 'umount '+tmptree+'/source'
70   call(['umount', tmptree+"/dest"]) # needed to flush writes
71   print 'losetup -d '+sourcefs
72   print 'losetup -d '+destfs
73
74 if __name__ == '__main__':
75   duplicate_lv(*sys.argv[1:])