1 # Copyright 2012 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
11 # 2. Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following
13 # disclaimer in the documentation and/or other materials
14 # provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
34 from image_creator.os_type.unix import Unix, sysprep
41 """OS class for Linux"""
42 def __init__(self, rootdev, ghandler, output):
43 super(Linux, self).__init__(rootdev, ghandler, output)
45 self._persistent = re.compile('/dev/[hsv]d[a-z][1-9]*')
47 def is_persistent(self, dev):
48 return not self._persistent.match(dev)
50 def get_uuid(self, dev):
52 return self._uuid[dev]
54 uuid = self.g.vfs_uuid(dev)
56 self._uuid[dev] = uuid
60 def fix_acpid(self, print_header=True):
61 """Replace acpid powerdown action scripts to immediately shutdown the
62 system without checking if a GUI is running.
66 self.out.output('Fixing acpid powerdown action')
68 powerbtn_action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n' \
69 'shutdown -h now "Power button pressed"\n'
71 events_dir = '/etc/acpi/events'
72 if not self.g.is_dir(events_dir):
73 self.out.warn("No acpid event directory found")
76 event_exp = re.compile('event=(.+)', re.I)
77 action_exp = re.compile('action=(.+)', re.I)
78 for f in self.g.readdir(events_dir):
82 fullpath = "%s/%s" % (events_dir, f['name'])
85 for line in self.g.cat(fullpath).splitlines():
86 m = event_exp.match(line)
90 m = action_exp.match(line)
95 if event.strip() in ("button[ /]power", "button/power.*"):
97 if not self.g.is_file(action):
98 self.out.warn("Acpid action file: %s does not exist" %
101 self.g.copy_file_to_file(action,
102 "%s.orig.snf-image-creator-%d" %
103 (action, time.time()))
104 self.g.write(action, powerbtn_action)
107 self.out.warn("Acpid event file %s does not contain and "
110 elif event.strip() == ".*":
111 self.out.warn("Found action `.*'. Don't know how to handle "
112 "this. Please edit `%s' image file manually to "
113 "make the system immediatelly shutdown when an "
114 "power button acpi event occures." %
115 action.strip().split()[0])
118 self.out.warn("No acpi power button event found!")
121 def remove_persistent_net_rules(self, print_header=True):
122 """Remove udev rules that will keep network interface names persistent
123 after hardware changes and reboots. Those rules will be created again
124 the next time the image runs.
128 self.out.output('Removing persistent network interface names')
130 rule_file = '/etc/udev/rules.d/70-persistent-net.rules'
131 if self.g.is_file(rule_file):
135 def remove_swap_entry(self, print_header=True):
136 """Remove swap entry from /etc/fstab. If swap is the last partition
137 then the partition will be removed when shrinking is performed. If the
138 swap partition is not the last partition in the disk or if you are not
139 going to shrink the image you should probably disable this.
143 self.out.output('Removing swap entry from fstab')
146 fstab = self.g.cat('/etc/fstab')
147 for line in fstab.splitlines():
149 entry = line.split('#')[0].strip().split()
150 if len(entry) == 6 and entry[2] == 'swap':
153 new_fstab += "%s\n" % line
155 self.g.write('/etc/fstab', new_fstab)
158 def use_persistent_block_device_names(self, print_header=True):
159 """Scan fstab & grub configuration files and replace all non-persistent
160 device references with UUIDs.
164 self.out.output("Replacing fstab & grub non-persistent device "
167 # convert all devices in fstab to persistent
168 persistent_root = self._persistent_fstab()
170 # convert all devices in grub1 to persistent
171 self._persistent_grub1(persistent_root)
173 def _persistent_grub1(self, new_root):
174 if self.g.is_file('/boot/grub/menu.lst'):
175 grub1 = '/boot/grub/menu.lst'
176 elif self.g.is_file('/etc/grub.conf'):
177 grub1 = '/etc/grub.conf'
181 self.g.aug_init('/', 0)
183 roots = self.g.aug_match('/files%s/title[*]/kernel/root' % grub1)
185 dev = self.g.aug_get(root)
186 if not self.is_persistent(dev):
187 # This is not always correct. Grub may contain root entries
188 # for other systems, but we only support 1 OS per hard
189 # disk, so this shouldn't harm.
190 self.g.aug_set(root, new_root)
195 def _persistent_fstab(self):
196 mpoints = self.g.mountpoints()
197 if len(mpoints) == 0:
198 pass # TODO: error handling
200 device_dict = dict([[mpoint, dev] for dev, mpoint in mpoints])
204 fstab = self.g.cat('/etc/fstab')
205 for line in fstab.splitlines():
207 line, dev, mpoint = self._convert_fstab_line(line, device_dict)
208 new_fstab += "%s\n" % line
213 self.g.write('/etc/fstab', new_fstab)
215 pass # TODO: error handling
219 def _convert_fstab_line(self, line, devices):
221 line = line.split('#')[0].strip()
227 self.out.warn("Detected abnormal entry in fstab")
233 if not self.is_persistent(dev):
234 if mpoint in devices:
235 dev = "UUID=%s" % self.get_uuid(devices[mpoint])
238 # comment out the entry
239 entry[0] = "#%s" % dev
240 return " ".join(entry), dev, mpoint
242 return orig, dev, mpoint
244 # vim: set sta sts=4 shiftwidth=4 sw=4 et ai :