fda6df3da6f8c551522d036a1e3a41fe72909a5c
[matrix.git] / matrix / rootfs.py
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2007-2008 Movial Oy
4 # Authors: Kalle Vahlman <kalle.vahlman@movial.fi>
5
6 import errno
7 import os
8 import re
9 import shutil
10 import sys
11
12 class RootFS(object):
13         builddir = "/tmp"
14         target = None
15
16         # Tools
17         strip = "strip"
18         mknod = "fakeroot -i /tmp/env.faked -s /tmp/env.faked mknod"
19         chmod = "fakeroot -i /tmp/env.faked -s /tmp/env.faked chmod"
20         chown = "fakeroot -i /tmp/env.faked -s /tmp/env.faked chown"
21         mkfs = "fakeroot -i /tmp/env.faked -s /tmp/env.faked mkfs.jffs2"
22         tar = "fakeroot -i /tmp/env.faked -s /tmp/env.faked tar"
23         flash_erase_size = "0x4000"
24         flash_pad_size = "0x3e00000"
25
26         file_list = []
27         remove_list = []
28
29         created_paths = []
30         devices = {}
31         chown_owner = {}
32
33         def __init__(self, mytarget):
34                 self.target = mytarget
35
36         def include_paths(self, paths):
37                 old_dir = os.getcwd()
38                 os.chdir("/targets")
39
40                 # Traverse include_paths hierarchies and grab all files there
41                 for path in paths:
42                         for root, dirs, files in os.walk(self.target + path):
43                                 for f in files:
44                                         self.file_list.append("%s/%s" % (root, f))
45                                 if len(files) == 0:
46                                         self.file_list.append(root)
47
48                 os.chdir(old_dir)
49
50         def include_files(self, files):
51                 old_dir = os.getcwd()
52                 os.chdir("/targets")
53
54                 # Append included individual files
55                 for f in files:
56                         self.file_list.append(self.target + f)
57
58                 os.chdir(old_dir)
59
60         def filter_paths(self, paths):
61                 # Filter out files in exluded paths
62                 for f in self.file_list:
63                         for d in paths:
64                                 if f == self.target + d or f.startswith(self.target + d + '/'):
65                                         self.remove_list.append(f)
66
67         def filter_files(self, files):
68                 # Filter out exluded files
69                 for f in files:
70                         self.remove_list.append(self.target + f)
71
72         def filter_expressions(self, expressions):
73                 # Filter out files matching exluded patterns
74                 compiled_patterns = []
75                 for pattern_str in expressions:
76                         compiled_patterns.append(re.compile(pattern_str))
77
78                 for f in self.file_list:
79                         for pattern in compiled_patterns:
80                                 if pattern.search(f):
81                                         self.remove_list.append(f)
82
83         def add_paths(self, paths):
84                 for path in paths:
85                         self.created_paths.append(path)
86
87         def set_devices(self, devices):
88                 self.devices = devices
89
90         def set_change_owner(self, change_owner):
91                 self.change_owner= change_owner
92
93         def set_erase_size(self, size):
94                 self.flash_erase_size = size
95
96         def set_pad_size(self, size):
97                 self.flash_pad_size = size
98
99         def generate(self, clean, build_target="all"):
100                 copy_list = self.file_list
101
102                 for f in self.remove_list:
103                                 try:
104                                         copy_list.remove(f)
105                                 except:
106                                         pass
107
108                 n_files = len(copy_list)*1.0
109                 current_percent = 0.0
110                 current_file = 0.0
111
112                 old_dir = os.getcwd()
113                 os.chdir("/targets")
114
115                 if os.path.exists(os.path.join(self.builddir, self.target)):
116                         print "%s exists, please remove it and try again" % os.path.join(self.builddir, self.target)
117                         return
118
119                 # Copy the wanted files, strip binaries
120                 print "Copying files..."
121                 for f in copy_list:
122                         if f[0] == '/':
123                                 f = f[1:]
124                         path = os.path.join(self.builddir, os.path.dirname(f))
125                         try:
126                                 os.makedirs(path)
127                         except OSError, e:
128                                 if e.errno == errno.EEXIST:
129                                         pass
130
131                         if os.path.islink(f):
132                                 link_dest = os.readlink(f)
133                                 os.symlink(link_dest, os.path.join(self.builddir, f))
134                         elif os.path.isdir(f):
135                                 try:
136                                         os.makedirs(os.path.join(self.builddir, f))
137                                 except OSError, e:
138                                         if e.errno == errno.EEXIST:
139                                                 pass
140                         else:
141                                 shutil.copy(f, path)
142                                 if not f.endswith(".ko"):
143                                         os.system(self.strip + " " + os.path.join(path,os.path.basename(f)) + " &> /dev/null")
144
145                         if (current_file/n_files)*100 > current_percent:
146                                 current_percent += 10.0
147                                 print "%0.1f%%" % current_percent,
148                                 sys.stdout.flush()
149
150                         current_file += 1.0
151
152                 # Create extra directory structure
153                 print "\nCreating extra directories..."
154                 for d in self.created_paths:
155                         if d[0] == '/':
156                                 d = d[1:]
157                         path = os.path.join(self.builddir, self.target, d)
158                         try:
159                                 os.makedirs(path)
160                         except OSError, e:
161                                 if e.errno == errno.EEXIST:
162                                         pass
163
164                 # Remove always the fakeroot environment.
165                 if os.path.exists("/tmp/env.faked"):
166                         os.remove("/tmp/env.faked")
167                 os.system("touch /tmp/env.faked")
168
169                 # Create device nodes
170                 print "Creating device nodes..."
171                 for d in self.devices.keys():
172                         mode = "664"
173                         if len(self.devices[d]) == 3:
174                                 device_type,major,minor = self.devices[d]
175                         else:
176                                 device_type,major,minor,mode = self.devices[d]
177                         os.system("%s -m %s %s/%s/dev/%s %s %i %i" % (self.mknod, mode, self.builddir, self.target, d, device_type, major, minor))
178
179                 # Fix permissions
180                 print "Adjusting ownerships and permissions..."
181                 # Make the whole fs root-owned
182                 os.system("%s root.root -R %s/%s" % (self.chown, self.builddir, self.target))
183
184                 # For sshd:
185                 os.system("%s go-r %s/%s/etc/ssh*key*" % (self.chmod, self.builddir, self.target))
186
187                 # For /var/empty (sshd requires this):
188                 os.system("%s go-rw /%s/%s/var/empty" % (self.chmod, self.builddir, self.target))
189
190                 # /dev/null needs to be writable by all:
191                 os.system("%s a+rw /%s/%s/dev/null" % (self.chmod, self.builddir, self.target))
192
193                 # Set non-root owners
194                 print "Setting non-root owner ships..."
195                 for d in self.change_owner.keys():
196                         dir = d
197                         if dir[0] == '/':
198                                 dir = dir[1:]
199                         if os.path.exists(os.path.join(self.builddir, self.target, dir)):
200                                 user,group = self.change_owner[d]
201                                 os.system("%s %s.%s -R %s/%s/%s " % (self.chown, user, group, self.builddir, self.target, dir))
202
203                 if build_target is "all" or build_target is "rootfs":
204                         print "Creating a rootfs..."
205                         os.system("%s -c --one-file-system -C %s/%s -z -f %s/%s.tgz ." % (self.tar, self.builddir, self.target, self.builddir, self.target))
206                 if build_target is "all" or build_target is "jffs2":
207                         print "Creating a root image..."
208                         os.system("%s -p%s -n -e%s -r %s/%s -o %s/%s.jffs2" % (self.mkfs, self.flash_pad_size, self.flash_erase_size, self.builddir, self.target, self.builddir, self.target))
209                 if build_target is "all" or build_target is "devrootfs":
210                         print "Creating a rootstrap..."
211                         os.system("%s -c --one-file-system -C /targets/%s -z -f %s/%s-rootstrap.tgz ." % ("tar", self.target, self.builddir, self.target))
212
213                 os.chdir(old_dir)
214
215                 print "Build finished:"
216                 if build_target is "all" or build_target is "rootfs":
217                         s = os.stat(self.builddir + "/" + self.target + ".tgz");
218                         print "\t%s/%s.tgz\t%0.2f MiB" % (self.builddir, self.target, s.st_size/1024.0/1024.0)
219                 if build_target is "all" or build_target is "jffs2":
220                         s = os.stat(self.builddir + "/" + self.target + ".jffs2");
221                         print "\t%s/%s.jffs2\t%0.2f MiB" % (self.builddir, self.target, s.st_size/1024.0/1024.0)
222                 if build_target is "all" or build_target is "devrootfs":
223                         s = os.stat(self.builddir + "/" + self.target + "-rootstrap.tgz");
224                         print "\t%s/%s-rootstrap.tgz\t%0.2f MiB" % (self.builddir, self.target, s.st_size/1024.0/1024.0)
225
226                 if clean:
227                         print "Cleaning up"
228                         os.remove("/tmp/env.faked")
229                         os.system("rm -rf %s/%s" % (self.builddir, self.target))
230
231
232 #rootfs = RootFS("ROOTFS")
233 #rootfs.include_paths(include_paths)
234 #rootfs.include_files(include_files)
235 #rootfs.filter_paths(exclude_paths)
236 #rootfs.filter_files(exclude_files)
237 #rootfs.filter_expressions(exclude_expressions)
238 #rootfs.add_paths(created_paths)
239 #rootfs.set_devices(devices)
240
241 #rootfs.generate()