Statistics
| Branch: | Tag: | Revision:

root / image_creator / os_type / linux.py @ 06bfd21a

History | View | Annotate | Download (12.1 kB)

1 121f3bc0 Nikos Skalkotos
# -*- coding: utf-8 -*-
2 121f3bc0 Nikos Skalkotos
#
3 ae48a082 Nikos Skalkotos
# Copyright 2012 GRNET S.A. All rights reserved.
4 ae48a082 Nikos Skalkotos
#
5 ae48a082 Nikos Skalkotos
# Redistribution and use in source and binary forms, with or
6 ae48a082 Nikos Skalkotos
# without modification, are permitted provided that the following
7 ae48a082 Nikos Skalkotos
# conditions are met:
8 ae48a082 Nikos Skalkotos
#
9 ae48a082 Nikos Skalkotos
#   1. Redistributions of source code must retain the above
10 ae48a082 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
11 ae48a082 Nikos Skalkotos
#      disclaimer.
12 ae48a082 Nikos Skalkotos
#
13 ae48a082 Nikos Skalkotos
#   2. Redistributions in binary form must reproduce the above
14 ae48a082 Nikos Skalkotos
#      copyright notice, this list of conditions and the following
15 ae48a082 Nikos Skalkotos
#      disclaimer in the documentation and/or other materials
16 ae48a082 Nikos Skalkotos
#      provided with the distribution.
17 ae48a082 Nikos Skalkotos
#
18 ae48a082 Nikos Skalkotos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 ae48a082 Nikos Skalkotos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ae48a082 Nikos Skalkotos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 ae48a082 Nikos Skalkotos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 ae48a082 Nikos Skalkotos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 ae48a082 Nikos Skalkotos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 ae48a082 Nikos Skalkotos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 ae48a082 Nikos Skalkotos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 ae48a082 Nikos Skalkotos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 ae48a082 Nikos Skalkotos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 ae48a082 Nikos Skalkotos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 ae48a082 Nikos Skalkotos
# POSSIBILITY OF SUCH DAMAGE.
30 ae48a082 Nikos Skalkotos
#
31 ae48a082 Nikos Skalkotos
# The views and conclusions contained in the software and
32 ae48a082 Nikos Skalkotos
# documentation are those of the authors and should not be
33 ae48a082 Nikos Skalkotos
# interpreted as representing official policies, either expressed
34 ae48a082 Nikos Skalkotos
# or implied, of GRNET S.A.
35 ae48a082 Nikos Skalkotos
36 121f3bc0 Nikos Skalkotos
"""This module hosts OS-specific code for Linux"""
37 121f3bc0 Nikos Skalkotos
38 f165adc0 Nikos Skalkotos
from image_creator.os_type.unix import Unix, sysprep
39 22a6d232 Nikos Skalkotos
40 a83f5185 Nikos Skalkotos
import re
41 3f70f242 Nikos Skalkotos
import time
42 aa2062ba Nikos Skalkotos
43 8c574358 Nikos Skalkotos
44 aa2062ba Nikos Skalkotos
class Linux(Unix):
45 88f83027 Nikos Skalkotos
    """OS class for Linux"""
46 d415dda2 Nikos Skalkotos
    def __init__(self, image, **kargs):
47 d415dda2 Nikos Skalkotos
        super(Linux, self).__init__(image, **kargs)
48 a83f5185 Nikos Skalkotos
        self._uuid = dict()
49 a83f5185 Nikos Skalkotos
        self._persistent = re.compile('/dev/[hsv]d[a-z][1-9]*')
50 a83f5185 Nikos Skalkotos
51 173022fb Nikos Skalkotos
    @sysprep('Removing user accounts with id greater that 1000', enabled=False)
52 173022fb Nikos Skalkotos
    def remove_user_accounts(self):
53 2dcd42b7 Nikos Skalkotos
        """Remove all user accounts with id greater than 1000"""
54 2dcd42b7 Nikos Skalkotos
55 2dcd42b7 Nikos Skalkotos
        if 'USERS' not in self.meta:
56 2dcd42b7 Nikos Skalkotos
            return
57 2dcd42b7 Nikos Skalkotos
58 2dcd42b7 Nikos Skalkotos
        # Remove users from /etc/passwd
59 2dcd42b7 Nikos Skalkotos
        passwd = []
60 2dcd42b7 Nikos Skalkotos
        removed_users = {}
61 2dcd42b7 Nikos Skalkotos
        metadata_users = self.meta['USERS'].split()
