Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 1 | import os |
| 2 | |
| 3 | def 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 | |
| 32 | def 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 | |
| 40 | def 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) |