mkinitrd.py (5897B) - raw
1 #!/usr/bin/env python 2 3 import os 4 import sys 5 import tempfile 6 import shutil 7 import re 8 import subprocess 9 from glob import glob 10 11 def check_output(*args, **kwargs): 12 p = subprocess.Popen(*args, stdout=subprocess.PIPE, **kwargs) 13 out = p.communicate()[0] 14 if p.returncode != 0: 15 raise RuntimeError('Command %r exited with return code %r' 16 % (args[0], p.returncode)) 17 return out 18 19 install_set = dict() 20 21 class Dir(object): 22 def install_to(self, dest): 23 os.mkdir(dest) 24 25 class File(object): 26 def __init__(self, path): 27 self.path = path 28 def install_to(self, dest): 29 shutil.copy2(self.path, dest) 30 31 class Symlink(object): 32 def __init__(self, target): 33 self.target = target 34 def install_to(self, dest): 35 os.symlink(self.target, dest) 36 37 def install_dir(path): 38 install_set[path] = Dir() 39 40 def install_config(path): 41 install_set[path] = File(path) 42 43 def install_binary(path): 44 install_set[path] = File(path) 45 for line in check_output(['ldd', path]).splitlines(): 46 if re.match(r'\s*linux-vdso\.so', line): 47 continue 48 m = re.match(r'\s*(\S+) => (\S+)\s+\(0x', line) 49 if m: 50 lib = m.group(2) 51 else: 52 m = re.match(r'\s*(\S+)\s+\(0x', line) 53 lib = m.group(1) 54 install_set[os.path.realpath(lib)] = File(lib) 55 if os.path.islink(lib): 56 install_set[os.path.join(os.path.realpath(os.path.dirname(lib)), os.path.basename(lib))] \ 57 = Symlink(os.readlink(lib)) 58 59 def install_symlink(path, target): 60 install_set[path] = Symlink(target) 61 62 def install_tree(path): 63 for dirpath, dirnames, filenames in os.walk(path): 64 install_set[dirpath] = Dir() 65 for filename in filenames: 66 path = os.path.join(dirpath, filename) 67 install_set[path] = File(path) 68 69 def main(): 70 install_dir('/newroot') 71 install_dir('/sys') 72 install_dir('/proc') 73 install_dir('/dev') 74 install_dir('/run') 75 install_symlink('/lib', 'lib64') 76 install_binary('/bin/bash') 77 install_binary('/sbin/udevd') 78 install_binary('/sbin/udevadm') 79 install_config('/etc/mdadm.conf') 80 install_binary('/sbin/mdadm') 81 for binary in glob('/sbin/fsck*'): 82 install_binary(binary) 83 install_binary('/sbin/dmsetup') 84 install_binary('/sbin/blkid') 85 install_binary('/sbin/lvm') 86 for program in ['lvchange', 'lvconvert', 'lvcreate', 'lvdisplay', 87 'lvextend', 'lvmchange', 'lvmdiskscan', 'lvmsadc', 'lvmsar', 'lvreduce', 88 'lvremove', 'lvrename', 'lvresize', 'lvs', 'lvscan', 'pvchange', 'pvck', 89 'pvcreate', 'pvdisplay', 'pvmove', 'pvremove', 'pvresize', 'pvs', 'pvscan', 90 'vgcfgbackup', 'vgcfgrestore', 'vgchange', 'vgck', 'vgconvert', 'vgcreate', 91 'vgdisplay', 'vgexport', 'vgextend', 'vgimport', 'vgmerge', 'vgmknodes', 92 'vgreduce', 'vgremove', 'vgrename', 'vgs', 'vgscan', 'vgsplit']: 93 install_symlink('/sbin/%s' % program, 'lvm') 94 install_binary('/usr/bin/cat') 95 install_binary('/usr/bin/ls') 96 install_binary('/usr/bin/ln') 97 install_binary('/usr/bin/ed') 98 install_binary('/usr/bin/less') 99 install_binary('/usr/bin/mkdir') 100 install_binary('/bin/pidof') 101 install_binary('/bin/mount') 102 install_binary('/bin/umount') 103 install_binary('/sbin/switch_root') 104 install_tree('/lib64/udev') 105 install_tree('/etc/udev') 106 107 tmpdir = tempfile.mkdtemp(prefix='mkinitrd') 108 print 'Building initrd in %s ...' % tmpdir 109 for path, obj in sorted(install_set.items(), 110 key=lambda (path, obj): (isinstance(obj, Symlink), path)): 111 print path 112 dest = tmpdir + path 113 if not os.path.exists(os.path.dirname(dest)): 114 os.makedirs(os.path.dirname(dest)) 115 obj.install_to(dest) 116 open(tmpdir + '/init', 'w').write('''#!/bin/bash 117 118 export PATH=/sbin:/usr/bin:/bin 119 export EDITOR=ed 120 121 function edo() { 122 [ -e /dev/kmsg ] && echo "initrd: $*" >/dev/kmsg 123 $* 2>&1 >/dev/kmsg || ( echo "Bailing..." ; exec /bin/bash ) 124 } 125 126 # mount important stuff 127 edo mount -n -t devtmpfs -o mode=0755 udev /dev 128 edo mkdir /dev/shm /dev/pts 129 edo mkdir -p -m 0755 /dev/.udev/rules.d 130 edo mount -n -t devpts -o gid=5,mode=620 devpts /dev/pts 131 edo mount -n -t tmpfs tmpfs /dev/shm 132 edo mount -n -t sysfs none /sys 133 edo mount -n -t proc none /proc 134 cmdline=$(cat /proc/cmdline) 135 edo mount -n -t tmpfs tmpfs /run 136 137 # let udev do its thing 138 edo udevd --daemon --resolve-names=never 139 edo udevadm settle 140 141 # set up some nice block devices to mount 142 edo mdadm --quiet --assemble --scan 143 edo vgchange -a y 144 145 # pass fixme in kernel args to get a shell for fixing things 146 for arg in $cmdline ; do 147 if [[ "$arg" == fixme ]] ; then 148 ( export PS1='fixme$ ' ; bash ) 149 break 150 fi 151 done 152 153 # the important bit: mount root, and /usr if defined 154 root_mounted="" 155 for arg in $cmdline ; do 156 if [[ "$arg" == root=* ]] ; then 157 edo fsck -a "${arg:5}" 158 edo mount -n -r "${arg:5}" /newroot 159 root_mounted="true" 160 break 161 fi 162 done 163 edo [ $root_mounted ] 164 ( while read -r dev mountpoint type opts rest ; do 165 if [[ "$dev" != \#* ]] && [[ "$mountpoint" == /usr ]] ; then 166 edo fsck -a "$dev" 167 edo mount -n -r -t "$type" -o "$opts" "$dev" /newroot/usr 168 break 169 fi 170 done ) </newroot/etc/fstab 171 172 # clean up 173 edo udevadm control --exit 174 edo umount -n /dev/pts 175 edo umount -n /dev/shm 176 edo mount --move /run /newroot/run 177 178 # sanity check 179 edo [ -x /newroot/sbin/init ] 180 181 # switch to the new root 182 edo exec switch_root /newroot /sbin/init $cmdline 183 ''') 184 os.chmod(tmpdir + '/init', 0755) 185 186 image = '/boot/initramfs.img' 187 print 'Writing image to %s' % image 188 subprocess.check_call('find . | cpio --quiet -o -H newc | gzip -9', 189 stdout=open(image, 'w'), shell=True, cwd=tmpdir) 190 191 shutil.rmtree(tmpdir) 192 193 if __name__ == '__main__': 194 main()