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