62 2dcd42b7 Nikos Skalkotos
        for line in self.g.cat('/etc/passwd').splitlines():
63 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
64 2dcd42b7 Nikos Skalkotos
            if int(fields[2]) > 1000:
65 2dcd42b7 Nikos Skalkotos
                removed_users[fields[0]] = fields
66 2dcd42b7 Nikos Skalkotos
                # remove it from the USERS metadata too
67 2dcd42b7 Nikos Skalkotos
                if fields[0] in metadata_users:
68 2dcd42b7 Nikos Skalkotos
                    metadata_users.remove(fields[0])
69 2dcd42b7 Nikos Skalkotos
            else:
70 2dcd42b7 Nikos Skalkotos
                passwd.append(':'.join(fields))
71 2dcd42b7 Nikos Skalkotos
72 2dcd42b7 Nikos Skalkotos
        self.meta['USERS'] = " ".join(metadata_users)
73 2dcd42b7 Nikos Skalkotos
74 2dcd42b7 Nikos Skalkotos
        # Delete the USERS metadata if empty
75 2dcd42b7 Nikos Skalkotos
        if not len(self.meta['USERS']):
76 2dcd42b7 Nikos Skalkotos
            del self.meta['USERS']
77 2dcd42b7 Nikos Skalkotos
78 2dcd42b7 Nikos Skalkotos
        self.g.write('/etc/passwd', '\n'.join(passwd) + '\n')
79 2dcd42b7 Nikos Skalkotos
80 2dcd42b7 Nikos Skalkotos
        # Remove the corresponding /etc/shadow entries
81 2dcd42b7 Nikos Skalkotos
        shadow = []
82 2dcd42b7 Nikos Skalkotos
        for line in self.g.cat('/etc/shadow').splitlines():
83 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
84 2dcd42b7 Nikos Skalkotos
            if fields[0] not in removed_users:
85 2dcd42b7 Nikos Skalkotos
                shadow.append(':'.join(fields))
86 2dcd42b7 Nikos Skalkotos
87 2dcd42b7 Nikos Skalkotos
        self.g.write('/etc/shadow', "\n".join(shadow) + '\n')
88 2dcd42b7 Nikos Skalkotos
89 2dcd42b7 Nikos Skalkotos
        # Remove the corresponding /etc/group entries
90 2dcd42b7 Nikos Skalkotos
        group = []
91 2dcd42b7 Nikos Skalkotos
        for line in self.g.cat('/etc/group').splitlines():
92 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
93 2dcd42b7 Nikos Skalkotos
            # Remove groups tha have the same name as the removed users
94 2dcd42b7 Nikos Skalkotos
            if fields[0] not in removed_users:
95 2dcd42b7 Nikos Skalkotos
                group.append(':'.join(fields))
96 2dcd42b7 Nikos Skalkotos
97 2dcd42b7 Nikos Skalkotos
        self.g.write('/etc/group', '\n'.join(group) + '\n')
98 2dcd42b7 Nikos Skalkotos
99 2dcd42b7 Nikos Skalkotos
        # Remove home directories
100 2dcd42b7 Nikos Skalkotos
        for home in [field[5] for field in removed_users.values()]:
101 2dcd42b7 Nikos Skalkotos
            if self.g.is_dir(home) and home.startswith('/home/'):
102 2dcd42b7 Nikos Skalkotos
                self.g.rm_rf(home)
103 2dcd42b7 Nikos Skalkotos
104 173022fb Nikos Skalkotos
    @sysprep('Cleaning up password & locking all user accounts')
105 173022fb Nikos Skalkotos
    def cleanup_passwords(self):
106 2dcd42b7 Nikos Skalkotos
        """Remove all passwords and lock all user accounts"""
107 2dcd42b7 Nikos Skalkotos
108 2dcd42b7 Nikos Skalkotos
        shadow = []
109 2dcd42b7 Nikos Skalkotos
110 2dcd42b7 Nikos Skalkotos
        for line in self.g.cat('/etc/shadow').splitlines():
111 2dcd42b7 Nikos Skalkotos
            fields = line.split(':')
112 2dcd42b7 Nikos Skalkotos
            if fields[1] not in ('*', '!'):
113 2dcd42b7 Nikos Skalkotos
                fields[1] = '!'
114 2dcd42b7 Nikos Skalkotos
115 2dcd42b7 Nikos Skalkotos
            shadow.append(":".join(fields))
116 2dcd42b7 Nikos Skalkotos
117 2dcd42b7 Nikos Skalkotos
        self.g.write('/etc/shadow', "\n".join(shadow) + '\n')
