Another method of install tpk.
[tools/mic.git] / plugins / imager / raw_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 subprocess
20 import shutil
21 import re
22 import tempfile
23
24 from mic import chroot, msger, rt_util
25 from mic.utils import misc, fs_related, errors, runner
26 from mic.conf import configmgr
27 from mic.plugin import pluginmgr
28 from mic.utils.partitionedfs import PartitionedMount
29
30 import mic.imager.raw as raw
31
32 from mic.pluginbase import ImagerPlugin
33 class RawPlugin(ImagerPlugin):
34     name = 'raw'
35
36     @classmethod
37     def do_create(self, args):
38         """${cmd_name}: create raw image
39
40         Usage:
41             ${name} ${cmd_name} <ksfile> [OPTS]
42
43         ${cmd_option_list}
44         """
45
46         creatoropts = configmgr.create
47         ksconf = args.ksfile
48
49         if creatoropts['runtime'] == "bootstrap":
50             configmgr._ksconf = ksconf
51             rt_util.bootstrap_mic()
52
53         recording_pkgs = []
54         if len(creatoropts['record_pkgs']) > 0:
55             recording_pkgs = creatoropts['record_pkgs']
56
57         if creatoropts['release'] is not None:
58             if 'name' not in recording_pkgs:
59                 recording_pkgs.append('name')
60             if 'vcs' not in recording_pkgs:
61                 recording_pkgs.append('vcs')
62
63         configmgr._ksconf = ksconf
64
65         # try to find the pkgmgr
66         pkgmgr = None
67         backends = pluginmgr.get_plugins('backend')
68         if 'auto' == creatoropts['pkgmgr']:
69             for key in configmgr.prefer_backends:
70                 if key in backends:
71                     pkgmgr = backends[key]
72                     break
73         else:
74             for key in backends.keys():
75                 if key == creatoropts['pkgmgr']:
76                     pkgmgr = backends[key]
77                     break
78
79         if not pkgmgr:
80             raise errors.CreatorError("Can't find backend: %s, "
81                                       "available choices: %s" %
82                                       (creatoropts['pkgmgr'],
83                                        ','.join(backends.keys())))
84
85         creator = raw.RawImageCreator(creatoropts, pkgmgr, args.compress_image,
86                                       args.generate_bmap, args.fstab_entry)
87
88         if len(recording_pkgs) > 0:
89             creator._recording_pkgs = recording_pkgs
90
91         images = ["%s-%s.raw" % (creator.name, disk_name)
92                   for disk_name in creator.get_disk_names()]
93         self.check_image_exists(creator.destdir,
94                                 creator.pack_to,
95                                 images,
96                                 creatoropts['release'])
97
98         try:
99             creator.check_depend_tools()
100             creator.mount(None, creatoropts["cachedir"])
101             creator.install()
102             creator.tpkinstall()
103             creator.configure(creatoropts["repomd"])
104             creator.copy_kernel()
105             creator.unmount()
106             creator.generate_bmap()
107             creator.package(creatoropts["destdir"])
108             creator.create_manifest()
109             if creatoropts['release'] is not None:
110                 creator.release_output(ksconf, creatoropts['destdir'], creatoropts['release'])
111             creator.print_outimage_info()
112
113         except errors.CreatorError:
114             raise
115         finally:
116             creator.cleanup()
117
118         #Run script of --run_script after image created
119         if creatoropts['run_script']:
120             cmd = creatoropts['run_script']
121             try:
122                 runner.show(cmd)
123             except OSError,err:
124                 msger.warning(str(err))
125
126
127         msger.info("Finished.")
128         return 0
129
130     @classmethod
131     def do_chroot(cls, target, cmd=[]):
132         img = target
133         imgsize = misc.get_file_size(img) * 1024L * 1024L
134         partedcmd = fs_related.find_binary_path("parted")
135         disk = fs_related.SparseLoopbackDisk(img, imgsize)
136         imgmnt = misc.mkdtemp()
137         imgloop = PartitionedMount(imgmnt, skipformat = True)
138         imgloop.add_disk('/dev/sdb', disk)
139         img_fstype = "ext3"
140
141         msger.info("Partition Table:")
142         partnum = []
143         for line in runner.outs([partedcmd, "-s", img, "print"]).splitlines():
144             # no use strip to keep line output here
145             if "Number" in line:
146                 msger.raw(line)
147             if line.strip() and line.strip()[0].isdigit():
148                 partnum.append(line.strip()[0])
149                 msger.raw(line)
150
151         rootpart = None
152         if len(partnum) > 1:
153             rootpart = msger.choice("please choose root partition", partnum)
154
155         # Check the partitions from raw disk.
156         # if choose root part, the mark it as mounted
157         if rootpart:
158             root_mounted = True
159         else:
160             root_mounted = False
161         partition_mounts = 0
162         for line in runner.outs([ partedcmd, "-s", img, "unit", "B", "print" ]).splitlines():
163             line = line.strip()
164
165             # Lines that start with number are the partitions,
166             # because parted can be translated we can't refer to any text lines.
167             if not line or not line[0].isdigit():
168                 continue
169
170             # Some vars have extra , as list seperator.
171             line = line.replace(",","")
172
173             # Example of parted output lines that are handled:
174             # Number  Start        End          Size         Type     File system    Flags
175             #  1      512B         3400000511B  3400000000B  primary
176             #  2      3400531968B  3656384511B  255852544B   primary  linux-swap(v1)
177             #  3      3656384512B  3720347647B  63963136B    primary  fat16          boot, lba
178
179             partition_info = re.split("\s+", line)
180
181             size = partition_info[3].split("B")[0]
182
183             if len(partition_info) < 6 or partition_info[5] in ["boot"]:
184                 # No filesystem can be found from partition line. Assuming
185                 # btrfs, because that is the only MeeGo fs that parted does
186                 # not recognize properly.
187                 # TODO: Can we make better assumption?
188                 fstype = "btrfs"
189             elif partition_info[5] in [ "ext2", "ext3", "ext4", "btrfs" ]:
190                 fstype = partition_info[5]
191             elif partition_info[5] in [ "fat16", "fat32" ]:
192                 fstype = "vfat"
193             elif "swap" in partition_info[5]:
194                 fstype = "swap"
195             else:
196                 raise errors.CreatorError("Could not recognize partition fs type '%s'." %
197                         partition_info[5])
198
199             if rootpart and rootpart == line[0]:
200                 mountpoint = '/'
201             elif not root_mounted and fstype in [ "ext2", "ext3", "ext4", "btrfs" ]:
202                 # TODO: Check that this is actually the valid root partition from /etc/fstab
203                 mountpoint = "/"
204                 root_mounted = True
205             elif fstype == "swap":
206                 mountpoint = "swap"
207             else:
208                 # TODO: Assing better mount points for the rest of the partitions.
209                 partition_mounts += 1
210                 mountpoint = "/media/partition_%d" % partition_mounts
211
212             if "boot" in partition_info:
213                 boot = True
214             else:
215                 boot = False
216
217             msger.verbose("Size: %s Bytes, fstype: %s, mountpoint: %s, boot: %s" %
218                     (size, fstype, mountpoint, boot))
219             # TODO: add_partition should take bytes as size parameter.
220             imgloop.add_partition((int)(size)/1024/1024, "/dev/sdb", mountpoint,
221                     fstype = fstype, boot = boot)
222
223         try:
224             imgloop.mount()
225
226         except errors.MountError:
227             imgloop.cleanup()
228             raise
229
230         try:
231             if len(cmd) != 0:
232                 cmdline = ' '.join(cmd)
233             else:
234                 cmdline = "/bin/bash"
235             envcmd = fs_related.find_binary_inchroot("env", imgmnt)
236             if envcmd:
237                 cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
238             chroot.chroot(imgmnt, None, cmdline)
239         except:
240             raise errors.CreatorError("Failed to chroot to %s." %img)
241         finally:
242             chroot.cleanup_after_chroot("img", imgloop, None, imgmnt)
243
244     @classmethod
245     def do_unpack(cls, srcimg):
246         srcimgsize = (misc.get_file_size(srcimg)) * 1024L * 1024L
247         srcmnt = misc.mkdtemp("srcmnt")
248         disk = fs_related.SparseLoopbackDisk(srcimg, srcimgsize)
249         srcloop = PartitionedMount(srcmnt, skipformat = True)
250
251         srcloop.add_disk('/dev/sdb', disk)
252         srcloop.add_partition(srcimgsize/1024/1024, "/dev/sdb", "/", "ext3", boot=False)
253         try:
254             srcloop.mount()
255
256         except errors.MountError:
257             srcloop.cleanup()
258             raise
259
260         image = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), "target.img")
261         args = ['dd', "if=%s" % srcloop.partitions[0]['device'], "of=%s" % image]
262
263         msger.info("`dd` image ...")
264         rc = runner.show(args)
265         srcloop.cleanup()
266         shutil.rmtree(os.path.dirname(srcmnt), ignore_errors = True)
267
268         if rc != 0:
269             raise errors.CreatorError("Failed to dd")
270         else:
271             return image