70659a09e73d77bf45c249263e4a5a3ebf78d402
[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 configmgr, pluginmgr, chroot, msger
23 from mic.utils import misc, fs_related, errors
24 from mic.utils.partitionedfs import PartitionedMount
25
26 import mic.imager.liveusb as liveusb
27
28 from mic.pluginbase import ImagerPlugin
29 class LiveUSBPlugin(ImagerPlugin):
30     name = 'liveusb'
31
32     @classmethod
33     def do_create(self, subcmd, opts, *args):
34         """${cmd_name}: create liveusb image
35
36         ${cmd_usage}
37         ${cmd_option_list}
38         """
39
40         if not args:
41             raise errors.Usage("More arguments needed")
42
43         if len(args) != 1:
44             raise errors.Usage("Extra arguments given")
45
46         cfgmgr = configmgr.getConfigMgr()
47         creatoropts = cfgmgr.create
48         ksconf = args[0]
49
50         if not os.path.exists(ksconf):
51             raise errors.CreatorError("Can't find the file: %s" % ksconf)
52
53         if creatoropts['arch'] and creatoropts['arch'].startswith('arm'):
54             msger.warning('liveusb cannot support arm images, Quit')
55             return
56
57         recording_pkgs = []
58         if len(creatoropts['record_pkgs']) > 0:
59             recording_pkgs = creatoropts['record_pkgs']
60         if creatoropts['release'] is not None:
61             if 'name' not in recording_pkgs:
62                 recording_pkgs.append('name')
63             ksconf = misc.save_ksconf_file(ksconf, creatoropts['release'])
64             name = os.path.splitext(os.path.basename(ksconf))[0]
65             creatoropts['outdir'] = "%s/%s/images/%s/" % (creatoropts['outdir'], creatoropts['release'], name)
66         cfgmgr._ksconf = ksconf
67
68         # try to find the pkgmgr
69         pkgmgr = None
70         for (key, pcls) in pluginmgr.PluginMgr().get_plugins('backend').iteritems():
71             if key == creatoropts['pkgmgr']:
72                 pkgmgr = pcls
73                 break
74
75         if not pkgmgr:
76             pkgmgrs = pluginmgr.PluginMgr().get_plugins('backend').keys()
77             raise errors.CreatorError("Can't find package manager: %s (availables: %s)" % (creatoropts['pkgmgr'], ', '.join(pkgmgrs)))
78
79         creator = liveusb.LiveUSBImageCreator(creatoropts, pkgmgr)
80
81         if len(recording_pkgs) > 0:
82             creator._recording_pkgs = recording_pkgs
83
84         if creatoropts['release'] is None:
85             imagefile = "%s.usbimg" % os.path.join(creator.destdir, creator.name)
86             if os.path.exists(imagefile):
87                 if msger.ask('The target image: %s already exists, need to delete it?' % imagefile):
88                     os.unlink(imagefile)
89
90         try:
91             creator.check_depend_tools()
92             creator.mount(None, creatoropts["cachedir"])
93             creator.install()
94             creator.configure(creatoropts["repomd"])
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         extmnt = misc.mkdtemp()
117         tfstype = "ext3"
118         tlabel = "ext3 label"
119
120         MyDiskMount = fs_related.ExtDiskMount
121         extloop = MyDiskMount(fs_related.SparseLoopbackDisk(os_image, imgsize),
122                               extmnt,
123                               tfstype,
124                               4096,
125                               tlabel)
126         try:
127             extloop.mount()
128
129         except errors.MountError:
130             extloop.cleanup()
131             shutil.rmtree(extmnt, ignore_errors = True)
132             raise
133
134         try:
135             chroot.chroot(extmnt, None,  "/bin/env HOME=/root /bin/bash")
136         except:
137             raise errors.CreatorError("Failed to chroot to %s." %target)
138         finally:
139             chroot.cleanup_after_chroot("img", extloop, os_image_dir, extmnt)
140
141     @classmethod
142     def do_pack(cls, base_on):
143         import subprocess
144
145         def __mkinitrd(instance):
146             kernelver = instance._get_kernel_versions().values()[0][0]
147             args = [ "/usr/libexec/mkliveinitrd", "/boot/initrd-%s.img" % kernelver, "%s" % kernelver ]
148             try:
149                 subprocess.call(args, preexec_fn = instance._chroot)
150
151             except OSError, (err, msg):
152                raise errors.CreatorError("Failed to execute /usr/libexec/mkliveinitrd: %s" % msg)
153
154         def __run_post_cleanups(instance):
155             kernelver = instance._get_kernel_versions().values()[0][0]
156             args = ["rm", "-f", "/boot/initrd-%s.img" % kernelver]
157
158             try:
159                 subprocess.call(args, preexec_fn = instance._chroot)
160             except OSError, (err, msg):
161                raise errors.CreatorError("Failed to run post cleanups: %s" % msg)
162
163         convertor = liveusb.LiveUSBImageCreator()
164         srcimgsize = (misc.get_file_size(base_on)) * 1024L * 1024L
165         convertor._set_fstype("ext3")
166         convertor._set_image_size(srcimgsize)
167         base_on_dir = os.path.dirname(base_on)
168         convertor._LoopImageCreator__imgdir = base_on_dir
169         try:
170             convertor.mount()
171             __mkinitrd(convertor)
172             convertor._create_bootconfig()
173             __run_post_cleanups(convertor)
174             convertor.unmount()
175             convertor.package()
176             convertor.print_outimage_info()
177         finally:
178             shutil.rmtree(base_on_dir, ignore_errors = True)
179
180     @classmethod
181     def do_unpack(cls, srcimg):
182         img = srcimg
183         imgsize = misc.get_file_size(img) * 1024L * 1024L
184         imgmnt = misc.mkdtemp()
185         disk = fs_related.SparseLoopbackDisk(img, imgsize)
186         imgloop = PartitionedMount({'/dev/sdb':disk}, imgmnt, skipformat = True)
187         imgloop.add_partition(imgsize/1024/1024, "/dev/sdb", "/", "vfat", boot=False)
188         try:
189             imgloop.mount()
190         except errors.MountError:
191             imgloop.cleanup()
192             raise
193
194         # legacy LiveOS filesystem layout support, remove for F9 or F10
195         if os.path.exists(imgmnt + "/squashfs.img"):
196             squashimg = imgmnt + "/squashfs.img"
197         else:
198             squashimg = imgmnt + "/LiveOS/squashfs.img"
199
200         tmpoutdir = misc.mkdtemp()
201         # unsquashfs requires outdir mustn't exist
202         shutil.rmtree(tmpoutdir, ignore_errors = True)
203         misc.uncompress_squashfs(squashimg, tmpoutdir)
204
205         try:
206             # legacy LiveOS filesystem layout support, remove for F9 or F10
207             if os.path.exists(tmpoutdir + "/os.img"):
208                 os_image = tmpoutdir + "/os.img"
209             else:
210                 os_image = tmpoutdir + "/LiveOS/ext3fs.img"
211
212             if not os.path.exists(os_image):
213                 raise errors.CreatorError("'%s' is not a valid live CD ISO : neither "
214                                           "LiveOS/ext3fs.img nor os.img exist" %img)
215             rtimage = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), "target.img")
216             shutil.copyfile(os_image, rtimage)
217
218         finally:
219             imgloop.cleanup()
220             shutil.rmtree(tmpoutdir, ignore_errors = True)
221             shutil.rmtree(imgmnt, ignore_errors = True)
222
223         return rtimage