7 from subprocess import call, Popen
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.
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
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
31 if loopdevice is not None:
32 call(['losetup', '-o', str(offset), loopdevice, source])
34 os.unlink(lockfilename) #unlock
36 # XX this means we can duplicate 9 at once. since it takes around 30 seconds,
37 # this seems like an adequate capacity.
39 def duplicate_lv(source, dest):
40 '''duplicate boot record, filesystem from LV source to LV dest
42 source, dest should be device filenames.
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
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
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
74 if __name__ == '__main__':
75 duplicate_lv(*sys.argv[1:])