auto selecting backend with 'pkgmgr=auto'
[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 'auto' == creatoropts['pkgmgr']:
73                 pkgmgr = pcls
74                 break
75             elif key == creatoropts['pkgmgr']:
76                 pkgmgr = pcls
77                 break
78
79         if not pkgmgr:
80             pkgmgrs = pluginmgr.get_plugins('backend').keys()
81             raise errors.CreatorError("Can't find package manager: %s (availables: %s)" % (creatoropts['pkgmgr'], ', '.join(pkgmgrs)))
82
83         creator = liveusb.LiveUSBImageCreator(creatoropts, pkgmgr)
84
85         if len(recording_pkgs) > 0:
86             creator._recording_pkgs = recording_pkgs
87
88         self.check_image_exists(creator.destdir,
89                                 creator.pack_to,
90                                 [creator.name + ".usbimg"],
91                                 creatoropts['release'])
92         try:
93             creator.check_depend_tools()
94             creator.mount(None, creatoropts["cachedir"])
95             creator.install()
96             creator.configure(creatoropts["repomd"])
97             creator.copy_kernel()
98             creator.unmount()
99             creator.package(creatoropts["outdir"])
100             if creatoropts['release'] is not None:
101                 creator.release_output(ksconf, creatoropts['outdir'], creatoropts['release'])
102             creator.print_outimage_info()
103
104         except errors.CreatorError:
105             raise
106         finally:
107             creator.cleanup()
108
109         msger.info("Finished.")
110         return 0
111
112     @classmethod
113     def do_chroot(cls, target):
114         os_image = cls.do_unpack(target)
115         os_image_dir = os.path.dirname(os_image)
116
117         # unpack image to target dir
118         imgsize = misc.get_file_size(os_image) * 1024L * 1024L
119         imgtype = misc.get_image_type(os_image)
120         if imgtype == "btrfsimg":
121             fstype = "btrfs"
122             myDiskMount = fs_related.BtrfsDiskMount
123         elif imgtype in ("ext3fsimg", "ext4fsimg"):
124             fstype = imgtype[:4]
125             myDiskMount = fs_related.ExtDiskMount
126         else:
127             raise errors.CreatorError("Unsupported filesystem type: %s" % fstype)
128
129         extmnt = misc.mkdtemp()
130         extloop = myDiskMount(fs_related.SparseLoopbackDisk(os_image, imgsize),
131                               extmnt,
132                               fstype,
133                               4096,
134                               "%s label" % fstype)
135
136         try:
137             extloop.mount()
138
139         except errors.MountError:
140             extloop.cleanup()
141             shutil.rmtree(extmnt, ignore_errors = True)
142             raise
143
144         try:
145             envcmd = fs_related.find_binary_inchroot("env", extmnt)
146             if envcmd:
147                 cmdline = "%s HOME=/root /bin/bash" % envcmd
148             else:
149                 cmdline = "/bin/bash"
150             chroot.chroot(extmnt, None, cmdline)
151         except:
152             raise errors.CreatorError("Failed to chroot to %s." %target)
153         finally:
154             chroot.cleanup_after_chroot("img", extloop, os_image_dir, extmnt)
155
156     @classmethod
157     def do_pack(cls, base_on):
158         import subprocess
159
160         def __mkinitrd(instance):
161             kernelver = instance._get_kernel_versions().values()[0][0]
162             args = [ "/usr/libexec/mkliveinitrd", "/boot/initrd-%s.img" % kernelver, "%s" % kernelver ]
163             try:
164                 subprocess.call(args, preexec_fn = instance._chroot)
165
166             except OSError, (err, msg):
167                raise errors.CreatorError("Failed to execute /usr/libexec/mkliveinitrd: %s" % msg)
168
169         def __run_post_cleanups(instance):
170             kernelver = instance._get_kernel_versions().values()[0][0]
171             args = ["rm", "-f", "/boot/initrd-%s.img" % kernelver]
172
173             try:
174                 subprocess.call(args, preexec_fn = instance._chroot)
175             except OSError, (err, msg):
176                raise errors.CreatorError("Failed to run post cleanups: %s" % msg)
177
178         convertoropts = configmgr.convert
179         convertoropts['name'] = os.path.splitext(os.path.basename(base_on))[0]
180         convertor = liveusb.LiveUSBImageCreator(convertoropts)
181         imgtype = misc.get_image_type(base_on)
182         if imgtype == "btrfsimg":
183             fstype = "btrfs"
184         elif imgtype in ("ext3fsimg", "ext4fsimg"):
185             fstype = imgtype[:4]
186         else:
187             raise errors.CreatorError("Unsupported filesystem type: %s" % fstyp)
188         convertor._set_fstype(fstype)
189         try:
190             convertor.mount(base_on)
191             __mkinitrd(convertor)
192             convertor._create_bootconfig()
193             __run_post_cleanups(convertor)
194             convertor.launch_shell(convertoropts['shell'])
195             convertor.unmount()
196             convertor.package()
197             convertor.print_outimage_info()
198         finally:
199             shutil.rmtree(os.path.dirname(base_on), ignore_errors = True)
200
201     @classmethod
202     def do_unpack(cls, srcimg):
203         img = srcimg
204         imgsize = misc.get_file_size(img) * 1024L * 1024L
205         imgmnt = misc.mkdtemp()
206         disk = fs_related.SparseLoopbackDisk(img, imgsize)
207         imgloop = PartitionedMount({'/dev/sdb':disk}, imgmnt, skipformat = True)
208         imgloop.add_partition(imgsize/1024/1024, "/dev/sdb", "/", "vfat", boot=False)
209         try:
210             imgloop.mount()
211         except errors.MountError:
212             imgloop.cleanup()
213             raise
214
215         # legacy LiveOS filesystem layout support, remove for F9 or F10
216         if os.path.exists(imgmnt + "/squashfs.img"):
217             squashimg = imgmnt + "/squashfs.img"
218         else:
219             squashimg = imgmnt + "/LiveOS/squashfs.img"
220
221         tmpoutdir = misc.mkdtemp()
222         # unsquashfs requires outdir mustn't exist
223         shutil.rmtree(tmpoutdir, ignore_errors = True)
224         misc.uncompress_squashfs(squashimg, tmpoutdir)
225
226         try:
227             # legacy LiveOS filesystem layout support, remove for F9 or F10
228             if os.path.exists(tmpoutdir + "/os.img"):
229                 os_image = tmpoutdir + "/os.img"
230             else:
231                 os_image = tmpoutdir + "/LiveOS/ext3fs.img"
232
233             if not os.path.exists(os_image):
234                 raise errors.CreatorError("'%s' is not a valid live CD ISO : neither "
235                                           "LiveOS/ext3fs.img nor os.img exist" %img)
236             imgname = os.path.basename(srcimg)
237             imgname = os.path.splitext(imgname)[0] + ".img"
238             rtimage = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), imgname)
239             shutil.copyfile(os_image, rtimage)
240
241         finally:
242             imgloop.cleanup()
243             shutil.rmtree(tmpoutdir, ignore_errors = True)
244             shutil.rmtree(imgmnt, ignore_errors = True)
245
246         return rtimage