118 2dcd42b7 Nikos Skalkotos
119 173022fb Nikos Skalkotos
    @sysprep('Fixing acpid powerdown action')
120 173022fb Nikos Skalkotos
    def fix_acpid(self):
121 d144e954 Nikos Skalkotos
        """Replace acpid powerdown action scripts to immediately shutdown the
122 d144e954 Nikos Skalkotos
        system without checking if a GUI is running.
123 9cbb5794 Nikos Skalkotos
        """
124 22a6d232 Nikos Skalkotos
125 3f70f242 Nikos Skalkotos
        powerbtn_action = '#!/bin/sh\n\nPATH=/sbin:/bin:/usr/bin\n' \
126 f99fe99d Nikos Skalkotos
                          'shutdown -h now "Power button pressed"\n'
127 3f70f242 Nikos Skalkotos
128 3f70f242 Nikos Skalkotos
        events_dir = '/etc/acpi/events'
129 3f70f242 Nikos Skalkotos
        if not self.g.is_dir(events_dir):
130 e77e66a9 Nikos Skalkotos
            self.out.warn("No acpid event directory found")
131 3f70f242 Nikos Skalkotos
            return
132 3f70f242 Nikos Skalkotos
133 3f70f242 Nikos Skalkotos
        event_exp = re.compile('event=(.+)', re.I)
134 3f70f242 Nikos Skalkotos
        action_exp = re.compile('action=(.+)', re.I)
135 121f3bc0 Nikos Skalkotos
        for events_file in self.g.readdir(events_dir):
136 121f3bc0 Nikos Skalkotos
            if events_file['ftyp'] != 'r':
137 3f70f242 Nikos Skalkotos
                continue
138 3f70f242 Nikos Skalkotos
139 121f3bc0 Nikos Skalkotos
            fullpath = "%s/%s" % (events_dir, events_file['name'])
140 3f70f242 Nikos Skalkotos
            event = ""
141 3f70f242 Nikos Skalkotos
            action = ""
142 3f70f242 Nikos Skalkotos
            for line in self.g.cat(fullpath).splitlines():
143 121f3bc0 Nikos Skalkotos
                match = event_exp.match(line)
144 121f3bc0 Nikos Skalkotos
                if match:
145 121f3bc0 Nikos Skalkotos
                    event = match.group(1)
146 3f70f242 Nikos Skalkotos
                    continue
147 121f3bc0 Nikos Skalkotos
                match = action_exp.match(line)
148 121f3bc0 Nikos Skalkotos
                if match:
149 121f3bc0 Nikos Skalkotos
                    action = match.group(1)
150 3f70f242 Nikos Skalkotos
                    continue
151 3f70f242 Nikos Skalkotos
152 c0f3abdc Nikos Skalkotos
            if event.strip() in ("button[ /]power", "button/power.*"):
153 3f70f242 Nikos Skalkotos
                if action:
154 3f70f242 Nikos Skalkotos
                    if not self.g.is_file(action):
155 e77e66a9 Nikos Skalkotos
                        self.out.warn("Acpid action file: %s does not exist" %
156 f99fe99d Nikos Skalkotos
                                      action)
157 3f70f242 Nikos Skalkotos
                        return
158 f99fe99d Nikos Skalkotos
                    self.g.copy_file_to_file(action,
159 f99fe99d Nikos Skalkotos
                                             "%s.orig.snf-image-creator-%d" %
160 f99fe99d Nikos Skalkotos
                                             (action, time.time()))
161 d144e954 Nikos Skalkotos
                    self.g.write(action, powerbtn_action)
162 3f70f242 Nikos Skalkotos
                    return
163 3f70f242 Nikos Skalkotos
                else:
164 f99fe99d Nikos Skalkotos
                    self.out.warn("Acpid event file %s does not contain and "
165 f99fe99d Nikos Skalkotos
                                  "action")
166 3f70f242 Nikos Skalkotos
                    return
167 3f70f242 Nikos Skalkotos
            elif event.strip() == ".*":
168 f99fe99d Nikos Skalkotos
                self.out.warn("Found action `.*'. Don't know how to handle "
169 f99fe99d Nikos Skalkotos
                              "this. Please edit `%s' image file manually to "
170 f99fe99d Nikos Skalkotos
                              "make the system immediatelly shutdown when an "
171 f99fe99d Nikos Skalkotos
                              "power button acpi event occures." %
172 f99fe99d Nikos Skalkotos
                              action.strip().split()[0])
