rootfspostcommands.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. #
  2. # SPDX-License-Identifier: GPL-2.0-only
  3. #
  4. import os
  5. def sort_file(filename, mapping):
  6. """
  7. Sorts a passwd or group file based on the numeric ID in the third column.
  8. If a mapping is given, the name from the first column is mapped via that
  9. dictionary instead (necessary for /etc/shadow and /etc/gshadow). If not,
  10. a new mapping is created on the fly and returned.
  11. """
  12. new_mapping = {}
  13. with open(filename, 'rb+') as f:
  14. lines = f.readlines()
  15. # No explicit error checking for the sake of simplicity. /etc
  16. # files are assumed to be well-formed, causing exceptions if
  17. # not.
  18. for line in lines:
  19. entries = line.split(b':')
  20. name = entries[0]
  21. if mapping is None:
  22. id = int(entries[2])
  23. else:
  24. id = mapping[name]
  25. new_mapping[name] = id
  26. # Sort by numeric id first, with entire line as secondary key
  27. # (just in case that there is more than one entry for the same id).
  28. lines.sort(key=lambda line: (new_mapping[line.split(b':')[0]], line))
  29. # We overwrite the entire file, i.e. no truncate() necessary.
  30. f.seek(0)
  31. f.write(b''.join(lines))
  32. return new_mapping
  33. def remove_backup(filename):
  34. """
  35. Removes the backup file for files like /etc/passwd.
  36. """
  37. backup_filename = filename + '-'
  38. if os.path.exists(backup_filename):
  39. os.unlink(backup_filename)
  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)