diff options
Diffstat (limited to 'scripts/lib/mic/imager/liveusb.py')
| -rw-r--r-- | scripts/lib/mic/imager/liveusb.py | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/scripts/lib/mic/imager/liveusb.py b/scripts/lib/mic/imager/liveusb.py new file mode 100644 index 0000000000..a909928a4c --- /dev/null +++ b/scripts/lib/mic/imager/liveusb.py | |||
| @@ -0,0 +1,308 @@ | |||
| 1 | #!/usr/bin/python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os | ||
| 19 | import shutil | ||
| 20 | import re | ||
| 21 | |||
| 22 | from mic import msger | ||
| 23 | from mic.utils import misc, fs_related, runner | ||
| 24 | from mic.utils.errors import CreatorError, MountError | ||
| 25 | from mic.utils.partitionedfs import PartitionedMount | ||
| 26 | from mic.imager.livecd import LiveCDImageCreator | ||
| 27 | |||
| 28 | |||
| 29 | class LiveUSBImageCreator(LiveCDImageCreator): | ||
| 30 | def __init__(self, *args): | ||
| 31 | LiveCDImageCreator.__init__(self, *args) | ||
| 32 | |||
| 33 | self._dep_checks.extend(["kpartx", "parted"]) | ||
| 34 | |||
| 35 | # remove dependency of genisoimage in parent class | ||
| 36 | if "genisoimage" in self._dep_checks: | ||
| 37 | self._dep_checks.remove("genisoimage") | ||
| 38 | |||
| 39 | def _create_usbimg(self, isodir): | ||
| 40 | overlaysizemb = 64 #default | ||
| 41 | #skipcompress = self.skip_compression? | ||
| 42 | fstype = "vfat" | ||
| 43 | homesizemb=0 | ||
| 44 | swapsizemb=0 | ||
| 45 | homefile="home.img" | ||
| 46 | plussize=128 | ||
| 47 | kernelargs=None | ||
| 48 | |||
| 49 | if fstype == 'vfat': | ||
| 50 | if overlaysizemb > 2047: | ||
| 51 | raise CreatorError("Can't have an overlay of 2048MB or " | ||
| 52 | "greater on VFAT") | ||
| 53 | |||
| 54 | if homesizemb > 2047: | ||
| 55 | raise CreatorError("Can't have an home overlay of 2048MB or " | ||
| 56 | "greater on VFAT") | ||
| 57 | |||
| 58 | if swapsizemb > 2047: | ||
| 59 | raise CreatorError("Can't have an swap overlay of 2048MB or " | ||
| 60 | "greater on VFAT") | ||
| 61 | |||
| 62 | livesize = misc.get_file_size(isodir + "/LiveOS") | ||
| 63 | |||
| 64 | usbimgsize = (overlaysizemb + \ | ||
| 65 | homesizemb + \ | ||
| 66 | swapsizemb + \ | ||
| 67 | livesize + \ | ||
| 68 | plussize) * 1024L * 1024L | ||
| 69 | |||
| 70 | disk = fs_related.SparseLoopbackDisk("%s/%s.usbimg" \ | ||
| 71 | % (self._outdir, self.name), | ||
| 72 | usbimgsize) | ||
| 73 | usbmnt = self._mkdtemp("usb-mnt") | ||
| 74 | usbloop = PartitionedMount(usbmnt) | ||
| 75 | usbloop.add_disk('/dev/sdb', disk) | ||
| 76 | |||
| 77 | usbloop.add_partition(usbimgsize/1024/1024, | ||
| 78 | "/dev/sdb", | ||
| 79 | "/", | ||
| 80 | fstype, | ||
| 81 | boot=True) | ||
| 82 | |||
| 83 | usbloop.mount() | ||
| 84 | |||
| 85 | try: | ||
| 86 | fs_related.makedirs(usbmnt + "/LiveOS") | ||
| 87 | |||
| 88 | if os.path.exists(isodir + "/LiveOS/squashfs.img"): | ||
| 89 | shutil.copyfile(isodir + "/LiveOS/squashfs.img", | ||
| 90 | usbmnt + "/LiveOS/squashfs.img") | ||
| 91 | else: | ||
| 92 | fs_related.mksquashfs(os.path.dirname(self._image), | ||
| 93 | usbmnt + "/LiveOS/squashfs.img") | ||
| 94 | |||
| 95 | if os.path.exists(isodir + "/LiveOS/osmin.img"): | ||
| 96 | shutil.copyfile(isodir + "/LiveOS/osmin.img", | ||
| 97 | usbmnt + "/LiveOS/osmin.img") | ||
| 98 | |||
| 99 | if fstype == "vfat" or fstype == "msdos": | ||
| 100 | uuid = usbloop.partitions[0]['mount'].uuid | ||
| 101 | label = usbloop.partitions[0]['mount'].fslabel | ||
| 102 | usblabel = "UUID=%s-%s" % (uuid[0:4], uuid[4:8]) | ||
| 103 | overlaysuffix = "-%s-%s-%s" % (label, uuid[0:4], uuid[4:8]) | ||
| 104 | else: | ||
| 105 | diskmount = usbloop.partitions[0]['mount'] | ||
| 106 | usblabel = "UUID=%s" % diskmount.uuid | ||
| 107 | overlaysuffix = "-%s-%s" % (diskmount.fslabel, diskmount.uuid) | ||
| 108 | |||
| 109 | args = ['cp', "-Rf", isodir + "/isolinux", usbmnt + "/syslinux"] | ||
| 110 | rc = runner.show(args) | ||
| 111 | if rc: | ||
| 112 | raise CreatorError("Can't copy isolinux directory %s" \ | ||
| 113 | % (isodir + "/isolinux/*")) | ||
| 114 | |||
| 115 | if os.path.isfile("/usr/share/syslinux/isolinux.bin"): | ||
| 116 | syslinux_path = "/usr/share/syslinux" | ||
| 117 | elif os.path.isfile("/usr/lib/syslinux/isolinux.bin"): | ||
| 118 | syslinux_path = "/usr/lib/syslinux" | ||
| 119 | else: | ||
| 120 | raise CreatorError("syslinux not installed : " | ||
| 121 | "cannot find syslinux installation path") | ||
| 122 | |||
| 123 | for f in ("isolinux.bin", "vesamenu.c32"): | ||
| 124 | path = os.path.join(syslinux_path, f) | ||
| 125 | if os.path.isfile(path): | ||
| 126 | args = ['cp', path, usbmnt + "/syslinux/"] | ||
| 127 | rc = runner.show(args) | ||
| 128 | if rc: | ||
| 129 | raise CreatorError("Can't copy syslinux file " + path) | ||
| 130 | else: | ||
| 131 | raise CreatorError("syslinux not installed: " | ||
| 132 | "syslinux file %s not found" % path) | ||
| 133 | |||
| 134 | fd = open(isodir + "/isolinux/isolinux.cfg", "r") | ||
| 135 | text = fd.read() | ||
| 136 | fd.close() | ||
| 137 | pattern = re.compile('CDLABEL=[^ ]*') | ||
| 138 | text = pattern.sub(usblabel, text) | ||
| 139 | pattern = re.compile('rootfstype=[^ ]*') | ||
| 140 | text = pattern.sub("rootfstype=" + fstype, text) | ||
| 141 | if kernelargs: | ||
| 142 | text = text.replace("rd.live.image", "rd.live.image " + kernelargs) | ||
| 143 | |||
| 144 | if overlaysizemb > 0: | ||
| 145 | msger.info("Initializing persistent overlay file") | ||
| 146 | overfile = "overlay" + overlaysuffix | ||
| 147 | if fstype == "vfat": | ||
| 148 | args = ['dd', | ||
| 149 | "if=/dev/zero", | ||
| 150 | "of=" + usbmnt + "/LiveOS/" + overfile, | ||
| 151 | "count=%d" % overlaysizemb, | ||
| 152 | "bs=1M"] | ||
| 153 | else: | ||
| 154 | args = ['dd', | ||
| 155 | "if=/dev/null", | ||
| 156 | "of=" + usbmnt + "/LiveOS/" + overfile, | ||
| 157 | "count=1", | ||
| 158 | "bs=1M", | ||
| 159 | "seek=%d" % overlaysizemb] | ||
| 160 | rc = runner.show(args) | ||
| 161 | if rc: | ||
| 162 | raise CreatorError("Can't create overlay file") | ||
| 163 | text = text.replace("rd.live.image", "rd.live.image rd.live.overlay=" + usblabel) | ||
| 164 | text = text.replace(" ro ", " rw ") | ||
| 165 | |||
| 166 | if swapsizemb > 0: | ||
| 167 | msger.info("Initializing swap file") | ||
| 168 | swapfile = usbmnt + "/LiveOS/" + "swap.img" | ||
| 169 | args = ['dd', | ||
| 170 | "if=/dev/zero", | ||
| 171 | "of=" + swapfile, | ||
| 172 | "count=%d" % swapsizemb, | ||
| 173 | "bs=1M"] | ||
| 174 | rc = runner.show(args) | ||
| 175 | if rc: | ||
| 176 | raise CreatorError("Can't create swap file") | ||
| 177 | args = ["mkswap", "-f", swapfile] | ||
| 178 | rc = runner.show(args) | ||
| 179 | if rc: | ||
| 180 | raise CreatorError("Can't mkswap on swap file") | ||
| 181 | |||
| 182 | if homesizemb > 0: | ||
| 183 | msger.info("Initializing persistent /home") | ||
| 184 | homefile = usbmnt + "/LiveOS/" + homefile | ||
| 185 | if fstype == "vfat": | ||
| 186 | args = ['dd', | ||
| 187 | "if=/dev/zero", | ||
| 188 | "of=" + homefile, | ||
| 189 | "count=%d" % homesizemb, | ||
| 190 | "bs=1M"] | ||
| 191 | else: | ||
| 192 | args = ['dd', | ||
| 193 | "if=/dev/null", | ||
| 194 | "of=" + homefile, | ||
| 195 | "count=1", | ||
| 196 | "bs=1M", | ||
| 197 | "seek=%d" % homesizemb] | ||
| 198 | rc = runner.show(args) | ||
| 199 | if rc: | ||
| 200 | raise CreatorError("Can't create home file") | ||
| 201 | |||
| 202 | mkfscmd = fs_related.find_binary_path("/sbin/mkfs." + fstype) | ||
| 203 | if fstype == "ext2" or fstype == "ext3": | ||
| 204 | args = [mkfscmd, "-F", "-j", homefile] | ||
| 205 | else: | ||
| 206 | args = [mkfscmd, homefile] | ||
| 207 | rc = runner.show(args) | ||
| 208 | if rc: | ||
| 209 | raise CreatorError("Can't mke2fs home file") | ||
| 210 | if fstype == "ext2" or fstype == "ext3": | ||
| 211 | tune2fs = fs_related.find_binary_path("tune2fs") | ||
| 212 | args = [tune2fs, | ||
| 213 | "-c0", | ||
| 214 | "-i0", | ||
| 215 | "-ouser_xattr,acl", | ||
| 216 | homefile] | ||
| 217 | rc = runner.show(args) | ||
| 218 | if rc: | ||
| 219 | raise CreatorError("Can't tune2fs home file") | ||
| 220 | |||
| 221 | if fstype == "vfat" or fstype == "msdos": | ||
| 222 | syslinuxcmd = fs_related.find_binary_path("syslinux") | ||
| 223 | syslinuxcfg = usbmnt + "/syslinux/syslinux.cfg" | ||
| 224 | args = [syslinuxcmd, | ||
| 225 | "-d", | ||
| 226 | "syslinux", | ||
| 227 | usbloop.partitions[0]["device"]] | ||
| 228 | |||
| 229 | elif fstype == "ext2" or fstype == "ext3": | ||
| 230 | extlinuxcmd = fs_related.find_binary_path("extlinux") | ||
| 231 | syslinuxcfg = usbmnt + "/syslinux/extlinux.conf" | ||
| 232 | args = [extlinuxcmd, | ||
| 233 | "-i", | ||
| 234 | usbmnt + "/syslinux"] | ||
| 235 | |||
| 236 | else: | ||
| 237 | raise CreatorError("Invalid file system type: %s" % (fstype)) | ||
| 238 | |||
| 239 | os.unlink(usbmnt + "/syslinux/isolinux.cfg") | ||
| 240 | fd = open(syslinuxcfg, "w") | ||
| 241 | fd.write(text) | ||
| 242 | fd.close() | ||
| 243 | rc = runner.show(args) | ||
| 244 | if rc: | ||
| 245 | raise CreatorError("Can't install boot loader.") | ||
| 246 | |||
| 247 | finally: | ||
| 248 | usbloop.unmount() | ||
| 249 | usbloop.cleanup() | ||
| 250 | |||
| 251 | # Need to do this after image is unmounted and device mapper is closed | ||
| 252 | msger.info("set MBR") | ||
| 253 | mbrfile = "/usr/lib/syslinux/mbr.bin" | ||
| 254 | if not os.path.exists(mbrfile): | ||
| 255 | mbrfile = "/usr/share/syslinux/mbr.bin" | ||
| 256 | if not os.path.exists(mbrfile): | ||
| 257 | raise CreatorError("mbr.bin file didn't exist.") | ||
| 258 | mbrsize = os.path.getsize(mbrfile) | ||
| 259 | outimg = "%s/%s.usbimg" % (self._outdir, self.name) | ||
| 260 | |||
| 261 | args = ['dd', | ||
| 262 | "if=" + mbrfile, | ||
| 263 | "of=" + outimg, | ||
| 264 | "seek=0", | ||
| 265 | "conv=notrunc", | ||
| 266 | "bs=1", | ||
| 267 | "count=%d" % (mbrsize)] | ||
| 268 | rc = runner.show(args) | ||
| 269 | if rc: | ||
| 270 | raise CreatorError("Can't set MBR.") | ||
| 271 | |||
| 272 | def _stage_final_image(self): | ||
| 273 | try: | ||
| 274 | isodir = self._get_isodir() | ||
| 275 | fs_related.makedirs(isodir + "/LiveOS") | ||
| 276 | |||
| 277 | minimal_size = self._resparse() | ||
| 278 | |||
| 279 | if not self.skip_minimize: | ||
| 280 | fs_related.create_image_minimizer(isodir + "/LiveOS/osmin.img", | ||
| 281 | self._image, | ||
| 282 | minimal_size) | ||
| 283 | |||
| 284 | if self.skip_compression: | ||
| 285 | shutil.move(self._image, | ||
| 286 | isodir + "/LiveOS/ext3fs.img") | ||
| 287 | else: | ||
| 288 | fs_related.makedirs(os.path.join( | ||
| 289 | os.path.dirname(self._image), | ||
| 290 | "LiveOS")) | ||
| 291 | shutil.move(self._image, | ||
| 292 | os.path.join(os.path.dirname(self._image), | ||
| 293 | "LiveOS", "ext3fs.img")) | ||
| 294 | fs_related.mksquashfs(os.path.dirname(self._image), | ||
| 295 | isodir + "/LiveOS/squashfs.img") | ||
| 296 | |||
| 297 | self._create_usbimg(isodir) | ||
| 298 | |||
| 299 | if self.pack_to: | ||
| 300 | usbimg = os.path.join(self._outdir, self.name + ".usbimg") | ||
| 301 | packimg = os.path.join(self._outdir, self.pack_to) | ||
| 302 | misc.packing(packimg, usbimg) | ||
| 303 | os.unlink(usbimg) | ||
| 304 | |||
| 305 | finally: | ||
| 306 | shutil.rmtree(isodir, ignore_errors = True) | ||
| 307 | self._set_isodir(None) | ||
| 308 | |||