173 3f70f242 Nikos Skalkotos
                return
174 3f70f242 Nikos Skalkotos
175 c0f3abdc Nikos Skalkotos
        self.out.warn("No acpi power button event found!")
176 c0f3abdc Nikos Skalkotos
177 173022fb Nikos Skalkotos
    @sysprep('Removing persistent network interface names')
178 173022fb Nikos Skalkotos
    def remove_persistent_net_rules(self):
179 9cbb5794 Nikos Skalkotos
        """Remove udev rules that will keep network interface names persistent
180 9cbb5794 Nikos Skalkotos
        after hardware changes and reboots. Those rules will be created again
181 9cbb5794 Nikos Skalkotos
        the next time the image runs.
182 9cbb5794 Nikos Skalkotos
        """
183 22a6d232 Nikos Skalkotos
184 9cbb5794 Nikos Skalkotos
        rule_file = '/etc/udev/rules.d/70-persistent-net.rules'
185 9cbb5794 Nikos Skalkotos
        if self.g.is_file(rule_file):
186 9cbb5794 Nikos Skalkotos
            self.g.rm(rule_file)
187 9cbb5794 Nikos Skalkotos
188 173022fb Nikos Skalkotos
    @sysprep('Removing swap entry from fstab')
189 173022fb Nikos Skalkotos
    def remove_swap_entry(self):
190 4a2fd05c Nikos Skalkotos
        """Remove swap entry from /etc/fstab. If swap is the last partition
191 4a2fd05c Nikos Skalkotos
        then the partition will be removed when shrinking is performed. If the
192 4a2fd05c Nikos Skalkotos
        swap partition is not the last partition in the disk or if you are not
193 4a2fd05c Nikos Skalkotos
        going to shrink the image you should probably disable this.
194 4a2fd05c Nikos Skalkotos
        """
195 4a2fd05c Nikos Skalkotos
196 4a2fd05c Nikos Skalkotos
        new_fstab = ""
197 4a2fd05c Nikos Skalkotos
        fstab = self.g.cat('/etc/fstab')
198 4a2fd05c Nikos Skalkotos
        for line in fstab.splitlines():
199 4a2fd05c Nikos Skalkotos
200 4a2fd05c Nikos Skalkotos
            entry = line.split('#')[0].strip().split()
201 4a2fd05c Nikos Skalkotos
            if len(entry) == 6 and entry[2] == 'swap':
202 4a2fd05c Nikos Skalkotos
                continue
203 4a2fd05c Nikos Skalkotos
204 4a2fd05c Nikos Skalkotos
            new_fstab += "%s\n" % line
205 4a2fd05c Nikos Skalkotos
206 4a2fd05c Nikos Skalkotos
        self.g.write('/etc/fstab', new_fstab)
207 4a2fd05c Nikos Skalkotos
208 173022fb Nikos Skalkotos
    @sysprep('Replacing fstab & grub non-persistent device references')
209 173022fb Nikos Skalkotos
    def use_persistent_block_device_names(self):
210 f165adc0 Nikos Skalkotos
        """Scan fstab & grub configuration files and replace all non-persistent
211 dcf9274b Vangelis Koukis
        device references with UUIDs.
212 9cbb5794 Nikos Skalkotos
        """
213 22a6d232 Nikos Skalkotos
214 a83f5185 Nikos Skalkotos
        # convert all devices in fstab to persistent
215 a83f5185 Nikos Skalkotos
        persistent_root = self._persistent_fstab()
216 a83f5185 Nikos Skalkotos
217 a83f5185 Nikos Skalkotos
        # convert all devices in grub1 to persistent
218 a83f5185 Nikos Skalkotos
        self._persistent_grub1(persistent_root)
219 a83f5185 Nikos Skalkotos
220 9cbb5794 Nikos Skalkotos
    def _persistent_grub1(self, new_root):
221 121f3bc0 Nikos Skalkotos
        """Replaces non-persistent device name occurencies with persistent
222 121f3bc0 Nikos Skalkotos
        ones in GRUB1 configuration files.
223 121f3bc0 Nikos Skalkotos
        """
224 a83f5185 Nikos Skalkotos
        if self.g.is_file('/boot/grub/menu.lst'):
225 a83f5185 Nikos Skalkotos
            grub1 = '/boot/grub/menu.lst'
226 a83f5185 Nikos Skalkotos
        elif self.g.is_file('/etc/grub.conf'):
