diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/add-git-hook.sh | 13 | ||||
-rwxr-xr-x | tools/check-efi-alignment.py | 36 | ||||
-rw-r--r-- | tools/check-version-history.py | 7 | ||||
-rw-r--r-- | tools/command_ignorelist | 6 | ||||
-rwxr-xr-x | tools/dbus_exporter.py | 2 | ||||
-rw-r--r-- | tools/dbus_ignorelist | 46 | ||||
-rwxr-xr-x | tools/elf2efi.py | 252 | ||||
-rwxr-xr-x | tools/git-contrib.sh | 12 | ||||
-rwxr-xr-x | tools/git-setup.sh | 16 | ||||
-rwxr-xr-x | tools/make-man-index.py | 2 | ||||
-rwxr-xr-x | tools/meson-extract-unit-files.py | 20 | ||||
-rwxr-xr-x | tools/meson-render-jinja2.py | 9 | ||||
-rwxr-xr-x | tools/meson-vcs-tag.sh | 33 | ||||
-rwxr-xr-x | tools/update-dbus-docs.py | 15 | ||||
-rwxr-xr-x | tools/update-distro-hash.py | 89 | ||||
-rwxr-xr-x | tools/update-man-rules.py | 1 |
16 files changed, 346 insertions, 213 deletions
diff --git a/tools/add-git-hook.sh b/tools/add-git-hook.sh deleted file mode 100755 index 8cff62e..0000000 --- a/tools/add-git-hook.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eu - -cd "${MESON_SOURCE_ROOT:?}" - -if [ ! -f .git/hooks/pre-commit.sample ] || [ -f .git/hooks/pre-commit ]; then - exit 2 # not needed -fi - -cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit -chmod +x .git/hooks/pre-commit -echo 'Activated pre-commit hook' diff --git a/tools/check-efi-alignment.py b/tools/check-efi-alignment.py new file mode 100755 index 0000000..26d5f5e --- /dev/null +++ b/tools/check-efi-alignment.py @@ -0,0 +1,36 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1-or-later +# vi: set tw=110 sw=4 ts=4 et: + +import sys + +try: + import pefile +except ImportError as e: + print(str(e), file=sys.stderr) + sys.exit(77) + + +def main(): + pe = pefile.PE(sys.argv[1], fast_load=True) + + for section in pe.sections: + name = section.Name.rstrip(b"\x00").decode() + file_addr = section.PointerToRawData + virt_addr = section.VirtualAddress + print(f"{name:10s} file=0x{file_addr:08x} virt=0x{virt_addr:08x}") + + if file_addr % 512 != 0: + print(f"File address of {name} section is not aligned to 512 bytes", file=sys.stderr) + return 1 + + if virt_addr % 512 != 0: + print(f"Virt address of {name} section is not aligned to 512 bytes", file=sys.stderr) + return 1 + +if __name__ == '__main__': + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} pe-image") + sys.exit(1) + + sys.exit(main()) diff --git a/tools/check-version-history.py b/tools/check-version-history.py index c4d4b3e..d4a87df 100644 --- a/tools/check-version-history.py +++ b/tools/check-version-history.py @@ -3,7 +3,12 @@ import os import sys -import lxml.etree as tree + +try: + import lxml.etree as tree +except ImportError as e: + print(str(e), file=sys.stderr) + sys.exit(77) _parser = tree.XMLParser(resolve_entities=False) tree.set_default_parser(_parser) diff --git a/tools/command_ignorelist b/tools/command_ignorelist index 186136d..af694c1 100644 --- a/tools/command_ignorelist +++ b/tools/command_ignorelist @@ -169,9 +169,9 @@ systemd-nspawn.xml /refsect1[title="Options"]/refsect2[title="Execution Options" systemd-nspawn.xml /refsect1[title="Options"]/refsect2[title="System Identity Options"]/variablelist/varlistentry[term="--uuid="] systemd-nspawn.xml /refsect1[title="Options"]/refsect2[title="Networking Options"]/variablelist/varlistentry[term="--private-network"] systemd-nspawn.xml /refsect1[title="Options"]/refsect2[title="Image Options"]/variablelist/varlistentry[term="--read-only"] -systemd-tmpfiles.xml /refsect1[title="Options"]/variablelist/varlistentry[term="--create"] -systemd-tmpfiles.xml /refsect1[title="Options"]/variablelist/varlistentry[term="--clean"] -systemd-tmpfiles.xml /refsect1[title="Options"]/variablelist/varlistentry[term="--remove"] +systemd-tmpfiles.xml /refsect1[title="Commands and options"]/variablelist/varlistentry[term="--create"] +systemd-tmpfiles.xml /refsect1[title="Commands and options"]/variablelist/varlistentry[term="--clean"] +systemd-tmpfiles.xml /refsect1[title="Commands and options"]/variablelist/varlistentry[term="--remove"] systemd-tmpfiles.xml /refsect1[title="Options"]/variablelist/varlistentry[term="--prefix=path"] systemd.automount.xml /refsect1[title="Options"]/variablelist/varlistentry[term="Where="] systemd.automount.xml /refsect1[title="Options"]/variablelist/varlistentry[term="DirectoryMode="] diff --git a/tools/dbus_exporter.py b/tools/dbus_exporter.py index 819584d..db95a58 100755 --- a/tools/dbus_exporter.py +++ b/tools/dbus_exporter.py @@ -36,6 +36,8 @@ def main(): args = parser.parse_args() args.output.mkdir(exist_ok=True) + # Make sure we don't inherit any setgid/setuid bit or such. + args.output.chmod(mode=0o755) for exe in args.executables: extract_interfaces_xml(args.output, exe) diff --git a/tools/dbus_ignorelist b/tools/dbus_ignorelist index d0c2150..71bdad8 100644 --- a/tools/dbus_ignorelist +++ b/tools/dbus_ignorelist @@ -82,12 +82,12 @@ org.freedesktop.import1.Manager.ImportTar() org.freedesktop.import1.Manager.ListTransfers() org.freedesktop.import1.Manager.PullRaw() org.freedesktop.import1.Manager.PullTar() -org.freedesktop.import1.Manager.TransferNew -org.freedesktop.import1.Manager.TransferRemoved +org.freedesktop.import1.Manager.TransferNew() +org.freedesktop.import1.Manager.TransferRemoved() org.freedesktop.import1.Transfer.Cancel() org.freedesktop.import1.Transfer.Id org.freedesktop.import1.Transfer.Local -org.freedesktop.import1.Transfer.LogMessage +org.freedesktop.import1.Transfer.LogMessage() org.freedesktop.import1.Transfer.Progress org.freedesktop.import1.Transfer.Remote org.freedesktop.import1.Transfer.Type @@ -168,8 +168,8 @@ org.freedesktop.login1.Manager.NCurrentSessions org.freedesktop.login1.Manager.OnExternalPower org.freedesktop.login1.Manager.PowerOff() org.freedesktop.login1.Manager.PowerOffWithFlags() -org.freedesktop.login1.Manager.PrepareForShutdown -org.freedesktop.login1.Manager.PrepareForSleep +org.freedesktop.login1.Manager.PrepareForShutdown() +org.freedesktop.login1.Manager.PrepareForSleep() org.freedesktop.login1.Manager.PreparingForShutdown org.freedesktop.login1.Manager.PreparingForSleep org.freedesktop.login1.Manager.Reboot() @@ -184,10 +184,10 @@ org.freedesktop.login1.Manager.RuntimeDirectoryInodesMax org.freedesktop.login1.Manager.RuntimeDirectorySize org.freedesktop.login1.Manager.ScheduleShutdown() org.freedesktop.login1.Manager.ScheduledShutdown -org.freedesktop.login1.Manager.SeatNew -org.freedesktop.login1.Manager.SeatRemoved -org.freedesktop.login1.Manager.SessionNew -org.freedesktop.login1.Manager.SessionRemoved +org.freedesktop.login1.Manager.SeatNew() +org.freedesktop.login1.Manager.SeatRemoved() +org.freedesktop.login1.Manager.SessionNew() +org.freedesktop.login1.Manager.SessionRemoved() org.freedesktop.login1.Manager.SessionsMax org.freedesktop.login1.Manager.SetRebootParameter() org.freedesktop.login1.Manager.SetRebootToBootLoaderEntry() @@ -204,8 +204,8 @@ org.freedesktop.login1.Manager.TerminateSession() org.freedesktop.login1.Manager.TerminateUser() org.freedesktop.login1.Manager.UnlockSession() org.freedesktop.login1.Manager.UnlockSessions() -org.freedesktop.login1.Manager.UserNew -org.freedesktop.login1.Manager.UserRemoved +org.freedesktop.login1.Manager.UserNew() +org.freedesktop.login1.Manager.UserRemoved() org.freedesktop.login1.Manager.UserStopDelayUSec org.freedesktop.login1.Manager.WallMessage org.freedesktop.login1.Seat.ActivateSession() @@ -237,14 +237,14 @@ org.freedesktop.login1.Session.Lock org.freedesktop.login1.Session.Lock() org.freedesktop.login1.Session.LockedHint org.freedesktop.login1.Session.Name -org.freedesktop.login1.Session.PauseDevice +org.freedesktop.login1.Session.PauseDevice() org.freedesktop.login1.Session.PauseDeviceComplete() org.freedesktop.login1.Session.ReleaseControl() org.freedesktop.login1.Session.ReleaseDevice() org.freedesktop.login1.Session.Remote org.freedesktop.login1.Session.RemoteHost org.freedesktop.login1.Session.RemoteUser -org.freedesktop.login1.Session.ResumeDevice +org.freedesktop.login1.Session.ResumeDevice() org.freedesktop.login1.Session.Scope org.freedesktop.login1.Session.Seat org.freedesktop.login1.Session.Service @@ -343,8 +343,8 @@ org.freedesktop.machine1.Manager.GetMachineUIDShift() org.freedesktop.machine1.Manager.KillMachine() org.freedesktop.machine1.Manager.ListImages() org.freedesktop.machine1.Manager.ListMachines() -org.freedesktop.machine1.Manager.MachineNew -org.freedesktop.machine1.Manager.MachineRemoved +org.freedesktop.machine1.Manager.MachineNew() +org.freedesktop.machine1.Manager.MachineRemoved() org.freedesktop.machine1.Manager.MapFromMachineGroup() org.freedesktop.machine1.Manager.MapFromMachineUser() org.freedesktop.machine1.Manager.MapToMachineGroup() @@ -653,8 +653,8 @@ org.freedesktop.systemd1.Manager.InitRDUnitsLoadFinishTimestamp org.freedesktop.systemd1.Manager.InitRDUnitsLoadFinishTimestampMonotonic org.freedesktop.systemd1.Manager.InitRDUnitsLoadStartTimestamp org.freedesktop.systemd1.Manager.InitRDUnitsLoadStartTimestampMonotonic -org.freedesktop.systemd1.Manager.JobNew -org.freedesktop.systemd1.Manager.JobRemoved +org.freedesktop.systemd1.Manager.JobNew() +org.freedesktop.systemd1.Manager.JobRemoved() org.freedesktop.systemd1.Manager.KExec() org.freedesktop.systemd1.Manager.KExecWatchdogUSec org.freedesktop.systemd1.Manager.KernelTimestamp @@ -696,7 +696,7 @@ org.freedesktop.systemd1.Manager.Reload() org.freedesktop.systemd1.Manager.ReloadOrRestartUnit() org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit() org.freedesktop.systemd1.Manager.ReloadUnit() -org.freedesktop.systemd1.Manager.Reloading +org.freedesktop.systemd1.Manager.Reloading() org.freedesktop.systemd1.Manager.ResetFailed() org.freedesktop.systemd1.Manager.ResetFailedUnit() org.freedesktop.systemd1.Manager.RestartUnit() @@ -717,7 +717,7 @@ org.freedesktop.systemd1.Manager.StartTransientUnit() org.freedesktop.systemd1.Manager.StartUnit() org.freedesktop.systemd1.Manager.StartUnitReplace() org.freedesktop.systemd1.Manager.StartUnitWithFlags() -org.freedesktop.systemd1.Manager.StartupFinished +org.freedesktop.systemd1.Manager.StartupFinished() org.freedesktop.systemd1.Manager.StopUnit() org.freedesktop.systemd1.Manager.Subscribe() org.freedesktop.systemd1.Manager.SwitchRoot() @@ -726,10 +726,10 @@ org.freedesktop.systemd1.Manager.Tainted org.freedesktop.systemd1.Manager.ThawUnit() org.freedesktop.systemd1.Manager.TimerSlackNSec org.freedesktop.systemd1.Manager.TryRestartUnit() -org.freedesktop.systemd1.Manager.UnitFilesChanged -org.freedesktop.systemd1.Manager.UnitNew +org.freedesktop.systemd1.Manager.UnitFilesChanged() +org.freedesktop.systemd1.Manager.UnitNew() org.freedesktop.systemd1.Manager.UnitPath -org.freedesktop.systemd1.Manager.UnitRemoved +org.freedesktop.systemd1.Manager.UnitRemoved() org.freedesktop.systemd1.Manager.UnitsLoadFinishTimestamp org.freedesktop.systemd1.Manager.UnitsLoadFinishTimestampMonotonic org.freedesktop.systemd1.Manager.UnitsLoadStartTimestamp @@ -1078,7 +1078,7 @@ org.freedesktop.systemd1.Scope.MemoryLow org.freedesktop.systemd1.Scope.MemoryMax org.freedesktop.systemd1.Scope.MemoryMin org.freedesktop.systemd1.Scope.MemorySwapMax -org.freedesktop.systemd1.Scope.RequestStop +org.freedesktop.systemd1.Scope.RequestStop() org.freedesktop.systemd1.Scope.RestartKillSignal org.freedesktop.systemd1.Scope.RestrictNetworkInterfaces org.freedesktop.systemd1.Scope.Result diff --git a/tools/elf2efi.py b/tools/elf2efi.py index 54f64fa..cb1a284 100755 --- a/tools/elf2efi.py +++ b/tools/elf2efi.py @@ -26,6 +26,7 @@ import hashlib import io import os import pathlib +import sys import time import typing from ctypes import ( @@ -55,26 +56,26 @@ from elftools.elf.relocation import ( class PeCoffHeader(LittleEndianStructure): _fields_ = ( - ("Machine", c_uint16), - ("NumberOfSections", c_uint16), - ("TimeDateStamp", c_uint32), + ("Machine", c_uint16), + ("NumberOfSections", c_uint16), + ("TimeDateStamp", c_uint32), ("PointerToSymbolTable", c_uint32), - ("NumberOfSymbols", c_uint32), + ("NumberOfSymbols", c_uint32), ("SizeOfOptionalHeader", c_uint16), - ("Characteristics", c_uint16), + ("Characteristics", c_uint16), ) class PeDataDirectory(LittleEndianStructure): _fields_ = ( ("VirtualAddress", c_uint32), - ("Size", c_uint32), + ("Size", c_uint32), ) class PeRelocationBlock(LittleEndianStructure): _fields_ = ( - ("PageRVA", c_uint32), + ("PageRVA", c_uint32), ("BlockSize", c_uint32), ) @@ -86,62 +87,62 @@ class PeRelocationBlock(LittleEndianStructure): class PeRelocationEntry(LittleEndianStructure): _fields_ = ( ("Offset", c_uint16, 12), - ("Type", c_uint16, 4), + ("Type", c_uint16, 4), ) class PeOptionalHeaderStart(LittleEndianStructure): _fields_ = ( - ("Magic", c_uint16), - ("MajorLinkerVersion", c_uint8), - ("MinorLinkerVersion", c_uint8), - ("SizeOfCode", c_uint32), - ("SizeOfInitializedData", c_uint32), + ("Magic", c_uint16), + ("MajorLinkerVersion", c_uint8), + ("MinorLinkerVersion", c_uint8), + ("SizeOfCode", c_uint32), + ("SizeOfInitializedData", c_uint32), ("SizeOfUninitializedData", c_uint32), - ("AddressOfEntryPoint", c_uint32), - ("BaseOfCode", c_uint32), + ("AddressOfEntryPoint", c_uint32), + ("BaseOfCode", c_uint32), ) class PeOptionalHeaderMiddle(LittleEndianStructure): _fields_ = ( - ("SectionAlignment", c_uint32), - ("FileAlignment", c_uint32), + ("SectionAlignment", c_uint32), + ("FileAlignment", c_uint32), ("MajorOperatingSystemVersion", c_uint16), ("MinorOperatingSystemVersion", c_uint16), - ("MajorImageVersion", c_uint16), - ("MinorImageVersion", c_uint16), - ("MajorSubsystemVersion", c_uint16), - ("MinorSubsystemVersion", c_uint16), - ("Win32VersionValue", c_uint32), - ("SizeOfImage", c_uint32), - ("SizeOfHeaders", c_uint32), - ("CheckSum", c_uint32), - ("Subsystem", c_uint16), - ("DllCharacteristics", c_uint16), + ("MajorImageVersion", c_uint16), + ("MinorImageVersion", c_uint16), + ("MajorSubsystemVersion", c_uint16), + ("MinorSubsystemVersion", c_uint16), + ("Win32VersionValue", c_uint32), + ("SizeOfImage", c_uint32), + ("SizeOfHeaders", c_uint32), + ("CheckSum", c_uint32), + ("Subsystem", c_uint16), + ("DllCharacteristics", c_uint16), ) class PeOptionalHeaderEnd(LittleEndianStructure): _fields_ = ( - ("LoaderFlags", c_uint32), - ("NumberOfRvaAndSizes", c_uint32), - ("ExportTable", PeDataDirectory), - ("ImportTable", PeDataDirectory), - ("ResourceTable", PeDataDirectory), - ("ExceptionTable", PeDataDirectory), - ("CertificateTable", PeDataDirectory), - ("BaseRelocationTable", PeDataDirectory), - ("Debug", PeDataDirectory), - ("Architecture", PeDataDirectory), - ("GlobalPtr", PeDataDirectory), - ("TLSTable", PeDataDirectory), - ("LoadConfigTable", PeDataDirectory), - ("BoundImport", PeDataDirectory), - ("IAT", PeDataDirectory), + ("LoaderFlags", c_uint32), + ("NumberOfRvaAndSizes", c_uint32), + ("ExportTable", PeDataDirectory), + ("ImportTable", PeDataDirectory), + ("ResourceTable", PeDataDirectory), + ("ExceptionTable", PeDataDirectory), + ("CertificateTable", PeDataDirectory), + ("BaseRelocationTable", PeDataDirectory), + ("Debug", PeDataDirectory), + ("Architecture", PeDataDirectory), + ("GlobalPtr", PeDataDirectory), + ("TLSTable", PeDataDirectory), + ("LoadConfigTable", PeDataDirectory), + ("BoundImport", PeDataDirectory), + ("IAT", PeDataDirectory), ("DelayImportDescriptor", PeDataDirectory), - ("CLRRuntimeHeader", PeDataDirectory), - ("Reserved", PeDataDirectory), + ("CLRRuntimeHeader", PeDataDirectory), + ("Reserved", PeDataDirectory), ) @@ -152,44 +153,44 @@ class PeOptionalHeader(LittleEndianStructure): class PeOptionalHeader32(PeOptionalHeader): _anonymous_ = ("Start", "Middle", "End") _fields_ = ( - ("Start", PeOptionalHeaderStart), - ("BaseOfData", c_uint32), - ("ImageBase", c_uint32), - ("Middle", PeOptionalHeaderMiddle), + ("Start", PeOptionalHeaderStart), + ("BaseOfData", c_uint32), + ("ImageBase", c_uint32), + ("Middle", PeOptionalHeaderMiddle), ("SizeOfStackReserve", c_uint32), - ("SizeOfStackCommit", c_uint32), - ("SizeOfHeapReserve", c_uint32), - ("SizeOfHeapCommit", c_uint32), - ("End", PeOptionalHeaderEnd), + ("SizeOfStackCommit", c_uint32), + ("SizeOfHeapReserve", c_uint32), + ("SizeOfHeapCommit", c_uint32), + ("End", PeOptionalHeaderEnd), ) class PeOptionalHeader32Plus(PeOptionalHeader): _anonymous_ = ("Start", "Middle", "End") _fields_ = ( - ("Start", PeOptionalHeaderStart), - ("ImageBase", c_uint64), - ("Middle", PeOptionalHeaderMiddle), + ("Start", PeOptionalHeaderStart), + ("ImageBase", c_uint64), + ("Middle", PeOptionalHeaderMiddle), ("SizeOfStackReserve", c_uint64), - ("SizeOfStackCommit", c_uint64), - ("SizeOfHeapReserve", c_uint64), - ("SizeOfHeapCommit", c_uint64), - ("End", PeOptionalHeaderEnd), + ("SizeOfStackCommit", c_uint64), + ("SizeOfHeapReserve", c_uint64), + ("SizeOfHeapCommit", c_uint64), + ("End", PeOptionalHeaderEnd), ) class PeSection(LittleEndianStructure): _fields_ = ( - ("Name", c_char * 8), - ("VirtualSize", c_uint32), - ("VirtualAddress", c_uint32), - ("SizeOfRawData", c_uint32), - ("PointerToRawData", c_uint32), + ("Name", c_char * 8), + ("VirtualSize", c_uint32), + ("VirtualAddress", c_uint32), + ("SizeOfRawData", c_uint32), + ("PointerToRawData", c_uint32), ("PointerToRelocations", c_uint32), ("PointerToLinenumbers", c_uint32), - ("NumberOfRelocations", c_uint16), - ("NumberOfLinenumbers", c_uint16), - ("Characteristics", c_uint32), + ("NumberOfRelocations", c_uint16), + ("NumberOfLinenumbers", c_uint16), + ("Characteristics", c_uint32), ) def __init__(self): @@ -206,12 +207,13 @@ assert sizeof(PeOptionalHeader32Plus) == 240 PE_CHARACTERISTICS_RX = 0x60000020 # CNT_CODE|MEM_READ|MEM_EXECUTE PE_CHARACTERISTICS_RW = 0xC0000040 # CNT_INITIALIZED_DATA|MEM_READ|MEM_WRITE -PE_CHARACTERISTICS_R = 0x40000040 # CNT_INITIALIZED_DATA|MEM_READ +PE_CHARACTERISTICS_R = 0x40000040 # CNT_INITIALIZED_DATA|MEM_READ IGNORE_SECTIONS = [ ".eh_frame", ".eh_frame_hdr", ".ARM.exidx", + ".relro_padding", ] IGNORE_SECTION_TYPES = [ @@ -246,9 +248,12 @@ def align_down(x: int, align: int) -> int: def next_section_address(sections: typing.List[PeSection]) -> int: - return align_to( - sections[-1].VirtualAddress + sections[-1].VirtualSize, SECTION_ALIGNMENT - ) + return align_to(sections[-1].VirtualAddress + sections[-1].VirtualSize, + SECTION_ALIGNMENT) + + +class BadSectionError(ValueError): + "One of the sections is in a bad state" def iter_copy_sections(elf: ELFFile) -> typing.Iterator[PeSection]: @@ -261,8 +266,9 @@ def iter_copy_sections(elf: ELFFile) -> typing.Iterator[PeSection]: relro = None for elf_seg in elf.iter_segments(): if elf_seg["p_type"] == "PT_LOAD" and elf_seg["p_align"] != SECTION_ALIGNMENT: - raise RuntimeError("ELF segments are not properly aligned.") - elif elf_seg["p_type"] == "PT_GNU_RELRO": + raise BadSectionError(f"ELF segment {elf_seg['p_type']} is not properly aligned" + f" ({elf_seg['p_align']} != {SECTION_ALIGNMENT})") + if elf_seg["p_type"] == "PT_GNU_RELRO": relro = elf_seg for elf_s in elf.iter_sections(): @@ -270,10 +276,14 @@ def iter_copy_sections(elf: ELFFile) -> typing.Iterator[PeSection]: elf_s["sh_flags"] & SH_FLAGS.SHF_ALLOC == 0 or elf_s["sh_type"] in IGNORE_SECTION_TYPES or elf_s.name in IGNORE_SECTIONS + or elf_s["sh_size"] == 0 ): continue if elf_s["sh_type"] not in ["SHT_PROGBITS", "SHT_NOBITS"]: - raise RuntimeError(f"Unknown section {elf_s.name}.") + raise BadSectionError(f"Unknown section {elf_s.name} with type {elf_s['sh_type']}") + if elf_s.name == '.got': + # FIXME: figure out why those sections are inserted + print("WARNING: Non-empty .got section", file=sys.stderr) if elf_s["sh_flags"] & SH_FLAGS.SHF_EXECINSTR: rwx = PE_CHARACTERISTICS_RX @@ -305,7 +315,7 @@ def iter_copy_sections(elf: ELFFile) -> typing.Iterator[PeSection]: def convert_sections(elf: ELFFile, opt: PeOptionalHeader) -> typing.List[PeSection]: - last_vma = 0 + last_vma = (0, 0) sections = [] for pe_s in iter_copy_sections(elf): @@ -325,10 +335,11 @@ def convert_sections(elf: ELFFile, opt: PeOptionalHeader) -> typing.List[PeSecti PE_CHARACTERISTICS_R: b".rodata", }[pe_s.Characteristics] - # This can happen if not building with `-z separate-code`. - if pe_s.VirtualAddress < last_vma: - raise RuntimeError("Overlapping PE sections.") - last_vma = pe_s.VirtualAddress + pe_s.VirtualSize + # This can happen if not building with '-z separate-code'. + if pe_s.VirtualAddress < sum(last_vma): + raise BadSectionError(f"Section {pe_s.Name.decode()!r} @0x{pe_s.VirtualAddress:x} overlaps" + f" previous section @0x{last_vma[0]:x}+0x{last_vma[1]:x}=@0x{sum(last_vma):x}") + last_vma = (pe_s.VirtualAddress, pe_s.VirtualSize) if pe_s.Name == b".text": opt.BaseOfCode = pe_s.VirtualAddress @@ -355,9 +366,9 @@ def copy_sections( if not elf_s: continue if elf_s.data_alignment > 1 and SECTION_ALIGNMENT % elf_s.data_alignment != 0: - raise RuntimeError(f"ELF section {name} is not aligned.") + raise BadSectionError(f"ELF section {name} is not aligned") if elf_s["sh_flags"] & (SH_FLAGS.SHF_EXECINSTR | SH_FLAGS.SHF_WRITE) != 0: - raise RuntimeError(f"ELF section {name} is not read-only data.") + raise BadSectionError(f"ELF section {name} is not read-only data") pe_s = PeSection() pe_s.Name = name.encode() @@ -376,12 +387,8 @@ def apply_elf_relative_relocation( sections: typing.List[PeSection], addend_size: int, ): - # fmt: off - [target] = [ - pe_s for pe_s in sections - if pe_s.VirtualAddress <= reloc["r_offset"] < pe_s.VirtualAddress + len(pe_s.data) - ] - # fmt: on + [target] = [pe_s for pe_s in sections + if pe_s.VirtualAddress <= reloc["r_offset"] < pe_s.VirtualAddress + len(pe_s.data)] addend_offset = reloc["r_offset"] - target.VirtualAddress @@ -425,9 +432,10 @@ def convert_elf_reloc_table( continue if reloc["r_info_type"] == RELATIVE_RELOC: - apply_elf_relative_relocation( - reloc, elf_image_base, sections, elf.elfclass // 8 - ) + apply_elf_relative_relocation(reloc, + elf_image_base, + sections, + elf.elfclass // 8) # Now that the ELF relocation has been applied, we can create a PE relocation. block_rva = reloc["r_offset"] & ~0xFFF @@ -442,7 +450,7 @@ def convert_elf_reloc_table( continue - raise RuntimeError(f"Unsupported relocation {reloc}") + raise BadSectionError(f"Unsupported relocation {reloc}") def convert_elf_relocations( @@ -453,27 +461,25 @@ def convert_elf_relocations( ) -> typing.Optional[PeSection]: dynamic = elf.get_section_by_name(".dynamic") if dynamic is None: - raise RuntimeError("ELF .dynamic section is missing.") + raise BadSectionError("ELF .dynamic section is missing") [flags_tag] = dynamic.iter_tags("DT_FLAGS_1") if not flags_tag["d_val"] & ENUM_DT_FLAGS_1["DF_1_PIE"]: - raise RuntimeError("ELF file is not a PIE.") + raise ValueError("ELF file is not a PIE") # This checks that the ELF image base is 0. symtab = elf.get_section_by_name(".symtab") if symtab: exe_start = symtab.get_symbol_by_name("__executable_start") if exe_start and exe_start[0]["st_value"] != 0: - raise RuntimeError("Unexpected ELF image base.") - - opt.SizeOfHeaders = align_to( - PE_OFFSET - + len(PE_MAGIC) - + sizeof(PeCoffHeader) - + sizeof(opt) - + sizeof(PeSection) * max(len(sections) + 1, minimum_sections), - FILE_ALIGNMENT, - ) + raise ValueError("Unexpected ELF image base") + + opt.SizeOfHeaders = align_to(PE_OFFSET + + len(PE_MAGIC) + + sizeof(PeCoffHeader) + + sizeof(opt) + + sizeof(PeSection) * max(len(sections) + 1, minimum_sections), + FILE_ALIGNMENT) # We use the basic VMA layout from the ELF image in the PE image. This could cause the first # section to overlap the PE image headers during runtime at VMA 0. We can simply apply a fixed @@ -482,9 +488,8 @@ def convert_elf_relocations( # the ELF portions of the image. segment_offset = 0 if sections[0].VirtualAddress < opt.SizeOfHeaders: - segment_offset = align_to( - opt.SizeOfHeaders - sections[0].VirtualAddress, SECTION_ALIGNMENT - ) + segment_offset = align_to(opt.SizeOfHeaders - sections[0].VirtualAddress, + SECTION_ALIGNMENT) opt.AddressOfEntryPoint = elf["e_entry"] + segment_offset opt.BaseOfCode += segment_offset @@ -494,10 +499,12 @@ def convert_elf_relocations( pe_reloc_blocks: typing.Dict[int, PeRelocationBlock] = {} for reloc_type, reloc_table in dynamic.get_relocation_tables().items(): if reloc_type not in ["REL", "RELA"]: - raise RuntimeError("Unsupported relocation type {elf_reloc_type}.") - convert_elf_reloc_table( - elf, reloc_table, opt.ImageBase + segment_offset, sections, pe_reloc_blocks - ) + raise BadSectionError(f"Unsupported relocation type {reloc_type}") + convert_elf_reloc_table(elf, + reloc_table, + opt.ImageBase + segment_offset, + sections, + pe_reloc_blocks) for pe_s in sections: pe_s.VirtualAddress += segment_offset @@ -517,9 +524,7 @@ def convert_elf_relocations( block.entries.append(PeRelocationEntry()) block.PageRVA += segment_offset - block.BlockSize = ( - sizeof(PeRelocationBlock) + sizeof(PeRelocationEntry) * n_relocs - ) + block.BlockSize = sizeof(PeRelocationBlock) + sizeof(PeRelocationEntry) * n_relocs data += block for entry in sorted(block.entries, key=lambda e: e.Offset): data += entry @@ -539,7 +544,10 @@ def convert_elf_relocations( def write_pe( - file, coff: PeCoffHeader, opt: PeOptionalHeader, sections: typing.List[PeSection] + file, + coff: PeCoffHeader, + opt: PeOptionalHeader, + sections: typing.List[PeSection], ): file.write(b"MZ") file.seek(0x3C, io.SEEK_SET) @@ -552,8 +560,8 @@ def write_pe( offset = opt.SizeOfHeaders for pe_s in sorted(sections, key=lambda s: s.VirtualAddress): if pe_s.VirtualAddress < opt.SizeOfHeaders: - # Linker script should make sure this does not happen. - raise RuntimeError(f"Section {pe_s.Name} overlapping PE headers.") + raise BadSectionError(f"Section {pe_s.Name} @0x{pe_s.VirtualAddress:x} overlaps" + " PE headers ending at 0x{opt.SizeOfHeaders:x}") pe_s.PointerToRawData = offset file.write(pe_s) @@ -571,9 +579,9 @@ def write_pe( def elf2efi(args: argparse.Namespace): elf = ELFFile(args.ELF) if not elf.little_endian: - raise RuntimeError("ELF file is not little-endian.") + raise ValueError("ELF file is not little-endian") if elf["e_type"] not in ["ET_DYN", "ET_EXEC"]: - raise RuntimeError("Unsupported ELF type.") + raise ValueError(f"Unsupported ELF type {elf['e_type']}") pe_arch = { "EM_386": 0x014C, @@ -584,7 +592,7 @@ def elf2efi(args: argparse.Namespace): "EM_X86_64": 0x8664, }.get(elf["e_machine"]) if pe_arch is None: - raise RuntimeError(f"Unsupported ELF arch {elf['e_machine']}") + raise ValueError(f"Unsupported ELF architecture {elf['e_machine']}") coff = PeCoffHeader() opt = PeOptionalHeader32() if elf.elfclass == 32 else PeOptionalHeader32Plus() @@ -637,7 +645,7 @@ def elf2efi(args: argparse.Namespace): write_pe(args.PE, coff, opt, sections) -def main(): +def create_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Convert ELF binaries to PE/EFI") parser.add_argument( "--version-major", @@ -691,7 +699,11 @@ def main(): default="", help="Copy these sections if found", ) + return parser + +def main(): + parser = create_parser() elf2efi(parser.parse_args()) diff --git a/tools/git-contrib.sh b/tools/git-contrib.sh index 6371d49..2cbcf6c 100755 --- a/tools/git-contrib.sh +++ b/tools/git-contrib.sh @@ -3,13 +3,7 @@ set -eu tag="$(git describe --abbrev=0 --match 'v[0-9][0-9][0-9]')" -( - # authors - git log --pretty=tformat:%aN -s "${tag}.." - # Co-authors (drop empty line and mail addresses) - git log --pretty='tformat:%(trailers:key=Co-authored-by,valueonly)' -s "${tag}.." | sed -e '/^[[:space:]]*$/ d' | sed -e 's/ <.*@.*>$//' -) | - grep -v noreply@weblate.org | - sed 's/ / /g; s/--/-/g; s/.*/\0,/' | - sort -u | tr '\n' ' ' | sed -e "s/^/Contributions from: /g" -e "s/,\s*$/\n/g" | fold -w 72 -s | +git shortlog -s --group=author --group=trailer:Co-authored-by "${tag}.." | + sed -e 's/^[[:space:]]*[0-9]*[[:space:]]*//; /Weblate/ d; /dependabot\[bot\]/ d; s/ / /g; s/--/-/g; s/.*/\0,/' | + tr '\n' ' ' | sed -e "s/^/Contributions from: /g" -e "s/,\s*$/\n/g" | fold -w 72 -s | sed -e "s/^/ /g" -e "s/\s*$//g" diff --git a/tools/git-setup.sh b/tools/git-setup.sh new file mode 100755 index 0000000..b5903b4 --- /dev/null +++ b/tools/git-setup.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eu + +cd "${MESON_SOURCE_ROOT:?}" + +ret=2 + +if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then + cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit + chmod +x .git/hooks/pre-commit + echo 'Activated pre-commit hook' + ret=0 +fi + +exit $ret diff --git a/tools/make-man-index.py b/tools/make-man-index.py index 579dd40..b4b262b 100755 --- a/tools/make-man-index.py +++ b/tools/make-man-index.py @@ -46,7 +46,7 @@ This index contains {count} entries, referring to {pages} individual manual page def check_id(page, t): page_id = t.getroot().get('id') - if not re.search('/' + page_id + '[.]', page): + if not re.search('/' + page_id + '[.]', page.translate(str.maketrans('@', '_'))): raise ValueError(f"id='{page_id}' is not the same as page name '{page}'") def make_index(pages): diff --git a/tools/meson-extract-unit-files.py b/tools/meson-extract-unit-files.py new file mode 100755 index 0000000..f2b4fa3 --- /dev/null +++ b/tools/meson-extract-unit-files.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +import json +import re +import subprocess +import sys + +def main(): + build_dir = sys.argv[1] + + out = subprocess.run(["meson", "introspect", "--installed", build_dir], + stdout=subprocess.PIPE, check=True) + files = json.loads(out.stdout) + for file in sorted(files.values()): + if re.search("^/usr/lib/systemd/(system|user)/", file) and not file.endswith(".conf"): + print(file) + +if __name__ == "__main__": + main() diff --git a/tools/meson-render-jinja2.py b/tools/meson-render-jinja2.py index 3a3d912..977de79 100755 --- a/tools/meson-render-jinja2.py +++ b/tools/meson-render-jinja2.py @@ -33,12 +33,11 @@ def render(filename, defines): def main(): defines = parse_config_h(sys.argv[1]) - defines.update(parse_config_h(sys.argv[2])) - output = render(sys.argv[3], defines) - with open(sys.argv[4], 'w') as f: + output = render(sys.argv[2], defines) + with open(sys.argv[3], 'w') as f: f.write(output) - info = os.stat(sys.argv[3]) - os.chmod(sys.argv[4], info.st_mode) + info = os.stat(sys.argv[2]) + os.chmod(sys.argv[3], info.st_mode) if __name__ == '__main__': main() diff --git a/tools/meson-vcs-tag.sh b/tools/meson-vcs-tag.sh deleted file mode 100755 index 4a8dc89..0000000 --- a/tools/meson-vcs-tag.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later - -set -u -set -o pipefail - -dir="${1:?}" -fallback="${2:?}" -version_tag="${3:-}" - -if [ -n "${version_tag}" ]; then - # If -Dversion_tag= was used, just use that without further changes. - echo "${version_tag}" -else - # Check that we have either .git/ (a normal clone) or a .git file (a work-tree) - # and that we don't get confused if a tarball is extracted in a higher-level - # git repository. - # - # If the working tree has no tags (CI builds), the first git-describe will fail - # and we fall back to project_version-commitid instead. - - c='' - if [ -e "${dir}/.git" ]; then - c="$(git -C "$dir" describe --abbrev=7 --dirty=^ 2>/dev/null)" - if [ -z "$c" ]; then - # This call might still fail with permission issues - suffix="$(git -C "$dir" describe --always --abbrev=7 --dirty=^ 2>/dev/null)" - [ -n "$suffix" ] && c="${fallback}-${suffix}" - fi - fi - [ -z "$c" ] && c="${fallback}" - echo "$c" | sed 's/^v//; s/-rc/~rc/' -fi diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index 008f7d4..ce7161c 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -152,12 +152,17 @@ def check_documented(document, declarations, stats, interface, missing_version): stats['total'] += len(items) for item in items: - if klass == 'method': + if klass in ('method', 'signal'): elem = 'function' item_repr = f'{item}()' - elif klass == 'signal': - elem = 'function' - item_repr = item + + # Find all functions/signals in <function> elements that are not + # suffixed with '()' and fix them + for section in sections: + element = section.find(f".//{elem}[. = '{item}']") + if element is not None: + element.text = item_repr + elif klass == 'property': elem = 'varname' item_repr = item @@ -259,7 +264,7 @@ def subst_output(document, programlisting, stats, missing_version): variablelist = etree.Element("variablelist") variablelist.attrib['class'] = 'dbus-'+decl_type variablelist.attrib['generated'] = 'True' - if decl_type == 'method' : + if decl_type in ('method', 'signal'): variablelist.attrib['extra-ref'] = declaration + '()' else: variablelist.attrib['extra-ref'] = declaration diff --git a/tools/update-distro-hash.py b/tools/update-distro-hash.py new file mode 100755 index 0000000..16ed2e7 --- /dev/null +++ b/tools/update-distro-hash.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +""" +Fetch commits for pkg/{distribution} and, if changed, commit the latest hash. +""" + +import argparse +import json +import shlex +import subprocess +from pathlib import Path + +def parse_args(): + p = argparse.ArgumentParser( + description=__doc__, + ) + p.add_argument( + 'distribution', + nargs='+', + ) + p.add_argument( + '--no-fetch', + dest='fetch', + action='store_false', + default=True, + ) + return p.parse_args() + +def read_config(distro: str): + cmd = ['mkosi', '--json', '-d', distro, 'summary'] + print(f"+ {shlex.join(cmd)}") + text = subprocess.check_output(cmd, text=True) + + data = json.loads(text) + return data['Images'][-1] + +def commit_file(distro: str, file: Path, commit: str, changes: str): + message = '\n'.join(( + f'mkosi: update {distro} commit reference', + '', + changes)) + + cmd = ['git', 'commit', '-m', message, str(file)] + print(f"+ {shlex.join(cmd)}") + subprocess.check_call(cmd) + +def update_distro(args, distro: str): + cmd = ['git', '-C', f'pkg/{distro}', 'fetch'] + print(f"+ {shlex.join(cmd)}") + subprocess.check_call(cmd) + + config = read_config(distro) + + branch = config['Environment']['GIT_BRANCH'] + old_commit = config['Environment']['GIT_COMMIT'] + + cmd = ['git', '-C', f'pkg/{distro}', 'rev-parse', f'refs/remotes/origin/{branch}'] + print(f"+ {shlex.join(cmd)}") + new_commit = subprocess.check_output(cmd, text=True).strip() + + if old_commit == new_commit: + print(f'{distro}: commit {new_commit!s} is still fresh') + return + + cmd = ['git', '-C', f'pkg/{distro}', 'log', '--graph', + '--pretty=oneline', '--no-decorate', '--abbrev-commit', '--abbrev=10', + f'{old_commit}..{new_commit}'] + print(f"+ {shlex.join(cmd)}") + changes = subprocess.check_output(cmd, text=True).strip() + + conf_dir = Path('mkosi.images/system/mkosi.conf.d') + files = conf_dir.glob('*/*.conf') + for file in files: + s = file.read_text() + if old_commit in s: + print(f'{distro}: {file}: found old hash, updating…') + new = s.replace(old_commit, new_commit) + assert new != s + file.write_text(new) + commit_file(distro, file, new_commit, changes) + break + else: + raise ValueError(f'{distro}: hash {new_commit} not found under {conf_dir}') + +if __name__ == '__main__': + args = parse_args() + for distro in args.distribution: + update_distro(args, distro) diff --git a/tools/update-man-rules.py b/tools/update-man-rules.py index 1c2c9a8..3f10a29 100755 --- a/tools/update-man-rules.py +++ b/tools/update-man-rules.py @@ -85,6 +85,7 @@ def main(): pages = glob.glob(source_glob) pages = (p for p in pages if Path(p).name not in { + 'standard-conf.xml', 'systemd.directives.xml', 'systemd.index.xml', 'directives-template.xml'}) |