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