227 a83f5185 Nikos Skalkotos
            grub1 = '/etc/grub.conf'
228 a83f5185 Nikos Skalkotos
        else:
229 a83f5185 Nikos Skalkotos
            return
230 a83f5185 Nikos Skalkotos
231 a83f5185 Nikos Skalkotos
        self.g.aug_init('/', 0)
232 a83f5185 Nikos Skalkotos
        try:
233 a83f5185 Nikos Skalkotos
            roots = self.g.aug_match('/files%s/title[*]/kernel/root' % grub1)
234 a83f5185 Nikos Skalkotos
            for root in roots:
235 a83f5185 Nikos Skalkotos
                dev = self.g.aug_get(root)
236 121f3bc0 Nikos Skalkotos
                if not self._is_persistent(dev):
237 a83f5185 Nikos Skalkotos
                    # This is not always correct. Grub may contain root entries
238 a83f5185 Nikos Skalkotos
                    # for other systems, but we only support 1 OS per hard
239 a83f5185 Nikos Skalkotos
                    # disk, so this shouldn't harm.
240 a83f5185 Nikos Skalkotos
                    self.g.aug_set(root, new_root)
241 a83f5185 Nikos Skalkotos
        finally:
242 a83f5185 Nikos Skalkotos
            self.g.aug_save()
243 a83f5185 Nikos Skalkotos
            self.g.aug_close()
244 a83f5185 Nikos Skalkotos
245 a83f5185 Nikos Skalkotos
    def _persistent_fstab(self):
246 121f3bc0 Nikos Skalkotos
        """Replaces non-persistent device name occurencies in /etc/fstab with
247 121f3bc0 Nikos Skalkotos
        persistent ones.
248 121f3bc0 Nikos Skalkotos
        """
249 a83f5185 Nikos Skalkotos
        mpoints = self.g.mountpoints()
250 a83f5185 Nikos Skalkotos
        if len(mpoints) == 0:
251 a83f5185 Nikos Skalkotos
            pass  # TODO: error handling
252 a83f5185 Nikos Skalkotos
253 a83f5185 Nikos Skalkotos
        device_dict = dict([[mpoint, dev] for dev, mpoint in mpoints])
254 a83f5185 Nikos Skalkotos
255 a83f5185 Nikos Skalkotos
        root_dev = None
256 a83f5185 Nikos Skalkotos
        new_fstab = ""
257 a83f5185 Nikos Skalkotos
        fstab = self.g.cat('/etc/fstab')
258 a83f5185 Nikos Skalkotos
        for line in fstab.splitlines():
259 a83f5185 Nikos Skalkotos
260 a83f5185 Nikos Skalkotos
            line, dev, mpoint = self._convert_fstab_line(line, device_dict)
261 a83f5185 Nikos Skalkotos
            new_fstab += "%s\n" % line
262 a83f5185 Nikos Skalkotos
263 a83f5185 Nikos Skalkotos
            if mpoint == '/':
264 a83f5185 Nikos Skalkotos
                root_dev = dev
265 a83f5185 Nikos Skalkotos
266 a83f5185 Nikos Skalkotos
        self.g.write('/etc/fstab', new_fstab)
267 a83f5185 Nikos Skalkotos
        if root_dev is None:
268 a83f5185 Nikos Skalkotos
            pass  # TODO: error handling
269 a83f5185 Nikos Skalkotos
270 a83f5185 Nikos Skalkotos
        return root_dev
271 a83f5185 Nikos Skalkotos
272 a83f5185 Nikos Skalkotos
    def _convert_fstab_line(self, line, devices):
273 121f3bc0 Nikos Skalkotos
        """Replace non-persistent device names in an fstab line to their UUID
274 121f3bc0 Nikos Skalkotos
        equivalent
275 121f3bc0 Nikos Skalkotos
        """
276 a83f5185 Nikos Skalkotos
        orig = line
277 a83f5185 Nikos Skalkotos
        line = line.split('#')[0].strip()
278 a83f5185 Nikos Skalkotos
        if len(line) == 0:
279 a83f5185 Nikos Skalkotos
            return orig, "", ""
280 a83f5185 Nikos Skalkotos
281 a83f5185 Nikos Skalkotos
        entry = line.split()
282 a83f5185 Nikos Skalkotos
        if len(entry) != 6:
283 e77e66a9 Nikos Skalkotos
            self.out.warn("Detected abnormal entry in fstab")
284 a83f5185 Nikos Skalkotos
            return orig, "", ""
