rename all micng to mic
[tools/mic.git] / plugins / imager / raw_plugin.py
1 #!/usr/bin/python
2 import os.path
3 import sys
4 import subprocess
5 import logging
6 import shutil
7 import re
8 import tempfile
9
10 from mic.pluginbase.imager_plugin import ImagerPlugin
11 import mic.utils.misc as misc
12 import mic.utils.fs_related as fs_related
13 import mic.utils.cmdln as cmdln
14 from mic.utils.errors import *
15 from mic.utils.partitionedfs import PartitionedMount
16 import mic.configmgr as configmgr
17 import mic.pluginmgr as pluginmgr
18 import mic.imager.raw as raw
19 import mic.chroot as chroot
20
21 class RawPlugin(ImagerPlugin):
22
23     @classmethod
24     def do_create(self, subcmd, opts, *args):
25         """${cmd_name}: create fs image
26
27         ${cmd_usage}
28         ${cmd_option_list}
29         """
30         if len(args) == 0:
31             return
32         if len(args) == 1:
33             ksconf = args[0]
34         else:
35             raise errors.Usage("Extra arguments given")
36
37         cfgmgr = configmgr.getConfigMgr()
38         creatoropts = cfgmgr.create
39         cfgmgr.setProperty("ksconf", ksconf)
40         plgmgr = pluginmgr.PluginMgr()
41         plgmgr.loadPlugins()
42         
43         for (key, pcls) in plgmgr.getBackendPlugins():
44             if key == creatoropts['pkgmgr']:
45                 pkgmgr = pcls
46
47         if not pkgmgr:
48             raise CreatorError("Can't find backend %s" % pkgmgr)
49
50         creator = raw.RawImageCreator(creatoropts, pkgmgr)
51         try:
52             creator.check_depend_tools()
53             creator.mount(None, creatoropts["cachedir"])
54             creator.install()
55             creator.configure(creatoropts["repomd"])
56             creator.unmount()
57             creator.package(creatoropts["outdir"])
58             outimage = creator.outimage
59             creator.print_outimage_info()
60             outimage = creator.outimage
61         except CreatorError, e:
62             raise CreatorError("failed to create image : %s" % e)
63         finally:
64             creator.cleanup()
65             print "Finished."
66         return 0
67     
68     @classmethod    
69     def do_chroot(cls, target):
70         img = target
71         imgsize = misc.get_file_size(img) * 1024L * 1024L
72         partedcmd = fs_related.find_binary_path("parted")
73         disk = fs_related.SparseLoopbackDisk(img, imgsize)
74         imgmnt = misc.mkdtemp()
75         imgloop = PartitionedMount({'/dev/sdb':disk}, imgmnt, skipformat = True)
76         img_fstype = "ext3"
77         
78         # Check the partitions from raw disk.
79         p1 = subprocess.Popen([partedcmd,"-s",img,"unit","B","print"],
80                               stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
81         out,err = p1.communicate()
82         lines = out.strip().split("\n")
83         
84         root_mounted = False
85         partition_mounts = 0
86
87         for line in lines:
88             line = line.strip()
89             # Lines that start with number are the partitions,
90             # because parted can be translated we can't refer to any text lines.
91             if not line or not line[0].isdigit():
92                 continue
93             
94             # Some vars have extra , as list seperator.
95             line = line.replace(",","")
96             
97             # Example of parted output lines that are handled:
98             # Number  Start        End          Size         Type     File system     Flags
99             #  1      512B         3400000511B  3400000000B  primary
100             #  2      3400531968B  3656384511B  255852544B   primary  linux-swap(v1)
101             #  3      3656384512B  3720347647B  63963136B    primary  fat16           boot, lba
102
103             partition_info = re.split("\s+",line)
104
105             size = partition_info[3].split("B")[0]
106
107             if len(partition_info) < 6 or partition_info[5] in ["boot"]:
108                 # No filesystem can be found from partition line. Assuming
109                 # btrfs, because that is the only MeeGo fs that parted does 
110                 # not recognize properly.
111                 # TODO: Can we make better assumption?
112                 fstype = "btrfs"
113             elif partition_info[5] in ["ext2","ext3","ext4","btrfs"]:
114                 fstype = partition_info[5]
115             elif partition_info[5] in ["fat16","fat32"]:
116                 fstype = "vfat"
117             elif "swap" in partition_info[5]:
118                 fstype = "swap"
119             else:
120                 raise CreatorError("Could not recognize partition fs type '%s'." % partition_info[5])
121
122             if not root_mounted and fstype in ["ext2","ext3","ext4","btrfs"]:
123                 # TODO: Check that this is actually the valid root partition from /etc/fstab
124                 mountpoint = "/"
125                 root_mounted = True
126             elif fstype == "swap":
127                 mountpoint = "swap"
128             else:
129                 # TODO: Assing better mount points for the rest of the partitions.
130                 partition_mounts += 1
131                 mountpoint = "/media/partition_%d" % partition_mounts
132
133             if "boot" in partition_info:
134                 boot = True
135             else:
136                 boot = False
137             
138             print "Size: %s Bytes, fstype: %s, mountpoint: %s, boot: %s" % ( size, fstype, mountpoint, boot )
139             # TODO: add_partition should take bytes as size parameter.
140             imgloop.add_partition((int)(size)/1024/1024, "/dev/sdb", mountpoint, fstype = fstype, boot = boot)
141         
142         try:
143             imgloop.mount()
144         except MountError, e:
145             imgloop.cleanup()
146             raise CreatorError("Failed to loopback mount '%s' : %s" %
147                                (img, e))
148
149         try:
150             chroot.chroot(imgmnt, None,  "/bin/env HOME=/root /bin/bash")
151         except:
152             raise CreatorError("Failed to chroot to %s." %img)  
153         finally:
154             chroot.cleanup_after_chroot("img", imgloop, None, imgmnt)
155             
156     @classmethod
157     def do_unpack(cls, srcimg):
158         srcimgsize = (misc.get_file_size(srcimg)) * 1024L * 1024L
159         srcmnt = misc.mkdtemp("srcmnt")
160         disk = fs_related.SparseLoopbackDisk(srcimg, srcimgsize)
161         srcloop = PartitionedMount({'/dev/sdb':disk}, srcmnt, skipformat = True)
162
163         srcloop.add_partition(srcimgsize/1024/1024, "/dev/sdb", "/", "ext3", boot=False)
164         try:
165             srcloop.mount()
166         except MountError, e:
167             srcloop.cleanup()
168             raise CreatorError("Failed to loopback mount '%s' : %s" %
169                                (srcimg, e))
170
171         image = os.path.join(tempfile.mkdtemp(dir = "/var/tmp", prefix = "tmp"), "meego.img")
172         ddcmd = misc.find_binary_path("dd")
173         args = [ ddcmd, "if=%s" % srcloop.partitions[0]['device'], "of=%s" % image ]
174         rc = subprocess.call(args)
175         if rc != 0:
176             raise CreatorError("Failed to dd")
177         srcloop.cleanup()
178         return image
179
180 mic_plugin = ["raw", RawPlugin]
181