xref: /OK3568_Linux_fs/yocto/poky/meta/lib/rootfspostcommands.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1#
2# SPDX-License-Identifier: GPL-2.0-only
3#
4
5import os
6
7def sort_file(filename, mapping):
8    """
9    Sorts a passwd or group file based on the numeric ID in the third column.
10    If a mapping is given, the name from the first column is mapped via that
11    dictionary instead (necessary for /etc/shadow and /etc/gshadow). If not,
12    a new mapping is created on the fly and returned.
13    """
14    new_mapping = {}
15    with open(filename, 'rb+') as f:
16        lines = f.readlines()
17        # No explicit error checking for the sake of simplicity. /etc
18        # files are assumed to be well-formed, causing exceptions if
19        # not.
20        for line in lines:
21            entries = line.split(b':')
22            name = entries[0]
23            if mapping is None:
24                id = int(entries[2])
25            else:
26                id = mapping[name]
27            new_mapping[name] = id
28        # Sort by numeric id first, with entire line as secondary key
29        # (just in case that there is more than one entry for the same id).
30        lines.sort(key=lambda line: (new_mapping[line.split(b':')[0]], line))
31        # We overwrite the entire file, i.e. no truncate() necessary.
32        f.seek(0)
33        f.write(b''.join(lines))
34    return new_mapping
35
36def remove_backup(filename):
37    """
38    Removes the backup file for files like /etc/passwd.
39    """
40    backup_filename = filename + '-'
41    if os.path.exists(backup_filename):
42        os.unlink(backup_filename)
43
44def sort_passwd(sysconfdir):
45    """
46    Sorts passwd and group files in a rootfs /etc directory by ID.
47    Backup files are sometimes are inconsistent and then cannot be
48    sorted (YOCTO #11043), and more importantly, are not needed in
49    the initial rootfs, so they get deleted.
50    """
51    for main, shadow in (('passwd', 'shadow'),
52                         ('group', 'gshadow')):
53        filename = os.path.join(sysconfdir, main)
54        remove_backup(filename)
55        if os.path.exists(filename):
56            mapping = sort_file(filename, None)
57            filename = os.path.join(sysconfdir, shadow)
58            remove_backup(filename)
59            if os.path.exists(filename):
60                 sort_file(filename, mapping)
61    # Drop other known backup shadow-utils.
62    for filename in (
63            'subgid',
64            'subuid',
65        ):
66        filepath = os.path.join(sysconfdir, filename)
67        remove_backup(filepath)
68