285 a83f5185 Nikos Skalkotos
286 a83f5185 Nikos Skalkotos
        dev = entry[0]
287 a83f5185 Nikos Skalkotos
        mpoint = entry[1]
288 a83f5185 Nikos Skalkotos
289 121f3bc0 Nikos Skalkotos
        if not self._is_persistent(dev):
290 a83f5185 Nikos Skalkotos
            if mpoint in devices:
291 121f3bc0 Nikos Skalkotos
                dev = "UUID=%s" % self._get_uuid(devices[mpoint])
292 a83f5185 Nikos Skalkotos
                entry[0] = dev
293 a83f5185 Nikos Skalkotos
            else:
294 a83f5185 Nikos Skalkotos
                # comment out the entry
295 a83f5185 Nikos Skalkotos
                entry[0] = "#%s" % dev
296 a83f5185 Nikos Skalkotos
            return " ".join(entry), dev, mpoint
297 a83f5185 Nikos Skalkotos
298 a83f5185 Nikos Skalkotos
        return orig, dev, mpoint
299 aa2062ba Nikos Skalkotos
300 121f3bc0 Nikos Skalkotos
    def _do_collect_metadata(self):
301 121f3bc0 Nikos Skalkotos
        """Collect metadata about the OS"""
302 121f3bc0 Nikos Skalkotos
        super(Linux, self)._do_collect_metadata()
303 121f3bc0 Nikos Skalkotos
        self.meta["USERS"] = " ".join(self._get_passworded_users())
304 121f3bc0 Nikos Skalkotos
305 121f3bc0 Nikos Skalkotos
        # Delete the USERS metadata if empty
306 121f3bc0 Nikos Skalkotos
        if not len(self.meta['USERS']):
307 121f3bc0 Nikos Skalkotos
            self.out.warn("No passworded users found!")
308 121f3bc0 Nikos Skalkotos
            del self.meta['USERS']
309 121f3bc0 Nikos Skalkotos
310 121f3bc0 Nikos Skalkotos
    def _get_passworded_users(self):
311 121f3bc0 Nikos Skalkotos
        """Returns a list of non-locked user accounts"""
312 121f3bc0 Nikos Skalkotos
        users = []
313 121f3bc0 Nikos Skalkotos
        regexp = re.compile('(\S+):((?:!\S+)|(?:[^!*]\S+)|):(?:\S*:){6}')
314 121f3bc0 Nikos Skalkotos
315 121f3bc0 Nikos Skalkotos
        for line in self.g.cat('/etc/shadow').splitlines():
316 121f3bc0 Nikos Skalkotos
            match = regexp.match(line)
317 121f3bc0 Nikos Skalkotos
            if not match:
318 121f3bc0 Nikos Skalkotos
                continue
319 121f3bc0 Nikos Skalkotos
320 121f3bc0 Nikos Skalkotos
            user, passwd = match.groups()
321 121f3bc0 Nikos Skalkotos
            if len(passwd) > 0 and passwd[0] == '!':
322 121f3bc0 Nikos Skalkotos
                self.out.warn("Ignoring locked %s account." % user)
323 121f3bc0 Nikos Skalkotos
            else:
324 121f3bc0 Nikos Skalkotos
                users.append(user)
325 121f3bc0 Nikos Skalkotos
326 121f3bc0 Nikos Skalkotos
        return users
327 121f3bc0 Nikos Skalkotos
328 121f3bc0 Nikos Skalkotos
    def _is_persistent(self, dev):
329 121f3bc0 Nikos Skalkotos
        """Checks if a device name is persistent."""
330 121f3bc0 Nikos Skalkotos
        return not self._persistent.match(dev)
331 121f3bc0 Nikos Skalkotos
332 121f3bc0 Nikos Skalkotos
    def _get_uuid(self, dev):
333 121f3bc0 Nikos Skalkotos
        """Returns the UUID corresponding to a device"""
334 121f3bc0 Nikos Skalkotos
        if dev in self._uuid:
335 121f3bc0 Nikos Skalkotos
            return self._uuid[dev]
336 121f3bc0 Nikos Skalkotos
337 121f3bc0 Nikos Skalkotos
        uuid = self.g.vfs_uuid(dev)
338 121f3bc0 Nikos Skalkotos
        assert len(uuid)
339 121f3bc0 Nikos Skalkotos
        self._uuid[dev] = uuid
340 121f3bc0 Nikos Skalkotos
        return uuid
341 121f3bc0 Nikos Skalkotos
342 aa2062ba Nikos Skalkotos
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :