rootfspostcommands.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #
  2. # Copyright OpenEmbedded Contributors
  3. #
  4. # SPDX-License-Identifier: GPL-2.0-only
  5. #
  6. import os
  7. def sort_shadowutils_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. def sort_shadowutils_files(sysconfdir):
  36. """
  37. Sorts shadow-utils 'passwd' and 'group' files in a rootfs' /etc directory
  38. by ID.
  39. """
  40. for main, shadow in (('passwd', 'shadow'),
  41. ('group', 'gshadow')):
  42. filename = os.path.join(sysconfdir, main)
  43. if os.path.exists(filename):
  44. mapping = sort_shadowutils_file(filename, None)
  45. filename = os.path.join(sysconfdir, shadow)
  46. if os.path.exists(filename):
  47. sort_shadowutils_file(filename, mapping)
  48. def remove_shadowutils_backup_file(filename):
  49. """
  50. Remove shadow-utils backup file for files like /etc/passwd.
  51. """
  52. backup_filename = filename + '-'
  53. if os.path.exists(backup_filename):
  54. os.unlink(backup_filename)
  55. def remove_shadowutils_backup_files(sysconfdir):
  56. """
  57. Remove shadow-utils backup files in a rootfs /etc directory. They are not
  58. needed in the initial root filesystem and sorting them can be inconsistent
  59. (YOCTO #11043).
  60. """
  61. for filename in (
  62. 'group',
  63. 'gshadow',
  64. 'passwd',
  65. 'shadow',
  66. 'subgid',
  67. 'subuid',
  68. ):
  69. filepath = os.path.join(sysconfdir, filename)
  70. remove_shadowutils_backup_file(filepath)
  71. def tidy_shadowutils_files(sysconfdir):
  72. """
  73. Tidy up shadow-utils files.
  74. """
  75. remove_shadowutils_backup_files(sysconfdir)
  76. sort_shadowutils_files(sysconfdir)
  77. return True