4b357e458eb65b4c3b52a1056fcb94d0d9d7e574
[tools/mic.git] / plugins / imager / liveusb_plugin.py
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 tempfile
21
22 from mic import chroot, msger
23 from mic.utils import misc, fs_related, errors
24 from mic.utils.partitionedfs import PartitionedMount
25 from mic.conf import configmgr
26 from mic.plugin import pluginmgr
27
28 import mic.imager.liveusb as liveusb
29
30 from mic.pluginbase import ImagerPlugin
31 class LiveUSBPlugin(ImagerPlugin):
32     name = 'liveusb'
33
34     @classmethod
35     def do_create(self, subcmd, opts, *args):
36         """${cmd_name}: create liveusb image
37
38         Usage:
39             ${name} ${cmd_name} <ksfile> [OPTS]
40
41         ${cmd_option_list}
42         """
43
44         creatoropts = configmgr.create
45         ksconf = args[0]
46
47         if creatoropts['arch'] and creatoropts['arch'].startswith('arm'):
48             msger.warning('liveusb cannot support arm images, Quit')
49             return
50
51         recording_pkgs = []
52         if len(creatoropts['record_pkgs']) > 0:
53             recording_pkgs = creatoropts['record_pkgs']
54
55         if creatoropts['release'] is not None:
56             if 'name' not in recording_pkgs:
57                 recording_pkgs.append('name')
58
59         ksconf = misc.normalize_ksfile(ksconf,
60                                        creatoropts['release'],
61                                        creatoropts['arch'])
62
63         configmgr._ksconf = ksconf
64
65         # Called After setting the configmgr._ksconf as the creatoropts['name'] is reset there.
66         if creatoropts['release'] is not None:
67             creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], creatoropts['release'], creatoropts['name'])
68
69         # try to find the pkgmgr
70         pkgmgr = None
71         for (key, pcls) in pluginmgr.get_plugins('backend').iteritems():
72             if key == creatoropts['pkgmgr']:
73                 pkgmgr = pcls
74                 break
75
76         if not pkgmgr:
77             pkgmgrs = pluginmgr.get_plugins('backend').keys()
78             raise errors.CreatorError("Can't find package manager: %s (availables: %s)" % (creatoropts['pkgmgr'], ', '.join(pkgmgrs)))
79
80         creator = liveusb.LiveUSBImageCreator(creatoropts, pkgmgr)
81
82         if len(recording_pkgs) > 0:
83             creator._recording_pkgs = recording_pkgs
84
85         self.check_image_exists(creator.destdir,
86                                 creator.pack_to,
87                                 [creator.name + ".usbimg"],
88                                 creatoropts['release'])
89         try:
90             creator.check_depend_tools()
91             creator.mount(None, creatoropts["cachedir"])
92             creator.install()
93             creator.configure(creatoropts["repomd"])
94             creator.copy_kernel()
95             creator.unmount()
96             creator.package(creatoropts["outdir"])
97             if creatoropts['release'] is not None:
98                 creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release'])
99             creator.print_outimage_info()
100
101         except errors.CreatorError:
102             raise
103         finally:
104             creator.cleanup()
105
106         msger.info("Finished.")
107         return 0
108
109     @classmethod
110     def do_chroot(cls, target):
111         os_image = cls.do_unpack(target)
112         os_image_dir = os.path.dirname(os_image)
113
114         # unpack image to target dir
115         imgsize = misc.get_file_size(os_image) * 1024L * 1024L
116         imgtype = misc.get_image_type(os_image)
117         if imgtype == "btrfsimg":
118             fstype = "btrfs"
119             myDiskMount = fs_related.BtrfsDiskMount
120         elif imgtype in ("ext3fsimg", "ext4fsimg"):
121             fstype = imgtype[:4]
122             myDiskMount = fs_related.ExtDiskMount
123         else:
124             raise errors.CreatorError("Unsupported filesystem type: %s" % fstype)
125
126         extmnt = misc.mkdtemp()
127         extloop = myDiskMount(fs_related.SparseLoopbackDisk(os_image, imgsize),
128                               extmnt,
129                               fstype,
130                               4096,
131                               "%s label" % fstype)
132
133         try:
134             extloop.mount()
135
136         except errors.MountError:
137             extloop.cleanup()
138             shutil.rmtree(extmnt, ignore_errors = True)
139             raise
140
141         try:
142             envcmd = fs_related.find_binary_inchroot("env", extmnt)
143             if envcmd:
144                 cmdline = "%s HOME=/root /bin/bash" % envcmd
145             else:
146                 cmdline = "/bin/bash"
147             chroot.chroot(extmnt, None, cmdline)
148         except:
149             raise errors.CreatorError("Failed to chroot to %s." %target)
150         finally:
151             chroot.cleanup_after_chroot("img", extloop, os_image_dir, extmnt)
152
153     @classmethod
154     def do_pack(cls, base_on):
155         import subprocess
156
157         def __mkinitrd(instance):
158             kernelver = instance._get_kernel_versions().values()[0][0]
159             args = [ "/usr/libexec/mkliveinitrd", "/boot/initrd-%s.img" % kernelver, "%s" % kernelver ]
160             try:
161                 subprocess.call(args, preexec_fn = instance._chroot)
162
163             except OSError, (err, msg):
164                raise errors.CreatorError("Failed to execute /usr/libexec/mkliveinitrd: %s" % msg)
165
166         def __run_post_cleanups(instance):
167             kernelver = instance._get_kernel_versions().values()[0][0]
168             args = ["rm", "-f", "/boot/initrd-%s.img" % kernelver]
169
170             try:
171                 subprocess.call(args, preexec_fn = instance._chroot)
172             except OSError, (err, msg):
173                raise errors.CreatorError("Failed to run post cleanups: %s" % msg)
174
175         convertoropts = configmgr.convert
176         convertoropts['name'] = os.path.splitext(os.path.basename(base_on))[0]
177         convertor = liveusb.LiveUSBImageCreator(convertoropts)
178         imgtype = misc.get_image_type(base_on)
179         if imgtype == "btrfsimg":
180             fstype = "btrfs"
181         elif imgtype in ("ext3fsimg", "ext4fsimg"):
182             fstype = imgtype[:4]
183         else:
184             raise errors.CreatorError("Unsupported filesystem type: %s" % fstyp)
185         convertor._set_fstype(fstype)
186         try:
187             convertor.mount(base_on)
188             __mkinitrd(convertor)
189             convertor._create_bootconfig()
190             __run_post_cleanups(convertor)
191             convertor.launch_shell(convertoropts['shell'])
192             convertor.unmount()
193             convertor.package()
194             convertor.print_outimage_info()
195         finally:
196             shutil.rmtree(os.path.dirname(base_on), ignore_errors = True)
197
198     @classmethod
199     def do_unpack(cls, srcimg):
200         img = srcimg
201         imgsize = misc.get_file_size(img) * 1024L * 1024L
202         imgmnt = misc.mkdtemp()
203         disk = fs_related.SparseLoopbackDisk(img, imgsize)
204         imgloop = PartitionedMount({'/dev/sdb':disk}, imgmnt, skipformat = True)
205         imgloop.add_partition(imgsize/1024/1024, "/dev/sdb", "/", "vfat", boot=False)
206         try:
207             imgloop.mount()
208         except errors.MountError:
209             imgloop.cleanup()
210             raise
211
212         # legacy LiveOS filesystem layout support, remove for F9 or F10
213         if os.path.exists(imgmnt + "/squashfs.img"):
214             squashimg = imgmnt + "/squashfs.img"
215         else:
216             squashimg = imgmnt + "/LiveOS/squashfs.img"
217
218         tmpoutdir = misc.mkdtemp()
219         # unsquashfs requires outdir mustn't exist
220         shutil.rmtree(tmpoutdir, ignore_errors = True)
221         misc.uncompress_squashfs(squashimg, tmpoutdir)
222
223         try:
224             # legacy LiveOS filesystem layout support, remove for F9 or F10
225             if os.path.exists(tmpoutdir + "/os.img"):
226                 os_image = tmpoutdir + "/os.img"
227             else:
228                 os_image = tmpoutdir + "/LiveOS/ext3fs.img"
229
230             if not os.path.exists(os_image):
231                 raise errors.CreatorError("'%s' is not a valid live CD ISO : neither "
232                                           "LiveOS/ext3fs.img nor os.img exist" %img)
233             imgname = os.path.basename(srcimg)
234             imgname = os.path.splitext(imgname)[0] + ".img"
235             rtimage = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), imgname)
236             shutil.copyfile(os_image, rtimage)
237
238         finally:
239             imgloop.cleanup()
240             shutil.rmtree(tmpoutdir, ignore_errors = True)
241             shutil.rmtree(imgmnt, ignore_errors = True)
242
243         return rtimage