steps:
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- # FIXME: drop once https://github.com/actions/runner-images/issues/9491 is resolved
- - name: Reduce ASLR entropy
- run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: Build check
run: .github/workflows/build_test.sh
matrix:
sanitizer: [address, undefined, memory]
steps:
- - run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: Build Fuzzers
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
security-events: write
steps:
- - run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
types:
- completed
-env:
- PULL_REQUEST_METADATA_DIR: pull_request
- PULL_REQUEST_METADATA_FILE: metadata
-
permissions:
contents: read
pull-requests: write
steps:
- - name: Download Pull Request Metadata artifact
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
- with:
- script: |
- const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: ${{ github.event.workflow_run.id }},
- });
-
- const matchArtifact = artifacts.data.artifacts.filter((artifact) => {
- return artifact.name == "${{ env.PULL_REQUEST_METADATA_FILE }}"
- })[0];
-
- const download = await github.rest.actions.downloadArtifact({
- owner: context.repo.owner,
- repo: context.repo.repo,
- artifact_id: matchArtifact.id,
- archive_format: 'zip',
- });
-
- const fs = require('fs');
- fs.writeFileSync('${{ github.workspace }}/${{ env.PULL_REQUEST_METADATA_FILE }}.zip', Buffer.from(download.data));
-
- - run: unzip ${{ env.PULL_REQUEST_METADATA_FILE }}.zip
-
- - name: 'Get Pull Request number'
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
+ - id: artifact
+ name: Download Pull Request Metadata artifact
+ uses: redhat-plumbers-in-action/download-artifact@463ae626ac2dd333491c7beccaa24c12c5c259b8
with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const fs = require('fs');
- const pr_number = Number(fs.readFileSync('./${{ env.PULL_REQUEST_METADATA_FILE }}'));
- core.exportVariable('pr_number', pr_number);
+ name: Pull Request Metadata
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
fetch-depth: 0
- name: Development Freezer
- uses: redhat-plumbers-in-action/devel-freezer@67aec4a153bd9fca5322e1c4dd4d7c419fb36362
+ uses: redhat-plumbers-in-action/devel-freezer@396c94ba8cb417474e6626c83a42addea210a403
with:
- pr-number: ${{ env.pr_number }}
+ pr-number: ${{ fromJSON(steps.artifact.outputs.pr-metadata-json).number }}
+ # delay start of validation to allow for some milestone/labels tweaking
+ delay: 20
token: ${{ secrets.GITHUB_TOKEN }}
pull_request:
branches: [ main ]
-env:
- PULL_REQUEST_METADATA_DIR: pull_request
- PULL_REQUEST_METADATA_FILE: metadata
-
permissions:
contents: read
steps:
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- with:
- fetch-depth: 0
- - name: Store PR number in file
- run: |
- mkdir -p ./${{ env.PULL_REQUEST_METADATA_DIR }}
- echo ${{ github.event.number }} >./${{ env.PULL_REQUEST_METADATA_DIR }}/${{ env.PULL_REQUEST_METADATA_FILE }}
+ - id: metadata
+ name: Gather Pull Request Metadata
+ uses: redhat-plumbers-in-action/gather-pull-request-metadata@69c703f376018c1a41c8ccce21dc2e16a79f3324
- name: Upload Pull Request Metadata artifact
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3
with:
- name: ${{ env.PULL_REQUEST_METADATA_FILE }}
- path: ${{ env.PULL_REQUEST_METADATA_DIR }}
+ name: Pull Request Metadata
+ path: ${{ steps.metadata.outputs.metadata-file }}
retention-days: 1
steps:
- name: Repository checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633
- # FIXME: drop once https://github.com/actions/runner-images/issues/9491 is resolved
- - name: Reduce ASLR entropy
- run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: Install build dependencies
run: |
# Drop XDG_* stuff from /etc/environment, so we don't get the user
[submodule "pkg/fedora"]
path = pkg/fedora
- url = https://src.fedoraproject.org/rpms/systemd
+ url = https://src.fedoraproject.org/rpms/systemd.git
branch = rawhide
[submodule "pkg/opensuse"]
path = pkg/opensuse
- url = https://src.opensuse.org/rpm/systemd
+ url = https://src.opensuse.org/rpm/systemd.git
branch = factory
[submodule "pkg/debian"]
path = pkg/debian
branch = debian/master
[submodule "pkg/centos"]
path = pkg/centos
- url = https://git.centos.org/rpms/systemd
+ url = https://git.centos.org/rpms/systemd.git
branch = c9s-sig-hyperscale
[submodule "pkg/arch"]
path = pkg/arch
- url = https://gitlab.archlinux.org/daandemeyer/systemd.git
- branch = strip
+ url = https://gitlab.archlinux.org/archlinux/packaging/packages/systemd.git
+ branch = main
Command-line tools:
- * systemd-run is now a multi-call binary. When invoked as 'uid0', it
+ * systemd-run is now a multi-call binary. When invoked as 'run0', it
provides as interface similar to 'sudo', with all arguments starting
at the first non-option parameter being treated the command to
invoke as root. Unlike 'sudo' and similar tools, it does not make use
* add a new ExecStart= flag that inserts the configured user's shell as first
word in the command line. (maybe use character '.'). Usecase: tool such as
- uid0 can use that to spawn the target user's default shell.
+ run0 can use that to spawn the target user's default shell.
* varlink: figure out how to do docs for our varlink interfaces. Idea: install
interface files augmented with docs in /usr/share/ somewhere. And have
- fingerprint authentication, pattern authentication, …
- make sure "classic" user records can also be managed by homed
- make size of $XDG_RUNTIME_DIR configurable in user record
- - query password from kernel keyring first
- - update even if record is "absent"
- move acct mgmt stuff from pam_systemd_home to pam_systemd?
- when "homectl --pkcs11-token-uri=" is used, synthesize ssh-authorized-keys records for all keys we have private keys on the stick for
- make slice for users configurable (requires logind rework)
- allow Name= to be specified repeatedly in the [Match] section. Maybe also
support Name=foo*|bar*|baz ?
- whenever uplink info changes, make DHCP server send out FORCERENEW
- - figure out spelling: NamespaceId vs. NamespaceNSID
* in networkd, when matching device types, fix up DEVTYPE rubbish the kernel passes to us
to receive a notification via VSOCK when a virtual machine has finished booting.
Note that in case the hypervisor does not support `SOCK_DGRAM` over `AF_VSOCK`,
`SOCK_SEQPACKET` will be tried instead. The credential payload should be in the
- form: `vsock:<CID>:<PORT>`. Also note that this requires support for VHOST to be
+ form: `vsock:<CID>:<PORT>`. `vsock` may be replaced with `vsock-stream`, `vsock-dgram` or `vsock-seqpacket`
+ to force usage of the corresponding socket type. Also note that this requires support for VHOST to be
built-in both the guest and the host kernels, and the kernel modules to be loaded.
* [`systemd-sysusers(8)`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html)
**/etc/systemd/system/my-nginx.socket**
```
+[Unit]
+After=network.target
+Requires=network.target
+
[Socket]
ListenStream=80
ListenStream=0.0.0.0:80
BindIPv6Only=ipv6-only
-After=network.target
-Requires=network.target
[Install]
WantedBy=sockets.target
```shell
$ git config submodule.recurse true
$ git config fetch.recurseSubmodules on-demand
+$ git config push.recurseSubmodules no
```
When adding new functionality, tests should be added. For shared functionality
usb:v0011p7788*
ID_MODEL_FROM_DATABASE=counterfeit flash drive
+usb:v001F*
+ ID_VENDOR_FROM_DATABASE=Walmart
+
+usb:v001Fp0B21*
+ ID_MODEL_FROM_DATABASE=AB13X Headset Adapter
+
usb:v0040*
ID_VENDOR_FROM_DATABASE=Anyware Corporation
usb:v03F0p002A*
ID_MODEL_FROM_DATABASE=LaserJet P1102
+usb:v03F0p0036*
+ ID_MODEL_FROM_DATABASE=CCID Smartcard Keyboard KUS0133
+
usb:v03F0p0053*
ID_MODEL_FROM_DATABASE=DeskJet 2620 All-in-One Printer
ID_MODEL_FROM_DATABASE=AVC-1410 GameBridge TV NTSC
usb:v03F3p2000*
- ID_MODEL_FROM_DATABASE=USBXchange
+ ID_MODEL_FROM_DATABASE=USBXchange Firmware Loader
usb:v03F3p2001*
ID_MODEL_FROM_DATABASE=USBXchange Adapter
usb:v03F3p2002*
- ID_MODEL_FROM_DATABASE=USB2-Xchange
+ ID_MODEL_FROM_DATABASE=USB2-Xchange Firmware Loader
usb:v03F3p2003*
ID_MODEL_FROM_DATABASE=USB2-Xchange Adapter
usb:v0403p6F70*
ID_MODEL_FROM_DATABASE=HB-RF-USB
+usb:v0403p7150*
+ ID_MODEL_FROM_DATABASE=FT2232x wired for MPSSE+UART
+
+usb:v0403p7151*
+ ID_MODEL_FROM_DATABASE=FT2232x wired for MPSSE+UART
+
+usb:v0403p7152*
+ ID_MODEL_FROM_DATABASE=FreeCalypso dual UART with boot control
+
usb:v0403p7BE8*
ID_MODEL_FROM_DATABASE=FT232R
usb:v0424p4060*
ID_MODEL_FROM_DATABASE=Ultra Fast Media Reader
+usb:v0424p4063*
+ ID_MODEL_FROM_DATABASE=xD/SD/MS/MMC Reader
+
usb:v0424p4064*
ID_MODEL_FROM_DATABASE=Ultra Fast Media Reader
usb:v043Ep9804*
ID_MODEL_FROM_DATABASE=DMB Receiver Control
+usb:v043Ep9A10*
+ ID_MODEL_FROM_DATABASE=34UC88-B
+
+usb:v043Ep9A11*
+ ID_MODEL_FROM_DATABASE=34UC88-B
+
usb:v043Ep9A39*
ID_MODEL_FROM_DATABASE=27UP850 - WK.AEUDCSN - External Monitor 4K
usb:v045Ep02FD*
ID_MODEL_FROM_DATABASE=Xbox One S Controller [Bluetooth]
+usb:v045Ep02FE*
+ ID_MODEL_FROM_DATABASE=Xbox Wireless Adapter for Windows
+
+usb:v045Ep0306*
+ ID_MODEL_FROM_DATABASE=Surface Pro 7 SD Card Reader
+
usb:v045Ep0400*
ID_MODEL_FROM_DATABASE=Windows Powered Pocket PC 2002
usb:v045Ep0823*
ID_MODEL_FROM_DATABASE=Classic IntelliMouse
+usb:v045Ep082A*
+ ID_MODEL_FROM_DATABASE=Pro Intellimouse
+
usb:v045Ep0900*
ID_MODEL_FROM_DATABASE=Surface Dock Hub
ID_MODEL_FROM_DATABASE=MK260 Wireless Combo Receiver
usb:v046DpC52F*
- ID_MODEL_FROM_DATABASE=Unifying Receiver
+ ID_MODEL_FROM_DATABASE=Nano Receiver
usb:v046DpC531*
ID_MODEL_FROM_DATABASE=C-U0007 [Unifying Receiver]
ID_MODEL_FROM_DATABASE=Unifying Receiver
usb:v046DpC534*
- ID_MODEL_FROM_DATABASE=Unifying Receiver
+ ID_MODEL_FROM_DATABASE=Nano Receiver
usb:v046DpC537*
ID_MODEL_FROM_DATABASE=Cordless Mouse Receiver
usb:v0483p5722*
ID_MODEL_FROM_DATABASE=Bulk Demo
+usb:v0483p572A*
+ ID_MODEL_FROM_DATABASE=STM32F401 microcontroller [ARM Cortex M4] [CDC/ACM serial port]
+
usb:v0483p5730*
ID_MODEL_FROM_DATABASE=Audio Speaker
ID_MODEL_FROM_DATABASE=MediaTek Bluetooth Adapter
usb:v0489pE0D8*
- ID_MODEL_FROM_DATABASE=Bluetooth Adapter
+ ID_MODEL_FROM_DATABASE=Bluetooth 5.2 Adapter [MediaTek MT7922]
usb:v048A*
ID_VENDOR_FROM_DATABASE=S-MOS Systems, Inc.
usb:v04BFp0A28*
ID_MODEL_FROM_DATABASE=INDI AV-IN Device
+usb:v04BFp1301*
+ ID_MODEL_FROM_DATABASE=Network Controller
+
+usb:v04BFp1302*
+ ID_MODEL_FROM_DATABASE=i3 Gateway
+
+usb:v04BFp1303*
+ ID_MODEL_FROM_DATABASE=3 Micro Module
+
+usb:v04BFp1304*
+ ID_MODEL_FROM_DATABASE=i3 Module
+
+usb:v04BFp1305*
+ ID_MODEL_FROM_DATABASE=i3 Multi Sensing Module
+
usb:v04C1*
ID_VENDOR_FROM_DATABASE=U.S. Robotics (3Com)
usb:v04CAp0020*
ID_MODEL_FROM_DATABASE=USB Keyboard
+usb:v04CAp003A*
+ ID_MODEL_FROM_DATABASE=Multimedia Keyboard
+
usb:v04CAp004B*
ID_MODEL_FROM_DATABASE=Keyboard
usb:v04D9p1603*
ID_MODEL_FROM_DATABASE=Keyboard
+usb:v04D9p1605*
+ ID_MODEL_FROM_DATABASE=Keyboard
+
usb:v04D9p1702*
ID_MODEL_FROM_DATABASE=Keyboard LKS02
usb:v04F2pB76B*
ID_MODEL_FROM_DATABASE=SunplusIT Inc [HP HD Camera]
+usb:v04F2pB7B4*
+ ID_MODEL_FROM_DATABASE=Integrated Camera (1920x1080)
+
usb:v04F3*
ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp.
usb:v04FEp0006*
ID_MODEL_FROM_DATABASE=Happy Hacking Keyboard Lite2
+usb:v04FEp0020*
+ ID_MODEL_FROM_DATABASE=HHKB-Classic
+
+usb:v04FEp0021*
+ ID_MODEL_FROM_DATABASE=Happy Hacking Keyboard Professional HYBRID Type-S
+
usb:v04FF*
ID_VENDOR_FROM_DATABASE=E-CMOS Corp.
usb:v050Dp0084*
ID_MODEL_FROM_DATABASE=F8T003v2 Bluetooth
+usb:v050Dp008A*
+ ID_MODEL_FROM_DATABASE=6-in-1 Multiport Adapter
+
usb:v050Dp0102*
ID_MODEL_FROM_DATABASE=Flip KVM
usb:v054Cp0689*
ID_MODEL_FROM_DATABASE=Walkman NWZ-B173F
+usb:v054Cp068C*
+ ID_MODEL_FROM_DATABASE=UP-D711
+
usb:v054Cp06BB*
ID_MODEL_FROM_DATABASE=WALKMAN NWZ-F805
usb:v056Ap03B3*
ID_MODEL_FROM_DATABASE=DTH167 [Cintiq Pro 16] touchscreen
+usb:v056Ap03C0*
+ ID_MODEL_FROM_DATABASE=DTH271 [Cintiq Pro 27] touchscreen
+
+usb:v056Ap03C4*
+ ID_MODEL_FROM_DATABASE=DTH172 [Cintiq Pro 17]
+
usb:v056Ap03C5*
ID_MODEL_FROM_DATABASE=CTL-4100WL [Intuos BT (S)]
usb:v056Ap03C7*
ID_MODEL_FROM_DATABASE=CTL-6100WL [Intuos BT (M)]
+usb:v056Ap03CB*
+ ID_MODEL_FROM_DATABASE=DTH134 [Wacom One 13] touchscreen
+
+usb:v056Ap03CE*
+ ID_MODEL_FROM_DATABASE=DTC121 [Wacom One 12] touchscreen
+
+usb:v056Ap03D0*
+ ID_MODEL_FROM_DATABASE=DTH227 [Cintiq Pro 22]
+
usb:v056Ap03DC*
ID_MODEL_FROM_DATABASE=PTH-460 [Intuos Pro (S)] tablet
usb:v056Ap03DD*
ID_MODEL_FROM_DATABASE=PTH-460 [Intuos Pro BT (S)] tablet
+usb:v056Ap03EC*
+ ID_MODEL_FROM_DATABASE=DTH134 [DTH134] touchscreen
+
+usb:v056Ap03ED*
+ ID_MODEL_FROM_DATABASE=DTC121 [DTC121] touchscreen
+
usb:v056Ap0400*
ID_MODEL_FROM_DATABASE=PenPartner 4x5
ID_MODEL_FROM_DATABASE=FlexScan EV3237
usb:v056Dp4001*
- ID_MODEL_FROM_DATABASE=Monitor
+ ID_MODEL_FROM_DATABASE=FlexScan EV2450
usb:v056Dp4002*
- ID_MODEL_FROM_DATABASE=USB HID Monitor
+ ID_MODEL_FROM_DATABASE=FlexScan EV2455
usb:v056Dp4014*
ID_MODEL_FROM_DATABASE=FlexScan EV2750
usb:v056Dp4027*
ID_MODEL_FROM_DATABASE=FlexScan EV2456
+usb:v056Dp402B*
+ ID_MODEL_FROM_DATABASE=FlexScan EV2780
+
usb:v056Dp4036*
ID_MODEL_FROM_DATABASE=FlexScan EV2785
usb:v056Dp405B*
ID_MODEL_FROM_DATABASE=FlexScan EV2460
+usb:v056Dp405E*
+ ID_MODEL_FROM_DATABASE=FlexScan EV2495
+
usb:v056Dp405F*
ID_MODEL_FROM_DATABASE=FlexScan EV2795
usb:v056Dp4065*
ID_MODEL_FROM_DATABASE=FlexScan EV3895
+usb:v056Dp406A*
+ ID_MODEL_FROM_DATABASE=FlexScan EV2480
+
usb:v056E*
ID_VENDOR_FROM_DATABASE=Elecom Co., Ltd
usb:v059Fp1095*
ID_MODEL_FROM_DATABASE=Rugged
+usb:v059Fp1105*
+ ID_MODEL_FROM_DATABASE=Mobile Drive (RLSD: 2022)
+
usb:v059FpA601*
ID_MODEL_FROM_DATABASE=HardDrive
usb:v05E6*
ID_VENDOR_FROM_DATABASE=Keithley Instruments
+usb:v05E6p3390*
+ ID_MODEL_FROM_DATABASE=3390 Arbitrary Waveform Generator
+
usb:v05E8*
ID_VENDOR_FROM_DATABASE=ICC, Inc.
usb:v0639*
ID_VENDOR_FROM_DATABASE=Chrontel, Inc.
+usb:v0639p7213*
+ ID_MODEL_FROM_DATABASE=CH7213
+
+usb:v0639p7231*
+ ID_MODEL_FROM_DATABASE=CH7213
+
usb:v063A*
ID_VENDOR_FROM_DATABASE=Techwin Corp.
usb:v06CBp00CB*
ID_MODEL_FROM_DATABASE=Fingerprint scanner
+usb:v06CBp00FC*
+ ID_MODEL_FROM_DATABASE=Prometheus Fingerprint Reader
+
usb:v06CBp0AC3*
ID_MODEL_FROM_DATABASE=Large Touch Screen
usb:v06D3p0394*
ID_MODEL_FROM_DATABASE=CP9000D/DW Port
+usb:v06D3p0395*
+ ID_MODEL_FROM_DATABASE=CP9000DW
+
usb:v06D3p0398*
ID_MODEL_FROM_DATABASE=P93D
+usb:v06D3p039E*
+ ID_MODEL_FROM_DATABASE=CP9500DW-S
+
usb:v06D3p03A1*
ID_MODEL_FROM_DATABASE=CP9550D/DW Port
usb:v06D3p3B10*
ID_MODEL_FROM_DATABASE=P95D
+usb:v06D3p3B20*
+ ID_MODEL_FROM_DATABASE=CP9820DW Series
+
usb:v06D3p3B21*
ID_MODEL_FROM_DATABASE=CP-9810D/DW
+usb:v06D3p3B2F*
+ ID_MODEL_FROM_DATABASE=LS9820A
+
usb:v06D3p3B30*
ID_MODEL_FROM_DATABASE=CP-D70DW / CP-D707DW
usb:v07CEpC010*
ID_MODEL_FROM_DATABASE=CPB-7000
+usb:v07CEpC011*
+ ID_MODEL_FROM_DATABASE=ASK-2500
+
usb:v07CF*
ID_VENDOR_FROM_DATABASE=Casio Computer Co., Ltd
ID_MODEL_FROM_DATABASE=MOTU Audio for 64 bit
usb:v07FDp0004*
- ID_MODEL_FROM_DATABASE=MicroBook
+ ID_MODEL_FROM_DATABASE=Microbook I/II/IIc
usb:v07FDp0008*
ID_MODEL_FROM_DATABASE=M Series
+usb:v07FDp0009*
+ ID_MODEL_FROM_DATABASE=M Series (firmware update mode)
+
+usb:v07FDp000B*
+ ID_MODEL_FROM_DATABASE=M Series
+
+usb:v07FDp000D*
+ ID_MODEL_FROM_DATABASE=M Series (firmware update mode)
+
usb:v07FF*
ID_VENDOR_FROM_DATABASE=Unknown
usb:v0828*
ID_VENDOR_FROM_DATABASE=Sato Corp.
+usb:v0828pA003*
+ ID_MODEL_FROM_DATABASE=WS408 Label Printer
+
usb:v0829*
ID_VENDOR_FROM_DATABASE=DirecTV Broadband, Inc. (Telocity)
usb:v0908p04B4*
ID_MODEL_FROM_DATABASE=SCR_CCID
+usb:v0908p04B5*
+ ID_MODEL_FROM_DATABASE=Camera
+
+usb:v0908p04B6*
+ ID_MODEL_FROM_DATABASE=Cockpit Touchkeypad
+
+usb:v0908p04B7*
+ ID_MODEL_FROM_DATABASE=Cockpit Touchkeypad Bootloader
+
+usb:v0908p04B8*
+ ID_MODEL_FROM_DATABASE=MediSET USB4-W
+
+usb:v0908p04B9*
+ ID_MODEL_FROM_DATABASE=MediSET USB4-R
+
+usb:v0908p04BA*
+ ID_MODEL_FROM_DATABASE=MediSET USB4-G
+
usb:v0908p2701*
ID_MODEL_FROM_DATABASE=ShenZhen SANZHAI Technology Co.,Ltd Spy Pen VGA
usb:v090Cp1132*
ID_MODEL_FROM_DATABASE=5-in-1 Card Reader
+usb:v090Cp2000*
+ ID_MODEL_FROM_DATABASE=Disk
+
usb:v090Cp337B*
ID_MODEL_FROM_DATABASE=Silicon Motion Camera
usb:v0920*
ID_VENDOR_FROM_DATABASE=Echelon Co.
+usb:v0920p5550*
+ ID_MODEL_FROM_DATABASE=U60 FT Network Interface
+
usb:v0920p7500*
ID_MODEL_FROM_DATABASE=Network Interface
usb:v0944p012F*
ID_MODEL_FROM_DATABASE=SQ-1
+usb:v0944p0203*
+ ID_MODEL_FROM_DATABASE=KRONOS
+
usb:v0944p0F03*
ID_MODEL_FROM_DATABASE=K-Series K61P MIDI studio controller
usb:v0955p7321*
ID_MODEL_FROM_DATABASE=Switch [Tegra Erista] recovery mode
+usb:v0955p7323*
+ ID_MODEL_FROM_DATABASE=T234 [Orin NX 16GB] recovery mode
+
+usb:v0955p7423*
+ ID_MODEL_FROM_DATABASE=T234 [Orin NX 8GB] recovery mode
+
usb:v0955p7721*
ID_MODEL_FROM_DATABASE=T210 [TX1 Tegra Erista] recovery mode
usb:v0957*
ID_VENDOR_FROM_DATABASE=Agilent Technologies, Inc.
+usb:v0957p0007*
+ ID_MODEL_FROM_DATABASE=82357A GPIB Interface Firmware loader
+
+usb:v0957p0107*
+ ID_MODEL_FROM_DATABASE=82357A GPIB Interface
+
usb:v0957p0200*
ID_MODEL_FROM_DATABASE=E-Video DC-350 Camera
ID_MODEL_FROM_DATABASE=33220A Waveform Generator
usb:v0957p0518*
+ ID_MODEL_FROM_DATABASE=82357B GPIB Interface Firmware loader
+
+usb:v0957p0607*
+ ID_MODEL_FROM_DATABASE=34410A Multimeter
+
+usb:v0957p0718*
ID_MODEL_FROM_DATABASE=82357B GPIB Interface
usb:v0957p0A07*
usb:v0957p1745*
ID_MODEL_FROM_DATABASE=Test and Measurement Device (IVI)
+usb:v0957p1907*
+ ID_MODEL_FROM_DATABASE=53230A Frequency Counter
+
usb:v0957p1F01*
ID_MODEL_FROM_DATABASE=N5181A MXG Analog Signal Generator
usb:v099Ap7160*
ID_MODEL_FROM_DATABASE=Hyper Slim Keyboard
+usb:v099Ap7202*
+ ID_MODEL_FROM_DATABASE=Enermax Aurora Micro Wireless Receiver
+
usb:v099E*
ID_VENDOR_FROM_DATABASE=Trimble Navigation, Ltd
usb:v09D8p0406*
ID_MODEL_FROM_DATABASE=TWN4 MIFARE NFC
+usb:v09D8p0410*
+ ID_MODEL_FROM_DATABASE=TWN4 HID
+
+usb:v09D8p0420*
+ ID_MODEL_FROM_DATABASE=TWN4 CDC
+
usb:v09D9*
ID_VENDOR_FROM_DATABASE=KRF Tech, Ltd
usb:v09DAp002A*
ID_MODEL_FROM_DATABASE=Wireless Optical Mouse NB-30
+usb:v09DAp0103*
+ ID_MODEL_FROM_DATABASE=Oscar X-710BK Gaming Mouse
+
usb:v09DAp022B*
ID_MODEL_FROM_DATABASE=Wireless Mouse (Battery Free)
usb:v09DAp112C*
ID_MODEL_FROM_DATABASE=Bloody V5 Mouse
+usb:v09DAp2268*
+ ID_MODEL_FROM_DATABASE=Keyboard (FK11)
+
+usb:v09DAp2690*
+ ID_MODEL_FROM_DATABASE=PK-635G
+
usb:v09DAp3A60*
ID_MODEL_FROM_DATABASE=Bloody V8M Core 2 Mouse
ID_MODEL_FROM_DATABASE=F3 V-Track Gaming Mouse
usb:v09DAp9090*
- ID_MODEL_FROM_DATABASE=XL-730K / XL-750BK / XL-755BK Mice
+ ID_MODEL_FROM_DATABASE=XL-730K / XL-747H / XL-750BK / XL-755BK Mice
usb:v09DApF613*
ID_MODEL_FROM_DATABASE=Bloody V7M Mouse
+usb:v09DApF6CC*
+ ID_MODEL_FROM_DATABASE=B314 Light Strike Gaming Keyboard
+
+usb:v09DApFA44*
+ ID_MODEL_FROM_DATABASE=B930 Light Strike RGB Mechanical Gaming Keyboard
+
usb:v09DB*
ID_VENDOR_FROM_DATABASE=Measurement Computing Corp.
usb:v09E8*
ID_VENDOR_FROM_DATABASE=AKAI Professional M.I. Corp.
+usb:v09E8p0029*
+ ID_MODEL_FROM_DATABASE=APC40 mkII
+
usb:v09E8p0045*
ID_MODEL_FROM_DATABASE=MPK Mini Mk II MIDI Controller
usb:v09E8p0076*
ID_MODEL_FROM_DATABASE=LPK25 MIDI Keyboard
+usb:v09E8p007C*
+ ID_MODEL_FROM_DATABASE=MPK Mini MIDI Controller
+
usb:v09E9*
ID_VENDOR_FROM_DATABASE=Chen-Source, Inc.
usb:v0A12p1012*
ID_MODEL_FROM_DATABASE=Bluetooth Device
+usb:v0A12p1243*
+ ID_MODEL_FROM_DATABASE=CSRA64210 [TaoTronics Headset BH-22 in charging mode]
+
+usb:v0A12p4007*
+ ID_MODEL_FROM_DATABASE=Mpow HC5 Headset in charging mode - HID / Mass Storage
+
+usb:v0A12p4010*
+ ID_MODEL_FROM_DATABASE=Mpow HC5 Headset in charging mode - USB Hub
+
usb:v0A12pFFFF*
ID_MODEL_FROM_DATABASE=USB Bluetooth Device in DFU State
usb:v0A35p008A*
ID_MODEL_FROM_DATABASE=SAC Hub
+usb:v0A38*
+ ID_VENDOR_FROM_DATABASE=IRIS sa
+
usb:v0A39*
ID_VENDOR_FROM_DATABASE=Gilat Satellite Networks, Ltd
usb:v0A5Cp219B*
ID_MODEL_FROM_DATABASE=Bluetooth 2.1 Device
+usb:v0A5Cp219C*
+ ID_MODEL_FROM_DATABASE=BCM2070 Bluetooth
+
usb:v0A5Cp21B1*
ID_MODEL_FROM_DATABASE=HP Bluetooth Module
usb:v0A5Cp5804*
ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor with fingerprint swipe sensor
+usb:v0A5Cp5832*
+ ID_MODEL_FROM_DATABASE=BCM5880 Secure Applications Processor Smartcard reader
+
usb:v0A5Cp6300*
ID_MODEL_FROM_DATABASE=Pirelli Remote NDIS Device
usb:v20A0p4107*
ID_MODEL_FROM_DATABASE=GPF Crypto Stick V1.2
+usb:v20A0p4108*
+ ID_MODEL_FROM_DATABASE=Nitrokey Pro
+
+usb:v20A0p4109*
+ ID_MODEL_FROM_DATABASE=Nitrokey Storage
+
usb:v20A0p4123*
ID_MODEL_FROM_DATABASE=IKALOGIC SCANALOGIC 2
usb:v20A0p4223*
ID_MODEL_FROM_DATABASE=ATSAMD21 [castAR]
+usb:v20A0p4230*
+ ID_MODEL_FROM_DATABASE=Nitrokey HSM
+
+usb:v20A0p4287*
+ ID_MODEL_FROM_DATABASE=Nitrokey FIDO U2F
+
usb:v20A0p428D*
ID_MODEL_FROM_DATABASE=Electrosense wideband converter
+usb:v20A0p42B1*
+ ID_MODEL_FROM_DATABASE=Nitrokey FIDO2
+
+usb:v20A0p42B2*
+ ID_MODEL_FROM_DATABASE=Nitrokey 3A Mini/3A NFC/3C NFC
+
+usb:v20A0p42B4*
+ ID_MODEL_FROM_DATABASE=Nitrokey Pro Bootloader
+
+usb:v20A0p42DA*
+ ID_MODEL_FROM_DATABASE=MuteMe
+
+usb:v20A0p42DD*
+ ID_MODEL_FROM_DATABASE=Nitrokey 3A NFC Bootloader/3C NFC Bootloader
+
+usb:v20A0p42E8*
+ ID_MODEL_FROM_DATABASE=Nitrokey 3A Mini Bootloader
+
+usb:v20A0p42EC*
+ ID_MODEL_FROM_DATABASE=RP2040 [PicoWifi]
+
usb:v20B1*
ID_VENDOR_FROM_DATABASE=XMOS Ltd
ID_MODEL_FROM_DATABASE=WinUSB Smartcard
usb:v2581pF1D0*
- ID_MODEL_FROM_DATABASE=FIDO U2F Security Key
+ ID_MODEL_FROM_DATABASE=Nitrokey U2F
usb:v258D*
ID_VENDOR_FROM_DATABASE=Sequans Communications
EVDEV_ABS_00=::200
EVDEV_ABS_01=::200
+# HUION Kamvas 19 Pro (GT-1902)
+evdev:input:b0003v256Cp006Be0110*
+ EVDEV_ABS_00=::68
+ EVDEV_ABS_01=::123
+
#########################################
# Lenovo
#########################################
KEYBOARD_KEY_13f=f21 # Touchpad toggle
KEYBOARD_KEY_9e=wlan
+# Portege Z830 ACPI quickstart buttons
+evdev:name:Quickstart Button 1:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
+ KEYBOARD_KEY_1=prog1 # TOSHIBA eco button
+
+evdev:name:Quickstart Button 2:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
+ KEYBOARD_KEY_1=prog2 # TOSHIBA Presentation button
+
+evdev:name:Quickstart Button 3:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnPORTEGEZ830:*
+ KEYBOARD_KEY_1=f21 # Touchpad toggle
+
###########################################################
# VIA
###########################################################
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivoTecnologiaSA:pn*:pvr*:rvnPositivoTecnologiaSA:rnK116*
KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
+# Positivo (N14NPE-N, N15NPE-N)
+evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:svnPositivo*:pn*:pvr*:rvnPositivo*:rnN1[45]NPE-N*
+ KEYBOARD_KEY_76=f21 # Fn+F1 toggle touchpad
+ KEYBOARD_KEY_dd=search
+
# Positivo (CG15D)
evdev:name:AT Translated Set 2 keyboard:dmi:bvn*:bvr*:svnPositivoTecnologiaSA:pn*:pvr*:rvn*:rnCG15D*
# Positivo Motion (N14DP6, N14DP7, N14DP7-V2, N14DP9, N14JP6, N14KP6)
# The latest version can be obtained from
# http://www.linux-usb.org/usb.ids
#
-# Version: 2023.11.08
-# Date: 2023-11-08 20:34:02
+# Version: 2024.03.18
+# Date: 2024-03-18 20:34:02
#
# Vendors, devices and interfaces. Please keep sorted.
0004 Nebraska Furniture Mart
0011 Unknown
7788 counterfeit flash drive
+001f Walmart
+ 0b21 AB13X Headset Adapter
0040 Anyware Corporation
073d Mini Multimedia 2.4GHz Wireless Keyboard with Touch Pad
0042 DMT
0012 DeskJet 1125C Printer Port
0024 KU-0316 Keyboard
002a LaserJet P1102
+ 0036 CCID Smartcard Keyboard KUS0133
0053 DeskJet 2620 All-in-One Printer
0101 ScanJet 4100c
0102 PhotoSmart S20
008c AVC-2310 Device
0094 eHome Infrared Receiver
009b AVC-1410 GameBridge TV NTSC
- 2000 USBXchange
+ 2000 USBXchange Firmware Loader
2001 USBXchange Adapter
- 2002 USB2-Xchange
+ 2002 USB2-Xchange Firmware Loader
2003 USB2-Xchange Adapter
4000 4-port hub
adcc Composite Device Support
601f FT601 32-bit FIFO IC
6ee0 EZO Carrier Board
6f70 HB-RF-USB
+ 7150 FT2232x wired for MPSSE+UART
+ 7151 FT2232x wired for MPSSE+UART
+ 7152 FreeCalypso dual UART with boot control
7be8 FT232R
8028 Dev board JTAG (FT232H based)
8040 4 Port Hub
3fcc RME MADIface
4041 Hub and media card controller
4060 Ultra Fast Media Reader
+ 4063 xD/SD/MS/MMC Reader
4064 Ultra Fast Media Reader
4712 USB4712 high-speed hub
4713 USB4715 high-speed hub (2 ports disabled)
9800 Remote Control Receiver_iMON
9803 eHome Infrared Receiver
9804 DMB Receiver Control
+ 9a10 34UC88-B
+ 9a11 34UC88-B
9a39 27UP850 - WK.AEUDCSN - External Monitor 4K
9c01 LGE Sync
043f RadiSys Corp.
02e6 Xbox Wireless Adapter for Windows
02ea Xbox One Controller
02fd Xbox One S Controller [Bluetooth]
+ 02fe Xbox Wireless Adapter for Windows
+ 0306 Surface Pro 7 SD Card Reader
0400 Windows Powered Pocket PC 2002
0401 Windows Powered Pocket PC 2002
0402 Windows Powered Pocket PC 2002
0800 Wireless keyboard (All-in-One-Media)
0810 LifeCam HD-3000
0823 Classic IntelliMouse
+ 082a Pro Intellimouse
0900 Surface Dock Hub
0901 Surface Dock Hub
0902 Surface Dock Hub
c52b Unifying Receiver
c52d R700 Remote Presenter receiver
c52e MK260 Wireless Combo Receiver
- c52f Unifying Receiver
+ c52f Nano Receiver
c531 C-U0007 [Unifying Receiver]
c532 Unifying Receiver
- c534 Unifying Receiver
+ c534 Nano Receiver
c537 Cordless Mouse Receiver
c539 Lightspeed Receiver
c53a PowerPlay Wireless Charging System
5720 Mass Storage Device
5721 Interrupt Demo
5722 Bulk Demo
+ 572a STM32F401 microcontroller [ARM Cortex M4] [CDC/ACM serial port]
5730 Audio Speaker
5731 Microphone
5740 Virtual COM Port
e07a Broadcom BCM20702A1 Bluetooth
e0c8 MediaTek MT7921 Bluetooth
e0cd MediaTek Bluetooth Adapter
- e0d8 Bluetooth Adapter
+ e0d8 Bluetooth 5.2 Adapter [MediaTek MT7922]
048a S-MOS Systems, Inc.
048c Alps Electric Ireland, Ltd
048d Integrated Technology Express, Inc.
0320 Bluetooth Adapter
0321 Bluetooth Device
0a28 INDI AV-IN Device
+ 1301 Network Controller
+ 1302 i3 Gateway
+ 1303 3 Micro Module
+ 1304 i3 Module
+ 1305 i3 Multi Sensing Module
04c1 U.S. Robotics (3Com)
0020 56K Voice Pro
0022 56K Voice Pro
072d Revio KD410Z
04ca Lite-On Technology Corp.
0020 USB Keyboard
+ 003a Multimedia Keyboard
004b Keyboard
004f SK-9020 keyboard
008a Acer Wired Mouse Model SM-9023
1400 PS/2 keyboard + mouse controller
1503 Keyboard
1603 Keyboard
+ 1605 Keyboard
1702 Keyboard LKS02
1818 Keyboard [Diatec Filco Majestouch 2]
2011 Keyboard [Diatec Filco Majestouch 1]
b681 ThinkPad T490 Webcam
b71a Integrated IR Camera
b76b SunplusIT Inc [HP HD Camera]
+ b7b4 Integrated Camera (1920x1080)
04f3 Elan Microelectronics Corp.
000a Touchscreen
0103 ActiveJet K-2024 Multimedia Keyboard
0003 Smart Card Reader II
04fe PFU, Ltd
0006 Happy Hacking Keyboard Lite2
+ 0020 HHKB-Classic
+ 0021 Happy Hacking Keyboard Professional HYBRID Type-S
04ff E-CMOS Corp.
0500 Siam United Hi-Tech
0001 DART Keyboard Mouse
0081 F8T001v2 Bluetooth
0083 Bluetooth Device
0084 F8T003v2 Bluetooth
+ 008a 6-in-1 Multiport Adapter
0102 Flip KVM
0103 F5U103 Serial Adapter [etek]
0106 VideoBus II Adapter, Video
05c4 DualShock 4 [CUH-ZCT1x]
0643 DSC-H100 in PTP/MTP mode
0689 Walkman NWZ-B173F
+ 068c UP-D711
06bb WALKMAN NWZ-F805
06c3 RC-S380
07c3 ILCE-6000 (aka Alpha-6000) in Mass Storage mode
03ac DTH-W1620 [MobileStudio Pro 16] touchscreen
03b2 DTH167 [Cintiq Pro 16] tablet
03b3 DTH167 [Cintiq Pro 16] touchscreen
+ 03c0 DTH271 [Cintiq Pro 27] touchscreen
+ 03c4 DTH172 [Cintiq Pro 17]
03c5 CTL-4100WL [Intuos BT (S)]
03c7 CTL-6100WL [Intuos BT (M)]
+ 03cb DTH134 [Wacom One 13] touchscreen
+ 03ce DTC121 [Wacom One 12] touchscreen
+ 03d0 DTH227 [Cintiq Pro 22]
03dc PTH-460 [Intuos Pro (S)] tablet
03dd PTH-460 [Intuos Pro BT (S)] tablet
+ 03ec DTH134 [DTH134] touchscreen
+ 03ed DTC121 [DTC121] touchscreen
0400 PenPartner 4x5
4001 TPC4001
4004 TPC4004
0002 HID Monitor Controls
0003 Device Bay Controller
4000 FlexScan EV3237
- 4001 Monitor
- 4002 USB HID Monitor
+ 4001 FlexScan EV2450
+ 4002 FlexScan EV2455
4014 FlexScan EV2750
4026 FlexScan EV2451
4027 FlexScan EV2456
+ 402b FlexScan EV2780
4036 FlexScan EV2785
4037 FlexScan EV3285
4044 FlexScan EV2457
4059 FlexScan EV2760
405a FlexScan EV2360
405b FlexScan EV2460
+ 405e FlexScan EV2495
405f FlexScan EV2795
4065 FlexScan EV3895
+ 406a FlexScan EV2480
056e Elecom Co., Ltd
0002 29UO Mouse
0057 Micro Grast Pop M-PGDL
1093 Rugged
1094 Rugged THB
1095 Rugged
+ 1105 Mobile Drive (RLSD: 2022)
a601 HardDrive
a602 CD R/W
05a0 Vetronix Corp.
05e4 Red Wing Corp.
05e5 Fuji Electric Co., Ltd
05e6 Keithley Instruments
+ 3390 3390 Arbitrary Waveform Generator
05e8 ICC, Inc.
05e9 Kawasaki LSI
0008 KL5KUSB101B Ethernet [klsi]
# typo?
4004 Minolta Dimage Scan Elite II AF-2920 (2888)
0639 Chrontel, Inc.
+ 7213 CH7213
+ 7231 CH7213
063a Techwin Corp.
063b Taugagreining HF
063c Yamaichi Electronics Co., Ltd (Sakura)
00bd Prometheus MIS Touch Fingerprint Reader
00c7 TouchPad
00cb Fingerprint scanner
+ 00fc Prometheus Fingerprint Reader
0ac3 Large Touch Screen
2970 touchpad
06cc Terayon Communication Systems
038c CP900DW(ID) Port
0393 CP9500D/DW Port
0394 CP9000D/DW Port
+ 0395 CP9000DW
0398 P93D
+ 039e CP9500DW-S
03a1 CP9550D/DW Port
03a5 CP9550DW-S
03a9 CP-9600DW
03ae CP-9800DW-S
0f10 Hori/Namco FlightStick 2
3b10 P95D
+ 3b20 CP9820DW Series
3b21 CP-9810D/DW
+ 3b2f LS9820A
3b30 CP-D70DW / CP-D707DW
3b31 CP-K60DW-S
3b36 CP-D80DW
c007 DPB-4000
c009 DPB-6000
c010 CPB-7000
+ c011 ASK-2500
07cf Casio Computer Co., Ltd
1001 QV-8000SX/5700/3000EX Digicam; Exilim EX-M20
1003 Exilim EX-S500
0000 FastLane MIDI Interface
0001 MIDI Interface
0002 MOTU Audio for 64 bit
- 0004 MicroBook
+ 0004 Microbook I/II/IIc
0008 M Series
+ 0009 M Series (firmware update mode)
+ 000b M Series
+ 000d M Series (firmware update mode)
07ff Unknown
00ff Portable Hard Drive
ffff Mad Catz Gamepad
0826 Data Transit
0827 BroadLogic, Inc.
0828 Sato Corp.
+ a003 WS408 Label Printer
0829 DirecTV Broadband, Inc. (Telocity)
082d Handspring
0100 Visor
04b2 NC interface
04b3 keyboard front panel Cockpit
04b4 SCR_CCID
+ 04b5 Camera
+ 04b6 Cockpit Touchkeypad
+ 04b7 Cockpit Touchkeypad Bootloader
+ 04b8 MediSET USB4-W
+ 04b9 MediSET USB4-R
+ 04ba MediSET USB4-G
2701 ShenZhen SANZHAI Technology Co.,Ltd Spy Pen VGA
0909 Audio-Technica Corp.
001b ATR2100-USB
037c 300k Pixel Camera
1000 Flash Drive
1132 5-in-1 Card Reader
+ 2000 Disk
337b Silicon Motion Camera
3710 Silicon Motion Camera
3720 Silicon Motion Camera
4cda Fenix 6 Sapphire
4cdb Fenix 6
0920 Echelon Co.
+ 5550 U60 FT Network Interface
7500 Network Interface
0921 GoHubs, Inc.
1001 GoCOM232 Serial
010f nanoKONTROL studio controller
0117 nanoKONTROL2 MIDI Controller
012f SQ-1
+ 0203 KRONOS
0f03 K-Series K61P MIDI studio controller
0945 Pasco Scientific
0948 Kronauer music in digital
7140 T124 [Tegra K1/Logan 32-bit]
7210 SHIELD Controller
7321 Switch [Tegra Erista] recovery mode
+ 7323 T234 [Orin NX 16GB] recovery mode
+ 7423 T234 [Orin NX 8GB] recovery mode
7721 T210 [TX1 Tegra Erista] recovery mode
7820 T20 [Tegra 2] recovery mode
7c18 T186 [TX2 Tegra Parker] recovery mode
cf09 SHIELD Tablet
0956 BSquare Corp.
0957 Agilent Technologies, Inc.
+ 0007 82357A GPIB Interface Firmware loader
+ 0107 82357A GPIB Interface
0200 E-Video DC-350 Camera
0202 E-Video DC-350 Camera
0407 33220A Waveform Generator
- 0518 82357B GPIB Interface
+ 0518 82357B GPIB Interface Firmware loader
+ 0607 34410A Multimeter
+ 0718 82357B GPIB Interface
0a07 34411A Multimeter
1507 33210A Waveform Generator
1745 Test and Measurement Device (IVI)
+ 1907 53230A Frequency Counter
1f01 N5181A MXG Analog Signal Generator
2918 U2702A oscilloscope
fb18 LC Device
6330 SANWA Supply Inc. Slim Keyboard
713a WK-713 Multimedia Keyboard
7160 Hyper Slim Keyboard
+ 7202 Enermax Aurora Micro Wireless Receiver
099e Trimble Navigation, Ltd
09a3 PairGain Technologies
09a4 Contech Research, Inc.
09d8 ELATEC GmbH
0320 TWN3 Multi125
0406 TWN4 MIFARE NFC
+ 0410 TWN4 HID
+ 0420 TWN4 CDC
09d9 KRF Tech, Ltd
09da A4Tech Co., Ltd.
0006 Optical Mouse WOP-35 / Trust 450L Optical Mouse
0018 Trust Human Interface Device
001a Wireless Mouse & RXM-15 Receiver
002a Wireless Optical Mouse NB-30
+ 0103 Oscar X-710BK Gaming Mouse
022b Wireless Mouse (Battery Free)
024f RF Receiver and G6-20D Wireless Optical Mouse
0260 KV-300H Isolation Keyboard
09da Bloody V8 Mouse
1068 Bloody A90 Mouse
112c Bloody V5 Mouse
+ 2268 Keyboard (FK11)
+ 2690 PK-635G
3a60 Bloody V8M Core 2 Mouse
8090 X-718BK Oscar Optical Gaming Mouse
9033 X-718BK Optical Mouse
9066 F3 V-Track Gaming Mouse
- 9090 XL-730K / XL-750BK / XL-755BK Mice
+ 9090 XL-730K / XL-747H / XL-750BK / XL-755BK Mice
f613 Bloody V7M Mouse
+ f6cc B314 Light Strike Gaming Keyboard
+ fa44 B930 Light Strike RGB Mechanical Gaming Keyboard
09db Measurement Computing Corp.
0075 MiniLab 1008
0076 PMD-1024
09e6 Silutia, Inc.
09e7 Real 3D, Inc.
09e8 AKAI Professional M.I. Corp.
+ 0029 APC40 mkII
0045 MPK Mini Mk II MIDI Controller
0062 MPD16 MIDI Pad Controller Unit
006d EWI electronic wind instrument
0071 MPK25 MIDI Keyboard
0076 LPK25 MIDI Keyboard
+ 007c MPK Mini MIDI Controller
09e9 Chen-Source, Inc.
09eb IM Networks, Inc.
4331 iRhythm Tuner Remote
1010 Bluetooth Device
1011 Bluetooth Device
1012 Bluetooth Device
+ 1243 CSRA64210 [TaoTronics Headset BH-22 in charging mode]
+ 4007 Mpow HC5 Headset in charging mode - HID / Mass Storage
+ 4010 Mpow HC5 Headset in charging mode - USB Hub
ffff USB Bluetooth Device in DFU State
0a13 Telebyte, Inc.
0a14 Spacelabs Medical, Inc.
0a35 Radikal Technologies
002a SAC - Software Assigned Controller
008a SAC Hub
+0a38 IRIS sa
0a39 Gilat Satellite Networks, Ltd
0a3a PentaMedia Co., Ltd
0163 KN-W510U 1.0 Wireless LAN Adapter
217f BCM2045B (BDC-2.1)
2198 Bluetooth 3.0 Device
219b Bluetooth 2.1 Device
+ 219c BCM2070 Bluetooth
21b1 HP Bluetooth Module
21b4 BCM2070 Bluetooth 2.1 + EDR
21b9 BCM2070 Bluetooth 2.1 + EDR
5802 BCM5880 Secure Applications Processor with fingerprint touch sensor
5803 BCM5880 Secure Applications Processor with secure keyboard
5804 BCM5880 Secure Applications Processor with fingerprint swipe sensor
+ 5832 BCM5880 Secure Applications Processor Smartcard reader
6300 Pirelli Remote NDIS Device
6410 BCM20703A1 Bluetooth 4.1 + LE
bd11 BCM4320 802.11bg Wireless Adapter
20a0 Clay Logic
0006 flirc
4107 GPF Crypto Stick V1.2
+ 4108 Nitrokey Pro
+ 4109 Nitrokey Storage
4123 IKALOGIC SCANALOGIC 2
414a MDE SPI Interface
415a OpenPilot
41e5 BlinkStick
4211 Nitrokey Start
4223 ATSAMD21 [castAR]
+ 4230 Nitrokey HSM
+ 4287 Nitrokey FIDO U2F
428d Electrosense wideband converter
+ 42b1 Nitrokey FIDO2
+ 42b2 Nitrokey 3A Mini/3A NFC/3C NFC
+ 42b4 Nitrokey Pro Bootloader
+ 42da MuteMe
+ 42dd Nitrokey 3A NFC Bootloader/3C NFC Bootloader
+ 42e8 Nitrokey 3A Mini Bootloader
+ 42ec RP2040 [PicoWifi]
20b1 XMOS Ltd
10ad XUSB Loader
f7d1 XTAG2 - JTAG Adapter
2581 Plug-up
1807 Generic HID Smartcard
1808 WinUSB Smartcard
- f1d0 FIDO U2F Security Key
+ f1d0 Nitrokey U2F
258d Sequans Communications
259a TriQuint Semiconductor
25a7 Areson Technology Corp
<term><varname>$SYSTEMD_LOG_LEVEL</varname></term>
<listitem><para id='log-level-body'>The maximum log level of emitted messages (messages with a higher
- log level, i.e. less important ones, will be suppressed). Either one of (in order of decreasing
- importance) <constant>emerg</constant>, <constant>alert</constant>, <constant>crit</constant>,
- <constant>err</constant>, <constant>warning</constant>, <constant>notice</constant>,
- <constant>info</constant>, <constant>debug</constant>, or an integer in the range 0…7. See
+ log level, i.e. less important ones, will be suppressed). Takes a comma-separated list of values. A
+ value may be either one of (in order of decreasing importance) <constant>emerg</constant>,
+ <constant>alert</constant>, <constant>crit</constant>, <constant>err</constant>,
+ <constant>warning</constant>, <constant>notice</constant>, <constant>info</constant>,
+ <constant>debug</constant>, or an integer in the range 0…7. See
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- for more information.</para>
- </listitem>
+ for more information. Each value may optionally be prefixed with one of <constant>console</constant>,
+ <constant>syslog</constant>, <constant>kmsg</constant> or <constant>journal</constant> followed by a
+ colon to set the maximum log level for that specific log target (e.g.
+ <constant>SYSTEMD_LOG_LEVEL=debug,console:info</constant> specifies to log at debug level except when
+ logging to the console which should be at info level). Note that the global maximum log level takes
+ priority over any per target maximum log levels.</para></listitem>
</varlistentry>
<varlistentry id='log-color'>
<para>For the latter five mechanisms the source for the key material used for unlocking the volume is
primarily configured in the third field of each <filename>/etc/crypttab</filename> line, but may also
- configured in <filename>/etc/cryptsetup-keys.d/</filename> and
+ be configured in <filename>/etc/cryptsetup-keys.d/</filename> and
<filename>/run/cryptsetup-keys.d/</filename> (see above) or in the LUKS2 JSON token header (in case of
the latter three). Use the
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
is acquired by connecting to the socket and reading the key from the connection. The connection is made
from an <constant>AF_UNIX</constant> socket name in the abstract namespace, see <citerefentry
project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
- details. The source socket name is chosen according the following format:</para>
+ details. The source socket name is chosen according to the following format:</para>
<programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> /cryptsetup/ <replaceable>VOLUME</replaceable></programlisting>
<listitem><para>If the service opens sockets or other files on it own, and those file descriptors
shall survive a restart, the daemon should store them in the service manager via
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> with
- <varname>FDSTORE=1</varname>..</para></listitem>
+ <varname>FDSTORE=1</varname>.</para></listitem>
<listitem><para>Instead of using the <function>syslog()</function> call to log directly to the system
syslog service, a new-style daemon may choose to simply log to standard error via
<xi:include href="version-info.xml" xpointer="v245"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--offline</option></term>
+
+ <listitem><para>Do not attempt to update the copy of the user record and blob directory that is embedded inside
+ of the home area. This allows for operation on home areas that are absent, or without needing to authenticate as
+ the user being modified.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />
<refsect1>
<title>Commands</title>
- <para>The following commands are understood. If none is specified the default is to display journal records.</para>
+ <para>The following commands are understood. If none is specified the default is to display journal records:</para>
<variablelist>
<varlistentry>
out h send_fd);
@org.freedesktop.systemd1.Privileged("true")
ReleaseHome(in s user_name);
- InhibitSuspendHome(in s user_name,
- out h send_fd);
@org.freedesktop.systemd1.Privileged("true")
LockAllHomes();
@org.freedesktop.systemd1.Privileged("true")
<variablelist class="dbus-method" generated="True" extra-ref="ReleaseHome()"/>
- <variablelist class="dbus-method" generated="True" extra-ref="InhibitSuspendHome()"/>
-
<variablelist class="dbus-method" generated="True" extra-ref="LockAllHomes()"/>
<variablelist class="dbus-method" generated="True" extra-ref="DeactivateAllHomes()"/>
the numeric UID and GID, the real name, home directory and shell. In addition it returns a state
identifier describing the state the user's home directory is in, as well as a bus path referring to the
bus object encapsulating the user record and home directory. This object implements the
- <classname>org.freedesktop.home1.Home</classname> interface documented below.</para>
+ <classname>org.freedesktop.home1.Home</classname> interface documented below. This method, and most others
+ in this interface that take user names, will try to use the caller's home area if the specified user name is
+ an empty string.</para>
<para><function>GetHomeByUID()</function> is similar to <function>GetHomeByName()</function> but
acquires the information based on the numeric UID of the user.</para>
interface.</para>
<para><function>UpdateHome()</function> updates a locally registered user record. Takes a fully
- specified JSON user record as argument (including the <literal>secret</literal> section). A user with a
- matching name and realm must be registered locally already, and the last change timestamp of the newly
- supplied record must be newer than the previously existing user record. Note this operation updates the
- user record only, it does not propagate passwords/authentication tokens from the user record to the
+ specified JSON user record as argument (possibly including the <literal>secret</literal> section). A user
+ with a matching name and realm must be registered locally already, and the last change timestamp of the
+ newly supplied record must be newer than the previously existing user record. Note this operation updates
+ the user record only, it does not propagate passwords/authentication tokens from the user record to the
storage back-end, or resizes the storage back-end. Typically a home directory is first updated, and then
the password of the underlying storage updated using <function>ChangePasswordHome()</function> as well
as the storage resized using <function>ResizeHome()</function>. This method is equivalent to
Directories</ulink> for more info). The <varname>blobs</varname> argument works in the same way as
<function>CreateHomeEx()</function>, so check there for details. The new blob directory contents passed into
this method will completely replace the user's existing blob directory. The <varname>flags</varname> argument
- may be used for future expansion, but for now pass 0. This method is equivalent to <function>UpdateEx()</function>
- on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
+ can be used to further customize the behavior of this method via flags defined as follows:</para>
+ <programlisting>
+#define SD_HOMED_UPDATE_OFFLINE (UINT64_C(1) << 0)
+ </programlisting>
+ <para>When <constant>SD_HOMED_UPDATE_OFFLINE</constant> (0x01) is set, no attempt is made to update the copies
+ of the user record and blob directory that are embedded into the home directory. Changes will be stored, however,
+ and may be propagated into the home directory the next time it is reconciled (most likely when the user next logs in).
+ Note that any changes made with this flag set may be lost if the home area has a newer record, which can happen
+ if the home area is updated on another machine after this method call. This method is equivalent to
+ <function>UpdateEx()</function> on the <classname>org.freedesktop.home1.Home</classname> interface.</para>
<para><function>ResizeHome()</function> resizes the storage associated with a user record. Takes a user
- name, a disk size in bytes and a user record consisting only of the <literal>secret</literal> section
- as argument. If the size is specified as <constant>UINT64_MAX</constant> the storage is resized to the
- size already specified in the user record. Typically, if the user record is updated using
+ name, a disk size in bytes, and optionally a user record consisting only of the <literal>secret</literal>
+ section as arguments. If the size is specified as <constant>UINT64_MAX</constant> the storage is resized to
+ the size already specified in the user record. Typically, if the user record is updated using
<function>UpdateHome()</function> above this is used to propagate the size configured there-in down to
- the underlying storage back-end. This method is equivalent to
- <function>Resize()</function> on the <classname>org.freedesktop.home1.Home</classname>
- interface.</para>
+ the underlying storage back-end. This method is equivalent to <function>Resize()</function> on the
+ <classname>org.freedesktop.home1.Home</classname> interface.</para>
<para><function>ChangePasswordHome()</function> changes the passwords/authentication tokens of a home
directory. Takes a user name, and two JSON user record objects, each consisting only of the
re-authenticate when the system comes back from suspending. It should be set by all clients that
implement a secure lock screen running outside of the user's context, that is brought up when the
system comes back from suspend and can be used to re-acquire the credentials to unlock the user's home
- directory. A home directory is locked automatically at system suspend only if all clients with open
- references to the home directory specify that they support this functionality, and no client has
- temporarily inhibited it (see <function>InhibitSuspendHome()</function> below); otherwise the directory
- remains unlocked. This method is equivalent to <function>Acquire()</function> on the
+ directory. If a home directory has at least one client with an open reference to the home directory
+ that does not support this it is not suspended automatically at system suspend, otherwise it is. This
+ method is equivalent to <function>Acquire()</function> on the
<classname>org.freedesktop.home1.Home</classname> interface.</para>
<para><function>RefHome()</function> is similar to <function>AcquireHome()</function> but takes no user
triggered deactivation is completed. This method is equivalent to <function>Release()</function> on the
<classname>org.freedesktop.home1.Home</classname> interface.</para>
- <para><function>InhibitSuspendHome()</function> temporarily inhibits automatic locking during system
- suspend for a home directory. It returns a file descriptor that inhibits this functionality for as long
- as it is open. As mentioned above, locking a home directory requires a secure lock screen running
- outside of the user context, and is likely to freeze any process that attempts to access the directory.
- Thus, locking a home directory is a trade-off: it increases security, but prevents the client from
- displaying any user content on its secure lock screen, including notifications, media controls, contact
- information for incoming phone calls, and much more. A client may use this method to implement more
- complicated automatic locking behavior for home directories, in order to solve some of these UX issues.
- For instance, the client may choose to only lock the home directory and switch to the secure lock screen
- if the device has been suspended for over 24 hours. Note that this inhibitor does not prevent clients from
- calling <function>LockHome()</function>, and in fact clients will need to call <function>LockHome()</function>
- manually as part of their custom behavior to lock the home directory. Clients should take care to ensure that
- the file descriptor is closed in the event that their custom behavior fails or is disabled. This method is
- equivalent to <function>InhibitSuspend()</function> on the <classname>org.freedesktop.home1.Home</classname>
- interface.</para>
-
<para><function>LockAllHomes()</function> locks all active home directories that only have references
- that opted into automatic locking during system suspend and have no clients inhibiting this behavior.
- This is usually invoked automatically shortly before system suspend.</para>
+ that opted into automatic suspending during system suspend. This is usually invoked automatically
+ shortly before system suspend.</para>
<para><function>DeactivateAllHomes()</function> deactivates all home areas that are currently
active. This is usually invoked automatically shortly before system shutdown.</para>
out h send_fd);
@org.freedesktop.systemd1.Privileged("true")
Release();
- InhibitSuspend(out h send_fd);
properties:
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s UserName = '...';
<variablelist class="dbus-method" generated="True" extra-ref="Release()"/>
- <variablelist class="dbus-method" generated="True" extra-ref="InhibitSuspend()"/>
-
<variablelist class="dbus-property" generated="True" extra-ref="UserName"/>
<variablelist class="dbus-property" generated="True" extra-ref="UID"/>
<function>Update()</function>, <function>UpdateEx()</function>, <function>Resize()</function>,
<function>ChangePassword()</function>, <function>Lock()</function>, <function>Unlock()</function>,
<function>Acquire()</function>, <function>Ref()</function>, <function>RefUnrestricted()</function>,
- <function>Release()</function>, <function>InhibitSuspend()</function> operate like their matching counterparts
- on the <classname>org.freedesktop.home1.Manager</classname> interface (see above). The main difference is that
- they are methods of the home directory objects, and hence carry no additional user name
- parameter. Which of the two flavors of methods to call depends on the handles to the user known on the
- client side: if only the user name is known, it's preferable to use the methods on the manager object
- since they operate with user names only. If however the home object path was already acquired some way
- it is preferable to operate on the <classname>org.freedesktop.home1.Home</classname> objects
- instead.</para>
+ <function>Release()</function>,
+ operate like their matching counterparts on the <classname>org.freedesktop.home1.Manager</classname>
+ interface (see above). The main difference is that they are methods of the home directory objects, and
+ hence carry no additional user name parameter. Which of the two flavors of methods to call depends on
+ the handles to the user known on the client side: if only the user name is known, it's preferable to use
+ the methods on the manager object since they operate with user names only. Clients can also easily operate
+ on their own home area by using the methods on the manager object with an empty string as the user name.
+ If the client has the home's object path already acquired in some way, however, it is preferable to operate
+ on the <classname>org.freedesktop.home1.Home</classname> objects instead.</para>
</refsect2>
<refsect2>
<title>History</title>
<refsect2>
<title>The Manager Object</title>
- <para><function>InhibitSuspendHome()</function>, <function>ActivateHomeIfReferenced()</function>, <function>RefHomeUnrestricted()</function>,
+ <para><function>ActivateHomeIfReferenced()</function>, <function>RefHomeUnrestricted()</function>,
<function>CreateHomeEx()</function>, and <function>UpdateHomeEx()</function> were added in version 256.</para>
</refsect2>
<refsect2>
<title>Home Objects</title>
- <para><function>InhibitSuspend()</function>, <function>ActivateIfReferenced()</function>, <function>RefUnrestricted()</function>, and
+ <para><function>ActivateIfReferenced()</function>, <function>RefUnrestricted()</function>, and
<function>UpdateEx()</function> were added in version 256.</para>
</refsect2>
</refsect1>
multiple times, in which case the order in which images are laid down follows the rules specified in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for the <varname>ExtensionImages=</varname> directive and for the
- <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> and.
+ <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
<citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>8</manvolnum></citerefentry> tools.
The images must contain an <filename>extension-release</filename> file with metadata that matches
what is defined in the <filename>os-release</filename> of <replaceable>IMAGE</replaceable>. See:
<para>The file specified here must have a size that is a multiple of the basic block size 512 and not
be empty. If this option is used, the size allocation algorithm is slightly altered: the partition is
- created as least as big as required to fit the data in, i.e. the data size is an additional minimum
+ created at least as big as required to fit the data in, i.e. the data size is an additional minimum
size value taken into consideration for the allocation algorithm, similar to and in addition to the
<varname>SizeMin=</varname> value configured above.</para>
<literal>squashfs</literal> or the special value <literal>swap</literal>. If specified and the partition
is newly created it is formatted with the specified file system (or as swap device). The file system
UUID and label are automatically derived from the partition UUID and label. If this option is used,
- the size allocation algorithm is slightly altered: the partition is created as least as big as
+ the size allocation algorithm is slightly altered: the partition is created at least as big as
required for the minimal file system of the specified type (or 4KiB if the minimal size is not
known).</para>
['repart.d', '5', [], 'ENABLE_REPART'],
['resolvectl', '1', ['resolvconf'], 'ENABLE_RESOLVE'],
['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
+ ['run0', '1', [], ''],
['runlevel', '8', [], 'HAVE_SYSV_COMPAT'],
['sd-bus-errors',
'3',
''],
['udev_new', '3', ['udev_ref', 'udev_unref'], ''],
['udevadm', '8', [], ''],
- ['uid0', '1', [], ''],
['ukify', '1', [], 'ENABLE_UKIFY'],
['user@.service',
'5',
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
-<refentry id="uid0"
+<refentry id="run0"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
- <title>uid0</title>
+ <title>run0</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
- <refentrytitle>uid0</refentrytitle>
+ <refentrytitle>run0</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
- <refname>uid0</refname>
+ <refname>run0</refname>
<refpurpose>Elevate privileges</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
- <command>uid0</command>
+ <command>run0</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">COMMAND</arg>
</cmdsynopsis>
<refsect1>
<title>Description</title>
- <para><command>uid0</command> may be used to temporarily and interactively acquire elevated or different
+ <para><command>run0</command> may be used to temporarily and interactively acquire elevated or different
privileges. It serves a similar purpose as <citerefentry
project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry>, but
operates differently in a couple of key areas:</para>
setting the <varname>NoNewPrivileges=</varname> variable in
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).</para>
- <para>Any session invoked via <command>uid0</command> will run through the
- <literal>systemd-uid0</literal> PAM stack.</para>
+ <para>Any session invoked via <command>run0</command> will run through the
+ <literal>systemd-run0</literal> PAM stack.</para>
- <para>Note that <command>uid0</command> is implemented as an alternative multi-call invocation of
+ <para>Note that <command>run0</command> is implemented as an alternative multi-call invocation of
<citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</refsect1>
<term><option>--slice-inherit</option></term>
<listitem><para>Make the new <filename>.service</filename> unit part of the slice the
- <command>uid0</command> itself has been invoked in. This option may be combined with
+ <command>run0</command> itself has been invoked in. This option may be combined with
<option>--slice=</option>, in which case the slice specified via <option>--slice=</option> is placed
- within the slice the <command>uid0</command> command is invoked in.</para>
+ within the slice the <command>run0</command> command is invoked in.</para>
- <para>Example: consider <command>uid0</command> being invoked in the slice
+ <para>Example: consider <command>run0</command> being invoked in the slice
<filename>foo.slice</filename>, and the <option>--slice=</option> argument is
<filename>bar</filename>. The unit will then be placed under
<filename>foo-bar.slice</filename>.</para>
<refsect1>
<title>Exit status</title>
- <para>On success, 0 is returned. If <command>uid0</command> failed to start the session or the specified command fails, a
+ <para>On success, 0 is returned. If <command>run0</command> failed to start the session or the specified command fails, a
non-zero return value will be returned.</para>
</refsect1>
<constant>AF_VSOCK</constant> address, which is useful for hypervisors/VMMs or other processes on the
host to receive a notification when a virtual machine has finished booting. Note that in case the
hypervisor does not support <constant>SOCK_DGRAM</constant> over <constant>AF_VSOCK</constant>,
- <constant>SOCK_SEQPACKET</constant> will be used instead. The address should be in the form:
- <literal>vsock:CID:PORT</literal>. Note that unlike other uses of vsock, the CID is mandatory and cannot
- be <literal>VMADDR_CID_ANY</literal>. Note that PID1 will send the VSOCK packets from a privileged port
- (i.e.: lower than 1024), as an attempt to address concerns that unprivileged processes in the guest might
- try to send malicious notifications to the host, driving it to make destructive decisions based on
- them.</para>
+ <constant>SOCK_SEQPACKET</constant> will be used instead. <literal>vsock-stream</literal>,
+ <literal>vsock-dgram</literal> and <literal>vsock-seqpacket</literal> can be used instead of
+ <literal>vsock</literal> to force usage of the corresponding socket type. The address should be in the
+ form: <literal>vsock:CID:PORT</literal>. Note that unlike other uses of vsock, the CID is mandatory and
+ cannot be <literal>VMADDR_CID_ANY</literal>. Note that PID1 will send the VSOCK packets from a
+ privileged port (i.e.: lower than 1024), as an attempt to address concerns that unprivileged processes in
+ the guest might try to send malicious notifications to the host, driving it to make destructive decisions
+ based on them.</para>
</refsect1>
<refsect1>
<term><option>--order</option></term>
<term><option>--require</option></term>
- <listitem><para>When used in conjunction with the
- <command>dot</command> command (see above), selects which
- dependencies are shown in the dependency graph. If
- <option>--order</option> is passed, only dependencies of type
- <varname>After=</varname> or <varname>Before=</varname> are
- shown. If <option>--require</option> is passed, only
- dependencies of type <varname>Requires=</varname>,
- <varname>Requisite=</varname>,
- <varname>Wants=</varname> and <varname>Conflicts=</varname>
- are shown. If neither is passed, this shows dependencies of
+ <listitem><para>When used in conjunction with the <command>dot</command> command (see above),
+ selects which dependencies are shown in the dependency graph. If <option>--order</option> is passed,
+ only dependencies of type <varname>After=</varname> or <varname>Before=</varname> are shown.
+ If <option>--require</option> is passed, only dependencies of type <varname>Requires=</varname>,
+ <varname>Requisite=</varname>, <varname>BindsTo=</varname>, <varname>Wants=</varname>, and
+ <varname>Conflicts=</varname> are shown. If neither is passed, this shows dependencies of
all these types.</para>
<xi:include href="version-info.xml" xpointer="v198"/></listitem>
similar, to extend the native firmware support.</para>
<para>Enrollment of Secure Boot variables can be performed manually or automatically if files are available
- under <filename>/loader/keys/<replaceable>NAME</replaceable>/{db,KEK,PK}.auth</filename>, <replaceable>NAME</replaceable>
+ under <filename>/loader/keys/<replaceable>NAME</replaceable>/{db,dbx,KEK,PK}.auth</filename>, <replaceable>NAME</replaceable>
being the display name for the set of variables in the menu. If one of the sets is named <filename>auto</filename>
then it might be enrolled automatically depending on whether <literal>secure-boot-enroll</literal> is set
to force or not.</para>
<refnamediv>
<refname>systemd-bsod.service</refname>
<refname>systemd-bsod</refname>
- <refpurpose>Displays boot-time emergency log message in full screen.</refpurpose>
+ <refpurpose>Displays boot-time emergency log message in full screen</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-cryptsetup</filename> is used to set up (with <command>attach</command>) and tear
down (with <command>detach</command>) access to an encrypted block device. It is primarily used via
<filename>systemd-cryptsetup@.service</filename> during early boot, but may also be be called manually.
- The positional arguments <parameter>VOLUME</parameter>, <parameter>SOURCEDEVICE</parameter>,
+ The positional arguments <parameter>VOLUME</parameter>, <parameter>SOURCE-DEVICE</parameter>,
<parameter>KEY-FILE</parameter>, and <parameter>CRYPTTAB-OPTIONS</parameter> have the same meaning as the
fields in <citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
<para>In order to embed binary data into the credential data for <option>--set-credential=</option>,
use C-style escaping (i.e. <literal>\n</literal> to embed a newline, or <literal>\x00</literal> to
embed a <constant>NUL</constant> byte). Note that the invoking shell might already apply unescaping
- once, hence this might require double escaping!.</para>
+ once, hence this might require double escaping!</para>
<para>The
<citerefentry><refentrytitle>systemd-sysusers.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<listitem><para>Generates/removes a <filename>.pcrlock</filename> file based on raw binary data. The
data is either read from the specified file or from STDIN (if none is specified). This requires that
- <option>--pcrs=</option> is specified. The generated pcrlock file is written to the file specified
+ <option>--pcrs=</option> is specified. The generated .pcrlock file is written to the file specified
via <option>--pcrlock=</option> or to STDOUT (if none is specified).</para>
<xi:include href="version-info.xml" xpointer="v255"/>
<varlistentry>
<term><option>--nv-index=</option></term>
- <listitem><para>Specifies to NV index to store the policy in. Honoured by
+ <listitem><para>Specifies the NV index to store the policy in. Honoured by
<command>make-policy</command>. If not specified the command will automatically pick a free NV
index.</para>
<literal>kexec</literal>, depending on the chosen action. All executables in this directory are executed
in parallel, and execution of the action is not continued before all executables finished. Note that
these executables are run <emphasis>after</emphasis> all services have been shut down, and after most
- mounts have been detached (the root file system as well as <filename>/run/</filename> and various API
+ mounts have been unmounted (the root file system as well as <filename>/run/</filename> and various API
file systems are still around though). This means any programs dropped into this directory must be
prepared to run in such a limited execution environment and not rely on external services or hierarchies
such as <filename>/var/</filename> to be around (or writable).</para>
<title>Generate a configuration extension image</title>
<para>The following creates a configuration extension DDI (confext) for an
- <filename>/etc/motd</filename> update.</para>
+ <filename>/etc/motd</filename> update:</para>
<programlisting>mkdir tree tree/etc tree/etc/extension-release.d
echo "Hello World" > tree/etc/motd
<member><citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-mount</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
- <member><citerefentry><refentrytitle>uid0</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+ <member><citerefentry><refentrytitle>run0</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
via <varname>SurviveFinalKillSignal=yes</varname>, and also be configured to avoid being stopped on
isolate via <varname>IgnoreOnIsolate=yes</varname>. They also have to be configured to be stopped on
normal shutdown, reboot and maintenance mode. Finally, they have to be ordered after
- <constant>basic.target</constant> to ensure correct ordeering on boot. Note that in case any new or
+ <constant>basic.target</constant> to ensure correct ordering on boot. Note that in case any new or
custom units are used to isolate to, or that implement an equivalent shutdown functionality, they will
also have to be configured manually for correct ordering and conflicting. For example:</para>
exposed NVMe-TCP mass storage devices. The NQN should follow the syntax described in <ulink
url="https://nvmexpress.org/wp-content/uploads/NVM-Express-Base-Specification-2.0c-2022.10.04-Ratified.pdf">NVM
Express Base Specification 2.0c</ulink>, section 4.5 "NVMe Qualified Names". Note that the NQN
- specified here will be suffixed with a dot and the the block device name before it is exposed on the
+ specified here will be suffixed with a dot and the block device name before it is exposed on the
NVMe target. If not specified defaults to
<literal>nqn.2023-10.io.systemd:storagetm.<replaceable>ID</replaceable></literal>, where ID is
replaced by a 128bit ID derived from
but the used architecture identifiers are the same as for <varname>ConditionArchitecture=</varname>
described in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
<varname>EXTENSION_RELOAD_MANAGER=</varname> can be set to 1 if the extension requires a service manager reload after application
- of the extension. Note that the for the reasons mentioned earlier:
+ of the extension. Note that for the reasons mentioned earlier:
<ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink> remain
the recommended way to ship system services.
<para>The services will store the public key of the SRK key pair in a PEM file in
<filename>/run/systemd/tpm2-srk-public-key.pem</filename> and
- <filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>. It will also store it in TPM2B_PUBLIC
+ <filename>/var/lib/systemd/tpm2-srk-public-key.pem</filename>. They will also store it in TPM2B_PUBLIC
format in <filename>/run/systemd/tpm2-srk-public-key.tpm2_public</filename> and
<filename>/var/lib/systemd/tpm2-srk-public-key.tpm2b_public</filename>.</para>
<refnamediv>
<refname>systemd-vmspawn</refname>
- <refpurpose>Spawn an OS in a virtual machine.</refpurpose>
+ <refpurpose>Spawn an OS in a virtual machine</refpurpose>
</refnamediv>
<refsynopsisdiv>
<xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><option>--pass-ssh-key=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>By default an SSH key is generated to allow <command>systemd-vmspawn</command> to open
+ a D-Bus connection to the VM's systemd bus. Setting this to "no" will disable SSH key generation.</para>
+
+ <para>The generated keys are ephemeral. That is they are valid only for the current invocation of <command>systemd-vmspawn</command>,
+ and are typically not persisted.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--ssh-key-type=</option><replaceable>TYPE</replaceable></term>
+
+ <listitem><para>Configures the type of SSH key to generate, see
+ <citerefentry><refentrytitle>ssh-keygen</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for more information.</para>
+
+ <para>By default <literal>ed25519</literal> keys are generated, however <literal>rsa</literal> keys
+ may also be useful if the VM has a particularly old version of <command>sshd</command></para>.
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect2>
<para>In order to embed binary data into the credential data for <option>--set-credential=</option>,
use C-style escaping (i.e. <literal>\n</literal> to embed a newline, or <literal>\x00</literal> to
embed a <constant>NUL</constant> byte). Note that the invoking shell might already apply unescaping
- once, hence this might require double escaping!.</para>
+ once, hence this might require double escaping!</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<literal>ipv4</literal>, <literal>ipv6</literal>, <literal>both</literal>, or
<literal>no</literal>. Defaults to <literal>no</literal>.</para>
<para>Note. Any positive boolean values such as <literal>yes</literal> or
- <literal>true</literal> are now deprecated. Please use one of the values in the above.</para>
+ <literal>true</literal> are now deprecated. Please use one of the values above.</para>
<xi:include href="version-info.xml" xpointer="v219"/>
</listitem>
Address=192.168.0.2/24
[DHCPServer]
ServerAddress=192.168.0.1/24</programlisting>
- are equivalent to the following.
+ are equivalent to the following:
<programlisting>[Network]
DHCPServer=yes
Address=192.168.0.2/24
<listitem><para>Takes a timespan. Configures the retransmit time, used by clients to retransmit Neighbor
Solicitation messages on address resolution and the Neighbor Unreachability Detection algorithm.
- An integer the default unit of seconds, in the range 0…4294967295 msec. Defaults to 0.</para>
+ An integer, the default unit is seconds, in the range 0…4294967295 msec. Defaults to 0.</para>
<xi:include href="version-info.xml" xpointer="v255"/>
</listitem>
<varlistentry>
<term><varname>HomeAgent=</varname></term>
- <listitem><para>Takes a boolean. Specifies that IPv6 router advertisements which indicates to hosts that
- the router acts as a Home Agent and includes a Home Agent Option. Defaults to false. See
+ <listitem><para>Takes a boolean. Specifies that IPv6 router advertisements which indicate to hosts that
+ the router acts as a Home Agent and includes a Home Agent option. Defaults to false. See
<ulink url="https://tools.ietf.org/html/rfc6275">RFC 6275</ulink> for further details.</para>
<xi:include href="version-info.xml" xpointer="v255"/>
<varlistentry>
<term><varname>HomeAgentLifetimeSec=</varname></term>
- <listitem><para>Takes a timespan. Specifies the lifetime of the Home Agent. An integer the default unit of seconds,
+ <listitem><para>Takes a timespan. Specifies the lifetime of the Home Agent. An integer, the default unit is seconds,
in the range 1…65535. Defaults to the value set to <varname>RouterLifetimeSec=</varname>.</para>
<xi:include href="version-info.xml" xpointer="v255"/>
<term><filename>250-firmware-code-early.pcrlock</filename></term>
<listitem><para>Firmware code measurements, as recorded to PCR 0 and 2, up to the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> below). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> below). May be generated via
<command>systemd-pcrlock lock-firmware-code</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>250-firmware-config-early.pcrlock</filename></term>
<listitem><para>Firmware configuration measurements, as recorded to PCR 1 and 3, up to the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> below). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> below). May be generated via
<command>systemd-pcrlock lock-firmware-config</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>550-firmware-code-late.pcrlock</filename></term>
<listitem><para>Firmware code measurements, as recorded to PCR 0 and 2, after the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> above). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> above). May be generated via
<command>systemd-pcrlock lock-firmware-code</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>550-firmware-config-late.pcrlock</filename></term>
<listitem><para>Firmware configuration measurements, as recorded to PCR 1 and 3, after the separator
- measurement (see <filename>400-secureboot-separator.pcrlock.</filename> above). May be generated via
+ measurement (see <filename>400-secureboot-separator.pcrlock</filename> above). May be generated via
<command>systemd-pcrlock lock-firmware-config</command>.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<term><filename>700-action-efi-exit-boot-services.pcrlock</filename></term>
<listitem><para>The EFI action generated when <function>ExitBootServices()</function> is generated,
- i.e. the UEFI environment is left and the OS takes over. Covers the PCR 5 measurement. Statically
+ i.e. when the UEFI environment is left and the OS takes over. Covers the PCR 5 measurement. Statically
defined.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<replaceable>x</replaceable> on a port <replaceable>y</replaceable> address in the
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit integer identifier in
<constant>AF_VSOCK</constant> analogous to an IP address. Specifying the CID is optional, and may be
- set to the empty string.</para>
+ set to the empty string. <literal>vsock</literal> may be replaced with
+ <literal>vsock-stream</literal>, <literal>vsock-dgram</literal> or <literal>vsock-seqpacket</literal>
+ to force usage of the corresponding socket type.</para>
<para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
<varname>ListenSequentialPacket=</varname>) is only available
<constant>SOCK_DGRAM</constant> over <constant>AF_VSOCK</constant>,
<constant>SOCK_SEQPACKET</constant> will be tried instead. The credential payload for
<constant>AF_VSOCK</constant> should be a string in the form
- <literal>vsock:CID:PORT</literal>.</para>
+ <literal>vsock:CID:PORT</literal>. <literal>vsock-stream</literal>, <literal>vsock-dgram</literal>
+ and <literal>vsock-seqpacket</literal> can be used instead of <literal>vsock</literal> to force
+ usage of the corresponding socket type.</para>
<para>This feature is useful for machine managers or other processes on the host to receive a
notification via VSOCK when a virtual machine has finished booting.</para>
<arg choice="plain">call</arg>
<arg choice="plain"><replaceable>ADDRESS</replaceable></arg>
<arg choice="plain"><replaceable>METHOD</replaceable></arg>
- <arg choice="opt"><replaceable>PARAMETERS</replaceable></arg>
+ <arg choice="opt"><replaceable>ARGUMENTS</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<term><command>info</command> <replaceable>ADDRESS</replaceable></term>
<listitem><para>Show brief information about the specified service, including vendor name and list of
- implemented interfaces. Expects a service address in the formats described above.</para>
+ implemented interfaces. Expects a service address in one of the formats described above.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<term><command>list-interfaces</command> <replaceable>ADDRESS</replaceable></term>
<listitem><para>Show list of interfaces implemented by the specified service. Expects a service
- address in the formats described above.</para>
+ address in one of the formats described above.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
</varlistentry>
<term><command>introspect</command> <replaceable>ADDRESS</replaceable> <replaceable>INTERFACE</replaceable></term>
<listitem><para>Show interface definition of the specified interface provided by the specified
- service. Expects a service address in the formats described above and a Varlink interface
+ service. Expects a service address in one of the formats described above and a Varlink interface
name.</para>
<xi:include href="version-info.xml" xpointer="v255"/></listitem>
<varlistentry>
<term><option>uuid=<replaceable>UUID</replaceable></option></term>
- <listitem><para>Use the provided <replaceable>UUID</replaceable> for format command instead of generating new one. The <replaceable>UUID</replaceable> must be
+ <listitem><para>Use the provided <replaceable>UUID</replaceable> instead of generating new one. The <replaceable>UUID</replaceable> must be
provided in standard <acronym>UUID</acronym> format, e.g. <literal>12345678-1234-1234-1234-123456789abc</literal>.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
<term><option>fec-device=<replaceable>PATH</replaceable></option></term>
<listitem><para>Use forward error correction (<acronym>FEC</acronym>) to recover from corruption if hash verification fails. Use
- encoding data from the specified device. The fec device argument can be block device or file image. For format,
- if fec device path doesn't exist, it will be created as file. Note: block sizes for data and hash devices must
+ encoding data from the specified device. The fec device argument can be block device or file image.
+ If fec device path doesn't exist, it will be created as file. Note: block sizes for data and hash devices must
match. Also, if the verity data_device is encrypted the fec_device should be too.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
error('POSIX caps headers not found')
endif
foreach header : ['crypt.h',
+ 'linux/ioprio.h',
'linux/memfd.h',
+ 'linux/time_types.h',
'linux/vm_sockets.h',
'sys/auxv.h',
+ 'sys/sdt.h',
'threads.h',
'valgrind/memcheck.h',
'valgrind/valgrind.h',
- 'linux/time_types.h',
- 'sys/sdt.h',
]
conf.set10('HAVE_' + header.underscorify().to_upper(),
'crypt_reencrypt_init_by_passphrase',
'crypt_reencrypt',
'crypt_set_data_offset',
- 'crypt_set_keyring_to_link']
+ 'crypt_set_keyring_to_link',
+ 'crypt_resume_by_volume_key']
have_ident = have and cc.has_function(
ident,
prefix : '#include <libcryptsetup.h>',
have = get_option('homed').require(
conf.get('HAVE_OPENSSL') == 1 and
conf.get('HAVE_LIBFDISK') == 1 and
- conf.get('HAVE_LIBCRYPTSETUP') == 1,
+ conf.get('HAVE_LIBCRYPTSETUP') == 1 and
+ conf.get('HAVE_CRYPT_RESUME_BY_VOLUME_KEY') == 1,
error_message : 'openssl, fdisk and libcryptsetup required').allowed()
conf.set10('ENABLE_HOMED', have)
'-std=gnu11',
'-fno-stack-protector',
'-O2',
- '-mkernel=5.2',
'-mcpu=v3',
'-mco-re',
'-gbtf',
bpf_o_unstripped_cmd += ['-I.']
- if not meson.is_cross_build() and bpf_compiler == 'clang'
+ if not meson.is_cross_build()
target_triplet_cmd = run_command('gcc', '-dumpmachine', check: false)
if target_triplet_cmd.returncode() == 0
target_triplet = target_triplet_cmd.stdout().strip()
#####################################################################
+check_efi_alignment_py = find_program('tools/check-efi-alignment.py')
check_version_history_py = find_program('tools/check-version-history.py')
elf2efi_py = find_program('tools/elf2efi.py')
export_dbus_interfaces_py = find_program('tools/dbus_exporter.py')
enforcing=0
systemd.early_core_pattern=/core
systemd.firstboot=no
+ systemd.setenv=SYSTEMD_ENABLE_LOG_CONTEXT=yes
+ SYSTEMD_ENABLE_LOG_CONTEXT=yes
kexec-tools
kmod
less
+ man
mtools
nano
nftables
# tmpfs during the build script so these changes don't end up in the image itself.
tee --append /etc/makepkg.conf >/dev/null <<EOF
CFLAGS="$CFLAGS -Og"
-OPTIONS=(!strip docs !libtool !staticlibs emptydirs !zipman purge debug !lto)
+OPTIONS=(!strip docs !libtool !staticlibs emptydirs !zipman purge !debug !lto)
EOF
# Linting the PKGBUILD takes multiple seconds every build so avoid that by nuking all the linting functions.
TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
fi
+sed --in-place "pkg/$PKG_SUBDIR/PKGBUILD" \
+ --expression "s/^_tag=.*/_tag=$(cat meson.version)/" \
+ --expression "s/^pkgrel=.*/pkgrel=$(date "+%Y%m%d%H%M%S" --date "@$TS")/"
+
# We get around makepkg's root check by setting EUID to something else.
# shellcheck disable=SC2046
env --chdir="pkg/$PKG_SUBDIR" \
--noextract \
$( ((WITH_TESTS)) || echo --nocheck) \
--force \
- UPSTREAM=1 \
- QUIET=1 \
+ _systemd_UPSTREAM=1 \
+ _systemd_QUIET=1 \
BUILDDIR="$PWD/pkg/$PKG_SUBDIR" \
PKGDEST="$PACKAGEDIR" \
PKGEXT=".pkg.tar" \
- PKGVER="$(cat meson.version)" \
- PKGREL="$(date "+%Y%m%d%H%M%S" --date "@$TS")" \
MESON_EXTRA_CONFIGURE_OPTIONS="-D mode=developer -D b_sanitize=${SANITIZERS:-none}"
libasan
libcap-ng-utils
libubsan
+ man-db
netcat
openssh-clients
openssh-server
libcap-ng-utils
libtss2-rc0
libtss2-tcti-device0
+ man-db
netcat-openbsd
openssh-client
openssh-server
# See https://github.com/openSUSE/suse-module-tools/pull/71
rm -f "$BUILDROOT/usr/lib/modprobe.d/60-blacklist_fs-erofs.conf"
-mkosi-install systemd udev
+mkosi-install systemd udev systemd-experimental
openssh-clients
openssh-server
pam
+ python3-pefile
quota
rpm-build
rsync
-Subproject commit 733045c8f6b0acf2f0cfaac207500483a678f4d2
+Subproject commit 3b86b9146b84d499789ba924a9dd4ac643d796ab
-Subproject commit 5451923e3e7f5d6cc54f78a8b1d08317a42b4109
+Subproject commit 1932e19d92daef5928a1402073ad3b5aa6fc0767
-Subproject commit 2822a03dded26b9453bddbba7c6a152de8204aec
+Subproject commit f1d38667ef013aa832f43ea7b5861efd29b09fee
# Julien Humbert <julroy67@gmail.com>, 2020, 2021.
# Arnaud T. <listes.00@gmail.com>, 2021.
# blutch112 <vincent.lefebvre59@gmail.com>, 2022.
-# Pierre GRASSER <pierre.grasser@proton.me>, 2023.
+# Pierre GRASSER <pierre.grasser@proton.me>, 2023, 2024.
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-03-04 10:09+0100\n"
-"PO-Revision-Date: 2023-10-12 16:36+0000\n"
+"PO-Revision-Date: 2024-03-22 10:36+0000\n"
"Last-Translator: Pierre GRASSER <pierre.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
-"master/fr/>\n"
+"main/fr/>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 5.0.2\n"
+"X-Generator: Weblate 5.4\n"
#: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system"
#: src/home/org.freedesktop.home1.policy:73
msgid "Inhibit automatic lock of a home area"
-msgstr ""
+msgstr "Empêcher le verrouillage automatique d'un espace personnel"
#: src/home/org.freedesktop.home1.policy:74
-#, fuzzy
msgid ""
"Authentication is required to inhibit automatic lock of a user's home area."
msgstr ""
-"Authentification requise pour mettre à jour l’espace personnel d’un "
-"utilisateur."
+"Authentification requise pour empêcher le verrouillage automatique de "
+"l'espace personnel d'un utilisateur."
#: src/home/org.freedesktop.home1.policy:83
-#, fuzzy
msgid "Activate a home area"
-msgstr "Créer un espace personnel"
+msgstr "Activer un espace personnel"
#: src/home/org.freedesktop.home1.policy:84
-#, fuzzy
msgid "Authentication is required to activate a user's home area."
msgstr ""
-"Authentification requise pour créer l’espace personnel d’un utilisateur."
+"Authentification requise pour activer l’espace personnel d’un utilisateur."
#: src/home/pam_systemd_home.c:293
#, c-format
msgstr "Authentification requise pour obtenir la description du système."
#: src/import/org.freedesktop.import1.policy:22
-#, fuzzy
msgid "Import a disk image"
-msgstr "Importer une image de machine virtuelle ou de conteneur"
+msgstr "Importer une image disque"
#: src/import/org.freedesktop.import1.policy:23
-#, fuzzy
msgid "Authentication is required to import an image"
-msgstr ""
-"Authentification requise pour importer une image de machine virtuelle ou de "
-"conteneur"
+msgstr "Authentification requise pour importer une image"
#: src/import/org.freedesktop.import1.policy:32
-#, fuzzy
msgid "Export a disk image"
-msgstr "Exporter une image de machine virtuelle ou de conteneur"
+msgstr "Exporter une image disque"
#: src/import/org.freedesktop.import1.policy:33
-#, fuzzy
msgid "Authentication is required to export disk image"
-msgstr ""
-"Authentification requise pour exporter une image de machine virtuelle ou de "
-"conteneur"
+msgstr "Authentification requise pour exporter une image disque."
#: src/import/org.freedesktop.import1.policy:42
-#, fuzzy
msgid "Download a disk image"
-msgstr "Télécharger une image de machine virtuelle (VM) ou de conteneur"
+msgstr "Télécharger une image disque"
#: src/import/org.freedesktop.import1.policy:43
-#, fuzzy
msgid "Authentication is required to download a disk image"
-msgstr ""
-"Authentification requise pour télécharger une image de machine virtuelle ou "
-"de conteneur"
+msgstr "Authentification requise pour télécharger une image disque."
#: src/import/org.freedesktop.import1.policy:52
msgid "Cancel transfer of a disk image"
-msgstr ""
+msgstr "Annuler le transfert d'une image disque"
#: src/import/org.freedesktop.import1.policy:53
-#, fuzzy
msgid ""
"Authentication is required to cancel the ongoing transfer of a disk image"
msgstr ""
-"Authentification requise pour changer le mot de passe de l’espace personnel "
-"d’un utilisateur."
+"Authentification requise pour annuler le transfert en cours d'une image "
+"disque."
#: src/locale/org.freedesktop.locale1.policy:22
msgid "Set system locale"
const UnitInfo *u,
const char *prop,
const char *color,
- char *patterns[],
- char *from_patterns[],
- char *to_patterns[]) {
+ char **patterns,
+ char **from_patterns,
+ char **to_patterns) {
_cleanup_strv_free_ char **units = NULL;
bool match_patterns;
int r;
+ assert(bus);
assert(u);
assert(prop);
assert(color);
return 0;
}
-static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *from_patterns[], char *to_patterns[]) {
+static int graph_one(
+ sd_bus *bus,
+ const UnitInfo *u,
+ char **patterns,
+ char **from_patterns,
+ char **to_patterns) {
+
int r;
assert(bus);
r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
+
r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
+
+ r = graph_one_property(bus, u, "BindsTo", "gold", patterns, from_patterns, to_patterns);
+ if (r < 0)
+ return r;
+
r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
+
r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
if (r < 0)
return r;
_cleanup_strv_free_ char **expanded_patterns = NULL;
int r;
+ assert(bus);
+ assert(ret);
+
STRV_FOREACH(pattern, patterns) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *unit = NULL, *unit_id = NULL;
if (r < 0)
return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
- if (!streq(*pattern, unit_id)) {
+ if (!streq(*pattern, unit_id))
if (strv_extend(&expanded_patterns, unit_id) < 0)
return log_oom();
- }
}
*ret = TAKE_PTR(expanded_patterns); /* do not free */
_cleanup_strv_free_ char **expanded_patterns = NULL;
_cleanup_strv_free_ char **expanded_from_patterns = NULL;
_cleanup_strv_free_ char **expanded_to_patterns = NULL;
- int r;
UnitInfo u;
+ int r;
r = acquire_bus(&bus, NULL);
if (r < 0)
log_info(" Color legend: black = Requires\n"
" dark blue = Requisite\n"
+ " gold = BindsTo\n"
" dark grey = Wants\n"
" red = Conflicts\n"
" green = After\n");
uint64_t *ret_badness,
char **ret_description) {
- _cleanup_free_ char *d = NULL;
+ const char *d;
uint64_t b;
+ int r;
assert(ret_badness);
assert(ret_description);
if (streq_ptr(info->user, NOBODY_USER_NAME)) {
- d = strdup("Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services");
+ d = "Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services";
b = 9;
} else if (info->dynamic_user && !STR_IN_SET(info->user, "0", "root")) {
- d = strdup("Service runs under a transient non-root user identity");
+ d = "Service runs under a transient non-root user identity";
b = 0;
} else if (info->user && !STR_IN_SET(info->user, "0", "root", "")) {
- d = strdup("Service runs under a static non-root user identity");
+ d = "Service runs under a static non-root user identity";
b = 0;
} else {
*ret_badness = 10;
return 0;
}
- if (!d)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = TAKE_PTR(d);
-
return 0;
}
const char *description;
uint64_t badness;
- char *copy;
int r;
assert(ret_badness);
description = "Service has no access to home directories";
}
- copy = strdup(description);
- if (!copy)
- return log_oom();
+ r = strdup_to(ret_description, description);
+ if (r < 0)
+ return r;
*ret_badness = badness;
- *ret_description = copy;
-
return 0;
}
const char *description;
uint64_t badness;
- char *copy;
int r;
assert(ret_badness);
description = "Service has limited write access to the OS file hierarchy";
}
- copy = strdup(description);
- if (!copy)
- return log_oom();
+ r = strdup_to(ret_description, description);
+ if (r < 0)
+ return r;
*ret_badness = badness;
- *ret_description = copy;
-
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *copy = NULL;
const char *d;
uint64_t b;
+ int r;
assert(ret_badness);
assert(ret_description);
b = 0;
}
- copy = strdup(d);
- if (!copy)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = copy;
-
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *d;
+ const char *d;
uint64_t b;
+ int r;
assert(ret_badness);
assert(ret_description);
if (set_isempty(info->system_call_architectures)) {
b = 10;
- d = strdup("Service may execute system calls with all ABIs");
+ d = "Service may execute system calls with all ABIs";
} else if (set_contains(info->system_call_architectures, "native") &&
set_size(info->system_call_architectures) == 1) {
b = 0;
- d = strdup("Service may execute system calls only with native ABI");
+ d = "Service may execute system calls only with native ABI";
} else {
b = 8;
- d = strdup("Service may execute system calls with multiple ABIs");
+ d = "Service may execute system calls with multiple ABIs";
}
- if (!d)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = d;
-
return 0;
}
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
const SyscallFilterSet *f = syscall_filter_sets + a->parameter;
- _cleanup_free_ char *d = NULL;
+ char *d;
uint64_t b;
int r;
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
- r = free_and_strdup(&d, "Service does not filter system calls");
+ r = strdup_to(&d, "Service does not filter system calls");
b = 10;
} else {
bool bad;
if (r < 0)
return log_oom();
+ *ret_description = d;
*ret_badness = b;
- *ret_description = TAKE_PTR(d);
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *d = NULL;
+ const char *d;
uint64_t b;
+ int r;
assert(info);
assert(ret_badness);
assert(ret_description);
if (info->ip_filters_custom_ingress || info->ip_filters_custom_egress) {
- d = strdup("Service defines custom ingress/egress IP filters with BPF programs");
+ d = "Service defines custom ingress/egress IP filters with BPF programs";
b = 0;
} else if (!info->ip_address_deny_all) {
- d = strdup("Service does not define an IP address allow list");
+ d = "Service does not define an IP address allow list";
b = 10;
} else if (info->ip_address_allow_other) {
- d = strdup("Service defines IP address allow list with non-localhost entries");
+ d = "Service defines IP address allow list with non-localhost entries";
b = 5;
} else if (info->ip_address_allow_localhost) {
- d = strdup("Service defines IP address allow list with only localhost entries");
+ d = "Service defines IP address allow list with only localhost entries";
b = 2;
} else {
- d = strdup("Service blocks all IP address ranges");
+ d = "Service blocks all IP address ranges";
b = 0;
}
- if (!d)
- return log_oom();
+ r = strdup_to(ret_description, d);
+ if (r < 0)
+ return r;
*ret_badness = b;
- *ret_description = d;
-
return 0;
}
uint64_t *ret_badness,
char **ret_description) {
- char *d = NULL;
+ char *d;
uint64_t b;
assert(info);
(void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 7);
}
- for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
- const struct security_assessor *a = security_assessor_table + i;
+ FOREACH_ARRAY(a, security_assessor_table, ELEMENTSOF(security_assessor_table)) {
_cleanup_free_ char *d = NULL;
uint64_t badness;
void *data;
uint64_t weight = access_weight(a, policy);
uint64_t range = access_range(a, policy);
- data = (uint8_t *) info + a->offset;
+ data = (uint8_t*) info + a->offset;
if (a->default_dependencies_only && !info->default_dependencies) {
badness = UINT64_MAX;
for (;;) {
UnitInfo info;
- char *copy = NULL;
r = bus_parse_unit_info(reply, &info);
if (r < 0)
if (!GREEDY_REALLOC(list, n + 2))
return log_oom();
- copy = strdup(info.id);
- if (!copy)
- return log_oom();
+ r = strdup_to(&list[n], info.id);
+ if (r < 0)
+ return r;
- list[n++] = copy;
- list[n] = NULL;
+ list[++n] = NULL;
}
strv_sort(list);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --threshold= is only supported for security right now.");
- if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL &&
- !STR_IN_SET(argv[optind] ?: "time", "dot", "unit-paths", "verify"))
+ if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL && !streq_ptr(argv[optind], "unit-paths"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Option --global only makes sense with verbs dot, unit-paths, verify.");
+ "Option --global only makes sense with verb unit-paths.");
if (streq_ptr(argv[optind], "cat-config") && arg_runtime_scope == RUNTIME_SCOPE_USER)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
return r;
for (const char *p = content;;) {
- _cleanup_free_ char *line = NULL, *key = NULL, *val = NULL;
+ _cleanup_free_ char *line = NULL, *key = NULL;
const char *q;
r = extract_first_word(&p, &line, "\n", 0);
if (!streq(key, event))
continue;
- val = strdup(q);
- if (!val)
- return -ENOMEM;
-
- *ret = TAKE_PTR(val);
- return 0;
+ return strdup_to(ret, q);
}
}
assert(ret);
FOREACH_DIRENT_ALL(de, d, return -errno) {
- char *b;
-
if (de->d_type != DT_DIR)
continue;
if (dot_or_dot_dot(de->d_name))
continue;
- b = strdup(de->d_name);
- if (!b)
- return -ENOMEM;
-
- *ret = b;
- return 1;
+ return strdup_to_full(ret, de->d_name);
}
*ret = NULL;
if (r < 0)
return r;
- if (c == raw)
+ if (c == raw) {
*ret_cgroup = TAKE_PTR(raw);
- else {
- char *n;
-
- n = strdup(c);
- if (!n)
- return -ENOMEM;
-
- *ret_cgroup = n;
+ return 0;
}
- return 0;
+ return strdup_to(ret_cgroup, c);
}
int cg_path_decode_unit(const char *cgroup, char **ret_unit) {
- char *c, *s;
- size_t n;
-
assert(cgroup);
assert(ret_unit);
- n = strcspn(cgroup, "/");
+ size_t n = strcspn(cgroup, "/");
if (n < 3)
return -ENXIO;
- c = strndupa_safe(cgroup, n);
+ char *c = strndupa_safe(cgroup, n);
c = cg_unescape(c);
if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
return -ENXIO;
- s = strdup(c);
- if (!s)
- return -ENOMEM;
-
- *ret_unit = s;
- return 0;
+ return strdup_to(ret_unit, c);
}
static bool valid_slice_name(const char *p, size_t n) {
if (!session_id_valid(start))
return -ENXIO;
- if (ret_session) {
- char *rr;
-
- rr = strdup(start);
- if (!rr)
- return -ENOMEM;
-
- *ret_session = rr;
- }
+ if (!ret_session)
+ return 0;
- return 0;
+ return strdup_to(ret_session, start);
}
int cg_pid_get_session(pid_t pid, char **ret_session) {
assert(p);
assert(ret_slice);
- /* Finds the right-most slice unit from the beginning, but
- * stops before we come to the first non-slice unit. */
+ /* Finds the right-most slice unit from the beginning, but stops before we come to
+ * the first non-slice unit. */
for (;;) {
- size_t n;
-
- p += strspn(p, "/");
+ const char *s;
+ int n;
- n = strcspn(p, "/");
- if (!valid_slice_name(p, n)) {
-
- if (!e) {
- char *s;
-
- s = strdup(SPECIAL_ROOT_SLICE);
- if (!s)
- return -ENOMEM;
+ n = path_find_first_component(&p, /* accept_dot_dot = */ false, &s);
+ if (n < 0)
+ return n;
+ if (!valid_slice_name(s, n))
+ break;
- *ret_slice = s;
- return 0;
- }
+ e = s;
+ }
- return cg_path_decode_unit(e, ret_slice);
- }
+ if (e)
+ return cg_path_decode_unit(e, ret_slice);
- e = p;
- p += n;
- }
+ return strdup_to(ret_slice, SPECIAL_ROOT_SLICE);
}
int cg_pid_get_slice(pid_t pid, char **ret_slice) {
assert(unit);
assert(ret);
- if (streq(unit, SPECIAL_ROOT_SLICE)) {
- char *x;
-
- x = strdup("");
- if (!x)
- return -ENOMEM;
- *ret = x;
- return 0;
- }
+ if (streq(unit, SPECIAL_ROOT_SLICE))
+ return strdup_to(ret, "");
if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
return -EINVAL;
return r;
}
- char *fname = strdup(".");
- if (!fname)
- return -ENOMEM;
-
- *ret = fname;
- return 0;
+ return strdup_to(ret, ".");
}
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path) {
}
int device_path_make_inaccessible(mode_t mode, char **ret) {
- char *s;
+ const char *s;
assert(ret);
if (S_ISCHR(mode))
- s = strdup("/run/systemd/inaccessible/chr");
+ s = "/run/systemd/inaccessible/chr";
else if (S_ISBLK(mode))
- s = strdup("/run/systemd/inaccessible/blk");
+ s = "/run/systemd/inaccessible/blk";
else
return -ENODEV;
- if (!s)
- return -ENOMEM;
- *ret = s;
- return 0;
+ return strdup_to(ret, s);
}
int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) {
/* For testing purposes it is sometimes useful to be able to override this */
e = secure_getenv("SYSTEMD_EFI_OPTIONS");
- if (e) {
- char *m;
-
- m = strdup(e);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0;
- }
+ if (e)
+ return strdup_to(ret, e);
r = read_one_line_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), ret);
if (r == -ENOENT)
int read_stripped_line(FILE *f, size_t limit, char **ret) {
_cleanup_free_ char *s = NULL;
- int r;
+ int r, k;
assert(f);
return r;
if (ret) {
- const char *p;
-
- p = strstrip(s);
+ const char *p = strstrip(s);
if (p == s)
*ret = TAKE_PTR(s);
else {
- char *copy;
-
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
+ k = strdup_to(ret, p);
+ if (k < 0)
+ return k;
}
}
- return r;
+ return r > 0; /* Return 1 if something was read. */
}
int safe_fgetc(FILE *f, char *ret) {
}
int format_ifname_full_alloc(int ifindex, FormatIfnameFlag flag, char **ret) {
- char buf[IF_NAMESIZE], *copy;
+ char buf[IF_NAMESIZE];
int r;
assert(ret);
if (r < 0)
return r;
- copy = strdup(buf);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
- return 0;
+ return strdup_to(ret, buf);
}
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
static LogTarget log_target = LOG_TARGET_CONSOLE;
static int log_max_level = LOG_INFO;
+static int log_target_max_level[] = {
+ [LOG_TARGET_CONSOLE] = INT_MAX,
+ [LOG_TARGET_KMSG] = INT_MAX,
+ [LOG_TARGET_SYSLOG] = INT_MAX,
+ [LOG_TARGET_JOURNAL] = INT_MAX,
+};
static int log_facility = LOG_DAEMON;
static bool ratelimit_kmsg = true;
if (console_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_CONSOLE])
+ return 0;
+
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
xsprintf(prefix, "<%i>", level);
iovec[n++] = IOVEC_MAKE_STRING(prefix);
if (syslog_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_SYSLOG])
+ return 0;
+
xsprintf(header_priority, "<%i>", level);
t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
if (kmsg_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_KMSG])
+ return 0;
+
if (ratelimit_kmsg && !ratelimit_below(&ratelimit)) {
if (ratelimit_num_dropped(&ratelimit) > 1)
return 0;
if (journal_fd < 0)
return 0;
+ if (LOG_PRI(level) > log_target_max_level[LOG_TARGET_JOURNAL])
+ return 0;
+
iovec_len = MIN(6 + _log_context_num_fields * 2, IOVEC_MAX);
iovec = newa(struct iovec, iovec_len);
PROTECT_ERRNO;
log_assert(LOG_DEBUG, text, file, line, func,
- "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
+ "Assertion '%s' failed at %s:%u, function %s(), ignoring.");
}
int log_oom_internal(int level, const char *file, int line, const char *func) {
int log_set_max_level_from_string(const char *e) {
int r;
- r = log_level_from_string(e);
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *prefix = NULL;
+ LogTarget target;
+ const char *colon;
+
+ r = extract_first_word(&e, &word, ",", 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ colon = strchr(word, ':');
+ if (!colon) {
+ r = log_level_from_string(word);
+ if (r < 0)
+ return r;
+
+ log_set_max_level(r);
+ continue;
+ }
+
+ prefix = strndup(word, colon - word);
+ if (!prefix)
+ return -ENOMEM;
+
+ target = log_target_from_string(prefix);
+ if (target < 0)
+ return target;
+
+ if (target >= _LOG_TARGET_SINGLE_MAX)
+ return -EINVAL;
+
+ r = log_level_from_string(colon + 1);
+ if (r < 0)
+ return r;
+
+ log_target_max_level[target] = r;
+ }
+
+ return 0;
+}
+
+int log_max_levels_to_string(int level, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ assert(ret);
+
+ r = log_level_to_string_alloc(level, &s);
if (r < 0)
return r;
- log_set_max_level(r);
+ for (LogTarget target = 0; target < _LOG_TARGET_SINGLE_MAX; target++) {
+ _cleanup_free_ char *l = NULL;
+
+ if (log_target_max_level[target] == INT_MAX)
+ continue;
+
+ r = log_level_to_string_alloc(log_target_max_level[target], &l);
+ if (r < 0)
+ return r;
+
+ r = strextendf_with_separator(&s, ",", "%s:%s", log_target_to_string(target), l);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(s);
return 0;
}
return 0;
if (log_set_target_from_string(value) < 0)
- log_warning("Failed to parse log target '%s'. Ignoring.", value);
+ log_warning("Failed to parse log target '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
return 0;
if (log_set_max_level_from_string(value) < 0)
- log_warning("Failed to parse log level '%s'. Ignoring.", value);
+ log_warning("Failed to parse log level setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
if (log_show_color_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log color setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
if (log_show_location_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log location setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_tid")) {
if (log_show_tid_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log tid setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log tid setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_time")) {
if (log_show_time_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log time setting '%s'. Ignoring.", value);
+ log_warning("Failed to parse log time setting '%s', ignoring.", value);
} else if (proc_cmdline_key_streq(key, "systemd.log_ratelimit_kmsg")) {
if (log_set_ratelimit_kmsg_from_string(value ?: "1") < 0)
- log_warning("Failed to parse log ratelimit kmsg boolean '%s'. Ignoring.", value);
+ log_warning("Failed to parse log ratelimit kmsg boolean '%s', ignoring.", value);
}
return 0;
e = getenv("SYSTEMD_LOG_TARGET");
if (e && log_set_target_from_string(e) < 0)
- log_warning("Failed to parse log target '%s'. Ignoring.", e);
+ log_warning("Failed to parse log target '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_LEVEL");
if (e && log_set_max_level_from_string(e) < 0)
- log_warning("Failed to parse log level '%s'. Ignoring.", e);
+ log_warning("Failed to parse log level '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_COLOR");
if (e && log_show_color_from_string(e) < 0)
- log_warning("Failed to parse log color '%s'. Ignoring.", e);
+ log_warning("Failed to parse log color '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_LOCATION");
if (e && log_show_location_from_string(e) < 0)
- log_warning("Failed to parse log location '%s'. Ignoring.", e);
+ log_warning("Failed to parse log location '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_TIME");
if (e && log_show_time_from_string(e) < 0)
- log_warning("Failed to parse log time '%s'. Ignoring.", e);
+ log_warning("Failed to parse log time '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_TID");
if (e && log_show_tid_from_string(e) < 0)
- log_warning("Failed to parse log tid '%s'. Ignoring.", e);
+ log_warning("Failed to parse log tid '%s', ignoring.", e);
e = getenv("SYSTEMD_LOG_RATELIMIT_KMSG");
if (e && log_set_ratelimit_kmsg_from_string(e) < 0)
- log_warning("Failed to parse log ratelimit kmsg boolean '%s'. Ignoring.", e);
+ log_warning("Failed to parse log ratelimit kmsg boolean '%s', ignoring.", e);
}
void log_parse_environment(void) {
typedef enum LogTarget{
LOG_TARGET_CONSOLE,
- LOG_TARGET_CONSOLE_PREFIXED,
LOG_TARGET_KMSG,
LOG_TARGET_JOURNAL,
- LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG,
+ LOG_TARGET_CONSOLE_PREFIXED,
+ LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */
LOG_TARGET_NULL,
- _LOG_TARGET_MAX,
+ _LOG_TARGET_SINGLE_MAX = LOG_TARGET_SYSLOG + 1,
+ _LOG_TARGET_MAX = LOG_TARGET_NULL + 1,
_LOG_TARGET_INVALID = -EINVAL,
} LogTarget;
void log_set_max_level(int level);
int log_set_max_level_from_string(const char *e);
int log_get_max_level(void) _pure_;
+int log_max_levels_to_string(int level, char **ret);
void log_set_facility(int facility);
((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
_current_++)
+#define DECIMAL_STR_FMT(x) _Generic((x), \
+ char: "%c", \
+ bool: "%d", \
+ unsigned char: "%d", \
+ short: "%hd", \
+ unsigned short: "%hu", \
+ int: "%d", \
+ unsigned: "%u", \
+ long: "%ld", \
+ unsigned long: "%lu", \
+ long long: "%lld", \
+ unsigned long long: "%llu")
+
#include "log.h"
#include <linux/audit.h>
#if HAVE_AUDIT
-#include <libaudit.h>
+# include <libaudit.h>
#endif
#ifndef AUDIT_SERVICE_START
-#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
+# define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
+#else
+assert_cc(AUDIT_SERVICE_START == 1130);
#endif
#ifndef AUDIT_SERVICE_STOP
-#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
+# define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
+#else
+assert_cc(AUDIT_SERVICE_STOP == 1131);
#endif
#ifndef MAX_AUDIT_MESSAGE_LENGTH
-#define MAX_AUDIT_MESSAGE_LENGTH 8970
+# define MAX_AUDIT_MESSAGE_LENGTH 8970
+#else
+assert_cc(MAX_AUDIT_MESSAGE_LENGTH == 8970);
#endif
+/* Note: we check for AUDIT_NLGRP_MAX because it's a define, but we actually
+ * need AUDIT_NLGRP_READLOG which is an enum. */
#ifndef AUDIT_NLGRP_MAX
-#define AUDIT_NLGRP_READLOG 1
+# define AUDIT_NLGRP_READLOG 1
+#else
+assert_cc(AUDIT_NLGRP_READLOG == 1);
#endif
/* 3a101b8de0d39403b2c7e5c23fd0b005668acf48 (3.16) */
#ifndef CAP_AUDIT_READ
# define CAP_AUDIT_READ 37
+#else
+assert_cc(CAP_AUDIT_READ == 37);
#endif
/* 980737282232b752bb14dab96d77665c15889c36 (5.8) */
#ifndef CAP_PERFMON
# define CAP_PERFMON 38
+#else
+assert_cc(CAP_PERFMON == 38);
#endif
/* a17b53c4a4b55ec322c132b6670743612229ee9c (5.8) */
#ifndef CAP_BPF
# define CAP_BPF 39
+#else
+assert_cc(CAP_BPF == 39);
#endif
/* 124ea650d3072b005457faed69909221c2905a1f (5.9) */
#ifndef CAP_CHECKPOINT_RESTORE
# define CAP_CHECKPOINT_RESTORE 40
+#else
+assert_cc(CAP_CHECKPOINT_RESTORE == 40);
#endif
#define SYSTEMD_CAP_LAST_CAP CAP_CHECKPOINT_RESTORE
# undef CAP_LAST_CAP
# endif
#endif
+
#ifndef CAP_LAST_CAP
# define CAP_LAST_CAP SYSTEMD_CAP_LAST_CAP
#endif
#pragma once
#ifndef DRM_IOCTL_SET_MASTER
-#define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
+# define DRM_IOCTL_SET_MASTER _IO('d', 0x1e)
#endif
#ifndef DRM_IOCTL_DROP_MASTER
-#define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
+# define DRM_IOCTL_DROP_MASTER _IO('d', 0x1f)
#endif
#include <linux/types.h>
+#include "macro.h"
+
/* linux/fs.h */
#ifndef RENAME_NOREPLACE /* 0a7c3937a1f23f8cb5fc77ae01661e9968a51d0c (3.15) */
#define RENAME_NOREPLACE (1 << 0)
/* linux/fs.h or sys/mount.h */
#ifndef MS_MOVE
-#define MS_MOVE 8192
+# define MS_MOVE 8192
+#else
+assert_cc(MS_MOVE == 8192);
#endif
#ifndef MS_REC
-#define MS_REC 16384
+# define MS_REC 16384
+#else
+assert_cc(MS_REC == 16384);
#endif
#ifndef MS_PRIVATE
-#define MS_PRIVATE (1<<18)
+# define MS_PRIVATE (1<<18)
+#else
+assert_cc(MS_PRIVATE == (1<<18));
#endif
#ifndef MS_SLAVE
-#define MS_SLAVE (1<<19)
+# define MS_SLAVE (1<<19)
+#else
+assert_cc(MS_SLAVE == (1<<19));
#endif
#ifndef MS_SHARED
-#define MS_SHARED (1<<20)
+# define MS_SHARED (1<<20)
+#else
+assert_cc(MS_SHARED == (1<<20));
#endif
#ifndef MS_RELATIME
-#define MS_RELATIME (1<<21)
+# define MS_RELATIME (1<<21)
+#else
+assert_cc(MS_RELATIME == (1<<21));
#endif
#ifndef MS_KERNMOUNT
-#define MS_KERNMOUNT (1<<22)
+# define MS_KERNMOUNT (1<<22)
+#else
+assert_cc(MS_KERNMOUNT == (1<<22));
#endif
#ifndef MS_I_VERSION
-#define MS_I_VERSION (1<<23)
+# define MS_I_VERSION (1<<23)
+#else
+assert_cc(MS_I_VERSION == (1<<23));
#endif
#ifndef MS_STRICTATIME
-#define MS_STRICTATIME (1<<24)
+# define MS_STRICTATIME (1<<24)
+#else
+assert_cc(MS_STRICTATIME == (1 << 24));
#endif
#ifndef MS_LAZYTIME
-#define MS_LAZYTIME (1<<25)
+# define MS_LAZYTIME (1<<25)
+#else
+assert_cc(MS_LAZYTIME == (1<<25));
#endif
/* Not exposed yet. Defined at fs/ext4/ext4.h */
#endif
#ifndef FS_PROJINHERIT_FL
-#define FS_PROJINHERIT_FL 0x20000000
+# define FS_PROJINHERIT_FL 0x20000000
+#else
+assert_cc(FS_PROJINHERIT_FL == 0x20000000);
#endif
/* linux/fscrypt.h */
#ifndef FS_KEY_DESCRIPTOR_SIZE
-#define FS_KEY_DESCRIPTOR_SIZE 8
+# define FS_KEY_DESCRIPTOR_SIZE 8
+#else
+assert_cc(FS_KEY_DESCRIPTOR_SIZE == 8);
#endif
#include <linux/input.h>
#include <linux/types.h>
+#include "macro.h"
+
/* linux@c7dc65737c9a607d3e6f8478659876074ad129b8 (3.12) */
#ifndef EVIOCREVOKE
-#define EVIOCREVOKE _IOW('E', 0x91, int)
+# define EVIOCREVOKE _IOW('E', 0x91, int)
#endif
/* linux@06a16293f71927f756dcf37558a79c0b05a91641 (4.4) */
__u64 codes_ptr;
};
-#define EVIOCGMASK _IOR('E', 0x92, struct input_mask)
-#define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
+# define EVIOCGMASK _IOR('E', 0x92, struct input_mask)
+# define EVIOCSMASK _IOW('E', 0x93, struct input_mask)
#endif
/* linux@7611392fe8ff95ecae528b01a815ae3d72ca6b95 (3.17) */
#ifndef INPUT_PROP_POINTING_STICK
-#define INPUT_PROP_POINTING_STICK 0x05
+# define INPUT_PROP_POINTING_STICK 0x05
+#else
+assert_cc(INPUT_PROP_POINTING_STICK == 0x05);
#endif
/* linux@500d4160abe9a2e88b12e319c13ae3ebd1e18108 (4.0) */
#ifndef INPUT_PROP_ACCELEROMETER
-#define INPUT_PROP_ACCELEROMETER 0x06
+# define INPUT_PROP_ACCELEROMETER 0x06
+#else
+assert_cc(INPUT_PROP_ACCELEROMETER == 0x06);
#endif
/* linux@d09bbfd2a8408a995419dff0d2ba906013cf4cc9 (3.11) */
#ifndef BTN_DPAD_UP
-#define BTN_DPAD_UP 0x220
-#define BTN_DPAD_DOWN 0x221
-#define BTN_DPAD_LEFT 0x222
-#define BTN_DPAD_RIGHT 0x223
+# define BTN_DPAD_UP 0x220
+# define BTN_DPAD_DOWN 0x221
+# define BTN_DPAD_LEFT 0x222
+# define BTN_DPAD_RIGHT 0x223
+#else
+assert_cc(BTN_DPAD_UP == 0x220);
+assert_cc(BTN_DPAD_DOWN == 0x221);
+assert_cc(BTN_DPAD_LEFT == 0x222);
+assert_cc(BTN_DPAD_RIGHT == 0x223);
#endif
/* linux@358f24704f2f016af7d504b357cdf32606091d07 (3.13) */
#ifndef KEY_ALS_TOGGLE
-#define KEY_ALS_TOGGLE 0x230
+# fine KEY_ALS_TOGGLE 0x230
+#else
+assert_cc(KEY_ALS_TOGGLE == 0x230);
#endif
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include <sched.h>
+#if HAVE_LINUX_IOPRIO_H
+# include <linux/ioprio.h>
+#endif
+
+#include "macro.h"
/* Match values uses by the kernel internally, as no public header seems to exist. */
#ifndef IOPRIO_N_CLASSES
# define IOPRIO_N_CLASSES 8
+#else
+assert_cc(IOPRIO_N_CLASSES == 8);
#endif
#ifndef IOPRIO_BE_NR
# define IOPRIO_BE_NR 8
+#else
+assert_cc(IOPRIO_BE_NR == 8);
#endif
#ifndef IOPRIO_CLASS_NONE
# define IOPRIO_CLASS_NONE 0
+#else
+assert_cc(IOPRIO_CLASS_NONE == 0);
#endif
#ifndef IOPRIO_CLASS_RT
# define IOPRIO_CLASS_RT 1
+#else
+assert_cc(IOPRIO_CLASS_RT == 1);
#endif
#ifndef IOPRIO_CLASS_BE
# define IOPRIO_CLASS_BE 2
+#else
+assert_cc(IOPRIO_CLASS_BE == 2);
#endif
#ifndef IOPRIO_CLASS_IDLE
# define IOPRIO_CLASS_IDLE 3
+#else
+assert_cc(IOPRIO_CLASS_IDLE == 3);
#endif
#ifndef IOPRIO_WHO_PROCESS
# define IOPRIO_WHO_PROCESS 1
+#else
+assert_cc(IOPRIO_WHO_PROCESS == 1);
#endif
+
#ifndef IOPRIO_WHO_PGRP
# define IOPRIO_WHO_PGRP 2
+#else
+assert_cc(IOPRIO_WHO_PGRP == 2);
#endif
+
#ifndef IOPRIO_WHO_USER
# define IOPRIO_WHO_USER 3
+#else
+assert_cc(IOPRIO_WHO_USER == 3);
#endif
#ifndef IOPRIO_BITS
# define IOPRIO_BITS 16
+#else
+assert_cc(IOPRIO_BITS == 16);
#endif
+
#ifndef IOPRIO_N_CLASSES
# define IOPRIO_N_CLASSES 8
+#else
+assert_cc(IOPRIO_N_CLASSES == 8);
#endif
+
#ifndef IOPRIO_CLASS_SHIFT
# define IOPRIO_CLASS_SHIFT 13
+#else
+assert_cc(IOPRIO_CLASS_SHIFT == 13);
#endif
static inline int ioprio_prio_class(int value) {
#include <inttypes.h>
#include <linux/keyctl.h>
+#include "macro.h"
+
#ifndef KEYCTL_JOIN_SESSION_KEYRING
-#define KEYCTL_JOIN_SESSION_KEYRING 1
+# define KEYCTL_JOIN_SESSION_KEYRING 1
+#else
+assert_cc(KEYCTL_JOIN_SESSION_KEYRING == 1);
#endif
#ifndef KEYCTL_CHOWN
-#define KEYCTL_CHOWN 4
+# define KEYCTL_CHOWN 4
+#else
+assert_cc(KEYCTL_CHOWN == 4);
#endif
#ifndef KEYCTL_SETPERM
-#define KEYCTL_SETPERM 5
+# define KEYCTL_SETPERM 5
+#else
+assert_cc(KEYCTL_SETPERM == 5);
#endif
#ifndef KEYCTL_DESCRIBE
-#define KEYCTL_DESCRIBE 6
+# define KEYCTL_DESCRIBE 6
+#else
+assert_cc(KEYCTL_DESCRIBE == 6);
#endif
#ifndef KEYCTL_LINK
-#define KEYCTL_LINK 8
+# define KEYCTL_LINK 8
+#else
+assert_cc(KEYCTL_LINK == 8);
#endif
#ifndef KEYCTL_READ
-#define KEYCTL_READ 11
+# define KEYCTL_READ 11
+#else
+assert_cc(KEYCTL_READ == 11);
#endif
#ifndef KEYCTL_SET_TIMEOUT
-#define KEYCTL_SET_TIMEOUT 15
+# define KEYCTL_SET_TIMEOUT 15
+#else
+assert_cc(KEYCTL_SET_TIMEOUT == 15);
#endif
#ifndef KEY_SPEC_USER_KEYRING
-#define KEY_SPEC_USER_KEYRING -4
+# define KEY_SPEC_USER_KEYRING -4
+#else
+assert_cc(KEY_SPEC_USER_KEYRING == -4);
#endif
#ifndef KEY_SPEC_SESSION_KEYRING
-#define KEY_SPEC_SESSION_KEYRING -3
+# define KEY_SPEC_SESSION_KEYRING -3
+#else
+assert_cc(KEY_SPEC_SESSION_KEYRING == -3);
#endif
/* From linux/key.h */
typedef int32_t key_serial_t;
-#define KEY_POS_VIEW 0x01000000
-#define KEY_POS_READ 0x02000000
-#define KEY_POS_WRITE 0x04000000
-#define KEY_POS_SEARCH 0x08000000
-#define KEY_POS_LINK 0x10000000
-#define KEY_POS_SETATTR 0x20000000
-#define KEY_POS_ALL 0x3f000000
-
-#define KEY_USR_VIEW 0x00010000
-#define KEY_USR_READ 0x00020000
-#define KEY_USR_WRITE 0x00040000
-#define KEY_USR_SEARCH 0x00080000
-#define KEY_USR_LINK 0x00100000
-#define KEY_USR_SETATTR 0x00200000
-#define KEY_USR_ALL 0x003f0000
-
-#define KEY_GRP_VIEW 0x00000100
-#define KEY_GRP_READ 0x00000200
-#define KEY_GRP_WRITE 0x00000400
-#define KEY_GRP_SEARCH 0x00000800
-#define KEY_GRP_LINK 0x00001000
-#define KEY_GRP_SETATTR 0x00002000
-#define KEY_GRP_ALL 0x00003f00
-
-#define KEY_OTH_VIEW 0x00000001
-#define KEY_OTH_READ 0x00000002
-#define KEY_OTH_WRITE 0x00000004
-#define KEY_OTH_SEARCH 0x00000008
-#define KEY_OTH_LINK 0x00000010
-#define KEY_OTH_SETATTR 0x00000020
-#define KEY_OTH_ALL 0x0000003f
+# define KEY_POS_VIEW 0x01000000
+# define KEY_POS_READ 0x02000000
+# define KEY_POS_WRITE 0x04000000
+# define KEY_POS_SEARCH 0x08000000
+# define KEY_POS_LINK 0x10000000
+# define KEY_POS_SETATTR 0x20000000
+# define KEY_POS_ALL 0x3f000000
+
+# define KEY_USR_VIEW 0x00010000
+# define KEY_USR_READ 0x00020000
+# define KEY_USR_WRITE 0x00040000
+# define KEY_USR_SEARCH 0x00080000
+# define KEY_USR_LINK 0x00100000
+# define KEY_USR_SETATTR 0x00200000
+# define KEY_USR_ALL 0x003f0000
+
+# define KEY_GRP_VIEW 0x00000100
+# define KEY_GRP_READ 0x00000200
+# define KEY_GRP_WRITE 0x00000400
+# define KEY_GRP_SEARCH 0x00000800
+# define KEY_GRP_LINK 0x00001000
+# define KEY_GRP_SETATTR 0x00002000
+# define KEY_GRP_ALL 0x00003f00
+
+# define KEY_OTH_VIEW 0x00000001
+# define KEY_OTH_READ 0x00000002
+# define KEY_OTH_WRITE 0x00000004
+# define KEY_OTH_SEARCH 0x00000008
+# define KEY_OTH_LINK 0x00000010
+# define KEY_OTH_SETATTR 0x00000020
+# define KEY_OTH_ALL 0x0000003f
+#else
+assert_cc(KEY_OTH_ALL == 0x0000003f);
#endif
#include <linux/loop.h>
+#include "macro.h"
+
#ifndef LOOP_CONFIGURE
struct loop_config {
__u32 fd;
__u64 __reserved[8];
};
-#define LOOP_CONFIGURE 0x4C0A
+# define LOOP_CONFIGURE 0x4C0A
+#else
+assert_cc(LOOP_CONFIGURE == 0x4C0A);
#endif
#ifndef LO_FLAGS_DIRECT_IO
-#define LO_FLAGS_DIRECT_IO 16
-#define LOOP_SET_DIRECT_IO 0x4C08
+# define LO_FLAGS_DIRECT_IO 16
+# define LOOP_SET_DIRECT_IO 0x4C08
+#else
+assert_cc(LO_FLAGS_DIRECT_IO == 16);
+assert_cc(LO_FLAGS_DIRECT_IO == 0x4C08);
#endif
#ifndef LOOP_SET_STATUS_SETTABLE_FLAGS
-#define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN | LO_FLAGS_DIRECT_IO)
+# define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN | LO_FLAGS_DIRECT_IO)
#endif
/* 62aa81d7c4c24b90fdb61da70ac0dbbc414f9939 (4.13) */
#ifndef OCFS2_SUPER_MAGIC
-#define OCFS2_SUPER_MAGIC 0x7461636f
+# define OCFS2_SUPER_MAGIC 0x7461636f
+#else
+assert_cc(OCFS2_SUPER_MAGIC == 0x7461636f);
#endif
/* 67e9c74b8a873408c27ac9a8e4c1d1c8d72c93ff (4.5) */
#ifndef CGROUP2_SUPER_MAGIC
-#define CGROUP2_SUPER_MAGIC 0x63677270
+# define CGROUP2_SUPER_MAGIC 0x63677270
+#else
+assert_cc(CGROUP2_SUPER_MAGIC == 0x63677270);
#endif
/* 4282d60689d4f21b40692029080440cc58e8a17d (4.1) */
#ifndef TRACEFS_MAGIC
-#define TRACEFS_MAGIC 0x74726163
+# define TRACEFS_MAGIC 0x74726163
+#else
+assert_cc(TRACEFS_MAGIC == 0x74726163);
#endif
/* e149ed2b805fefdccf7ccdfc19eca22fdd4514ac (3.19) */
#ifndef NSFS_MAGIC
-#define NSFS_MAGIC 0x6e736673
+# define NSFS_MAGIC 0x6e736673
+#else
+assert_cc(NSFS_MAGIC == 0x6e736673);
#endif
/* b2197755b2633e164a439682fb05a9b5ea48f706 (4.4) */
#ifndef BPF_FS_MAGIC
-#define BPF_FS_MAGIC 0xcafe4a11
+# define BPF_FS_MAGIC 0xcafe4a11
+#else
+assert_cc(BPF_FS_MAGIC == 0xcafe4a11);
#endif
/* Not exposed yet (4.20). Defined at ipc/mqueue.c */
#ifndef MQUEUE_MAGIC
-#define MQUEUE_MAGIC 0x19800202
+# define MQUEUE_MAGIC 0x19800202
+#else
+assert_cc(MQUEUE_MAGIC == 0x19800202);
#endif
/* Not exposed yet (as of Linux 5.4). Defined in fs/xfs/libxfs/xfs_format.h */
#ifndef XFS_SB_MAGIC
-#define XFS_SB_MAGIC 0x58465342
+# define XFS_SB_MAGIC 0x58465342
+#else
+assert_cc(XFS_SB_MAGIC == 0x58465342);
#endif
/* dea2903719283c156b53741126228c4a1b40440f (5.17) */
#ifndef CIFS_SUPER_MAGIC
-#define CIFS_SUPER_MAGIC 0xFF534D42
+# define CIFS_SUPER_MAGIC 0xFF534D42
+#else
+assert_cc(CIFS_SUPER_MAGIC == 0xFF534D42);
#endif
/* dea2903719283c156b53741126228c4a1b40440f (5.17) */
#ifndef SMB2_SUPER_MAGIC
-#define SMB2_SUPER_MAGIC 0xFE534D42
+# define SMB2_SUPER_MAGIC 0xFE534D42
+#else
+assert_cc(SMB2_SUPER_MAGIC == 0xFE534D42);
#endif
/* 257f871993474e2bde6c497b54022c362cf398e1 (4.5) */
#ifndef OVERLAYFS_SUPER_MAGIC
-#define OVERLAYFS_SUPER_MAGIC 0x794c7630
+# define OVERLAYFS_SUPER_MAGIC 0x794c7630
+#else
+assert_cc(OVERLAYFS_SUPER_MAGIC == 0x794c7630);
#endif
/* 2a28900be20640fcd1e548b1e3bad79e8221fcf9 (4.7) */
#ifndef UDF_SUPER_MAGIC
-#define UDF_SUPER_MAGIC 0x15013346
+# define UDF_SUPER_MAGIC 0x15013346
+#else
+assert_cc(UDF_SUPER_MAGIC == 0x15013346);
#endif
/* b1123ea6d3b3da25af5c8a9d843bd07ab63213f4 (4.8) */
#ifndef BALLOON_KVM_MAGIC
-#define BALLOON_KVM_MAGIC 0x13661366
+# define BALLOON_KVM_MAGIC 0x13661366
+#else
+assert_cc(BALLOON_KVM_MAGIC == 0x13661366);
#endif
/* 48b4800a1c6af2cdda344ea4e2c843dcc1f6afc9 (4.8) */
#ifndef ZSMALLOC_MAGIC
-#define ZSMALLOC_MAGIC 0x58295829
+# define ZSMALLOC_MAGIC 0x58295829
+#else
+assert_cc(ZSMALLOC_MAGIC == 0x58295829);
#endif
/* 3bc52c45bac26bf7ed1dc8d287ad1aeaed1250b6 (4.9) */
#ifndef DAXFS_MAGIC
-#define DAXFS_MAGIC 0x64646178
+# define DAXFS_MAGIC 0x64646178
+#else
+assert_cc(DAXFS_MAGIC == 0x64646178);
#endif
/* 5ff193fbde20df5d80fec367cea3e7856c057320 (4.10) */
#ifndef RDTGROUP_SUPER_MAGIC
-#define RDTGROUP_SUPER_MAGIC 0x7655821
+# define RDTGROUP_SUPER_MAGIC 0x7655821
+#else
+assert_cc(RDTGROUP_SUPER_MAGIC == 0x7655821);
#endif
/* a481f4d917835cad86701fc0d1e620c74bb5cd5f (4.13) */
#ifndef AAFS_MAGIC
-#define AAFS_MAGIC 0x5a3c69f0
+# define AAFS_MAGIC 0x5a3c69f0
+#else
+assert_cc(AAFS_MAGIC == 0x5a3c69f0);
#endif
/* f044c8847bb61eff5e1e95b6f6bb950e7f4a73a4 (4.15) */
#ifndef AFS_FS_MAGIC
-#define AFS_FS_MAGIC 0x6b414653
+# define AFS_FS_MAGIC 0x6b414653
+#else
+assert_cc(AFS_FS_MAGIC == 0x6b414653);
#endif
/* dddde68b8f06dd83486124b8d245e7bfb15c185d (4.20) */
#ifndef XFS_SUPER_MAGIC
-#define XFS_SUPER_MAGIC 0x58465342
+# define XFS_SUPER_MAGIC 0x58465342
+#else
+assert_cc(XFS_SUPER_MAGIC == 0x58465342);
#endif
/* 3ad20fe393b31025bebfc2d76964561f65df48aa (5.0) */
#ifndef BINDERFS_SUPER_MAGIC
-#define BINDERFS_SUPER_MAGIC 0x6c6f6f70
+# define BINDERFS_SUPER_MAGIC 0x6c6f6f70
+#else
+assert_cc(BINDERFS_SUPER_MAGIC == 0x6c6f6f70);
#endif
/* ed63bb1d1f8469586006a9ca63c42344401aa2ab (5.3) */
#ifndef DMA_BUF_MAGIC
-#define DMA_BUF_MAGIC 0x444d4142
+# define DMA_BUF_MAGIC 0x444d4142
+#else
+assert_cc(DMA_BUF_MAGIC == 0x444d4142);
#endif
/* ea8157ab2ae5e914dd427e5cfab533b6da3819cd (5.3) */
#ifndef Z3FOLD_MAGIC
-#define Z3FOLD_MAGIC 0x33
+# define Z3FOLD_MAGIC 0x33
+#else
+assert_cc(Z3FOLD_MAGIC == 0x33);
#endif
/* 47e4937a4a7ca4184fd282791dfee76c6799966a (5.4) */
#ifndef EROFS_SUPER_MAGIC_V1
-#define EROFS_SUPER_MAGIC_V1 0xe0f5e1e2
+# define EROFS_SUPER_MAGIC_V1 0xe0f5e1e2
+#else
+assert_cc(EROFS_SUPER_MAGIC_V1 == 0xe0f5e1e2);
#endif
/* fe030c9b85e6783bc52fe86449c0a4b8aa16c753 (5.5) */
#ifndef PPC_CMM_MAGIC
-#define PPC_CMM_MAGIC 0xc7571590
+# define PPC_CMM_MAGIC 0xc7571590
+#else
+assert_cc(PPC_CMM_MAGIC == 0xc7571590);
#endif
/* 8dcc1a9d90c10fa4143e5c17821082e5e60e46a1 (5.6) */
#ifndef ZONEFS_MAGIC
-#define ZONEFS_MAGIC 0x5a4f4653
+# define ZONEFS_MAGIC 0x5a4f4653
+#else
+assert_cc(ZONEFS_MAGIC == 0x5a4f4653);
#endif
/* 3234ac664a870e6ea69ae3a57d824cd7edbeacc5 (5.8) */
#ifndef DEVMEM_MAGIC
-#define DEVMEM_MAGIC 0x454d444d
+# define DEVMEM_MAGIC 0x454d444d
+#else
+assert_cc(DEVMEM_MAGIC == 0x454d444d);
#endif
/* cb12fd8e0dabb9a1c8aef55a6a41e2c255fcdf4b (6.8) */
#ifndef PID_FS_MAGIC
-#define PID_FS_MAGIC 0x50494446
+# define PID_FS_MAGIC 0x50494446
+#else
+assert_cc(PID_FS_MAGIC == 0x50494446);
#endif
/* Not in mainline but included in Ubuntu */
#ifndef SHIFTFS_MAGIC
-#define SHIFTFS_MAGIC 0x6a656a62
+# define SHIFTFS_MAGIC 0x6a656a62
+#else
+assert_cc(SHIFTFS_MAGIC == 0x6a656a62);
#endif
/* 1507f51255c9ff07d75909a84e7c0d7f3c4b2f49 (5.14) */
#ifndef SECRETMEM_MAGIC
-#define SECRETMEM_MAGIC 0x5345434d
+# define SECRETMEM_MAGIC 0x5345434d
+#else
+assert_cc(SECRETMEM_MAGIC == 0x5345434d);
#endif
/* Not exposed yet. Defined at fs/fuse/inode.c */
#ifndef FUSE_SUPER_MAGIC
-#define FUSE_SUPER_MAGIC 0x65735546
+# define FUSE_SUPER_MAGIC 0x65735546
+#else
+assert_cc(FUSE_SUPER_MAGIC == 0x65735546);
#endif
/* Not exposed yet. Defined at fs/fuse/control.c */
#ifndef FUSE_CTL_SUPER_MAGIC
-#define FUSE_CTL_SUPER_MAGIC 0x65735543
+# define FUSE_CTL_SUPER_MAGIC 0x65735543
+#else
+assert_cc(FUSE_CTL_SUPER_MAGIC == 0x65735543);
#endif
/* Not exposed yet. Defined at fs/ceph/super.h */
#ifndef CEPH_SUPER_MAGIC
-#define CEPH_SUPER_MAGIC 0x00c36400
+# define CEPH_SUPER_MAGIC 0x00c36400
+#else
+assert_cc(CEPH_SUPER_MAGIC == 0x00c36400);
#endif
/* Not exposed yet. Defined at fs/orangefs/orangefs-kernel.h */
#ifndef ORANGEFS_DEVREQ_MAGIC
-#define ORANGEFS_DEVREQ_MAGIC 0x20030529
+# define ORANGEFS_DEVREQ_MAGIC 0x20030529
+#else
+assert_cc(ORANGEFS_DEVREQ_MAGIC == 0x20030529);
#endif
/* linux/gfs2_ondisk.h */
#ifndef GFS2_MAGIC
-#define GFS2_MAGIC 0x01161970
+# define GFS2_MAGIC 0x01161970
+#else
+assert_cc(GFS2_MAGIC == 0x01161970);
#endif
/* Not exposed yet. Defined at fs/configfs/mount.c */
#ifndef CONFIGFS_MAGIC
-#define CONFIGFS_MAGIC 0x62656570
+# define CONFIGFS_MAGIC 0x62656570
+#else
+assert_cc(CONFIGFS_MAGIC == 0x62656570);
#endif
/* Not exposed yet. Defined at fs/vboxsf/super.c */
#ifndef VBOXSF_SUPER_MAGIC
-#define VBOXSF_SUPER_MAGIC 0x786f4256
+# define VBOXSF_SUPER_MAGIC 0x786f4256
+#else
+assert_cc(VBOXSF_SUPER_MAGIC == 0x786f4256);
#endif
/* Not exposed yet. Defined at fs/exfat/exfat_fs.h */
#ifndef EXFAT_SUPER_MAGIC
-#define EXFAT_SUPER_MAGIC 0x2011BAB0UL
+# define EXFAT_SUPER_MAGIC 0x2011BAB0UL
+#else
+assert_cc(EXFAT_SUPER_MAGIC == 0x2011BAB0UL);
#endif
/* Not exposed yet, internally actually called RPCAUTH_GSSMAGIC. Defined in net/sunrpc/rpc_pipe.c */
#ifndef RPC_PIPEFS_SUPER_MAGIC
-#define RPC_PIPEFS_SUPER_MAGIC 0x67596969
+# define RPC_PIPEFS_SUPER_MAGIC 0x67596969
+#else
+assert_cc(RPC_PIPEFS_SUPER_MAGIC == 0x67596969);
#endif
/* Not exposed yet, defined at fs/ntfs/ntfs.h */
#ifndef NTFS_SB_MAGIC
-#define NTFS_SB_MAGIC 0x5346544e
+# define NTFS_SB_MAGIC 0x5346544e
+#else
+assert_cc(NTFS_SB_MAGIC == 0x5346544e);
#endif
/* Not exposed yet, encoded literally in fs/ntfs3/super.c. */
#ifndef NTFS3_SUPER_MAGIC
-#define NTFS3_SUPER_MAGIC 0x7366746e
+# define NTFS3_SUPER_MAGIC 0x7366746e
+#else
+assert_cc(NTFS3_SUPER_MAGIC == 0x7366746e);
#endif
#include <sys/mman.h>
+#include "macro.h"
+
#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002U
+# define MFD_ALLOW_SEALING 0x0002U
+#else
+assert_cc(MFD_ALLOW_SEALING == 0x0002U);
#endif
#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
+# define MFD_CLOEXEC 0x0001U
+#else
+assert_cc(MFD_CLOEXEC == 0x0001U);
#endif
#ifndef MFD_NOEXEC_SEAL
-#define MFD_NOEXEC_SEAL 0x0008U
+# define MFD_NOEXEC_SEAL 0x0008U
+#else
+assert_cc(MFD_NOEXEC_SEAL == 0x0008U);
#endif
#ifndef MFD_EXEC
-#define MFD_EXEC 0x0010U
+# define MFD_EXEC 0x0010U
+#else
+assert_cc(MFD_EXEC == 0x0010U);
#endif
#include <sys/mount.h>
+#include "macro.h"
+
/* dab741e0e02bd3c4f5e2e97be74b39df2523fc6e (5.10) */
#ifndef MS_NOSYMFOLLOW
-#define MS_NOSYMFOLLOW 256
+# define MS_NOSYMFOLLOW 256
+#else
+assert_cc(MS_NOSYMFOLLOW == 256);
#endif
#include <linux/prctl.h>
+#include "macro.h"
+
/* 58319057b7847667f0c9585b9de0e8932b0fdb08 (4.3) */
#ifndef PR_CAP_AMBIENT
#define PR_CAP_AMBIENT 47
/* b507808ebce23561d4ff8c2aa1fb949fe402bc61 (6.3) */
#ifndef PR_SET_MDWE
-#define PR_SET_MDWE 65
+# define PR_SET_MDWE 65
+#else
+assert_cc(PR_SET_MDWE == 65);
#endif
+
#ifndef PR_MDWE_REFUSE_EXEC_GAIN
-#define PR_MDWE_REFUSE_EXEC_GAIN 1
+# define PR_MDWE_REFUSE_EXEC_GAIN 1
+#else
+assert_cc(PR_MDWE_REFUSE_EXEC_GAIN == 1);
#endif
#ifndef PR_SET_MEMORY_MERGE
-#define PR_SET_MEMORY_MERGE 67
+# define PR_SET_MEMORY_MERGE 67
+#else
+assert_cc(PR_SET_MEMORY_MERGE == 67);
#endif
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "macro.h"
+
#if USE_SYS_RANDOM_H
# include <sys/random.h>
#else
#endif
#ifndef GRND_NONBLOCK
-#define GRND_NONBLOCK 0x0001
+# define GRND_NONBLOCK 0x0001
+#else
+assert_cc(GRND_NONBLOCK == 0x0001);
#endif
#ifndef GRND_RANDOM
-#define GRND_RANDOM 0x0002
+# define GRND_RANDOM 0x0002
+#else
+assert_cc(GRND_RANDOM == 0x0002);
#endif
#ifndef GRND_INSECURE
-#define GRND_INSECURE 0x0004
+# define GRND_INSECURE 0x0004
+#else
+assert_cc(GRND_INSECURE == 0x0004);
#endif
#include <sys/resource.h>
+#include "macro.h"
+
#ifndef RLIMIT_RTTIME
-#define RLIMIT_RTTIME 15
+# define RLIMIT_RTTIME 15
+#else
+assert_cc(RLIMIT_RTTIME == 15);
#endif
/* If RLIMIT_RTTIME is not defined, then we cannot use RLIMIT_NLIMITS as is */
#include <sched.h>
+#include "macro.h"
+
#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
+# define CLONE_NEWCGROUP 0x02000000
+#else
+assert_cc(CLONE_NEWCGROUP == 0x02000000);
#endif
/* 769071ac9f20b6a447410c7eaa55d1a5233ef40c (5.8) */
#ifndef CLONE_NEWTIME
-#define CLONE_NEWTIME 0x00000080
+# define CLONE_NEWTIME 0x00000080
+#else
+assert_cc(CLONE_NEWTIME == 0x00000080);
#endif
/* Not exposed yet. Defined at include/linux/sched.h */
#ifndef PF_KTHREAD
-#define PF_KTHREAD 0x00200000
+# define PF_KTHREAD 0x00200000
+#else
+assert_cc(PF_KTHREAD == 0x00200000);
#endif
-/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of the same
- * name, which we need in userspace at various places but is not defined in userspace currently, neither under this
- * name nor any other. */
-/* Not exposed yet. Defined at include/linux/sched.h */
+/* The maximum thread/process name length including trailing NUL byte. This mimics the kernel definition of
+ * the same name, which we need in userspace at various places but is not defined in userspace currently,
+ * neither under this name nor any other.
+ *
+ * Not exposed yet. Defined at include/linux/sched.h */
#ifndef TASK_COMM_LEN
-#define TASK_COMM_LEN 16
+# define TASK_COMM_LEN 16
+#else
+assert_cc(TASK_COMM_LEN == 16);
#endif
#include <sys/timerfd.h>
+#include "macro.h"
+
#ifndef TFD_TIMER_CANCEL_ON_SET
-#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+# define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#else
+assert_cc(TFD_TIMER_CANCEL_ON_SET == (1 << 1));
#endif
#include <uchar.h>
#if !HAVE_CHAR32_T
-#define char32_t uint32_t
+# define char32_t uint32_t
#endif
#if !HAVE_CHAR16_T
-#define char16_t uint16_t
+# define char16_t uint16_t
#endif
#include <sys/wait.h>
+#include "macro.h"
+
#ifndef P_PIDFD
-#define P_PIDFD 3
+# define P_PIDFD 3
+#else
+assert_cc(P_PIDFD == 3);
#endif
#include "string-util.h"
#include "strv.h"
+const char* nulstr_get(const char *nulstr, const char *needle) {
+ if (!nulstr)
+ return NULL;
+
+ NULSTR_FOREACH(i, nulstr)
+ if (streq(i, needle))
+ return i;
+
+ return NULL;
+}
+
char** strv_parse_nulstr_full(const char *s, size_t l, bool drop_trailing_nuls) {
+ _cleanup_strv_free_ char **v = NULL;
+ size_t c = 0, i = 0;
+
/* l is the length of the input data, which will be split at NULs into elements of the resulting
* strv. Hence, the number of items in the resulting strv will be equal to one plus the number of NUL
* bytes in the l bytes starting at s, unless s[l-1] is NUL, in which case the final empty string is
* Note that contrary to a normal nulstr which cannot contain empty strings, because the input data
* is terminated by any two consequent NUL bytes, this parser accepts empty strings in s. */
- _cleanup_strv_free_ char **v = NULL;
- size_t c = 0, i = 0;
-
assert(s || l <= 0);
if (drop_trailing_nuls)
if (!v)
return NULL;
- for (const char *p = s; p < s + l; ) {
+ for (const char *p = s; p < s + l;) {
const char *e;
e = memchr(p, 0, s + l - p);
v[i] = memdup_suffix0(p, e ? e - p : s + l - p);
if (!v[i])
return NULL;
-
i++;
if (!e)
}
int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
+ _cleanup_free_ char *m = NULL;
+ size_t n = 0;
+
/* Builds a nulstr and returns it together with the size. An extra NUL byte will be appended (⚠️ but
* not included in the size! ⚠️). This is done so that the nulstr can be used both in
* strv_parse_nulstr() and in NULSTR_FOREACH()/strv_split_nulstr() contexts, i.e. with and without a
* NUL bytes (which it will, if not empty). To ensure that this assumption *always* holds, we'll
* return a buffer with two NUL bytes in that case, but return a size of zero. */
- _cleanup_free_ char *m = NULL;
- size_t n = 0;
-
assert(ret);
STRV_FOREACH(i, l) {
size_t z;
- z = strlen(*i);
+ z = strlen(*i) + 1;
- if (!GREEDY_REALLOC(m, n + z + 2))
+ if (!GREEDY_REALLOC(m, n + z + 1)) /* One extra NUL at the end as marker */
return -ENOMEM;
- memcpy(m + n, *i, z + 1);
- n += z + 1;
+ memcpy(m + n, *i, z);
+ n += z;
}
if (!m) {
n = 0;
} else
- /* Make sure there is a second extra NUL at the end of resulting nulstr (not counted in return size) */
+ /* Extra NUL is not counted in size returned */
m[n] = '\0';
*ret = TAKE_PTR(m);
return strv_make_nulstr(strv, ret, ret_size);
}
-
-const char* nulstr_get(const char *nulstr, const char *needle) {
- if (!nulstr)
- return NULL;
-
- NULSTR_FOREACH(i, nulstr)
- if (streq(i, needle))
- return i;
-
- return NULL;
-}
for (typeof(*(l)) *(i) = (l), *(j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
const char* nulstr_get(const char *nulstr, const char *needle);
-
static inline bool nulstr_contains(const char *nulstr, const char *needle) {
return nulstr_get(nulstr, needle);
}
return strv_parse_nulstr_full(s, l, false);
}
char** strv_split_nulstr(const char *s);
-int strv_make_nulstr(char * const *l, char **p, size_t *n);
-int set_make_nulstr(Set *s, char **ret, size_t *ret_size);
-
static inline int strv_from_nulstr(char ***ret, const char *nulstr) {
char **t;
*ret = t;
return 0;
}
+
+int strv_make_nulstr(char * const *l, char **p, size_t *n);
+int set_make_nulstr(Set *s, char **ret, size_t *ret_size);
}
int runtime_directory(char **ret, RuntimeScope scope, const char *suffix) {
- _cleanup_free_ char *d = NULL;
int r;
assert(ret);
* Return value indicates whether the suffix was applied or not */
const char *e = secure_getenv("RUNTIME_DIRECTORY");
- if (e) {
- d = strdup(e);
- if (!d)
- return -ENOMEM;
-
- *ret = TAKE_PTR(d);
- return false;
- }
+ if (e)
+ return strdup_to(ret, e);
if (scope == RUNTIME_SCOPE_USER) {
- r = xdg_user_runtime_dir(&d, suffix);
+ r = xdg_user_runtime_dir(ret, suffix);
if (r < 0)
return r;
} else {
- d = path_join("/run", suffix);
+ char *d = path_join("/run", suffix);
if (!d)
return -ENOMEM;
+ *ret = d;
}
- *ret = TAKE_PTR(d);
return true;
}
}
int path_extract_directory(const char *path, char **ret) {
- _cleanup_free_ char *a = NULL;
const char *c, *next = NULL;
int r;
if (*path != '/') /* filename only */
return -EDESTADDRREQ;
- a = strdup("/");
- if (!a)
- return -ENOMEM;
- *ret = TAKE_PTR(a);
- return 0;
+ return strdup_to(ret, "/");
}
- a = strndup(path, next - path);
+ _cleanup_free_ char *a = strndup(path, next - path);
if (!a)
return -ENOMEM;
return 0;
}
-static inline bool path_equal_ptr(const char *a, const char *b) {
- return !!a == !!b && (!a || path_equal(a, b));
-}
-
/* Note: the search terminates on the first NULL item. */
#define PATH_IN_SET(p, ...) path_strv_contains(STRV_MAKE(__VA_ARGS__), p)
/* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */
e = secure_getenv("SYSTEMD_PROC_CMDLINE");
- if (e) {
- char *m;
-
- m = strdup(e);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0;
- }
+ if (e)
+ return strdup_to(ret, e);
if (detect_container() > 0)
return pid_get_cmdline(1, SIZE_MAX, 0, ret);
int getenv_for_pid(pid_t pid, const char *field, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
- char *value = NULL;
const char *path;
size_t sum = 0;
int r;
assert(field);
assert(ret);
- if (pid == 0 || pid == getpid_cached()) {
- const char *e;
-
- e = getenv(field);
- if (!e) {
- *ret = NULL;
- return 0;
- }
-
- value = strdup(e);
- if (!value)
- return -ENOMEM;
-
- *ret = value;
- return 1;
- }
+ if (pid == 0 || pid == getpid_cached())
+ return strdup_to_full(ret, getenv(field));
if (!pid_is_valid(pid))
return -EINVAL;
sum += r;
match = startswith(line, field);
- if (match && *match == '=') {
- value = strdup(match + 1);
- if (!value)
- return -ENOMEM;
-
- *ret = value;
- return 1;
- }
+ if (match && *match == '=')
+ return strdup_to_full(ret, match + 1);
}
*ret = NULL;
assert(sa);
assert(salen >= sizeof(sa->sa.sa_family));
+ assert(ret);
switch (sa->sa.sa_family) {
assert(sa);
assert(salen > sizeof(sa_family_t));
+ assert(ret);
r = getnameinfo(sa, salen, host, sizeof(host), /* service= */ NULL, /* service_len= */ 0, IDN_FLAGS);
if (r != 0) {
return sockaddr_pretty(sa, salen, /* translate_ipv6= */ true, /* include_port= */ true, ret);
}
- if (ret) {
- char *copy = strdup(host);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
- }
-
- return 0;
+ return strdup_to(ret, host);
}
static const char* const netlink_family_table[] = {
* When looking under root_dir, we can't expect /dev/ to be mounted,
* so let's see if the path is a (possibly dangling) symlink to /dev/null. */
- if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
+ if (path_equal(path_startswith(fn, root ?: "/"), "dev/null"))
return true;
r = chase_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st);
return 1;
}
+int strdup_to_full(char **ret, const char *src) {
+ if (!src) {
+ if (ret)
+ *ret = NULL;
+
+ return 0;
+ } else {
+ if (ret) {
+ char *t = strdup(src);
+ if (!t)
+ return -ENOMEM;
+ *ret = t;
+ }
+
+ return 1;
+ }
+};
+
bool string_is_safe(const char *p) {
if (!p)
return false;
return -ENOMEM;
*ret = m;
- return !isempty(q + 1); /* more coming? */
- } else {
- if (p == s)
- *ret = NULL; /* Just use the input string */
- else {
- char *m;
-
- m = strdup(p);
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- }
-
- return 0; /* The end */
- }
+ return !isempty(q + 1); /* More coming? */
+ } else
+ /* Tell the caller to use the input string if equal */
+ return strdup_to(ret, p != s ? p : NULL);
}
- if (!q) {
- char *m;
-
+ if (!q)
/* No more lines, return empty line */
-
- m = strdup("");
- if (!m)
- return -ENOMEM;
-
- *ret = m;
- return 0; /* The end */
- }
+ return strdup_to(ret, "");
p = q + 1;
c++;
}
int free_and_strndup(char **p, const char *s, size_t l);
+int strdup_to_full(char **ret, const char *src);
+static inline int strdup_to(char **ret, const char *src) {
+ int r = strdup_to_full(ASSERT_PTR(ret), src);
+ return r < 0 ? r : 0; /* Suppress return value of 1. */
+}
+
bool string_is_safe(const char *p) _pure_;
DISABLE_WARNING_STRINGOP_TRUNCATION;
ssize_t strlevenshtein(const char *x, const char *y);
-static inline int strdup_or_null(const char *s, char **ret) {
- char *c;
-
- assert(ret);
-
- /* This is a lot like strdup(), but is happy with NULL strings, and does not treat that as error, but
- * copies the NULL value. */
-
- if (!s) {
- *ret = NULL;
- return 0;
- }
-
- c = strdup(s);
- if (!c)
- return -ENOMEM;
-
- *ret = c;
- return 1;
-}
-
char *strrstr(const char *haystack, const char *needle);
tty = active;
}
- if (tty == active)
- *ret = TAKE_PTR(active);
- else {
- char *tmp;
-
- tmp = strdup(tty);
- if (!tmp)
- return -ENOMEM;
-
- *ret = tmp;
- }
+ if (tty != active)
+ return strdup_to(ret, tty);
+ *ret = TAKE_PTR(active);
return 0;
}
}
int getttyname_malloc(int fd, char **ret) {
- char path[PATH_MAX], *c; /* PATH_MAX is counted *with* the trailing NUL byte */
+ char path[PATH_MAX]; /* PATH_MAX is counted *with* the trailing NUL byte */
int r;
assert(fd >= 0);
if (r > 0)
return -r;
- c = strdup(skip_dev_prefix(path));
- if (!c)
- return -ENOMEM;
-
- *ret = c;
- return 0;
+ return strdup_to(ret, skip_dev_prefix(path));
}
int getttyname_harder(int fd, char **ret) {
return -EINVAL;
if (ret) {
- _cleanup_free_ char *b = NULL;
-
- b = strdup(w);
- if (!b)
- return -ENOMEM;
-
- *ret = TAKE_PTR(b);
+ r = strdup_to(ret, w);
+ if (r < 0)
+ return r;
}
if (ret_devnr)
}
static inline const char *ansi_underline(void) {
- return underline_enabled() ? ANSI_UNDERLINE : ANSI_NORMAL;
+ return underline_enabled() ? ANSI_UNDERLINE : "";
}
static inline const char *ansi_add_underline(void) {
int get_timezone(char **ret) {
_cleanup_free_ char *t = NULL;
- const char *e;
- char *z;
int r;
assert(ret);
r = readlink_malloc("/etc/localtime", &t);
- if (r == -ENOENT) {
+ if (r == -ENOENT)
/* If the symlink does not exist, assume "UTC", like glibc does */
- z = strdup("UTC");
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
- }
+ return strdup_to(ret, "UTC");
if (r < 0)
- return r; /* returns EINVAL if not a symlink */
+ return r; /* Return EINVAL if not a symlink */
- e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
+ const char *e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
if (!e)
return -EINVAL;
-
if (!timezone_is_valid(e, LOG_DEBUG))
return -EINVAL;
- z = strdup(e);
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
+ return strdup_to(ret, e);
}
time_t mktime_or_timegm(struct tm *tm, bool utc) {
return 1;
good:
- s = strdup(name);
- if (!s)
- return -ENOMEM;
-
- *ret = TAKE_PTR(s);
- return 0;
+ return strdup_to(ret, name);
}
int slice_build_parent_slice(const char *slice, char **ret) {
- _cleanup_free_ char *s = NULL;
- char *dash;
- int r;
-
assert(slice);
assert(ret);
return 0;
}
- s = strdup(slice);
+ _cleanup_free_ char *s = strdup(slice);
if (!s)
return -ENOMEM;
- dash = strrchr(s, '-');
- if (dash)
- strcpy(dash, ".slice");
- else {
- r = free_and_strdup(&s, SPECIAL_ROOT_SLICE);
- if (r < 0)
- return r;
- }
+ char *dash = strrchr(s, '-');
+ if (!dash)
+ return strdup_to_full(ret, SPECIAL_ROOT_SLICE);
+
+ /* We know that s ended with .slice before truncation, so we have enough space. */
+ strcpy(dash, ".slice");
*ret = TAKE_PTR(s);
return 1;
{ "VMW", VIRTUALIZATION_VMWARE },
{ "innotek GmbH", VIRTUALIZATION_ORACLE },
{ "VirtualBox", VIRTUALIZATION_ORACLE },
+ { "Oracle Corporation", VIRTUALIZATION_ORACLE }, /* Detect VirtualBox on some proprietary systems via the board_vendor */
{ "Xen", VIRTUALIZATION_XEN },
{ "Bochs", VIRTUALIZATION_BOCHS },
{ "Parallels", VIRTUALIZATION_PARALLELS },
GUID_DEF(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
#define EFI_IMAGE_SECURITY_DATABASE_GUID \
GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
+#define EFI_CUSTOM_MODE_ENABLE_GUID \
+ GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
#define EVT_TIMER 0x80000000U
#define EVT_RUNTIME 0x40000000U
efi_arch_c_args = {
'aarch64' : ['-mgeneral-regs-only'],
'arm' : ['-mgeneral-regs-only'],
- # Until -mgeneral-regs-only is supported in LoongArch, use the following option instead:
+ # Until -mgeneral-regs-only is supported in LoongArch, use the following option instead:
'loongarch64' : ['-mno-lsx', '-mno-lasx'],
# Pass -m64/32 explicitly to make building on x32 work.
'x86_64' : ['-m64', '-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'],
if name == 'addon@0@.efi.stub'.format(efi_arch)
efi_addon = exe.full_path()
endif
+
+ test('check-alignment-@0@'.format(name),
+ check_efi_alignment_py,
+ args : exe.full_path(),
+ suite : 'efi')
endforeach
alias_target('systemd-boot', boot_targets)
return decode_secure_boot_mode(secure, audit, deployed, setup);
}
+/*
+ * Custom mode allows to change secure boot certificate databases db, dbx, KEK and PK without the variable
+ * updates being signed. When enrolling certificates to an unconfigured system (no PK present yet) writing
+ * db, dbx and KEK updates without signature works fine even in standard mode. Writing PK updates without
+ * signature requires custom mode in any case.
+ *
+ * Enabling custom mode works only if a user is physically present. Note that OVMF has a dummy
+ * implementation for the user presence check (there is no useful way to implement a presence check for a
+ * virtual machine).
+ *
+ * FYI: Your firmware setup utility might offers the option to enroll certificates from *.crt files
+ * (DER-encoded x509 certificates) on the ESP; that uses custom mode too. Your firmware setup might also
+ * offer the option to switch the system into custom mode for the next boot.
+ */
+static bool custom_mode_enabled(void) {
+ bool enabled = false;
+
+ (void) efivar_get_boolean_u8(MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE),
+ u"CustomMode", &enabled);
+ return enabled;
+}
+
+static EFI_STATUS set_custom_mode(bool enable) {
+ static char16_t name[] = u"CustomMode";
+ static uint32_t attr =
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS;
+ uint8_t mode = enable
+ ? 1 /* CUSTOM_SECURE_BOOT_MODE */
+ : 0; /* STANDARD_SECURE_BOOT_MODE */
+
+ return RT->SetVariable(name, MAKE_GUID_PTR(EFI_CUSTOM_MODE_ENABLE),
+ attr, sizeof(mode), &mode);
+}
+
EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force) {
assert(root_dir);
assert(path);
+ bool need_custom_mode = false;
EFI_STATUS err;
clear_screen(COLOR_NORMAL);
const char16_t *name;
const char16_t *filename;
const EFI_GUID vendor;
+ bool required;
char *buffer;
size_t size;
} sb_vars[] = {
- { u"db", u"db.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, NULL, 0 },
- { u"KEK", u"KEK.auth", EFI_GLOBAL_VARIABLE, NULL, 0 },
- { u"PK", u"PK.auth", EFI_GLOBAL_VARIABLE, NULL, 0 },
+ { u"db", u"db.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, true, NULL, 0 },
+ { u"dbx", u"dbx.auth", EFI_IMAGE_SECURITY_DATABASE_GUID, false, NULL, 0 },
+ { u"KEK", u"KEK.auth", EFI_GLOBAL_VARIABLE, true, NULL, 0 },
+ { u"PK", u"PK.auth", EFI_GLOBAL_VARIABLE, true, NULL, 0 },
};
/* Make sure all keys files exist before we start enrolling them by loading them from the disk first. */
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
err = file_read(dir, sb_vars[i].filename, 0, 0, &sb_vars[i].buffer, &sb_vars[i].size);
- if (err != EFI_SUCCESS) {
+ if (err != EFI_SUCCESS && sb_vars[i].required) {
log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_vars[i].filename);
goto out_deallocate;
}
+ if (streq16(sb_vars[i].name, u"PK") && sb_vars[i].size > 20) {
+ assert(sb_vars[i].buffer);
+ /*
+ * The buffer should be EFI_TIME (16 bytes), followed by
+ * EFI_VARIABLE_AUTHENTICATION_2 header. First header field is the size. If the
+ * size covers only the header itself (8 bytes) plus the signature type guid (16
+ * bytes), leaving no space for an actual signature, we can conclude that no
+ * signature is present.
+ */
+ uint32_t *sigsize = (uint32_t*)(sb_vars[i].buffer + 16);
+ if (*sigsize <= 24) {
+ printf("PK is not signed (need custom mode).\n");
+ need_custom_mode = true;
+ }
+ }
+ }
+
+ if (need_custom_mode && !custom_mode_enabled()) {
+ err = set_custom_mode(/* enable */ true);
+ if (err != EFI_SUCCESS) {
+ log_error_status(err, "Failed to enable custom mode: %m");
+ goto out_deallocate;
+ }
+ printf("Custom mode enabled.\n");
}
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ if (sb_vars[i].size == 0)
+ continue;
err = efivar_set_raw(&sb_vars[i].vendor, sb_vars[i].name, sb_vars[i].buffer, sb_vars[i].size, sb_vars_opts);
if (err != EFI_SUCCESS) {
log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_vars[i].name);
static int automount_send_ready(Automount *a, Set *tokens, int status);
static void automount_init(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
- assert(a);
- assert(u);
assert(u->load_state == UNIT_STUB);
a->pipe_fd = -EBADF;
}
static void automount_done(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
unmount_autofs(a);
}
static int automount_load(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
/* Load a .automount file */
static void automount_set_state(Automount *a, AutomountState state) {
AutomountState old_state;
+
assert(a);
if (a->state != state)
}
static int automount_coldplug(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(a->state == AUTOMOUNT_DEAD);
if (a->deserialized_state == a->state)
}
static void automount_dump(Unit *u, FILE *f, const char *prefix) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
fprintf(f,
"%sAutomount State: %s\n"
r = 0;
/* Autofs thankfully does not hand out 0 as a token */
- while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
- int k;
-
+ while ((token = PTR_TO_UINT(set_steal_first(tokens))))
/* Autofs fun fact:
*
- * if you pass a positive status code here, kernels
- * prior to 4.12 will freeze! Yay! */
-
- k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
- ioctl_fd,
- token,
- status);
- if (k < 0)
- r = k;
- }
+ * if you pass a positive status code here, kernels prior to 4.12 will freeze! Yay! */
+ RET_GATHER(r, autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
+ ioctl_fd,
+ token,
+ status));
return r;
}
static void automount_trigger_notify(Unit *u, Unit *other) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(other);
/* Filter out invocations with bogus state */
}
static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
+ Automount *a = ASSERT_PTR(AUTOMOUNT(userdata));
_cleanup_close_ int ioctl_fd = -EBADF;
- Automount *a = AUTOMOUNT(userdata);
int r;
- assert(a);
assert(source == a->expire_event_source);
ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
}
static int automount_start(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(IN_SET(a->state, AUTOMOUNT_DEAD, AUTOMOUNT_FAILED));
if (path_is_mount_point(a->where) > 0)
}
static int automount_stop(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
- assert(a);
assert(IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING));
automount_enter_dead(a, AUTOMOUNT_SUCCESS);
}
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
void *p;
int r;
- assert(a);
assert(f);
assert(fds);
}
static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
assert(fds);
if (streq(key, "state")) {
}
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
+ Automount *a = ASSERT_PTR(AUTOMOUNT(userdata));
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
union autofs_v5_packet_union packet;
- Automount *a = AUTOMOUNT(userdata);
Unit *trigger;
int r;
- assert(a);
assert(fd == a->pipe_fd);
if (events & (EPOLLHUP|EPOLLERR)) {
}
static void automount_reset_failed(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
if (a->state == AUTOMOUNT_FAILED)
automount_set_state(a, AUTOMOUNT_DEAD);
}
static int automount_can_start(Unit *u) {
- Automount *a = AUTOMOUNT(u);
+ Automount *a = ASSERT_PTR(AUTOMOUNT(u));
int r;
- assert(a);
-
r = unit_test_start_limit(u);
if (r < 0) {
automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
assert(map_fd >= 0);
+ if (!head) {
+ static const struct socket_bind_rule val = {
+ .address_family = SOCKET_BIND_RULE_AF_MATCH_NOTHING,
+ };
+
+ if (sym_bpf_map_update_elem(map_fd, &i, &val, BPF_ANY) != 0)
+ return -errno;
+ }
+
LIST_FOREACH(socket_bind_items, item, head) {
struct socket_bind_rule val = {
.address_family = (uint32_t) item->address_family,
*/
#include <linux/types.h>
+#include <stdint.h>
/*
* Bind rule is matched with socket fields accessible to cgroup/bind{4,6} hook
* through bpf_sock_addr struct.
- * 'address_family' is expected to be one of AF_UNSPEC, AF_INET or AF_INET6.
+ * 'address_family' is expected to be one of AF_UNSPEC, AF_INET, AF_INET6 or the
+ * magic SOCKET_BIND_RULE_AF_MATCH_NOTHING.
* Matching by family is bypassed for rules with AF_UNSPEC set, which makes the
* rest of a rule applicable for both IPv4 and IPv6 addresses.
+ * If SOCKET_BIND_RULE_AF_MATCH_NOTHING is set the rule fails unconditionally
+ * and other checks are skipped.
* If matching by family is either successful or bypassed, a rule and a socket
* are matched by ip protocol.
* If 'protocol' is 0, matching is bypassed.
};
#define SOCKET_BIND_MAX_RULES 128
+#define SOCKET_BIND_RULE_AF_MATCH_NOTHING UINT32_MAX
__u32 protocol,
__u16 port,
const struct socket_bind_rule *r) {
+ if (r->address_family == SOCKET_BIND_RULE_AF_MATCH_NOTHING)
+ return false;
+
return match_af(address_family, r) &&
match_protocol(protocol, r) &&
match_user_port(port, r);
}
static void device_init(Unit *u) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- assert(d);
- assert(UNIT(d)->load_state == UNIT_STUB);
+ assert(u->load_state == UNIT_STUB);
/* In contrast to all other unit types we timeout jobs waiting
* for devices by default. This is because they otherwise wait
}
static void device_done(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
+ Device *d = ASSERT_PTR(DEVICE(u));
device_unset_sysfs(d);
d->deserialized_sysfs = mfree(d->deserialized_sysfs);
}
static int device_coldplug(Unit *u) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- assert(d);
assert(d->state == DEVICE_DEAD);
/* First, let's put the deserialized state and found mask into effect, if we have it. */
}
static void device_catchup(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
+ Device *d = ASSERT_PTR(DEVICE(u));
/* Second, let's update the state with the enumerated state */
device_update_found_one(d, d->enumerated_found, DEVICE_FOUND_MASK);
}
static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_free_ char *s = NULL;
- Device *d = DEVICE(u);
- assert(d);
- assert(u);
assert(f);
assert(fds);
}
static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
int r;
- assert(d);
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static void device_dump(Unit *u, FILE *f, const char *prefix) {
- Device *d = DEVICE(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_free_ char *s = NULL;
- assert(d);
+ assert(f);
+ assert(prefix);
(void) device_found_to_string_many(d->found, &s);
}
static UnitActiveState device_active_state(Unit *u) {
- assert(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- return state_translation_table[DEVICE(u)->state];
+ return state_translation_table[d->state];
}
static const char *device_sub_state_to_string(Unit *u) {
- assert(u);
+ Device *d = ASSERT_PTR(DEVICE(u));
- return device_state_to_string(DEVICE(u)->state);
+ return device_state_to_string(d->state);
}
static int device_update_description(Unit *u, sd_device *dev, const char *path) {
}
static int device_add_udev_wants(Unit *u, sd_device *dev) {
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_strv_free_ char **added = NULL;
const char *wants, *property;
- Device *d = DEVICE(u);
int r;
- assert(d);
assert(dev);
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
/* Let's upgrade Requires= to BindsTo= on us. (Used when SYSTEMD_MOUNT_DEVICE_BOUND is set) */
+ assert(u);
+
HASHMAP_FOREACH_KEY(v, other, unit_get_dependencies(u, UNIT_REQUIRED_BY)) {
if (other->type != UNIT_MOUNT)
continue;
unit_add_to_load_queue(u);
}
- if (!DEVICE(u)->path) {
- DEVICE(u)->path = strdup(path);
- if (!DEVICE(u)->path)
+ Device *d = ASSERT_PTR(DEVICE(u));
+
+ if (!d->path) {
+ d->path = strdup(path);
+ if (!d->path)
return log_oom();
}
/* If this was created via some dependency and has not actually been seen yet ->sysfs will not be
* initialized. Hence initialize it if necessary. */
if (sysfs) {
- r = device_set_sysfs(DEVICE(u), sysfs);
+ r = device_set_sysfs(d, sysfs);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set sysfs path %s: %m", sysfs);
* by systemd before the device appears on its radar. In this case the device unit is partially
* initialized and includes the deps on the mount unit but at that time the "bind mounts" flag wasn't
* present. Fix this up now. */
- if (dev && device_is_bound_by_mounts(DEVICE(u), dev))
+ if (dev && device_is_bound_by_mounts(d, dev))
device_upgrade_mount_deps(u);
if (units) {
- r = set_ensure_put(units, NULL, DEVICE(u));
+ r = set_ensure_put(units, NULL, d);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to store unit: %m");
}
}
static Unit *device_following(Unit *u) {
- Device *d = DEVICE(u);
- Device *first = NULL;
-
- assert(d);
+ Device *d = ASSERT_PTR(DEVICE(u)), *first = NULL;
if (startswith(u->id, "sys-"))
return NULL;
return UNIT(first);
}
-static int device_following_set(Unit *u, Set **_set) {
- Device *d = DEVICE(u);
+static int device_following_set(Unit *u, Set **ret) {
+ Device *d = ASSERT_PTR(DEVICE(u));
_cleanup_set_free_ Set *set = NULL;
int r;
- assert(d);
- assert(_set);
+ assert(ret);
if (LIST_JUST_US(same_sysfs, d)) {
- *_set = NULL;
+ *ret = NULL;
return 0;
}
return r;
}
- *_set = TAKE_PTR(set);
+ *ret = TAKE_PTR(set);
return 1;
}
}
static int make_uid_symlinks(uid_t uid, const char *name, bool b) {
-
char path1[STRLEN("/run/systemd/dynamic-uid/direct:") + DECIMAL_STR_MAX(uid_t) + 1];
const char *path2;
int r = 0, k;
int dynamic_creds_make(Manager *m, const char *user, const char *group, DynamicCreds **ret) {
_cleanup_(dynamic_creds_unrefp) DynamicCreds *creds = NULL;
- bool acquired = false;
int r;
assert(m);
r = dynamic_user_acquire(m, user, &creds->user);
if (r < 0)
return r;
-
- acquired = true;
}
- if (creds->user && (!group || streq_ptr(user, group)))
- creds->group = dynamic_user_ref(creds->user);
- else if (group) {
+ if (group && !streq_ptr(user, group)) {
r = dynamic_user_acquire(m, group, &creds->group);
- if (r < 0) {
- if (acquired)
- creds->user = dynamic_user_unref(creds->user);
+ if (r < 0)
return r;
- }
- }
+ } else
+ creds->group = ASSERT_PTR(dynamic_user_ref(creds->user));
*ret = TAKE_PTR(creds);
* to inherit the $TERM set for PID 1. This is useful for containers so that the $TERM the
* container manager passes to PID 1 ends up all the way in the console login shown. */
- if (path_equal_ptr(tty_path, "/dev/console") && getppid() == 1)
+ if (path_equal(tty_path, "/dev/console") && getppid() == 1)
term = getenv("TERM");
else if (tty_path && in_charset(skip_dev_prefix(tty_path), ALPHANUMERICAL)) {
_cleanup_free_ char *key = NULL;
PidRef *ret) {
char serialization_fd_number[DECIMAL_STR_MAX(int) + 1];
- _cleanup_free_ char *subcgroup_path = NULL, *log_level = NULL, *executor_path = NULL;
+ _cleanup_free_ char *subcgroup_path = NULL, *max_log_levels = NULL, *executor_path = NULL;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
_cleanup_fdset_free_ FDSet *fdset = NULL;
_cleanup_fclose_ FILE *f = NULL;
/* If LogLevelMax= is specified, then let's use the specified log level at the beginning of the
* executor process. To achieve that the specified log level is passed as an argument, rather than
* the one for the manager process. */
- r = log_level_to_string_alloc(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &log_level);
+ r = log_max_levels_to_string(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &max_log_levels);
if (r < 0)
- return log_unit_error_errno(unit, r, "Failed to convert log level to string: %m");
+ return log_unit_error_errno(unit, r, "Failed to convert max log levels to string: %m");
r = fd_get_path(unit->manager->executor_fd, &executor_path);
if (r < 0)
FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
STRV_MAKE(executor_path,
"--deserialize", serialization_fd_number,
- "--log-level", log_level,
+ "--log-level", max_log_levels,
"--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
environ,
cg_unified() > 0 ? subcgroup_path : NULL,
if (!c->user)
return true;
- if (streq(c->user, "root") || streq(c->user, "0"))
+ if (STR_IN_SET(c->user, "root", "0"))
return true;
return false;
return 0;
/* Do not try to merge initrd credentials into foreign credentials directories */
- if (!path_equal_ptr(creds_dir, SYSTEM_CREDENTIALS_DIRECTORY)) {
+ if (!path_equal(creds_dir, SYSTEM_CREDENTIALS_DIRECTORY)) {
log_debug("Not importing initrd credentials, as foreign $CREDENTIALS_DIRECTORY has been set.");
return 0;
}
/* Fragment paths should also be equal as a custom fragment for a specific template instance
* wouldn't necessarily lead to infinite recursion. */
- if (!path_equal_ptr(u->fragment_path, fragment_path))
+ if (!path_equal(u->fragment_path, fragment_path))
return false;
if (!contains_instance_specifier_superset(format))
return -errno;
/* The kernels sets HOME=/ for init. Let's undo this. */
- if (path_equal_ptr(getenv("HOME"), "/"))
+ if (path_equal(getenv("HOME"), "/"))
assert_se(unsetenv("HOME") == 0);
return 0;
[MANAGER_KEXEC] = "kexec",
};
- char log_level[STRLEN("--log-level=") + DECIMAL_STR_MAX(int)],
- timeout[STRLEN("--timeout=") + DECIMAL_STR_MAX(usec_t) + STRLEN("us")],
+ char timeout[STRLEN("--timeout=") + DECIMAL_STR_MAX(usec_t) + STRLEN("us")],
exit_code[STRLEN("--exit-code=") + DECIMAL_STR_MAX(uint8_t)];
_cleanup_strv_free_ char **env_block = NULL;
+ _cleanup_free_ char *max_log_levels = NULL;
usec_t watchdog_timer = 0;
int r;
assert(objective >= 0 && objective < _MANAGER_OBJECTIVE_MAX);
assert(table[objective]);
- xsprintf(log_level, "--log-level=%d", log_get_max_level());
xsprintf(timeout, "--timeout=%" PRI_USEC "us", arg_defaults.timeout_stop_usec);
- const char* command_line[10] = {
+ const char* command_line[11] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
table[objective],
- log_level,
timeout,
/* Note that the last position is a terminator and must contain NULL. */
};
- size_t pos = 4;
+ size_t pos = 3;
assert(command_line[pos-1]);
assert(!command_line[pos]);
+ (void) log_max_levels_to_string(log_get_max_level(), &max_log_levels);
+
+ if (max_log_levels) {
+ command_line[pos++] = "--log-level";
+ command_line[pos++] = max_log_levels;
+ }
+
switch (log_get_target()) {
case LOG_TARGET_KMSG:
}
static void mount_init(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- assert(m);
- assert(u);
assert(u->load_state == UNIT_STUB);
m->timeout_usec = u->manager->defaults.timeout_start_usec;
}
static void mount_done(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
m->where = mfree(m->where);
MountParameters *p;
int r, q, w;
+ assert(m);
+
p = &m->parameters_proc_self_mountinfo;
r = free_and_strdup(&p->what, what);
}
static bool mount_is_extrinsic(Unit *u) {
+ Mount *m = ASSERT_PTR(MOUNT(u));
MountParameters *p;
- Mount *m = MOUNT(u);
- assert(m);
/* Returns true for all units that are "magic" and should be excluded from the usual
* start-up and shutdown dependencies. We call them "extrinsic" here, as they are generally
}
static int mount_add_extras(Mount *m) {
- Unit *u = UNIT(m);
+ Unit *u = UNIT(ASSERT_PTR(m));
int r;
- assert(m);
-
/* Note: this call might be called after we already have been loaded once (and even when it has already been
* activated), in case data from /proc/self/mountinfo has changed. This means all code here needs to be ready
* to run with an already set up unit. */
}
static void mount_load_root_mount(Unit *u) {
- assert(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
if (!unit_has_name(u, SPECIAL_ROOT_MOUNT))
return;
u->default_dependencies = false;
/* The stdio/kmsg bridge socket is on /, in order to avoid a dep loop, don't use kmsg logging for -.mount */
- MOUNT(u)->exec_context.std_output = EXEC_OUTPUT_NULL;
- MOUNT(u)->exec_context.std_input = EXEC_INPUT_NULL;
+ m->exec_context.std_output = EXEC_OUTPUT_NULL;
+ m->exec_context.std_input = EXEC_INPUT_NULL;
if (!u->description)
u->description = strdup("Root Mount");
}
static int mount_load(Unit *u) {
- Mount *m = MOUNT(u);
- int r, q = 0;
+ Mount *m = ASSERT_PTR(MOUNT(u));
+ int r;
- assert(m);
- assert(u);
assert(u->load_state == UNIT_STUB);
mount_load_root_mount(u);
- bool fragment_optional = m->from_proc_self_mountinfo || u->perpetual;
- r = unit_load_fragment_and_dropin(u, !fragment_optional);
+ bool from_kernel = m->from_proc_self_mountinfo || u->perpetual;
+
+ r = unit_load_fragment_and_dropin(u, /* fragment_required = */ !from_kernel);
/* Add in some extras. Note we do this in all cases (even if we failed to load the unit) when announced by the
* kernel, because we need some things to be set up no matter what when the kernel establishes a mount and thus
* we need to update the state in our unit to track it. After all, consider that we don't allow changing the
* 'slice' field for a unit once it is active. */
- if (u->load_state == UNIT_LOADED || m->from_proc_self_mountinfo || u->perpetual)
- q = mount_add_extras(m);
+ if (u->load_state == UNIT_LOADED || from_kernel)
+ RET_GATHER(r, mount_add_extras(m));
if (r < 0)
return r;
- if (q < 0)
- return q;
+
if (u->load_state != UNIT_LOADED)
return 0;
static void mount_set_state(Mount *m, MountState state) {
MountState old_state;
+
assert(m);
if (m->state != state)
}
static int mount_coldplug(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
assert(m->state == MOUNT_DEAD);
if (m->deserialized_state == m->state)
}
static void mount_catchup(Unit *u) {
- Mount *m = MOUNT(ASSERT_PTR(u));
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
/* Adjust the deserialized state. See comments in mount_process_proc_self_mountinfo(). */
if (m->from_proc_self_mountinfo)
}
static void mount_dump(Unit *u, FILE *f, const char *prefix) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
MountParameters *p;
- assert(m);
assert(f);
p = get_mount_parameters(m);
}
static int mount_spawn(Mount *m, ExecCommand *c, PidRef *ret_pid) {
-
_cleanup_(exec_params_shallow_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
}
static void mount_enter_mounting(Mount *m) {
- int r;
MountParameters *p;
bool source_is_dir = true;
+ int r;
assert(m);
}
static void mount_enter_remounting(Mount *m) {
- int r;
MountParameters *p;
+ int r;
assert(m);
}
static int mount_start(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
-
/* We cannot fulfill this request right now, try again later
* please! */
if (IN_SET(m->state,
}
static int mount_stop(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
/* When we directly call umount() for a path, then the state of the corresponding mount unit may be
* outdated. Let's re-read mountinfo now and update the state. */
}
static int mount_reload(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- assert(m);
assert(m->state == MOUNT_MOUNTED);
mount_enter_remounting(m);
}
static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- assert(m);
assert(f);
assert(fds);
}
static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState mount_active_state(Unit *u) {
- assert(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- return state_translation_table[MOUNT(u)->state];
+ return state_translation_table[m->state];
}
static const char *mount_sub_state_to_string(Unit *u) {
- assert(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
- return mount_state_to_string(MOUNT(u)->state);
+ return mount_state_to_string(m->state);
}
static bool mount_may_gc(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
if (m->from_proc_self_mountinfo)
return false;
}
static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
MountResult f;
- assert(m);
assert(pid >= 0);
if (pid != m->control_pid.pid)
}
static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Mount *m = MOUNT(userdata);
+ Mount *m = ASSERT_PTR(MOUNT(userdata));
- assert(m);
assert(m->timer_event_source == source);
switch (m->state) {
Unit **ret) {
_cleanup_(unit_freep) Unit *u = NULL;
+ Mount *mnt;
int r;
assert(m);
if (r < 0)
return r;
+ mnt = ASSERT_PTR(MOUNT(u));
+
r = free_and_strdup(&u->source_path, "/proc/self/mountinfo");
if (r < 0)
return r;
- r = free_and_strdup(&MOUNT(u)->where, where);
+ r = free_and_strdup(&mnt->where, where);
if (r < 0)
return r;
- r = update_parameters_proc_self_mountinfo(MOUNT(u), what, options, fstype);
+ r = update_parameters_proc_self_mountinfo(mnt, what, options, fstype);
if (r < 0)
return r;
/* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the
* time we load the unit file for it (and thus add in extra deps right after) we know what source to
* attributes the deps to. */
- MOUNT(u)->from_proc_self_mountinfo = true;
+ mnt->from_proc_self_mountinfo = true;
- r = mount_add_non_exec_dependencies(MOUNT(u));
+ r = mount_add_non_exec_dependencies(mnt);
if (r < 0)
return r;
const char *fstype,
MountProcFlags *ret_flags) {
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
assert(u);
+ assert(where);
assert(ret_flags);
- if (!MOUNT(u)->where) {
- MOUNT(u)->where = strdup(where);
- if (!MOUNT(u)->where)
+ if (!m->where) {
+ m->where = strdup(where);
+ if (!m->where)
return -ENOMEM;
}
* for the current unit. Note that the flags field is reset on each iteration of reading
* /proc/self/mountinfo, hence we know for sure anything already set here is from the current
* iteration and thus worthy of taking into account. */
- MountProcFlags flags =
- MOUNT(u)->proc_flags | MOUNT_PROC_IS_MOUNTED;
+ MountProcFlags flags = m->proc_flags | MOUNT_PROC_IS_MOUNTED;
- r = update_parameters_proc_self_mountinfo(MOUNT(u), what, options, fstype);
+ r = update_parameters_proc_self_mountinfo(m, what, options, fstype);
if (r < 0)
return r;
if (r > 0)
* from the serialized state), and need to catch up. Since we know that the MOUNT_MOUNTING state is
* reached when we wait for the mount to appear we hence can assume that if we are in it, we are
* actually seeing it established for the first time. */
- if (!MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->state == MOUNT_MOUNTING)
+ if (!m->from_proc_self_mountinfo || m->state == MOUNT_MOUNTING)
flags |= MOUNT_PROC_JUST_MOUNTED;
- MOUNT(u)->from_proc_self_mountinfo = true;
+ m->from_proc_self_mountinfo = true;
- if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+ if (UNIT_IS_LOAD_ERROR(u->load_state)) {
/* The unit was previously not found or otherwise not loaded. Now that the unit shows up in
* /proc/self/mountinfo we should reconsider it this, hence set it to UNIT_LOADED. */
u->load_state = UNIT_LOADED;
if (FLAGS_SET(flags, MOUNT_PROC_JUST_CHANGED)) {
/* If things changed, then make sure that all deps are regenerated. Let's
* first remove all automatic deps, and then add in the new ones. */
- r = mount_add_non_exec_dependencies(MOUNT(u));
+ r = mount_add_non_exec_dependencies(m);
if (r < 0)
return r;
}
}
static int mount_get_timeout(Unit *u, usec_t *timeout) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
usec_t t;
int r;
- assert(m);
- assert(u);
-
if (!m->timer_event_source)
return 0;
}
static int mount_can_clean(Unit *u, ExecCleanMask *ret) {
- Mount *m = MOUNT(u);
-
- assert(m);
+ Mount *m = ASSERT_PTR(MOUNT(u));
return exec_context_get_clean_mask(&m->exec_context, ret);
}
static int mount_can_start(Unit *u) {
- Mount *m = MOUNT(u);
+ Mount *m = ASSERT_PTR(MOUNT(u));
int r;
- assert(m);
-
r = unit_test_start_limit(u);
if (r < 0) {
mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
static void path_spec_mkdir(PathSpec *s, mode_t mode) {
int r;
+ assert(s);
+
if (IN_SET(s->type, PATH_EXISTS, PATH_EXISTS_GLOB))
return;
static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
const char *type;
+ assert(s);
+ assert(f);
+ assert(prefix);
+
assert_se(type = path_type_to_string(s->type));
fprintf(f, "%s%s: %s\n", prefix, type, s->path);
}
}
static void path_init(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(u);
assert(u->load_state == UNIT_STUB);
p->directory_mode = 0755;
}
static void path_done(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
+ Path *p = ASSERT_PTR(PATH(u));
p->trigger_notify_event_source = sd_event_source_disable_unref(p->trigger_notify_event_source);
path_free_specs(p);
}
static int path_load(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin(u, true);
}
static void path_dump(Unit *u, FILE *f, const char *prefix) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
Unit *trigger;
- assert(p);
assert(f);
+ assert(prefix);
trigger = UNIT_TRIGGER(u);
static void path_set_state(Path *p, PathState state) {
PathState old_state;
+
assert(p);
if (p->state != state)
static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify);
static int path_coldplug(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(p);
assert(p->state == PATH_DEAD);
if (p->deserialized_state != p->state) {
}
static int path_start(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(p);
assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED));
r = unit_test_trigger_loaded(u);
}
static int path_stop(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(p);
assert(IN_SET(p->state, PATH_WAITING, PATH_RUNNING));
path_enter_dead(p, PATH_SUCCESS);
}
static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(u);
assert(f);
assert(fds);
}
static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState path_active_state(Unit *u) {
- assert(u);
+ Path *p = ASSERT_PTR(PATH(u));
- return state_translation_table[PATH(u)->state];
+ return state_translation_table[p->state];
}
static const char *path_sub_state_to_string(Unit *u) {
- assert(u);
+ Path *p = ASSERT_PTR(PATH(u));
- return path_state_to_string(PATH(u)->state);
+ return path_state_to_string(p->state);
}
static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- PathSpec *s = userdata, *found = NULL;
- Path *p;
+ PathSpec *s = ASSERT_PTR(userdata), *found = NULL;
+ Path *p = ASSERT_PTR(PATH(s->unit));
int changed;
- assert(s);
- assert(s->unit);
assert(fd >= 0);
- p = PATH(s->unit);
-
if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
return 0;
}
static void path_trigger_notify_impl(Unit *u, Unit *other, bool on_defer) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(u);
assert(other);
/* Invoked whenever the unit we trigger changes state or gains or loses a job */
}
static void path_reset_failed(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
+ Path *p = ASSERT_PTR(PATH(u));
if (p->state == PATH_FAILED)
path_set_state(p, PATH_DEAD);
}
static int path_can_start(Unit *u) {
- Path *p = PATH(u);
+ Path *p = ASSERT_PTR(PATH(u));
int r;
- assert(p);
-
r = unit_test_start_limit(u);
if (r < 0) {
path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
}
static int activation_details_path_append_env(ActivationDetails *details, char ***strv) {
- ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
+ ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
char *s;
int r;
- assert(details);
assert(strv);
- assert(p);
if (isempty(p->trigger_path_filename))
return 0;
}
static int activation_details_path_append_pair(ActivationDetails *details, char ***strv) {
- ActivationDetailsPath *p = ACTIVATION_DETAILS_PATH(details);
+ ActivationDetailsPath *p = ASSERT_PTR(ACTIVATION_DETAILS_PATH(details));
int r;
- assert(details);
assert(strv);
- assert(p);
if (isempty(p->trigger_path_filename))
return 0;
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static void scope_init(Unit *u) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- assert(u);
assert(u->load_state == UNIT_STUB);
s->runtime_max_usec = USEC_INFINITY;
}
static void scope_done(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
s->controller = mfree(s->controller);
s->controller_track = sd_bus_track_unref(s->controller_track);
static void scope_set_state(Scope *s, ScopeState state) {
ScopeState old_state;
+
assert(s);
if (s->state != state)
}
static int scope_load(Unit *u) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
int r;
- assert(s);
assert(u->load_state == UNIT_STUB);
if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
}
static int scope_coldplug(Unit *u) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
int r;
- assert(s);
assert(s->state == SCOPE_DEAD);
if (s->deserialized_state == s->state)
}
static void scope_dump(Unit *u, FILE *f, const char *prefix) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- assert(s);
assert(f);
+ assert(prefix);
fprintf(f,
"%sScope State: %s\n"
prefix, FORMAT_TIMESPAN(s->runtime_rand_extra_usec, USEC_PER_SEC),
prefix, oom_policy_to_string(s->oom_policy));
- cgroup_context_dump(UNIT(s), f, prefix);
+ cgroup_context_dump(u, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
}
}
static int scope_enter_start_chown(Scope *s) {
+ Unit *u = UNIT(ASSERT_PTR(s));
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- Unit *u = UNIT(s);
int r;
- assert(s);
assert(s->user);
if (!s->cgroup_runtime)
}
static int scope_enter_running(Scope *s) {
- Unit *u = UNIT(s);
+ Unit *u = UNIT(ASSERT_PTR(s));
int r;
- assert(s);
-
(void) bus_scope_track_controller(s);
r = unit_acquire_invocation_id(u);
}
static int scope_start(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (unit_has_name(u, SPECIAL_INIT_SCOPE))
return -EPERM;
}
static int scope_stop(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
return 0;
}
static void scope_reset_failed(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (s->state == SCOPE_FAILED)
scope_set_state(s, SCOPE_DEAD);
}
static int scope_get_timeout(Unit *u, usec_t *timeout) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
usec_t t;
int r;
}
static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
PidRef *pid;
- assert(s);
assert(f);
assert(fds);
}
static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
int r;
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static void scope_notify_cgroup_empty_event(Unit *u) {
- Scope *s = SCOPE(u);
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
log_unit_debug(u, "cgroup is empty");
}
static void scope_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
- Scope *s = SCOPE(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (managed_oom)
log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
}
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Scope *s = SCOPE(u);
-
- assert(s);
+ Scope *s = ASSERT_PTR(SCOPE(u));
if (s->state == SCOPE_START_CHOWN) {
if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
}
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Scope *s = SCOPE(userdata);
+ Scope *s = ASSERT_PTR(SCOPE(userdata));
- assert(s);
assert(s->timer_event_source == source);
switch (s->state) {
}
static UnitActiveState scope_active_state(Unit *u) {
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- return state_translation_table[SCOPE(u)->state];
+ return state_translation_table[s->state];
}
static const char *scope_sub_state_to_string(Unit *u) {
- assert(u);
+ Scope *s = ASSERT_PTR(SCOPE(u));
- return scope_state_to_string(SCOPE(u)->state);
+ return scope_state_to_string(s->state);
}
static void scope_enumerate_perpetual(Manager *m) {
}
static void service_unwatch_pid_file(Service *s) {
+ assert(s);
+
if (!s->pid_file_pathspec)
return;
}
static void service_done(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
open_file_free_many(&s->open_files);
}
static int service_load(Unit *u) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
r = unit_load_fragment_and_dropin(u, true);
}
static void service_dump(Unit *u, FILE *f, const char *prefix) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
const char *prefix2;
- assert(s);
-
prefix = strempty(prefix);
prefix2 = strjoina(prefix, "\t");
static bool service_good(Service *s) {
int main_pid_ok;
+
assert(s);
if (s->type == SERVICE_DBUS && !s->bus_name_good)
static void service_enter_start_post(Service *s) {
int r;
+
assert(s);
service_unwatch_control_pid(s);
}
static int service_stop(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
/* Don't create restart jobs from manual stops. */
s->forbid_restart = true;
}
static int service_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
}
static bool service_can_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
return s->exec_command[SERVICE_EXEC_RELOAD] ||
s->type == SERVICE_NOTIFY_RELOAD;
}
static int service_serialize_exec_command(Unit *u, FILE *f, const ExecCommand *command) {
+ Service *s = ASSERT_PTR(SERVICE(u));
_cleanup_free_ char *args = NULL, *p = NULL;
- Service *s = SERVICE(u);
const char *type, *key;
ServiceExecCommand id;
size_t length = 0;
unsigned idx;
- assert(s);
assert(f);
if (!command)
}
static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(u);
assert(f);
assert(fds);
const char *key,
const char *value) {
- Service *s = SERVICE(u);
- int r;
- unsigned idx = 0, i;
- bool control, found = false, last = false;
- ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID;
+ Service *s = ASSERT_PTR(SERVICE(u));
ExecCommand *command = NULL;
+ ServiceExecCommand id = _SERVICE_EXEC_COMMAND_INVALID;
_cleanup_free_ char *path = NULL;
_cleanup_strv_free_ char **argv = NULL;
+ unsigned idx = 0, i;
+ bool control, found = false, last = false;
+ int r;
enum ExecCommandState {
STATE_EXEC_COMMAND_TYPE,
_STATE_EXEC_COMMAND_INVALID = -EINVAL,
} state;
- assert(s);
assert(key);
assert(value);
}
static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState service_active_state(Unit *u) {
+ Service *s = ASSERT_PTR(SERVICE(u));
const UnitActiveState *table;
- assert(u);
-
- table = SERVICE(u)->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
+ table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
- return table[SERVICE(u)->state];
+ return table[s->state];
}
static const char *service_sub_state_to_string(Unit *u) {
}
static bool service_may_gc(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
/* Never clean up services that still have a process around, even if the service is formally dead. Note that
* unit_may_gc() already checked our cgroup for us, we just check our two additional PIDs, too, in case they
static int service_retry_pid_file(Service *s) {
int r;
+ assert(s);
assert(s->pid_file);
assert(IN_SET(s->state, SERVICE_START, SERVICE_START_POST));
static int service_watch_pid_file(Service *s) {
int r;
+ assert(s);
+
log_unit_debug(UNIT(s), "Setting watch for PID file %s", s->pid_file_pathspec->path);
r = path_spec_watch(s->pid_file_pathspec, service_dispatch_inotify_io);
static int service_demand_pid_file(Service *s) {
_cleanup_free_ PathSpec *ps = NULL;
+ assert(s);
assert(s->pid_file);
assert(!s->pid_file_pathspec);
static int service_dispatch_inotify_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
PathSpec *p = ASSERT_PTR(userdata);
- Service *s;
-
- s = SERVICE(p->unit);
+ Service *s = ASSERT_PTR(SERVICE(p->unit));
- assert(s);
assert(fd >= 0);
assert(IN_SET(s->state, SERVICE_START, SERVICE_START_POST));
assert(s->pid_file_pathspec);
}
static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
- Service *s = SERVICE(userdata);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(userdata));
log_unit_debug(UNIT(s), "got exec-fd event");
}
static void service_notify_cgroup_empty_event(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
log_unit_debug(u, "Control group is empty.");
}
static void service_notify_cgroup_oom_event(Unit *u, bool managed_oom) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
if (managed_oom)
log_unit_debug(u, "Process(es) of control group were killed by systemd-oomd.");
}
static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
+ Service *s = ASSERT_PTR(SERVICE(u));
bool notify_dbus = true;
- Service *s = SERVICE(u);
ServiceResult f;
ExitClean clean_mode;
int r;
- assert(s);
assert(pid >= 0);
/* Oneshot services and non-SERVICE_EXEC_START commands should not be
}
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Service *s = SERVICE(userdata);
+ Service *s = ASSERT_PTR(SERVICE(userdata));
- assert(s);
assert(source == s->timer_event_source);
switch (s->state) {
}
static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) {
- Service *s = SERVICE(userdata);
+ Service *s = ASSERT_PTR(SERVICE(userdata));
usec_t watchdog_usec;
- assert(s);
assert(source == s->watchdog_event_source);
watchdog_usec = service_get_watchdog_usec(s);
}
static void service_force_watchdog(Service *s) {
+ assert(s);
+
if (!UNIT(s)->manager->service_watchdogs)
return;
}
static int service_get_timeout(Unit *u, usec_t *timeout) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
uint64_t t;
int r;
+ assert(timeout);
+
if (!s->timer_event_source)
return 0;
}
static usec_t service_get_timeout_start_usec(Unit *u) {
- Service *s = SERVICE(ASSERT_PTR(u));
+ Service *s = ASSERT_PTR(SERVICE(u));
return s->timeout_start_usec;
}
}
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
+ Service *s = ASSERT_PTR(SERVICE(userdata));
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
const sd_bus_error *e;
- Unit *u = ASSERT_PTR(userdata);
uint32_t pid;
- Service *s;
int r;
assert(reply);
- s = SERVICE(u);
s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
if (!s->bus_name || !pick_up_pid_from_bus_name(s))
return 1;
}
- log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid);
+ log_unit_debug(UNIT(s), "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid);
(void) service_set_main_pidref(s, &pidref);
(void) unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
}
static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
-
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(s);
-
if (new_owner)
log_unit_debug(u, "D-Bus name %s now owned by %s", s->bus_name, new_owner);
else
assert(s);
assert(fd >= 0);
+ assert(sock);
/* This is called by the socket code when instantiating a new service for a stream socket and the socket needs
* to be configured. We take ownership of the passed fd on success. */
return r;
}
- r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false, UNIT_DEPENDENCY_IMPLICIT);
+ r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_TRIGGERED_BY, UNIT(sock), false, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
- return r;
+ return log_unit_debug_errno(UNIT(s), r,
+ "Failed to add After=/TriggeredBy= dependencies on socket unit: %m");
s->socket_fd = fd;
- s->socket_peer = socket_peer_ref(peer);
+ s->socket_peer = peer;
s->socket_fd_selinux_context_net = selinux_context_net;
unit_ref_set(&s->accept_socket, UNIT(s), UNIT(sock));
}
static void service_reset_failed(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
if (s->state == SERVICE_FAILED)
service_set_state(s, service_determine_dead_state(s));
}
static bool service_needs_console(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
/* We provide our own implementation of this here, instead of relying of the generic implementation
* unit_needs_console() provides, since we want to return false if we are in SERVICE_EXITED state. */
}
static int service_exit_status(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
if (s->main_exec_status.pid <= 0 ||
!dual_timestamp_is_set(&s->main_exec_status.exit_timestamp))
}
static const char* service_status_text(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
+ Service *s = ASSERT_PTR(SERVICE(u));
return s->status_text;
}
static int service_clean(Unit *u, ExecCleanMask mask) {
+ Service *s = ASSERT_PTR(SERVICE(u));
_cleanup_strv_free_ char **l = NULL;
bool may_clean_fdstore = false;
- Service *s = SERVICE(u);
int r;
- assert(s);
assert(mask != 0);
if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_DEAD_RESOURCES_PINNED))
}
static int service_can_clean(Unit *u, ExecCleanMask *ret) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
ExecCleanMask mask = 0;
int r;
- assert(s);
assert(ret);
r = exec_context_get_clean_mask(&s->exec_context, &mask);
return 0;
}
-static const char *service_finished_job(Unit *u, JobType t, JobResult result) {
+static const char* service_finished_job(Unit *u, JobType t, JobResult result) {
+ Service *s = ASSERT_PTR(SERVICE(u));
+
if (t == JOB_START &&
result == JOB_DONE &&
- SERVICE(u)->type == SERVICE_ONESHOT)
+ s->type == SERVICE_ONESHOT)
return "Finished %s.";
/* Fall back to generic */
}
static int service_can_start(Unit *u) {
- Service *s = SERVICE(u);
+ Service *s = ASSERT_PTR(SERVICE(u));
int r;
- assert(s);
-
/* Make sure we don't enter a busy loop of some kind. */
r = unit_test_start_limit(u);
if (r < 0) {
}
static void service_release_resources(Unit *u) {
- Service *s = SERVICE(ASSERT_PTR(u));
+ Service *s = ASSERT_PTR(SERVICE(u));
/* Invoked by the unit state engine, whenever it realizes that unit is dead and there's no job
* anymore for it, and it hence is a good idea to release resources */
/* Returns the SELinux label used for execution of the main service binary */
- if (s->exec_context.selinux_context) { /* Prefer the explicitly configured label if there is one */
- char *con = strdup(s->exec_context.selinux_context);
- if (!con)
- return -ENOMEM;
-
- *ret = con;
- return 0;
- }
+ if (s->exec_context.selinux_context)
+ /* Prefer the explicitly configured label if there is one */
+ return strdup_to(ret, s->exec_context.selinux_context);
if (s->exec_context.root_image ||
s->exec_context.n_extension_images > 0 ||
static void slice_set_state(Slice *t, SliceState state) {
SliceState old_state;
+
assert(t);
if (t->state != state)
}
static int slice_add_parent_slice(Slice *s) {
- Unit *u = UNIT(s);
+ Unit *u = UNIT(ASSERT_PTR(s));
_cleanup_free_ char *a = NULL;
int r;
- assert(s);
-
if (UNIT_GET_SLICE(u))
return 0;
}
static int slice_load(Unit *u) {
- Slice *s = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
int r;
- assert(s);
assert(u->load_state == UNIT_STUB);
r = slice_load_root_slice(u);
}
static int slice_coldplug(Unit *u) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(t);
- assert(t->state == SLICE_DEAD);
+ assert(s->state == SLICE_DEAD);
- if (t->deserialized_state != t->state)
- slice_set_state(t, t->deserialized_state);
+ if (s->deserialized_state != s->state)
+ slice_set_state(s, s->deserialized_state);
return 0;
}
static void slice_dump(Unit *u, FILE *f, const char *prefix) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(t);
+ assert(s);
assert(f);
+ assert(prefix);
fprintf(f,
"%sSlice State: %s\n",
- prefix, slice_state_to_string(t->state));
+ prefix, slice_state_to_string(s->state));
- cgroup_context_dump(UNIT(t), f, prefix);
+ cgroup_context_dump(u, f, prefix);
}
static int slice_start(Unit *u) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
int r;
- assert(t);
- assert(t->state == SLICE_DEAD);
+ assert(s->state == SLICE_DEAD);
r = unit_acquire_invocation_id(u);
if (r < 0)
(void) unit_realize_cgroup(u);
(void) unit_reset_accounting(u);
- slice_set_state(t, SLICE_ACTIVE);
+ slice_set_state(s, SLICE_ACTIVE);
return 1;
}
static int slice_stop(Unit *u) {
- Slice *t = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(t);
- assert(t->state == SLICE_ACTIVE);
+ assert(s->state == SLICE_ACTIVE);
/* We do not need to destroy the cgroup explicitly,
* unit_notify() will do that for us anyway. */
- slice_set_state(t, SLICE_DEAD);
+ slice_set_state(s, SLICE_DEAD);
return 1;
}
static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
- Slice *s = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(s);
assert(f);
assert(fds);
}
static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Slice *s = SLICE(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- assert(u);
assert(key);
assert(value);
assert(fds);
state = slice_state_from_string(value);
if (state < 0)
- log_debug("Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state: %s", value);
else
s->deserialized_state = state;
} else
- log_debug("Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
static UnitActiveState slice_active_state(Unit *u) {
- assert(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- return state_translation_table[SLICE(u)->state];
+ return state_translation_table[s->state];
}
static const char *slice_sub_state_to_string(Unit *u) {
- assert(u);
+ Slice *s = ASSERT_PTR(SLICE(u));
- return slice_state_to_string(SLICE(u)->state);
+ return slice_state_to_string(s->state);
}
static int slice_make_perpetual(Manager *m, const char *name, Unit **ret) {
}
static void socket_done(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
SocketPeer *p;
- assert(s);
-
socket_free_ports(s);
while ((p = set_steal_first(s->peers_by_address)))
static int socket_add_default_dependencies(Socket *s) {
int r;
+
assert(s);
if (!UNIT(s)->default_dependencies)
static bool socket_has_exec(Socket *s) {
unsigned i;
+
assert(s);
for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++)
}
static int socket_add_extras(Socket *s) {
- Unit *u = UNIT(s);
+ Unit *u = UNIT(ASSERT_PTR(s));
int r;
- assert(s);
-
/* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit
* in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept()
* ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly
DEFINE_PRIVATE_HASH_OPS(peer_address_hash_ops, SocketPeer, peer_address_hash_func, peer_address_compare_func);
static int socket_load(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin(u, true);
}, *i;
int r;
- assert(fd >= 0);
assert(s);
+ assert(fd >= 0);
assert(ret);
if (getpeername(fd, &key.peer.sa, &key.peer_salen) < 0)
}
static void socket_dump(Unit *u, FILE *f, const char *prefix) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
const char *prefix2, *str;
- assert(s);
assert(f);
prefix = strempty(prefix);
static int usbffs_write_descs(int fd, Service *s) {
int r;
+ assert(fd >= 0);
+ assert(s);
+
if (!s->usb_function_descriptors || !s->usb_function_strings)
return -EINVAL;
}
int socket_load_service_unit(Socket *s, int cfd, Unit **ret) {
+ int r;
+
/* Figure out what the unit that will be used to handle the connections on the socket looks like.
*
* If cfd < 0, then we don't have a connection yet. In case of Accept=yes sockets, use a fake
* instance name.
*/
+ assert(s);
+ assert(ret);
+
if (UNIT_ISSET(s->service)) {
*ret = UNIT_DEREF(s->service);
return 0;
/* Build the instance name and load the unit */
_cleanup_free_ char *prefix = NULL, *instance = NULL, *name = NULL;
- int r;
r = unit_name_to_prefix(UNIT(s)->id, &prefix);
if (r < 0)
static void socket_set_state(Socket *s, SocketState state) {
SocketState old_state;
+
assert(s);
if (s->state != state)
}
static int socket_coldplug(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(s);
assert(s->state == SOCKET_DEAD);
if (s->deserialized_state == s->state)
}
static int socket_spawn(Socket *s, ExecCommand *c, PidRef *ret_pid) {
-
_cleanup_(exec_params_shallow_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
static void socket_enter_stop_post(Socket *s, SocketResult f) {
int r;
+
assert(s);
if (s->result == SOCKET_SUCCESS)
static void socket_enter_stop_pre(Socket *s, SocketResult f) {
int r;
+
assert(s);
if (s->result == SOCKET_SUCCESS)
static void socket_enter_listening(Socket *s) {
int r;
+
assert(s);
if (!s->accept && s->flush_pending) {
static void socket_enter_start_post(Socket *s) {
int r;
+
assert(s);
socket_unwatch_control_pid(s);
static void socket_enter_start_pre(Socket *s) {
int r;
+
assert(s);
socket_unwatch_control_pid(s);
/* Note that this call takes possession of the connection fd passed. It either has to assign it
* somewhere or close it. */
_cleanup_close_ int cfd = cfd_in;
-
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
if (!pending) {
if (!UNIT_ISSET(s->service)) {
- r = log_unit_warning_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT),
- "Service to activate vanished, refusing activation.");
+ log_unit_warning(UNIT(s),
+ "Service to activate vanished, refusing activation.");
goto fail;
}
}
r = socket_load_service_unit(s, cfd, &service);
- if (r < 0) {
- if (ERRNO_IS_DISCONNECT(r))
- return;
-
- log_unit_warning_errno(UNIT(s), r, "Failed to load connection service unit: %m");
+ if (ERRNO_IS_NEG_DISCONNECT(r))
+ return;
+ if (r < 0 || UNIT_IS_LOAD_ERROR(service->load_state)) {
+ log_unit_warning_errno(UNIT(s), r < 0 ? r : service->load_error,
+ "Failed to load connection service unit: %m");
goto fail;
}
-
- r = unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, service,
- false, UNIT_DEPENDENCY_IMPLICIT);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to add Before=/Triggers= dependencies on connection unit: %m");
+ if (service->load_state == UNIT_MASKED) {
+ log_unit_warning(UNIT(s), "Connection service unit is masked, refusing.");
goto fail;
}
goto fail;
}
- TAKE_FD(cfd); /* We passed ownership of the fd to the service now. Forget it here. */
+ /* We passed ownership of the fd and socket peer to the service now. */
+ TAKE_FD(cfd);
+ TAKE_PTR(p);
+
s->n_connections++;
r = manager_add_job(UNIT(s)->manager, JOB_START, service, JOB_REPLACE, NULL, &error, NULL);
return;
queue_error:
- if (ERRNO_IS_RESOURCE(r))
- log_unit_warning(UNIT(s), "Failed to queue service startup job: %s",
- bus_error_message(&error, r));
- else
- log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
- cfd >= 0 ? "template" : "non-template",
- bus_error_message(&error, r));
+ log_unit_warning_errno(UNIT(s), r, "Failed to queue service startup job%s: %s",
+ cfd >= 0 && !ERRNO_IS_RESOURCE(r) ? " (Maybe the service is missing or is a template unit?)" : "",
+ bus_error_message(&error, r));
fail:
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
}
static int socket_start(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(s);
-
/* We cannot fulfill this request right now, try again later
* please! */
if (IN_SET(s->state,
}
static int socket_stop(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
+ Socket *s = ASSERT_PTR(SOCKET(u));
/* Already on it */
if (IN_SET(s->state,
}
static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(u);
assert(f);
assert(fds);
}
static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(u);
assert(key);
assert(value);
}
static void socket_distribute_fds(Unit *u, FDSet *fds) {
- Socket *s = SOCKET(u);
-
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
LIST_FOREACH(port, p, s->ports) {
int fd;
}
static UnitActiveState socket_active_state(Unit *u) {
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
- return state_translation_table[SOCKET(u)->state];
+ return state_translation_table[s->state];
}
static const char *socket_sub_state_to_string(Unit *u) {
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
- return socket_state_to_string(SOCKET(u)->state);
+ return socket_state_to_string(s->state);
}
int socket_port_to_address(const SocketPort *p, char **ret) {
}
const char* socket_port_type_to_string(SocketPort *p) {
-
assert(p);
switch (p->type) {
}
static bool socket_may_gc(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
return s->n_connections == 0;
}
}
static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
SocketResult f;
- assert(s);
assert(pid >= 0);
if (pid != s->control_pid.pid)
}
static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Socket *s = SOCKET(userdata);
+ Socket *s = ASSERT_PTR(SOCKET(userdata));
- assert(s);
assert(s->timer_event_source == source);
switch (s->state) {
return 0;
}
-int socket_collect_fds(Socket *s, int **fds) {
- size_t k = 0, n = 0;
- int *rfds;
+int socket_collect_fds(Socket *s, int **ret) {
+ size_t n = 0, k = 0;
assert(s);
- assert(fds);
+ assert(ret);
/* Called from the service code for requesting our fds */
n += p->n_auxiliary_fds;
}
- if (n <= 0) {
- *fds = NULL;
+ if (n == 0) {
+ *ret = NULL;
return 0;
}
- rfds = new(int, n);
- if (!rfds)
+ int *fds = new(int, n);
+ if (!fds)
return -ENOMEM;
LIST_FOREACH(port, p, s->ports) {
if (p->fd >= 0)
- rfds[k++] = p->fd;
- for (size_t i = 0; i < p->n_auxiliary_fds; ++i)
- rfds[k++] = p->auxiliary_fds[i];
+ fds[k++] = p->fd;
+ FOREACH_ARRAY(i, p->auxiliary_fds, p->n_auxiliary_fds)
+ fds[k++] = *i;
}
assert(k == n);
- *fds = rfds;
+ *ret = fds;
return (int) n;
}
}
static void socket_trigger_notify(Unit *u, Unit *other) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
- assert(u);
assert(other);
/* Filter out invocations with bogus state */
}
static int socket_get_timeout(Unit *u, usec_t *timeout) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
usec_t t;
int r;
}
static int socket_clean(Unit *u, ExecCleanMask mask) {
+ Socket *s = ASSERT_PTR(SOCKET(u));
_cleanup_strv_free_ char **l = NULL;
- Socket *s = SOCKET(u);
int r;
- assert(s);
assert(mask != 0);
if (s->state != SOCKET_DEAD)
}
static int socket_can_clean(Unit *u, ExecCleanMask *ret) {
- Socket *s = SOCKET(u);
-
- assert(s);
+ Socket *s = ASSERT_PTR(SOCKET(u));
return exec_context_get_clean_mask(&s->exec_context, ret);
}
static int socket_can_start(Unit *u) {
- Socket *s = SOCKET(u);
+ Socket *s = ASSERT_PTR(SOCKET(u));
int r;
- assert(s);
-
r = unit_test_start_limit(u);
if (r < 0) {
socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
DEFINE_TRIVIAL_CLEANUP_FUNC(SocketPeer*, socket_peer_unref);
/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds);
+int socket_collect_fds(Socket *s, int **ret);
/* Called from the service code when a per-connection service ended */
void socket_connection_unref(Socket *s);
}
static bool swap_may_gc(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
if (s->from_proc_swaps)
return false;
}
static void swap_init(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
+ assert(u->load_state == UNIT_STUB);
s->timeout_usec = u->manager->defaults.timeout_start_usec;
}
static void swap_done(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
swap_unset_proc_swaps(s);
swap_set_devnode(s, NULL);
_cleanup_free_ char *e = NULL;
int r;
+ assert(s);
assert(UNIT(s)->load_state == UNIT_LOADED);
r = unit_name_from_path(s->what, ".swap", &e);
}
static int swap_load(Unit *u) {
- Swap *s = SWAP(u);
- int r, q = 0;
+ Swap *s = ASSERT_PTR(SWAP(u));
+ int r;
- assert(s);
assert(u->load_state == UNIT_STUB);
/* Load a .swap file */
- bool fragment_optional = s->from_proc_swaps;
- r = unit_load_fragment_and_dropin(u, !fragment_optional);
+ r = unit_load_fragment_and_dropin(u, /* fragment_required = */ !s->from_proc_swaps);
/* Add in some extras, and do so either when we successfully loaded something or when /proc/swaps is
* already active. */
if (u->load_state == UNIT_LOADED || s->from_proc_swaps)
- q = swap_add_extras(s);
+ RET_GATHER(r, swap_add_extras(s));
if (r < 0)
return r;
- if (q < 0)
- return q;
+
if (u->load_state != UNIT_LOADED)
return 0;
int priority,
bool set_flags) {
+ _cleanup_(unit_freep) Unit *new = NULL;
_cleanup_free_ char *e = NULL;
- bool delete = false;
- Unit *u = NULL;
+ Unit *u;
+ Swap *s;
int r;
- SwapParameters *p;
assert(m);
assert(what);
r = unit_name_from_path(what, ".swap", &e);
if (r < 0)
- return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
+ return log_error_errno(r, "Failed to generate unit name from path: %m");
u = manager_get_unit(m, e);
- if (u &&
- SWAP(u)->from_proc_swaps &&
- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
- return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
- "Swap %s appeared twice with different device paths %s and %s",
- e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
-
- if (!u) {
- delete = true;
+ if (u) {
+ s = ASSERT_PTR(SWAP(u));
+
+ if (s->from_proc_swaps &&
+ !path_equal(s->parameters_proc_swaps.what, what_proc_swaps))
+ return log_unit_error_errno(u, SYNTHETIC_ERRNO(EEXIST),
+ "Swap appeared twice with different device paths %s and %s, refusing.",
+ s->parameters_proc_swaps.what, what_proc_swaps);
+ } else {
+ r = unit_new_for_name(m, sizeof(Swap), e, &new);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to load swap unit '%s': %m", e);
- r = unit_new_for_name(m, sizeof(Swap), e, &u);
- if (r < 0) {
- log_unit_warning_errno(u, r, "Failed to load swap unit: %m");
- goto fail;
- }
+ u = new;
+ s = ASSERT_PTR(SWAP(u));
- SWAP(u)->what = strdup(what);
- if (!SWAP(u)->what) {
- r = log_oom();
- goto fail;
- }
+ s->what = strdup(what);
+ if (!s->what)
+ return log_oom();
unit_add_to_load_queue(u);
- } else
- delete = false;
+ }
- p = &SWAP(u)->parameters_proc_swaps;
+ SwapParameters *p = &s->parameters_proc_swaps;
if (!p->what) {
p->what = strdup(what_proc_swaps);
- if (!p->what) {
- r = log_oom();
- goto fail;
- }
+ if (!p->what)
+ return log_oom();
}
- /* The unit is definitely around now, mark it as loaded if it was previously referenced but could not be
- * loaded. After all we can load it now, from the data in /proc/swaps. */
- if (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR)) {
+ /* The unit is definitely around now, mark it as loaded if it was previously referenced but
+ * could not be loaded. After all we can load it now, from the data in /proc/swaps. */
+ if (UNIT_IS_LOAD_ERROR(u->load_state)) {
u->load_state = UNIT_LOADED;
u->load_error = 0;
}
if (set_flags) {
- SWAP(u)->is_active = true;
- SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
+ s->is_active = true;
+ s->just_activated = !s->from_proc_swaps;
}
- SWAP(u)->from_proc_swaps = true;
+ s->from_proc_swaps = true;
p->priority = priority;
p->priority_set = true;
unit_add_to_dbus_queue(u);
- return 0;
-
-fail:
- if (delete)
- unit_free(u);
+ TAKE_PTR(new);
- return r;
+ return 0;
}
static void swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
}
static int swap_coldplug(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
SwapState new_state = SWAP_DEAD;
int r;
- assert(s);
assert(s->state == SWAP_DEAD);
if (s->deserialized_state != s->state)
}
static void swap_dump(Unit *u, FILE *f, const char *prefix) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
SwapParameters *p;
- assert(s);
assert(f);
if (s->from_proc_swaps)
}
static int swap_spawn(Swap *s, ExecCommand *c, PidRef *ret_pid) {
-
_cleanup_(exec_params_shallow_clear) ExecParameters exec_params = EXEC_PARAMETERS_INIT(
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
}
static int swap_stop(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
switch (s->state) {
}
static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
- assert(s);
assert(f);
assert(fds);
}
static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
- assert(s);
assert(fds);
if (streq(key, "state")) {
}
static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
SwapResult f;
- assert(s);
assert(pid >= 0);
if (pid != s->control_pid.pid)
}
static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Swap *s = SWAP(userdata);
+ Swap *s = ASSERT_PTR(SWAP(userdata));
- assert(s);
assert(s->timer_event_source == source);
switch (s->state) {
return swap_process_proc_swaps(m);
}
-static Unit *swap_following(Unit *u) {
- Swap *s = SWAP(u);
+static Unit* swap_following(Unit *u) {
+ Swap *s = ASSERT_PTR(SWAP(u));
Swap *first = NULL;
- assert(s);
-
/* If the user configured the swap through /etc/fstab or
* a device unit, follow that. */
return UNIT(first);
}
-static int swap_following_set(Unit *u, Set **_set) {
- Swap *s = SWAP(u);
+static int swap_following_set(Unit *u, Set **ret) {
+ Swap *s = ASSERT_PTR(SWAP(u));
_cleanup_set_free_ Set *set = NULL;
int r;
- assert(s);
- assert(_set);
+ assert(ret);
if (LIST_JUST_US(same_devnode, s)) {
- *_set = NULL;
+ *ret = NULL;
return 0;
}
return r;
}
- *_set = TAKE_PTR(set);
+ *ret = TAKE_PTR(set);
return 1;
}
int swap_process_device_remove(Manager *m, sd_device *dev) {
const char *dn;
- int r;
Swap *s;
+ int r;
r = sd_device_get_devname(dev, &dn);
if (r < 0)
return 0;
- while ((s = hashmap_get(m->swaps_by_devnode, dn))) {
- int q;
-
- q = swap_set_devnode(s, NULL);
- if (q < 0)
- r = q;
- }
+ r = 0;
+ while ((s = hashmap_get(m->swaps_by_devnode, dn)))
+ RET_GATHER(r, swap_set_devnode(s, NULL));
return r;
}
static void swap_reset_failed(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
if (s->state == SWAP_FAILED)
swap_set_state(s, SWAP_DEAD);
}
static int swap_get_timeout(Unit *u, usec_t *timeout) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
usec_t t;
int r;
- assert(s);
- assert(u);
-
if (!s->timer_event_source)
return 0;
}
static int swap_clean(Unit *u, ExecCleanMask mask) {
+ Swap *s = ASSERT_PTR(SWAP(u));
_cleanup_strv_free_ char **l = NULL;
- Swap *s = SWAP(u);
int r;
- assert(s);
assert(mask != 0);
if (s->state != SWAP_DEAD)
}
static int swap_can_clean(Unit *u, ExecCleanMask *ret) {
- Swap *s = SWAP(u);
-
- assert(s);
+ Swap *s = ASSERT_PTR(SWAP(u));
return exec_context_get_clean_mask(&s->exec_context, ret);
}
static int swap_can_start(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = ASSERT_PTR(SWAP(u));
int r;
- assert(s);
-
r = unit_test_start_limit(u);
if (r < 0) {
swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
}
static int target_load(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
int r;
- assert(t);
-
r = unit_load_fragment_and_dropin(u, true);
if (r < 0)
return r;
}
static int target_coldplug(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(t);
assert(t->state == TARGET_DEAD);
if (t->deserialized_state != t->state)
}
static void target_dump(Unit *u, FILE *f, const char *prefix) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(t);
assert(f);
+ assert(prefix);
fprintf(f,
"%sTarget State: %s\n",
}
static int target_start(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
int r;
- assert(t);
assert(t->state == TARGET_DEAD);
r = unit_acquire_invocation_id(u);
}
static int target_stop(Unit *u) {
- Target *t = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(t);
assert(t->state == TARGET_ACTIVE);
target_set_state(t, TARGET_DEAD);
}
static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
- Target *s = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(s);
assert(f);
assert(fds);
- (void) serialize_item(f, "state", target_state_to_string(s->state));
+ (void) serialize_item(f, "state", target_state_to_string(t->state));
return 0;
}
static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Target *s = TARGET(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- assert(s);
- assert(u);
assert(key);
assert(value);
assert(fds);
state = target_state_from_string(value);
if (state < 0)
- log_debug("Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state: %s", value);
else
- s->deserialized_state = state;
+ t->deserialized_state = state;
} else
- log_debug("Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
static UnitActiveState target_active_state(Unit *u) {
- assert(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- return state_translation_table[TARGET(u)->state];
+ return state_translation_table[t->state];
}
static const char *target_sub_state_to_string(Unit *u) {
- assert(u);
+ Target *t = ASSERT_PTR(TARGET(u));
- return target_state_to_string(TARGET(u)->state);
+ return target_state_to_string(t->state);
}
const UnitVTable target_vtable = {
static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
static void timer_init(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(u->load_state == UNIT_STUB);
t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
}
static void timer_done(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
+ Timer *t = ASSERT_PTR(TIMER(u));
timer_free_values(t);
}
static int timer_load(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(u);
assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin(u, true);
}
static void timer_dump(Unit *u, FILE *f, const char *prefix) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
Unit *trigger;
+ assert(f);
+ assert(prefix);
+
trigger = UNIT_TRIGGER(u);
fprintf(f,
static void timer_set_state(Timer *t, TimerState state) {
TimerState old_state;
+
assert(t);
if (t->state != state)
static void timer_enter_waiting(Timer *t, bool time_change);
static int timer_coldplug(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(t);
assert(t->state == TIMER_DEAD);
if (t->deserialized_state == t->state)
}
static int timer_start(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(t);
assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
r = unit_test_trigger_loaded(u);
}
static int timer_stop(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(t);
assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
timer_enter_dead(t, TIMER_SUCCESS);
}
static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(f);
assert(fds);
}
static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(key);
assert(value);
assert(fds);
}
static UnitActiveState timer_active_state(Unit *u) {
- assert(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- return state_translation_table[TIMER(u)->state];
+ return state_translation_table[t->state];
}
static const char *timer_sub_state_to_string(Unit *u) {
- assert(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- return timer_state_to_string(TIMER(u)->state);
+ return timer_state_to_string(t->state);
}
static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
- Timer *t = TIMER(userdata);
-
- assert(t);
+ Timer *t = ASSERT_PTR(TIMER(userdata));
if (t->state != TIMER_WAITING)
return 0;
}
static void timer_trigger_notify(Unit *u, Unit *other) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(u);
assert(other);
/* Filter out invocations with bogus state */
}
static void timer_reset_failed(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
+ Timer *t = ASSERT_PTR(TIMER(u));
if (t->state == TIMER_FAILED)
timer_set_state(t, TIMER_DEAD);
}
static void timer_time_change(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
usec_t ts;
- assert(u);
-
if (t->state != TIMER_WAITING)
return;
}
static void timer_timezone_change(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
if (t->state != TIMER_WAITING)
return;
}
static int timer_clean(Unit *u, ExecCleanMask mask) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(t);
assert(mask != 0);
if (t->state != TIMER_DEAD)
}
static int timer_can_clean(Unit *u, ExecCleanMask *ret) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
- assert(t);
assert(ret);
*ret = t->persistent ? EXEC_CLEAN_STATE : 0;
}
static int timer_can_start(Unit *u) {
- Timer *t = TIMER(u);
+ Timer *t = ASSERT_PTR(TIMER(u));
int r;
- assert(t);
-
r = unit_test_start_limit(u);
if (r < 0) {
timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
}
static void activation_details_timer_serialize(ActivationDetails *details, FILE *f) {
- ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
- assert(details);
assert(f);
assert(t);
}
static int activation_details_timer_append_env(ActivationDetails *details, char ***strv) {
- ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
int r;
- assert(details);
assert(strv);
assert(t);
}
static int activation_details_timer_append_pair(ActivationDetails *details, char ***strv) {
- ActivationDetailsTimer *t = ACTIVATION_DETAILS_TIMER(details);
+ ActivationDetailsTimer *t = ASSERT_PTR(ACTIVATION_DETAILS_TIMER(details));
int r;
- assert(details);
assert(strv);
assert(t);
bad_specifier(u, specifier);
- if (crt && crt->cgroup_path) {
- char *n;
-
- n = strdup(crt->cgroup_path);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
- }
+ if (crt && crt->cgroup_path)
+ return strdup_to(ret, crt->cgroup_path);
return unit_default_cgroup_path(u, ret);
}
static int specifier_cgroup_root(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
- char *n;
bad_specifier(u, specifier);
- n = strdup(u->manager->cgroup_root);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, u->manager->cgroup_root);
}
static int specifier_cgroup_slice(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata), *slice;
- char *n;
bad_specifier(u, specifier);
CGroupRuntime *crt = unit_get_cgroup_runtime(slice);
if (crt && crt->cgroup_path)
- n = strdup(crt->cgroup_path);
- else
- return unit_default_cgroup_path(slice, ret);
- } else
- n = strdup(u->manager->cgroup_root);
- if (!n)
- return -ENOMEM;
+ return strdup_to(ret, crt->cgroup_path);
- *ret = n;
- return 0;
+ return unit_default_cgroup_path(slice, ret);
+ }
+
+ return strdup_to(ret, u->manager->cgroup_root);
}
static int specifier_special_directory(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Unit *u = ASSERT_PTR(userdata);
- char *n;
- n = strdup(u->manager->prefix[PTR_TO_UINT(data)]);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, u->manager->prefix[PTR_TO_UINT(data)]);
}
static int specifier_credentials_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
p->runtime_scope = u->manager->runtime_scope;
- r = strdup_or_null(manager_get_confirm_spawn(u->manager), &p->confirm_spawn);
+ r = strdup_to(&p->confirm_spawn, manager_get_confirm_spawn(u->manager));
if (r < 0)
return r;
return t >= 0 && t < _UNIT_LOAD_STATE_MAX && t != UNIT_STUB && t != UNIT_MERGED;
}
+static inline bool UNIT_IS_LOAD_ERROR(UnitLoadState t) {
+ return IN_SET(t, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_ERROR);
+}
+
/* Stores the 'reason' a dependency was created as a bit mask, i.e. due to which configuration source it came to be. We
* use this so that we can selectively flush out parts of dependencies again. Note that the same dependency might be
* created as a result of multiple "reasons", hence the bitmask. */
c = hashmap_get(h, UID_TO_PTR(uid));
if (c) {
-
if (t < c->oldest_mtime) {
- char *n;
-
- n = strdup(de->d_name);
- if (!n)
- return log_oom();
-
- free_and_replace(c->oldest_file, n);
+ r = free_and_strdup_warn(&c->oldest_file, de->d_name);
+ if (r < 0)
+ return r;
c->oldest_mtime = t;
}
-
} else {
_cleanup_(vacuum_candidate_freep) VacuumCandidate *n = NULL;
if (!n)
return log_oom();
- n->oldest_file = strdup(de->d_name);
- if (!n->oldest_file)
- return log_oom();
-
+ r = free_and_strdup_warn(&n->oldest_file, de->d_name);
+ if (r < 0)
+ return r;
n->oldest_mtime = t;
r = hashmap_put(h, UID_TO_PTR(uid), n);
assert(where);
assert(ret_options);
- if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT))) {
- r = strdup_or_null(options, ret_options);
- if (r < 0)
- return r;
-
- return 0;
- }
+ if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT)))
+ return strdup_to(ret_options, options);
log_debug("Mount '%s' is mandatory, ignoring 'noauto', 'nofail', and 'x-systemd.automount' options.",
where);
#include "time-util.h"
#include "user-record.h"
+/* Flags supported by UpdateEx() */
+#define SD_HOMED_UPDATE_OFFLINE (UINT64_C(1) << 0)
+#define SD_HOMED_UPDATE_FLAGS_ALL (SD_HOMED_UPDATE_OFFLINE)
+
+/* Flags supported by CreateHomeEx() */
+#define SD_HOMED_CREATE_FLAGS_ALL (0)
+
/* Put some limits on disk sizes: not less than 5M, not more than 5T */
#define USER_DISK_SIZE_MIN (UINT64_C(5)*1024*1024)
#define USER_DISK_SIZE_MAX (UINT64_C(5)*1024*1024*1024*1024)
static bool arg_ask_password = true;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static const char *arg_host = NULL;
+static bool arg_offline = false;
static const char *arg_identity = NULL;
static JsonVariant *arg_identity_extra = NULL;
static JsonVariant *arg_identity_extra_privileged = NULL;
_cleanup_free_ char *buffer = NULL;
_cleanup_hashmap_free_ Hashmap *blobs = NULL;
const char *username;
+ uint64_t flags = 0;
int r;
if (argc >= 2)
if (arg_and_resize || arg_and_change_password)
log_info("Updating home directory.");
+ if (arg_offline)
+ flags |= SD_HOMED_UPDATE_OFFLINE;
+
for (;;) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append(m, "t", UINT64_C(0));
+ r = sd_bus_message_append(m, "t", flags);
if (r < 0)
return bus_log_create_error(r);
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --no-ask-password Do not ask for system passwords\n"
+ " --offline Don't update record embedded in home directory\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" --identity=PATH Read JSON identity from file\n"
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_NO_ASK_PASSWORD,
+ ARG_OFFLINE,
ARG_REALM,
ARG_EMAIL_ADDRESS,
ARG_DISK_SIZE,
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
+ { "offline", no_argument, NULL, ARG_OFFLINE },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "identity", required_argument, NULL, 'I' },
arg_ask_password = false;
break;
+ case ARG_OFFLINE:
+ arg_offline = true;
+ break;
+
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
#include "bus-polkit.h"
#include "fd-util.h"
#include "format-util.h"
+#include "home-util.h"
#include "homed-bus.h"
#include "homed-home-bus.h"
#include "homed-home.h"
return 1;
}
-int bus_home_method_update_record(
+int bus_home_update_record(
Home *h,
sd_bus_message *message,
UserRecord *hr,
if (r < 0)
return r;
- if (flags != 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Provided flags are unsupported.");
+ if ((flags & ~SD_HOMED_UPDATE_FLAGS_ALL) != 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
r = home_verify_polkit_async(
h,
if (r < 0)
return r;
+ h->current_operation->call_flags = flags;
+
return 1;
}
assert(message);
- r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_REQUIRE_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
+ r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0)
return r;
return r;
}
- return bus_home_method_update_record(h, message, hr, blobs, flags, error);
+ return bus_home_update_record(h, message, hr, blobs, flags, error);
}
int bus_home_method_resize(
if (r == 0)
return 1; /* Will call us back */
- r = home_resize(h, sz, secret, /* automatic= */ false, error);
+ r = home_resize(h, sz, secret, error);
if (r < 0)
return r;
return r;
/* This operation might not be something we can executed immediately, hence queue it */
- fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND);
+ fd = home_create_fifo(h, please_suspend);
if (fd < 0)
return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
}
}
- fd = home_create_fifo(h, please_suspend ? HOME_FIFO_PLEASE_SUSPEND : HOME_FIFO_DONT_SUSPEND);
+ fd = home_create_fifo(h, please_suspend);
if (fd < 0)
return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
return 1;
}
-int bus_home_method_inhibit_suspend(
- sd_bus_message *message,
- void *userdata,
- sd_bus_error *error) {
-
- _cleanup_close_ int fd = -EBADF;
- Home *h = ASSERT_PTR(userdata);
- HomeState state;
- int r;
-
- r = home_verify_polkit_async(
- h,
- message,
- "org.freedesktop.home1.inhibit-suspend",
- h->uid,
- error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* Will call us back */
-
- state = home_get_state(h);
- switch (state) {
- case HOME_ABSENT:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
- case HOME_UNFIXATED:
- case HOME_INACTIVE:
- case HOME_DIRTY:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name);
- case HOME_LOCKED:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
- default:
- if (HOME_STATE_IS_ACTIVE(state))
- break;
-
- return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name);
- }
-
- fd = home_create_fifo(h, HOME_FIFO_INHIBIT_SUSPEND);
- if (fd < 0)
- return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name);
-
- return sd_bus_reply_method_return(message, "h", fd);
-}
-
/* We map a uid_t as uint32_t bus property, let's ensure this is safe. */
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
bus_home_method_ref,
0),
SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0),
- SD_BUS_METHOD_WITH_ARGS("InhibitSuspend",
- SD_BUS_NO_ARGS,
- SD_BUS_RESULT("h", send_fd),
- bus_home_method_inhibit_suspend,
- SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
int bus_home_method_fixate(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_authenticate(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_update(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_home_method_update_record(Home *home, sd_bus_message *message, UserRecord *hr, Hashmap *blobs, uint64_t flags, sd_bus_error *error);
int bus_home_method_resize(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_change_password(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_acquire(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_home_method_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_home_method_inhibit_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error);
+
+int bus_home_update_record(Home *home, sd_bus_message *message, UserRecord *hr, Hashmap *blobs, uint64_t flags, sd_bus_error *error);
extern const BusObjectImplementation home_object;
h->ref_event_source_please_suspend = sd_event_source_disable_unref(h->ref_event_source_please_suspend);
h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend);
- h->inhibit_suspend_event_source = sd_event_source_disable_unref(h->inhibit_suspend_event_source);
h->pending_operations = ordered_set_free(h->pending_operations);
h->pending_event_source = sd_event_source_disable_unref(h->pending_event_source);
static void home_change_finish(Home *h, int ret, UserRecord *hr) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ uint64_t flags;
int r;
assert(h);
+ flags = h->current_operation ? h->current_operation->call_flags : 0;
+
if (ret < 0) {
(void) home_count_bad_authentication(h, ret, /* save= */ true);
}
if (hr) {
- r = home_set_record(h, hr);
- if (r < 0)
- log_warning_errno(r, "Failed to update home record, ignoring: %m");
- else {
+ if (!FLAGS_SET(flags, SD_HOMED_UPDATE_OFFLINE)) {
r = user_record_good_authentication(h->record);
if (r < 0)
log_warning_errno(r, "Failed to increase good authentication counter, ignoring: %m");
+ }
+ r = home_set_record(h, hr);
+ if (r >= 0)
r = home_save_record(h);
- if (r < 0)
- log_warning_errno(r, "Failed to write home record to disk, ignoring: %m");
+ if (r < 0) {
+ if (FLAGS_SET(flags, SD_HOMED_UPDATE_OFFLINE)) {
+ log_error_errno(r, "Failed to update home record and write it to disk: %m");
+ sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Failed to cache changes to home record");
+ goto finish;
+ } else
+ log_warning_errno(r, "Failed to update home record, ignoring: %m");
}
}
_exit(EXIT_FAILURE);
}
+ if (setenv("SYSTEMD_HOMEWORK_UPDATE_OFFLINE", one_zero(FLAGS_SET(flags, SD_HOMED_UPDATE_OFFLINE)), 1) < 0) {
+ log_error_errno(errno, "Failed to set $SYSTEMD_HOMEWORK_UPDATE_OFFLINE: %m");
+ _exit(EXIT_FAILURE);
+ }
+
r = setenv_systemd_exec_pid(true);
if (r < 0)
log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
case HOME_UNFIXATED:
return sd_bus_error_setf(error, BUS_ERROR_HOME_UNFIXATED, "Home %s has not been fixated yet.", h->user_name);
case HOME_ABSENT:
- return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
+ if (!FLAGS_SET(flags, SD_HOMED_UPDATE_OFFLINE))
+ return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name);
+ break; /* offline updates are compatible w/ an absent home area */
case HOME_LOCKED:
return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name);
case HOME_INACTIVE:
int home_resize(Home *h,
uint64_t disk_size,
UserRecord *secret,
- bool automatic,
sd_bus_error *error) {
_cleanup_(user_record_unrefp) UserRecord *c = NULL;
c = TAKE_PTR(signed_c);
}
- r = home_update_internal(h, automatic ? "resize-auto" : "resize", c, secret, NULL, 0, error);
+ r = home_update_internal(h, "resize", c, secret, NULL, 0, error);
if (r < 0)
return r;
if (h->ref_event_source_dont_suspend == s)
h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend);
- if (h->inhibit_suspend_event_source == s)
- h->inhibit_suspend_event_source = sd_event_source_disable_unref(h->inhibit_suspend_event_source);
-
if (home_is_referenced(h))
return 0;
return 0;
}
-int home_create_fifo(Home *h, HomeFifoType type) {
- static const struct {
- const char *suffix;
- const char *description;
- size_t event_source;
- } table[_HOME_FIFO_TYPE_MAX] = {
- [HOME_FIFO_PLEASE_SUSPEND] = {
- .suffix = ".please-suspend",
- .description = "acquire-ref",
- .event_source = offsetof(Home, ref_event_source_please_suspend),
- },
- [HOME_FIFO_DONT_SUSPEND] = {
- .suffix = ".dont-suspend",
- .description = "acquire-ref-dont-suspend",
- .event_source = offsetof(Home, ref_event_source_dont_suspend),
- },
- [HOME_FIFO_INHIBIT_SUSPEND] = {
- .suffix = ".inhibit-suspend",
- .description = "inhibit-suspend",
- .event_source = offsetof(Home, inhibit_suspend_event_source),
- },
- };
-
+int home_create_fifo(Home *h, bool please_suspend) {
_cleanup_close_ int ret_fd = -EBADF;
- sd_event_source **evt;
- const char *fn;
+ sd_event_source **ss;
+ const char *fn, *suffix;
int r;
assert(h);
- assert(type >= 0 && type < _HOME_FIFO_TYPE_MAX);
- evt = (sd_event_source**) ((uint8_t*) h + table[type].event_source);
+ if (please_suspend) {
+ suffix = ".please-suspend";
+ ss = &h->ref_event_source_please_suspend;
+ } else {
+ suffix = ".dont-suspend";
+ ss = &h->ref_event_source_dont_suspend;
+ }
- fn = strjoina("/run/systemd/home/", h->user_name, table[type].suffix);
+ fn = strjoina("/run/systemd/home/", h->user_name, suffix);
- if (!*evt) {
+ if (!*ss) {
_cleanup_close_ int ref_fd = -EBADF;
(void) mkdir("/run/systemd/home/", 0755);
if (ref_fd < 0)
return log_error_errno(errno, "Failed to open FIFO %s for reading: %m", fn);
- r = sd_event_add_io(h->manager->event, evt, ref_fd, 0, on_home_ref_eof, h);
+ r = sd_event_add_io(h->manager->event, ss, ref_fd, 0, on_home_ref_eof, h);
if (r < 0)
return log_error_errno(r, "Failed to allocate reference FIFO event source: %m");
- (void) sd_event_source_set_description(*evt, table[type].description);
+ (void) sd_event_source_set_description(*ss, "acquire-ref");
- r = sd_event_source_set_priority(*evt, SD_EVENT_PRIORITY_IDLE-1);
+ /* We need to notice dropped refs before we process new bus requests (which
+ * might try to obtain new refs) */
+ r = sd_event_source_set_priority(*ss, SD_EVENT_PRIORITY_NORMAL-10);
if (r < 0)
return r;
- r = sd_event_source_set_io_fd_own(*evt, true);
+ r = sd_event_source_set_io_fd_own(*ss, true);
if (r < 0)
return log_error_errno(r, "Failed to pass ownership of FIFO event fd to event source: %m");
+
TAKE_FD(ref_fd);
}
bool home_shall_suspend(Home *h) {
assert(h);
- /* We lock the home area on suspend if... */
- return h->ref_event_source_please_suspend && /* at least one client supports suspend, and... */
- !h->ref_event_source_dont_suspend && /* no clients lack support for suspend, and... */
- !h->inhibit_suspend_event_source; /* no client is temporarily inhibiting suspend */
+ /* Suspend if there's at least one client referencing this home directory that wants a suspend and none who does not. */
+ return h->ref_event_source_please_suspend && !h->ref_event_source_dont_suspend;
}
static int home_dispatch_release(Home *h, Operation *o) {
static int home_get_image_path_seat(Home *h, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
- _cleanup_free_ char *c = NULL;
const char *ip, *seat;
struct stat st;
int r;
else if (r < 0)
return r;
- c = strdup(seat);
- if (!c)
- return -ENOMEM;
-
- *ret = TAKE_PTR(c);
- return 0;
+ return strdup_to(ret, seat);
}
int home_auto_login(Home *h, char ***ret_seats) {
bool unregister_on_failure;
/* The reading side of a FIFO stored in /run/systemd/home/, the writing side being used for reference
- * counting. The references dropped to zero as soon as we see EOF. This concept exists thrice: once
- * for clients that are fine if we lock the home directory on system suspend, once for clients
- * that are not ok with that, and once for clients that are usually ok with it but temporarily
- * want to opt-out so that they can implement more advanced behavior on their own. This allows
- * us to determine for each home whether there are any clients that don't support suspend at this
- * moment. */
+ * counting. The references dropped to zero as soon as we see EOF. This concept exists twice: once
+ * for clients that are fine if we suspend the home directory on system suspend, and once for clients
+ * that are not ok with that. This allows us to determine for each home whether there are any clients
+ * that support unsuspend. */
sd_event_source *ref_event_source_please_suspend;
sd_event_source *ref_event_source_dont_suspend;
- /* This is distinct from ref_event_source_dont_suspend because it can be obtained from unprivileged
- * code, and thus we don't count it as a reference on the home area. */
- sd_event_source *inhibit_suspend_event_source;
/* Any pending operations we still need to execute. These are for operations we want to queue if we
* can't execute them right-away. */
int home_create(Home *h, UserRecord *secret, Hashmap *blobs, uint64_t flags, sd_bus_error *error);
int home_remove(Home *h, sd_bus_error *error);
int home_update(Home *h, UserRecord *new_record, Hashmap *blobs, uint64_t flags, sd_bus_error *error);
-int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, bool automatic, sd_bus_error *error);
+int home_resize(Home *h, uint64_t disk_size, UserRecord *secret, sd_bus_error *error);
int home_passwd(Home *h, UserRecord *new_secret, UserRecord *old_secret, sd_bus_error *error);
int home_unregister(Home *h, sd_bus_error *error);
int home_lock(Home *h, sd_bus_error *error);
int home_augment_status(Home *h, UserRecordLoadFlags flags, UserRecord **ret);
-typedef enum {
- HOME_FIFO_PLEASE_SUSPEND,
- HOME_FIFO_DONT_SUSPEND,
- HOME_FIFO_INHIBIT_SUSPEND,
- _HOME_FIFO_TYPE_MAX,
- _HOME_FIFO_TYPE_INVALID = -EINVAL,
-} HomeFifoType;
-int home_create_fifo(Home *h, HomeFifoType mode);
-
+int home_create_fifo(Home *h, bool please_suspend);
int home_schedule_operation(Home *h, Operation *o, sd_bus_error *error);
int home_auto_login(Home *h, char ***ret_seats);
#include "bus-common-errors.h"
#include "bus-polkit.h"
#include "format-util.h"
+#include "home-util.h"
#include "homed-bus.h"
#include "homed-home-bus.h"
#include "homed-manager-bus.h"
r = sd_bus_message_read(message, "t", &flags);
if (r < 0)
return r;
- if (flags != 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Provided flags are unsupported.");
+ if ((flags & ~SD_HOMED_CREATE_FLAGS_ALL) != 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags provided.");
}
r = bus_verify_polkit_async(
if (r < 0)
return r;
+ h->current_operation->call_flags = flags;
+
return 1;
fail:
if (!h)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_HOME, "No home for user %s known", hr->user_name);
- return bus_home_method_update_record(h, message, hr, blobs, flags, error);
+ return bus_home_update_record(h, message, hr, blobs, flags, error);
}
static int method_resize_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return generic_home_method(userdata, message, bus_home_method_release, error);
}
-static int method_inhibit_suspend_home(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return generic_home_method(userdata, message, bus_home_method_inhibit_suspend, error);
-}
-
static int method_lock_all_homes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(operation_unrefp) Operation *o = NULL;
bool waiting = false;
method_release_home,
0),
- SD_BUS_METHOD_WITH_ARGS("InhibitSuspendHome",
- SD_BUS_ARGS("s", user_name),
- SD_BUS_RESULT("h", send_fd),
- method_inhibit_suspend_home,
- SD_BUS_VTABLE_UNPRIVILEGED),
-
/* An operation that acts on all homes that allow it */
SD_BUS_METHOD("LockAllHomes", NULL, NULL, method_lock_all_homes, 0),
SD_BUS_METHOD("DeactivateAllHomes", NULL, NULL, method_deactivate_all_homes, 0),
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
- r = sd_bus_attach_event(m->bus, m->event, 0);
+ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
h->rebalance_pending = false;
- r = home_resize(h, h->rebalance_goal, /* secret= */ NULL, /* automatic= */ true, &error);
+ r = home_resize(h, h->rebalance_goal, /* secret= */ NULL, &error);
if (r < 0)
log_warning_errno(r, "Failed to resize home '%s' for rebalancing, ignoring: %s",
h->user_name, bus_error_message(&error, r));
sd_bus_message *message;
UserRecord *secret;
+ uint64_t call_flags; /* flags passed into UpdateEx() or CreateHomeEx() */
int send_fd; /* pipe fd for AcquireHome() which is taken already when we start the operation */
int result; /* < 0 if not completed yet, == 0 on failure, > 0 on success */
sd_id128_t *ret_uuid) {
_cleanup_(blkid_free_probep) blkid_probe b = NULL;
- _cleanup_free_ char *s = NULL;
const char *fstype = NULL, *uuid = NULL;
sd_id128_t id;
int r;
if (r < 0)
return r;
- s = strdup(fstype);
- if (!s)
- return -ENOMEM;
-
- *ret_fstype = TAKE_PTR(s);
+ r = strdup_to(ret_fstype, fstype);
+ if (r < 0)
+ return r;
*ret_uuid = id;
-
return 0;
}
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(key_serial_t, keyring_unlink, -1);
-static int upload_to_keyring(
- UserRecord *h,
- const char *password,
- key_serial_t *ret_key_serial) {
+static int upload_to_keyring(UserRecord *h, const void *vk, size_t vks, key_serial_t *ret) {
_cleanup_free_ char *name = NULL;
key_serial_t serial;
assert(h);
- assert(password);
-
- /* If auto-shrink-on-logout is turned on, we need to keep the key we used to unlock the LUKS volume
- * around, since we'll need it when automatically resizing (since we can't ask the user there
- * again). We do this by uploading it into the kernel keyring, specifically the "session" one. This
- * is done under the assumption systemd-homed gets its private per-session keyring (i.e. default
- * service behaviour, given that KeyringMode=private is the default). It will survive between our
- * systemd-homework invocations that way.
- *
- * If auto-shrink-on-logout is disabled we'll skip this step, to be frugal with sensitive data. */
-
- if (user_record_auto_resize_mode(h) != AUTO_RESIZE_SHRINK_AND_GROW) { /* Won't need it */
- if (ret_key_serial)
- *ret_key_serial = -1;
- return 0;
- }
+ assert(vk);
+ assert(vks > 0);
+
+ /* We upload the LUKS volume key into the kernel session keyring, under the assumption that
+ * systemd-homed gets its own private session keyring (i.e. the default service behavior, given
+ * that KeyringMode=private is the default). That way, the key will survive between invocations
+ * of systemd-homework. */
name = strjoin("homework-user-", h->user_name);
if (!name)
return -ENOMEM;
- serial = add_key("user", name, password, strlen(password), KEY_SPEC_SESSION_KEYRING);
+ serial = add_key("user", name, vk, vks, KEY_SPEC_SESSION_KEYRING);
if (serial == -1)
return -errno;
- if (ret_key_serial)
- *ret_key_serial = serial;
-
+ if (ret)
+ *ret = serial;
return 1;
}
struct crypt_device *cd,
char **passwords,
void *volume_key,
- size_t *volume_key_size,
- key_serial_t *ret_key_serial) {
+ size_t *volume_key_size) {
int r;
assert(h);
assert(cd);
+ assert(volume_key);
+ assert(volume_key_size);
STRV_FOREACH(pp, passwords) {
size_t vks = *volume_key_size;
*pp,
strlen(*pp));
if (r >= 0) {
- if (ret_key_serial) {
- /* If ret_key_serial is non-NULL, let's try to upload the password that
- * worked, and return its serial. */
- r = upload_to_keyring(h, *pp, ret_key_serial);
- if (r < 0) {
- log_debug_errno(r, "Failed to upload LUKS password to kernel keyring, ignoring: %m");
- *ret_key_serial = -1;
- }
- }
-
*volume_key_size = vks;
return 0;
}
return -ENOKEY;
}
+static int luks_get_volume_key(
+ UserRecord *h,
+ struct crypt_device *cd,
+ const PasswordCache *cache,
+ void *volume_key,
+ size_t *volume_key_size,
+ key_serial_t *ret_key_serial) {
+
+ char **list;
+ size_t vks;
+ int r;
+
+ assert(h);
+ assert(cd);
+ assert(volume_key);
+ assert(volume_key_size);
+
+ if (cache && cache->volume_key) {
+ /* Shortcut: If volume key was loaded from the keyring then just use it */
+ if (cache->volume_key_size > *volume_key_size)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOBUFS),
+ "LUKS volume key from kernel keyring too big for buffer (need %zu bytes, have %zu)",
+ cache->volume_key_size, *volume_key_size);
+ memcpy(volume_key, cache->volume_key, cache->volume_key_size);
+ *volume_key_size = cache->volume_key_size;
+ if (ret_key_serial)
+ *ret_key_serial = -1; /* Key came from keyring. No need to re-upload it */
+ return 0;
+ }
+
+ vks = *volume_key_size;
+
+ FOREACH_ARGUMENT(list,
+ cache ? cache->pkcs11_passwords : NULL,
+ cache ? cache->fido2_passwords : NULL,
+ h->password) {
+
+ r = luks_try_passwords(h, cd, list, volume_key, &vks);
+ if (r == -ENOKEY)
+ continue;
+ if (r < 0)
+ return r;
+
+ /* We got a volume key! */
+
+ if (ret_key_serial) {
+ r = upload_to_keyring(h, volume_key, vks, ret_key_serial);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to upload LUKS volume key to kernel keyring, ignoring: %m");
+ *ret_key_serial = -1;
+ }
+ }
+
+ *volume_key_size = vks;
+ return 0;
+ }
+
+ return -ENOKEY;
+}
+
static int luks_setup(
UserRecord *h,
const char *node,
const char *cipher,
const char *cipher_mode,
uint64_t volume_key_size,
- char **passwords,
const PasswordCache *cache,
bool discard,
struct crypt_device **ret,
if (!vk)
return log_oom();
- r = -ENOKEY;
- char **list;
- FOREACH_ARGUMENT(list,
- cache ? cache->keyring_passswords : NULL,
- cache ? cache->pkcs11_passwords : NULL,
- cache ? cache->fido2_passwords : NULL,
- passwords) {
-
- r = luks_try_passwords(h, cd, list, vk, &vks, ret_key_serial ? &key_serial : NULL);
- if (r != -ENOKEY)
- break;
- }
+ r = luks_get_volume_key(h, cd, cache, vk, &vks, ret_key_serial ? &key_serial : NULL);
if (r == -ENOKEY)
return log_error_errno(r, "No valid password for LUKS superblock.");
if (r < 0)
if (!vk)
return log_oom();
- r = -ENOKEY;
- char **list;
- FOREACH_ARGUMENT(list,
- cache ? cache->keyring_passswords : NULL,
- cache ? cache->pkcs11_passwords : NULL,
- cache ? cache->fido2_passwords : NULL,
- h->password) {
-
- r = luks_try_passwords(h, setup->crypt_device, list, vk, &vks, NULL);
- if (r != -ENOKEY)
- break;
- }
+ r = luks_get_volume_key(h, setup->crypt_device, cache, vk, &vks, NULL);
if (r == -ENOKEY)
return log_error_errno(r, "No valid password for LUKS superblock.");
if (r < 0)
h->luks_cipher,
h->luks_cipher_mode,
h->luks_volume_key_size,
- h->password,
cache,
user_record_luks_discard(h) || user_record_luks_offline_discard(h),
&setup->crypt_device,
if (!volume_key)
return log_oom();
- r = -ENOKEY;
- char **list;
- FOREACH_ARGUMENT(list,
- cache ? cache->keyring_passswords : NULL,
- cache ? cache->pkcs11_passwords : NULL,
- cache ? cache->fido2_passwords : NULL,
- h->password) {
-
- r = luks_try_passwords(h, setup->crypt_device, list, volume_key, &volume_key_size, NULL);
- if (r != -ENOKEY)
- break;
- }
+ r = luks_get_volume_key(h, setup->crypt_device, cache, volume_key, &volume_key_size, NULL);
if (r == -ENOKEY)
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "Failed to unlock LUKS superblock with supplied passwords.");
if (r < 0)
return log_error_errno(r, "Failed to set up LUKS password: %m");
log_info("Updated LUKS key slot %zu.", i);
-
- /* If we changed the password, then make sure to update the copy in the keyring, so that
- * auto-rebalance continues to work. We only do this if we operate on an active home dir. */
- if (i == 0 && FLAGS_SET(flags, HOME_SETUP_ALREADY_ACTIVATED))
- upload_to_keyring(h, effective_passwords[i], NULL);
}
return 1;
return 0;
}
-static int luks_try_resume(
- struct crypt_device *cd,
- const char *dm_name,
- char **password) {
-
- int r;
-
- assert(cd);
- assert(dm_name);
-
- STRV_FOREACH(pp, password) {
- r = sym_crypt_resume_by_passphrase(
- cd,
- dm_name,
- CRYPT_ANY_SLOT,
- *pp,
- strlen(*pp));
- if (r >= 0) {
- log_info("Resumed LUKS device %s.", dm_name);
- return 0;
- }
-
- log_debug_errno(r, "Password %zu didn't work for resuming device: %m", (size_t) (pp - password));
- }
-
- return -ENOKEY;
-}
-
int home_unlock_luks(UserRecord *h, HomeSetup *setup, const PasswordCache *cache) {
+ _cleanup_(keyring_unlinkp) key_serial_t key_serial = -1;
+ _cleanup_(erase_and_freep) void *vk = NULL;
+ size_t vks;
int r;
assert(h);
log_info("Discovered used LUKS device %s.", setup->dm_node);
- r = -ENOKEY;
- char **list;
- FOREACH_ARGUMENT(list,
- cache ? cache->pkcs11_passwords : NULL,
- cache ? cache->fido2_passwords : NULL,
- h->password) {
+ r = sym_crypt_get_volume_key_size(setup->crypt_device);
+ if (r <= 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
+ vks = (size_t) r;
- r = luks_try_resume(setup->crypt_device, setup->dm_name, list);
- if (r != -ENOKEY)
- break;
- }
+ vk = malloc(vks);
+ if (!vk)
+ return log_oom();
+
+ r = luks_get_volume_key(h, setup->crypt_device, cache, vk, &vks, &key_serial);
if (r == -ENOKEY)
return log_error_errno(r, "No valid password for LUKS superblock.");
+ if (r < 0)
+ return log_error_errno(r, "Failed to unlock LUKS superblock: %m");
+
+ r = sym_crypt_resume_by_volume_key(setup->crypt_device, setup->dm_name, vk, vks);
if (r < 0)
return log_error_errno(r, "Failed to resume LUKS superblock: %m");
+ TAKE_KEY_SERIAL(key_serial); /* Leave key in kernel keyring */
+
log_info("LUKS device resumed.");
return 0;
}
if (!cache)
return;
+ cache->volume_key = erase_and_free(cache->volume_key);
cache->pkcs11_passwords = strv_free_erase(cache->pkcs11_passwords);
cache->fido2_passwords = strv_free_erase(cache->fido2_passwords);
- cache->keyring_passswords = strv_free_erase(cache->keyring_passswords);
}
void password_cache_load_keyring(UserRecord *h, PasswordCache *cache) {
- _cleanup_(erase_and_freep) void *p = NULL;
_cleanup_free_ char *name = NULL;
- char **strv;
+ _cleanup_(erase_and_freep) void *vk = NULL;
+ size_t vks;
key_serial_t serial;
- size_t sz;
int r;
assert(h);
assert(cache);
- /* Loads the password we need to for automatic resizing from the kernel keyring */
-
name = strjoin("homework-user-", h->user_name);
if (!name)
return (void) log_oom();
serial = request_key("user", name, NULL, 0);
- if (serial == -1)
- return (void) log_debug_errno(errno, "Failed to request key '%s', ignoring: %m", name);
-
- r = keyring_read(serial, &p, &sz);
+ if (serial == -1) {
+ if (errno == ENOKEY) {
+ log_info("Home volume key is not available in kernel keyring.");
+ return;
+ }
+ return (void) log_warning_errno(errno, "Failed to request key '%s', ignoring: %m", name);
+ }
+
+ r = keyring_read(serial, &vk, &vks);
if (r < 0)
- return (void) log_debug_errno(r, "Failed to read keyring key '%s', ignoring: %m", name);
-
- if (memchr(p, 0, sz))
- return (void) log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Cached password contains embedded NUL byte, ignoring.");
-
- strv = new(char*, 2);
- if (!strv)
- return (void) log_oom();
-
- strv[0] = TAKE_PTR(p); /* Note that keyring_read() will NUL terminate implicitly, hence we don't have
- * to NUL terminate manually here: it's a valid string. */
- strv[1] = NULL;
+ return (void) log_warning_errno(r, "Failed to read keyring key '%s', ignoring: %m", name);
- strv_free_erase(cache->keyring_passswords);
- cache->keyring_passswords = strv;
+ log_info("Successfully acquired home volume key from kernel keyring.");
- log_debug("Successfully acquired home key from kernel keyring.");
+ erase_and_free(cache->volume_key);
+ cache->volume_key = TAKE_PTR(vk);
+ cache->volume_key_size = vks;
}
#include "user-record.h"
typedef struct PasswordCache {
- /* Passwords acquired from the kernel keyring */
- char **keyring_passswords;
+ /* The volume key from the kernel keyring */
+ void *volume_key;
+ size_t volume_key_size;
/* Decoding passwords from security tokens is expensive and typically requires user interaction,
* hence cache any we already figured out. */
if (!cache)
return false;
+ /* Used to decide whether or not to set a minimal PBKDF, under the assumption that if
+ * the cache contains a password then the password came from a hardware token of some kind
+ * and is thus naturally high-entropy. */
+
return strv_contains(cache->pkcs11_passwords, p) ||
- strv_contains(cache->fido2_passwords, p) ||
- strv_contains(cache->keyring_passswords, p);
+ strv_contains(cache->fido2_passwords, p);
}
void password_cache_load_keyring(UserRecord *h, PasswordCache *cache);
* times over the course of an operation (think: on login we authenticate the host user record, the
* record embedded in the LUKS record and the one embedded in $HOME). Hence we keep a list of
* passwords we already decrypted, so that we don't have to do the (slow and potentially interactive)
- * PKCS#11/FIDO2 dance for the relevant token again and again. */
+ * PKCS#11/FIDO2 dance for the relevant token again and again.
+ *
+ * The 'cache' parameter might also contain the LUKS volume key, loaded from the kernel keyring.
+ * In this case, authentication becomes optional - if a secret section is provided it will be
+ * verified, but if missing then authentication is skipped entirely. Thus, callers should
+ * consider carefuly whether it is safe to load the volume key into 'cache' before doing so.
+ * Note that most of the time this is safe, because the home area must be active for the key
+ * to exist in the keyring, and the user would have had to authenticate when activating their
+ * home area; however, for some methods (i.e. ChangePassword, Authenticate) it makes more sense
+ * to force re-authentication. */
+
+ /* First, let's see if we already have a volume key from the keyring */
+ if (cache && cache->volume_key &&
+ json_variant_is_blank_object(json_variant_by_key(secret->json, "secret"))) {
+ log_info("LUKS volume key from keyring unlocks user record.");
+ return 1;
+ }
- /* First, let's see if the supplied plain-text passwords work? */
+ /* Next, let's see if the supplied plain-text passwords work? */
r = user_record_test_password(h, secret);
if (r == -ENOKEY)
need_password = true;
else
log_info("None of the supplied plaintext passwords unlock the user record's hashed recovery keys.");
- /* Second, test cached PKCS#11 passwords */
+ /* Next, test cached PKCS#11 passwords */
for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++)
STRV_FOREACH(pp, cache->pkcs11_passwords) {
r = test_password_one(h->pkcs11_encrypted_key[n].hashed_password, *pp);
}
}
- /* Third, test cached FIDO2 passwords */
+ /* Next, test cached FIDO2 passwords */
for (size_t n = 0; n < h->n_fido2_hmac_salt; n++)
/* See if any of the previously calculated passwords work */
STRV_FOREACH(pp, cache->fido2_passwords) {
}
}
- /* Fourth, let's see if any of the PKCS#11 security tokens are plugged in and help us */
+ /* Next, let's see if any of the PKCS#11 security tokens are plugged in and help us */
for (size_t n = 0; n < h->n_pkcs11_encrypted_key; n++) {
#if HAVE_P11KIT
_cleanup_(pkcs11_callback_data_release) struct pkcs11_callback_data data = {
#endif
}
- /* Fifth, let's see if any of the FIDO2 security tokens are plugged in and help us */
+ /* Next, let's see if any of the FIDO2 security tokens are plugged in and help us */
for (size_t n = 0; n < h->n_fido2_hmac_salt; n++) {
#if HAVE_LIBFIDO2
_cleanup_(erase_and_freep) char *decrypted_password = NULL;
return 0;
}
-static int home_validate_update(UserRecord *h, HomeSetup *setup, HomeSetupFlags *flags) {
- bool has_mount = false;
- int r;
-
+static int home_basic_validate_update(UserRecord *h) {
assert(h);
- assert(setup);
if (!h->user_name)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks user name, refusing.");
+
if (!uid_is_valid(h->uid))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks UID, refusing.");
+
if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Processing home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
+ return 0;
+}
+
+static int home_validate_update(UserRecord *h, HomeSetup *setup, HomeSetupFlags *flags) {
+ bool has_mount = false;
+ int r;
+
+ assert(h);
+ assert(setup);
+
+ r = home_basic_validate_update(h);
+ if (r < 0)
+ return r;
+
r = user_record_test_home_directory_and_warn(h);
if (r < 0)
return r;
_cleanup_(home_setup_done) HomeSetup setup = HOME_SETUP_INIT;
_cleanup_(password_cache_free) PasswordCache cache = {};
HomeSetupFlags flags = 0;
+ bool offline;
int r;
assert(h);
assert(ret);
- r = user_record_authenticate(h, h, &cache, /* strict_verify= */ true);
- if (r < 0)
- return r;
- assert(r > 0); /* Insist that a password was verified */
+ offline = getenv_bool("SYSTEMD_HOMEWORK_UPDATE_OFFLINE") > 0;
- r = home_validate_update(h, &setup, &flags);
+ if (!offline) {
+ password_cache_load_keyring(h, &cache);
+
+ r = user_record_authenticate(h, h, &cache, /* strict_verify= */ true);
+ if (r < 0)
+ return r;
+ assert(r > 0); /* Insist that a password was verified */
+
+ r = home_validate_update(h, &setup, &flags);
+ } else {
+ /* In offline mode we skip all authentication, since we're
+ * not propagating anything into the home area. The new home
+ * records's authentication will still be checked when the user
+ * next logs in, so this is fine */
+
+ r = home_basic_validate_update(h);
+ }
if (r < 0)
return r;
if (r < 0)
return r;
+ if (offline) {
+ log_info("Offline update requested. Not touching embedded records.");
+ return user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, ret);
+ }
+
r = home_setup(h, flags, &setup, &cache, &header_home);
if (r < 0)
return r;
return 0;
}
-static int home_resize(UserRecord *h, bool automatic, UserRecord **ret) {
+static int home_resize(UserRecord *h, UserRecord **ret) {
_cleanup_(home_setup_done) HomeSetup setup = HOME_SETUP_INIT;
_cleanup_(password_cache_free) PasswordCache cache = {};
HomeSetupFlags flags = 0;
if (h->disk_size == UINT64_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No target size specified, refusing.");
- if (automatic)
- /* In automatic mode don't want to ask the user for the password, hence load it from the kernel keyring */
- password_cache_load_keyring(h, &cache);
- else {
- /* In manual mode let's ensure the user is fully authenticated */
- r = user_record_authenticate(h, h, &cache, /* strict_verify= */ true);
- if (r < 0)
- return r;
- assert(r > 0); /* Insist that a password was verified */
- }
+ password_cache_load_keyring(h, &cache);
- r = home_validate_update(h, &setup, &flags);
+ r = user_record_authenticate(h, h, &cache, /* strict_verify= */ true);
if (r < 0)
return r;
+ assert(r > 0); /* Insist that a password was verified */
- /* In automatic mode let's skip syncing identities, because we can't validate them, since we can't
- * ask the user for reauthentication */
- if (automatic)
- flags |= HOME_SETUP_RESIZE_DONT_SYNC_IDENTITIES;
+ r = home_validate_update(h, &setup, &flags);
+ if (r < 0)
+ return r;
switch (user_record_storage(h)) {
unit_freezer_done(&freezer); /* Don't thaw the user session. */
+ /* Explicitly flush any per-user key from the keyring */
+ (void) keyring_flush(h);
+
log_info("Everything completed.");
return 1;
}
r = home_remove(home);
else if (streq(argv[1], "update"))
r = home_update(home, blobs, &new_home);
- else if (streq(argv[1], "resize")) /* Resize on user request */
- r = home_resize(home, false, &new_home);
- else if (streq(argv[1], "resize-auto")) /* Automatic resize */
- r = home_resize(home, true, &new_home);
+ else if (streq(argv[1], "resize"))
+ r = home_resize(home, &new_home);
else if (streq(argv[1], "passwd"))
r = home_passwd(home, &new_home);
else if (streq(argv[1], "inspect"))
send_interface="org.freedesktop.home1.Manager"
send_member="ReleaseHome"/>
- <allow send_destination="org.freedesktop.home1"
- send_interface="org.freedesktop.home1.Manager"
- send_member="InhibitSuspendHome"/>
-
<allow send_destination="org.freedesktop.home1"
send_interface="org.freedesktop.home1.Manager"
send_member="LockAllHomes"/>
send_interface="org.freedesktop.home1.Home"
send_member="Release"/>
- <allow send_destination="org.freedesktop.home1"
- send_interface="org.freedesktop.home1.Home"
- send_member="InhibitSuspend"/>
-
<allow receive_sender="org.freedesktop.home1"/>
</policy>
</defaults>
</action>
- <action id="org.freedesktop.home1.inhibit-suspend">
- <description gettext-domain="systemd">Inhibit automatic lock of a home area</description>
- <message gettext-domain="systemd">Authentication is required to inhibit automatic lock of a user's home area.</message>
- <defaults>
- <allow_any>auth_admin_keep</allow_any>
- <allow_inactive>auth_admin_keep</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- </action>
-
<action id="org.freedesktop.home1.activate-home">
<description gettext-domain="systemd">Activate a home area</description>
<message gettext-domain="systemd">Authentication is required to activate a user's home area.</message>
static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
- _cleanup_free_ char *b = NULL;
const char *s = NULL;
int r;
if (!s && regular_key)
(void) sd_device_get_property_value(device, regular_key, &s);
- if (!ret)
- return !!s;
-
- if (s) {
- b = strdup(s);
- if (!b)
- return -ENOMEM;
- }
-
- *ret = TAKE_PTR(b);
- return !!s;
+ return strdup_to_full(ret, s);
}
static int get_hardware_vendor(char **ret) {
(void) sd_device_get_sysattr_value(device, sysattr, &s);
- bool empty = isempty(s);
-
- if (ret) {
- if (empty)
- *ret = NULL;
- else {
- _cleanup_free_ char *b = NULL;
-
- b = strdup(s);
- if (!b)
- return -ENOMEM;
-
- *ret = TAKE_PTR(b);
- }
- }
-
- return !empty;
+ return strdup_to_full(ret, empty_to_null(s));
}
static int get_hardware_serial(char **ret) {
typedef struct Context {
sd_journal *journal;
+ bool has_cursor;
bool need_seek;
bool since_seeked;
bool ellipsized;
break;
}
- if (arg_until_set && !arg_reverse && (arg_lines < 0 || arg_since_set)) {
- /* If --lines= is set, we usually rely on the n_shown to tell us
- * when to stop. However, if --since= is set too, we may end up
- * having less than --lines= to output. In this case let's also
- * check if the entry is in range. */
+ if (arg_until_set && !arg_reverse && (arg_lines < 0 || arg_since_set || c->has_cursor)) {
+ /* If --lines= is set, we usually rely on the n_shown to tell us when to stop.
+ * However, if --since= or one of the cursor argument is set too, we may end up
+ * having less than --lines= to output. In this case let's also check if the entry
+ * is in range. */
usec_t usec;
Context c = {
.journal = j,
+ .has_cursor = cursor,
.need_seek = need_seek,
.since_seeked = since_seeked,
};
ENTRY_DIR_ABS="$3"
KERNEL_IMAGE="$4"
-[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
-
ENTRY_TOKEN="$KERNEL_INSTALL_ENTRY_TOKEN"
BOOT_ROOT="$KERNEL_INSTALL_BOOT_ROOT"
;;
esac
+[ "$KERNEL_INSTALL_LAYOUT" = "uki" ] || exit 0
+
if ! [ -d "$UKI_DIR" ]; then
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "creating $UKI_DIR"
mkdir -p "$UKI_DIR"
return copy.rfd;
}
- r = strdup_or_null(source->layout_other, ©.layout_other);
+ r = strdup_to(©.layout_other, source->layout_other);
if (r < 0)
return r;
- r = strdup_or_null(source->conf_root, ©.conf_root);
+ r = strdup_to(©.conf_root, source->conf_root);
if (r < 0)
return r;
- r = strdup_or_null(source->boot_root, ©.boot_root);
+ r = strdup_to(©.boot_root, source->boot_root);
if (r < 0)
return r;
- r = strdup_or_null(source->entry_token, ©.entry_token);
+ r = strdup_to(©.entry_token, source->entry_token);
if (r < 0)
return r;
- r = strdup_or_null(source->entry_dir, ©.entry_dir);
+ r = strdup_to(©.entry_dir, source->entry_dir);
if (r < 0)
return r;
- r = strdup_or_null(source->version, ©.version);
+ r = strdup_to(©.version, source->version);
if (r < 0)
return r;
- r = strdup_or_null(source->kernel, ©.kernel);
+ r = strdup_to(©.kernel, source->kernel);
if (r < 0)
return r;
r = strv_copy_unless_empty(source->initrds, ©.initrds);
if (r < 0)
return r;
- r = strdup_or_null(source->initrd_generator, ©.initrd_generator);
+ r = strdup_to(©.initrd_generator, source->initrd_generator);
if (r < 0)
return r;
- r = strdup_or_null(source->uki_generator, ©.uki_generator);
+ r = strdup_to(©.uki_generator, source->uki_generator);
if (r < 0)
return r;
- r = strdup_or_null(source->staging_area, ©.staging_area);
+ r = strdup_to(©.staging_area, source->staging_area);
if (r < 0)
return r;
r = strv_copy_unless_empty(source->plugins, ©.plugins);
int devname_from_devnum(mode_t mode, dev_t devnum, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
- _cleanup_free_ char *s = NULL;
const char *devname;
int r;
if (r < 0)
return r;
- s = strdup(devname);
- if (!s)
- return -ENOMEM;
-
- *ret = TAKE_PTR(s);
- return 0;
+ return strdup_to(ret, devname);
}
-int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret) {
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_close_ int fd = -EBADF;
int r;
if (fd < 0)
return fd;
- if (ret) {
+ if (ret_devname) {
const char *devname;
- char *s;
r = sd_device_get_devname(dev, &devname);
if (r < 0)
return r;
- s = strdup(devname);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
+ r = strdup_to(ret_devname, devname);
+ if (r < 0)
+ return r;
}
return TAKE_FD(fd);
assert(st);
return devname_from_devnum(st->st_mode, st->st_rdev, ret);
}
-int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret);
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname);
char** device_make_log_fields(sd_device *device);
const char* deflang,
char **ret) {
- size_t c;
- char *z;
-
- c = strlen(t);
+ size_t c = strlen(t);
if (c < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] Language too short.", filename, line);
log_warning("[%s:%u] language differs from default for file", filename, line);
}
- z = strdup(t);
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
+ return strdup_to(ret, t);
}
int catalog_import_file(OrderedHashmap *h, const char *path) {
le64toh(f->offset);
}
-int catalog_get(const char* database, sd_id128_t id, char **_text) {
+int catalog_get(const char* database, sd_id128_t id, char **ret_text) {
_cleanup_close_ int fd = -EBADF;
void *p = NULL;
- struct stat st = {};
- char *text = NULL;
+ struct stat st;
int r;
const char *s;
- assert(_text);
+ assert(ret_text);
r = open_mmap(database, &fd, &st, &p);
if (r < 0)
goto finish;
}
- text = strdup(s);
- if (!text) {
- r = -ENOMEM;
- goto finish;
- }
-
- *_text = text;
- r = 0;
-
+ r = strdup_to(ret_text, s);
finish:
(void) munmap(p, st.st_size);
int catalog_import_file(OrderedHashmap *h, const char *path);
int catalog_update(const char* database, const char* root, const char* const* dirs);
-int catalog_get(const char* database, sd_id128_t id, char **data);
+int catalog_get(const char* database, sd_id128_t id, char **ret_text);
int catalog_list(FILE *f, const char* database, bool oneline);
int catalog_list_items(FILE *f, const char* database, bool oneline, char **items);
int catalog_file_lang(const char *filename, char **lang);
if (new_locale[p])
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name);
- new_locale[p] = strdup(e);
- if (!new_locale[p])
- return -ENOMEM;
-
- return 0;
+ return strdup_to(&new_locale[p], e);
}
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *p = NULL;
const char *path;
int r;
if (r < 0)
return bus_log_parse_error(r);
- p = strdup(path);
- if (!p)
- return log_oom();
-
- *ret = TAKE_PTR(p);
- return 0;
+ return strdup_to(ret, path);
}
static int show_session(int argc, char *argv[], void *userdata) {
user->gc_mode = USER_GC_BY_PIN;
if (!isempty(tty)) {
- session->tty = strdup(tty);
- if (!session->tty) {
- r = -ENOMEM;
+ r = strdup_to(&session->tty, tty);
+ if (r < 0)
goto fail;
- }
session->tty_validity = TTY_FROM_PAM;
}
if (!isempty(display)) {
- session->display = strdup(display);
- if (!session->display) {
- r = -ENOMEM;
+ r = strdup_to(&session->display, display);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(remote_user)) {
- session->remote_user = strdup(remote_user);
- if (!session->remote_user) {
- r = -ENOMEM;
+ r = strdup_to(&session->remote_user, remote_user);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(remote_host)) {
- session->remote_host = strdup(remote_host);
- if (!session->remote_host) {
- r = -ENOMEM;
+ r = strdup_to(&session->remote_host, remote_host);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(service)) {
- session->service = strdup(service);
- if (!session->service) {
- r = -ENOMEM;
+ r = strdup_to(&session->service, service);
+ if (r < 0)
goto fail;
- }
}
if (!isempty(desktop)) {
- session->desktop = strdup(desktop);
- if (!session->desktop) {
- r = -ENOMEM;
+ r = strdup_to(&session->desktop, desktop);
+ if (r < 0)
goto fail;
- }
}
if (seat) {
Manager *manager,
const char *scope,
const PidRef *pidref,
+ bool allow_pidfd,
const char *slice,
const char *description,
const char * const *requires,
if (r < 0)
return r;
- r = bus_append_scope_pidref(m, pidref);
+ r = bus_append_scope_pidref(m, pidref, allow_pidfd);
if (r < 0)
return r;
return r;
r = sd_bus_call(manager->bus, m, 0, error, &reply);
- if (r < 0)
+ if (r < 0) {
+ /* If this failed with a property we couldn't write, this is quite likely because the server
+ * doesn't support PIDFDs yet, let's try without. */
+ if (allow_pidfd &&
+ sd_bus_error_has_names(error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
+ return manager_start_scope(
+ manager,
+ scope,
+ pidref,
+ /* allow_pidfd = */ false,
+ slice,
+ description,
+ requires,
+ extra_after,
+ requires_mounts_for,
+ more_properties,
+ error,
+ ret_job);
+
return r;
+ }
return strdup_job(reply, ret_job);
}
Manager *manager,
const char *scope,
const PidRef *pidref,
+ bool allow_pidfd,
const char *slice,
const char *description,
const char * const *requires,
if (sd->device->seat != sd->session->seat)
return -EPERM;
- sd->node = strdup(node);
- if (!sd->node)
- return -ENOMEM;
-
- return 0;
+ return strdup_to(&sd->node, node);
}
int session_device_new(Session *s, dev_t dev, bool open_device, SessionDevice **ret) {
s->manager,
scope,
&s->leader,
+ /* allow_pidfd = */ true,
s->user->slice,
description,
/* These should have been pulled in explicitly in user_start(). Just to be sure. */
if (r < 0)
return r;
- r = bus_append_scope_pidref(m, &machine->leader);
+ r = bus_append_scope_pidref(m, &machine->leader, /* allow_pidfd = */ true);
if (r < 0)
return r;
static int call_get_os_release(sd_bus *bus, const char *method, const char *name, const char *query, ...) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *k, *v, **query_res = NULL;
- size_t count = 0, awaited_args = 0;
va_list ap;
int r;
assert(bus);
+ assert(method);
assert(name);
assert(query);
- NULSTR_FOREACH(iter, query)
- awaited_args++;
- query_res = newa0(const char *, awaited_args);
-
r = bus_call_method(bus, bus_machine_mgr, method, &error, &reply, "s", name);
if (r < 0)
return log_debug_errno(r, "Failed to call '%s()': %s", method, bus_error_message(&error, r));
if (r < 0)
return bus_log_parse_error(r);
+ const char **res;
+ size_t n_fields = 0;
+
+ NULSTR_FOREACH(i, query)
+ n_fields++;
+
+ res = newa0(const char*, n_fields);
+
+ const char *k, *v;
while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
- count = 0;
- NULSTR_FOREACH(iter, query) {
- if (streq(k, iter)) {
- query_res[count] = v;
+ size_t c = 0;
+ NULSTR_FOREACH(i, query) {
+ if (streq(i, k)) {
+ res[c] = v;
break;
}
- count++;
+ c++;
}
}
if (r < 0)
if (r < 0)
return bus_log_parse_error(r);
+ r = 0;
+
va_start(ap, query);
- for (count = 0; count < awaited_args; count++) {
- char *val, **out;
-
- out = va_arg(ap, char **);
- assert(out);
- if (query_res[count]) {
- val = strdup(query_res[count]);
- if (!val) {
- va_end(ap);
- return -ENOMEM;
- }
- *out = val;
- }
+ FOREACH_ARRAY(i, res, n_fields) {
+ r = strdup_to(va_arg(ap, char**), *i);
+ if (r < 0)
+ break;
}
va_end(ap);
- return 0;
+ return r;
}
static int call_get_addresses(
addresses = strdup(prefix);
if (!addresses)
return log_oom();
- prefix = "";
r = sd_bus_message_enter_container(reply, 'a', "(iay)");
if (r < 0)
return bus_log_parse_error(r);
+ prefix = "";
while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
int family;
const void *a;
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, freep);
static int varlink_connect_networkd(Varlink **ret_varlink) {
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
JsonVariant *reply;
uint64_t id;
int r;
if (r < 0)
return log_error_errno(r, "Failed to connect to network service /run/systemd/netif/io.systemd.Network: %m");
+ (void) varlink_set_description(vl, "varlink-network");
+
+ r = varlink_set_allow_fd_passing_output(vl, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allow passing file descriptor through varlink: %m");
+
r = varlink_call_and_log(vl, "io.systemd.Network.GetNamespaceId", /* parameters= */ NULL, &reply);
if (r < 0)
return r;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
int r, c;
}
static int link_lldp_status(int argc, char *argv[], void *userdata) {
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
JsonVariant *reply;
uint64_t all = 0;
}
static int verb_persistent_storage(int argc, char *argv[], void *userdata) {
- _cleanup_(varlink_unrefp) Varlink *vl = NULL;
+ _cleanup_(varlink_flush_close_unrefp) Varlink *vl = NULL;
bool ready;
int r;
if (r < 0)
return r;
+ if (ready) {
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+
+ r = varlink_push_fd(vl, fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to push file descriptor of /var/lib/systemd/network/ into varlink: %m");
+
+ TAKE_FD(fd);
+ }
+
return varlink_callb_and_log(vl, "io.systemd.Network.SetPersistentStorage", /* reply = */ NULL,
JSON_BUILD_OBJECT(JSON_BUILD_PAIR_BOOLEAN("Ready", ready)));
}
dest->nft_set_context.n_sets = 0;
if (src->family == AF_INET) {
- r = strdup_or_null(src->label, &dest->label);
+ r = strdup_to(&dest->label, src->label);
if (r < 0)
return r;
}
- r = strdup_or_null(src->netlabel, &dest->netlabel);
+ r = strdup_to(&dest->netlabel, src->netlabel);
if (r < 0)
return r;
return r;
if (ready) {
- _cleanup_close_ int fd = -EBADF;
struct stat st, st_prev;
+ int fd;
- fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+ fd = varlink_peek_fd(vlink, 0);
if (fd < 0)
- return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+ return log_warning_errno(fd, "Failed to peek file descriptor of the persistent storage: %m");
+
+ r = fd_verify_safe_flags_full(fd, O_DIRECTORY);
+ if (r == -EREMOTEIO)
+ return log_warning_errno(r, "Passed persistent storage fd has unexpected flags, refusing.");
+ if (r < 0)
+ return log_warning_errno(r, "Failed to verify flags of passed persistent storage fd: %m");
r = fd_is_read_only_fs(fd);
if (r < 0)
}
if (fstat(fd, &st) < 0)
- return log_warning_errno(r, "Failed to stat the persistent storage: %m");
+ return log_warning_errno(r, "Failed to stat the passed persistent storage fd: %m");
+
+ r = stat_verify_directory(&st);
+ if (r < 0)
+ return log_warning_errno(r, "The passed persistent storage fd is not a directory, refusing: %m");
if (manager->persistent_storage_fd >= 0 &&
fstat(manager->persistent_storage_fd, &st_prev) >= 0 &&
if (ready) {
_cleanup_close_ int fd = -EBADF;
- fd = open("/var/lib/systemd/network/", O_CLOEXEC | O_DIRECTORY | O_PATH);
+ fd = varlink_take_fd(vlink, 0);
if (fd < 0)
- return log_warning_errno(errno, "Failed to open /var/lib/systemd/network/: %m");
+ return log_warning_errno(fd, "Failed to take file descriptor of the persistent storage: %m");
close_and_replace(manager->persistent_storage_fd, fd);
} else
return varlink_reply(vlink, NULL);
}
+static int on_connect(VarlinkServer *s, Varlink *vlink, void *userdata) {
+ int r;
+
+ assert(vlink);
+
+ r = varlink_set_allow_fd_passing_input(vlink, true);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to allow receiving file descriptor through varlink: %m");
+
+ return 0;
+}
+
int manager_connect_varlink(Manager *m) {
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
int r;
varlink_server_set_userdata(s, m);
+ (void) varlink_server_set_description(s, "varlink-api-network");
+
r = varlink_server_add_interface(s, &vl_interface_io_systemd_Network);
if (r < 0)
return log_error_errno(r, "Failed to add Network interface to varlink server: %m");
if (r < 0)
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
+ r = varlink_server_bind_connect(s, on_connect);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set on-connect callback for varlink: %m");
+
m->varlink_server = TAKE_PTR(s);
return 0;
}
} else
dest->metrics_set = NULL;
- return strdup_or_null(src->tcp_congestion_control_algo, &dest->tcp_congestion_control_algo);
+ return strdup_to(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo);
}
void route_metric_hash_func(const RouteMetric *metric, struct siphash *state) {
/* unset pointer copied in the above. */
dest->ifname = NULL;
- return strdup_or_null(src->ifindex > 0 ? NULL : src->ifname, &dest->ifname);
+ return strdup_to(&dest->ifname, src->ifindex > 0 ? NULL : src->ifname);
}
static int route_nexthop_dup(const RouteNextHop *src, RouteNextHop **ret) {
description = strjoina("Container ", machine_name);
- if (allow_pidfd) {
- _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- r = pidref_set_pid(&pidref, pid);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate PID reference: %m");
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ r = pidref_set_pid(&pidref, pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate PID reference: %m");
- r = bus_append_scope_pidref(m, &pidref);
- } else
- r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) pid);
+ r = bus_append_scope_pidref(m, &pidref, allow_pidfd);
if (r < 0)
return bus_log_create_error(r);
if (dissected_image) {
/* Now we know the uid shift, let's now mount everything else that might be in the image. */
- r = dissected_image_mount(
+ r = dissected_image_mount_and_warn(
dissected_image,
directory,
arg_uid_shift,
determine_dissect_image_flags()|
DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|
(idmap ? DISSECT_IMAGE_MOUNT_IDMAPPED : 0));
- if (r == -EUCLEAN)
- return log_error_errno(r, "File system check for image failed: %m");
if (r < 0)
- return log_error_errno(r, "Failed to mount image file system: %m");
+ return r;
}
if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
if (r == -ENOMEM)
return r; /* Treat oom as a hard error */
if (r < 0) {
- if (ret == 0)
- ret = r;
+ RET_GATHER(ret, r);
continue; /* Try to find something else to kill */
}
dump_until = MAX(dump_until, i + 1);
- char *selected = strdup(sorted[i]->path);
- if (!selected)
- return -ENOMEM;
- *ret_selected = selected;
+
ret = r;
+ r = strdup_to(ret_selected, sorted[i]->path);
+ if (r < 0)
+ return r;
break;
}
if (r == -ENOMEM)
return r; /* Treat oom as a hard error */
if (r < 0) {
- if (ret == 0)
- ret = r;
+ RET_GATHER(ret, r);
continue; /* Try to find something else to kill */
}
dump_until = MAX(dump_until, i + 1);
- char *selected = strdup(sorted[i]->path);
- if (!selected)
- return -ENOMEM;
- *ret_selected = selected;
+
ret = r;
+ r = strdup_to(ret_selected, sorted[i]->path);
+ if (r < 0)
+ return r;
break;
}
return log_debug_errno(r, "Error converting pgscan value to uint64_t: %m");
}
- ctx->path = strdup(empty_to_root(path));
- if (!ctx->path)
- return -ENOMEM;
+ r = strdup_to(&ctx->path, empty_to_root(path));
+ if (r < 0)
+ return r;
*ret = TAKE_PTR(ctx);
return 0;
dns_name_endswith(dns_resource_key_name(key), "_udp.local");
}
+bool dns_resource_key_is_dnssd_two_label_ptr(const DnsResourceKey *key) {
+ assert(key);
+
+ /* Check if this is a PTR resource key used in Service Instance
+ * Enumeration as described in RFC6763 § 4.1, excluding selective
+ * service names described in RFC6763 § 7.1. */
+
+ if (key->type != DNS_TYPE_PTR)
+ return false;
+
+ const char *name = dns_resource_key_name(key);
+ if (dns_name_parent(&name) <= 0)
+ return false;
+
+ return dns_name_equal(name, "_tcp.local") || dns_name_equal(name, "_udp.local");
+}
+
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
int r;
const char* dns_resource_key_name(const DnsResourceKey *key);
bool dns_resource_key_is_address(const DnsResourceKey *key);
bool dns_resource_key_is_dnssd_ptr(const DnsResourceKey *key);
+bool dns_resource_key_is_dnssd_two_label_ptr(const DnsResourceKey *key);
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b);
int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain);
int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain);
continue;
}
- /* Collect service types for _services._dns-sd._udp.local RRs in a set */
+ /* Collect service types for _services._dns-sd._udp.local RRs in a set. Only two-label names
+ * (not selective names) are considered according to RFC6763 § 9. */
if (!scope->announced &&
- dns_resource_key_is_dnssd_ptr(z->rr->key)) {
+ dns_resource_key_is_dnssd_two_label_ptr(z->rr->key)) {
if (!set_contains(types, dns_resource_key_name(z->rr->key))) {
r = set_ensure_put(&types, &dns_name_hash_ops, dns_resource_key_name(z->rr->key));
if (r < 0)
return 1;
}
-static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) {
+static int dns_transaction_request_dnssec_rr_full(DnsTransaction *t, DnsResourceKey *key, DnsTransaction **ret) {
_cleanup_(dns_answer_unrefp) DnsAnswer *a = NULL;
DnsTransaction *aux;
int r;
r = dns_transaction_go(aux);
if (r < 0)
return r;
+ if (ret)
+ *ret = aux;
}
return 1;
}
+static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) {
+ assert(t);
+ assert(key);
+ return dns_transaction_request_dnssec_rr_full(t, key, NULL);
+}
+
static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const char *name) {
int r;
int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
DnsResourceRecord *rr;
+ /* Have we already requested a record that would be sufficient to validate an insecure delegation? */
+ bool chased_insecure = false;
int r;
assert(t);
* - For RRSIG we get the matching DNSKEY
* - For DNSKEY we get the matching DS
* - For unsigned SOA/NS we get the matching DS
- * - For unsigned CNAME/DNAME/DS we get the parent SOA RR
- * - For other unsigned RRs we get the matching SOA RR
+ * - For unsigned CNAME/DNAME/DS we get the parent DS RR
+ * - For other unsigned RRs we get the matching DS RR
* - For SOA/NS queries with no matching response RR, and no NSEC/NSEC3, the DS RR
- * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
- * - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR
+ * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's DS RR
+ * - For other queries with no matching response RRs, and no NSEC/NSEC3, the DS RR
*/
if (FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) || t->scope->dnssec_mode == DNSSEC_NO)
case DNS_TYPE_RRSIG: {
/* For each RRSIG we request the matching DNSKEY */
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *dnskey = NULL;
+ DnsTransaction *aux = NULL;
/* If this RRSIG is about a DNSKEY RR and the
* signer is the same as the owner, then we
log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").",
t->id, dns_resource_key_name(rr->key), rr->rrsig.key_tag);
- r = dns_transaction_request_dnssec_rr(t, dnskey);
+ r = dns_transaction_request_dnssec_rr_full(t, dnskey, &aux);
if (r < 0)
return r;
+
+ /* If we are requesting a DNSKEY, we can anticipate that we will want the matching DS
+ * in the near future. Let's request it in advance so we don't have to wait in the
+ * common case. */
+ if (aux) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds =
+ dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(dnskey));
+ r = dns_transaction_request_dnssec_rr(t, ds);
+ if (r < 0)
+ return r;
+ }
break;
}
if (r > 0)
continue;
+ chased_insecure = true;
ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
if (!ds)
return -ENOMEM;
case DNS_TYPE_DS:
case DNS_TYPE_CNAME:
case DNS_TYPE_DNAME: {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL;
const char *name;
/* CNAMEs and DNAMEs cannot be located at a
- * zone apex, hence ask for the parent SOA for
+ * zone apex, hence ask for the parent DS for
* unsigned CNAME/DNAME RRs, maybe that's the
* apex. But do all that only if this is
* actually a response to our original
if (r == 0)
continue;
- soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, name);
- if (!soa)
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, name);
+ if (!ds)
return -ENOMEM;
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).",
+ log_debug("Requesting parent DS to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).",
t->id, dns_resource_key_name(rr->key));
- r = dns_transaction_request_dnssec_rr(t, soa);
+ r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
}
default: {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL;
/* For other unsigned RRsets (including
* NSEC/NSEC3!), look for proof the zone is
- * unsigned, by requesting the SOA RR of the
+ * unsigned, by requesting the DS RR of the
* zone. However, do so only if they are
* directly relevant to our original
* question. */
if (r > 0)
continue;
- soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, dns_resource_key_name(rr->key));
- if (!soa)
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
+ if (!ds)
return -ENOMEM;
- log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).",
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).",
t->id, dns_resource_key_name(rr->key), dns_resource_record_to_string(rr));
- r = dns_transaction_request_dnssec_rr(t, soa);
+ r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
break;
if (r < 0)
return r;
if (r > 0) {
- const char *name, *signed_status;
- uint16_t type = 0;
-
- name = dns_resource_key_name(dns_transaction_key(t));
- signed_status = dns_answer_contains_nsec_or_nsec3(t->answer) ? "signed" : "unsigned";
-
- /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this
- * could also be used as indication that we are not at a zone apex, but in real world setups there are
- * too many broken DNS servers (Hello, incapdns.net!) where non-terminal zones return NXDOMAIN even
- * though they have further children. If this was a DS request, then it's signed when the parent zone
- * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR,
- * to see if that is signed. */
+ const char *name = dns_resource_key_name(dns_transaction_key(t));
+ bool was_signed = dns_answer_contains_nsec_or_nsec3(t->answer);
- if (dns_transaction_key(t)->type == DNS_TYPE_DS) {
- r = dns_name_parent(&name);
- if (r > 0) {
- type = DNS_TYPE_SOA;
- log_debug("Requesting parent SOA (%s %s) to validate transaction %" PRIu16 " (%s, %s empty DS response).",
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id,
- dns_resource_key_name(dns_transaction_key(t)), signed_status);
- } else
+ /* If the response is empty, seek the DS for this name, just in case we're at a zone cut
+ * already, unless we just requested the DS, in which case we have to ask the parent to make
+ * progress.
+ *
+ * If this was an SOA or NS request, we could also skip to the parent, but in real world
+ * setups there are too many broken DNS servers (Hello, incapdns.net!) where non-terminal
+ * zones return NXDOMAIN even though they have further children. */
+
+ if (chased_insecure || was_signed)
+ /* In this case we already requested what we need above. */
+ name = NULL;
+ else if (dns_transaction_key(t)->type == DNS_TYPE_DS)
+ /* If the DS response is empty, we'll walk up the dns labels requesting DS until we
+ * find a referral to the SOA or hit it anyway and get a positive DS response. */
+ if (dns_name_parent(&name) <= 0)
name = NULL;
- } else if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_SOA, DNS_TYPE_NS)) {
-
- type = DNS_TYPE_DS;
- log_debug("Requesting DS (%s %s) to validate transaction %" PRIu16 " (%s, %s empty SOA/NS response).",
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id, name, signed_status);
-
- } else {
- type = DNS_TYPE_SOA;
- log_debug("Requesting SOA (%s %s) to validate transaction %" PRIu16 " (%s, %s empty non-SOA/NS/DS response).",
- special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id, name, signed_status);
- }
-
if (name) {
- _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL;
- soa = dns_resource_key_new(dns_transaction_key(t)->class, type, name);
- if (!soa)
+ log_debug("Requesting DS (%s %s) to validate transaction %" PRIu16 " (%s empty response).",
+ special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), name, t->id,
+ dns_resource_key_name(dns_transaction_key(t)));
+
+ ds = dns_resource_key_new(dns_transaction_key(t)->class, DNS_TYPE_DS, name);
+ if (!ds)
return -ENOMEM;
- r = dns_transaction_request_dnssec_rr(t, soa);
+ r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
}
DnsTransaction *dt;
/* For SOA or NS RRs we look for a matching DS transaction */
-
SET_FOREACH(dt, t->dnssec_transactions) {
if (dns_transaction_key(dt)->class != rr->key->class)
if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), dns_resource_key_name(rr->key));
+ r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
DnsTransaction *dt;
/*
- * CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent SOA.
+ * CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent DS.
*
- * DS RRs are signed if the parent is signed, hence also look at the parent SOA
+ * DS RRs are signed if the parent is signed, hence also look at the parent DS
*/
SET_FOREACH(dt, t->dnssec_transactions) {
if (dns_transaction_key(dt)->class != rr->key->class)
continue;
- if (dns_transaction_key(dt)->type != DNS_TYPE_SOA)
+ if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
if (!parent) {
}
}
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), parent);
+ r = dns_name_endswith(parent, dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
default: {
DnsTransaction *dt;
- /* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our SOA lookup was authenticated */
+ /* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our DS lookup was authenticated */
SET_FOREACH(dt, t->dnssec_transactions) {
-
if (dns_transaction_key(dt)->class != rr->key->class)
continue;
- if (dns_transaction_key(dt)->type != DNS_TYPE_SOA)
+ if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), dns_resource_key_name(rr->key));
+ r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
continue;
- /* We found the transaction that was supposed to find the SOA RR for us. It was
- * successful, but found no RR for us. This means we are not at a zone cut. In this
- * case, we require authentication if the SOA lookup was authenticated too. */
- return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+ if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
+ return false;
+
+ /* We expect this to be signed when the DS record exists, and don't expect it to be
+ * signed when the DS record is proven not to exist. */
+ return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL);
}
return true;
char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsTransaction *dt;
const char *name;
- uint16_t type = 0;
int r;
assert(t);
name = dns_resource_key_name(dns_transaction_key(t));
- if (dns_transaction_key(t)->type == DNS_TYPE_DS) {
-
- /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed,
- * hence check the parent SOA in this case. */
-
+ if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_DS, DNS_TYPE_CNAME, DNS_TYPE_DNAME)) {
+ /* We got a negative reply for this DS/CNAME/DNAME lookup? Check the parent in this case to
+ * see if this answer should have been signed. */
r = dns_name_parent(&name);
if (r < 0)
return r;
if (r == 0)
return true;
+ }
- type = DNS_TYPE_SOA;
-
- } else if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_SOA, DNS_TYPE_NS))
- /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */
- type = DNS_TYPE_DS;
- else
- /* For all other negative replies, check for the SOA lookup */
- type = DNS_TYPE_SOA;
-
- /* For all other RRs we check the SOA on the same level to see
+ /* For all other RRs we check the DS on the same level to see
* if it's signed. */
SET_FOREACH(dt, t->dnssec_transactions) {
-
if (dns_transaction_key(dt)->class != dns_transaction_key(t)->class)
continue;
- if (dns_transaction_key(dt)->type != type)
+ if (dns_transaction_key(dt)->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), name);
+ r = dns_name_endswith(name, dns_resource_key_name(dns_transaction_key(dt)));
if (r < 0)
return r;
if (r == 0)
continue;
- return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED);
+ if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
+ return false;
+
+ /* We expect this to be signed when the DS record exists, and don't expect it to be signed
+ * when the DS record is proven not to exist. */
+ return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL);
}
/* If in doubt, require NSEC/NSEC3 */
static int specifier_dnssd_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const Manager *m = ASSERT_PTR(userdata);
- char *n;
assert(m->llmnr_hostname);
- n = strdup(m->llmnr_hostname);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, m->llmnr_hostname);
}
int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret) {
meson.add_install_script(sh, '-c',
ln_s.format(bindir / 'systemd-run',
- bindir / 'uid0'))
+ bindir / 'run0'))
custom_target(
- 'systemd-uid0',
- input : 'systemd-uid0.in',
- output : 'systemd-uid0',
+ 'systemd-run0',
+ input : 'systemd-run0.in',
+ output : 'systemd-run0',
command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : pamconfdir != 'no',
install_dir : pamconfdir)
_cleanup_free_ char *link = NULL;
int r;
- r = terminal_urlify_man("uid0", "1", &link);
+ r = terminal_urlify_man("run0", "1", &link);
if (r < 0)
return log_oom();
ARG_BACKGROUND,
};
- /* If invoked as "uid0" binary, let's expose a more sudo-like interface. We add various extensions
+ /* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
* though (but limit the extension to long options). */
static const struct option options[] = {
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_USER=%s", un) < 0)
return log_oom();
- if (strv_extend(&arg_property, "PAMName=systemd-uid0") < 0)
+ if (strv_extend(&arg_property, "PAMName=systemd-run0") < 0)
return log_oom();
if (!arg_background && arg_stdio == ARG_STDIO_PTY) {
if (r < 0)
return r;
- if (allow_pidfd) {
- _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- r = pidref_set_self(&pidref);
- if (r < 0)
- return r;
+ r = pidref_set_self(&pidref);
+ if (r < 0)
+ return r;
- r = bus_append_scope_pidref(m, &pidref);
- } else
- r = sd_bus_message_append(
- m, "(sv)",
- "PIDs", "au", 1, getpid_cached());
+ r = bus_append_scope_pidref(m, &pidref, allow_pidfd);
if (r < 0)
return bus_log_create_error(r);
log_parse_environment();
log_open();
- if (invoked_as(argv, "uid0"))
+ if (invoked_as(argv, "run0"))
r = parse_argv_sudo_mode(argc, argv);
else
r = parse_argv(argc, argv);
# SPDX-License-Identifier: LGPL-2.1-or-later
# This file is part of systemd.
#
-# Used by uid0 sessions
+# Used by run0 sessions
{% if ENABLE_HOMED %}
-account sufficient pam_systemd_home.so
return 0;
}
-int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref) {
+int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
assert(m);
if (!pidref_is_set(pidref))
return -ESRCH;
- if (pidref->fd >= 0)
+ if (pidref->fd >= 0 && allow_pidfd)
return sd_bus_message_append(
m, "(sv)",
"PIDFDs", "ah", 1, pidref->fd);
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment);
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l);
-int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref);
+int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd);
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet);
DLSYM_FUNCTION(crypt_keyslot_max);
DLSYM_FUNCTION(crypt_load);
DLSYM_FUNCTION(crypt_resize);
-DLSYM_FUNCTION(crypt_resume_by_passphrase);
+#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY
+DLSYM_FUNCTION(crypt_resume_by_volume_key);
+#endif
DLSYM_FUNCTION(crypt_set_data_device);
DLSYM_FUNCTION(crypt_set_debug_level);
DLSYM_FUNCTION(crypt_set_log_callback);
DLSYM_ARG(crypt_keyslot_max),
DLSYM_ARG(crypt_load),
DLSYM_ARG(crypt_resize),
- DLSYM_ARG(crypt_resume_by_passphrase),
+#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY
+ DLSYM_ARG(crypt_resume_by_volume_key),
+#endif
DLSYM_ARG(crypt_set_data_device),
DLSYM_ARG(crypt_set_debug_level),
DLSYM_ARG(crypt_set_log_callback),
DLSYM_PROTOTYPE(crypt_keyslot_max);
DLSYM_PROTOTYPE(crypt_load);
DLSYM_PROTOTYPE(crypt_resize);
-DLSYM_PROTOTYPE(crypt_resume_by_passphrase);
+#if HAVE_CRYPT_RESUME_BY_VOLUME_KEY
+DLSYM_PROTOTYPE(crypt_resume_by_volume_key);
+#endif
DLSYM_PROTOTYPE(crypt_set_data_device);
DLSYM_PROTOTYPE(crypt_set_debug_level);
DLSYM_PROTOTYPE(crypt_set_log_callback);
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
if (fstype) {
- char *t;
-
log_debug("Probed fstype '%s' on partition %s.", fstype, path);
-
- t = strdup(fstype);
- if (!t)
- return -ENOMEM;
-
- *ret_fstype = t;
- return 1;
+ return strdup_to_full(ret_fstype, fstype);
}
not_found:
r = dissected_image_mount(m, where, uid_shift, uid_range, userns_fd, flags);
if (r == -ENXIO)
- return log_error_errno(r, "Not root file system found in image.");
+ return log_error_errno(r, "Failed to mount image: No root file system found in image.");
if (r == -EMEDIUMTYPE)
- return log_error_errno(r, "No suitable os-release/extension-release file in image found.");
+ return log_error_errno(r, "Failed to mount image: No suitable os-release/extension-release file in image found.");
if (r == -EUNATCH)
- return log_error_errno(r, "Encrypted file system discovered, but decryption not requested.");
+ return log_error_errno(r, "Failed to mount image: Encrypted file system discovered, but decryption not requested.");
if (r == -EUCLEAN)
- return log_error_errno(r, "File system check on image failed.");
+ return log_error_errno(r, "Failed to mount image: File system check on image failed.");
if (r == -EBUSY)
- return log_error_errno(r, "File system already mounted elsewhere.");
+ return log_error_errno(r, "Failed to mount image: File system already mounted elsewhere.");
if (r == -EAFNOSUPPORT)
- return log_error_errno(r, "File system type not supported or not known.");
+ return log_error_errno(r, "Failed to mount image: File system type not supported or not known.");
if (r == -EIDRM)
- return log_error_errno(r, "File system is too uncommon, refused.");
+ return log_error_errno(r, "Failed to mount image: File system is too uncommon, refused.");
if (r < 0)
return log_error_errno(r, "Failed to mount image: %m");
struct ifreq ifr = {
.ifr_data = (void*) &ecmd,
};
- char *d;
int r;
assert(ethtool_fd);
if (isempty(ecmd.driver))
return -ENODATA;
- d = strdup(ecmd.driver);
- if (!d)
- return -ENOMEM;
-
- *ret = d;
- return 0;
+ return strdup_to(ret, ecmd.driver);
}
int ethtool_get_link_info(
static int specifier_name(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const InstallInfo *i = ASSERT_PTR(userdata);
- char *ans;
if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance)
return unit_name_replace_instance(i->name, i->default_instance, ret);
- ans = strdup(i->name);
- if (!ans)
- return -ENOMEM;
- *ret = ans;
- return 0;
+ return strdup_to(ret, i->name);
}
static int specifier_prefix(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
return r;
dash = strrchr(prefix, '-');
- if (dash) {
- dash = strdup(dash + 1);
- if (!dash)
- return -ENOMEM;
- *ret = dash;
- } else
- *ret = TAKE_PTR(prefix);
+ if (dash)
+ return strdup_to(ret, dash + 1);
+ *ret = TAKE_PTR(prefix);
return 0;
}
if (r < 0)
return r;
- return path_equal_ptr(parent, lp->generator) ||
- path_equal_ptr(parent, lp->generator_early) ||
- path_equal_ptr(parent, lp->generator_late);
+ return PATH_IN_SET(parent,
+ lp->generator,
+ lp->generator_early,
+ lp->generator_late);
}
static int path_is_transient(const LookupPaths *lp, const char *path) {
if (r < 0)
return r;
- return path_equal_ptr(parent, lp->transient);
+ return path_equal(parent, lp->transient);
}
static int path_is_control(const LookupPaths *lp, const char *path) {
if (r < 0)
return r;
- return path_equal_ptr(parent, lp->persistent_control) ||
- path_equal_ptr(parent, lp->runtime_control);
+ return PATH_IN_SET(parent,
+ lp->persistent_control,
+ lp->runtime_control);
}
static int path_is_config(const LookupPaths *lp, const char *path, bool check_parent) {
path = parent;
}
- return path_equal_ptr(path, lp->persistent_config) ||
- path_equal_ptr(path, lp->runtime_config);
+ return PATH_IN_SET(path,
+ lp->persistent_config,
+ lp->runtime_config);
}
static int path_is_runtime(const LookupPaths *lp, const char *path, bool check_parent) {
path = parent;
}
- return path_equal_ptr(path, lp->runtime_config) ||
- path_equal_ptr(path, lp->generator) ||
- path_equal_ptr(path, lp->generator_early) ||
- path_equal_ptr(path, lp->generator_late) ||
- path_equal_ptr(path, lp->transient) ||
- path_equal_ptr(path, lp->runtime_control);
+ return PATH_IN_SET(path,
+ lp->runtime_config,
+ lp->generator,
+ lp->generator_early,
+ lp->generator_late,
+ lp->transient,
+ lp->runtime_control);
}
static int path_is_vendor_or_generator(const LookupPaths *lp, const char *path) {
if (r > 0) {
/* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
- if (path_equal_ptr(*p, lp->persistent_config)) {
+ if (path_equal(*p, lp->persistent_config)) {
/* This is the best outcome, let's return it immediately. */
*state = UNIT_FILE_ENABLED;
return 1;
enabled_at_all = true;
} else if (same_name_link) {
- if (path_equal_ptr(*p, lp->persistent_config))
+ if (path_equal(*p, lp->persistent_config))
same_name_link_config = true;
else {
r = path_is_runtime(lp, *p, false);
int unit_file_get_default(
RuntimeScope scope,
const char *root_dir,
- char **name) {
+ char **ret) {
_cleanup_(lookup_paths_done) LookupPaths lp = {};
_cleanup_(install_context_done) InstallContext ctx = { .scope = scope };
InstallInfo *info;
- char *n;
int r;
assert(scope >= 0);
assert(scope < _RUNTIME_SCOPE_MAX);
- assert(name);
+ assert(ret);
r = lookup_paths_init(&lp, scope, 0, root_dir);
if (r < 0)
if (r < 0)
return r;
- n = strdup(info->name);
- if (!n)
- return -ENOMEM;
-
- *name = n;
- return 0;
+ return strdup_to(ret, info->name);
}
int unit_file_lookup_state(
if (ret_path) {
assert(info);
- _cleanup_free_ char *p = strdup(info->path);
- if (!p)
- return -ENOMEM;
-
- *ret_path = TAKE_PTR(p);
+ r = strdup_to(ret_path, info->path);
+ if (r < 0)
+ return r;
}
return 1;
int unit_file_get_default(
RuntimeScope scope,
const char *root_dir,
- char **name);
+ char **ret);
int unit_file_add_dependency(
RuntimeScope scope,
UnitFileFlags flags,
int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) {
_cleanup_free_ char *salt = NULL;
_cleanup_(erase_and_freep) void *_cd_data = NULL;
- char *p;
+ const char *p;
int r, _cd_size = 0;
assert(!!cd_data == !!cd_size);
return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)),
CRYPT_RA_NAME "() failed: %m");
- p = strdup(p);
- if (!p)
- return -ENOMEM;
-
- *ret = p;
- return 0;
+ return strdup_to(ret, p);
}
bool looks_like_hashed_password(const char *s) {
if (device &&
sd_device_get_devtype(device, &t) >= 0 &&
- !isempty(t)) {
- p = strdup(t);
- if (!p)
- return -ENOMEM;
-
- *ret = p;
- return 0;
- }
+ !isempty(t))
+ return strdup_to(ret, t);
t = arphrd_to_name(iftype);
if (!t)
_cleanup_strv_free_erase_ char **suggestions = NULL;
_cleanup_(erase_and_freep) char *joined = NULL;
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
- size_t i;
int r;
r = pwq_allocate_context(&pwq);
if (!suggestions)
return log_oom();
- for (i = 0; i < N_SUGGESTIONS; i++) {
+ for (size_t i = 0; i < N_SUGGESTIONS; i++) {
r = sym_pwquality_generate(pwq, 64, suggestions + i);
if (r < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring: %s",
r = sym_pwquality_check(pwq, password, old, username, &auxerror);
if (r < 0) {
if (ret_error) {
- _cleanup_free_ char *e = NULL;
-
- e = strdup(sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
- if (!e)
- return -ENOMEM;
-
- *ret_error = TAKE_PTR(e);
+ r = strdup_to(ret_error,
+ sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
+ if (r < 0)
+ return r;
}
return 0; /* all bad */
if (isempty(text))
text = path;
- if (!urlify_enabled()) {
- char *n;
-
- n = strdup(text);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
- }
+ if (!urlify_enabled())
+ return strdup_to(ret, text);
r = file_url_from_path(path, &url);
if (r < 0)
return (int) l;
}
-static int insert_newline_color_erase(PTYForward *f, size_t offset) {
+static int insert_background_color(PTYForward *f, size_t offset) {
_cleanup_free_ char *s = NULL;
assert(f);
if (!f->background_color)
return 0;
- /* When we see a newline (ASCII 10) then this sets the background color to the desired one, and erase the rest
- * of the line with it */
-
- s = background_color_sequence(f);
- if (!s)
- return -ENOMEM;
-
- if (!strextend(&s, ANSI_ERASE_TO_END_OF_LINE))
- return -ENOMEM;
-
- return insert_string(f, offset, s);
-}
-
-static int insert_carriage_return_color(PTYForward *f, size_t offset) {
- _cleanup_free_ char *s = NULL;
-
- assert(f);
-
- if (!f->background_color)
- return 0;
-
- /* When we see a carriage return (ASCII 13) then this sets only the background */
-
s = background_color_sequence(f);
if (!s)
return -ENOMEM;
case ANSI_COLOR_STATE_TEXT:
break;
- case ANSI_COLOR_STATE_NEWLINE: {
- /* Immediately after a newline insert an ANSI sequence to erase the line with a background color */
-
- r = insert_newline_color_erase(f, i);
- if (r < 0)
- return r;
-
- i += r;
- break;
- }
-
- case ANSI_COLOR_STATE_CARRIAGE_RETURN: {
- /* Immediately after a carriage return insert an ANSI sequence set the background color back */
+ case ANSI_COLOR_STATE_NEWLINE:
+ case ANSI_COLOR_STATE_CARRIAGE_RETURN:
+ /* Immediately after a newline (ASCII 10) or carriage return (ASCII 13) insert an
+ * ANSI sequence set the background color back. */
- r = insert_carriage_return_color(f, i);
+ r = insert_background_color(f, i);
if (r < 0)
return r;
i += r;
break;
- }
- case ANSI_COLOR_STATE_ESC: {
+ case ANSI_COLOR_STATE_ESC:
if (c == '[') {
f->ansi_color_state = ANSI_COLOR_STATE_CSI_SEQUENCE;
f->ansi_color_state = ANSI_COLOR_STATE_OSC_SEQUENCE;
continue;
}
-
break;
- }
- case ANSI_COLOR_STATE_CSI_SEQUENCE: {
+ case ANSI_COLOR_STATE_CSI_SEQUENCE:
if (c >= 0x20 && c <= 0x3F) {
/* If this is a "parameter" or "intermediary" byte (i.e. ranges 0x20…0x2F and
f->csi_sequence = mfree(f->csi_sequence);
f->ansi_color_state = ANSI_COLOR_STATE_TEXT;
}
-
continue;
- }
- case ANSI_COLOR_STATE_OSC_SEQUENCE: {
+ case ANSI_COLOR_STATE_OSC_SEQUENCE:
if ((uint8_t) c >= ' ') {
if (strlen_ptr(f->osc_sequence) >= 64) {
f->osc_sequence = mfree(f->osc_sequence);
f->ansi_color_state = ANSI_COLOR_STATE_TEXT;
}
-
continue;
- }
default:
assert_not_reached();
/* Generic handler for simple string replacements */
int specifier_string(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
- char *n = NULL;
-
- assert(ret);
-
- if (!isempty(data)) {
- n = strdup(data);
- if (!n)
- return -ENOMEM;
- }
-
- *ret = n;
- return 0;
+ return strdup_to(ASSERT_PTR(ret), empty_to_null(data));
}
int specifier_real_path(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
int specifier_kernel_release(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
struct utsname uts;
- char *n;
assert(ret);
if (uname(&uts) < 0)
return -errno;
- n = strdup(uts.release);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return strdup_to(ret, uts.release);
}
int specifier_architecture(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
- char *t;
-
- assert(ret);
-
- t = strdup(architecture_to_string(uname_architecture()));
- if (!t)
- return -ENOMEM;
-
- *ret = t;
- return 0;
+ return strdup_to(ASSERT_PTR(ret),
+ architecture_to_string(uname_architecture()));
}
/* Note: fields in /etc/os-release might quite possibly be missing, even if everything is entirely valid
int specifier_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const char *p;
- char *copy;
int r;
assert(ret);
if (r < 0)
return r;
}
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
- *ret = copy;
- return 0;
+ return strdup_to(ret, p);
}
int specifier_var_tmp_dir(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
const char *p;
- char *copy;
int r;
assert(ret);
if (r < 0)
return r;
}
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
- *ret = copy;
- return 0;
+ return strdup_to(ret, p);
}
int specifier_escape_strv(char **l, char ***ret) {
DEFINE_TEST_MAIN_FULL(log_level, intro, NULL)
#define DEFINE_TEST_MAIN(log_level) \
DEFINE_TEST_MAIN_FULL(log_level, NULL, NULL)
+
+#define ASSERT_OK(expr) \
+ ({ \
+ typeof(expr) _result = (expr); \
+ if (_result < 0) { \
+ log_error_errno(_result, "%s:%i: Assertion failed: %s: %m", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_TRUE(expr) \
+ ({ \
+ if (!(expr)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be true", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_FALSE(expr) \
+ ({ \
+ if ((expr)) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be false", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NULL(expr) \
+ ({ \
+ if ((expr) != NULL) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be NULL", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NOT_NULL(expr) \
+ ({ \
+ if ((expr) == NULL) { \
+ log_error("%s:%i: Assertion failed: expected \"%s\" to be not NULL", \
+ PROJECT_FILE, __LINE__, #expr); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_STREQ(expr1, expr2) \
+ ({ \
+ const char* _expr1 = (expr1); \
+ const char* _expr2 = (expr2); \
+ if (strcmp(_expr1, _expr2) != 0) { \
+ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _expr1, _expr2); \
+ abort(); \
+ } \
+ })
+
+/* DECIMAL_STR_FMT() uses _Generic which cannot be used in string concatenation so we have to format the
+ * input into strings first and then format those into the final assertion message. */
+
+#define ASSERT_EQ(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 != _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s == %s\", but \"%s != %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_GE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 < _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s >= %s\", but \"%s < %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_LE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 > _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s <= %s\", but \"%s > %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_NE(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (_expr1 == _expr2) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s != %s\", but \"%s == %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_GT(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (!(_expr1 > _expr2)) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s > %s\", but \"%s <= %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
+
+#define ASSERT_LT(expr1, expr2) \
+ ({ \
+ typeof(expr1) _expr1 = (expr1); \
+ typeof(expr2) _expr2 = (expr2); \
+ if (!(_expr1 < _expr2)) { \
+ char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
+ char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
+ xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
+ xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
+ log_error("%s:%i: Assertion failed: expected \"%s < %s\", but \"%s >= %s\"", \
+ PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
+ abort(); \
+ } \
+ })
if (r < 0)
return r;
- _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
- r = tpm2_make_encryption_session(c, primary_handle, hmac_key, &encryption_session);
- if (r < 0)
- return r;
-
_cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL;
for (unsigned i = RETRY_UNSEAL_MAX;; i--) {
+ _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
+ r = tpm2_make_encryption_session(c, primary_handle, hmac_key, &encryption_session);
+ if (r < 0)
+ return r;
+
_cleanup_(tpm2_handle_freep) Tpm2Handle *policy_session = NULL;
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
r = tpm2_make_policy_session(
}
_cleanup_free_ char *desc = NULL;
- if (asprintf(&desc, "%s-%i", server->description ?: "varlink", v->fd) >= 0)
+ if (asprintf(&desc, "%s-%i", varlink_server_description(server), v->fd) >= 0)
v->description = TAKE_PTR(desc);
/* Link up the server and the connection, and take reference in both directions. Note that the
"Description=OpenSSH Per-Connection Server Daemon\n"
"Documentation=man:systemd-ssh-generator(8) man:sshd(8)\n"
"[Service]\n"
- "ExecStart=-%s -i\n"
- "StandardInput=socket",
+ "ExecStart=-%s -i -o \"AuthorizedKeysFile ${CREDENTIALS_DIRECTORY}/ssh.ephemeral-authorized_keys-all .ssh/authorized_keys\"\n"
+ "StandardInput=socket\n"
+ "ImportCredential=ssh.ephemeral-authorized_keys-all",
sshd_binary);
r = fflush_and_check(f);
const char *a_shell = pick_shell(a),
*b_shell = pick_shell(b);
- if (!path_equal_ptr(a_shell, b_shell) &&
+ if (!path_equal(a_shell, b_shell) &&
!(is_nologin_shell(a_shell) && is_nologin_shell(b_shell))) {
_cleanup_free_ char *pa = NULL, *pb = NULL;
'test-psi-util.c',
'test-ratelimit.c',
'test-raw-clone.c',
+ 'test-recovery-key.c',
'test-recurse-dir.c',
'test-replace-var.c',
'test-rlimit-util.c',
TEST(mask_supported, .sd_booted = true) {
CGroupMask m;
- CGroupController c;
assert_se(cg_mask_supported(&m) >= 0);
- for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
- printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
+ for (CGroupController c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
+ printf("'%s' is supported: %s\n",
+ cgroup_controller_to_string(c),
+ yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
}
TEST(is_cgroup_fs, .sd_booted = true) {
TEST(cg_get_keyed_attribute) {
_cleanup_free_ char *val = NULL;
char *vals3[3] = {}, *vals3a[3] = {};
- int i, r;
+ int r;
r = cg_get_keyed_attribute("cpu", "/init.scope", "no_such_file", STRV_MAKE("no_such_attr"), &val);
if (IN_SET(r, -ENOMEDIUM, -ENOENT) || ERRNO_IS_PRIVILEGE(r)) {
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0);
- for (i = 0; i < 3; i++)
+ for (size_t i = 0; i < 3; i++)
free(vals3[i]);
assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0);
- for (i = 0; i < 3; i++)
+ for (size_t i = 0; i < 3; i++)
free(vals3a[i]);
assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"",
vals3a[0], vals3a[1], vals3a[2]);
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
free(vals3[i]);
free(vals3a[i]);
}
log_debug("/* create source from %s */", srcfile);
- assert_se((src = open(srcfile, O_RDONLY|O_CLOEXEC)) >= 0);
+ ASSERT_OK((src = open(srcfile, O_RDONLY|O_CLOEXEC)));
log_debug("/* test compression */");
assert_se((dst = mkostemp_safe(pattern)) >= 0);
- assert_se(compress(src, dst, -1, &uncompressed_size) >= 0);
+ ASSERT_OK(compress(src, dst, -1, &uncompressed_size));
if (cat) {
assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
printf("%s %s\n", GREEN_CHECK_MARK(), joined);
if (streq(prefix, "root-") && streq(suffix, ""))
- assert_se(type.designator == PARTITION_ROOT);
+ ASSERT_EQ(type.designator, PARTITION_ROOT);
if (streq(prefix, "root-") && streq(suffix, "-verity"))
- assert_se(type.designator == PARTITION_ROOT_VERITY);
+ ASSERT_EQ(type.designator, PARTITION_ROOT_VERITY);
if (streq(prefix, "usr-") && streq(suffix, ""))
- assert_se(type.designator == PARTITION_USR);
+ ASSERT_EQ(type.designator, PARTITION_USR);
if (streq(prefix, "usr-") && streq(suffix, "-verity"))
- assert_se(type.designator == PARTITION_USR_VERITY);
+ ASSERT_EQ(type.designator, PARTITION_USR_VERITY);
- assert_se(type.arch == a);
+ ASSERT_EQ(type.arch, a);
}
}
GptPartitionType x, y;
x = gpt_partition_type_from_uuid(t->uuid); /* search first by uuid */
- assert_se(gpt_partition_type_from_string(t->name, &y) >= 0); /* search first by name */
+ ASSERT_GE(gpt_partition_type_from_string(t->name, &y), 0); /* search first by name */
- assert_se(t->arch == x.arch);
- assert_se(t->arch == y.arch);
- assert_se(t->designator == x.designator);
- assert_se(t->designator == y.designator);
+ ASSERT_EQ(t->arch, x.arch);
+ ASSERT_EQ(t->arch, y.arch);
+ ASSERT_EQ(t->designator, x.designator);
+ ASSERT_EQ(t->designator, y.designator);
}
}
TEST(override_architecture) {
GptPartitionType x, y;
- assert_se(gpt_partition_type_from_string("root-x86-64", &x) >= 0);
- assert_se(x.arch == ARCHITECTURE_X86_64);
+ ASSERT_GE(gpt_partition_type_from_string("root-x86-64", &x), 0);
+ ASSERT_EQ(x.arch, ARCHITECTURE_X86_64);
- assert_se(gpt_partition_type_from_string("root-arm64", &y) >= 0);
- assert(y.arch == ARCHITECTURE_ARM64);
+ ASSERT_GE(gpt_partition_type_from_string("root-arm64", &y), 0);
+ ASSERT_EQ(y.arch, ARCHITECTURE_ARM64);
x = gpt_partition_type_override_architecture(x, ARCHITECTURE_ARM64);
- assert_se(x.arch == y.arch);
- assert_se(x.designator == y.designator);
+ ASSERT_EQ(x.arch, y.arch);
+ ASSERT_EQ(x.designator, y.designator);
assert_se(sd_id128_equal(x.uuid, y.uuid));
assert_se(streq(x.name, y.name));
/* If the partition type does not have an architecture, nothing should change. */
- assert_se(gpt_partition_type_from_string("esp", &x) >= 0);
+ ASSERT_GE(gpt_partition_type_from_string("esp", &x), 0);
y = x;
x = gpt_partition_type_override_architecture(x, ARCHITECTURE_ARM64);
- assert_se(x.arch == y.arch);
- assert_se(x.designator == y.designator);
+ ASSERT_EQ(x.arch, y.arch);
+ ASSERT_EQ(x.designator, y.designator);
assert_se(sd_id128_equal(x.uuid, y.uuid));
assert_se(streq(x.name, y.name));
}
}
TEST(string_compare_func) {
- assert_se(string_compare_func("fred", "wilma") != 0);
+ ASSERT_NE(string_compare_func("fred", "wilma"), 0);
assert_se(string_compare_func("fred", "fred") == 0);
}
"",
result);
hex_result = hexmem(result, sizeof(result));
- assert_se(streq_ptr(hex_result, "cadd5e42114351181f3abff477641d88efb57d2b5641a1e5c6d623363a6d3bad"));
+ ASSERT_STREQ(hex_result, "cadd5e42114351181f3abff477641d88efb57d2b5641a1e5c6d623363a6d3bad");
hex_result = mfree(hex_result);
hmac_sha256_by_string("waldo",
assert(dir_path);
dir_fd = RET_NERRNO(open_mkdir_at(AT_FDCWD, dir_path, O_CLOEXEC, mode));
if (dir_fd < 0)
- return log_error_errno(dir_fd, "Error occured while opening directory =>: %m");
+ return log_error_errno(dir_fd, "Error occurred while opening directory =>: %m");
return dir_fd;
}
/* Write data to the file*/
count = RET_NERRNO(write(write_fd, text, strlen(text)));
if (count < 0)
- return log_error_errno(count, "Error occured while opening file for writing =>: %m");
+ return log_error_errno(count, "Error occurred while opening file for writing =>: %m");
return 0;
}
*/
/* file mountpoints */
- assert_se(mkdtemp(tmp_dir) != NULL);
+ ASSERT_NOT_NULL(mkdtemp(tmp_dir));
file1 = path_join(tmp_dir, "file1");
assert_se(file1);
file2 = path_join(tmp_dir, "file2");
#include "tmpfile-util.h"
TEST(path_is_os_tree) {
- assert_se(path_is_os_tree("/") > 0);
- assert_se(path_is_os_tree("/etc") == 0);
+ ASSERT_GT(path_is_os_tree("/"), 0);
+ ASSERT_EQ(path_is_os_tree("/etc"), 0);
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
TEST(parse_os_release) {
/* Let's assume that we're running in a valid system, so os-release is available */
_cleanup_free_ char *id = NULL, *id2 = NULL, *name = NULL, *foobar = NULL;
- assert_se(parse_os_release(NULL, "ID", &id) == 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id), 0);
log_info("ID: %s", id);
- assert_se(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1) == 0);
- assert_se(parse_os_release(NULL, "ID", &id2) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", "/dev/null", 1), 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id2), 0);
log_info("ID: %s", strnull(id2));
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
- assert_se(write_tmpfile(tmpfile,
+ ASSERT_EQ(write_tmpfile(tmpfile,
"ID=the-id \n"
- "NAME=the-name") == 0);
+ "NAME=the-name"), 0);
- assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
- assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1), 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id, "NAME", &name), 0);
log_info("ID: %s NAME: %s", id, name);
assert_se(streq(id, "the-id"));
assert_se(streq(name, "the-name"));
_cleanup_(unlink_tempfilep) char tmpfile2[] = "/tmp/test-os-util.XXXXXX";
- assert_se(write_tmpfile(tmpfile2,
+ ASSERT_EQ(write_tmpfile(tmpfile2,
"ID=\"ignored\" \n"
"ID=\"the-id\" \n"
- "NAME='the-name'") == 0);
+ "NAME='the-name'"), 0);
- assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1) == 0);
- assert_se(parse_os_release(NULL, "ID", &id, "NAME", &name) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", tmpfile2, 1), 0);
+ ASSERT_EQ(parse_os_release(NULL, "ID", &id, "NAME", &name), 0);
log_info("ID: %s NAME: %s", id, name);
assert_se(streq(id, "the-id"));
assert_se(streq(name, "the-name"));
- assert_se(parse_os_release(NULL, "FOOBAR", &foobar) == 0);
+ ASSERT_EQ(parse_os_release(NULL, "FOOBAR", &foobar), 0);
log_info("FOOBAR: %s", strnull(foobar));
- assert_se(foobar == NULL);
+ ASSERT_NULL(foobar);
assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
}
assert_se(a = path_join(tempdir, "/usr/lib/extension-release.d/extension-release.test"));
assert_se(mkdir_parents(a, 0777) >= 0);
+ ASSERT_GE(mkdir_parents(a, 0777), 0);
r = write_string_file(a, "ID=the-id \n VERSION_ID=the-version-id", WRITE_STRING_FILE_CREATE);
if (r < 0)
if (r < 0)
log_error_errno(r, "Failed to write file: %m");
- assert_se(parse_extension_release(tempdir, IMAGE_CONFEXT, "tester", false, "ID", &id, "VERSION_ID", &version_id) == 0);
+ ASSERT_EQ(parse_extension_release(tempdir, IMAGE_CONFEXT, "tester", false, "ID", &id, "VERSION_ID", &version_id), 0);
log_info("ID: %s VERSION_ID: %s", id, version_id);
assert_se(streq(id, "the-id"));
assert_se(streq(version_id, "the-version-id"));
assert_se(parse_extension_release(tempdir, IMAGE_CONFEXT, "tester", false, "FOOBAR", &foobar) == 0);
log_info("FOOBAR: %s", strnull(foobar));
- assert_se(foobar == NULL);
+ ASSERT_NULL(foobar);
assert_se(parse_extension_release(tempdir, IMAGE_SYSEXT, "test", false, "FOOBAR", &foobar) == 0);
log_info("FOOBAR: %s", strnull(foobar));
- assert_se(foobar == NULL);
+ ASSERT_NULL(foobar);
}
TEST(load_os_release_pairs) {
_cleanup_(unlink_tempfilep) char tmpfile[] = "/tmp/test-os-util.XXXXXX";
- assert_se(write_tmpfile(tmpfile,
+ ASSERT_EQ(write_tmpfile(tmpfile,
"ID=\"ignored\" \n"
"ID=\"the-id\" \n"
- "NAME='the-name'") == 0);
+ "NAME='the-name'"), 0);
- assert_se(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1) == 0);
+ ASSERT_EQ(setenv("SYSTEMD_OS_RELEASE", tmpfile, 1), 0);
_cleanup_strv_free_ char **pairs = NULL;
- assert_se(load_os_release_pairs(NULL, &pairs) == 0);
+ ASSERT_EQ(load_os_release_pairs(NULL, &pairs), 0);
assert_se(strv_equal(pairs, STRV_MAKE("ID", "the-id",
"NAME", "the-name")));
- assert_se(unsetenv("SYSTEMD_OS_RELEASE") == 0);
+ ASSERT_EQ(unsetenv("SYSTEMD_OS_RELEASE"), 0);
}
TEST(os_release_support_ended) {
int r;
- assert_se(os_release_support_ended("1999-01-01", false, NULL) == true);
- assert_se(os_release_support_ended("2037-12-31", false, NULL) == false);
+ ASSERT_TRUE(os_release_support_ended("1999-01-01", false, NULL));
+ ASSERT_FALSE(os_release_support_ended("2037-12-31", false, NULL));
assert_se(os_release_support_ended("-1-1-1", true, NULL) == -EINVAL);
r = os_release_support_ended(NULL, false, NULL);
}
TEST(path) {
- assert_se(path_is_absolute("/"));
+ assert_se( path_is_absolute("/"));
assert_se(!path_is_absolute("./"));
assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
assert_se(streq(basename("/aa///file..."), "file..."));
assert_se(streq(basename("file.../"), ""));
- assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
- assert_se(PATH_IN_SET("/bin", "/bin"));
- assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
- assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
+ assert_se( PATH_IN_SET("/bin", "/", "/bin", "/foo"));
+ assert_se( PATH_IN_SET("/bin", "/bin"));
+ assert_se( PATH_IN_SET("/bin", "/foo/bar", "/bin"));
+ assert_se( PATH_IN_SET("/", "/", "/", "/foo/bar"));
assert_se(!PATH_IN_SET("/", "/abc", "/def"));
- assert_se(path_equal_ptr(NULL, NULL));
- assert_se(path_equal_ptr("/a", "/a"));
- assert_se(!path_equal_ptr("/a", "/b"));
- assert_se(!path_equal_ptr("/a", NULL));
- assert_se(!path_equal_ptr(NULL, "/a"));
+ assert_se( path_equal(NULL, NULL));
+ assert_se( path_equal("/a", "/a"));
+ assert_se(!path_equal("/a", "/b"));
+ assert_se(!path_equal("/a", NULL));
+ assert_se(!path_equal(NULL, "/a"));
+ assert_se(!path_equal("a", NULL));
+ assert_se(!path_equal(NULL, "a"));
}
TEST(is_path) {
log_error("---%s---", s);
assert_se(streq(s, values[i++]));
}
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
i = 1;
PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
log_error("---%s---", s);
assert_se(streq(s, values[i++]));
}
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
i = 0;
PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
assert_se(streq(s, values[i++]));
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
i = 1;
PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
assert_se(streq(s, values[i++]));
- assert_se(values[i] == NULL);
+ ASSERT_NULL(values[i]);
PATH_FOREACH_PREFIX(s, "////")
assert_not_reached();
const char *t;
assert_se(s = path_join(r, p));
- assert_se(path_equal_ptr(s, expected));
+ assert_se(path_equal(s, expected));
t = prefix_roota(r, p);
assert_se(t);
- assert_se(path_equal_ptr(t, expected));
+ assert_se(path_equal(t, expected));
}
TEST(prefix_root) {
memset(buf, 0xff, sizeof(buf));
draw_cylon(buf, sizeof(buf), CYLON_WIDTH, pos);
- assert_se(strlen(buf) < sizeof(buf));
+ ASSERT_LE(strlen(buf), sizeof(buf));
}
TEST(draw_cylon) {
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <string.h>
+
+#include "memory-util.h"
+#include "random-util.h"
+#include "recovery-key.h"
+#include "tests.h"
+
+TEST(make_recovery_key) {
+ _cleanup_(erase_and_freep) char *recovery_key = NULL;
+ size_t length;
+ const size_t num_test = 10;
+ char *generated_keys[num_test];
+ int r;
+
+ /* Check for successful recovery-key creation */
+ r = make_recovery_key(&recovery_key);
+ assert_se(r == 0);
+ ASSERT_NOT_NULL(recovery_key);
+
+ /* Check that length of formatted key is 72 with 64 modhex characters */
+ length = strlen(recovery_key);
+ assert_se(length == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH - 1);
+ /* Check modhex characters in formatted key with dashes */
+ for (size_t i = 0; i < length; i++) {
+ assert_se((recovery_key[i] >= 'a' && recovery_key[i] <= 'v') || recovery_key[i] == '-');
+ if (i % 9 == 8)
+ /* confirm '-' is after every 8 characters */
+ assert_se(recovery_key[i] == '-');
+ }
+ /* Repeat tests to determine randomness of generated keys */
+ for (size_t test = 0; test < num_test; ++test) {
+ r = make_recovery_key(&generated_keys[test]);
+ assert_se(r == 0);
+ length = strlen(generated_keys[test]);
+ assert_se(length == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH - 1);
+ for (size_t i = 0; i < length; i++) {
+ assert_se((generated_keys[test][i] >= 'a' && generated_keys[test][i] <= 'v')
+ || generated_keys[test][i] == '-');
+ if (i % 9 == 8)
+ assert_se(generated_keys[test][i] == '-');
+ }
+ /* Check for uniqueness of each generated recovery key */
+ for (size_t prev = 0; prev < test; ++prev)
+ assert_se(!streq(generated_keys[test], generated_keys[prev]));
+ }
+ for (size_t i = 0; i < num_test; i++)
+ free(generated_keys[i]);
+}
+
+TEST(decode_modhex_char) {
+
+ assert_se(decode_modhex_char('c') == 0);
+ assert_se(decode_modhex_char('C') == 0);
+ assert_se(decode_modhex_char('b') == 1);
+ assert_se(decode_modhex_char('B') == 1);
+ assert_se(decode_modhex_char('d') == 2);
+ assert_se(decode_modhex_char('D') == 2);
+ assert_se(decode_modhex_char('e') == 3);
+ assert_se(decode_modhex_char('E') == 3);
+ assert_se(decode_modhex_char('f') == 4);
+ assert_se(decode_modhex_char('F') == 4);
+ assert_se(decode_modhex_char('g') == 5);
+ assert_se(decode_modhex_char('G') == 5);
+ assert_se(decode_modhex_char('h') == 6);
+ assert_se(decode_modhex_char('H') == 6);
+ assert_se(decode_modhex_char('i') == 7);
+ assert_se(decode_modhex_char('I') == 7);
+ assert_se(decode_modhex_char('j') == 8);
+ assert_se(decode_modhex_char('J') == 8);
+ assert_se(decode_modhex_char('k') == 9);
+ assert_se(decode_modhex_char('K') == 9);
+ assert_se(decode_modhex_char('l') == 10);
+ assert_se(decode_modhex_char('L') == 10);
+ assert_se(decode_modhex_char('n') == 11);
+ assert_se(decode_modhex_char('N') == 11);
+ assert_se(decode_modhex_char('r') == 12);
+ assert_se(decode_modhex_char('R') == 12);
+ assert_se(decode_modhex_char('t') == 13);
+ assert_se(decode_modhex_char('T') == 13);
+ assert_se(decode_modhex_char('u') == 14);
+ assert_se(decode_modhex_char('U') == 14);
+ assert_se(decode_modhex_char('v') == 15);
+ assert_se(decode_modhex_char('V') == 15);
+ assert_se(decode_modhex_char('a') == -EINVAL);
+ assert_se(decode_modhex_char('A') == -EINVAL);
+ assert_se(decode_modhex_char('x') == -EINVAL);
+ assert_se(decode_modhex_char('.') == -EINVAL);
+ assert_se(decode_modhex_char('/') == -EINVAL);
+ assert_se(decode_modhex_char('\0') == -EINVAL);
+}
+
+TEST(normalize_recovery_key) {
+ _cleanup_(erase_and_freep) char *normalized_key1 = NULL;
+ _cleanup_(erase_and_freep) char *normalized_key2 = NULL;
+ _cleanup_(erase_and_freep) char *normalized_key3 = NULL;
+ int r;
+
+ /* Case 1: Normalization without dashes */
+ r = normalize_recovery_key("cdefghijcdefghijcdefghijcdefghijcdefghijcdefghijcdefghijcdefghij",
+ &normalized_key1);
+ assert(r == 0);
+ assert(streq(normalized_key1, "cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij"));
+
+ /* Case 2: Normalization with dashes */
+ r = normalize_recovery_key("cdefVhij-cDefghij-cdefkhij-cdufghij-cdefgdij-cidefIhj-cdefNijR-cdVfguij",
+ &normalized_key2);
+ assert_se(r == 0);
+ assert_se(streq(normalized_key2, "cdefvhij-cdefghij-cdefkhij-cdufghij-cdefgdij-cidefihj-cdefnijr-cdvfguij"));
+
+ /* Case 3: Invalid password length */
+ r = normalize_recovery_key("1234-5678-90AB-CDEF-1234-5678-90AB-CDEF", &normalized_key1);
+ assert(r == -EINVAL);
+
+ /* Case 4: Invalid password format(missing dash) */
+ r = normalize_recovery_key("cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghijcdefghij",
+ &normalized_key1);
+ assert_se(r == -EINVAL);
+
+ /* Case 5: Normalization of Upper cases password without dashes */
+ r = normalize_recovery_key("BFGHICEHHIUVLKJIHFHEDlntruvcdefjiTUVKLNIJVTUTKJIHDFBCBGHIJHHFDBC",
+ &normalized_key3);
+ assert(r == 0);
+ assert_se(streq(normalized_key3, "bfghiceh-hiuvlkji-hfhedlnt-ruvcdefj-ituvklni-jvtutkji-hdfbcbgh-ijhhfdbc"));
+
+ /* Case 6: Minimum password length */
+ r = normalize_recovery_key("", &normalized_key1);
+ assert_se(r == -EINVAL);
+
+ /* Case 7: Invalid characters and numbers in password */
+ r = normalize_recovery_key("cde123hi-cdefgzij-cdefghij-cdefghij-cdefghij-cdefghij-cdefghijcdefghij",
+ &normalized_key1);
+ assert_se(r == -EINVAL);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
}
}
+TEST(strdup_to_full) {
+ _cleanup_free_ char *dst;
+
+ assert_se(strdup_to_full(NULL, NULL) == 0);
+ assert_se(strdup_to_full(&dst, NULL) == 0);
+
+ assert_se(strdup_to_full(NULL, "") == 1);
+ assert_se(strdup_to_full(&dst, "") == 1);
+ assert_se(streq_ptr(dst, ""));
+ dst = mfree(dst);
+
+ assert_se(strdup_to_full(NULL, "x") == 1);
+ assert_se(strdup_to_full(&dst, "x") == 1);
+ assert_se(streq_ptr(dst, "x"));
+}
+
+TEST(strdup_to) {
+ _cleanup_free_ char *dst;
+
+ assert_se(strdup_to(&dst, NULL) == 0);
+
+ assert_se(strdup_to(&dst, "") == 0);
+ assert_se(streq_ptr(dst, ""));
+ dst = mfree(dst);
+
+ assert_se(strdup_to(&dst, "x") == 0);
+ assert_se(streq_ptr(dst, "x"));
+}
+
TEST(ascii_strcasecmp_n) {
assert_se(ascii_strcasecmp_n("", "", 0) == 0);
assert_se(ascii_strcasecmp_n("", "", 1) == 0);
}
TEST(uid_ptr) {
- assert_se(UID_TO_PTR(0) != NULL);
- assert_se(UID_TO_PTR(1000) != NULL);
+ ASSERT_NOT_NULL(UID_TO_PTR(0));
+ ASSERT_NOT_NULL(UID_TO_PTR(1000));
assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0);
assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
"AddRef", "b", 1,
"CollectMode", "s", "inactive-or-failed");
- if (allow_pidfd) {
- _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
- r = pidref_set_pid(&pidref, getpid_cached());
- if (r < 0)
- return log_error_errno(r, "Failed to allocate PID reference: %m");
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ r = pidref_set_self(&pidref);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate PID reference: %m");
- r = bus_append_scope_pidref(m, &pidref);
- } else
- r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, getpid_cached());
+ r = bus_append_scope_pidref(m, &pidref, allow_pidfd);
if (r < 0)
return bus_log_create_error(r);
#include "dirent-util.h"
#include "fd-util.h"
#include "discover-image.h"
+#include "pidref.h"
#include "sd-daemon.h"
#include "sd-event.h"
#include "sd-id128.h"
#include "gpt.h"
#include "hexdecoct.h"
#include "hostname-util.h"
+#include "io-util.h"
#include "kernel-image.h"
#include "log.h"
#include "machine-credential.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
+#include "time-util.h"
#include "tmpfile-util.h"
#include "unit-name.h"
#include "vmspawn-mount.h"
static char **arg_kernel_cmdline_extra = NULL;
static char **arg_extra_drives = NULL;
static char *arg_background = NULL;
+static bool arg_pass_ssh_key = true;
+static char *arg_ssh_key_type = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline_extra, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_extra_drives, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_ssh_key_type, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
"\n%3$sIntegration:%4$s\n"
" --forward-journal=FILE|DIR\n"
" Forward the VM's journal to the host\n"
+ " --pass-ssh-key=BOOL Create an SSH key to access the VM\n"
+ " --ssh-key-type=TYPE Choose what type of SSH key to pass\n"
"\n%3$sInput/Output:%4$s\n"
" --console=MODE Console mode (interactive, native, gui)\n"
" --background=COLOR Set ANSI color for background\n"
ARG_SECURE_BOOT,
ARG_PRIVATE_USERS,
ARG_FORWARD_JOURNAL,
+ ARG_PASS_SSH_KEY,
+ ARG_SSH_KEY_TYPE,
ARG_SET_CREDENTIAL,
ARG_LOAD_CREDENTIAL,
ARG_FIRMWARE,
{ "secure-boot", required_argument, NULL, ARG_SECURE_BOOT },
{ "private-users", required_argument, NULL, ARG_PRIVATE_USERS },
{ "forward-journal", required_argument, NULL, ARG_FORWARD_JOURNAL },
+ { "pass-ssh-key", required_argument, NULL, ARG_PASS_SSH_KEY },
+ { "ssh-key-type", required_argument, NULL, ARG_SSH_KEY_TYPE },
{ "set-credential", required_argument, NULL, ARG_SET_CREDENTIAL },
{ "load-credential", required_argument, NULL, ARG_LOAD_CREDENTIAL },
{ "firmware", required_argument, NULL, ARG_FIRMWARE },
return r;
break;
+ case ARG_PASS_SSH_KEY:
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --pass-ssh-key= argument: %s", optarg);
+
+ arg_pass_ssh_key = r;
+ break;
+
+ case ARG_SSH_KEY_TYPE:
+ if (!string_is_safe(optarg))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid value for --arg-ssh-key-type=: %s", optarg);
+
+ r = free_and_strdup_warn(&arg_ssh_key_type, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case ARG_SET_CREDENTIAL: {
r = machine_credential_set(&arg_credentials, optarg);
if (r < 0)
if (dot)
(void) pty_forward_set_title_prefix(f, dot);
}
+static int generate_ssh_keypair(const char *key_path, const char *key_type) {
+ _cleanup_free_ char *ssh_keygen = NULL;
+ _cleanup_strv_free_ char **cmdline = NULL;
+ int r;
+
+ assert(key_path);
+
+ r = find_executable("ssh-keygen", &ssh_keygen);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find ssh-keygen: %m");
+
+ cmdline = strv_new(ssh_keygen, "-f", key_path, /* don't encrypt the key */ "-N", "");
+ if (!cmdline)
+ return log_oom();
+
+ if (key_type) {
+ r = strv_extend_many(&cmdline, "-t", key_type);
+ if (r < 0)
+ return log_oom();
+ }
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *joined = quote_command_line(cmdline, SHELL_ESCAPE_EMPTY);
+ if (!joined)
+ return log_oom();
+
+ log_debug("Executing: %s", joined);
+ }
+
+ r = safe_fork(
+ ssh_keygen,
+ FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
+ NULL);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ execv(ssh_keygen, cmdline);
+ log_error_errno(errno, "Failed to execve %s: %m", ssh_keygen);
+ _exit(EXIT_FAILURE);
+ }
+
+ return 0;
+}
static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *machine = NULL, *qemu_binary = NULL, *mem = NULL, *trans_scope = NULL, *kernel = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *ssh_private_key_path = NULL, *ssh_public_key_path = NULL;
_cleanup_close_ int notify_sock_fd = -EBADF;
_cleanup_strv_free_ char **cmdline = NULL;
_cleanup_free_ int *pass_fds = NULL;
return r;
}
+ if (arg_pass_ssh_key) {
+ _cleanup_free_ char *scope_prefix = NULL, *privkey_path = NULL, *pubkey_path = NULL;
+ const char *key_type = arg_ssh_key_type ?: "ed25519";
+
+ r = unit_name_to_prefix(trans_scope, &scope_prefix);
+ if (r < 0)
+ return log_error_errno(r, "Failed to strip .scope suffix from scope: %m");
+
+ privkey_path = strjoin(arg_runtime_directory, "/", scope_prefix, "-", key_type);
+ if (!privkey_path)
+ return log_oom();
+
+ pubkey_path = strjoin(privkey_path, ".pub");
+ if (!pubkey_path)
+ return log_oom();
+
+ r = generate_ssh_keypair(privkey_path, key_type);
+ if (r < 0)
+ return r;
+
+ ssh_private_key_path = TAKE_PTR(privkey_path);
+ ssh_public_key_path = TAKE_PTR(pubkey_path);
+ }
+
+ if (ssh_public_key_path && ssh_private_key_path) {
+ _cleanup_free_ char *scope_prefix = NULL, *cred_path = NULL;
+
+ cred_path = strjoin("ssh.ephemeral-authorized_keys-all:", ssh_public_key_path);
+ if (!cred_path)
+ return log_oom();
+
+ r = machine_credential_load(&arg_credentials, cred_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load credential %s: %m", cred_path);
+
+ r = unit_name_to_prefix(trans_scope, &scope_prefix);
+ if (r < 0)
+ return log_error_errno(r, "Failed to strip .scope suffix from scope: %m");
+ }
+
if (ARCHITECTURE_SUPPORTS_SMBIOS)
FOREACH_ARRAY(cred, arg_credentials.credentials, arg_credentials.n_credentials) {
_cleanup_free_ char *cred_data_b64 = NULL;
reachable in the same URL parent directory as the logs.gz that gets linked on
the Github CI status.
+The log URL can be derived following a simple algorithm, however the test
+completion timestamp is needed and it's not easy to find without access to the
+log itself. For example, a noble s390x job started on 2024-03-23 at 02:09:11
+will be stored at the following URL:
+
+https://autopkgtest.ubuntu.com/results/autopkgtest-noble-upstream-systemd-ci-systemd-ci/noble/s390x/s/systemd-upstream/20240323_020911_e8e88@/log.gz
+
+The 5 characters at the end of the last directory are not random, but the first
+5 characters of a SHA1 hash generated based on the set of parameters given to
+the build plus the completion timestamp, such as:
+
+$ echo -n 'systemd-upstream {"build-git": "https://salsa.debian.org/systemd-team/systemd.git#debian/master", "env": ["UPSTREAM_REPO=https://github.com/systemd/systemd.git", "CFLAGS=-O0", "DEB_BUILD_PROFILES=pkg.systemd.upstream noudeb", "TEST_UPSTREAM=1", "CONFFLAGS_UPSTREAM=--werror -Dslow-tests=true", "UPSTREAM_PULL_REQUEST=31444", "GITHUB_STATUSES_URL=https://api.github.com/repos/systemd/systemd/statuses/c27f600a1c47f10b22964eaedfb5e9f0d4279cd9"], "ppas": ["upstream-systemd-ci/systemd-ci"], "submit-time": "2024-02-27 17:06:27", "uuid": "02cd262f-af22-4f82-ac91-53fa5a9e7811"}' | sha1sum | cut -c1-5
+
To add new dependencies or new binaries to the packages used during the tests,
a merge request can be sent to: https://salsa.debian.org/systemd-team/systemd
targeting the 'upstream-ci' branch.
local workspace="${1:?}"
local dropin_dir
- mkdir -p "$workspace/test-journals/"
- cp -av "${TEST_BASE_DIR:?}/test-journals/"* "$workspace/test-journals/"
-
image_install curl setterm unzstd
image_install -o openssl
# Necessary for RH-based systems, otherwise MHD fails with:
# shellcheck source=test/test-functions
. "${TEST_BASE_DIR:?}/test-functions"
-# (Hopefully) a temporary workaround for https://github.com/systemd/systemd/issues/30573
-KERNEL_APPEND="${KERNEL_APPEND:-} SYSTEMD_DEFAULT_MOUNT_RATE_LIMIT_BURST=100"
-
# Make sure vsock is available in the VM
CID=$((RANDOM + 3))
QEMU_OPTIONS+=" -device vhost-vsock-pci,guest-cid=$CID"
foreach subdir : [
'auxv',
'journal-data',
+ 'test-journals',
'units',
'test-execute',
'test-fstab-generator',
RESULTS["$test"]="$result"
TIMES["$test"]="$SECONDS"
- [[ "$result" -ne 0 ]] && FAILURES=$((FAILURES + 1))
- done
-fi
-
-# Run clean-again, if requested, and if no tests failed
-if [[ $FAILURES -eq 0 && $CLEAN_AGAIN -eq 1 ]]; then
- for test in "${!RESULTS[@]}"; do
- test_run "$test" make -C "$test" clean-again
+ # Run clean-again here to free up space, if requested, and if the test succeeded
+ if [[ "$result" -ne 0 ]]; then
+ FAILURES=$((FAILURES + 1))
+ elif [[ $CLEAN_AGAIN -eq 1 ]]; then
+ test_run "$test" make -C "$test" clean-again
+ fi
done
fi
[ -n "$TESTDIR" ] || return
rm -rf "$TESTDIR/unprivileged-nspawn-root"
[[ -n "$initdir" ]] && _umount_dir "$initdir"
+ # Test specific images are not reused, so delete them or we run out of disk space
+ if [[ -n "$IMAGE_PUBLIC" ]] && [ "$(basename "$IMAGE_PUBLIC")" != "default.img" ]; then
+ rm -vf "$IMAGE_PUBLIC"
+ fi
+ if [[ -n "$IMAGE_PRIVATE" ]] && [ "$(basename "$IMAGE_PRIVATE")" != "default.img" ]; then
+ rm -vf "$IMAGE_PRIVATE"
+ fi
}
test_create_image() {
JOURNAL_DIR="$(mktemp -d)"
REMOTE_OUT="$(mktemp -d)"
# tar on C8S doesn't support the --zstd option
-unzstd --stdout "/test-journals/afl-corrupted-journals.tar.zst" | tar -xC "$JOURNAL_DIR/"
+unzstd --stdout "/usr/lib/systemd/tests/testdata/test-journals/afl-corrupted-journals.tar.zst" | tar -xC "$JOURNAL_DIR/"
while read -r file; do
filename="${file##*/}"
unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}"
-done < <(find /test-journals/corrupted/ -name "*.zst")
+done < <(find /usr/lib/systemd/tests/testdata/test-journals/corrupted/ -name "*.zst")
# First, try each of them sequentially. Skip this part when running with plain
# QEMU, as it is excruciatingly slow
# Note: we care only about exit code 124 (timeout) and special bash exit codes
while read -r file; do
filename="${file##*/}"
unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}"
-done < <(find /test-journals/no-rtc -name "*.zst")
+done < <(find /usr/lib/systemd/tests/testdata/test-journals/no-rtc -name "*.zst")
journalctl --directory="$JOURNAL_DIR" --list-boots --output=json >/tmp/lb1
diff -u /tmp/lb1 - <<'EOF'
world
EOF
rm -f "$CURSOR_FILE"
+
+# Check that --until works with --after-cursor and --lines/-n
+# See: https://github.com/systemd/systemd/issues/31776
+CURSOR_FILE="$(mktemp)"
+journalctl -q -n 0 --cursor-file="$CURSOR_FILE"
+TIMESTAMP="$(journalctl -q -n 1 --cursor="$(<"$CURSOR_FILE")" --output=short-unix | cut -d ' ' -f 1 | cut -d '.' -f 1)"
+[[ -z "$(journalctl -q -n 10 --after-cursor="$(<"$CURSOR_FILE")" --until "@$((TIMESTAMP - 3))")" ]]
+rm -f "$CURSOR_FILE"
bash -xec 'timeout 1s nc -6 -u -l ::1 9999; exit 42'
systemd-run --wait -p SuccessExitStatus="1 2" --pipe "${ARGUMENTS[@]}" \
bash -xec 'timeout 1s nc -4 -l 127.0.0.1 6666; exit 42'
+ systemd-run --wait -p SuccessExitStatus="1 2" --pipe -p SocketBindDeny=any \
+ bash -xec 'timeout 1s nc -l 127.0.0.1 9999; exit 42'
# Consequently, we should succeed when binding to a socket on the allow list
# and keep listening on it until we're killed by `timeout` (EC 124)
systemd-run --wait --pipe -p SuccessExitStatus=124 "${ARGUMENTS[@]}" \
# we enable --luks-discard= since we run our tests in a tight VM, hence don't
# needlessly pressure for storage. We also set the cheapest KDF, since we don't
-# want to waste CI CPU cycles on it.
+# want to waste CI CPU cycles on it. We also effectively disable rate-limiting on
+# the user by allowing 1000 logins per second
NEWPASSWORD=xEhErW0ndafV4s homectl create test-user \
--disk-size=min \
--luks-discard=yes \
--image-path=/home/test-user.home \
--luks-pbkdf-type=pbkdf2 \
- --luks-pbkdf-time-cost=1ms
+ --luks-pbkdf-time-cost=1ms \
+ --rate-limit-interval=1s \
+ --rate-limit-burst=1000
inspect test-user
PASSWORD=xEhErW0ndafV4s homectl authenticate test-user
homectl deactivate test-user
inspect test-user
+homectl update test-user --real-name "Offline test" --offline
+inspect test-user
+
PASSWORD=xEhErW0ndafV4s homectl activate test-user
inspect test-user
+# Ensure that the offline changes were propagated in
+grep "Offline test" /home/test-user/.identity
+
homectl deactivate test-user
inspect test-user
-PASSWORD=xEhErW0ndafV4s homectl update test-user --real-name="Offline test"
+PASSWORD=xEhErW0ndafV4s homectl update test-user --real-name="Inactive test"
inspect test-user
PASSWORD=xEhErW0ndafV4s homectl activate test-user
homectl deactivate test-user
inspect test-user
+# Do some keyring tests, but only on real kernels, since keyring access inside of containers will fail
+# (See: https://github.com/systemd/systemd/issues/17606)
+if ! systemd-detect-virt -cq ; then
+ PASSWORD=xEhErW0ndafV4s homectl activate test-user
+ inspect test-user
+
+ # Key should now be in the keyring
+ homectl update test-user --real-name "Keyring Test"
+ inspect test-user
+
+ # These commands shouldn't use the keyring
+ (! timeout 5s homectl authenticate test-user )
+ (! NEWPASSWORD="foobar" timeout 5s homectl passwd test-user )
+
+ homectl lock test-user
+ inspect test-user
+
+ # Key should be gone from keyring
+ (! timeout 5s homectl update test-user --real-name "Keyring Test 2" )
+
+ PASSWORD=xEhErW0ndafV4s homectl unlock test-user
+ inspect test-user
+
+ # Key should have been re-instantiated into the keyring
+ homectl update test-user --real-name "Keyring Test 3"
+ inspect test-user
+
+ homectl deactivate test-user
+ inspect test-user
+fi
+
# Do some resize tests, but only if we run on real kernels, as quota inside of containers will fail
if ! systemd-detect-virt -cq ; then
# grow while inactive
--luks-discard=yes \
--image-path=/home/test-user2.home \
--luks-pbkdf-type=pbkdf2 \
- --luks-pbkdf-time-cost=1ms
+ --luks-pbkdf-time-cost=1ms \
+ --rate-limit-interval=1s \
+ --rate-limit-burst=1000
inspect test-user2
# activate second user
homectl rebalance
inspect test-user
inspect test-user2
+
+ wait_for_state test-user2 active
+ homectl deactivate test-user2
+ wait_for_state test-user2 inactive
+ homectl remove test-user2
fi
PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz
(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz)
PASSWORD=xEhErW0ndafV4s homectl with test-user -- touch /home/test-user/xyz
PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz
-# CAREFUL adding more `homectl with` tests here. Auth can get rate-limited and cause the tests to fail.
+PASSWORD=xEhErW0ndafV4s homectl with test-user -- rm /home/test-user/xyz
+PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz
+(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz)
wait_for_state test-user inactive
homectl remove test-user
-if ! systemd-detect-virt -cq ; then
- wait_for_state test-user2 active
- homectl deactivate test-user2
- wait_for_state test-user2 inactive
- homectl remove test-user2
-fi
-
# blob directory tests
# See docs/USER_RECORD_BLOB_DIRS.md
checkblob() {
NEWPASSWORD=EMJuc3zQaMibJo homectl create blob-user \
--disk-size=min --luks-discard=yes \
--luks-pbkdf-type=pbkdf2 --luks-pbkdf-time-cost=1ms \
+ --rate-limit-interval=1s --rate-limit-burst=1000 \
--uid=12345 \
--blob=/tmp/blob1
inspect blob-user
(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b файл=/tmp/external-test3 )
(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b special@chars=/tmp/external-test3 )
+# Make sure offline updates to blobs get propagated in
+homectl deactivate blob-user
+inspect blob-user
+homectl update blob-user --offline -b barely-fits= -b propagated=/tmp/external-test3
+inspect blob-user
+PASSWORD=EMJuc3zQaMibJo homectl activate blob-user
+inspect blob-user
+(! checkblob barely-fits /tmp/external-barely-fits )
+checkblob propagated /tmp/external-test3
+
homectl deactivate blob-user
wait_for_state blob-user inactive
homectl remove blob-user
--luks-discard=yes \
--luks-pbkdf-type=pbkdf2 \
--luks-pbkdf-time-cost=1ms \
+ --rate-limit-interval=1s \
+ --rate-limit-burst=1000 \
--enforce-password-policy=no \
--ssh-authorized-keys=@/tmp/homed.id_ecdsa.pub \
--stop-delay=0 \
umount /proc/version
rm -f "$TMP_KVER"
-# Check that invoking the tool under the uid0 alias name works
-uid0 ls /
-assert_eq "$(uid0 echo foo)" "foo"
+# Check that invoking the tool under the run0 alias name works
+run0 ls /
+assert_eq "$(run0 echo foo)" "foo"
# Check if we set some expected environment variables
for arg in "" "--user=root" "--user=testuser"; do
- assert_eq "$(uid0 ${arg:+"$arg"} bash -c 'echo $SUDO_USER')" "$USER"
- assert_eq "$(uid0 ${arg:+"$arg"} bash -c 'echo $SUDO_UID')" "$(id -u "$USER")"
- assert_eq "$(uid0 ${arg:+"$arg"} bash -c 'echo $SUDO_GID')" "$(id -u "$USER")"
+ assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_USER')" "$USER"
+ assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_UID')" "$(id -u "$USER")"
+ assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_GID')" "$(id -u "$USER")"
done
-# Let's chain a couple of uid0 calls together, for fun
-readarray -t cmdline < <(printf "%.0suid0\n" {0..31})
+# Let's chain a couple of run0 calls together, for fun
+readarray -t cmdline < <(printf "%.0srun0\n" {0..31})
assert_eq "$("${cmdline[@]}" bash -c 'echo $SUDO_USER')" "$USER"
--- /dev/null
+#!/usr/bin/python3
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# vi: set tw=110 sw=4 ts=4 et:
+
+import sys
+
+import pefile
+
+
+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())
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)
import io
import os
import pathlib
+import sys
import time
import typing
from ctypes 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),
)
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),
)
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):
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 = [
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]:
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():
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
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):
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
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()
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
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
continue
- raise RuntimeError(f"Unsupported relocation {reloc}")
+ raise BadSectionError(f"Unsupported relocation {reloc}")
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
# 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
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
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
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)
offset = opt.SizeOfHeaders
for pe_s in sorted(sections, key=lambda s: s.VirtualAddress):
if pe_s.VirtualAddress < opt.SizeOfHeaders:
- 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)
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,
"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()
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",
default="",
help="Copy these sections if found",
)
+ return parser
+
+def main():
+ parser = create_parser()
elf2efi(parser.parse_args())
if [ -e .git ]; then
git config submodule.recurse true
git config fetch.recurseSubmodules on-demand
+ git config push.recurseSubmodules no
fi
if [ ! -f .git/hooks/pre-commit.sample ] || [ -f .git/hooks/pre-commit ]; then
ConditionVirtualization=no
ConditionDirectoryNotEmpty=/sys/class/power_supply/
ConditionKernelCommandLine=!systemd.battery_check=0
+ConditionKernelCommandLine=!systemd.battery-check=0
AssertPathExists=/etc/initrd-release
DefaultDependencies=no
After=plymouth-start.service
ExecStart=!!{{LIBEXECDIR}}/systemd-networkd
FileDescriptorStoreMax=512
ImportCredential=network.wireguard.*
-InaccessiblePaths=-/boot -/efi
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
ProtectHome=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
-ProtectSystem=full
+ProtectSystem=strict
Restart=on-failure
RestartKillSignal=SIGUSR2
RestartSec=0