summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore16
-rw-r--r--.travis.yml4
-rw-r--r--CODING_STYLE109
-rw-r--r--LICENSE.MIT19
-rw-r--r--Makefile-man.am125
-rw-r--r--Makefile.am1254
-rw-r--r--NEWS244
-rw-r--r--README31
-rw-r--r--TODO173
-rwxr-xr-xautogen.sh13
-rw-r--r--configure.ac200
-rw-r--r--docs/.gitignore1
-rw-r--r--docs/gudev/.gitignore19
-rw-r--r--docs/gudev/Makefile.am115
-rw-r--r--docs/gudev/gudev-docs.xml52
-rw-r--r--docs/gudev/gudev-sections.txt102
-rw-r--r--docs/gudev/gudev.types4
-rw-r--r--docs/gudev/version.xml.in1
-rw-r--r--docs/libudev/.gitignore19
-rw-r--r--docs/libudev/Makefile.am109
-rw-r--r--docs/libudev/libudev-docs.xml40
-rw-r--r--docs/libudev/libudev-sections.txt137
-rw-r--r--docs/libudev/libudev.types0
-rw-r--r--docs/libudev/version.xml.in1
-rw-r--r--hwdb/20-OUI.hwdb1232
-rw-r--r--hwdb/20-bluetooth-vendor-product.hwdb239
-rw-r--r--hwdb/20-pci-vendor-model.hwdb2533
-rw-r--r--hwdb/20-sdio-vendor-model.hwdb30
-rw-r--r--hwdb/20-usb-vendor-model.hwdb847
-rw-r--r--hwdb/60-evdev.hwdb104
-rw-r--r--hwdb/60-keyboard.hwdb382
-rw-r--r--hwdb/70-mouse.hwdb39
-rw-r--r--hwdb/70-pointingstick.hwdb107
-rw-r--r--hwdb/70-touchpad.hwdb4
-rw-r--r--hwdb/sdio.ids10
-rw-r--r--m4/.gitignore1
-rw-r--r--m4/arch.m413
-rw-r--r--m4/attributes.m45
-rw-r--r--m4/ax_normalize_path.m4115
-rw-r--r--man/binfmt.d.xml5
-rw-r--r--man/bootchart.conf.xml20
-rw-r--r--man/bootctl.xml85
-rw-r--r--man/bootup.xml7
-rw-r--r--man/busctl.xml11
-rw-r--r--man/coredump.conf.xml18
-rw-r--r--man/coredumpctl.xml5
-rw-r--r--man/crypttab.xml49
-rw-r--r--man/custom-html.xsl38
-rw-r--r--man/daemon.xml5
-rw-r--r--man/file-hierarchy.xml12
-rw-r--r--man/halt.xml5
-rw-r--r--man/hostname.xml16
-rw-r--r--man/hostnamectl.xml5
-rw-r--r--man/hwdb.xml15
-rw-r--r--man/journal-remote.conf.xml117
-rw-r--r--man/journalctl.xml10
-rw-r--r--man/journald.conf.xml84
-rw-r--r--man/kernel-command-line.xml9
-rw-r--r--man/kernel-install.xml29
-rw-r--r--man/less-variables.xml5
-rw-r--r--man/libsystemd-pkgconfig.xml5
-rw-r--r--man/locale.conf.xml13
-rw-r--r--man/localectl.xml13
-rw-r--r--man/localtime.xml5
-rw-r--r--man/loginctl.xml5
-rw-r--r--man/logind.conf.xml36
-rw-r--r--man/machine-id.xml9
-rw-r--r--man/machine-info.xml5
-rw-r--r--man/machinectl.xml190
-rw-r--r--man/modules-load.d.xml7
-rw-r--r--man/networkctl.xml5
-rw-r--r--man/nss-myhostname.xml7
-rw-r--r--man/nss-mymachines.xml5
-rw-r--r--man/os-release.xml45
-rw-r--r--man/pam_systemd.xml5
-rw-r--r--man/resolved.conf.xml14
-rw-r--r--man/runlevel.xml5
-rw-r--r--man/sd-daemon.xml5
-rw-r--r--man/sd-id128.xml5
-rw-r--r--man/sd-journal.xml5
-rw-r--r--man/sd-login.xml5
-rw-r--r--man/sd_booted.xml5
-rw-r--r--man/sd_bus_creds_get_pid.xml236
-rw-r--r--man/sd_bus_creds_new_from_pid.xml5
-rw-r--r--man/sd_bus_default.xml (renamed from man/sd_bus_open_user.xml)171
-rw-r--r--man/sd_bus_error.xml33
-rw-r--r--man/sd_bus_message_append.xml9
-rw-r--r--man/sd_bus_message_append_array.xml29
-rw-r--r--man/sd_bus_message_append_basic.xml5
-rw-r--r--man/sd_bus_message_append_string_memfd.xml29
-rw-r--r--man/sd_bus_message_append_strv.xml5
-rw-r--r--man/sd_bus_message_get_cookie.xml5
-rw-r--r--man/sd_bus_message_get_monotonic_usec.xml7
-rw-r--r--man/sd_bus_negotiate_fds.xml31
-rw-r--r--man/sd_bus_new.xml5
-rw-r--r--man/sd_bus_path_encode.xml5
-rw-r--r--man/sd_bus_request_name.xml5
-rw-r--r--man/sd_event_add_child.xml29
-rw-r--r--man/sd_event_add_defer.xml5
-rw-r--r--man/sd_event_add_signal.xml33
-rw-r--r--man/sd_event_add_time.xml7
-rw-r--r--man/sd_event_get_fd.xml29
-rw-r--r--man/sd_event_new.xml5
-rw-r--r--man/sd_event_run.xml186
-rw-r--r--man/sd_event_set_name.xml29
-rw-r--r--man/sd_event_wait.xml216
-rw-r--r--man/sd_get_seats.xml5
-rw-r--r--man/sd_id128_get_machine.xml5
-rw-r--r--man/sd_id128_randomize.xml5
-rw-r--r--man/sd_id128_to_string.xml5
-rw-r--r--man/sd_is_fifo.xml5
-rw-r--r--man/sd_journal_add_match.xml5
-rw-r--r--man/sd_journal_get_catalog.xml7
-rw-r--r--man/sd_journal_get_cursor.xml7
-rw-r--r--man/sd_journal_get_cutoff_realtime_usec.xml5
-rw-r--r--man/sd_journal_get_data.xml5
-rw-r--r--man/sd_journal_get_fd.xml5
-rw-r--r--man/sd_journal_get_realtime_usec.xml5
-rw-r--r--man/sd_journal_get_usage.xml5
-rw-r--r--man/sd_journal_next.xml5
-rw-r--r--man/sd_journal_open.xml5
-rw-r--r--man/sd_journal_print.xml19
-rw-r--r--man/sd_journal_query_unique.xml5
-rw-r--r--man/sd_journal_seek_head.xml5
-rw-r--r--man/sd_journal_stream_fd.xml5
-rw-r--r--man/sd_listen_fds.xml5
-rw-r--r--man/sd_login_monitor_new.xml5
-rw-r--r--man/sd_machine_get_class.xml5
-rw-r--r--man/sd_notify.xml5
-rw-r--r--man/sd_pid_get_session.xml62
-rw-r--r--man/sd_seat_get_active.xml5
-rw-r--r--man/sd_session_is_active.xml5
-rw-r--r--man/sd_uid_get_state.xml5
-rw-r--r--man/sd_watchdog_enabled.xml5
-rw-r--r--man/shutdown.xml5
-rw-r--r--man/standard-conf.xml45
-rw-r--r--man/standard-options.xml5
-rw-r--r--man/sysctl.d.xml15
-rw-r--r--man/systemctl.xml77
-rw-r--r--man/systemd-activate.xml17
-rw-r--r--man/systemd-analyze.xml9
-rw-r--r--man/systemd-ask-password-console.service.xml5
-rw-r--r--man/systemd-ask-password.xml5
-rw-r--r--man/systemd-backlight@.service.xml7
-rw-r--r--man/systemd-binfmt.service.xml7
-rw-r--r--man/systemd-bootchart.xml13
-rw-r--r--man/systemd-bus-proxyd.xml33
-rw-r--r--man/systemd-bus-proxyd@.service.xml7
-rw-r--r--man/systemd-cat.xml7
-rw-r--r--man/systemd-cgls.xml5
-rw-r--r--man/systemd-cgtop.xml5
-rw-r--r--man/systemd-coredump.xml9
-rw-r--r--man/systemd-cryptsetup-generator.xml15
-rw-r--r--man/systemd-cryptsetup@.service.xml9
-rw-r--r--man/systemd-debug-generator.xml13
-rw-r--r--man/systemd-delta.xml7
-rw-r--r--man/systemd-detect-virt.xml5
-rw-r--r--man/systemd-efi-boot-generator.xml16
-rw-r--r--man/systemd-escape.xml5
-rw-r--r--man/systemd-firstboot.xml19
-rw-r--r--man/systemd-fsck@.service.xml33
-rw-r--r--man/systemd-fstab-generator.xml19
-rw-r--r--man/systemd-getty-generator.xml12
-rw-r--r--man/systemd-gpt-auto-generator.xml19
-rw-r--r--man/systemd-halt.service.xml11
-rw-r--r--man/systemd-hibernate-resume-generator.xml9
-rw-r--r--man/systemd-hibernate-resume@.service.xml7
-rw-r--r--man/systemd-hostnamed.service.xml7
-rw-r--r--man/systemd-hwdb.xml7
-rw-r--r--man/systemd-inhibit.xml5
-rw-r--r--man/systemd-initctl.service.xml7
-rw-r--r--man/systemd-journal-gatewayd.service.xml31
-rw-r--r--man/systemd-journal-remote.xml8
-rw-r--r--man/systemd-journal-upload.xml33
-rw-r--r--man/systemd-journald.service.xml11
-rw-r--r--man/systemd-localed.service.xml15
-rw-r--r--man/systemd-logind.service.xml7
-rw-r--r--man/systemd-machine-id-commit.service.xml7
-rw-r--r--man/systemd-machine-id-commit.xml5
-rw-r--r--man/systemd-machine-id-setup.xml7
-rw-r--r--man/systemd-machined.service.xml7
-rw-r--r--man/systemd-modules-load.service.xml7
-rw-r--r--man/systemd-networkd-wait-online.service.xml7
-rw-r--r--man/systemd-networkd.service.xml11
-rw-r--r--man/systemd-notify.xml5
-rw-r--r--man/systemd-nspawn.xml151
-rw-r--r--man/systemd-path.xml5
-rw-r--r--man/systemd-quotacheck.service.xml9
-rw-r--r--man/systemd-random-seed.service.xml7
-rw-r--r--man/systemd-remount-fs.service.xml19
-rw-r--r--man/systemd-resolved.service.xml7
-rw-r--r--man/systemd-rfkill@.service.xml7
-rw-r--r--man/systemd-run.xml21
-rw-r--r--man/systemd-shutdownd.service.xml77
-rw-r--r--man/systemd-sleep.conf.xml40
-rw-r--r--man/systemd-socket-proxyd.xml18
-rw-r--r--man/systemd-suspend.service.xml13
-rw-r--r--man/systemd-sysctl.service.xml15
-rw-r--r--man/systemd-system-update-generator.xml13
-rw-r--r--man/systemd-system.conf.xml33
-rw-r--r--man/systemd-sysusers.xml5
-rw-r--r--man/systemd-sysv-generator.xml13
-rw-r--r--man/systemd-timedated.service.xml7
-rw-r--r--man/systemd-timesyncd.service.xml7
-rw-r--r--man/systemd-tmpfiles.xml5
-rw-r--r--man/systemd-tty-ask-password-agent.xml5
-rw-r--r--man/systemd-udevd.service.xml7
-rw-r--r--man/systemd-update-done.service.xml7
-rw-r--r--man/systemd-update-utmp.service.xml9
-rw-r--r--man/systemd-user-sessions.service.xml16
-rw-r--r--man/systemd-vconsole-setup.service.xml15
-rw-r--r--man/systemd.automount.xml19
-rw-r--r--man/systemd.device.xml5
-rw-r--r--man/systemd.exec.xml27
-rw-r--r--man/systemd.generator.xml8
-rw-r--r--man/systemd.journal-fields.xml9
-rw-r--r--man/systemd.kill.xml9
-rw-r--r--man/systemd.link.xml15
-rw-r--r--man/systemd.mount.xml60
-rw-r--r--man/systemd.netdev.xml230
-rw-r--r--man/systemd.network.xml105
-rw-r--r--man/systemd.path.xml9
-rw-r--r--man/systemd.preset.xml21
-rw-r--r--man/systemd.resource-control.xml5
-rw-r--r--man/systemd.scope.xml29
-rw-r--r--man/systemd.service.xml16
-rw-r--r--man/systemd.slice.xml7
-rw-r--r--man/systemd.snapshot.xml5
-rw-r--r--man/systemd.socket.xml48
-rw-r--r--man/systemd.special.xml5
-rw-r--r--man/systemd.swap.xml18
-rw-r--r--man/systemd.target.xml5
-rw-r--r--man/systemd.time.xml5
-rw-r--r--man/systemd.timer.xml5
-rw-r--r--man/systemd.unit.xml40
-rw-r--r--man/systemd.xml28
-rw-r--r--man/sysusers.d.xml5
-rw-r--r--man/telinit.xml5
-rw-r--r--man/timedatectl.xml65
-rw-r--r--man/timesyncd.conf.xml14
-rw-r--r--man/tmpfiles.d.xml126
-rw-r--r--man/udev.conf.xml5
-rw-r--r--man/udev.xml25
-rw-r--r--man/udevadm.xml5
-rw-r--r--man/user-system-options.xml5
-rw-r--r--man/vconsole.conf.xml11
-rw-r--r--po/LINGUAS1
-rw-r--r--po/de.po15
-rw-r--r--po/el.po11
-rw-r--r--po/es.po532
-rw-r--r--po/fr.po121
-rw-r--r--po/hu.po11
-rw-r--r--po/it.po159
-rw-r--r--po/pl.po126
-rw-r--r--po/pt_BR.po11
-rw-r--r--po/ru.po136
-rw-r--r--po/sv.po173
-rw-r--r--po/uk.po12
-rw-r--r--rules/42-usb-hid-pm.rules6
-rw-r--r--rules/50-udev-default.rules9
-rw-r--r--rules/60-block.rules11
-rw-r--r--rules/60-evdev.rules19
-rw-r--r--rules/60-keyboard.rules22
-rw-r--r--rules/60-persistent-storage.rules46
-rw-r--r--rules/60-serial.rules (renamed from rules/60-persistent-serial.rules)18
-rw-r--r--rules/75-tty-description.rules12
-rw-r--r--rules/78-sound-card.rules13
-rw-r--r--rules/95-udev-late.rules4
-rw-r--r--rules/99-systemd.rules.in23
-rw-r--r--shell-completion/bash/systemctl.in12
-rw-r--r--shell-completion/zsh/_bootctl7
-rw-r--r--shell-completion/zsh/_hostnamectl12
-rw-r--r--shell-completion/zsh/_journalctl1
-rw-r--r--shell-completion/zsh/_loginctl5
-rw-r--r--shell-completion/zsh/_machinectl84
-rw-r--r--shell-completion/zsh/_systemctl.in136
-rw-r--r--shell-completion/zsh/_systemd-analyze2
-rw-r--r--shell-completion/zsh/_systemd-nspawn22
-rw-r--r--src/activate/activate.c1
-rw-r--r--src/analyze/analyze-verify.c38
-rw-r--r--src/analyze/analyze-verify.h2
-rw-r--r--src/analyze/analyze.c6
-rw-r--r--src/ask-password/ask-password.c12
-rw-r--r--src/binfmt/binfmt.c2
-rw-r--r--src/boot/boot-efi.c190
-rw-r--r--src/boot/boot-loader.c132
-rw-r--r--src/boot/boot.h64
-rw-r--r--src/boot/bootctl.c1203
-rw-r--r--src/boot/efi/.gitignore2
-rw-r--r--src/boot/efi/boot.c1834
-rw-r--r--src/boot/efi/console.c141
-rw-r--r--src/boot/efi/console.h34
-rw-r--r--src/boot/efi/graphics.c91
-rw-r--r--src/boot/efi/graphics.h24
-rw-r--r--src/boot/efi/linux.c130
-rw-r--r--src/boot/efi/linux.h24
-rw-r--r--src/boot/efi/pefile.c172
-rw-r--r--src/boot/efi/pefile.h22
-rw-r--r--src/boot/efi/splash.c323
-rw-r--r--src/boot/efi/splash.h22
-rw-r--r--src/boot/efi/stub.c113
-rw-r--r--src/boot/efi/util.c347
-rw-r--r--src/boot/efi/util.h50
-rw-r--r--src/bootchart/bootchart.c237
-rw-r--r--src/bootchart/bootchart.conf7
-rw-r--r--src/bootchart/bootchart.h20
-rw-r--r--src/bootchart/store.c219
-rw-r--r--src/bootchart/store.h10
-rw-r--r--src/bootchart/svg.c855
-rw-r--r--src/bootchart/svg.h12
-rw-r--r--src/bus-proxyd/bus-proxyd.c17
-rw-r--r--src/bus-proxyd/bus-xml-policy.c2
-rw-r--r--src/bus-proxyd/bus-xml-policy.h2
-rw-r--r--src/bus-proxyd/driver.c103
-rw-r--r--src/bus-proxyd/proxy.c27
-rw-r--r--src/bus-proxyd/proxy.h3
-rw-r--r--src/bus-proxyd/stdio-bridge.c15
-rw-r--r--src/bus-proxyd/synthesize.c10
-rw-r--r--src/bus-proxyd/synthesize.h2
-rw-r--r--src/bus-proxyd/test-bus-xml-policy.c13
-rw-r--r--src/cgls/cgls.c1
-rw-r--r--src/cgtop/cgtop.c3
-rw-r--r--src/console/consoled-display.c1
-rw-r--r--src/console/consoled-manager.c16
-rw-r--r--src/console/consoled-session.c4
-rw-r--r--src/console/consoled-terminal.c3
-rw-r--r--src/console/consoled-workspace.c1
-rw-r--r--src/console/consoled.c7
-rw-r--r--src/console/consoled.h4
-rw-r--r--src/core/automount.c360
-rw-r--r--src/core/automount.h6
-rw-r--r--src/core/bus-policy.c7
-rw-r--r--src/core/busname.c115
-rw-r--r--src/core/busname.h1
-rw-r--r--src/core/cgroup.c103
-rw-r--r--src/core/cgroup.h5
-rw-r--r--src/core/dbus-automount.c3
-rw-r--r--src/core/dbus-automount.h1
-rw-r--r--src/core/dbus-busname.c1
-rw-r--r--src/core/dbus-busname.h2
-rw-r--r--src/core/dbus-device.c1
-rw-r--r--src/core/dbus-device.h1
-rw-r--r--src/core/dbus-job.c34
-rw-r--r--src/core/dbus-job.h2
-rw-r--r--src/core/dbus-kill.c4
-rw-r--r--src/core/dbus-manager.c500
-rw-r--r--src/core/dbus-manager.h2
-rw-r--r--src/core/dbus-mount.c1
-rw-r--r--src/core/dbus-path.c1
-rw-r--r--src/core/dbus-path.h1
-rw-r--r--src/core/dbus-scope.c25
-rw-r--r--src/core/dbus-service.c1
-rw-r--r--src/core/dbus-slice.c1
-rw-r--r--src/core/dbus-snapshot.c13
-rw-r--r--src/core/dbus-snapshot.h2
-rw-r--r--src/core/dbus-socket.c2
-rw-r--r--src/core/dbus-swap.c2
-rw-r--r--src/core/dbus-target.c2
-rw-r--r--src/core/dbus-target.h1
-rw-r--r--src/core/dbus-timer.c2
-rw-r--r--src/core/dbus-unit.c167
-rw-r--r--src/core/dbus-unit.h10
-rw-r--r--src/core/dbus.c127
-rw-r--r--src/core/dbus.h5
-rw-r--r--src/core/device.c454
-rw-r--r--src/core/device.h18
-rw-r--r--src/core/execute.c204
-rw-r--r--src/core/execute.h17
-rw-r--r--src/core/failure-action.c4
-rw-r--r--src/core/hostname-setup.c29
-rw-r--r--src/core/ima-setup.c18
-rw-r--r--src/core/job.c178
-rw-r--r--src/core/job.h6
-rw-r--r--src/core/kill.c5
-rw-r--r--src/core/killall.c4
-rw-r--r--src/core/kmod-setup.c23
-rw-r--r--src/core/load-dropin.c3
-rw-r--r--src/core/load-fragment-gperf.gperf.m41
-rw-r--r--src/core/load-fragment.c114
-rw-r--r--src/core/locale-setup.c2
-rw-r--r--src/core/loopback-setup.c8
-rw-r--r--src/core/machine-id-setup.c295
-rw-r--r--src/core/main.c73
-rw-r--r--src/core/manager.c236
-rw-r--r--src/core/manager.h22
-rw-r--r--src/core/mount-setup.c11
-rw-r--r--src/core/mount.c339
-rw-r--r--src/core/mount.h10
-rw-r--r--src/core/namespace.c113
-rw-r--r--src/core/namespace.h3
-rw-r--r--src/core/org.freedesktop.systemd1.policy.in.in14
-rw-r--r--src/core/path.c42
-rw-r--r--src/core/path.h1
-rw-r--r--src/core/scope.c36
-rw-r--r--src/core/scope.h1
-rw-r--r--src/core/selinux-access.c43
-rw-r--r--src/core/selinux-access.h1
-rw-r--r--src/core/selinux-setup.c4
-rw-r--r--src/core/service.c502
-rw-r--r--src/core/service.h6
-rw-r--r--src/core/shutdown.c10
-rw-r--r--src/core/slice.c33
-rw-r--r--src/core/slice.h1
-rw-r--r--src/core/smack-setup.c6
-rw-r--r--src/core/snapshot.c20
-rw-r--r--src/core/snapshot.h1
-rw-r--r--src/core/socket.c245
-rw-r--r--src/core/socket.h4
-rw-r--r--src/core/swap.c204
-rw-r--r--src/core/swap.h7
-rw-r--r--src/core/system.conf7
-rw-r--r--src/core/systemd.pc.in1
-rw-r--r--src/core/target.c4
-rw-r--r--src/core/target.h1
-rw-r--r--src/core/timer.c67
-rw-r--r--src/core/timer.h1
-rw-r--r--src/core/transaction.c173
-rw-r--r--src/core/umount.c39
-rw-r--r--src/core/unit-printf.c116
-rw-r--r--src/core/unit.c624
-rw-r--r--src/core/unit.h76
-rw-r--r--src/cryptsetup/cryptsetup-generator.c36
-rw-r--r--src/cryptsetup/cryptsetup.c52
-rw-r--r--src/dbus1-generator/dbus1-generator.c6
-rw-r--r--src/debug-generator/debug-generator.c12
-rw-r--r--src/delta/delta.c3
-rw-r--r--src/detect-virt/detect-virt.c1
-rw-r--r--src/efi-boot-generator/efi-boot-generator.c26
-rw-r--r--src/escape/escape.c40
-rw-r--r--src/firstboot/firstboot.c27
-rw-r--r--src/fsck/fsck.c298
-rw-r--r--src/fstab-generator/fstab-generator.c172
-rw-r--r--src/getty-generator/getty-generator.c24
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c105
-rw-r--r--src/gudev/.gitignore7
-rwxr-xr-xsrc/gudev/gjs-example.js75
-rw-r--r--src/gudev/gudev-1.0.pc.in11
-rw-r--r--src/gudev/gudev.h32
-rw-r--r--src/gudev/gudevclient.c532
-rw-r--r--src/gudev/gudevclient.h99
-rw-r--r--src/gudev/gudevdevice.c1026
-rw-r--r--src/gudev/gudevdevice.h130
-rw-r--r--src/gudev/gudevenumerator.c429
-rw-r--r--src/gudev/gudevenumerator.h106
-rw-r--r--src/gudev/gudevenums.h48
-rw-r--r--src/gudev/gudevenumtypes.c.template39
-rw-r--r--src/gudev/gudevenumtypes.h.template24
-rw-r--r--src/gudev/gudevmarshal.list1
-rw-r--r--src/gudev/gudevprivate.h40
-rw-r--r--src/gudev/gudevtypes.h50
-rw-r--r--src/gudev/libgudev-1.0.sym68
-rwxr-xr-xsrc/gudev/seed-example-enum.js38
-rwxr-xr-xsrc/gudev/seed-example.js72
-rw-r--r--src/hibernate-resume/hibernate-resume-generator.c8
-rw-r--r--src/hibernate-resume/hibernate-resume.c2
-rw-r--r--src/hostname/hostnamectl.c11
-rw-r--r--src/hostname/hostnamed.c84
-rw-r--r--src/hwdb/hwdb.c2
-rw-r--r--src/import/aufs-util.c5
-rw-r--r--src/import/export-raw.c345
-rw-r--r--src/import/export-raw.h37
-rw-r--r--src/import/export-tar.c329
-rw-r--r--src/import/export-tar.h37
-rw-r--r--src/import/export.c320
-rw-r--r--src/import/import-common.c401
-rw-r--r--src/import/import-common.h17
-rw-r--r--src/import/import-compress.c470
-rw-r--r--src/import/import-compress.h64
-rw-r--r--src/import/import-job.h119
-rw-r--r--src/import/import-raw.c496
-rw-r--r--src/import/import-raw.h4
-rw-r--r--src/import/import-tar.c415
-rw-r--r--src/import/import-tar.h2
-rw-r--r--src/import/import.c337
-rw-r--r--src/import/importd.c340
-rw-r--r--src/import/org.freedesktop.import1.policy.in20
-rw-r--r--src/import/pull-common.c425
-rw-r--r--src/import/pull-common.h36
-rw-r--r--src/import/pull-dkr.c (renamed from src/import/import-dkr.c)710
-rw-r--r--src/import/pull-dkr.h37
-rw-r--r--src/import/pull-job.c (renamed from src/import/import-job.c)260
-rw-r--r--src/import/pull-job.h117
-rw-r--r--src/import/pull-raw.c517
-rw-r--r--src/import/pull-raw.h (renamed from src/import/import-dkr.h)19
-rw-r--r--src/import/pull-tar.c417
-rw-r--r--src/import/pull-tar.h37
-rw-r--r--src/import/pull.c81
-rw-r--r--src/import/qcow2-util.c8
-rw-r--r--src/initctl/initctl.c27
-rw-r--r--src/journal-remote/journal-gatewayd.c56
-rw-r--r--src/journal-remote/journal-remote-parse.c59
-rw-r--r--src/journal-remote/journal-remote-parse.h6
-rw-r--r--src/journal-remote/journal-remote-write.c2
-rw-r--r--src/journal-remote/journal-remote-write.h1
-rw-r--r--src/journal-remote/journal-remote.c150
-rw-r--r--src/journal-remote/journal-remote.h1
-rw-r--r--src/journal-remote/journal-upload.c2
-rw-r--r--src/journal-remote/microhttpd-util.c53
-rw-r--r--src/journal-remote/microhttpd-util.h16
-rw-r--r--src/journal/.gitignore2
-rw-r--r--src/journal/audit-type.c (renamed from src/shared/time-dst.h)18
-rw-r--r--src/journal/audit-type.h39
-rw-r--r--src/journal/cat.c1
-rw-r--r--src/journal/catalog.c3
-rw-r--r--src/journal/compress.c26
-rw-r--r--src/journal/compress.h2
-rw-r--r--src/journal/coredump-vacuum.c5
-rw-r--r--src/journal/coredump.c7
-rw-r--r--src/journal/coredump.conf7
-rw-r--r--src/journal/coredumpctl.c6
-rw-r--r--src/journal/fsprg.c1
-rw-r--r--src/journal/journal-authenticate.c4
-rw-r--r--src/journal/journal-authenticate.h1
-rw-r--r--src/journal/journal-def.h2
-rw-r--r--src/journal/journal-file.c84
-rw-r--r--src/journal/journal-file.h2
-rw-r--r--src/journal/journal-qrcode.h2
-rw-r--r--src/journal/journal-vacuum.c5
-rw-r--r--src/journal/journal-vacuum.h1
-rw-r--r--src/journal/journal-verify.c6
-rw-r--r--src/journal/journalctl.c581
-rw-r--r--src/journal/journald-audit.c25
-rw-r--r--src/journal/journald-console.c4
-rw-r--r--src/journal/journald-kmsg.c8
-rw-r--r--src/journal/journald-native.c2
-rw-r--r--src/journal/journald-rate-limit.c1
-rw-r--r--src/journal/journald-rate-limit.h1
-rw-r--r--src/journal/journald-server.c21
-rw-r--r--src/journal/journald-server.h4
-rw-r--r--src/journal/journald-stream.c3
-rw-r--r--src/journal/journald-syslog.c4
-rw-r--r--src/journal/journald-wall.c4
-rw-r--r--src/journal/journald.c5
-rw-r--r--src/journal/journald.conf7
-rw-r--r--src/journal/mmap-cache.c1
-rw-r--r--src/journal/mmap-cache.h1
-rw-r--r--src/journal/sd-journal.c27
-rw-r--r--src/journal/stacktrace.c1
-rw-r--r--src/journal/test-audit-type.c44
-rw-r--r--src/journal/test-catalog.c1
-rw-r--r--src/journal/test-compress.c1
-rw-r--r--src/journal/test-journal-enum.c1
-rw-r--r--src/journal/test-journal-flush.c4
-rw-r--r--src/journal/test-journal-init.c3
-rw-r--r--src/journal/test-journal-interleaving.c9
-rw-r--r--src/journal/test-journal-stream.c12
-rw-r--r--src/journal/test-journal-verify.c5
-rw-r--r--src/journal/test-journal.c7
-rw-r--r--src/journal/test-mmap-cache.c1
-rw-r--r--src/kernel-install/90-loaderentry.install6
-rw-r--r--src/libsystemd-network/dhcp-identifier.c11
-rw-r--r--src/libsystemd-network/dhcp-identifier.h4
-rw-r--r--src/libsystemd-network/dhcp-network.c2
-rw-r--r--src/libsystemd-network/dhcp-packet.c8
-rw-r--r--src/libsystemd-network/lldp-internal.c18
-rw-r--r--src/libsystemd-network/lldp-network.c1
-rw-r--r--src/libsystemd-network/lldp-tlv.c8
-rw-r--r--src/libsystemd-network/network-internal.c1
-rw-r--r--src/libsystemd-network/network-internal.h2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c6
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c11
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c3
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c20
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c1
-rw-r--r--src/libsystemd-network/sd-lldp.c5
-rw-r--r--src/libsystemd-network/sd-pppoe.c4
-rw-r--r--src/libsystemd-network/test-dhcp-client.c4
-rw-r--r--src/libsystemd-network/test-dhcp-option.c34
-rw-r--r--src/libsystemd-network/test-dhcp-server.c2
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c2
-rw-r--r--src/libsystemd-network/test-ipv4ll.c3
-rw-r--r--src/libsystemd-network/test-lldp.c5
-rw-r--r--src/libsystemd-network/test-pppoe.c7
-rw-r--r--src/libsystemd-terminal/evcat.c16
-rw-r--r--src/libsystemd-terminal/grdev-drm.c20
-rw-r--r--src/libsystemd-terminal/grdev-internal.h6
-rw-r--r--src/libsystemd-terminal/grdev.c11
-rw-r--r--src/libsystemd-terminal/grdev.h6
-rw-r--r--src/libsystemd-terminal/idev-evdev.c15
-rw-r--r--src/libsystemd-terminal/idev-internal.h6
-rw-r--r--src/libsystemd-terminal/idev-keyboard.c29
-rw-r--r--src/libsystemd-terminal/idev.c19
-rw-r--r--src/libsystemd-terminal/idev.h7
-rw-r--r--src/libsystemd-terminal/modeset.c17
-rw-r--r--src/libsystemd-terminal/subterm.c8
-rw-r--r--src/libsystemd-terminal/sysview-internal.h8
-rw-r--r--src/libsystemd-terminal/sysview.c94
-rw-r--r--src/libsystemd-terminal/sysview.h10
-rw-r--r--src/libsystemd-terminal/term-charset.c3
-rw-r--r--src/libsystemd-terminal/term-page.c5
-rw-r--r--src/libsystemd-terminal/term-wcwidth.c1
-rw-r--r--src/libsystemd-terminal/test-term-page.c4
-rw-r--r--src/libsystemd-terminal/test-term-parser.c4
-rw-r--r--src/libsystemd-terminal/test-unifont.c3
-rw-r--r--src/libsystemd-terminal/unifont.c3
-rw-r--r--src/libsystemd-terminal/unifont.h3
-rw-r--r--src/libsystemd/libsystemd.sym.m480
-rw-r--r--src/libsystemd/sd-bus/bus-bloom.h1
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c10
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h1
-rw-r--r--src/libsystemd/sd-bus/bus-container.c2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c81
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c28
-rw-r--r--src/libsystemd/sd-bus/bus-creds.c360
-rw-r--r--src/libsystemd/sd-bus/bus-creds.h7
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c79
-rw-r--r--src/libsystemd/sd-bus/bus-error.c4
-rw-r--r--src/libsystemd/sd-bus/bus-gvariant.c1
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h3
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.c1
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.h1
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.c102
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.h2
-rw-r--r--src/libsystemd/sd-bus/bus-match.c3
-rw-r--r--src/libsystemd/sd-bus/bus-message.c40
-rw-r--r--src/libsystemd/sd-bus/bus-message.h1
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c4
-rw-r--r--src/libsystemd/sd-bus/bus-signature.h1
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c37
-rw-r--r--src/libsystemd/sd-bus/bus-track.c7
-rw-r--r--src/libsystemd/sd-bus/bus-type.c1
-rw-r--r--src/libsystemd/sd-bus/bus-type.h1
-rw-r--r--src/libsystemd/sd-bus/bus-util.c393
-rw-r--r--src/libsystemd/sd-bus/bus-util.h31
-rw-r--r--src/libsystemd/sd-bus/busctl-introspect.h1
-rw-r--r--src/libsystemd/sd-bus/busctl.c3
-rw-r--r--src/libsystemd/sd-bus/kdbus.h68
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c94
-rw-r--r--src/libsystemd/sd-bus/test-bus-benchmark.c (renamed from src/libsystemd/sd-bus/test-bus-kernel-benchmark.c)152
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c46
-rw-r--r--src/libsystemd/sd-bus/test-bus-creds.c1
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-introspect.c1
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel-bloom.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel.c6
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c13
-rw-r--r--src/libsystemd/sd-bus/test-bus-match.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c31
-rw-r--r--src/libsystemd/sd-bus/test-bus-server.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-signature.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-zero-copy.c8
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c67
-rw-r--r--src/libsystemd/sd-device/device-enumerator-private.h36
-rw-r--r--src/libsystemd/sd-device/device-enumerator.c983
-rw-r--r--src/libsystemd/sd-device/device-internal.h126
-rw-r--r--src/libsystemd/sd-device/device-private.c1117
-rw-r--r--src/libsystemd/sd-device/device-private.h64
-rw-r--r--src/libsystemd/sd-device/device-util.h60
-rw-r--r--src/libsystemd/sd-device/sd-device.c1839
-rw-r--r--src/libsystemd/sd-event/sd-event.c53
-rw-r--r--src/libsystemd/sd-event/test-event.c1
-rw-r--r--src/libsystemd/sd-hwdb/sd-hwdb.c4
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c28
-rw-r--r--src/libsystemd/sd-login/sd-login.c31
-rw-r--r--src/libsystemd/sd-login/test-login.c1
-rw-r--r--src/libsystemd/sd-network/network-util.h1
-rw-r--r--src/libsystemd/sd-network/sd-network.c11
-rw-r--r--src/libsystemd/sd-path/sd-path.c4
-rw-r--r--src/libsystemd/sd-resolve/sd-resolve.c15
-rw-r--r--src/libsystemd/sd-resolve/test-resolve.c5
-rw-r--r--src/libsystemd/sd-rtnl/local-addresses.h4
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-internal.h1
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-message.c20
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-types.c61
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-types.h23
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-util.c1
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-util.h1
-rw-r--r--src/libsystemd/sd-rtnl/sd-rtnl.c73
-rw-r--r--src/libsystemd/sd-rtnl/test-rtnl.c1
-rw-r--r--src/libudev/libudev-device-internal.h57
-rw-r--r--src/libudev/libudev-device-private.c519
-rw-r--r--src/libudev/libudev-device.c1728
-rw-r--r--src/libudev/libudev-enumerate.c814
-rw-r--r--src/libudev/libudev-list.c3
-rw-r--r--src/libudev/libudev-monitor.c96
-rw-r--r--src/libudev/libudev-private.h14
-rw-r--r--src/libudev/libudev-queue.c5
-rw-r--r--src/libudev/libudev-util.c10
-rw-r--r--src/libudev/libudev.c3
-rw-r--r--src/libudev/libudev.h1
-rw-r--r--src/locale/localectl.c10
-rw-r--r--src/locale/localed.c66
-rw-r--r--src/login/inhibit.c5
-rw-r--r--src/login/loginctl.c20
-rw-r--r--src/login/logind-acl.c5
-rw-r--r--src/login/logind-action.c6
-rw-r--r--src/login/logind-action.h1
-rw-r--r--src/login/logind-button.c3
-rw-r--r--src/login/logind-button.h2
-rw-r--r--src/login/logind-core.c4
-rw-r--r--src/login/logind-dbus.c822
-rw-r--r--src/login/logind-device.c1
-rw-r--r--src/login/logind-device.h2
-rw-r--r--src/login/logind-gperf.gperf1
-rw-r--r--src/login/logind-inhibit.c14
-rw-r--r--src/login/logind-inhibit.h3
-rw-r--r--src/login/logind-seat-dbus.c30
-rw-r--r--src/login/logind-seat.c7
-rw-r--r--src/login/logind-seat.h5
-rw-r--r--src/login/logind-session-dbus.c81
-rw-r--r--src/login/logind-session-device.c4
-rw-r--r--src/login/logind-session-device.h4
-rw-r--r--src/login/logind-session.c32
-rw-r--r--src/login/logind-session.h11
-rw-r--r--src/login/logind-user-dbus.c37
-rw-r--r--src/login/logind-user.c17
-rw-r--r--src/login/logind-user.h5
-rw-r--r--src/login/logind-utmp.c182
-rw-r--r--src/login/logind.c48
-rw-r--r--src/login/logind.conf8
-rw-r--r--src/login/logind.h45
-rw-r--r--src/login/org.freedesktop.login1.conf8
-rw-r--r--src/login/org.freedesktop.login1.policy.in30
-rw-r--r--src/login/pam_systemd.c5
-rw-r--r--src/login/sysfs-show.c1
-rw-r--r--src/login/test-inhibit.c1
-rw-r--r--src/machine-id-commit/machine-id-commit.c10
-rw-r--r--src/machine-id-setup/machine-id-setup-main.c1
-rw-r--r--src/machine/image-dbus.c112
-rw-r--r--src/machine/image-dbus.h9
-rw-r--r--src/machine/machine-dbus.c534
-rw-r--r--src/machine/machine-dbus.h15
-rw-r--r--src/machine/machine.c51
-rw-r--r--src/machine/machine.h20
-rw-r--r--src/machine/machinectl.c919
-rw-r--r--src/machine/machined-dbus.c397
-rw-r--r--src/machine/machined.c13
-rw-r--r--src/machine/machined.h10
-rw-r--r--src/machine/org.freedesktop.machine1.conf84
-rw-r--r--src/machine/org.freedesktop.machine1.policy.in22
-rw-r--r--src/modules-load/modules-load.c6
-rw-r--r--src/network/networkctl.c116
-rw-r--r--src/network/networkd-address-pool.c1
-rw-r--r--src/network/networkd-address.c27
-rw-r--r--src/network/networkd-dhcp4.c105
-rw-r--r--src/network/networkd-dhcp6.c103
-rw-r--r--src/network/networkd-fdb.c84
-rw-r--r--src/network/networkd-link.c925
-rw-r--r--src/network/networkd-link.h25
-rw-r--r--src/network/networkd-manager.c16
-rw-r--r--src/network/networkd-netdev-bond.c319
-rw-r--r--src/network/networkd-netdev-bond.h85
-rw-r--r--src/network/networkd-netdev-bridge.c4
-rw-r--r--src/network/networkd-netdev-dummy.c5
-rw-r--r--src/network/networkd-netdev-gperf.gperf108
-rw-r--r--src/network/networkd-netdev-ipvlan.c3
-rw-r--r--src/network/networkd-netdev-macvlan.c2
-rw-r--r--src/network/networkd-netdev-tunnel.c287
-rw-r--r--src/network/networkd-netdev-tunnel.h1
-rw-r--r--src/network/networkd-netdev-tuntap.c14
-rw-r--r--src/network/networkd-netdev-veth.c2
-rw-r--r--src/network/networkd-netdev-vlan.c2
-rw-r--r--src/network/networkd-netdev-vxlan.c29
-rw-r--r--src/network/networkd-netdev-vxlan.h3
-rw-r--r--src/network/networkd-netdev.c197
-rw-r--r--src/network/networkd-netdev.h36
-rw-r--r--src/network/networkd-network-bus.c2
-rw-r--r--src/network/networkd-network-gperf.gperf3
-rw-r--r--src/network/networkd-network.c54
-rw-r--r--src/network/networkd-route.c3
-rw-r--r--src/network/networkd-wait-online-link.c2
-rw-r--r--src/network/networkd-wait-online-manager.c1
-rw-r--r--src/network/networkd-wait-online.c5
-rw-r--r--src/network/networkd-wait-online.h1
-rw-r--r--src/network/networkd.c15
-rw-r--r--src/network/networkd.h18
-rw-r--r--src/network/test-network-tables.c1
-rw-r--r--src/notify/notify.c4
-rw-r--r--src/nspawn/nspawn.c2187
-rw-r--r--src/nss-myhostname/nss-myhostname.c5
-rw-r--r--src/nss-resolve/nss-resolve.c5
-rw-r--r--src/path/path.c4
-rw-r--r--src/python-systemd/_daemon.c2
-rw-r--r--src/python-systemd/daemon.py2
-rw-r--r--src/python-systemd/docs/layout.html2
-rw-r--r--src/quotacheck/quotacheck.c3
-rw-r--r--src/random-seed/random-seed.c60
-rw-r--r--src/remount-fs/remount-fs.c13
-rw-r--r--src/reply-password/reply-password.c8
-rw-r--r--src/resolve-host/resolve-host.c2
-rw-r--r--src/resolve/resolved-bus.c27
-rw-r--r--src/resolve/resolved-dns-answer.c2
-rw-r--r--src/resolve/resolved-dns-cache.c7
-rw-r--r--src/resolve/resolved-dns-cache.h1
-rw-r--r--src/resolve/resolved-dns-domain.h1
-rw-r--r--src/resolve/resolved-dns-packet.h1
-rw-r--r--src/resolve/resolved-dns-query.c6
-rw-r--r--src/resolve/resolved-dns-query.h8
-rw-r--r--src/resolve/resolved-dns-rr.h2
-rw-r--r--src/resolve/resolved-dns-scope.c10
-rw-r--r--src/resolve/resolved-dns-scope.h3
-rw-r--r--src/resolve/resolved-dns-server.c15
-rw-r--r--src/resolve/resolved-dns-server.h1
-rw-r--r--src/resolve/resolved-dns-stream.h1
-rw-r--r--src/resolve/resolved-dns-transaction.c3
-rw-r--r--src/resolve/resolved-dns-transaction.h2
-rw-r--r--src/resolve/resolved-link.c6
-rw-r--r--src/resolve/resolved-link.h2
-rw-r--r--src/resolve/resolved-manager.c50
-rw-r--r--src/resolve/resolved-manager.h4
-rw-r--r--src/resolve/resolved.c2
-rw-r--r--src/resolve/resolved.conf.in5
-rw-r--r--src/resolve/test-dns-domain.c3
-rw-r--r--src/run/run.c135
-rw-r--r--src/shared/acl-util.c182
-rw-r--r--src/shared/acl-util.h6
-rw-r--r--src/shared/acpi-fpdt.c2
-rw-r--r--src/shared/apparmor-util.c1
-rw-r--r--src/shared/architecture.c10
-rw-r--r--src/shared/architecture.h2
-rw-r--r--src/shared/arphrd-list.c1
-rw-r--r--src/shared/ask-password-api.c7
-rw-r--r--src/shared/ask-password-api.h1
-rw-r--r--src/shared/audit.c10
-rw-r--r--src/shared/audit.h4
-rw-r--r--src/shared/barrier.c7
-rw-r--r--src/shared/barrier.h7
-rw-r--r--src/shared/base-filesystem.c23
-rw-r--r--src/shared/base-filesystem.h4
-rw-r--r--src/shared/boot-timestamps.c3
-rw-r--r--src/shared/btrfs-ctree.h6
-rw-r--r--src/shared/btrfs-util.c703
-rw-r--r--src/shared/btrfs-util.h31
-rw-r--r--src/shared/bus-label.c24
-rw-r--r--src/shared/bus-label.h9
-rw-r--r--src/shared/cap-list.c1
-rw-r--r--src/shared/capability.c7
-rw-r--r--src/shared/capability.h3
-rw-r--r--src/shared/cgroup-show.c3
-rw-r--r--src/shared/cgroup-show.h1
-rw-r--r--src/shared/cgroup-util.c309
-rw-r--r--src/shared/cgroup-util.h2
-rw-r--r--src/shared/clean-ipc.c2
-rw-r--r--src/shared/clock-util.c13
-rw-r--r--src/shared/clock-util.h1
-rw-r--r--src/shared/condition.c11
-rw-r--r--src/shared/conf-files.c9
-rw-r--r--src/shared/conf-files.h1
-rw-r--r--src/shared/conf-parser.c85
-rw-r--r--src/shared/conf-parser.h17
-rw-r--r--src/shared/copy.c24
-rw-r--r--src/shared/dev-setup.c34
-rw-r--r--src/shared/dev-setup.h4
-rw-r--r--src/shared/device-nodes.c24
-rw-r--r--src/shared/dropin.c15
-rw-r--r--src/shared/efivars.c406
-rw-r--r--src/shared/efivars.h94
-rw-r--r--src/shared/env-util.c145
-rw-r--r--src/shared/env-util.h4
-rw-r--r--src/shared/errno-list.c1
-rw-r--r--src/shared/exit-status.c17
-rw-r--r--src/shared/exit-status.h1
-rw-r--r--src/shared/fdset.c3
-rw-r--r--src/shared/fdset.h1
-rw-r--r--src/shared/fileio-label.c4
-rw-r--r--src/shared/formats-util.h63
-rw-r--r--src/shared/fstab-util.c30
-rw-r--r--src/shared/fstab-util.h2
-rw-r--r--src/shared/fw-util.c8
-rw-r--r--src/shared/fw-util.h4
-rw-r--r--src/shared/generator.c97
-rw-r--r--src/shared/generator.h17
-rw-r--r--src/shared/hashmap.c68
-rw-r--r--src/shared/hashmap.h26
-rw-r--r--src/shared/hostname-util.c193
-rw-r--r--src/shared/hostname-util.h39
-rw-r--r--src/shared/import-util.c21
-rw-r--r--src/shared/import-util.h2
-rw-r--r--src/shared/install-printf.c28
-rw-r--r--src/shared/install-printf.h3
-rw-r--r--src/shared/install.c279
-rw-r--r--src/shared/install.h48
-rw-r--r--src/shared/json.c442
-rw-r--r--src/shared/json.h40
-rw-r--r--src/shared/lockfile-util.c154
-rw-r--r--src/shared/lockfile-util.h39
-rw-r--r--src/shared/log.c79
-rw-r--r--src/shared/log.h37
-rw-r--r--src/shared/login-shared.c6
-rw-r--r--src/shared/logs-show.c68
-rw-r--r--src/shared/logs-show.h1
-rw-r--r--src/shared/machine-image.c57
-rw-r--r--src/shared/machine-image.h5
-rw-r--r--src/shared/machine-pool.c379
-rw-r--r--src/shared/machine-pool.h30
-rw-r--r--src/shared/macro.h9
-rw-r--r--src/shared/memfd-util.c2
-rw-r--r--src/shared/memfd-util.h5
-rw-r--r--src/shared/missing.h240
-rw-r--r--src/shared/mkdir-label.c6
-rw-r--r--src/shared/mkdir.c11
-rw-r--r--src/shared/mkdir.h1
-rw-r--r--src/shared/ordered-set.h59
-rw-r--r--src/shared/pager.c3
-rw-r--r--src/shared/path-lookup.c16
-rw-r--r--src/shared/path-lookup.h22
-rw-r--r--src/shared/path-util.c274
-rw-r--r--src/shared/path-util.h32
-rw-r--r--src/shared/prioq.c6
-rw-r--r--src/shared/prioq.h2
-rw-r--r--src/shared/process-util.c539
-rw-r--r--src/shared/process-util.h65
-rw-r--r--src/shared/pty.c9
-rw-r--r--src/shared/pty.h5
-rw-r--r--src/shared/ptyfwd.c78
-rw-r--r--src/shared/ptyfwd.h5
-rw-r--r--src/shared/random-util.c129
-rw-r--r--src/shared/random-util.h38
-rw-r--r--src/shared/ratelimit.c2
-rw-r--r--src/shared/ring.c1
-rw-r--r--src/shared/ring.h5
-rw-r--r--src/shared/rm-rf.c224
-rw-r--r--src/shared/rm-rf.h34
-rw-r--r--src/shared/selinux-util.c4
-rw-r--r--src/shared/selinux-util.h1
-rw-r--r--src/shared/set.h2
-rw-r--r--src/shared/signal-util.c228
-rw-r--r--src/shared/signal-util.h41
-rw-r--r--src/shared/smack-util.c3
-rw-r--r--src/shared/socket-label.c11
-rw-r--r--src/shared/socket-util.c159
-rw-r--r--src/shared/socket-util.h6
-rw-r--r--src/shared/spawn-ask-password-agent.c5
-rw-r--r--src/shared/spawn-polkit-agent.c5
-rw-r--r--src/shared/special.h9
-rw-r--r--src/shared/specifier.c1
-rw-r--r--src/shared/strbuf.h2
-rw-r--r--src/shared/strv.c8
-rw-r--r--src/shared/strv.h4
-rw-r--r--src/shared/strxcpyx.h2
-rw-r--r--src/shared/switch-root.c7
-rw-r--r--src/shared/sysctl-util.c80
-rw-r--r--src/shared/sysctl-util.h (renamed from src/boot/boot-loader.h)8
-rw-r--r--src/shared/terminal-util.c1072
-rw-r--r--src/shared/terminal-util.h109
-rw-r--r--src/shared/time-dst.c335
-rw-r--r--src/shared/time-util.c17
-rw-r--r--src/shared/time-util.h2
-rw-r--r--src/shared/udev-util.h4
-rw-r--r--src/shared/unit-name.c678
-rw-r--r--src/shared/unit-name.h86
-rw-r--r--src/shared/utf8.c13
-rw-r--r--src/shared/utf8.h2
-rw-r--r--src/shared/util.c3234
-rw-r--r--src/shared/util.h315
-rw-r--r--src/shared/utmp-wtmp.c22
-rw-r--r--src/shared/utmp-wtmp.h15
-rw-r--r--src/shared/virt.c25
-rw-r--r--src/shutdownd/shutdownd.c459
-rw-r--r--src/sleep/sleep.c2
-rw-r--r--src/socket-proxy/socket-proxyd.c2
-rw-r--r--src/sysctl/sysctl.c78
-rw-r--r--src/system-update-generator/system-update-generator.c2
-rw-r--r--src/systemctl/systemctl.c744
-rwxr-xr-xsrc/systemctl/systemd-sysv-install.SKELETON47
-rw-r--r--src/systemd/sd-bus.h79
-rw-r--r--src/systemd/sd-daemon.h2
-rw-r--r--src/systemd/sd-device.h99
-rw-r--r--src/systemd/sd-event.h4
-rw-r--r--src/systemd/sd-id128.h4
-rw-r--r--src/systemd/sd-login.h25
-rw-r--r--src/systemd/sd-messages.h2
-rw-r--r--src/systemd/sd-network.h6
-rw-r--r--src/systemd/sd-shutdown.h119
-rw-r--r--src/sysusers/sysusers.c44
-rw-r--r--src/sysv-generator/sysv-generator.c315
-rw-r--r--src/test/test-barrier.c3
-rw-r--r--src/test/test-btrfs.c67
-rw-r--r--src/test/test-cap-list.c1
-rw-r--r--src/test/test-capability.c1
-rw-r--r--src/test/test-cgroup-mask.c7
-rw-r--r--src/test/test-cgroup-util.c79
-rw-r--r--src/test/test-cgroup.c1
-rw-r--r--src/test/test-condition.c1
-rw-r--r--src/test/test-conf-files.c4
-rw-r--r--src/test/test-conf-parser.c234
-rw-r--r--src/test/test-copy.c9
-rw-r--r--src/test/test-ellipsize.c2
-rw-r--r--src/test/test-engine.c9
-rw-r--r--src/test/test-env-replace.c27
-rw-r--r--src/test/test-execute.c8
-rw-r--r--src/test/test-fdset.c53
-rw-r--r--src/test/test-fileio.c1
-rw-r--r--src/test/test-hashmap-plain.c2
-rw-r--r--src/test/test-hashmap.c4
-rw-r--r--src/test/test-hostname.c5
-rw-r--r--src/test/test-install.c4
-rw-r--r--src/test/test-job-type.c3
-rw-r--r--src/test/test-json.c97
-rw-r--r--src/test/test-libudev.c12
-rw-r--r--src/test/test-locale-util.c1
-rw-r--r--src/test/test-log.c1
-rw-r--r--src/test/test-loopback.c3
-rw-r--r--src/test/test-namespace.c1
-rw-r--r--src/test/test-ns.c28
-rw-r--r--src/test/test-path-lookup.c22
-rw-r--r--src/test/test-path-util.c137
-rw-r--r--src/test/test-path.c18
-rw-r--r--src/test/test-process-util.c138
-rw-r--r--src/test/test-pty.c5
-rw-r--r--src/test/test-ring.c5
-rw-r--r--src/test/test-rtnl-manual.c5
-rw-r--r--src/test/test-sched-prio.c2
-rw-r--r--src/test/test-set.c18
-rw-r--r--src/test/test-sleep.c5
-rw-r--r--src/test/test-socket-util.c19
-rw-r--r--src/test/test-strip-tab-ansi.c1
-rw-r--r--src/test/test-strv.c6
-rw-r--r--src/test/test-strxcpyx.c1
-rw-r--r--src/test/test-tables.c2
-rw-r--r--src/test/test-terminal-util.c84
-rw-r--r--src/test/test-time.c6
-rw-r--r--src/test/test-tmpfiles.c3
-rw-r--r--src/test/test-udev.c28
-rw-r--r--src/test/test-unit-file.c65
-rw-r--r--src/test/test-unit-name.c361
-rw-r--r--src/test/test-utf8.c2
-rw-r--r--src/test/test-util.c347
-rw-r--r--src/test/test-watchdog.c1
-rw-r--r--src/timedate/timedatectl.c97
-rw-r--r--src/timedate/timedated.c145
-rw-r--r--src/timesync/timesyncd-conf.c1
-rw-r--r--src/timesync/timesyncd-manager.c26
-rw-r--r--src/timesync/timesyncd-manager.h2
-rw-r--r--src/timesync/timesyncd-server.h2
-rw-r--r--src/timesync/timesyncd.c2
-rw-r--r--src/timesync/timesyncd.conf.in7
-rw-r--r--src/tmpfiles/tmpfiles.c639
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c7
-rw-r--r--src/udev/.gitignore2
-rw-r--r--src/udev/accelerometer/accelerometer.c6
-rw-r--r--src/udev/ata_id/ata_id.c2
-rw-r--r--src/udev/cdrom_id/cdrom_id.c28
-rw-r--r--src/udev/collect/collect.c8
l---------src/udev/mtd_probe/Makefile (renamed from src/gudev/Makefile)0
-rw-r--r--src/udev/mtd_probe/mtd_probe.c4
-rw-r--r--src/udev/mtd_probe/mtd_probe.h6
-rw-r--r--src/udev/net/ethtool-util.c3
-rw-r--r--src/udev/net/link-config.c30
-rw-r--r--src/udev/net/link-config.h5
-rw-r--r--src/udev/scsi_id/scsi_serial.c1
-rw-r--r--src/udev/udev-builtin-blkid.c4
-rw-r--r--src/udev/udev-builtin-btrfs.c4
-rw-r--r--src/udev/udev-builtin-hwdb.c6
-rw-r--r--src/udev/udev-builtin-input_id.c175
-rw-r--r--src/udev/udev-builtin-keyboard.c251
-rw-r--r--src/udev/udev-builtin-kmod.c5
-rw-r--r--src/udev/udev-builtin-net_id.c58
-rw-r--r--src/udev/udev-builtin-path_id.c30
-rw-r--r--src/udev/udev-builtin-uaccess.c7
-rw-r--r--src/udev/udev-builtin-usb_id.c68
-rw-r--r--src/udev/udev-builtin.c11
-rw-r--r--src/udev/udev-ctrl.c75
-rw-r--r--src/udev/udev-event.c266
-rw-r--r--src/udev/udev-node.c5
-rw-r--r--src/udev/udev-rules.c111
-rw-r--r--src/udev/udev-watch.c4
-rw-r--r--src/udev/udev.h13
-rw-r--r--src/udev/udevadm-control.c5
-rw-r--r--src/udev/udevadm-hwdb.c1
-rw-r--r--src/udev/udevadm-info.c17
-rw-r--r--src/udev/udevadm-monitor.c8
-rw-r--r--src/udev/udevadm-settle.c15
-rw-r--r--src/udev/udevadm-test-builtin.c10
-rw-r--r--src/udev/udevadm-test.c20
-rw-r--r--src/udev/udevadm-trigger.c7
-rw-r--r--src/udev/udevadm.c3
-rw-r--r--src/udev/udevd.c1623
-rw-r--r--src/udev/v4l_id/v4l_id.c19
-rw-r--r--src/update-done/update-done.c24
-rw-r--r--src/update-utmp/update-utmp.c11
l---------src/user-sessions/Makefile (renamed from src/shutdownd/Makefile)0
-rw-r--r--src/user-sessions/user-sessions.c (renamed from src/login/user-sessions.c)1
-rw-r--r--src/vconsole/90-vconsole.rules.in7
-rw-r--r--src/vconsole/vconsole-setup.c90
-rw-r--r--sysctl.d/50-default.conf9
-rw-r--r--test/README.testsuite2
-rwxr-xr-xtest/TEST-03-JOBS/test-jobs.sh8
-rwxr-xr-xtest/mocks/fsck27
-rw-r--r--test/splash.bmpbin0 -> 289238 bytes
-rw-r--r--test/sysv-generator-test.py39
-rwxr-xr-xtest/test-efi-create-disk.sh42
-rw-r--r--test/test-functions2
-rwxr-xr-xtest/udev-test.pl9
-rw-r--r--tmpfiles.d/etc.conf.m44
-rw-r--r--tmpfiles.d/home.conf (renamed from units/systemd-shutdownd.socket)13
-rw-r--r--tmpfiles.d/journal-nocow.conf27
-rw-r--r--tmpfiles.d/legacy.conf2
-rw-r--r--tmpfiles.d/systemd-nologin.conf2
-rw-r--r--tmpfiles.d/var.conf2
-rw-r--r--units/.gitignore3
-rw-r--r--units/basic.target8
-rw-r--r--units/console-getty.service.m4.in1
-rw-r--r--units/emergency.service.in2
-rw-r--r--units/rescue.service.in2
-rw-r--r--units/systemd-binfmt.service.in1
-rw-r--r--units/systemd-fsck-root.service.in1
-rw-r--r--units/systemd-fsck@.service.in1
-rw-r--r--units/systemd-hwdb-update.service.in1
-rw-r--r--units/systemd-importd.service.in6
-rw-r--r--units/systemd-journald-audit.socket1
-rw-r--r--units/systemd-machine-id-commit.service.in1
-rw-r--r--units/systemd-machined.service.in11
-rw-r--r--units/systemd-modules-load.service.in1
-rw-r--r--units/systemd-networkd.service.m4.in (renamed from units/systemd-networkd.service.in)7
-rw-r--r--units/systemd-nspawn@.service.in16
-rw-r--r--units/systemd-random-seed.service.in1
-rw-r--r--units/systemd-resolved.service.m4.in (renamed from units/systemd-resolved.service.in)4
-rw-r--r--units/systemd-rfkill@.service.in1
-rw-r--r--units/systemd-sysctl.service.in1
-rw-r--r--units/systemd-sysusers.service.in1
-rw-r--r--units/systemd-timesyncd.service.in2
-rw-r--r--units/systemd-udev-trigger.service.in2
-rw-r--r--units/systemd-udevd.service.in4
-rw-r--r--units/systemd-user-sessions.service.in2
-rw-r--r--units/var-lib-machines.mount (renamed from units/systemd-shutdownd.service.in)13
1116 files changed, 51221 insertions, 27705 deletions
diff --git a/.gitignore b/.gitignore
index e8a4085a3a..ea9aacfd9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,10 @@
/*.tar.xz
/Makefile
/TAGS
+/GPATH
+/GRTAGS
+/GSYMS
+/GTAGS
/accelerometer
/ata_id
/bootctl
@@ -34,7 +38,6 @@
/defined
/exported
/exported-*
-/gtk-doc.make
/hostnamectl
/install-tree
/journalctl
@@ -45,6 +48,9 @@
/machinectl
/mtd_probe
/networkctl
+/linuxx64.efi.stub
+/systemd-bootx64.efi
+/test-efi-disk.img
/scsi_id
/systemadm
/systemctl
@@ -72,6 +78,7 @@
/systemd-efi-boot-generator
/systemd-escape
/systemd-evcat
+/systemd-export
/systemd-firstboot
/systemd-fsck
/systemd-fstab-generator
@@ -115,7 +122,6 @@
/systemd-rfkill
/systemd-run
/systemd-shutdown
-/systemd-shutdownd
/systemd-sleep
/systemd-socket-proxyd
/systemd-stdio-bridge
@@ -136,10 +142,12 @@
/systemd-vconsole-setup
/tags
/test-architecture
+/test-audit-type
/test-async
/test-barrier
/test-boot-timestamp
/test-btrfs
+/test-bus-benchmark
/test-bus-chat
/test-bus-cleanup
/test-bus-creds
@@ -147,7 +155,6 @@
/test-bus-gvariant
/test-bus-introspect
/test-bus-kernel
-/test-bus-kernel-benchmark
/test-bus-kernel-bloom
/test-bus-marshal
/test-bus-match
@@ -167,6 +174,7 @@
/test-compress-benchmark
/test-condition
/test-conf-files
+/test-conf-parser
/test-copy
/test-coredump-vacuum
/test-daemon
@@ -229,6 +237,7 @@
/test-path-util
/test-pppoe
/test-prioq
+/test-process-util
/test-pty
/test-qcow2
/test-ratelimit
@@ -250,6 +259,7 @@
/test-tables
/test-term-page
/test-term-parser
+/test-terminal-util
/test-time
/test-tmpfiles
/test-udev
diff --git a/.travis.yml b/.travis.yml
index 4ea2bc2d30..5d63474c1d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,8 +3,8 @@ compiler:
- gcc
before_install:
- sudo apt-get update -qq
- - sudo apt-get install autotools-dev automake autoconf libtool libdbus-1-dev libcap-dev libblkid-dev libmount-dev libpam-dev libcryptsetup-dev libaudit-dev libacl1-dev libattr1-dev libselinux-dev liblzma-dev libgcrypt-dev libqrencode-dev libmicrohttpd-dev gtk-doc-tools gperf python2.7-dev
-script: ./autogen.sh && ./configure --enable-gtk-doc --enable-gtk-doc-pdf && make V=1 && sudo ./systemd-machine-id-setup && make check && make distcheck
+ - sudo apt-get install autotools-dev automake autoconf libtool libdbus-1-dev libcap-dev libblkid-dev libmount-dev libpam-dev libcryptsetup-dev libaudit-dev libacl1-dev libattr1-dev libselinux-dev liblzma-dev libgcrypt-dev libqrencode-dev libmicrohttpd-dev gperf python2.7-dev
+script: ./autogen.sh && ./configure && make V=1 && sudo ./systemd-machine-id-setup && make check && make distcheck
after_failure: cat test-suite.log
notifications:
irc:
diff --git a/CODING_STYLE b/CODING_STYLE
index 5574013487..bdec988ce6 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -1,6 +1,10 @@
- 8ch indent, no tabs, except for files in man/ which are 2ch indent,
and still no tabs
+- We prefer /* comments */ over // comments, please. This is not C++, after
+ all. (Yes we know that C99 supports both kinds of comments, but still,
+ please!)
+
- Don't break code lines too eagerly. We do *not* force line breaks at
80ch, all of today's screens should be much larger than that. But
then again, don't overdo it, ~140ch should be enough really.
@@ -117,7 +121,8 @@
no speed benefit, and on calls like printf() "float"s get promoted
to "double"s anyway, so there is no point.
-- Do not invoke functions when you allocate variables on the stack. Wrong:
+- Do not mix function invocations with variable definitions in one
+ line. Wrong:
{
int a = foobar();
@@ -142,7 +147,9 @@
- Do not use types like "short". They *never* make sense. Use ints,
longs, long longs, all in unsigned+signed fashion, and the fixed
- size types uint32_t and so on, as well as size_t, but nothing else.
+ size types uint32_t and so on, as well as size_t, but nothing
+ else. Do not use kernel types like u32 and so on, leave that to the
+ kernel.
- Public API calls (i.e. functions exported by our shared libraries)
must be marked "_public_" and need to be prefixed with "sd_". No
@@ -208,3 +215,101 @@
is needed. Everytime you need that please immediately undefine
basename(), and add a comment about it, so that no code ever ends up
using the XDG version!
+
+- Use the bool type for booleans, not integers. One exception: in public
+ headers (i.e those in src/systemd/sd-*.h) use integers after all, as "bool"
+ is C99 and in our public APIs we try to stick to C89 (with a few extension).
+
+- When you invoke certain calls like unlink(), or mkdir_p() and you
+ know it is safe to ignore the error it might return (because a later
+ call would detect the failure anyway, or because the error is in an
+ error path and you thus couldn't do anything about it anyway), then
+ make this clear by casting the invocation explicitly to (void). Code
+ checks like Coverity understand that, and will not complain about
+ ignored error codes. Hence, please use this:
+
+ (void) unlink("/foo/bar/baz");
+
+ instead of just this:
+
+ unlink("/foo/bar/baz");
+
+- Don't invoke exit(), ever. It is not replacement for proper error
+ handling. Please escalate errors up your call chain, and use normal
+ "return" to exit from the main function of a process. If you
+ fork()ed off a child process, please use _exit() instead of exit(),
+ so that the exit handlers are not run.
+
+- Please never use dup(). Use fcntl(fd, F_DUPFD_CLOEXEC, 3)
+ instead. For two reason: first, you want O_CLOEXEC set on the new fd
+ (see above). Second, dup() will happily duplicate your fd as 0, 1,
+ 2, i.e. stdin, stdout, stderr, should those fds be closed. Given the
+ special semantics of those fds, it's probably a good idea to avoid
+ them. F_DUPFD_CLOEXEC with "3" as parameter avoids them.
+
+- When you define a destructor or unref() call for an object, please
+ accept a NULL object and simply treat this as NOP. This is similar
+ to how libc free() works, which accepts NULL pointers and becomes a
+ NOP for them. By following this scheme a lot of if checks can be
+ removed before invoking your destructor, which makes the code
+ substantially more readable and robust.
+
+- Related to this: when you define a destructor or unref() call for an
+ object, please make it return the same type it takes and always
+ return NULL from it. This allows writing code like this:
+
+ p = foobar_unref(p);
+
+ which will always work regardless if p is initialized or not, and
+ guarantees that p is NULL afterwards, all in just one line.
+
+- Use alloca(), but never forget that it is not OK to invoke alloca()
+ within a loop or within function call parameters. alloca() memory is
+ released at the end of a function, and not at the end of a {}
+ block. Thus, if you invoke it in a loop, you keep increasing the
+ stack pointer without ever releasing memory again. (VLAs have better
+ behaviour in this case, so consider using them as an alternative.)
+ Regarding not using alloca() within function parameters, see the
+ BUGS section of the alloca(3) man page.
+
+- Use memzero() or even better zero() instead of memset(..., 0, ...)
+
+- Instead of using memzero()/memset() to initialize structs allocated
+ on the stack, please try to use c99 structure initializers. It's
+ short, prettier and actually even faster at execution. Hence:
+
+ struct foobar t = {
+ .foo = 7,
+ .bar = "bazz",
+ };
+
+ instead of:
+
+ struct foobar t;
+ zero(t);
+ t.foo = 7;
+ t.bar = "bazz";
+
+- When returning a return code from main(), please preferably use
+ EXIT_FAILURE and EXIT_SUCCESS as defined by libc.
+
+- The order in which header files are included doesn't matter too
+ much. However, please try to include the headers of external
+ libraries first (these are all headers enclosed in <>), followed by
+ the headers of our own public headers (these are all headers
+ starting with "sd-"), internal utility libraries from src/shared/,
+ followed by the headers of the specific component. Or in other
+ words:
+
+ #include <stdio.h>
+ #include "sd-daemon.h"
+ #include "util.h"
+ #include "frobnicator.h"
+
+ Where stdio.h is a public glibc API, sd-daemon.h is a public API of
+ our own, util.h is a utility library header from src/shared, and
+ frobnicator.h is an placeholder name for any systemd component. The
+ benefit of following this ordering is that more local definitions
+ are always defined after more global ones. Thus, our local
+ definitions will never "leak" into the global header files, possibly
+ altering their effect due to #ifdeffery.
diff --git a/LICENSE.MIT b/LICENSE.MIT
deleted file mode 100644
index fd44f736ee..0000000000
--- a/LICENSE.MIT
+++ /dev/null
@@ -1,19 +0,0 @@
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation files
-(the "Software"), to deal in the Software without restriction,
-including without limitation the rights to use, copy, modify, merge,
-publish, distribute, sublicense, and/or sell copies of the Software,
-and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/Makefile-man.am b/Makefile-man.am
index d0fb9aa1ae..85579e0c0a 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -83,7 +83,6 @@ MANPAGES += \
man/systemd-path.1 \
man/systemd-remount-fs.service.8 \
man/systemd-run.1 \
- man/systemd-shutdownd.service.8 \
man/systemd-sleep.conf.5 \
man/systemd-socket-proxyd.8 \
man/systemd-suspend.service.8 \
@@ -222,8 +221,6 @@ MANPAGES_ALIAS += \
man/systemd-reboot.service.8 \
man/systemd-remount-fs.8 \
man/systemd-shutdown.8 \
- man/systemd-shutdownd.8 \
- man/systemd-shutdownd.socket.8 \
man/systemd-sleep.8 \
man/systemd-sysctl.8 \
man/systemd-sysusers.service.8 \
@@ -334,8 +331,6 @@ man/systemd-poweroff.service.8: man/systemd-halt.service.8
man/systemd-reboot.service.8: man/systemd-halt.service.8
man/systemd-remount-fs.8: man/systemd-remount-fs.service.8
man/systemd-shutdown.8: man/systemd-halt.service.8
-man/systemd-shutdownd.8: man/systemd-shutdownd.service.8
-man/systemd-shutdownd.socket.8: man/systemd-shutdownd.service.8
man/systemd-sleep.8: man/systemd-suspend.service.8
man/systemd-sysctl.8: man/systemd-sysctl.service.8
man/systemd-sysusers.service.8: man/systemd-sysusers.8
@@ -640,12 +635,6 @@ man/systemd-remount-fs.html: man/systemd-remount-fs.service.html
man/systemd-shutdown.html: man/systemd-halt.service.html
$(html-alias)
-man/systemd-shutdownd.html: man/systemd-shutdownd.service.html
- $(html-alias)
-
-man/systemd-shutdownd.socket.html: man/systemd-shutdownd.service.html
- $(html-alias)
-
man/systemd-sleep.html: man/systemd-suspend.service.html
$(html-alias)
@@ -780,6 +769,7 @@ if ENABLE_KDBUS
MANPAGES += \
man/sd_bus_creds_get_pid.3 \
man/sd_bus_creds_new_from_pid.3 \
+ man/sd_bus_default.3 \
man/sd_bus_error.3 \
man/sd_bus_message_append.3 \
man/sd_bus_message_append_array.3 \
@@ -790,7 +780,6 @@ MANPAGES += \
man/sd_bus_message_get_monotonic_usec.3 \
man/sd_bus_negotiate_fds.3 \
man/sd_bus_new.3 \
- man/sd_bus_open_user.3 \
man/sd_bus_path_encode.3 \
man/sd_bus_request_name.3 \
man/sd_event_add_child.3 \
@@ -799,7 +788,9 @@ MANPAGES += \
man/sd_event_add_time.3 \
man/sd_event_get_fd.3 \
man/sd_event_new.3 \
+ man/sd_event_run.3 \
man/sd_event_set_name.3 \
+ man/sd_event_wait.3 \
man/systemd-bus-proxyd.8 \
man/systemd-bus-proxyd@.service.8
MANPAGES_ALIAS += \
@@ -808,16 +799,25 @@ MANPAGES_ALIAS += \
man/sd_bus_creds_get_cgroup.3 \
man/sd_bus_creds_get_cmdline.3 \
man/sd_bus_creds_get_comm.3 \
- man/sd_bus_creds_get_connection_name.3 \
+ man/sd_bus_creds_get_description.3 \
+ man/sd_bus_creds_get_egid.3 \
+ man/sd_bus_creds_get_euid.3 \
man/sd_bus_creds_get_exe.3 \
+ man/sd_bus_creds_get_fsgid.3 \
+ man/sd_bus_creds_get_fsuid.3 \
man/sd_bus_creds_get_gid.3 \
man/sd_bus_creds_get_mask.3 \
man/sd_bus_creds_get_owner_uid.3 \
+ man/sd_bus_creds_get_ppid.3 \
man/sd_bus_creds_get_selinux_context.3 \
man/sd_bus_creds_get_session.3 \
+ man/sd_bus_creds_get_sgid.3 \
man/sd_bus_creds_get_slice.3 \
+ man/sd_bus_creds_get_suid.3 \
+ man/sd_bus_creds_get_supplementary_gids.3 \
man/sd_bus_creds_get_tid.3 \
man/sd_bus_creds_get_tid_comm.3 \
+ man/sd_bus_creds_get_tty.3 \
man/sd_bus_creds_get_uid.3 \
man/sd_bus_creds_get_unique_name.3 \
man/sd_bus_creds_get_unit.3 \
@@ -850,9 +850,11 @@ MANPAGES_ALIAS += \
man/sd_bus_message_get_seqnum.3 \
man/sd_bus_negotiate_creds.3 \
man/sd_bus_negotiate_timestamps.3 \
+ man/sd_bus_open.3 \
man/sd_bus_open_system.3 \
- man/sd_bus_open_system_container.3 \
+ man/sd_bus_open_system_machine.3 \
man/sd_bus_open_system_remote.3 \
+ man/sd_bus_open_user.3 \
man/sd_bus_path_decode.3 \
man/sd_bus_ref.3 \
man/sd_bus_release_name.3 \
@@ -860,7 +862,10 @@ MANPAGES_ALIAS += \
man/sd_event_add_exit.3 \
man/sd_event_add_post.3 \
man/sd_event_default.3 \
+ man/sd_event_dispatch.3 \
man/sd_event_get_name.3 \
+ man/sd_event_loop.3 \
+ man/sd_event_prepare.3 \
man/sd_event_ref.3 \
man/sd_event_source_get_child_pid.3 \
man/sd_event_source_get_signal.3 \
@@ -876,16 +881,25 @@ man/sd_bus_creds_get_audit_session_id.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_cgroup.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_cmdline.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_comm.3: man/sd_bus_creds_get_pid.3
-man/sd_bus_creds_get_connection_name.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_description.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_egid.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_euid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_exe.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_fsgid.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_fsuid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_gid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_mask.3: man/sd_bus_creds_new_from_pid.3
man/sd_bus_creds_get_owner_uid.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_ppid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_selinux_context.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_session.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_sgid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_slice.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_suid.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_supplementary_gids.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_tid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_tid_comm.3: man/sd_bus_creds_get_pid.3
+man/sd_bus_creds_get_tty.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_uid.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_unique_name.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_get_unit.3: man/sd_bus_creds_get_pid.3
@@ -897,8 +911,8 @@ man/sd_bus_creds_has_inheritable_cap.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_has_permitted_cap.3: man/sd_bus_creds_get_pid.3
man/sd_bus_creds_ref.3: man/sd_bus_creds_new_from_pid.3
man/sd_bus_creds_unref.3: man/sd_bus_creds_new_from_pid.3
-man/sd_bus_default_system.3: man/sd_bus_open_user.3
-man/sd_bus_default_user.3: man/sd_bus_open_user.3
+man/sd_bus_default_system.3: man/sd_bus_default.3
+man/sd_bus_default_user.3: man/sd_bus_default.3
man/sd_bus_error_copy.3: man/sd_bus_error.3
man/sd_bus_error_free.3: man/sd_bus_error.3
man/sd_bus_error_get_errno.3: man/sd_bus_error.3
@@ -918,9 +932,11 @@ man/sd_bus_message_get_reply_cookie.3: man/sd_bus_message_get_cookie.3
man/sd_bus_message_get_seqnum.3: man/sd_bus_message_get_monotonic_usec.3
man/sd_bus_negotiate_creds.3: man/sd_bus_negotiate_fds.3
man/sd_bus_negotiate_timestamps.3: man/sd_bus_negotiate_fds.3
-man/sd_bus_open_system.3: man/sd_bus_open_user.3
-man/sd_bus_open_system_container.3: man/sd_bus_open_user.3
-man/sd_bus_open_system_remote.3: man/sd_bus_open_user.3
+man/sd_bus_open.3: man/sd_bus_default.3
+man/sd_bus_open_system.3: man/sd_bus_default.3
+man/sd_bus_open_system_machine.3: man/sd_bus_default.3
+man/sd_bus_open_system_remote.3: man/sd_bus_default.3
+man/sd_bus_open_user.3: man/sd_bus_default.3
man/sd_bus_path_decode.3: man/sd_bus_path_encode.3
man/sd_bus_ref.3: man/sd_bus_new.3
man/sd_bus_release_name.3: man/sd_bus_request_name.3
@@ -928,7 +944,10 @@ man/sd_bus_unref.3: man/sd_bus_new.3
man/sd_event_add_exit.3: man/sd_event_add_defer.3
man/sd_event_add_post.3: man/sd_event_add_defer.3
man/sd_event_default.3: man/sd_event_new.3
+man/sd_event_dispatch.3: man/sd_event_wait.3
man/sd_event_get_name.3: man/sd_event_set_name.3
+man/sd_event_loop.3: man/sd_event_run.3
+man/sd_event_prepare.3: man/sd_event_wait.3
man/sd_event_ref.3: man/sd_event_new.3
man/sd_event_source_get_child_pid.3: man/sd_event_add_child.3
man/sd_event_source_get_signal.3: man/sd_event_add_signal.3
@@ -954,12 +973,24 @@ man/sd_bus_creds_get_cmdline.html: man/sd_bus_creds_get_pid.html
man/sd_bus_creds_get_comm.html: man/sd_bus_creds_get_pid.html
$(html-alias)
-man/sd_bus_creds_get_connection_name.html: man/sd_bus_creds_get_pid.html
+man/sd_bus_creds_get_description.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
+man/sd_bus_creds_get_egid.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
+man/sd_bus_creds_get_euid.html: man/sd_bus_creds_get_pid.html
$(html-alias)
man/sd_bus_creds_get_exe.html: man/sd_bus_creds_get_pid.html
$(html-alias)
+man/sd_bus_creds_get_fsgid.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
+man/sd_bus_creds_get_fsuid.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
man/sd_bus_creds_get_gid.html: man/sd_bus_creds_get_pid.html
$(html-alias)
@@ -969,21 +1000,36 @@ man/sd_bus_creds_get_mask.html: man/sd_bus_creds_new_from_pid.html
man/sd_bus_creds_get_owner_uid.html: man/sd_bus_creds_get_pid.html
$(html-alias)
+man/sd_bus_creds_get_ppid.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
man/sd_bus_creds_get_selinux_context.html: man/sd_bus_creds_get_pid.html
$(html-alias)
man/sd_bus_creds_get_session.html: man/sd_bus_creds_get_pid.html
$(html-alias)
+man/sd_bus_creds_get_sgid.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
man/sd_bus_creds_get_slice.html: man/sd_bus_creds_get_pid.html
$(html-alias)
+man/sd_bus_creds_get_suid.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
+man/sd_bus_creds_get_supplementary_gids.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
man/sd_bus_creds_get_tid.html: man/sd_bus_creds_get_pid.html
$(html-alias)
man/sd_bus_creds_get_tid_comm.html: man/sd_bus_creds_get_pid.html
$(html-alias)
+man/sd_bus_creds_get_tty.html: man/sd_bus_creds_get_pid.html
+ $(html-alias)
+
man/sd_bus_creds_get_uid.html: man/sd_bus_creds_get_pid.html
$(html-alias)
@@ -1017,10 +1063,10 @@ man/sd_bus_creds_ref.html: man/sd_bus_creds_new_from_pid.html
man/sd_bus_creds_unref.html: man/sd_bus_creds_new_from_pid.html
$(html-alias)
-man/sd_bus_default_system.html: man/sd_bus_open_user.html
+man/sd_bus_default_system.html: man/sd_bus_default.html
$(html-alias)
-man/sd_bus_default_user.html: man/sd_bus_open_user.html
+man/sd_bus_default_user.html: man/sd_bus_default.html
$(html-alias)
man/sd_bus_error_copy.html: man/sd_bus_error.html
@@ -1080,13 +1126,19 @@ man/sd_bus_negotiate_creds.html: man/sd_bus_negotiate_fds.html
man/sd_bus_negotiate_timestamps.html: man/sd_bus_negotiate_fds.html
$(html-alias)
-man/sd_bus_open_system.html: man/sd_bus_open_user.html
+man/sd_bus_open.html: man/sd_bus_default.html
+ $(html-alias)
+
+man/sd_bus_open_system.html: man/sd_bus_default.html
+ $(html-alias)
+
+man/sd_bus_open_system_machine.html: man/sd_bus_default.html
$(html-alias)
-man/sd_bus_open_system_container.html: man/sd_bus_open_user.html
+man/sd_bus_open_system_remote.html: man/sd_bus_default.html
$(html-alias)
-man/sd_bus_open_system_remote.html: man/sd_bus_open_user.html
+man/sd_bus_open_user.html: man/sd_bus_default.html
$(html-alias)
man/sd_bus_path_decode.html: man/sd_bus_path_encode.html
@@ -1110,9 +1162,18 @@ man/sd_event_add_post.html: man/sd_event_add_defer.html
man/sd_event_default.html: man/sd_event_new.html
$(html-alias)
+man/sd_event_dispatch.html: man/sd_event_wait.html
+ $(html-alias)
+
man/sd_event_get_name.html: man/sd_event_set_name.html
$(html-alias)
+man/sd_event_loop.html: man/sd_event_run.html
+ $(html-alias)
+
+man/sd_event_prepare.html: man/sd_event_wait.html
+ $(html-alias)
+
man/sd_event_ref.html: man/sd_event_new.html
$(html-alias)
@@ -1330,14 +1391,20 @@ endif
if HAVE_MICROHTTPD
MANPAGES += \
+ man/journal-remote.conf.5 \
man/systemd-journal-gatewayd.service.8 \
man/systemd-journal-remote.8 \
man/systemd-journal-upload.8
MANPAGES_ALIAS += \
+ man/journal-remote.conf.d.5 \
man/systemd-journal-gatewayd.8 \
man/systemd-journal-gatewayd.socket.8
+man/journal-remote.conf.d.5: man/journal-remote.conf.5
man/systemd-journal-gatewayd.8: man/systemd-journal-gatewayd.service.8
man/systemd-journal-gatewayd.socket.8: man/systemd-journal-gatewayd.service.8
+man/journal-remote.conf.d.html: man/journal-remote.conf.html
+ $(html-alias)
+
man/systemd-journal-gatewayd.html: man/systemd-journal-gatewayd.service.html
$(html-alias)
@@ -1634,6 +1701,7 @@ EXTRA_DIST += \
man/hostname.xml \
man/hostnamectl.xml \
man/hwdb.xml \
+ man/journal-remote.conf.xml \
man/journalctl.xml \
man/journald.conf.xml \
man/kernel-command-line.xml \
@@ -1663,6 +1731,7 @@ EXTRA_DIST += \
man/sd_booted.xml \
man/sd_bus_creds_get_pid.xml \
man/sd_bus_creds_new_from_pid.xml \
+ man/sd_bus_default.xml \
man/sd_bus_error.xml \
man/sd_bus_message_append.xml \
man/sd_bus_message_append_array.xml \
@@ -1673,7 +1742,6 @@ EXTRA_DIST += \
man/sd_bus_message_get_monotonic_usec.xml \
man/sd_bus_negotiate_fds.xml \
man/sd_bus_new.xml \
- man/sd_bus_open_user.xml \
man/sd_bus_path_encode.xml \
man/sd_bus_request_name.xml \
man/sd_event_add_child.xml \
@@ -1682,7 +1750,9 @@ EXTRA_DIST += \
man/sd_event_add_time.xml \
man/sd_event_get_fd.xml \
man/sd_event_new.xml \
+ man/sd_event_run.xml \
man/sd_event_set_name.xml \
+ man/sd_event_wait.xml \
man/sd_get_seats.xml \
man/sd_id128_get_machine.xml \
man/sd_id128_randomize.xml \
@@ -1770,7 +1840,6 @@ EXTRA_DIST += \
man/systemd-resolved.service.xml \
man/systemd-rfkill@.service.xml \
man/systemd-run.xml \
- man/systemd-shutdownd.service.xml \
man/systemd-sleep.conf.xml \
man/systemd-socket-proxyd.xml \
man/systemd-suspend.service.xml \
diff --git a/Makefile.am b/Makefile.am
index bf04d31840..7603b2c0e1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,16 +39,12 @@ SUBDIRS = . po
.PRECIOUS: $(TEST_SUITE_LOG) Makefile
LIBUDEV_CURRENT=7
-LIBUDEV_REVISION=2
+LIBUDEV_REVISION=3
LIBUDEV_AGE=6
-LIBGUDEV_CURRENT=2
-LIBGUDEV_REVISION=0
-LIBGUDEV_AGE=2
-
-LIBSYSTEMD_CURRENT=6
+LIBSYSTEMD_CURRENT=7
LIBSYSTEMD_REVISION=0
-LIBSYSTEMD_AGE=6
+LIBSYSTEMD_AGE=7
# The following four libraries only exist for compatibility reasons,
# their version info should not be bumped anymore
@@ -74,6 +70,7 @@ dbussessionservicedir=@dbussessionservicedir@
dbussystemservicedir=@dbussystemservicedir@
pamlibdir=@pamlibdir@
pamconfdir=@pamconfdir@
+pkgconfigdatadir=$(datadir)/pkgconfig
pkgconfiglibdir=$(libdir)/pkgconfig
polkitpolicydir=$(datadir)/polkit-1/actions
bashcompletiondir=@bashcompletiondir@
@@ -109,16 +106,15 @@ udevrulesdir=$(udevlibexecdir)/rules.d
udevhwdbdir=$(udevlibexecdir)/hwdb.d
catalogdir=$(prefix)/lib/systemd/catalog
kernelinstalldir = $(prefix)/lib/kernel/install.d
-factory_etcdir = $(prefix)/share/factory/etc
-factory_pamdir = $(prefix)/share/factory/etc/pam.d
+factory_etcdir = $(datadir)/factory/etc
+factory_pamdir = $(datadir)/factory/etc/pam.d
+bootlibdir = $(prefix)/lib/systemd/boot/efi
# And these are the special ones for /
rootprefix=@rootprefix@
rootbindir=$(rootprefix)/bin
rootlibexecdir=$(rootprefix)/lib/systemd
-CLEANFILES = $(BUILT_SOURCES)
-DISTCLEANFILES =
EXTRA_DIST =
BUILT_SOURCES =
INSTALL_EXEC_HOOKS =
@@ -132,6 +128,7 @@ noinst_LTLIBRARIES =
lib_LTLIBRARIES =
include_HEADERS =
noinst_DATA =
+pkgconfigdata_DATA =
pkgconfiglib_DATA =
polkitpolicy_in_in_files =
polkitpolicy_in_files =
@@ -144,6 +141,7 @@ dist_pkgdata_DATA =
dist_dbuspolicy_DATA =
dist_dbussystemservice_DATA =
dist_systemunit_DATA_busnames =
+dist_sysusers_DATA =
check_PROGRAMS =
check_DATA =
tests=
@@ -159,6 +157,16 @@ TESTS =
endif
udevlibexec_PROGRAMS =
+in_files = $(filter %.in,$(EXTRA_DIST))
+in_in_files = $(filter %.in.in, $(in_files))
+m4_files = $(filter %.m4,$(EXTRA_DIST) $(in_files:.m4.in=.m4))
+
+CLEANFILES = $(BUILT_SOURCES) \
+ $(pkgconfigdata_DATA) \
+ $(pkgconfiglib_DATA) \
+ $(in_files:.in=) $(in_in_files:.in.in=) \
+ $(m4_files:.m4=)
+
.PHONY: $(INSTALL_EXEC_HOOKS) $(UNINSTALL_EXEC_HOOKS) \
$(INSTALL_DATA_HOOKS) $(UNINSTALL_DATA_HOOKS) \
$(DISTCLEAN_LOCAL_HOOKS) $(CLEAN_LOCAL_HOOKS)
@@ -176,6 +184,7 @@ AM_CPPFLAGS = \
-DCATALOG_DATABASE=\"$(catalogstatedir)/database\" \
-DSYSTEMD_CGROUP_AGENT_PATH=\"$(rootlibexecdir)/systemd-cgroups-agent\" \
-DSYSTEMD_BINARY_PATH=\"$(rootlibexecdir)/systemd\" \
+ -DSYSTEMD_FSCK_PATH=\"$(rootlibexecdir)/systemd-fsck\" \
-DSYSTEMD_SHUTDOWN_BINARY_PATH=\"$(rootlibexecdir)/systemd-shutdown\" \
-DSYSTEMD_SLEEP_BINARY_PATH=\"$(rootlibexecdir)/systemd-sleep\" \
-DSYSTEMCTL_BINARY_PATH=\"$(rootbindir)/systemctl\" \
@@ -191,13 +200,15 @@ AM_CPPFLAGS = \
-DSYSTEM_SLEEP_PATH=\"$(systemsleepdir)\" \
-DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
-DSYSTEMD_LANGUAGE_FALLBACK_MAP=\"$(pkgdatadir)/language-fallback-map\" \
- -DX_SERVER=\"$(bindir)/X\" \
-DUDEVLIBEXECDIR=\"$(udevlibexecdir)\" \
-DPOLKIT_AGENT_BINARY_PATH=\"$(bindir)/pkttyagent\" \
-DQUOTACHECK=\"$(QUOTACHECK)\" \
-DKEXEC=\"$(KEXEC)\" \
+ -DMOUNT_PATH=\"$(MOUNT_PATH)\" \
+ -DUMOUNT_PATH=\"$(UMOUNT_PATH)\" \
-DLIBDIR=\"$(libdir)\" \
-DROOTLIBDIR=\"$(rootlibdir)\" \
+ -DROOTLIBEXECDIR=\"$(rootlibexecdir)\" \
-DTEST_DIR=\"$(abs_top_srcdir)/test\" \
-I $(top_srcdir)/src \
-I $(top_builddir)/src/shared \
@@ -205,6 +216,7 @@ AM_CPPFLAGS = \
-I $(top_srcdir)/src/network \
-I $(top_srcdir)/src/login \
-I $(top_srcdir)/src/journal \
+ -I $(top_builddir)/src/journal \
-I $(top_srcdir)/src/timedate \
-I $(top_srcdir)/src/timesync \
-I $(top_srcdir)/src/resolve \
@@ -221,6 +233,7 @@ AM_CPPFLAGS = \
-I $(top_srcdir)/src/libsystemd/sd-rtnl \
-I $(top_srcdir)/src/libsystemd/sd-network \
-I $(top_srcdir)/src/libsystemd/sd-hwdb \
+ -I $(top_srcdir)/src/libsystemd/sd-device \
-I $(top_srcdir)/src/libsystemd-network \
-I $(top_srcdir)/src/libsystemd-terminal \
$(OUR_CPPFLAGS)
@@ -241,14 +254,11 @@ endef
INSTALL_DIRS =
-RUNLEVEL1_TARGET_WANTS =
-RUNLEVEL2_TARGET_WANTS =
-RUNLEVEL3_TARGET_WANTS =
-RUNLEVEL4_TARGET_WANTS =
-RUNLEVEL5_TARGET_WANTS =
SHUTDOWN_TARGET_WANTS =
LOCAL_FS_TARGET_WANTS =
MULTI_USER_TARGET_WANTS =
+GRAPHICAL_TARGET_WANTS =
+RESCUE_TARGET_WANTS =
SYSINIT_TARGET_WANTS =
SOCKETS_TARGET_WANTS =
BUSNAMES_TARGET_WANTS =
@@ -262,14 +272,11 @@ USER_UNIT_ALIASES =
GENERAL_ALIASES =
install-target-wants-hook:
- what="$(RUNLEVEL1_TARGET_WANTS)" && wants=runlevel1.target && dir=$(systemunitdir) && $(add-wants)
- what="$(RUNLEVEL2_TARGET_WANTS)" && wants=runlevel2.target && dir=$(systemunitdir) && $(add-wants)
- what="$(RUNLEVEL3_TARGET_WANTS)" && wants=runlevel3.target && dir=$(systemunitdir) && $(add-wants)
- what="$(RUNLEVEL4_TARGET_WANTS)" && wants=runlevel4.target && dir=$(systemunitdir) && $(add-wants)
- what="$(RUNLEVEL5_TARGET_WANTS)" && wants=runlevel5.target && dir=$(systemunitdir) && $(add-wants)
what="$(SHUTDOWN_TARGET_WANTS)" && wants=shutdown.target && dir=$(systemunitdir) && $(add-wants)
what="$(LOCAL_FS_TARGET_WANTS)" && wants=local-fs.target && dir=$(systemunitdir) && $(add-wants)
what="$(MULTI_USER_TARGET_WANTS)" && wants=multi-user.target && dir=$(systemunitdir) && $(add-wants)
+ what="$(GRAPHICAL_TARGET_WANTS)" && wants=graphical.target && dir=$(systemunitdir) && $(add-wants)
+ what="$(RESCUE_TARGET_WANTS)" && wants=rescue.target && dir=$(systemunitdir) && $(add-wants)
what="$(SYSINIT_TARGET_WANTS)" && wants=sysinit.target && dir=$(systemunitdir) && $(add-wants)
what="$(SOCKETS_TARGET_WANTS)" && wants=sockets.target && dir=$(systemunitdir) && $(add-wants)
what="$(TIMERS_TARGET_WANTS)" && wants=timers.target && dir=$(systemunitdir) && $(add-wants)
@@ -385,7 +392,6 @@ rootlibexec_PROGRAMS = \
systemd \
systemd-cgroups-agent \
systemd-initctl \
- systemd-shutdownd \
systemd-shutdown \
systemd-remount-fs \
systemd-reply-password \
@@ -493,7 +499,6 @@ dist_systemunit_DATA = \
units/system.slice \
units/x-.slice \
units/systemd-initctl.socket \
- units/systemd-shutdownd.socket \
units/syslog.socket \
units/dev-hugepages.mount \
units/dev-mqueue.mount \
@@ -501,6 +506,7 @@ dist_systemunit_DATA = \
units/sys-kernel-debug.mount \
units/sys-fs-fuse-connections.mount \
units/tmp.mount \
+ units/var-lib-machines.mount \
units/printer.target \
units/sound.target \
units/bluetooth.target \
@@ -528,7 +534,6 @@ nodist_systemunit_DATA = \
units/console-getty.service \
units/container-getty@.service \
units/systemd-initctl.service \
- units/systemd-shutdownd.service \
units/systemd-remount-fs.service \
units/systemd-ask-password-wall.service \
units/systemd-ask-password-console.service \
@@ -581,7 +586,6 @@ EXTRA_DIST += \
units/container-getty@.service.m4.in \
units/rescue.service.in \
units/systemd-initctl.service.in \
- units/systemd-shutdownd.service.in \
units/systemd-remount-fs.service.in \
units/systemd-update-utmp.service.in \
units/systemd-update-utmp-runlevel.service.in \
@@ -608,12 +612,6 @@ EXTRA_DIST += \
units/systemd-nspawn@.service.in \
units/systemd-update-done.service.in
-CLEANFILES += \
- units/console-shell.service.m4 \
- units/console-getty.service.m4 \
- units/container-getty@.service.m4 \
- units/user@.service.m4
-
if HAVE_SYSV_COMPAT
nodist_systemunit_DATA += \
units/rc-local.service \
@@ -625,6 +623,7 @@ systemgenerator_PROGRAMS += \
endif
EXTRA_DIST += \
+ src/systemctl/systemd-sysv-install.SKELETON \
units/rc-local.service.in \
units/halt-local.service.in
@@ -644,7 +643,6 @@ dist_doc_DATA = \
NEWS \
LICENSE.LGPL2.1 \
LICENSE.GPL2 \
- LICENSE.MIT \
DISTRO_PORTING \
src/libsystemd/sd-bus/PORTING-DBUS1 \
src/libsystemd/sd-bus/DIFFERENCES \
@@ -720,12 +718,6 @@ man/systemd.directives.xml: $(top_srcdir)/tools/make-directive-index.py $(SOURCE
$(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(PYTHON) $< $@ $(filter-out $<,$^)
-EXTRA_DIST += \
- man/systemd.index.xml \
- man/index.html \
- man/systemd.directives.xml \
- man/glib-event-glue.c
-
CLEANFILES += \
man/systemd.index.xml \
man/systemd.directives.xml
@@ -741,7 +733,12 @@ EXTRA_DIST += \
$(man_MANS) \
tools/make-man-index.py \
tools/make-directive-index.py \
- tools/xml_helper.py
+ tools/xml_helper.py \
+ man/systemd.index.xml \
+ man/index.html \
+ man/systemd.directives.xml \
+ man/glib-event-glue.c \
+ $(NULL)
# ------------------------------------------------------------------------------
noinst_LTLIBRARIES += \
@@ -773,14 +770,19 @@ libsystemd_shared_la_SOURCES = \
src/shared/architecture.h \
src/shared/efivars.c \
src/shared/efivars.h \
+ src/shared/formats-util.h \
src/shared/fstab-util.c \
src/shared/fstab-util.h \
+ src/shared/lockfile-util.c \
+ src/shared/lockfile-util.h \
src/shared/path-util.c \
src/shared/path-util.h \
src/shared/time-util.c \
src/shared/time-util.h \
src/shared/locale-util.c \
src/shared/locale-util.h \
+ src/shared/signal-util.c \
+ src/shared/signal-util.h \
src/shared/mempool.c \
src/shared/mempool.h \
src/shared/hashmap.c \
@@ -788,6 +790,7 @@ libsystemd_shared_la_SOURCES = \
src/shared/siphash24.c \
src/shared/siphash24.h \
src/shared/set.h \
+ src/shared/ordered-set.h \
src/shared/fdset.c \
src/shared/fdset.h \
src/shared/prioq.c \
@@ -840,8 +843,6 @@ libsystemd_shared_la_SOURCES = \
src/shared/spawn-polkit-agent.h \
src/shared/clock-util.c \
src/shared/clock-util.h \
- src/shared/time-dst.c \
- src/shared/time-dst.h \
src/shared/calendarspec.c \
src/shared/calendarspec.h \
src/shared/fileio.c \
@@ -896,6 +897,12 @@ libsystemd_shared_la_SOURCES = \
src/shared/base-filesystem.h \
src/shared/memfd-util.c \
src/shared/memfd-util.h \
+ src/shared/process-util.c \
+ src/shared/process-util.h \
+ src/shared/random-util.c \
+ src/shared/random-util.h \
+ src/shared/terminal-util.c \
+ src/shared/terminal-util.h \
src/shared/uid-range.c \
src/shared/uid-range.h \
src/shared/nss-util.h \
@@ -905,7 +912,46 @@ libsystemd_shared_la_SOURCES = \
src/shared/sigbus.h \
src/shared/build.h \
src/shared/import-util.c \
- src/shared/import-util.h
+ src/shared/import-util.h \
+ src/shared/sysctl-util.c \
+ src/shared/sysctl-util.h \
+ src/shared/hostname-util.h \
+ src/shared/hostname-util.c \
+ src/shared/socket-label.c \
+ src/shared/label.c \
+ src/shared/label.h \
+ src/shared/selinux-util.c \
+ src/shared/selinux-util.h \
+ src/shared/mkdir-label.c \
+ src/shared/ask-password-api.c \
+ src/shared/ask-password-api.h \
+ src/shared/switch-root.h \
+ src/shared/switch-root.c \
+ src/shared/fileio-label.c \
+ src/shared/fileio-label.h \
+ src/shared/dev-setup.c \
+ src/shared/dev-setup.h \
+ src/shared/dropin.c \
+ src/shared/dropin.h \
+ src/shared/condition.c \
+ src/shared/condition.h \
+ src/shared/generator.h \
+ src/shared/generator.c \
+ src/shared/btrfs-util.c \
+ src/shared/btrfs-util.h \
+ src/shared/btrfs-ctree.h \
+ src/shared/rm-rf.c \
+ src/shared/rm-rf.h \
+ src/shared/copy.c \
+ src/shared/copy.h \
+ src/shared/install.c \
+ src/shared/install.h \
+ src/shared/install-printf.c \
+ src/shared/install-printf.h \
+ src/shared/path-lookup.c \
+ src/shared/path-lookup.h \
+ src/shared/specifier.c \
+ src/shared/specifier.h
if HAVE_UTMP
libsystemd_shared_la_SOURCES += \
@@ -924,70 +970,27 @@ nodist_libsystemd_shared_la_SOURCES = \
libsystemd_shared_la_CFLAGS = \
$(AM_CFLAGS) \
+ $(SELINUX_CFLAGS) \
$(CAP_CFLAGS) \
$(SECCOMP_CFLAGS) \
-pthread
libsystemd_shared_la_LIBADD = \
+ $(SELINUX_LIBS) \
$(CAP_LIBS) \
-lm
-# ------------------------------------------------------------------------------
-noinst_LTLIBRARIES += \
- libsystemd-units.la
-
-libsystemd_units_la_SOURCES = \
- src/shared/install.c \
- src/shared/install.h \
- src/shared/install-printf.c \
- src/shared/install-printf.h \
- src/shared/path-lookup.c \
- src/shared/path-lookup.h \
- src/shared/specifier.c \
- src/shared/specifier.h
-
-# ------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
noinst_LTLIBRARIES += \
- libsystemd-label.la
+ libsystemd-machine.la
-libsystemd_label_la_SOURCES = \
- src/shared/socket-label.c \
- src/shared/label.c \
- src/shared/label.h \
- src/shared/selinux-util.c \
- src/shared/selinux-util.h \
- src/shared/mkdir-label.c \
- src/shared/ask-password-api.c \
- src/shared/ask-password-api.h \
- src/shared/switch-root.h \
- src/shared/switch-root.c \
- src/shared/fileio-label.c \
- src/shared/fileio-label.h \
- src/shared/dev-setup.c \
- src/shared/dev-setup.h \
- src/shared/dropin.c \
- src/shared/dropin.h \
- src/shared/condition.c \
- src/shared/condition.h \
- src/shared/generator.h \
- src/shared/generator.c \
- src/shared/btrfs-util.c \
- src/shared/btrfs-util.h \
- src/shared/btrfs-ctree.h \
+libsystemd_machine_la_SOURCES = \
src/shared/machine-image.c \
src/shared/machine-image.h \
- src/shared/copy.c \
- src/shared/copy.h
-
-libsystemd_label_la_CFLAGS = \
- $(AM_CFLAGS) \
- $(SELINUX_CFLAGS)
-
-libsystemd_label_la_LIBADD = \
- $(SELINUX_LIBS)
+ src/shared/machine-pool.c \
+ src/shared/machine-pool.h
# -----------------------------------------------------------------------------
-
if HAVE_LIBIPTC
noinst_LTLIBRARIES += \
libsystemd-fw.la
@@ -1005,7 +1008,6 @@ libsystemd_fw_la_LIBADD = \
endif
# -----------------------------------------------------------------------------
-
if ENABLE_LDCONFIG
dist_systemunit_DATA += \
units/ldconfig.service
@@ -1198,8 +1200,6 @@ libsystemd_core_la_CFLAGS = \
-pthread
libsystemd_core_la_LIBADD = \
- libsystemd-units.la \
- libsystemd-label.la \
libudev-internal.la \
libsystemd-shared.la \
libsystemd-internal.la \
@@ -1219,40 +1219,40 @@ src/core/load-fragment-gperf-nulstr.c: src/core/load-fragment-gperf.gperf
$(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ keywords=0 ; FS="," ; print "extern const char load_fragment_gperf_nulstr[];" ; print "const char load_fragment_gperf_nulstr[] ="} ; keyword==1 { print "\"" $$1 "\\0\"" } ; /%%/ { keyword=1} ; END { print ";" }' < $< > $@
-EXTRA_DIST += \
+gperf_gperf_m4_sources = \
src/core/load-fragment-gperf.gperf.m4
-CLEANFILES += \
- src/core/load-fragment-gperf.gperf \
- src/core/load-fragment-gperf.c \
- src/core/load-fragment-gperf-nulstr.c \
+gperf_txt_sources = \
src/shared/errno-list.txt \
- src/shared/errno-from-name.gperf \
src/shared/af-list.txt \
- src/shared/af-from-name.gperf \
src/shared/arphrd-list.txt \
- src/shared/arphrd-from-name.gperf \
- src/shared/cap-list.txt \
- src/shared/cap-from-name.gperf \
- src/resolve/dns_type-list.txt \
- src/resolve/dns_type-from-name.gperf
+ src/shared/cap-list.txt
BUILT_SOURCES += \
- src/shared/errno-from-name.h \
- src/shared/errno-to-name.h \
- src/shared/af-from-name.h \
- src/shared/af-to-name.h \
- src/shared/arphrd-from-name.h \
- src/shared/arphrd-to-name.h \
- src/shared/cap-from-name.h \
- src/shared/cap-to-name.h \
- src/resolve/dns_type-from-name.h \
- src/resolve/dns_type-to-name.h
+ $(gperf_gperf_m4_sources:-gperf.gperf.m4=-gperf.c) \
+ $(gperf_gperf_m4_sources:-gperf.gperf.m4=-gperf-nulstr.c) \
+ $(gperf_gperf_sources:-gperf.gperf=-gperf.c) \
+ $(gperf_txt_sources:-list.txt=-from-name.h) \
+ $(gperf_txt_sources:-list.txt=-to-name.h)
+
+CLEANFILES += \
+ $(gperf_txt_sources:-list.txt=-from-name.gperf)
+DISTCLEANFILES = \
+ $(gperf_txt_sources)
+
+EXTRA_DIST += \
+ $(gperf_gperf_m4_sources) \
+ $(gperf_gperf_sources)
+
+CLEANFILES += \
+ $(gperf_txt_sources)
%-from-name.gperf: %-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct $(notdir $*)_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' <$< >$@
%-from-name.h: %-from-name.gperf
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_$(notdir $*) -H hash_$(notdir $*)_name -p -C <$< >$@
@@ -1261,6 +1261,7 @@ src/shared/errno-list.txt:
$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - </dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+/ { print $$2; }' >$@
src/shared/errno-to-name.h: src/shared/errno-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const errno_names[] = { "} !/EDEADLOCK/ && !/EWOULDBLOCK/ && !/ENOTSUP/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
@@ -1269,6 +1270,7 @@ src/shared/af-list.txt:
$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include sys/socket.h - </dev/null | grep -v AF_UNSPEC | grep -v AF_MAX | $(AWK) '/^#define[ \t]+AF_[^ \t]+[ \t]+PF_[^ \t]/ { print $$2; }' >$@
src/shared/af-to-name.h: src/shared/af-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const af_names[] = { "} !/AF_FILE/ && !/AF_ROUTE/ && !/AF_LOCAL/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
@@ -1277,9 +1279,11 @@ src/shared/arphrd-list.txt:
$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include net/if_arp.h - </dev/null | $(AWK) '/^#define[ \t]+ARPHRD_[^ \t]+[ \t]+[^ \t]/ { print $$2; }' | sed -e 's/ARPHRD_//' >$@
src/shared/arphrd-to-name.h: src/shared/arphrd-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const arphrd_names[] = { "} !/CISCO/ { printf "[ARPHRD_%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
src/shared/arphrd-from-name.gperf: src/shared/arphrd-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct arphrd_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, ARPHRD_%s\n", $$1, $$1 }' <$< >$@
@@ -1288,23 +1292,41 @@ src/shared/cap-list.txt:
$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/capability.h -include missing.h - </dev/null | $(AWK) '/^#define[ \t]+CAP_[A-Z_]+[ \t]+/ { print $$2; }' | grep -v CAP_LAST_CAP >$@
src/shared/cap-to-name.h: src/shared/cap-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const capability_names[] = { "} { printf "[%s] = \"%s\",\n", $$1, tolower($$1) } END{print "};"}' <$< >$@
src/shared/cap-from-name.gperf: src/shared/cap-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct capability_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, %s\n", $$1, $$1 }' <$< >$@
src/shared/cap-from-name.h: src/shared/cap-from-name.gperf
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GPERF)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_capability -H hash_capability_name -p -C <$< >$@
+audit_list_includes = -include linux/audit.h missing.h
+if HAVE_AUDIT
+audit_list_includes += -include libaudit.h
+endif
+
+src/journal/audit_type-list.txt:
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/audit.h -include missing.h - </dev/null | grep -vE 'AUDIT_.*(FIRST|LAST)_' | $(SED) -r -n 's/^#define\s+AUDIT_(\w+)\s+([0-9]{4})\s*$$/\1\t\2/p' | sort -k2 >$@
+
+src/journal/audit_type-to-name.h: src/journal/audit_type-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *audit_type_to_string(int type) {\n\tswitch(type) {" } {printf " case AUDIT_%s: return \"%s\";\n", $$1, $$1 } END{ print " default: return NULL;\n\t}\n}\n" }' <$< >$@
+
src/resolve/dns_type-list.txt: src/resolve/dns-type.h
$(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
src/resolve/dns_type-to-name.h: src/resolve/dns_type-list.txt
- $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } {printf " case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print "\ndefault: return NULL;\n\t}\n}\n" }' <$< >$@
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } {printf " case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print " default: return NULL;\n\t}\n}\n" }' <$< >$@
src/resolve/dns_type-from-name.gperf: src/resolve/dns_type-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct dns_type_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { s=$$1; sub(/_/, "-", s); printf "%s, ", $$s; printf "DNS_TYPE_%s\n", $$1 }' <$< >$@
# ------------------------------------------------------------------------------
@@ -1332,7 +1354,7 @@ dist_dbussystemservice_DATA += \
polkitpolicy_in_in_files += \
src/core/org.freedesktop.systemd1.policy.in.in
-pkgconfiglib_DATA += \
+pkgconfigdata_DATA += \
src/core/systemd.pc
nodist_rpmmacros_DATA = \
@@ -1342,10 +1364,6 @@ EXTRA_DIST += \
src/core/systemd.pc.in \
src/core/macros.systemd.in
-CLEANFILES += \
- src/core/macros.systemd \
- src/core/org.freedesktop.systemd1.policy.in
-
# ------------------------------------------------------------------------------
manual_tests += \
@@ -1385,6 +1403,8 @@ tests += \
test-utf8 \
test-ellipsize \
test-util \
+ test-process-util \
+ test-terminal-util \
test-path-lookup \
test-ring \
test-barrier \
@@ -1414,6 +1434,7 @@ tests += \
test-socket-util \
test-fdset \
test-conf-files \
+ test-conf-parser \
test-capability \
test-async \
test-ratelimit \
@@ -1617,7 +1638,6 @@ test_copy_SOURCES = \
src/test/test-copy.c
test_copy_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
test_sigbus_SOURCES = \
@@ -1630,9 +1650,8 @@ test_condition_SOURCES = \
src/test/test-condition.c
test_condition_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
test_fdset_SOURCES = \
src/test/test-fdset.c
@@ -1659,12 +1678,23 @@ test_util_SOURCES = \
test_util_LDADD = \
libsystemd-shared.la
+test_process_util_SOURCES = \
+ src/test/test-process-util.c
+
+test_process_util_LDADD = \
+ libsystemd-shared.la
+
+test_terminal_util_SOURCES = \
+ src/test/test-terminal-util.c
+
+test_terminal_util_LDADD = \
+ libsystemd-shared.la
+
test_path_lookup_SOURCES = \
src/test/test-path-lookup.c
test_path_lookup_LDADD = \
-lm \
- libsystemd-units.la \
libsystemd-shared.la
test_uid_range_SOURCES = \
@@ -1721,9 +1751,6 @@ test_verbs_LDADD = \
test_namespace_LDADD = \
libsystemd-core.la
-CLEANFILES += \
- src/test/test-hashmap-ordered.c
-
BUILT_SOURCES += \
src/test/test-hashmap-ordered.c
@@ -1841,7 +1868,6 @@ test_btrfs_SOURCES = \
src/test/test-btrfs.c
test_btrfs_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
if HAVE_LIBIPTC
@@ -1917,7 +1943,6 @@ test_cgroup_SOURCES = \
src/test/test-cgroup.c
test_cgroup_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la \
libsystemd-internal.la
@@ -1939,9 +1964,8 @@ test_cgroup_util_SOURCES = \
src/test/test-cgroup-util.c
test_cgroup_util_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
test_env_replace_SOURCES = \
src/test/test-env-replace.c
@@ -1959,9 +1983,8 @@ test_strv_SOURCES = \
src/test/test-strv.c
test_strv_LDADD = \
- libsystemd-units.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
test_path_util_SOURCES = \
src/test/test-path-util.c
@@ -1997,8 +2020,6 @@ test_install_SOURCES = \
src/test/test-install.c
test_install_LDADD = \
- libsystemd-units.la \
- libsystemd-label.la \
libsystemd-shared.la \
libsystemd-internal.la
@@ -2028,13 +2049,19 @@ test_conf_files_SOURCES = \
test_conf_files_LDADD = \
libsystemd-shared.la
+test_conf_parser_SOURCES = \
+ src/test/test-conf-parser.c
+
+test_conf_parser_LDADD = \
+ libsystemd-shared.la
+
test_bus_policy_SOURCES = \
src/bus-proxyd/test-bus-xml-policy.c
test_bus_policy_LDADD = \
libsystemd-proxy.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
# ------------------------------------------------------------------------------
## .PHONY so it always rebuilds it
@@ -2081,14 +2108,14 @@ systemd_analyze_SOURCES = \
src/analyze/analyze-verify.c \
src/analyze/analyze-verify.h
-systemd_verify_CFLAGS = \
+systemd_analyze_CFLAGS = \
$(AM_CFLAGS) \
$(SECCOMP_CFLAGS)
systemd_analyze_LDADD = \
libsystemd-core.la \
- libsystemd-internal.la \
libsystemd-shared.la \
+ libsystemd-internal.la \
$(RT_LIBS)
# ------------------------------------------------------------------------------
@@ -2117,21 +2144,8 @@ systemd_update_done_SOURCES = \
src/update-done/update-done.c
systemd_update_done_LDADD = \
- libsystemd-internal.la \
- libsystemd-label.la \
- libsystemd-shared.la
-
-# ------------------------------------------------------------------------------
-systemd_shutdownd_SOURCES = \
- src/shutdownd/shutdownd.c
-
-systemd_shutdownd_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
-
-dist_doc_DATA += \
- src/systemd/sd-shutdown.h
+ libsystemd-shared.la \
+ libsystemd-internal.la
# ------------------------------------------------------------------------------
systemd_shutdown_SOURCES = \
@@ -2144,8 +2158,8 @@ systemd_shutdown_SOURCES = \
src/core/killall.c
systemd_shutdown_LDADD = \
- libsystemd-label.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2189,10 +2203,8 @@ systemd_tmpfiles_SOURCES = \
src/tmpfiles/tmpfiles.c
systemd_tmpfiles_LDADD = \
- libsystemd-units.la \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
if HAVE_ACL
systemd_tmpfiles_LDADD += \
@@ -2211,14 +2223,15 @@ nodist_systemunit_DATA += \
units/systemd-tmpfiles-clean.service
nodist_tmpfiles_DATA = \
+ tmpfiles.d/systemd.conf \
tmpfiles.d/etc.conf
dist_tmpfiles_DATA = \
- tmpfiles.d/systemd.conf \
tmpfiles.d/systemd-nologin.conf \
tmpfiles.d/tmp.conf \
tmpfiles.d/x11.conf \
- tmpfiles.d/var.conf
+ tmpfiles.d/var.conf \
+ tmpfiles.d/home.conf
if HAVE_SYSV_COMPAT
dist_tmpfiles_DATA += \
@@ -2241,24 +2254,20 @@ INSTALL_DIRS += \
endif
EXTRA_DIST += \
+ tmpfiles.d/systemd.conf.m4 \
tmpfiles.d/etc.conf.m4 \
units/systemd-tmpfiles-setup-dev.service.in \
units/systemd-tmpfiles-setup.service.in \
units/systemd-tmpfiles-clean.service.in
-CLEANFILES += \
- tmpfiles.d/etc.conf
-
# ------------------------------------------------------------------------------
if ENABLE_SYSUSERS
systemd_sysusers_SOURCES = \
src/sysusers/sysusers.c
systemd_sysusers_LDADD = \
- libsystemd-units.la \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
rootbin_PROGRAMS += \
systemd-sysusers
@@ -2269,23 +2278,19 @@ nodist_systemunit_DATA += \
SYSINIT_TARGET_WANTS += \
systemd-sysusers.service
-dist_sysusers_DATA = \
- sysusers.d/systemd.conf
-
nodist_sysusers_DATA = \
- sysusers.d/basic.conf
-
-EXTRA_DIST += \
- units/systemd-sysusers.service.in \
- sysusers.d/basic.conf.in
-
-CLEANFILES += \
+ sysusers.d/systemd.conf \
sysusers.d/basic.conf
INSTALL_DIRS += \
$(sysusersdir)
endif
+EXTRA_DIST += \
+ units/systemd-sysusers.service.in \
+ sysusers.d/systemd.conf.m4 \
+ sysusers.d/basic.conf.in
+
# ------------------------------------------------------------------------------
dist_factory_etc_DATA = \
factory/etc/nsswitch.conf
@@ -2302,10 +2307,8 @@ systemd_firstboot_SOURCES = \
src/firstboot/firstboot.c
systemd_firstboot_LDADD = \
- libsystemd-units.la \
- libsystemd-label.la \
- libsystemd-internal.la \
libsystemd-shared.la \
+ libsystemd-internal.la \
-lcrypt
rootbin_PROGRAMS += \
@@ -2314,13 +2317,13 @@ rootbin_PROGRAMS += \
nodist_systemunit_DATA += \
units/systemd-firstboot.service
-EXTRA_DIST += \
- units/systemd-firstboot.service.in
-
SYSINIT_TARGET_WANTS += \
systemd-firstboot.service
endif
+EXTRA_DIST += \
+ units/systemd-firstboot.service.in
+
# ------------------------------------------------------------------------------
systemd_machine_id_setup_SOURCES = \
src/machine-id-setup/machine-id-setup-main.c \
@@ -2328,9 +2331,8 @@ systemd_machine_id_setup_SOURCES = \
src/core/machine-id-setup.h
systemd_machine_id_setup_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
# ------------------------------------------------------------------------------
systemd_sysctl_SOURCES = \
@@ -2351,8 +2353,8 @@ systemd_fsck_SOURCES = \
src/fsck/fsck.c
systemd_fsck_LDADD = \
- libsystemd-internal.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2362,9 +2364,8 @@ systemd_machine_id_commit_SOURCES = \
src/core/machine-id-setup.h
systemd_machine_id_commit_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
SYSINIT_TARGET_WANTS += \
systemd-machine-id-commit.service
@@ -2375,7 +2376,8 @@ systemd_ac_power_SOURCES = \
systemd_ac_power_LDADD = \
libudev-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
# ------------------------------------------------------------------------------
systemd_detect_virt_SOURCES = \
@@ -2399,7 +2401,6 @@ systemd_getty_generator_SOURCES = \
src/getty-generator/getty-generator.c
systemd_getty_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2407,7 +2408,6 @@ systemd_debug_generator_SOURCES = \
src/debug-generator/debug-generator.c
systemd_debug_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2416,7 +2416,6 @@ systemd_fstab_generator_SOURCES = \
src/core/mount-setup.c
systemd_fstab_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2424,7 +2423,6 @@ systemd_system_update_generator_SOURCES = \
src/system-update-generator/system-update-generator.c
systemd_system_update_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2439,21 +2437,15 @@ systemd_hibernate_resume_SOURCES = \
src/hibernate-resume/hibernate-resume.c
systemd_hibernate_resume_LDADD = \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
systemd_hibernate_resume_generator_SOURCES = \
src/hibernate-resume/hibernate-resume-generator.c
systemd_hibernate_resume_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
-EXTRA_DIST += \
- units/systemd-hibernate.service.in \
- units/systemd-hibernate-resume@.service.in \
- units/systemd-hybrid-sleep.service.in
-
dist_systemunit_DATA += \
units/hibernate.target \
units/hybrid-sleep.target
@@ -2464,6 +2456,11 @@ nodist_systemunit_DATA += \
units/systemd-hybrid-sleep.service
endif
+EXTRA_DIST += \
+ units/systemd-hibernate.service.in \
+ units/systemd-hibernate-resume@.service.in \
+ units/systemd-hybrid-sleep.service.in
+
# ------------------------------------------------------------------------------
if ENABLE_EFI
systemgenerator_PROGRAMS += \
@@ -2473,20 +2470,26 @@ systemd_efi_boot_generator_SOURCES = \
src/efi-boot-generator/efi-boot-generator.c
systemd_efi_boot_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
+if HAVE_BLKID
bootctl_SOURCES = \
- src/boot/boot.h \
- src/boot/boot-loader.h \
- src/boot/bootctl.c \
- src/boot/boot-loader.c \
- src/boot/boot-efi.c
+ src/boot/bootctl.c
+
+bootctl_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DEFI_MACHINE_TYPE_NAME=\"$(EFI_MACHINE_TYPE_NAME)\" \
+ -DBOOTLIBDIR=\"$(bootlibdir)\"
+
+bootctl_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(BLKID_CFLAGS)
bootctl_LDADD = \
libsystemd-shared.la \
- libsystemd-internal.la
+ libsystemd-internal.la \
+ $(BLKID_LIBS)
bin_PROGRAMS += \
bootctl
@@ -2496,10 +2499,163 @@ dist_bashcompletion_DATA += \
dist_zshcompletion_DATA += \
shell-completion/zsh/_bootctl
+endif
+
+# ------------------------------------------------------------------------------
+if HAVE_GNUEFI
+efi_cppflags = \
+ $(EFI_CPPFLAGS) \
+ -I$(top_builddir) -include config.h \
+ -I$(EFI_INC_DIR)/efi \
+ -I$(EFI_INC_DIR)/efi/$(EFI_ARCH) \
+ -DEFI_MACHINE_TYPE_NAME=\"$(EFI_MACHINE_TYPE_NAME)\"
+
+efi_cflags = \
+ $(EFI_CFLAGS) \
+ -Wall \
+ -Wextra \
+ -std=gnu90 \
+ -nostdinc \
+ -ggdb -O0 \
+ -fpic \
+ -fshort-wchar \
+ -nostdinc \
+ -ffreestanding \
+ -fno-strict-aliasing \
+ -fno-stack-protector \
+ -Wsign-compare \
+ -Wno-missing-field-initializers
+
+if ARCH_X86_64
+efi_cflags += \
+ -mno-red-zone \
+ -mno-sse \
+ -mno-mmx \
+ -DEFI_FUNCTION_WRAPPER \
+ -DGNU_EFI_USE_MS_ABI
+endif
+
+if ARCH_IA32
+efi_cflags += \
+ -mno-sse \
+ -mno-mmx
+endif
+
+efi_ldflags = \
+ $(EFI_LDFLAGS) \
+ -T $(EFI_LDS_DIR)/elf_$(EFI_ARCH)_efi.lds \
+ -shared \
+ -Bsymbolic \
+ -nostdlib \
+ -znocombreloc \
+ -L $(EFI_LIB_DIR) \
+ $(EFI_LDS_DIR)/crt0-efi-$(EFI_ARCH).o
+
+# Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary' instead,
+# and add required symbols manually.
+if ARCH_AARCH64
+efi_ldflags += --defsym=EFI_SUBSYSTEM=0xa
+EFI_FORMAT = -O binary
+else
+EFI_FORMAT = --target=efi-app-$(EFI_ARCH)
+endif
+endif
+endif
+
+# ------------------------------------------------------------------------------
+systemd_boot_headers = \
+ src/boot/efi/util.h \
+ src/boot/efi/console.h \
+ src/boot/efi/graphics.h \
+ src/boot/efi/pefile.h
+systemd_boot_sources = \
+ src/boot/efi/util.c \
+ src/boot/efi/console.c \
+ src/boot/efi/graphics.c \
+ src/boot/efi/pefile.c \
+ src/boot/efi/boot.c
+
+EXTRA_DIST += $(systemd_boot_sources) $(systemd_boot_headers)
+
+if ENABLE_EFI
+if HAVE_GNUEFI
+systemd_boot_objects = $(addprefix $(top_builddir)/,$(systemd_boot_sources:.c=.o))
+systemd_boot_solib = $(top_builddir)/src/boot/efi/systemd_boot.so
+systemd_boot = systemd-boot$(EFI_MACHINE_TYPE_NAME).efi
+
+bootlib_DATA = $(systemd_boot)
+CLEANFILES += $(systemd_boot_objects) $(systemd_boot_solib) $(systemd_boot)
+
+$(top_builddir)/src/boot/efi/%.o: $(top_srcdir)/src/boot/efi/%.c $(addprefix $(top_srcdir)/,$(systemd_boot_headers))
+ @$(MKDIR_P) $(top_builddir)/src/boot/efi/
+ $(AM_V_CC)$(EFI_CC) $(efi_cppflags) $(efi_cflags) -c $< -o $@
+
+$(systemd_boot_solib): $(systemd_boot_objects)
+ $(AM_V_CCLD)$(LD) $(efi_ldflags) $(systemd_boot_objects) \
+ -o $@ -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name); \
+ nm -D -u $@ | grep ' U ' && exit 1 || :
+
+$(systemd_boot): $(systemd_boot_solib)
+ $(AM_V_GEN)$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \
+ -j .dynsym -j .rel -j .rela -j .reloc $(EFI_FORMAT) $< $@
+endif
endif
# ------------------------------------------------------------------------------
+stub_headers = \
+ src/boot/efi/util.h \
+ src/boot/efi/pefile.h \
+ src/boot/efi/graphics.h \
+ src/boot/efi/splash.h \
+ src/boot/efi/linux.h
+
+stub_sources = \
+ src/boot/efi/util.c \
+ src/boot/efi/pefile.c \
+ src/boot/efi/graphics.c \
+ src/boot/efi/splash.c \
+ src/boot/efi/linux.c \
+ src/boot/efi/stub.c
+
+EXTRA_DIST += $(stub_sources) $(stub_headers)
+
+if ENABLE_EFI
+if HAVE_GNUEFI
+stub_objects = $(addprefix $(top_builddir)/,$(stub_sources:.c=.o))
+stub_solib = $(top_builddir)/src/boot/efi/stub.so
+stub = linux$(EFI_MACHINE_TYPE_NAME).efi.stub
+
+bootlib_DATA += $(stub)
+CLEANFILES += $(stub_objects) $(stub_solib) $(stub)
+
+$(top_builddir)/src/boot/efi/%.o: $(top_srcdir)/src/boot/efi/%.c $(addprefix $(top_srcdir)/,$(stub_headers))
+ @$(MKDIR_P) $(top_builddir)/src/boot/efi/
+ $(AM_V_CC)$(EFI_CC) $(efi_cppflags) $(efi_cflags) -c $< -o $@
+
+$(stub_solib): $(stub_objects)
+ $(AM_V_CCLD)$(LD) $(efi_ldflags) $(stub_objects) \
+ -o $@ -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name); \
+ nm -D -u $@ | grep ' U ' && exit 1 || :
+
+$(stub): $(stub_solib)
+ $(AM_V_GEN)$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \
+ -j .dynsym -j .rel -j .rela -j .reloc $(EFI_FORMAT) $< $@
+
+# ------------------------------------------------------------------------------
+CLEANFILES += test-efi-disk.img
+
+test-efi-disk.img: $(systemd_boot) $(stub) test/test-efi-create-disk.sh
+ $(AM_V_GEN)test/test-efi-create-disk.sh
+
+test-efi: test-efi-disk.img
+ $(QEMU) -machine accel=kvm -m 1024 -bios $(QEMU_BIOS) -snapshot test-efi-disk.img
+endif
+endif
+
+EXTRA_DIST += test/test-efi-create-disk.sh
+
+# ------------------------------------------------------------------------------
if HAVE_BLKID
systemgenerator_PROGRAMS += \
systemd-gpt-auto-generator
@@ -2509,9 +2665,8 @@ systemd_gpt_auto_generator_SOURCES = \
src/shared/blkid-util.h
systemd_gpt_auto_generator_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la \
$(BLKID_LIBS)
@@ -2529,7 +2684,6 @@ systemd_dbus1_generator_SOURCES = \
src/dbus1-generator/dbus1-generator.c
systemd_dbus1_generator_LDADD = \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -2554,7 +2708,6 @@ systemd_sysv_generator_SOURCES = \
systemd_sysv_generator_LDADD = \
libsystemd-core.la \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2562,7 +2715,6 @@ systemd_rc_local_generator_SOURCES = \
src/rc-local-generator/rc-local-generator.c
systemd_rc_local_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2572,7 +2724,6 @@ systemd_remount_fs_SOURCES = \
src/core/mount-setup.h
systemd_remount_fs_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2595,11 +2746,9 @@ systemctl_SOURCES = \
src/systemctl/systemctl.c
systemctl_LDADD = \
- libsystemd-units.la \
- libsystemd-label.la \
- libsystemd-internal.la \
libsystemd-logs.la \
libsystemd-journal-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2607,23 +2756,22 @@ systemd_notify_SOURCES = \
src/notify/notify.c
systemd_notify_LDADD = \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
# ------------------------------------------------------------------------------
systemd_path_SOURCES = \
src/path/path.c
systemd_path_LDADD = \
- libsystemd-internal.la \
- libsystemd-shared.la
+ libsystemd-shared.la \
+ libsystemd-internal.la
# ------------------------------------------------------------------------------
systemd_ask_password_SOURCES = \
src/ask-password/ask-password.c
systemd_ask_password_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2662,9 +2810,9 @@ systemd_nspawn_CFLAGS = \
$(BLKID_CFLAGS)
systemd_nspawn_LDADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
libudev-internal.la \
+ libsystemd-internal.la \
+ libsystemd-machine.la \
libsystemd-shared.la \
$(BLKID_LIBS)
@@ -2684,7 +2832,6 @@ systemd_run_SOURCES = \
src/run/run.c
systemd_run_LDADD = \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -2748,9 +2895,6 @@ EXTRA_DIST += \
units/systemd-bus-proxyd.service.m4.in \
units/user/systemd-bus-proxyd.service.in
-CLEANFILES += \
- units/systemd-bus-proxyd.service.m4
-
if HAVE_SMACK
bus-proxyd-set-cap-hook:
-$(SETCAP) cap_mac_admin+ei $(DESTDIR)$(rootlibexecdir)/systemd-bus-proxyd
@@ -2763,7 +2907,6 @@ systemd_tty_ask_password_agent_SOURCES = \
src/tty-ask-password-agent/tty-ask-password-agent.c
systemd_tty_ask_password_agent_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
# ------------------------------------------------------------------------------
@@ -2781,6 +2924,7 @@ libsystemd_internal_la_SOURCES = \
src/systemd/sd-path.h \
src/systemd/sd-network.h \
src/systemd/sd-hwdb.h \
+ src/systemd/sd-device.h \
src/libsystemd/sd-bus/sd-bus.c \
src/libsystemd/sd-bus/bus-control.c \
src/libsystemd/sd-bus/bus-control.h \
@@ -2844,7 +2988,14 @@ libsystemd_internal_la_SOURCES = \
src/libsystemd/sd-network/network-util.c \
src/libsystemd/sd-hwdb/sd-hwdb.c \
src/libsystemd/sd-hwdb/hwdb-util.h \
- src/libsystemd/sd-hwdb/hwdb-internal.h
+ src/libsystemd/sd-hwdb/hwdb-internal.h \
+ src/libsystemd/sd-device/device-internal.h \
+ src/libsystemd/sd-device/device-util.h \
+ src/libsystemd/sd-device/device-enumerator.c \
+ src/libsystemd/sd-device/device-enumerator-private.h \
+ src/libsystemd/sd-device/sd-device.c \
+ src/libsystemd/sd-device/device-private.c \
+ src/libsystemd/sd-device/device-private.h
nodist_libsystemd_internal_la_SOURCES = \
src/libsystemd/libsystemd.sym
@@ -2884,9 +3035,6 @@ EXTRA_DIST += \
src/libsystemd/sd-bus/DIFFERENCES \
src/libsystemd/sd-bus/GVARIANT-SERIALIZATION
-CLEANFILES += \
- src/libsystemd/libsystemd.sym
-
BUILT_SOURCES += \
src/libsystemd/libsystemd.sym
@@ -2927,17 +3075,17 @@ pkgconfiglib_DATA += \
src/libsystemd/libsystemd.pc
pkginclude_HEADERS += \
+ src/systemd/sd-bus.h \
+ src/systemd/sd-bus-protocol.h \
+ src/systemd/sd-bus-vtable.h \
+ src/systemd/sd-event.h \
src/systemd/sd-login.h \
src/systemd/sd-id128.h \
src/systemd/sd-daemon.h
if ENABLE_KDBUS
pkginclude_HEADERS += \
- src/systemd/sd-bus.h \
- src/systemd/sd-bus-protocol.h \
- src/systemd/sd-bus-vtable.h \
src/systemd/sd-utf8.h \
- src/systemd/sd-event.h \
src/systemd/sd-rtnl.h \
src/systemd/sd-resolve.h \
src/systemd/sd-path.h
@@ -2949,13 +3097,13 @@ lib_LTLIBRARIES += \
tests += \
test-bus-marshal \
test-bus-signature \
+ test-bus-benchmark \
test-bus-chat \
test-bus-cleanup \
test-bus-server \
test-bus-match \
test-bus-kernel \
test-bus-kernel-bloom \
- test-bus-kernel-benchmark \
test-bus-zero-copy \
test-bus-introspect \
test-bus-objects \
@@ -3087,10 +3235,10 @@ test_bus_kernel_bloom_LDADD = \
libsystemd-internal.la \
libsystemd-shared.la
-test_bus_kernel_benchmark_SOURCES = \
- src/libsystemd/sd-bus/test-bus-kernel-benchmark.c
+test_bus_benchmark_SOURCES = \
+ src/libsystemd/sd-bus/test-bus-benchmark.c
-test_bus_kernel_benchmark_LDADD = \
+test_bus_benchmark_LDADD = \
libsystemd-internal.la \
libsystemd-shared.la
@@ -3211,7 +3359,6 @@ libsystemd_network_la_SOURCES = \
libsystemd_network_la_LIBADD = \
libudev-internal.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la \
$(KMOD_LIBS)
@@ -3234,7 +3381,6 @@ test_dhcp_client_SOURCES = \
test_dhcp_client_LDADD = \
libsystemd-network.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -3253,7 +3399,6 @@ test_ipv4ll_SOURCES = \
test_ipv4ll_LDADD = \
libsystemd-network.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -3459,15 +3604,6 @@ src/libsystemd-terminal/unifont-glyph-array.bin: tools/compile-unifont.py $(UNIF
$(AM_V_GEN)$(PYTHON) $< <$(UNIFONT) >$@
# ------------------------------------------------------------------------------
-if ENABLE_GTK_DOC
-SUBDIRS += \
- docs/libudev
-
-noinst_DATA += \
- docs/html/libudev \
- docs/html/gudev
-endif
-
include_HEADERS += \
src/libudev/libudev.h
@@ -3477,10 +3613,12 @@ lib_LTLIBRARIES += \
libudev_la_SOURCES =\
src/libudev/libudev.sym \
src/libudev/libudev-private.h \
+ src/libudev/libudev-device-internal.h \
src/libudev/libudev.c \
src/libudev/libudev-list.c \
src/libudev/libudev-util.c \
src/libudev/libudev-device.c \
+ src/libudev/libudev-device-private.c \
src/libudev/libudev-enumerate.c \
src/libudev/libudev-monitor.c \
src/libudev/libudev-queue.c \
@@ -3505,19 +3643,6 @@ pkgconfiglib_DATA += \
EXTRA_DIST += \
src/libudev/libudev.pc.in
-CLEANFILES += \
- src/libudev/libudev.pc \
- docs/html/libudev \
- docs/html/gudev
-
-docs/html/libudev:
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_LN)$(LN_S) -f ../libudev/html $@
-
-docs/html/gudev:
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_LN)$(LN_S) -f ../gudev/html $@
-
# move lib from $(libdir) to $(rootlibdir) and update devel link, if needed
libudev-install-hook:
libname=libudev.so && $(move-to-rootlibdir)
@@ -3533,8 +3658,7 @@ noinst_LTLIBRARIES += \
libudev-internal.la
libudev_internal_la_SOURCES =\
- $(libudev_la_SOURCES) \
- src/libudev/libudev-device-private.c
+ $(libudev_la_SOURCES)
libudev_internal_la_CFLAGS = \
$(AM_CFLAGS) \
@@ -3552,21 +3676,20 @@ dist_network_DATA = \
dist_udevrules_DATA += \
rules/42-usb-hid-pm.rules \
rules/50-udev-default.rules \
+ rules/60-block.rules \
rules/60-drm.rules \
- rules/60-keyboard.rules \
+ rules/60-evdev.rules \
rules/60-persistent-storage-tape.rules \
- rules/60-persistent-serial.rules \
rules/60-persistent-input.rules \
rules/60-persistent-alsa.rules \
rules/60-persistent-storage.rules \
+ rules/60-serial.rules \
rules/64-btrfs.rules \
rules/70-mouse.rules \
rules/70-touchpad.rules \
rules/75-net-description.rules \
- rules/75-tty-description.rules \
rules/78-sound-card.rules \
- rules/80-net-setup-link.rules \
- rules/95-udev-late.rules
+ rules/80-net-setup-link.rules
nodist_udevrules_DATA += \
rules/99-systemd.rules
@@ -3575,28 +3698,18 @@ udevconfdir = $(sysconfdir)/udev
dist_udevconf_DATA = \
src/udev/udev.conf
-sharepkgconfigdir = $(datadir)/pkgconfig
-sharepkgconfig_DATA = \
+pkgconfigdata_DATA += \
src/udev/udev.pc
EXTRA_DIST += \
rules/99-systemd.rules.in \
src/udev/udev.pc.in
-CLEANFILES += \
- rules/99-systemd.rules \
- src/udev/udev.pc
-
EXTRA_DIST += \
units/systemd-udevd.service.in \
units/systemd-udev-trigger.service.in \
units/systemd-udev-settle.service.in
-CLEANFILES += \
- units/systemd-udevd.service \
- units/systemd-udev-trigger.service \
- units/systemd-udev-settle.service
-
SOCKETS_TARGET_WANTS += \
systemd-udevd-control.socket \
systemd-udevd-kernel.socket
@@ -3614,19 +3727,22 @@ rootlibexec_PROGRAMS += \
noinst_LTLIBRARIES += \
libudev-core.la
-src/udev/keyboard-keys.txt:
+src/udev/keyboard-keys-list.txt:
$(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@
-src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys.txt
+src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys-list.txt
$(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print tolower(substr($$1 ,5)) ", " $$1 }' < $< > $@
src/udev/keyboard-keys-from-name.h: src/udev/keyboard-keys-from-name.gperf
$(AM_V_GPERF)$(GPERF) -L ANSI-C -t -N keyboard_lookup_key -H hash_key_name -p -C < $< > $@
-src/udev/keyboard-keys-to-name.h: src/udev/keyboard-keys.txt
+src/udev/keyboard-keys-to-name.h: src/udev/keyboard-keys-list.txt
$(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@
+gperf_txt_sources += \
+ src/udev/keyboard-keys-list.txt
+
libudev_core_la_SOURCES = \
src/udev/udev.h \
src/udev/udev-event.c \
@@ -3653,15 +3769,7 @@ nodist_libudev_core_la_SOURCES = \
src/udev/keyboard-keys-to-name.h \
src/udev/net/link-config-gperf.c
-BUILT_SOURCES += \
- $(nodist_libudev_core_la_SOURCES)
-
-CLEANFILES += \
- src/udev/keyboard-keys-from-name.gperf \
- src/udev/keyboard-keys.txt \
- src/udev/net/link-config-gperf.c
-
-EXTRA_DIST += \
+gperf_gperf_sources = \
src/udev/net/link-config-gperf.gperf
libudev_core_la_CFLAGS = \
@@ -3671,7 +3779,6 @@ libudev_core_la_CFLAGS = \
libudev_core_la_LIBADD = \
libudev-internal.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-network.la \
libsystemd-shared.la \
@@ -3734,9 +3841,9 @@ systemd_hwdb_SOURCES = \
src/hwdb/hwdb.c
systemd_hwdb_LDADD = \
+ libudev-internal.la \
libsystemd-shared.la \
- libsystemd-internal.la \
- libudev-internal.la
+ libsystemd-internal.la
rootbin_PROGRAMS += \
systemd-hwdb
@@ -3752,16 +3859,12 @@ dist_udevhwdb_DATA = \
hwdb/20-acpi-vendor.hwdb \
hwdb/20-OUI.hwdb \
hwdb/20-net-ifname.hwdb \
+ hwdb/60-evdev.hwdb \
hwdb/60-keyboard.hwdb \
hwdb/70-mouse.hwdb \
+ hwdb/70-pointingstick.hwdb \
hwdb/70-touchpad.hwdb
-EXTRA_DIST += \
- units/systemd-hwdb-update.service.in
-
-CLEANFILES += \
- units/systemd-hwdb-update.service
-
SYSINIT_TARGET_WANTS += \
systemd-hwdb-update.service
@@ -3777,6 +3880,11 @@ hwdb-remove-hook:
-test -n "$(DESTDIR)" || rm -f /etc/udev/hwdb.bin
endif
+EXTRA_DIST += \
+ units/systemd-hwdb-update.service.in \
+ hwdb/ids-update.pl \
+ hwdb/sdio.ids
+
# ------------------------------------------------------------------------------
TESTS += \
test/udev-test.pl \
@@ -3785,9 +3893,14 @@ TESTS += \
if HAVE_PYTHON
TESTS += \
test/rule-syntax-check.py \
+ $(NULL)
+
+if HAVE_SYSV_COMPAT
+TESTS += \
test/sysv-generator-test.py \
$(NULL)
endif
+endif
manual_tests += \
test-libudev \
@@ -3797,10 +3910,9 @@ test_libudev_SOURCES = \
src/test/test-libudev.c
test_libudev_LDADD = \
- libsystemd-label.la \
libudev-internal.la \
- libsystemd-shared.la \
- libsystemd-internal.la
+ libsystemd-internal.la \
+ libsystemd-shared.la
test_udev_SOURCES = \
src/test/test-udev.c
@@ -3833,6 +3945,7 @@ EXTRA_DIST += \
test/udev-test.pl \
test/rule-syntax-check.py \
test/sysv-generator-test.py \
+ test/mocks/fsck \
$(NULL)
@@ -3842,6 +3955,7 @@ ata_id_SOURCES = \
ata_id_LDADD = \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
udevlibexec_PROGRAMS += \
@@ -3853,6 +3967,7 @@ cdrom_id_SOURCES = \
cdrom_id_LDADD = \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
udevlibexec_PROGRAMS += \
@@ -3867,6 +3982,7 @@ collect_SOURCES = \
collect_LDADD = \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
udevlibexec_PROGRAMS += \
@@ -3881,6 +3997,7 @@ scsi_id_SOURCES =\
scsi_id_LDADD = \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
udevlibexec_PROGRAMS += \
@@ -3895,6 +4012,7 @@ v4l_id_SOURCES = \
v4l_id_LDADD = \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
udevlibexec_PROGRAMS += \
@@ -3909,6 +4027,7 @@ accelerometer_SOURCES = \
accelerometer_LDADD = \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
udevlibexec_PROGRAMS += \
@@ -3918,154 +4037,6 @@ dist_udevrules_DATA += \
rules/61-accelerometer.rules
# ------------------------------------------------------------------------------
-if ENABLE_GUDEV
-if ENABLE_GTK_DOC
-SUBDIRS += \
- docs/gudev
-endif
-
-libgudev_includedir = \
- $(includedir)/gudev-1.0/gudev
-
-libgudev_include_HEADERS = \
- src/gudev/gudev.h \
- src/gudev/gudevenums.h \
- src/gudev/gudevenumtypes.h \
- src/gudev/gudevtypes.h \
- src/gudev/gudevclient.h \
- src/gudev/gudevdevice.h \
- src/gudev/gudevenumerator.h
-
-lib_LTLIBRARIES += libgudev-1.0.la
-
-pkgconfiglib_DATA += \
- src/gudev/gudev-1.0.pc
-
-CLEANFILES += \
- src/gudev/gudev-1.0.pc
-
-libgudev_1_0_la_SOURCES = \
- src/gudev/libgudev-1.0.sym \
- src/gudev/gudevenums.h \
- src/gudev/gudevenumtypes.h \
- src/gudev/gudevenumtypes.h\
- src/gudev/gudevtypes.h \
- src/gudev/gudevclient.h \
- src/gudev/gudevclient.c \
- src/gudev/gudevdevice.h \
- src/gudev/gudevdevice.c \
- src/gudev/gudevenumerator.h \
- src/gudev/gudevenumerator.c \
- src/gudev/gudevprivate.h
-
-nodist_libgudev_1_0_la_SOURCES = \
- src/gudev/gudevmarshal.h \
- src/gudev/gudevmarshal.c \
- src/gudev/gudevenumtypes.h \
- src/gudev/gudevenumtypes.c
-
-BUILT_SOURCES += \
- $(nodist_libgudev_1_0_la_SOURCES)
-
-libgudev_1_0_la_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -I$(top_builddir)/src\
- -I$(top_srcdir)/src\
- -I$(top_builddir)/src/gudev \
- -I$(top_srcdir)/src/gudev \
- -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
- -D_GUDEV_COMPILATION \
- -DG_LOG_DOMAIN=\"GUdev\"
-
-libgudev_1_0_la_CFLAGS = \
- $(AM_CFLAGS) \
- -fvisibility=default \
- $(GLIB_CFLAGS)
-
-libgudev_1_0_la_LIBADD = \
- libudev.la \
- $(GLIB_LIBS)
-
-libgudev_1_0_la_LDFLAGS = \
- $(AM_LDFLAGS) \
- -version-info $(LIBGUDEV_CURRENT):$(LIBGUDEV_REVISION):$(LIBGUDEV_AGE) \
- -export-dynamic \
- -no-undefined \
- -Wl,--version-script=$(top_srcdir)/src/gudev/libgudev-1.0.sym
-
-src/gudev/gudevmarshal.h: src/gudev/gudevmarshal.list
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)glib-genmarshal $< --prefix=g_udev_marshal --header > $@
-
-src/gudev/gudevmarshal.c: src/gudev/gudevmarshal.list
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)echo '#include "gudevmarshal.h"' > $@ && \
- glib-genmarshal $< --prefix=g_udev_marshal --body >> $@
-
-src/gudev/gudevenumtypes.%: src/gudev/gudevenumtypes.%.template src/gudev/gudevenums.h
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)glib-mkenums --template $^ > $@
-
-if HAVE_INTROSPECTION
--include $(INTROSPECTION_MAKEFILE)
-
-src/gudev/GUdev-1.0.gir: libgudev-1.0.la
-
-src_gudev_GUdev_1_0_gir_INCLUDES = GObject-2.0
-
-src_gudev_GUdev_1_0_gir_CFLAGS = \
- $(AM_CFLAGS) \
- $(INCLUDES) \
- -D_GUDEV_COMPILATION \
- -D_GUDEV_WORK_AROUND_DEV_T_BUG \
- -I$(top_srcdir)/src \
- -I$(top_builddir)/src \
- -I$(top_srcdir)/src/gudev \
- -I$(top_builddir)/src/gudev
-
-src_gudev_GUdev_1_0_gir_LIBS = libgudev-1.0.la
-
-src_gudev_GUdev_1_0_gir_SCANNERFLAGS = \
- --pkg-export=gudev-1.0 \
- --warn-all
-
-src_gudev_GUdev_1_0_gir_FILES = \
- src/gudev/gudev.h \
- src/gudev/gudevtypes.h \
- src/gudev/gudevenums.h \
- src/gudev/gudevenumtypes.h \
- src/gudev/gudevclient.h \
- src/gudev/gudevdevice.h \
- src/gudev/gudevenumerator.h \
- src/gudev/gudevclient.c \
- src/gudev/gudevdevice.c \
- src/gudev/gudevenumerator.c
-
-INTROSPECTION_GIRS = src/gudev/GUdev-1.0.gir
-INTROSPECTION_SCANNER_ARGS = --c-include=gudev/gudev.h
-
-girdir = $(datadir)/gir-1.0
-gir_DATA = \
- src/gudev/GUdev-1.0.gir
-
-typelibsdir = $(libdir)/girepository-1.0
-typelibs_DATA = \
- src/gudev/GUdev-1.0.typelib
-
-CLEANFILES += $(gir_DATA) $(typelibs_DATA)
-endif # HAVE_INTROSPECTION
-endif
-
-EXTRA_DIST += \
- src/gudev/gudev-1.0.pc.in \
- src/gudev/gudevmarshal.list \
- src/gudev/gudevenumtypes.h.template \
- src/gudev/gudevenumtypes.c.template \
- src/gudev/gjs-example.js \
- src/gudev/seed-example-enum.js \
- src/gudev/seed-example.js
-
-# ------------------------------------------------------------------------------
mtd_probe_SOURCES = \
src/udev/mtd_probe/mtd_probe.c \
src/udev/mtd_probe/mtd_probe.h \
@@ -4097,7 +4068,6 @@ systemd_activate_SOURCES = \
src/activate/activate.c
systemd_activate_LDADD = \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -4165,9 +4135,6 @@ dist_systemunit_DATA += \
nodist_systemunit_DATA += \
units/systemd-journal-remote.service
-EXTRA_DIST += \
- units/systemd-journal-remote.service.in
-
journal-remote-install-hook: journal-install-hook
-$(MKDIR_P) $(DESTDIR)/var/log/journal/remote
-chown 0:0 $(DESTDIR)/var/log/journal/remote
@@ -4181,10 +4148,9 @@ nodist_pkgsysconf_DATA += \
src/journal-remote/journal-remote.conf
EXTRA_DIST += \
+ units/systemd-journal-remote.service.in \
src/journal-remote/journal-remote.conf.in
-CLEANFILES += \
- src/journal-remote/journal-remote.conf
endif
if HAVE_LIBCURL
@@ -4209,19 +4175,15 @@ systemd_journal_upload_LDADD = \
nodist_systemunit_DATA += \
units/systemd-journal-upload.service
-EXTRA_DIST += \
- units/systemd-journal-upload.service.in
-
nodist_pkgsysconf_DATA += \
src/journal-remote/journal-upload.conf
+endif
+
EXTRA_DIST += \
+ units/systemd-journal-upload.service.in \
src/journal-remote/journal-upload.conf.in
-CLEANFILES += \
- src/journal-remote/journal-upload.conf
-endif
-
# using _CFLAGS = in the conditional below would suppress AM_CFLAGS
journalctl_CFLAGS = \
$(AM_CFLAGS)
@@ -4342,6 +4304,12 @@ test_compress_benchmark_LDADD = \
libsystemd-journal-internal.la \
libsystemd-shared.la
+test_audit_type_SOURCES = \
+ src/journal/test-audit-type.c
+
+test_audit_type_LDADD = \
+ libsystemd-journal-core.la
+
libsystemd_journal_core_la_SOURCES = \
src/journal/journald-kmsg.c \
src/journal/journald-kmsg.h \
@@ -4369,7 +4337,6 @@ nodist_libsystemd_journal_core_la_SOURCES = \
libsystemd_journal_core_la_LIBADD = \
libsystemd-journal-internal.la \
libudev-internal.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -4424,7 +4391,8 @@ tests += \
test-journal-interleaving \
test-journal-flush \
test-mmap-cache \
- test-catalog
+ test-catalog \
+ test-audit-type
if HAVE_COMPRESSION
tests += \
@@ -4456,14 +4424,21 @@ libsystemd_journal_internal_la_SOURCES = \
src/journal/catalog.h \
src/journal/mmap-cache.c \
src/journal/mmap-cache.h \
- src/journal/compress.c
+ src/journal/compress.c \
+ src/journal/audit-type.h \
+ src/journal/audit-type.c
+
+nodist_libsystemd_journal_internal_la_SOURCES = \
+ src/journal/audit_type-to-name.h
+
+gperf_txt_sources += \
+ src/journal/audit_type-list.txt
# using _CFLAGS = in the conditional below would suppress AM_CFLAGS
libsystemd_journal_internal_la_CFLAGS = \
$(AM_CFLAGS)
-libsystemd_journal_internal_la_LIBADD = \
- libsystemd-label.la
+libsystemd_journal_internal_la_LIBADD =
if HAVE_XZ
libsystemd_journal_internal_la_CFLAGS += \
@@ -4540,11 +4515,10 @@ SYSINIT_TARGET_WANTS += \
EXTRA_DIST += \
units/systemd-journald.service.in \
units/systemd-journal-flush.service.in \
- units/systemd-journal-catalog-update.service.in \
- src/journal/journald-gperf.gperf
+ units/systemd-journal-catalog-update.service.in
-CLEANFILES += \
- src/journal/journald-gperf.c
+gperf_gperf_sources += \
+ src/journal/journald-gperf.gperf
# ------------------------------------------------------------------------------
if HAVE_MICROHTTPD
@@ -4613,7 +4587,6 @@ systemd_coredump_SOURCES = \
systemd_coredump_LDADD = \
libsystemd-journal-internal.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -4666,7 +4639,7 @@ dist_bashcompletion_DATA += \
dist_zshcompletion_DATA += \
shell-completion/zsh/_coredumpctl
-sysctl_DATA = \
+nodist_sysctl_DATA = \
sysctl.d/50-coredump.conf
CLEANFILES += \
@@ -4718,17 +4691,14 @@ systemd_vconsole_setup_LDADD = \
rootlibexec_PROGRAMS += \
systemd-vconsole-setup
-nodist_systemunit_DATA += \
- units/systemd-vconsole-setup.service
-
nodist_udevrules_DATA += \
src/vconsole/90-vconsole.rules
+nodist_systemunit_DATA += \
+ units/systemd-vconsole-setup.service
+
SYSINIT_TARGET_WANTS += \
systemd-vconsole-setup.service
-
-CLEANFILES += \
- src/vconsole/90-vconsole.rules
endif
EXTRA_DIST += \
@@ -4757,14 +4727,11 @@ dist_pkgsysconf_DATA += \
nodist_systemunit_DATA += \
units/systemd-bootchart.service
+endif
EXTRA_DIST += \
units/systemd-bootchart.service.in
-CLEANFILES += \
- units/systemd-bootchart.service
-endif
-
# ------------------------------------------------------------------------------
if ENABLE_QUOTACHECK
rootlibexec_PROGRAMS += \
@@ -4798,7 +4765,6 @@ systemd_random_seed_SOURCES = \
src/random-seed/random-seed.c
systemd_random_seed_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
SYSINIT_TARGET_WANTS += \
@@ -4821,8 +4787,8 @@ systemd_backlight_SOURCES = \
src/backlight/backlight.c
systemd_backlight_LDADD = \
- libsystemd-label.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
endif
@@ -4841,8 +4807,8 @@ systemd_rfkill_SOURCES = \
src/rfkill/rfkill.c
systemd_rfkill_LDADD = \
- libsystemd-label.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
endif
@@ -4869,8 +4835,8 @@ systemd_cryptsetup_CFLAGS = \
$(LIBCRYPTSETUP_CFLAGS)
systemd_cryptsetup_LDADD = \
- libsystemd-label.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la \
$(LIBCRYPTSETUP_LIBS)
@@ -4878,7 +4844,6 @@ systemd_cryptsetup_generator_SOURCES = \
src/cryptsetup/cryptsetup-generator.c
systemd_cryptsetup_generator_LDADD = \
- libsystemd-label.la \
libsystemd-shared.la
SYSINIT_TARGET_WANTS += \
@@ -4892,7 +4857,6 @@ systemd_hostnamed_SOURCES = \
src/hostname/hostnamed.c
systemd_hostnamed_LDADD = \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -4957,7 +4921,6 @@ systemd_localed_SOURCES = \
src/locale/localed.c
systemd_localed_LDADD = \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la \
$(XKBCOMMON_LIBS)
@@ -5026,7 +4989,6 @@ systemd_timedated_SOURCES = \
src/timedate/timedated.c
systemd_timedated_LDADD = \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -5091,16 +5053,12 @@ systemd_timesyncd_SOURCES = \
nodist_systemd_timesyncd_SOURCES = \
src/timesync/timesyncd-gperf.c
-EXTRA_DIST += \
+gperf_gperf_sources += \
src/timesync/timesyncd-gperf.gperf
-CLEANFILES += \
- src/timesync/timesyncd-gperf.c
-
systemd_timesyncd_LDADD = \
libsystemd-resolve.la \
libsystemd-network.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la
@@ -5121,9 +5079,6 @@ nodist_pkgsysconf_DATA += \
EXTRA_DIST += \
src/timesync/timesyncd.conf.in
-
-CLEANFILES += \
- src/timesync/timesyncd.conf
endif
# ------------------------------------------------------------------------------
@@ -5171,9 +5126,9 @@ libsystemd_machine_core_la_SOURCES = \
src/machine/image-dbus.h
libsystemd_machine_core_la_LIBADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
libudev-internal.la \
+ libsystemd-internal.la \
+ libsystemd-machine.la \
libsystemd-shared.la
noinst_LTLIBRARIES += \
@@ -5234,9 +5189,6 @@ SYSTEM_UNIT_ALIASES += \
BUSNAMES_TARGET_WANTS += \
org.freedesktop.machine1.busname
-EXTRA_DIST += \
- units/systemd-machined.service.in
-
libnss_mymachines_la_SOURCES = \
src/nss-mymachines/nss-mymachines.sym \
src/nss-mymachines/nss-mymachines.c
@@ -5259,6 +5211,9 @@ lib_LTLIBRARIES += \
endif
+EXTRA_DIST += \
+ units/systemd-machined.service.in
+
# ------------------------------------------------------------------------------
if ENABLE_IMPORTD
@@ -5270,32 +5225,40 @@ if HAVE_GCRYPT
rootlibexec_PROGRAMS += \
systemd-importd \
- systemd-pull
+ systemd-pull \
+ systemd-import \
+ systemd-export
systemd_importd_SOURCES = \
src/import/importd.c
systemd_importd_CFLAGS = \
$(AM_CFLAGS) \
- -D SYSTEMD_PULL_PATH=\"$(rootlibexecdir)/systemd-pull\"
+ -D SYSTEMD_PULL_PATH=\"$(rootlibexecdir)/systemd-pull\" \
+ -D SYSTEMD_IMPORT_PATH=\"$(rootlibexecdir)/systemd-import\" \
+ -D SYSTEMD_EXPORT_PATH=\"$(rootlibexecdir)/systemd-export\"
systemd_importd_LDADD = \
+ libsystemd-machine.la \
libsystemd-internal.la \
- libsystemd-label.la \
libsystemd-shared.la
systemd_pull_SOURCES = \
src/import/pull.c \
- src/import/import-raw.c \
- src/import/import-raw.h \
- src/import/import-tar.c \
- src/import/import-tar.h \
- src/import/import-dkr.c \
- src/import/import-dkr.h \
- src/import/import-job.c \
- src/import/import-job.h \
+ src/import/pull-raw.c \
+ src/import/pull-raw.h \
+ src/import/pull-tar.c \
+ src/import/pull-tar.h \
+ src/import/pull-dkr.c \
+ src/import/pull-dkr.h \
+ src/import/pull-job.c \
+ src/import/pull-job.h \
+ src/import/pull-common.c \
+ src/import/pull-common.h \
src/import/import-common.c \
src/import/import-common.h \
+ src/import/import-compress.c \
+ src/import/import-compress.h \
src/import/curl-util.c \
src/import/curl-util.h \
src/import/aufs-util.c \
@@ -5313,8 +5276,8 @@ systemd_pull_CFLAGS = \
-D USER_KEYRING_PATH=\"$(pkgsysconfdir)/import-pubring.gpg\"
systemd_pull_LDADD = \
+ libsystemd-machine.la \
libsystemd-internal.la \
- libsystemd-label.la \
libsystemd-shared.la \
$(LIBCURL_LIBS) \
$(XZ_LIBS) \
@@ -5322,15 +5285,62 @@ systemd_pull_LDADD = \
-lbz2 \
$(GCRYPT_LIBS)
+systemd_import_SOURCES = \
+ src/import/import.c \
+ src/import/import-raw.c \
+ src/import/import-raw.h \
+ src/import/import-tar.c \
+ src/import/import-tar.h \
+ src/import/import-common.c \
+ src/import/import-common.h \
+ src/import/import-compress.c \
+ src/import/import-compress.h \
+ src/import/qcow2-util.c \
+ src/import/qcow2-util.h
+
+systemd_import_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(XZ_CFLAGS) \
+ $(ZLIB_CFLAGS)
+
+systemd_import_LDADD = \
+ libsystemd-machine.la \
+ libsystemd-internal.la \
+ libsystemd-shared.la \
+ $(XZ_LIBS) \
+ $(ZLIB_LIBS) \
+ -lbz2
+
+systemd_export_SOURCES = \
+ src/import/export.c \
+ src/import/export-tar.c \
+ src/import/export-tar.h \
+ src/import/export-raw.c \
+ src/import/export-raw.h \
+ src/import/import-common.c \
+ src/import/import-common.h \
+ src/import/import-compress.c \
+ src/import/import-compress.h
+
+systemd_export_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(XZ_CFLAGS) \
+ $(ZLIB_CFLAGS)
+
+systemd_export_LDADD = \
+ libsystemd-machine.la \
+ libsystemd-internal.la \
+ libsystemd-shared.la \
+ $(XZ_LIBS) \
+ $(ZLIB_LIBS) \
+ -lbz2
+
dist_rootlibexec_DATA = \
src/import/import-pubring.gpg
nodist_systemunit_DATA += \
units/systemd-importd.service
-EXTRA_DIST += \
- units/systemd-importd.service.in
-
dist_systemunit_DATA_busnames += \
units/org.freedesktop.import1.busname
@@ -5366,7 +5376,6 @@ test_qcow2_CFLAGS = \
test_qcow2_LDADD = \
libsystemd-internal.la \
- libsystemd-label.la \
libsystemd-shared.la \
$(ZLIB_LIBS)
@@ -5378,6 +5387,11 @@ endif
endif
+EXTRA_DIST += \
+ units/systemd-importd.service.in \
+ src/resolve/resolved.conf.in
+
+
# ------------------------------------------------------------------------------
if ENABLE_RESOLVED
systemd_resolved_SOURCES = \
@@ -5416,23 +5430,21 @@ systemd_resolved_SOURCES = \
src/resolve/resolved-dns-stream.h \
src/resolve/resolved-dns-stream.c \
src/resolve/dns-type.c \
- src/resolve/dns-type.h \
- src/resolve/dns_type-from-name.h \
- src/resolve/dns_type-to-name.h
+ src/resolve/dns-type.h
nodist_systemd_resolved_SOURCES = \
+ src/resolve/dns_type-from-name.h \
+ src/resolve/dns_type-to-name.h \
src/resolve/resolved-gperf.c
-EXTRA_DIST += \
- src/resolve/resolved-gperf.gperf \
- src/resolve/dns_type-from-name.gperf
+gperf_gperf_sources += \
+ src/resolve/resolved-gperf.gperf
-CLEANFILES += \
- src/resolve/resolved-gperf.c
+gperf_txt_sources += \
+ src/resolve/dns_type-list.txt
systemd_resolved_LDADD = \
libsystemd-network.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la \
$(LIBIDN_LIBS)
@@ -5452,9 +5464,6 @@ dist_dbuspolicy_DATA += \
dist_dbussystemservice_DATA += \
src/resolve/org.freedesktop.resolve1.service
-EXTRA_DIST += \
- units/systemd-resolved.service.in
-
SYSTEM_UNIT_ALIASES += \
systemd-resolved.service dbus-org.freedesktop.resolve1.service
@@ -5467,12 +5476,6 @@ GENERAL_ALIASES += \
nodist_pkgsysconf_DATA += \
src/resolve/resolved.conf
-EXTRA_DIST += \
- src/resolve/resolved.conf.in
-
-CLEANFILES += \
- src/resolve/resolved.conf
-
tests += \
test-dns-domain
@@ -5483,7 +5486,6 @@ test_dns_domain_SOURCES = \
test_dns_domain_LDADD = \
libsystemd-network.la \
- libsystemd-label.la \
libsystemd-internal.la \
libsystemd-shared.la \
$(LIBIDN_LIBS)
@@ -5521,7 +5523,9 @@ systemd_resolve_host_SOURCES = \
src/resolve/resolved-dns-domain.c \
src/resolve/resolved-dns-domain.h \
src/resolve/dns-type.c \
- src/resolve/dns-type.h \
+ src/resolve/dns-type.h
+
+nodist_systemd_resolve_host_SOURCES = \
src/resolve/dns_type-from-name.h \
src/resolve/dns_type-to-name.h
@@ -5535,6 +5539,9 @@ rootlibexec_PROGRAMS += \
endif
+EXTRA_DIST += \
+ units/systemd-resolved.service.m4.in
+
# ------------------------------------------------------------------------------
if ENABLE_NETWORKD
rootlibexec_PROGRAMS += \
@@ -5605,7 +5612,6 @@ libsystemd_networkd_core_la_LIBADD = \
libudev-internal.la \
libsystemd-internal.la \
libsystemd-network.la \
- libsystemd-label.la \
libsystemd-shared.la
rootlibexec_PROGRAMS += \
@@ -5635,8 +5641,8 @@ networkctl_SOURCES = \
src/network/networkctl.c
networkctl_LDADD = \
- libsystemd-internal.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la \
libsystemd-network.la
@@ -5695,17 +5701,15 @@ SYSTEM_UNIT_ALIASES += \
BUSNAMES_TARGET_WANTS += \
org.freedesktop.network1.busname
-EXTRA_DIST += \
+gperf_gperf_sources += \
src/network/networkd-network-gperf.gperf \
- src/network/networkd-netdev-gperf.gperf \
- units/systemd-networkd.service.in \
- units/systemd-networkd-wait-online.service.in
-
-CLEANFILES += \
- src/network/networkd-network-gperf.c \
- src/network/networkd-netdev-gperf.c
+ src/network/networkd-netdev-gperf.gperf
endif
+EXTRA_DIST += \
+ units/systemd-networkd.service.m4.in \
+ units/systemd-networkd-wait-online.service.in
+
# ------------------------------------------------------------------------------
if ENABLE_LOGIND
systemd_logind_SOURCES = \
@@ -5740,12 +5744,12 @@ libsystemd_logind_core_la_SOURCES = \
src/login/logind-session-dbus.c \
src/login/logind-seat-dbus.c \
src/login/logind-user-dbus.c \
+ src/login/logind-utmp.c \
src/login/logind-acl.h
libsystemd_logind_core_la_LIBADD = \
- libsystemd-label.la \
- libsystemd-internal.la \
libudev-internal.la \
+ libsystemd-internal.la \
libsystemd-shared.la
if HAVE_ACL
@@ -5759,15 +5763,8 @@ endif
noinst_LTLIBRARIES += \
libsystemd-logind-core.la
-systemd_user_sessions_SOURCES = \
- src/login/user-sessions.c
-
-systemd_user_sessions_LDADD = \
- libsystemd-shared.la
-
rootlibexec_PROGRAMS += \
- systemd-logind \
- systemd-user-sessions
+ systemd-logind
loginctl_SOURCES = \
src/login/loginctl.c \
@@ -5775,10 +5772,10 @@ loginctl_SOURCES = \
src/login/sysfs-show.c
loginctl_LDADD = \
+ libudev-internal.la \
libsystemd-internal.la \
libsystemd-logs.la \
libsystemd-journal-internal.la \
- libudev-internal.la \
libsystemd-shared.la
rootbin_PROGRAMS += \
@@ -5864,11 +5861,11 @@ pamlib_LTLIBRARIES = \
dist_pamconf_DATA = \
src/login/systemd-user
+
endif
nodist_systemunit_DATA += \
- units/systemd-logind.service \
- units/systemd-user-sessions.service
+ units/systemd-logind.service
dist_systemunit_DATA += \
units/user.slice
@@ -5892,8 +5889,7 @@ INSTALL_DIRS += \
$(systemdstatedir)
MULTI_USER_TARGET_WANTS += \
- systemd-logind.service \
- systemd-user-sessions.service
+ systemd-logind.service
SYSTEM_UNIT_ALIASES += \
systemd-logind.service dbus-org.freedesktop.login1.service
@@ -5909,23 +5905,44 @@ nodist_udevrules_DATA += \
src/login/71-seat.rules \
src/login/73-seat-late.rules
-CLEANFILES += \
- src/login/logind-gperf.c \
- src/login/71-seat.rules \
- src/login/73-seat-late.rules
endif
polkitpolicy_in_files += \
src/login/org.freedesktop.login1.policy.in
+gperf_gperf_sources += \
+ src/login/logind-gperf.gperf
+
EXTRA_DIST += \
- src/login/logind-gperf.gperf \
src/login/71-seat.rules.in \
src/login/73-seat-late.rules.in \
- units/systemd-logind.service.in \
+ units/systemd-logind.service.in
+
+# ------------------------------------------------------------------------------
+if HAVE_PAM
+
+systemd_user_sessions_SOURCES = \
+ src/user-sessions/user-sessions.c
+
+systemd_user_sessions_LDADD = \
+ libsystemd-shared.la
+
+rootlibexec_PROGRAMS += \
+ systemd-user-sessions
+
+nodist_systemunit_DATA += \
+ units/systemd-user-sessions.service
+
+MULTI_USER_TARGET_WANTS += \
+ systemd-user-sessions.service
+
+endif
+
+EXTRA_DIST += \
units/systemd-user-sessions.service.in
# ------------------------------------------------------------------------------
+
if HAVE_PYTHON_DEVEL
pkgpyexec_LTLIBRARIES = \
_journal.la \
@@ -6051,7 +6068,7 @@ src/python-systemd/id128-constants.h: src/systemd/sd-messages.h
$(AM_V_GEN)$(SED) -n -r 's/,//g; s/#define (SD_MESSAGE_[A-Z0-9_]+)\s.*/add_id(m, "\1", \1) JOINER/p' <$< >$@
BUILT_SOURCES += \
- src/python-systemd/id128-constants.h
+ $(nodist_id128_la_SOURCES)
SPHINXOPTS = -D version=$(VERSION) -D release=$(VERSION)
sphinx-%:
@@ -6085,9 +6102,6 @@ clean-python:
# ------------------------------------------------------------------------------
if ENABLE_COMPAT_LIBS
-EXTRA_DIST += \
- src/compat-libs/linkwarning.h
-
libsystemd-%.c: src/compat-libs/libsystemd-%.sym
$(AM_V_at)$(MKDIR_P) $(dir $@)
$(AM_V_GEN)sed -r -n 's/^ +(sd_.*);/obsolete_lib(\1,$(notdir $(basename $<)));/p' <$< >$@
@@ -6103,7 +6117,7 @@ libsystemd_journal_la_SOURCES = \
src/compat-libs/libsystemd-journal.sym
libsystemd_journal_la_CPPFLAGS = \
- $(AM_CFLAGS) \
+ $(AM_CPPFLAGS) \
-imacros$(top_srcdir)/src/compat-libs/linkwarning.h
libsystemd_journal_la_LDFLAGS = \
@@ -6121,7 +6135,7 @@ libsystemd_login_la_SOURCES = \
src/compat-libs/libsystemd-login.sym
libsystemd_login_la_CPPFLAGS = \
- $(AM_CFLAGS) \
+ $(AM_CPPFLAGS) \
-imacros$(top_srcdir)/src/compat-libs/linkwarning.h
libsystemd_login_la_LDFLAGS = \
@@ -6138,7 +6152,7 @@ libsystemd_id128_la_SOURCES = \
src/compat-libs/libsystemd-id128.sym
libsystemd_id128_la_CPPFLAGS = \
- $(AM_CFLAGS) \
+ $(AM_CPPFLAGS) \
-imacros$(top_srcdir)/src/compat-libs/linkwarning.h
libsystemd_id128_la_LDFLAGS = \
@@ -6155,7 +6169,7 @@ libsystemd_daemon_la_SOURCES = \
src/compat-libs/libsystemd-daemon.sym
libsystemd_daemon_la_CPPFLAGS = \
- $(AM_CFLAGS) \
+ $(AM_CPPFLAGS) \
-imacros$(top_srcdir)/src/compat-libs/linkwarning.h
libsystemd_daemon_la_LDFLAGS = \
@@ -6197,6 +6211,7 @@ UNINSTALL_EXEC_HOOKS += compat-lib-uninstall-hook
endif
EXTRA_DIST += \
+ src/compat-libs/linkwarning.h \
src/compat-libs/libsystemd-journal.pc.in \
src/compat-libs/libsystemd-login.pc.in \
src/compat-libs/libsystemd-id128.pc.in \
@@ -6243,6 +6258,8 @@ substitutions = \
'|DEBUGTTY=$(DEBUGTTY)|' \
'|KILL=$(KILL)|' \
'|KMOD=$(KMOD)|' \
+ '|MOUNT_PATH=$(MOUNT_PATH)|' \
+ '|UMOUNT_PATH=$(UMOUNT_PATH)|' \
'|MKDIR_P=$(MKDIR_P)|' \
'|QUOTAON=$(QUOTAON)|' \
'|QUOTACHECK=$(QUOTACHECK)|' \
@@ -6258,7 +6275,6 @@ substitutions = \
'|systemgidmax=$(SYSTEM_GID_MAX)|' \
'|TTY_GID=$(TTY_GID)|' \
'|systemsleepdir=$(systemsleepdir)|' \
- '|systemshutdowndir=$(systemshutdowndir)|' \
'|binfmtdir=$(binfmtdir)|' \
'|modulesloaddir=$(modulesloaddir)|'
@@ -6336,12 +6352,6 @@ EXTRA_DIST += \
$(polkitpolicy_in_files) \
$(polkitpolicy_in_in_files)
-CLEANFILES += \
- $(nodist_systemunit_DATA) \
- $(nodist_userunit_DATA) \
- $(pkgconfiglib_DATA) \
- $(nodist_polkitpolicy_DATA)
-
# ------------------------------------------------------------------------------
if ENABLE_MANPAGES
man/custom-entities.ent: configure.ac
@@ -6350,7 +6360,7 @@ man/custom-entities.ent: configure.ac
printf '$(subst '|,<!ENTITY ,$(subst =, ",$(subst |',">\n,$(substitutions))))') \
> $@ # '
-DISTCLEANFILES += \
+CLEANFILES += \
man/custom-entities.ent
XSLTPROC_FLAGS = \
@@ -6421,20 +6431,15 @@ EXTRA_DIST += \
docs/var-log/README.in
SOCKETS_TARGET_WANTS += \
- systemd-initctl.socket \
- systemd-shutdownd.socket
+ systemd-initctl.socket
if HAVE_UTMP
if HAVE_SYSV_COMPAT
-RUNLEVEL1_TARGET_WANTS += \
- systemd-update-utmp-runlevel.service
-RUNLEVEL2_TARGET_WANTS += \
- systemd-update-utmp-runlevel.service
-RUNLEVEL3_TARGET_WANTS += \
+MULTI_USER_TARGET_WANTS += \
systemd-update-utmp-runlevel.service
-RUNLEVEL4_TARGET_WANTS += \
+GRAPHICAL_TARGET_WANTS += \
systemd-update-utmp-runlevel.service
-RUNLEVEL5_TARGET_WANTS += \
+RESCUE_TARGET_WANTS += \
systemd-update-utmp-runlevel.service
endif
@@ -6447,7 +6452,8 @@ SYSINIT_TARGET_WANTS += \
LOCAL_FS_TARGET_WANTS += \
systemd-remount-fs.service \
- tmp.mount
+ tmp.mount \
+ var-lib-machines.mount
MULTI_USER_TARGET_WANTS += \
getty.target \
@@ -6552,7 +6558,6 @@ DISTCHECK_CONFIGURE_FLAGS = \
--with-pamlibdir=$$dc_install_base/$(pamlibdir) \
--with-pamconfdir=$$dc_install_base/$(pamconfdir) \
--with-rootprefix=$$dc_install_base \
- --disable-split-usr \
--enable-kdbus \
--enable-compat-libs
@@ -6571,9 +6576,12 @@ DISTCHECK_CONFIGURE_FLAGS += \
--with-python
endif
-if ENABLE_GTK_DOC
+if ENABLE_SPLIT_USR
+DISTCHECK_CONFIGURE_FLAGS += \
+ --enable-split-usr
+else
DISTCHECK_CONFIGURE_FLAGS += \
- --enable-gtk-doc
+ --disable-split-usr
endif
#
@@ -6602,11 +6610,6 @@ dist-check-help: $(rootbin_PROGRAMS) $(bin_PROGRAMS)
dist: dist-check-python dist-check-compat-libs
-# check "broken" platforms limited toolchains for link breakage before we release
-.PHONY: linkcheck
-linkcheck:
- $(MAKE) CFLAGS='-fno-lto' LDFLAGS='-Wl,-fuse-ld=gold -Wl,--as-needed -Wl,--no-gc-sections' distcheck
-
.PHONY: hwdb-update
hwdb-update:
( cd $(top_srcdir)/hwdb && \
@@ -6632,10 +6635,6 @@ upload: all check dist
.PHONY: doc-sync
doc-sync: all destdir-sphinx
- gtkdoc-rebase --html-dir=docs/libudev/html --online
- rsync -rlv --delete docs/libudev/html/ --omit-dir-times $(www_target)/libudev/
- gtkdoc-rebase --html-dir=docs/gudev/html --online
- rsync -rlv --delete docs/gudev/html/ --omit-dir-times $(www_target)/gudev/
rsync -rlv --delete-excluded --include="*.html" --exclude="*" --omit-dir-times man/ $(www_target)/man/
rsync -rlv --delete --omit-dir-times docs/html/python-systemd/ $(www_target)/python-systemd/
@@ -6725,7 +6724,8 @@ test-libsystemd-sym.c: \
src/systemd/sd-bus.h \
src/systemd/sd-utf8.h \
src/systemd/sd-resolve.h \
- src/systemd/sd-path.h
+ src/systemd/sd-path.h \
+ src/systemd/sd-event.h
$(generate-sym-test)
test-libudev-sym.c: \
diff --git a/NEWS b/NEWS
index d788749240..2e2d1cefeb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,245 @@
systemd System and Service Manager
+CHANGES WITH 221:
+
+ * Support for chkconfig (--enable-chkconfig) was removed in favour of
+ calling an abstraction /lib/systemd/systemd-sysv-install. This needs
+ to be implemented for your distribution. See "SYSV INIT.D SCRIPTS" in
+ README for details.
+
+ Contributions from: ...
+
+ -- Berlin, UNRELEASED
+
+CHANGES WITH 220:
+
+ * The gudev library has been extracted into a separate repository
+ available at: https://git.gnome.org/browse/libgudev/
+ It is now managed as part of the Gnome project. Distributions
+ are recommended to pass --disable-gudev to systemd and use
+ gudev from the Gnome project instead. gudev is still included
+ in systemd, for now. It will be removed soon, though. Please
+ also see the announcement-thread on systemd-devel:
+ http://lists.freedesktop.org/archives/systemd-devel/2015-May/032070.html
+
+ * systemd now exposes a CPUUsageNSec= property for each
+ service unit on the bus, that contains the overall consumed
+ CPU time of a service (the sum of what each process of the
+ service consumed). This value is only available if
+ CPUAccounting= is turned on for a service, and is then shown
+ in the "systemctl status" output.
+
+ * Support for configuring alternative mappings of the old SysV
+ runlevels to systemd targets has been removed. They are now
+ hardcoded in a way that runlevels 2, 3, 4 all map to
+ multi-user.target and 5 to graphical.target (which
+ previously was already the default behaviour).
+
+ * The auto-mounter logic gained support for mount point
+ expiry, using a new TimeoutIdleSec= setting in .automount
+ units. (Also available as x-systemd.idle-timeout= in /etc/fstab).
+
+ * The EFI System Partition (ESP) as mounted to /boot by
+ systemd-efi-boot-generator will now be unmounted
+ automatically after 2 minutes of not being used. This should
+ minimize the risk of ESP corruptions.
+
+ * New /etc/fstab options x-systemd.requires= and
+ x-systemd.requires-mounts-for= are now supported to express
+ additional dependencies for mounts. This is useful for
+ journalling file systems that support external journal
+ devices or overlay file systems that require underlying file
+ systems to be mounted.
+
+ * systemd does not support direct live-upgrades (via systemctl
+ daemon-reexec) from versions older than v44 anymore. As no
+ distribution we are aware of shipped such old versions in a
+ stable release this should not be problematic.
+
+ * When systemd forks off a new per-connection service instance
+ it will now set the $REMOTE_ADDR environment variable to the
+ remote IP address, and $REMOTE_PORT environment variable to
+ the remote IP port. This behaviour is similar to the
+ corresponding environment variables defined by CGI.
+
+ * systemd-networkd gained support for uplink failure
+ detection. The BindCarrier= option allows binding interface
+ configuration dynamically to the link sense of other
+ interfaces. This is useful to achieve behaviour like in
+ network switches.
+
+ * systemd-networkd gained support for configuring the DHCP
+ client identifier to use when requesting leases.
+
+ * systemd-networkd now has a per-network UseNTP= option to
+ configure whether NTP server information acquired via DHCP
+ is passed on to services like systemd-timesyncd.
+
+ * systemd-networkd gained support for vti6 tunnels.
+
+ * Note that systemd-networkd manages the sysctl variable
+ /proc/sys/net/ipv[46]/conf/*/forwarding for each interface
+ it is configured for since v219. The variable controls IP
+ forwarding, and is a per-interface alternative to the global
+ /proc/sys/net/ipv[46]/ip_forward. This setting is
+ configurable in the IPForward= option, which defaults to
+ "no". This means if networkd is used for an interface it is
+ no longer sufficient to set the global sysctl option to turn
+ on IP forwarding! Instead, the .network file option
+ IPForward= needs to be turned on! Note that the
+ implementation of this behaviour was broken in v219 and has
+ been fixed in v220.
+
+ * Many bonding and vxlan options are now configurable in
+ systemd-networkd.
+
+ * systemd-nspawn gained a new --property= setting to set unit
+ properties for the container scope. This is useful for
+ setting resource parameters (e.g "CPUShares=500") on
+ containers started from the command line.
+
+ * systemd-nspawn gained a new --private-users= switch to make
+ use of user namespacing available on recent Linux kernels.
+
+ * systemd-nspawn may now be called as part of a shell pipeline
+ in which case the pipes used for stdin and stdout are passed
+ directly to the process invoked in the container, without
+ indirection via a pseudo tty.
+
+ * systemd-nspawn gained a new switch to control the UNIX
+ signal to use when killing the init process of the container
+ when shutting down.
+
+ * systemd-nspawn gained a new --overlay= switch for mounting
+ overlay file systems into the container using the new kernel
+ overlayfs support.
+
+ * When a container image is imported via systemd-importd and
+ the host file system is not btrfs, a loopback block device
+ file is created in /var/lib/machines.raw with a btrfs file
+ system inside. It is then mounted to /var/lib/machines to
+ enable btrfs features for container management. The loopback
+ file and btrfs file system is grown as needed when container
+ images are imported via systemd-importd.
+
+ * systemd-machined/systemd-importd gained support for btrfs
+ quota, to enforce container disk space limits on disk. This
+ is exposed in "machinectl set-limit".
+
+ * systemd-importd now can import containers from local .tar,
+ .raw and .qcow2 images, and export them to .tar and .raw. It
+ can also import dkr v2 images now from the network (on top
+ of v1 as before).
+
+ * systemd-importd gained support for verifying downloaded
+ images with gpg2 (previously only gpg1 was supported).
+
+ * systemd-machined, systemd-logind, systemd: most bus calls
+ are now accessible to unprivileged processes via
+ PolicyKit. Also, systemd-logind will now allow users to kill
+ their own sessions without further privileges or
+ authorization.
+
+ * systemd-shutdownd has been removed. This service was
+ previously responsible for implementing scheduled shutdowns
+ as exposed in /usr/bin/shutdown's time parameter. This
+ functionality has now been moved into systemd-logind and is
+ accessible via a bus interface.
+
+ * "systemctl reboot" gained a new switch --firmware-setup that
+ can be used to reboot into the EFI firmware setup, if that
+ is available. systemd-logind now exposes an API on the bus
+ to trigger such reboots, in case graphical desktop UIs want
+ to cover this functionality.
+
+ * "systemctl enable", "systemctl disable" and "systemctl mask"
+ now support a new "--now" switch. If specified the units
+ that are enabled will also be started, and the ones
+ disabled/masked also stopped.
+
+ * The Gummiboot EFI boot loader tool has been merged into
+ systemd, and renamed to "systemd-boot". The bootctl tool has been
+ updated to support systemd-boot.
+
+ * An EFI kernel stub has been added that may be used to create
+ kernel EFI binaries that contain not only the actual kernel,
+ but also an initrd, boot splash, command line and OS release
+ information. This combined binary can then be signed as a
+ single image, so that the firmware can verify it all in one
+ step. systemd-boot has special support for EFI binaries created
+ like this and can extract OS release information from them
+ and show them in the boot menu. This functionality is useful
+ to implement cryptographically verified boot schemes.
+
+ * Optional support has been added to systemd-fsck to pass
+ fsck's progress report to an AF_UNIX socket in the file
+ system.
+
+ * udev will no longer create device symlinks for all block
+ devices by default. A blacklist for excluding special block
+ devices from this logic has been turned into a whitelist
+ that requires picking block devices explicitly that require
+ device symlinks.
+
+ * A new (currently still internal) API sd-device.h has been
+ added to libsystemd. This modernized API is supposed to
+ replace libudev eventually. In fact, already much of libudev
+ is now just a wrapper around sd-device.h.
+
+ * A new hwdb database for storing metadata about pointing
+ stick devices has been added.
+
+ * systemd-tmpfiles gained support for setting file attributes
+ similar to the "chattr" tool with new 'h' and 'H' lines.
+
+ * systemd-journald will no longer unconditionally set the
+ btrfs NOCOW flag on new journal files. This is instead done
+ with tmpfiles snippet using the new 'h' line type. This
+ allows easy disabling of this logic, by masking the
+ journal-nocow.conf tmpfiles file.
+
+ * systemd-journald will now translate audit message types to
+ human readable identifiers when writing them to the
+ journal. This should improve readability of audit messages.
+
+ * The LUKS logic gained support for the offset= and skip=
+ options in /etc/crypttab, as previously implemented by
+ Debian.
+
+ * /usr/lib/os-release gained a new optional field VARIANT= for
+ distributions that support multiple variants (such as a
+ desktop edition, a server edition, ...)
+
+ Contributions from: Aaro Koskinen, Adam Goode, Alban Crequy,
+ Alberto Fanjul Alonso, Alexander Sverdlin, Alex Puchades, Alin
+ Rauta, Alison Chaiken, Andrew Jones, Arend van Spriel,
+ Benedikt Morbach, Benjamin Franzke, Benjamin Tissoires, Blaž
+ Tomažič, Chris Morgan, Chris Morin, Colin Walters, Cristian
+ Rodríguez, Daniel Buch, Daniel Drake, Daniele Medri, Daniel
+ Mack, Daniel Mustieles, daurnimator, Davide Bettio, David
+ Herrmann, David Strauss, Didier Roche, Dimitri John Ledkov,
+ Eric Cook, Gavin Li, Goffredo Baroncelli, Hannes Reinecke,
+ Hans de Goede, Hans-Peter Deifel, Harald Hoyer, Iago López
+ Galeiras, Ivan Shapovalov, Jan Engelhardt, Jan Janssen, Jan
+ Pazdziora, Jan Synacek, Jasper St. Pierre, Jay Faulkner, John
+ Paul Adrian Glaubitz, Jonathon Gilbert, Karel Zak, Kay
+ Sievers, Koen Kooi, Lennart Poettering, Lubomir Rintel, Lucas
+ De Marchi, Lukas Nykryn, Lukas Rusak, Lukasz Skalski, Łukasz
+ Stelmach, Mantas Mikulėnas, Marc-Antoine Perennou, Marcel
+ Holtmann, Martin Pitt, Mathieu Chevrier, Matthew Garrett,
+ Michael Biebl, Michael Marineau, Michael Olbrich, Michal
+ Schmidt, Michal Sekletar, Mirco Tischler, Nir Soffer, Patrik
+ Flykt, Pavel Odvody, Peter Hutterer, Peter Lemenkov, Peter
+ Waller, Piotr Drąg, Raul Gutierrez S, Richard Maw, Ronny
+ Chevalier, Ross Burton, Sebastian Rasmussen, Sergey Ptashnick,
+ Seth Jennings, Shawn Landden, Simon Farnsworth, Stefan Junker,
+ Stephen Gallagher, Susant Sahani, Sylvain Plantefève, Thomas
+ Haller, Thomas Hindoe Paaboel Andersen, Tobias Hunger, Tom
+ Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Will
+ Woods, Zachary Cook, Zbigniew Jędrzejewski-Szmek
+
+ -- Berlin, 2015-05-22
+
CHANGES WITH 219:
* Introduce a new API "sd-hwdb.h" for querying the hardware
@@ -3768,7 +4008,7 @@ CHANGES WITH 191:
* HandleSleepKey= in logind.conf has been split up into
HandleSuspendKey= and HandleHibernateKey=. The old setting
is not available anymore. X11 and the kernel are
- distuingishing between these keys and we should too. This
+ distinguishing between these keys and we should too. This
also means the inhibition lock for these keys has been split
into two.
@@ -4514,7 +4754,7 @@ CHANGES WITH 43:
* Various functionality updates to libsystemd-login.so
- * Track class of PAM logins to distuingish greeters from
+ * Track class of PAM logins to distinguish greeters from
normal user logins.
Contributions from: Kay Sievers, Lennart Poettering, Michael
diff --git a/README b/README
index c72209262e..777b34335e 100644
--- a/README
+++ b/README
@@ -7,11 +7,11 @@ WEB SITE:
http://www.freedesktop.org/wiki/Software/systemd
GIT:
- git://anongit.freedesktop.org/systemd/systemd
- ssh://git.freedesktop.org/git/systemd/systemd
+ git@github.com:systemd/systemd.git
+ https://github.com/systemd/systemd.git
GITWEB:
- http://cgit.freedesktop.org/systemd/systemd
+ https://github.com/systemd/systemd
MAILING LIST:
http://lists.freedesktop.org/mailman/listinfo/systemd-devel
@@ -21,7 +21,7 @@ IRC:
#systemd on irc.freenode.org
BUG REPORTS:
- https://bugs.freedesktop.org/enter_bug.cgi?product=systemd
+ https://github.com/systemd/systemd/issues
AUTHOR:
Lennart Poettering
@@ -77,9 +77,10 @@ REQUIREMENTS:
Optional but strongly recommended:
CONFIG_IPV6
CONFIG_AUTOFS4_FS
- CONFIG_TMPFS_POSIX_ACL
CONFIG_TMPFS_XATTR
+ CONFIG_{TMPFS,EXT4,XFS,BTRFS_FS,...}_POSIX_ACL
CONFIG_SECCOMP
+ CONFIG_CHECKPOINT_RESTORE (for the kcmp() syscall)
Required for CPUShares in resource control unit settings
CONFIG_CGROUP_SCHED
@@ -110,7 +111,7 @@ REQUIREMENTS:
with audit being enabled. This works correctly only on kernels
3.14 and newer though. TL;DR: turn audit off, still.
- glibc >= 2.14
+ glibc >= 2.16
libcap
libmount >= 2.20 (from util-linux)
libseccomp >= 1.0.0 (optional)
@@ -128,14 +129,13 @@ REQUIREMENTS:
libmicrohttpd (optional)
libpython (optional)
libidn (optional)
- gobject-introspection > 1.40.0 (optional)
elfutils >= 158 (optional)
make, gcc, and similar tools
During runtime, you need the following additional
dependencies:
- util-linux >= v2.25 required
+ util-linux >= v2.26 required
dbus >= 1.4.0 (strictly speaking optional, but recommended)
dracut (optional)
PolicyKit (optional)
@@ -143,6 +143,7 @@ REQUIREMENTS:
When building from git, you need the following additional
dependencies:
+ pkg-config
docbook-xsl
xsltproc
automake
@@ -150,7 +151,6 @@ REQUIREMENTS:
libtool
intltool
gperf
- gtkdocize (optional)
python (optional)
python-lxml (optional, but required to build the indices)
sphinx (optional)
@@ -220,6 +220,17 @@ NSS:
hosts: files mymachines resolve myhostname
+SYSV INIT.D SCRIPTS:
+ When calling "systemctl enable/disable/is-enabled" on a unit which is a
+ SysV init.d script, it calls /usr/lib/systemd/systemd-sysv-install;
+ this needs to translate the action into the distribution specific
+ mechanism such as chkconfig or update-rc.d. Packagers need to provide
+ this script if you need this functionality (you don't if you disabled
+ SysV init support).
+
+ Please see src/systemctl/systemd-sysv-install.SKELETON for how this
+ needs to look like, and provide an implementation at the marked places.
+
WARNINGS:
systemd will warn you during boot if /etc/mtab is not a
symlink to /proc/mounts. Please ensure that /etc/mtab is a
@@ -237,7 +248,7 @@ WARNINGS:
supported anymore by the basic set of Linux OS components.
systemd requires that the /run mount point exists. systemd also
- requires that /var/run is a a symlink to /run.
+ requires that /var/run is a symlink to /run.
For more information on this issue consult
http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken
diff --git a/TODO b/TODO
index 255a4f2d07..db3205c9e8 100644
--- a/TODO
+++ b/TODO
@@ -12,10 +12,6 @@ Bugfixes:
Environment=ONE='one' "TWO='two two' too" THREE=
ExecStart=/bin/python3 -c 'import sys;print(sys.argv)' $ONE $TWO $THREE
-* MEMORY return code is overloaded for syntax errors in the command line.
- str_split_quoted() should return a real return code, so spawn_child can
- report the failure properly.
-
* When systemctl --host is used, underlying ssh connection can remain open.
bus_close does not kill children?
@@ -23,10 +19,6 @@ External:
* Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros.
-* Fedora: move kernel image to /usr/lib/modules/, kernel-install will take care of populating /boot
-
-* Fedora: remove /etc/resolv.conf tmpfiles hack
-
* wiki: update journal format documentation for lz4 additions
* When lz4 gets an API for lz4 command output, make use of it to
@@ -34,15 +26,97 @@ External:
Features:
+* introduce an NSS module that uses machined info to give container UIDs pretty names when user namespacing is used.
+
+* stop using off_t, it's a crazy type. Use uint64_t instead.
+
+* logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins
+
+* change to KillMode=mixed by default
+
+* introduce argv0contains=
+
+* invent a better systemd-run scheme for naming scopes, that works with remoting
+
+* add journalctl -H that talks via ssh to a remote peer and passes through binary logs data
+
+* change journalctl -M to acquire fd to journal directory via machined, and then operate on that via openat() instead of absolute paths
+
+* add a version of --merge which also merges /var/log/journal/remote
+
+* log accumulated resource usage after each service invocation
+
+* networkd: dhcp server: try to assign stable IP addresses based on client's MAC address
+
+* nspawn: a nice way to boot up without machine id set, so that it is set at boot automatically for supporting --ephemeral. Maybe hash the host machine id together with the machine name to generate the machine id for the container
+
+* logind: rename session scope so that it includes the UID. THat way
+ the session scope can be arranged freely in slices and we don't have
+ make assumptions about their slice anymore.
+
+* journalctl: -m should access container journals directly by enumerating them via machined, and also watch containers coming and going. Benefit: nspawn --ephemeral would start working nicely with the journal.
+
+* nspawn: don't copy /etc/resolv.conf from host into container unless we are in shared-network mode
+
+* nspawn: optionally automatically add FORWARD rules to iptables whenever nspawn is running, remove them when shut down.
+
+* importd: generate a nice warning if mkfs.btrfs is missing
+
+* nspawn: add a logic for cleaning up read-only, hidden container images in /var/lib/machines that are not ancestors of any non-hidden containers
+
+* nspawn: Improve error message when --bind= is used on a non-existing source directory
+
+* nspawn: maybe make copying of /etc/resolv.conf optional, and skip it if --read-only is used
+
+* man: document how update dkr images works with machinectl
+ http://lists.freedesktop.org/archives/systemd-devel/2015-February/028630.html
+
+* nspawn: as soon as networkd has a bus interface, hook up --network-interface=, --network-bridge= with networkd, to trigger netdev creation should an interface be missing
+
+* networkd: make DHCP server IP range configurable, including only with a single IP address
+
+* rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring
+ to unicode chars, to make things more expressive.
+
+* "machinectl migrate" or similar to copy a container from or to a
+ difference host, via ssh
+
+* tmpfiles: creating new directories/subvolumes/fifos/device nodes
+ should not follow symlinks. None of the other adjustment or creation
+ calls follow symlinks.
+
+* fstab-generator: default to tmpfs-as-root if only usr= is specified on the kernel cmdline
+
+* docs: bring http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date
+
+* mounting and unmounting mount points manually with different source
+ devices will result in collected collected on all devices used.
+ http://lists.freedesktop.org/archives/systemd-devel/2015-April/030225.html
+
+* add a job mode that will fail if a transaction would mean stopping
+ running units. Use this in timedated to manage the NTP service
+ state.
+ http://lists.freedesktop.org/archives/systemd-devel/2015-April/030229.html
+
+* Maybe add support for the equivalent of "ethtool advertise" to .link files?
+ http://lists.freedesktop.org/archives/systemd-devel/2015-April/030112.html
+
+* .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC
+
+* create a btrfs qgroup for /var/lib/machines, and add all container
+ subvolumes we create to it.
+
+* When logging about multiple units (stopping BoundTo units, conflicts, etc.),
+ log both units as UNIT=, so that journalctl -u triggers on both.
+
+* to allow "linking" of nspawn containers, extend --network-bridge= so
+ that it can dynamically create bridge interfaces that are refcounted
+ by the containers on them. For each group of containers to link together
+
* journalctl --verify: don't show files that are currently being
written to as FAIL, but instead show that their are being written
to.
-* nspawn: allow configuring cgroup (and other) properties via
- --property= when invoking from the command line.
-
-* add udev rule construct SYSCTL{} to write to sysctls
-
* assign MESSAGE_ID to log messages about failed services
* coredump: make the handler check /proc/$PID/rlimits for RLIMIT_CORE,
@@ -50,43 +124,13 @@ Features:
infinity by default for all services. This then allows per-service
control of coredumping.
-* introduce some call that iterates through cmsg and closes all fds
- passed in, and use it everywhere...
-
* generate better errors when people try to set transient properties
that are not supported...
http://lists.freedesktop.org/archives/systemd-devel/2015-February/028076.html
-* nspawn, if stdout/stderr/stdin are non-ttys, don't set up
- /dev/console, but instead just pass the fds through directly.
-
-* When runlevel3.target is used to define dependencies on other units,
- then we don't pick it up currently, since nothing ever references
- runlevel3.target, and never figure out it actually is just an alias
- for multi-user.target. A hackish fix could be to add a .wants link
- from multi-user.target to runlevel3.target, if it is a symlink to
- it. Best would be to create this .wants/ symlink from
- sysv-generator. systemd would then load the referenced unit, figure
- out it is just an alias and that the dependency would be on itself
- and suppress it. Thus the alias and its deps would be loaded as
- desired.
-
-* PID 1: when invoking systemctl preset-all on first boots, operate in
- an exclusively additive way, i.e. never remove any pre-existing
- symlinks, only add new ones.
-
* Introduce $LISTEN_NAMES to complement $LISTEN_FDS, containing a
colon separated list of identifiers for the fds passed.
-* networkd: implement BindCarrier= logic to .network units that binds
- application of the file to the carrier sense on another interface,
- in order to implement uplink/downlink logic.
-
-* make networkd subscribe to PrepareForSleep(false) and refresh all
- DHCP leases then.
-
-* when the fstab-generator runs in the initrd, it should create a /dev/null mask for systemd-fsck-root.service, to avoid that the the root fs is fsck'ed twice.
-
* maybe introduce WantsMountsFor=? Usecase:
http://lists.freedesktop.org/archives/systemd-devel/2015-January/027729.html
@@ -99,8 +143,6 @@ Features:
picked up by systemd unless they contain a medium. This would mirror
the behaviour we already have for CD drives.
-* We should remove really old cruft from cdrom_id
-
* nspawn: emulate /dev/kmsg using CUSE and turn off the syslog syscall
with seccomp. That should provide us with a useful log buffer that
systemd can log to during early boot, and disconnect container logs
@@ -120,7 +162,7 @@ Features:
* logind: maybe allow configuration of the StopTimeout for session scopes
-* Set NoNewPriviliges= on all of our own services, where that makes sense
+* Set NoNewPrivileges= on all of our own services, where that makes sense
* Rework systemctl's GetAll property parsing to use the generic bus_map_all_properties() API
@@ -130,14 +172,10 @@ Features:
* import-dkr: convert json bits to nspawn configuration
-* import: support import from local files, and export to local files
-
* core/cgroup: support net_cls modules, and support automatically allocating class ids, then add support for making firewall changes depending on it, to implement a per-service firewall
* introduce systemd-nspawn-ephemeral@.service, and hook it into "machinectl start" with a new --ephemeral switch
-* logind,machined: add generic catch-all polkit verbs for most privileged operations, similar to systemd itself
-
* "machinectl status" should also show internal logs of the container in question
* "machinectl list-images" should show os-release data, as well as machine-info data (including deployment level)
@@ -152,14 +190,8 @@ Features:
* "machinectl commit" that takes a writable snapshot of a tree, invokes a shell in it, and marks it read-only after use
-* "machinectl status" should show 10 most recent log lines of both the host logs of the unit of the machine, plus the logs generated in the machine
-
-* add transparent btrfs pool in a loopback file in /var if btrfs operations (such as systemd-import pull-dkr) are used and /var is not a btrfs file system
-
* systemd-nspawn -x should support ephemeral instances of gpt images
-* move machinectl's mount and copy commands into machined
-
* hostnamectl: show root image uuid
* sysfs set api in libudev is not const
@@ -189,17 +221,10 @@ Features:
* as soon as we have kdbus, and sender timestamps, revisit coalescing multiple parallel daemon reloads:
http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html
-* set $REMOTE_IP (or $REMOTE_ADDR/$REMOTE_PORT) environment variable when doing per-connection socket activation. use format introduced by xinetd or CGI for this
-
* the install state probably shouldn't get confused by generated units, think dbus1/kdbus compat!
* in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column
-* we should try harder to collapse start jobs for swaps that end up being the same:
- http://lists.freedesktop.org/archives/systemd-devel/2014-November/025359.html
-
-* timedated should compensate on SetTime for the time spent in polkit
-
* figure out when we can use the coarse timers
* sd-resolve: drop res_query wrapping, people should call via the bus to resolved instead
@@ -255,8 +280,6 @@ Features:
* exponential backoff in timesyncd and resolved when we cannot reach a server
-* tmpfiles: port to unquote_many_words(), similar to sysusers
-
* unquote_many_words() should probably be used by a lot of code that
currently uses FOREACH_WORD and friends. For example, most conf
parsing callbacks should use it.
@@ -266,6 +289,9 @@ Features:
* systemd.show_status= should probably have a mode where only failed
units are shown.
+* add systemd.abort_on_kill or some other such flag to send SIGABRT instead of SIGKILL
+ (throughout the codebase, not only PID1)
+
* networkd:
- add LLDP client side support
- the DHCP lease data (such as NTP/DNS) is still made available when
@@ -381,7 +407,6 @@ Features:
the hierarchies of child processes
* transient units:
- - allow creating auxiliary units with the same call
- add field to transient units that indicate whether systemd or somebody else saves/restores its settings, for integration with libvirt
- ensure scope units may be started only a single time
@@ -512,8 +537,6 @@ Features:
* maybe do not install getty@tty1.service symlink in /etc but in /usr?
-* re-enable "make check" for gtk-doc (broken for unknown reason)
-
* fstab: add new mount option x-systemd-after=/foobar/waldo to allow manual dependencies to other mount points
https://bugzilla.redhat.com/show_bug.cgi?id=812826
@@ -541,7 +564,6 @@ Features:
- logind: when the power button is pressed short, just popup a
logout dialog. If it is pressed for 1s, do the usual
shutdown. Inspiration are Macs here.
- - logind: allow users to kill or lock their own sessions
- expose "Locked" property on logind sesison objects
- given that logind now lets PID 1 do all nasty work, we can
probably reduce the capability set it retains substantially.
@@ -713,17 +735,6 @@ Features:
* when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr
-* automount: implement expire:
- - set superblock timeout AUTOFS_DEV_IOCTL_TIMEOUT_CMD
- - periodically run AUTOFS_DEV_IOCTL_EXPIRE_CMD
- - every timeout/4 (original autofs logic)
- - blocking, needs a thread
- - run until -EAGAIN
- - receive expire packet on pipe if kernel tells the timeout is over
- - call umount
- - answer expire packet on pipe with AUTOFS_DEV_IOCTL_{READY,FAIL}_CMD
- - AUTOFS_DEV_IOCTL_EXPIRE_CMD returns
-
* ExecOnFailure=/usr/bin/foo
* udev:
@@ -731,7 +742,6 @@ Features:
- kill scsi_id
- add trigger --subsystem-match=usb/usb_device device
- reimport udev db after MOVE events for devices without dev_t
- - don't keep stale db in case event processing fails (also notify userspace about the failure)
* when a service has the same env var set twice we actually store it twice and return that in systemctl show -p... We should only show the last setting
@@ -866,7 +876,6 @@ Features:
- add functions to set previously stored IPv6 addresses on startup and get
them at shutdown; store them in client->ia_na
- write more test cases
- - implement and do duplicate address detection, see rfc 4862, 5.4.
- implement reconfigure support, see 5.3., 15.11. and 22.20.
- implement support for temporary adressess (IA_TA)
- implement dhcpv6 authentication
diff --git a/autogen.sh b/autogen.sh
index 7b62449be8..2d4acdfef1 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -28,15 +28,6 @@ if [ -f .git/hooks/pre-commit.sample ] && [ ! -f .git/hooks/pre-commit ]; then
echo "Activated pre-commit hook." || :
fi
-if which gtkdocize >/dev/null 2>/dev/null; then
- gtkdocize --docdir docs/ --flavour no-tmpl
- gtkdocargs=--enable-gtk-doc
-else
- echo "You don't have gtk-doc installed, and thus won't be able to generate the documentation."
- rm -f docs/gtk-doc.make
- echo 'EXTRA_DIST =' > docs/gtk-doc.make
-fi
-
intltoolize --force --automake
autoreconf --force --install --symlink
@@ -48,7 +39,7 @@ args="\
--sysconfdir=/etc \
--localstatedir=/var \
--libdir=$(libdir /usr/lib) \
-$gtkdocargs"
+"
if [ -f "$topdir/.config.args" ]; then
args="$args $(cat $topdir/.config.args)"
@@ -56,7 +47,7 @@ fi
if [ ! -L /bin ]; then
args="$args \
---with-rootprefix= \
+--with-rootprefix=/ \
--with-rootlibdir=$(libdir /lib) \
"
fi
diff --git a/configure.ac b/configure.ac
index 97a29d63fd..2625e0d15b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,8 +20,8 @@
AC_PREREQ([2.64])
AC_INIT([systemd],
- [219],
- [http://bugs.freedesktop.org/enter_bug.cgi?product=systemd],
+ [220],
+ [http://github.com/systemd/systemd/issues],
[systemd],
[http://www.freedesktop.org/wiki/Software/systemd])
@@ -38,19 +38,18 @@ AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-di
AM_SILENT_RULES([yes])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
-AS_IF([test "x$host_cpu" = "xmips" || test "x$host_cpu" = "xmipsel" ||
- test "x$host_cpu" = "xmips64" || test "x$host_cpu" = "xmips64el"],
- [AC_DEFINE(ARCH_MIPS, [], [Whether on mips arch])])
-
LT_PREREQ(2.2)
LT_INIT([disable-static])
AS_IF([test "x$enable_static" = "xyes"], [AC_MSG_ERROR([--enable-static is not supported by systemd])])
AS_IF([test "x$enable_largefile" = "xno"], [AC_MSG_ERROR([--disable-largefile is not supported by systemd])])
-# i18n stuff for the PolicyKit policy files
+SET_ARCH(X86_64, x86_64*)
+SET_ARCH(IA32, i*86*)
+SET_ARCH(MIPS, mips*)
+SET_ARCH(AARCH64, aarch64*)
-# Check whether intltool can be found, disable NLS otherwise
+# i18n stuff for the PolicyKit policy files, heck whether intltool can be found, disable NLS otherwise
AC_CHECK_PROG(intltool_found, [intltool-merge], [yes], [no])
AS_IF([test x"$intltool_found" != xyes],
[AS_IF([test x"$enable_nls" = xyes],
@@ -75,6 +74,7 @@ AS_IF([test -z "$INTLTOOL_POLICY_RULE"], [
GETTEXT_PACKAGE=systemd
AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [systemd])
AC_PROG_MKDIR_P
AC_PROG_LN_S
@@ -100,26 +100,14 @@ AC_PATH_PROG([KEXEC], [kexec], [/usr/sbin/kexec], [$PATH:/usr/sbin:/sbin])
AC_PATH_PROG([SULOGIN], [sulogin], [/usr/sbin/sulogin], [$PATH:/usr/sbin:/sbin])
+AC_PATH_PROG([MOUNT_PATH], [mount], [/usr/bin/mount], [$PATH:/usr/sbin:/sbin])
+AC_PATH_PROG([UMOUNT_PATH], [umount], [/usr/bin/umount], [$PATH:/usr/sbin:/sbin])
+
AS_IF([! ln --relative --help > /dev/null 2>&1], [AC_MSG_ERROR([*** ln doesn't support --relative ***])])
M4_DEFINES=
-# gtkdocize greps for '^GTK_DOC_CHECK', so it needs to be on its own line
-m4_ifdef([GTK_DOC_CHECK], [
-GTK_DOC_CHECK([1.18],[--flavour no-tmpl])],
- [AM_CONDITIONAL([ENABLE_GTK_DOC], [false])
- enable_gtk_doc=no])
-
-AS_IF([test "x$enable_gtk_doc" = "xyes" -a "x$XSLTPROC" = x], [
- AC_MSG_ERROR([*** GTK doc requested but xsltproc not found])
-])
-
-m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [
-GOBJECT_INTROSPECTION_CHECK([1.31.1])
-], [
- AM_CONDITIONAL([HAVE_INTROSPECTION], [false])
- enable_introspection=no])
-
+AC_CHECK_TOOL(OBJCOPY, objcopy)
AC_CHECK_TOOL(STRINGS, strings)
AC_CHECK_TOOL(GPERF, gperf)
if test -z "$GPERF" ; then
@@ -165,7 +153,6 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
-Wundef \
"-Wformat=2 -Wformat-security -Wformat-nonliteral" \
-Wlogical-op \
- -Wsign-compare \
-Wmissing-include-dirs \
-Wold-style-definition \
-Wpointer-arith \
@@ -187,6 +174,7 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
-Wno-unused-parameter \
-Wno-missing-field-initializers \
-Wno-unused-result \
+ -Wno-format-signedness \
-Werror=overflow \
-Wdate-time \
-Wnested-externs \
@@ -195,8 +183,6 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
-fdiagnostics-show-option \
-fno-strict-aliasing \
-fvisibility=hidden \
- -ffunction-sections \
- -fdata-sections \
-fstack-protector \
-fstack-protector-strong \
-fPIE \
@@ -208,22 +194,33 @@ AS_CASE([$CC], [*clang*],
-Wno-gnu-variable-sized-type-not-at-end \
])])
-AS_CASE([$CFLAGS], [*-O[[12345\ ]]*],
+AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
[CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
-flto -ffat-lto-objects])],
[AC_MSG_RESULT([skipping -flto, optimization not enabled])])
AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags")
-AS_CASE([$CFLAGS], [*-O[[12345\ ]]*],
+AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
[CC_CHECK_FLAGS_APPEND([with_cppflags], [CPPFLAGS], [\
-Wp,-D_FORTIFY_SOURCE=2])],
[AC_MSG_RESULT([skipping -D_FORTIFY_SOURCE, optimization not enabled])])
AC_SUBST([OUR_CPPFLAGS], "$with_cppflags $sanitizer_cppflags")
+AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
+ [CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\
+ -Wl,--gc-sections])],
+ [AC_MSG_RESULT([skipping --gc-sections, optimization not enabled])])
+AC_SUBST([OUR_CFLAGS], "$with_ldflags $sanitizer_cflags")
+
+AS_CASE([$CFLAGS], [*-O[[12345sz\ ]]*],
+ [CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
+ -ffunction-sections -fdata-sections])],
+ [AC_MSG_RESULT([skipping -ffunction/data-section, optimization not enabled])])
+AC_SUBST([OUR_CFLAGS], "$with_cflags $sanitizer_cflags")
+
CC_CHECK_FLAGS_APPEND([with_ldflags], [LDFLAGS], [\
-Wl,--as-needed \
-Wl,--no-undefined \
- -Wl,--gc-sections \
-Wl,-z,relro \
-Wl,-z,now \
-pie \
@@ -330,10 +327,12 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
IFLA_PHYS_PORT_ID,
IFLA_BOND_AD_INFO,
IFLA_VLAN_PROTOCOL,
- IFLA_VXLAN_LOCAL6,
+ IFLA_VXLAN_REMCSUM_NOPARTIAL,
IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
IFLA_BRIDGE_VLAN_INFO,
- IFLA_BRPORT_UNICAST_FLOOD],
+ IFLA_BRPORT_UNICAST_FLOOD,
+ NDA_IFINDEX,
+ IFA_FLAGS],
[], [], [[
#include <inttypes.h>
#include <netinet/in.h>
@@ -344,6 +343,8 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
#include <linux/if_tunnel.h>
#include <linux/if_link.h>
#include <linux/if_bridge.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
]])
# This makes sure pkg.m4 is available.
@@ -483,25 +484,6 @@ if test "x${have_ima}" != xno ; then
fi
# ------------------------------------------------------------------------------
-have_chkconfig=yes
-AC_ARG_ENABLE([chkconfig], AS_HELP_STRING([--disable-chkconfig],[Disable optional chkconfig support]),
- [case "${enableval}" in
- yes) have_chkconfig=yes ;;
- no) have_chkconfig=no ;;
- *) AC_MSG_ERROR(bad value ${enableval} for --disable-chkconfig) ;;
- esac],
- [AC_PATH_PROG(CHKCONFIG, chkconfig)
- if test -z "$CHKCONFIG"; then
- have_chkconfig=no
- else
- have_chkconfig=yes
- fi])
-
-if test "x${have_chkconfig}" != xno ; then
- AC_DEFINE(HAVE_CHKCONFIG, 1, [Define if CHKCONFIG is available])
-fi
-
-# ------------------------------------------------------------------------------
have_selinux=no
AC_ARG_ENABLE(selinux, AS_HELP_STRING([--disable-selinux], [Disable optional SELINUX support]))
if test "x$enable_selinux" != "xno"; then
@@ -776,6 +758,7 @@ else
AUDIT_LIBS=
fi
AC_SUBST(AUDIT_LIBS)
+AM_CONDITIONAL([HAVE_AUDIT], [test "x$have_audit" != xno])
# ------------------------------------------------------------------------------
AC_ARG_ENABLE([elfutils],
@@ -1145,6 +1128,65 @@ fi
AM_CONDITIONAL(ENABLE_EFI, [test "x$have_efi" = "xyes"])
# ------------------------------------------------------------------------------
+AC_CHECK_TOOL(EFI_CC, gcc)
+
+EFI_ARCH=`echo $host | sed "s/\(-\).*$//"`
+
+AM_COND_IF(ARCH_IA32, [
+ EFI_ARCH=ia32
+ EFI_MACHINE_TYPE_NAME=ia32])
+
+AM_COND_IF(ARCH_X86_64, [
+ EFI_MACHINE_TYPE_NAME=x64])
+
+AM_COND_IF(ARCH_AARCH64, [
+ EFI_MACHINE_TYPE_NAME=aa64])
+
+AC_SUBST([EFI_ARCH])
+AC_SUBST([EFI_MACHINE_TYPE_NAME])
+
+have_gnuefi=no
+AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [Disable optional gnuefi support]))
+AS_IF([test "x$enable_gnuefi" != "xno"], [
+ AC_CHECK_HEADERS(efi/${EFI_ARCH}/efibind.h,
+ [AC_DEFINE(HAVE_GNUEFI, 1, [Define if gnuefi is available])
+ have_gnuefi=yes],
+ [AS_IF([test "x$enable_gnuefi" = xyes],
+ [AC_MSG_ERROR([*** gnuefi support requested but headers not found])])
+ ])
+
+ efiroot=$(echo $(cd /usr/lib/$(${EFI_CC} -print-multi-os-directory); pwd))
+
+ EFI_LIB_DIR="$efiroot"
+ AC_ARG_WITH(efi-libdir,
+ AS_HELP_STRING([--with-efi-libdir=PATH], [Path to EFI lib directory]),
+ [EFI_LIB_DIR="$withval"], [EFI_LIB_DIR="$efiroot"]
+ )
+ AC_SUBST([EFI_LIB_DIR])
+
+ have_efi_lds=no
+ AC_ARG_WITH(efi-ldsdir,
+ AS_HELP_STRING([--with-efi-ldsdir=PATH], [Path to EFI lds directory]),
+ [EFI_LDS_DIR="$withval" && AC_CHECK_FILE([${EFI_LDS_DIR}/elf_${EFI_ARCH}_efi.lds],
+ [have_efi_lds=yes])],
+ [AS_FOR([DIR], [EFI_LDS_DIR], ["${EFI_LIB_DIR}/gnuefi" "${EFI_LIB_DIR}"],
+ [AC_CHECK_FILE([${EFI_LDS_DIR}/elf_${EFI_ARCH}_efi.lds],
+ [have_efi_lds=yes && break])])])
+ AS_IF([test "x$have_efi_lds" = xyes],
+ [AC_SUBST([EFI_LDS_DIR])],
+ [AS_IF([test "x$enable_gnuefi" = xyes],
+ [AC_MSG_ERROR([*** gnuefi support requested but files not found])],
+ [have_gnuefi=no])])
+
+ AC_ARG_WITH(efi-includedir,
+ AS_HELP_STRING([--with-efi-includedir=PATH], [Path to EFI include directory]),
+ [EFI_INC_DIR="$withval"], [EFI_INC_DIR="/usr/include"]
+ )
+ AC_SUBST([EFI_INC_DIR])
+])
+AM_CONDITIONAL(HAVE_GNUEFI, [test "x$have_gnuefi" = xyes])
+
+# ------------------------------------------------------------------------------
AC_ARG_WITH(unifont,
AS_HELP_STRING([--with-unifont=PATH],
[Path to unifont.hex]),
@@ -1245,14 +1287,6 @@ fi
AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"])
# ------------------------------------------------------------------------------
-AC_ARG_ENABLE([gudev],
- AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]),
- [], [enable_gudev=yes])
-AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0 gio-2.0]) ])
-AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"])
-AS_IF([test "x$enable_gudev" = "xyes"], [ AC_DEFINE(HAVE_GLIB, 1, [Define if glib is available]) ])
-
-# ------------------------------------------------------------------------------
AC_ARG_ENABLE(hwdb, [AC_HELP_STRING([--disable-hwdb], [disable hardware database support])],
enable_hwdb=$enableval, enable_hwdb=yes)
AM_CONDITIONAL(ENABLE_HWDB, [test x$enable_hwdb = xyes])
@@ -1321,16 +1355,19 @@ AC_ARG_WITH([dbuspolicydir],
AS_HELP_STRING([--with-dbuspolicydir=DIR], [D-Bus policy directory]),
[],
[with_dbuspolicydir=${sysconfdir}/dbus-1/system.d])
+AX_NORMALIZE_PATH([with_dbuspolicydir])
AC_ARG_WITH([dbussessionservicedir],
AS_HELP_STRING([--with-dbussessionservicedir=DIR], [D-Bus session service directory]),
[],
[with_dbussessionservicedir=${datadir}/dbus-1/services])
+AX_NORMALIZE_PATH([with_dbussessionservicedir])
AC_ARG_WITH([dbussystemservicedir],
AS_HELP_STRING([--with-dbussystemservicedir=DIR], [D-Bus system service directory]),
[],
[with_dbussystemservicedir=${datadir}/dbus-1/system-services])
+AX_NORMALIZE_PATH([with_dbussystemservicedir])
AC_ARG_WITH([bashcompletiondir],
AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]),
@@ -1340,29 +1377,42 @@ AC_ARG_WITH([bashcompletiondir],
] , [
with_bashcompletiondir=${datadir}/bash-completion/completions
])])
+AX_NORMALIZE_PATH([with_bashcompletiondir])
AC_ARG_WITH([zshcompletiondir],
AS_HELP_STRING([--with-zshcompletiondir=DIR], [Zsh completions directory]),
[], [with_zshcompletiondir=${datadir}/zsh/site-functions])
+AX_NORMALIZE_PATH([with_zshcompletiondir])
AC_ARG_WITH([rootprefix],
AS_HELP_STRING([--with-rootprefix=DIR], [rootfs directory prefix for config files and kernel modules]),
[], [with_rootprefix=${ac_default_prefix}])
+# --with-rootprefix= (empty) should default to "/" but AX_NORMALIZE_PATH
+# defaults those to ".", solve that here for now until we can find a suitable
+# fix for AX_NORMALIZE_PATH upstream at autoconf-archive.
+# See: https://github.com/systemd/systemd/issues/54
+if test "x${with_rootprefix}" = "x"; then
+ with_rootprefix="/"
+fi
+AX_NORMALIZE_PATH([with_rootprefix])
AC_ARG_WITH([rootlibdir],
AS_HELP_STRING([--with-rootlibdir=DIR], [Root directory for libraries necessary for boot]),
[],
[with_rootlibdir=${libdir}])
+AX_NORMALIZE_PATH([with_rootlibdir])
AC_ARG_WITH([pamlibdir],
AS_HELP_STRING([--with-pamlibdir=DIR], [Directory for PAM modules]),
[],
[with_pamlibdir=${with_rootlibdir}/security])
+AX_NORMALIZE_PATH([with_pamlibdir])
AC_ARG_WITH([pamconfdir],
AS_HELP_STRING([--with-pamconfdir=DIR], [Directory for PAM configuration]),
[],
[with_pamconfdir=${sysconfdir}/pam.d])
+AX_NORMALIZE_PATH([with_pamconfdir])
AC_ARG_ENABLE([split-usr],
AS_HELP_STRING([--enable-split-usr], [Assume that /bin, /sbin aren\'t symlinks into /usr]),
@@ -1384,12 +1434,14 @@ AC_SUBST(DEFAULT_DKR_INDEX_URL)
AS_IF([test "x${enable_split_usr}" = "xyes"], [
AC_DEFINE(HAVE_SPLIT_USR, 1, [Define if /bin, /sbin aren't symlinks into /usr])
])
-
-# Work around intltoolize and gtk-doc problems in VPATH builds
-AM_CONDITIONAL([ENABLE_GTK_DOC_TESTS], [test "x$0" = "x./configure"],
- [Define to do gtk-doc tests])
-AS_IF([test "x$0" != "x./configure"], [
- AC_SUBST([INTLTOOL_UPDATE], [/bin/true])
+AM_CONDITIONAL(ENABLE_SPLIT_USR, [test "x${enable_split_usr}" = "xyes"])
+
+# QEMU and OVMF UEFI firmware
+AS_IF([test x"$cross_compiling" = "xyes"], [], [
+ AC_PATH_PROG([QEMU], [qemu-system-x86_64])
+ AC_CHECK_FILE([/usr/share/qemu/bios-ovmf.bin], [QEMU_BIOS=/usr/share/qemu/bios-ovmf.bin],
+ [AC_CHECK_FILE([/usr/share/qemu-ovmf/bios.bin], [QEMU_BIOS=/usr/share/qemu-ovmf/bios.bin])])
+ AC_SUBST([QEMU_BIOS])
])
AC_ARG_ENABLE(tests,
@@ -1438,11 +1490,8 @@ AC_SUBST([rootprefix], [$with_rootprefix])
AC_SUBST([rootlibdir], [$with_rootlibdir])
AC_CONFIG_FILES([
- Makefile po/Makefile.in
- docs/libudev/Makefile
- docs/libudev/version.xml
- docs/gudev/Makefile
- docs/gudev/version.xml
+ Makefile
+ po/Makefile.in
])
AC_OUTPUT
@@ -1465,7 +1514,6 @@ AC_MSG_RESULT([
GCRYPT: ${have_gcrypt}
QRENCODE: ${have_qrencode}
MICROHTTPD: ${have_microhttpd}
- CHKCONFIG: ${have_chkconfig}
GNUTLS: ${have_gnutls}
libcurl: ${have_libcurl}
libidn: ${have_libidn}
@@ -1496,21 +1544,25 @@ AC_MSG_RESULT([
coredump: ${have_coredump}
polkit: ${have_polkit}
efi: ${have_efi}
+ gnuefi: ${have_gnuefi}
+ efi arch: ${EFI_ARCH}
+ EFI machine type: ${EFI_MACHINE_TYPE_NAME}
+ EFI CC ${EFI_CC}
+ EFI libdir: ${EFI_LIB_DIR}
+ EFI ldsdir: ${EFI_LDS_DIR}
+ EFI includedir: ${EFI_INC_DIR}
kmod: ${have_kmod}
xkbcommon: ${have_xkbcommon}
blkid: ${have_blkid}
libmount: ${have_libmount}
dbus: ${have_dbus}
nss-myhostname: ${have_myhostname}
- gudev: ${enable_gudev}
hwdb: ${enable_hwdb}
- gintrospection: ${enable_introspection}
terminal: ${have_terminal}
kdbus: ${have_kdbus}
Python: ${have_python}
Python Headers: ${have_python_devel}
man pages: ${have_manpages}
- gtk-doc: ${enable_gtk_doc}
test coverage: ${have_coverage}
Split /usr: ${enable_split_usr}
SysV compatibility: ${SYSTEM_SYSV_COMPAT}
diff --git a/docs/.gitignore b/docs/.gitignore
index f48033d321..ac7af2e80e 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -1,2 +1 @@
-/gtk-doc.make
/html/
diff --git a/docs/gudev/.gitignore b/docs/gudev/.gitignore
deleted file mode 100644
index e6f2371ab1..0000000000
--- a/docs/gudev/.gitignore
+++ /dev/null
@@ -1,19 +0,0 @@
-/*.bak
-/gtk-doc.make
-/version.xml
-/Makefile
-/gudev-overrides.txt
-/gudev-decl-list.txt
-/gudev-decl.txt
-/gudev-undeclared.txt
-/gudev-undocumented.txt
-/gudev-unused.txt
-/gudev.args
-/gudev.hierarchy
-/gudev.interfaces
-/gudev.prerequisites
-/gudev.signals
-/html/
-/xml/
-/*.stamp
-/tmpl/
diff --git a/docs/gudev/Makefile.am b/docs/gudev/Makefile.am
deleted file mode 100644
index 659330303b..0000000000
--- a/docs/gudev/Makefile.am
+++ /dev/null
@@ -1,115 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-# We require automake 1.10 at least.
-AUTOMAKE_OPTIONS = 1.10 color-tests
-
-# This is a blank Makefile.am for using gtk-doc.
-# Copy this to your project's API docs directory and modify the variables to
-# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
-# of using the various options.
-
-# The name of the module, e.g. 'glib'.
-DOC_MODULE=gudev
-
-# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
-#DOC_MODULE_VERSION=2
-
-# The top-level SGML file. You can change this if you want to.
-DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
-
-# The directory containing the source code. Relative to $(srcdir).
-# gtk-doc will search all .c & .h files beneath here for inline comments
-# documenting the functions and macros.
-# e.g. DOC_SOURCE_DIR=../../../gtk
-DOC_SOURCE_DIR=$(top_srcdir)/src/gudev $(top_builddir)/src/gudev
-
-# Extra options to pass to gtkdoc-scangobj. Not normally needed.
-SCANGOBJ_OPTIONS=
-
-# Extra options to supply to gtkdoc-scan.
-# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
-SCAN_OPTIONS=
-
-# Extra options to supply to gtkdoc-mkdb.
-# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
-MKDB_OPTIONS=--xml-mode --output-format=xml --name-space=g_udev
-
-# Extra options to supply to gtkdoc-mktmpl
-# e.g. MKTMPL_OPTIONS=--only-section-tmpl
-MKTMPL_OPTIONS=
-
-# Extra options to supply to gtkdoc-mkhtml
-MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir)
-
-# Extra options to supply to gtkdoc-fixref. Not normally needed.
-# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
-FIXXREF_OPTIONS=>/dev/null 2>&1
-
-# Used for dependencies. The docs will be rebuilt if any of these change.
-# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
-# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
-HFILE_GLOB=$(top_srcdir)/src/gudev/*.h
-CFILE_GLOB=$(top_srcdir)/src/gudev/*.c
-
-# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
-# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
-EXTRA_HFILES=
-
-# Header files to ignore when scanning. Use base file name, no paths
-# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
-IGNORE_HFILES=gudevenumtypes.h gudevmarshal.h
-
-# Images to copy into HTML directory.
-# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
-HTML_IMAGES=
-
-# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
-# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
-content_files = version.xml
-
-# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
-# These files must be listed here *and* in content_files
-# e.g. expand_content_files=running.sgml
-expand_content_files=
-
-# Hack, hack. You silly gtk-doc, you must not add CFLAGS multiple
-# times when calling gcc; it surely can not work with options that must
-# be listed only once.
-# Kill CFLAGS here because gtk-doc thinks adding CFLAGS to CC _and_ also
-# adding CFLAGS itself again would work.
-override CFLAGS=
-override LDFLAGS=
-
-# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
-# Only needed if you are using gtkdoc-scangobj to dynamically query widget
-# signals and properties.
-# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
-# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
-GTKDOC_CFLAGS = \
- $(GLIB_CFLAGS) \
- -I$(top_srcdir)/src/gudev \
- -I$(top_builddir)/src/gudev
-
-GTKDOC_LIBS = \
- $(GLIB_LIBS) \
- $(top_builddir)/libgudev-1.0.la
-
-# This includes the standard gtk-doc make rules, copied by gtkdocize.
-include $(top_srcdir)/docs/gtk-doc.make
-
-# Other files to distribute
-# e.g. EXTRA_DIST += version.xml.in
-EXTRA_DIST += version.xml.in
-
-# Files not to distribute
-# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
-# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
-#DISTCLEANFILES +=
-
-# Comment this out if you want your docs-status tested during 'make check'
-if ENABLE_GTK_DOC
-if ENABLE_GTK_DOC_TESTS
-#TESTS_ENVIRONMENT = cd $(top_srcdir)
-#TESTS = $(GTKDOC_CHECK)
-endif
-endif
diff --git a/docs/gudev/gudev-docs.xml b/docs/gudev/gudev-docs.xml
deleted file mode 100644
index 3e7e50acd4..0000000000
--- a/docs/gudev/gudev-docs.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
-[
- <!ENTITY version SYSTEM "version.xml">
-]>
-<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
- <bookinfo>
- <title>GUdev Reference Manual</title>
- <releaseinfo>
- For version &version; — the latest version of this
- documentation can be found at
- <ulink role="online-location" url="http://www.freedesktop.org/software/systemd/gudev/">
- http://www.freedesktop.org/software/systemd/gudev/
- </ulink>.
- </releaseinfo>
- <copyright>
- <year>2009-2012</year>
- <holder>David Zeuthen &lt;davidz@redhat.com&gt;</holder>
- <holder>Bastien Nocera &lt;hadess@hadess.net&gt;</holder>
- </copyright>
- </bookinfo>
-
- <chapter id="ref-API">
- <title>API Reference</title>
- <xi:include href="xml/gudevclient.xml"/>
- <xi:include href="xml/gudevdevice.xml"/>
- <xi:include href="xml/gudevenumerator.xml"/>
- </chapter>
-
- <chapter id="gudev-hierarchy">
- <title>Object Hierarchy</title>
- <xi:include href="xml/tree_index.sgml"/>
- </chapter>
-
- <index id="api-index-full">
- <title>API Index</title>
- <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
- </index>
-
- <index role="165">
- <title>Index of new symbols in 165</title>
- <xi:include href="xml/api-index-165.xml"><xi:fallback /></xi:include>
- </index>
-
- <index id="api-index-deprecated" role="deprecated">
- <title>Index of deprecated API</title>
- <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
- </index>
-
- <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
-</book>
diff --git a/docs/gudev/gudev-sections.txt b/docs/gudev/gudev-sections.txt
deleted file mode 100644
index 90765ee4cf..0000000000
--- a/docs/gudev/gudev-sections.txt
+++ /dev/null
@@ -1,102 +0,0 @@
-<SECTION>
-<FILE>gudevclient</FILE>
-<TITLE>GUdevClient</TITLE>
-GUdevClient
-GUdevClientClass
-GUdevDeviceType
-GUdevDeviceNumber
-g_udev_client_new
-g_udev_client_query_by_subsystem
-g_udev_client_query_by_device_number
-g_udev_client_query_by_device_file
-g_udev_client_query_by_sysfs_path
-g_udev_client_query_by_subsystem_and_name
-<SUBSECTION Standard>
-G_UDEV_CLIENT
-G_UDEV_IS_CLIENT
-G_UDEV_TYPE_CLIENT
-g_udev_client_get_type
-G_UDEV_CLIENT_CLASS
-G_UDEV_IS_CLIENT_CLASS
-G_UDEV_CLIENT_GET_CLASS
-<SUBSECTION Private>
-GUdevClientPrivate
-</SECTION>
-
-<SECTION>
-<FILE>gudevdevice</FILE>
-<TITLE>GUdevDevice</TITLE>
-GUdevDevice
-GUdevDeviceClass
-g_udev_device_get_subsystem
-g_udev_device_get_devtype
-g_udev_device_get_name
-g_udev_device_get_number
-g_udev_device_get_sysfs_path
-g_udev_device_get_driver
-g_udev_device_get_action
-g_udev_device_get_seqnum
-g_udev_device_get_device_type
-g_udev_device_get_device_number
-g_udev_device_get_device_file
-g_udev_device_get_device_file_symlinks
-g_udev_device_get_parent
-g_udev_device_get_parent_with_subsystem
-g_udev_device_get_tags
-g_udev_device_get_is_initialized
-g_udev_device_get_usec_since_initialized
-g_udev_device_get_property_keys
-g_udev_device_has_property
-g_udev_device_get_property
-g_udev_device_get_property_as_int
-g_udev_device_get_property_as_uint64
-g_udev_device_get_property_as_double
-g_udev_device_get_property_as_boolean
-g_udev_device_get_property_as_strv
-g_udev_device_get_sysfs_attr_keys
-g_udev_device_has_sysfs_attr
-g_udev_device_get_sysfs_attr
-g_udev_device_get_sysfs_attr_as_int
-g_udev_device_get_sysfs_attr_as_uint64
-g_udev_device_get_sysfs_attr_as_double
-g_udev_device_get_sysfs_attr_as_boolean
-g_udev_device_get_sysfs_attr_as_strv
-<SUBSECTION Standard>
-G_UDEV_DEVICE
-G_UDEV_IS_DEVICE
-G_UDEV_TYPE_DEVICE
-g_udev_device_get_type
-G_UDEV_DEVICE_CLASS
-G_UDEV_IS_DEVICE_CLASS
-G_UDEV_DEVICE_GET_CLASS
-<SUBSECTION Private>
-GUdevDevicePrivate
-</SECTION>
-
-<SECTION>
-<FILE>gudevenumerator</FILE>
-<TITLE>GUdevEnumerator</TITLE>
-GUdevEnumerator
-GUdevEnumeratorClass
-g_udev_enumerator_new
-g_udev_enumerator_add_match_subsystem
-g_udev_enumerator_add_nomatch_subsystem
-g_udev_enumerator_add_match_sysfs_attr
-g_udev_enumerator_add_nomatch_sysfs_attr
-g_udev_enumerator_add_match_property
-g_udev_enumerator_add_match_name
-g_udev_enumerator_add_match_tag
-g_udev_enumerator_add_match_is_initialized
-g_udev_enumerator_add_sysfs_path
-g_udev_enumerator_execute
-<SUBSECTION Standard>
-G_UDEV_ENUMERATOR
-G_UDEV_IS_ENUMERATOR
-G_UDEV_TYPE_ENUMERATOR
-g_udev_enumerator_get_type
-G_UDEV_ENUMERATOR_CLASS
-G_UDEV_IS_ENUMERATOR_CLASS
-G_UDEV_ENUMERATOR_GET_CLASS
-<SUBSECTION Private>
-GUdevEnumeratorPrivate
-</SECTION>
diff --git a/docs/gudev/gudev.types b/docs/gudev/gudev.types
deleted file mode 100644
index a89857a04d..0000000000
--- a/docs/gudev/gudev.types
+++ /dev/null
@@ -1,4 +0,0 @@
-g_udev_device_type_get_type
-g_udev_device_get_type
-g_udev_client_get_type
-g_udev_enumerator_get_type
diff --git a/docs/gudev/version.xml.in b/docs/gudev/version.xml.in
deleted file mode 100644
index d78bda9342..0000000000
--- a/docs/gudev/version.xml.in
+++ /dev/null
@@ -1 +0,0 @@
-@VERSION@
diff --git a/docs/libudev/.gitignore b/docs/libudev/.gitignore
deleted file mode 100644
index f8dd67c50a..0000000000
--- a/docs/libudev/.gitignore
+++ /dev/null
@@ -1,19 +0,0 @@
-/gtk-doc.make
-/version.xml
-/Makefile
-/libudev-overrides.txt
-/libudev-decl-list.txt
-/libudev-decl.txt
-/libudev-undeclared.txt
-/libudev-undocumented.txt
-/libudev-unused.txt
-/libudev.args
-/libudev.hierarchy
-/libudev.interfaces
-/libudev.prerequisites
-/libudev.signals
-/html/
-/xml/
-/*.stamp
-/*.bak
-/tmpl/
diff --git a/docs/libudev/Makefile.am b/docs/libudev/Makefile.am
deleted file mode 100644
index 2998c35167..0000000000
--- a/docs/libudev/Makefile.am
+++ /dev/null
@@ -1,109 +0,0 @@
-## Process this file with automake to produce Makefile.in
-
-# We require automake 1.10 at least.
-AUTOMAKE_OPTIONS = 1.10 color-tests
-
-# This is a blank Makefile.am for using gtk-doc.
-# Copy this to your project's API docs directory and modify the variables to
-# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
-# of using the various options.
-
-# The name of the module, e.g. 'glib'.
-DOC_MODULE=libudev
-
-# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
-#DOC_MODULE_VERSION=2
-
-# The top-level SGML file. You can change this if you want to.
-DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
-
-# The directory containing the source code. Relative to $(srcdir).
-# gtk-doc will search all .c & .h files beneath here for inline comments
-# documenting the functions and macros.
-# e.g. DOC_SOURCE_DIR=../../../gtk
-DOC_SOURCE_DIR=$(top_srcdir)/src/libudev
-
-# Extra options to pass to gtkdoc-scangobj. Not normally needed.
-SCANGOBJ_OPTIONS=
-
-# Extra options to supply to gtkdoc-scan.
-# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
-SCAN_OPTIONS=
-
-# Extra options to supply to gtkdoc-mkdb.
-# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
-MKDB_OPTIONS=--xml-mode --output-format=xml --name-space=udev
-
-# Extra options to supply to gtkdoc-mktmpl
-# e.g. MKTMPL_OPTIONS=--only-section-tmpl
-MKTMPL_OPTIONS=
-
-# Extra options to supply to gtkdoc-mkhtml
-MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir)
-
-# Extra options to supply to gtkdoc-fixref. Not normally needed.
-# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
-FIXXREF_OPTIONS=>/dev/null 2>&1
-
-# Used for dependencies. The docs will be rebuilt if any of these change.
-# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
-# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
-HFILE_GLOB=$(top_srcdir)/src/libudev/libudev*.h
-CFILE_GLOB=$(top_srcdir)/src/libudev/libudev*.c
-
-# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
-# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
-EXTRA_HFILES=
-
-# Header files to ignore when scanning. Use base file name, no paths
-# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
-IGNORE_HFILES = libudev-private.h
-
-# Images to copy into HTML directory.
-# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
-HTML_IMAGES=
-
-# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
-# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
-content_files = version.xml
-
-# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
-# These files must be listed here *and* in content_files
-# e.g. expand_content_files=running.sgml
-expand_content_files=
-
-# Hack, hack. You silly gtk-doc, you must not add CFLAGS multiple
-# times when calling gcc; it surely can not work with options that must
-# be listed only once.
-# Kill CFLAGS here because gtk-doc thinks adding CFLAGS to CC _and_ also
-# adding CFLAGS itself again would work.
-override CFLAGS=
-override LDFLAGS=
-
-# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
-# Only needed if you are using gtkdoc-scangobj to dynamically query widget
-# signals and properties.
-# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
-# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
-GTKDOC_CFLAGS=
-GTKDOC_LIBS=
-
-# This includes the standard gtk-doc make rules, copied by gtkdocize.
-include $(top_srcdir)/docs/gtk-doc.make
-
-# Other files to distribute
-# e.g. EXTRA_DIST += version.xml.in
-EXTRA_DIST += version.xml.in
-
-# Files not to distribute
-# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
-# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
-#DISTCLEANFILES +=
-
-# Comment this out if you want your docs-status tested during 'make check'
-if ENABLE_GTK_DOC
-if ENABLE_GTK_DOC_TESTS
-#TESTS_ENVIRONMENT = cd $(top_srcdir)
-#TESTS = $(GTKDOC_CHECK)
-endif
-endif
diff --git a/docs/libudev/libudev-docs.xml b/docs/libudev/libudev-docs.xml
deleted file mode 100644
index 454cd31646..0000000000
--- a/docs/libudev/libudev-docs.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
-[
- <!ENTITY version SYSTEM "version.xml">
-]>
-<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
- <bookinfo>
- <title>libudev Reference Manual</title>
- <releaseinfo>
- For version &version; — the latest version of this
- documentation can be found at
- <ulink role="online-location" url="http://www.freedesktop.org/software/systemd/libudev/">
- http://www.freedesktop.org/software/systemd/libudev/
- </ulink>.
- </releaseinfo>
- <copyright>
- <year>2009-2012</year>
- <holder>Kay Sievers &lt;kay@vrfy.org&gt;</holder>
- </copyright>
- </bookinfo>
-
- <chapter>
- <title>API Reference</title>
- <xi:include href="xml/libudev.xml"/>
- <xi:include href="xml/libudev-list.xml"/>
- <xi:include href="xml/libudev-device.xml"/>
- <xi:include href="xml/libudev-monitor.xml"/>
- <xi:include href="xml/libudev-enumerate.xml"/>
- <xi:include href="xml/libudev-queue.xml"/>
- <xi:include href="xml/libudev-hwdb.xml"/>
- <xi:include href="xml/libudev-util.xml"/>
- <xi:include href="xml/api-index-deprecated.xml"/>
- </chapter>
-
- <index id="api-index-full">
- <title>Index</title>
- <xi:include href="xml/api-index-full.xml"/>
- </index>
-</book>
diff --git a/docs/libudev/libudev-sections.txt b/docs/libudev/libudev-sections.txt
deleted file mode 100644
index 8a31ded4e9..0000000000
--- a/docs/libudev/libudev-sections.txt
+++ /dev/null
@@ -1,137 +0,0 @@
-<SECTION>
-<FILE>libudev</FILE>
-<TITLE>udev</TITLE>
-udev
-udev_ref
-udev_unref
-udev_new
-udev_set_log_fn
-udev_get_log_priority
-udev_set_log_priority
-udev_get_userdata
-udev_set_userdata
-</SECTION>
-
-<SECTION>
-<FILE>libudev-list</FILE>
-<TITLE>udev_list</TITLE>
-udev_list_entry
-udev_list_entry_get_next
-udev_list_entry_get_by_name
-udev_list_entry_get_name
-udev_list_entry_get_value
-udev_list_entry_foreach
-</SECTION>
-
-<SECTION>
-<FILE>libudev-device</FILE>
-<TITLE>udev_device</TITLE>
-udev_device
-udev_device_ref
-udev_device_unref
-udev_device_get_udev
-udev_device_new_from_syspath
-udev_device_new_from_devnum
-udev_device_new_from_subsystem_sysname
-udev_device_new_from_device_id
-udev_device_new_from_environment
-udev_device_get_parent
-udev_device_get_parent_with_subsystem_devtype
-udev_device_get_devpath
-udev_device_get_subsystem
-udev_device_get_devtype
-udev_device_get_syspath
-udev_device_get_sysname
-udev_device_get_sysnum
-udev_device_get_devnode
-udev_device_get_is_initialized
-udev_device_get_devlinks_list_entry
-udev_device_get_properties_list_entry
-udev_device_get_tags_list_entry
-udev_device_get_property_value
-udev_device_get_driver
-udev_device_get_devnum
-udev_device_get_action
-udev_device_get_sysattr_value
-udev_device_set_sysattr_value
-udev_device_get_sysattr_list_entry
-udev_device_get_seqnum
-udev_device_get_usec_since_initialized
-udev_device_has_tag
-</SECTION>
-
-<SECTION>
-<FILE>libudev-monitor</FILE>
-<TITLE>udev_monitor</TITLE>
-udev_monitor
-udev_monitor_ref
-udev_monitor_unref
-udev_monitor_get_udev
-udev_monitor_new_from_netlink
-udev_monitor_enable_receiving
-udev_monitor_set_receive_buffer_size
-udev_monitor_get_fd
-udev_monitor_receive_device
-udev_monitor_filter_add_match_subsystem_devtype
-udev_monitor_filter_add_match_tag
-udev_monitor_filter_update
-udev_monitor_filter_remove
-</SECTION>
-
-<SECTION>
-<FILE>libudev-enumerate</FILE>
-<TITLE>udev_enumerate</TITLE>
-udev_enumerate
-udev_enumerate_ref
-udev_enumerate_unref
-udev_enumerate_get_udev
-udev_enumerate_new
-udev_enumerate_add_match_subsystem
-udev_enumerate_add_nomatch_subsystem
-udev_enumerate_add_match_sysattr
-udev_enumerate_add_nomatch_sysattr
-udev_enumerate_add_match_property
-udev_enumerate_add_match_tag
-udev_enumerate_add_match_parent
-udev_enumerate_add_match_is_initialized
-udev_enumerate_add_match_sysname
-udev_enumerate_add_syspath
-udev_enumerate_scan_devices
-udev_enumerate_scan_subsystems
-udev_enumerate_get_list_entry
-</SECTION>
-
-<SECTION>
-<FILE>libudev-queue</FILE>
-<TITLE>udev_queue</TITLE>
-udev_queue
-udev_queue_ref
-udev_queue_unref
-udev_queue_get_udev
-udev_queue_new
-udev_queue_get_udev_is_active
-udev_queue_get_queue_is_empty
-udev_queue_get_seqnum_is_finished
-udev_queue_get_seqnum_sequence_is_finished
-udev_queue_get_queued_list_entry
-udev_queue_get_kernel_seqnum
-udev_queue_get_udev_seqnum
-udev_queue_get_fd
-udev_queue_flush
-</SECTION>
-
-<SECTION>
-<FILE>libudev-hwdb</FILE>
-<TITLE>udev_hwdb</TITLE>
-udev_hwdb
-udev_hwdb_ref
-udev_hwdb_unref
-udev_hwdb_new
-udev_hwdb_get_properties_list_entry
-</SECTION>
-
-<SECTION>
-<FILE>libudev-util</FILE>
-<TITLE>udev_util</TITLE>
-udev_util_encode_string
-</SECTION>
diff --git a/docs/libudev/libudev.types b/docs/libudev/libudev.types
deleted file mode 100644
index e69de29bb2..0000000000
--- a/docs/libudev/libudev.types
+++ /dev/null
diff --git a/docs/libudev/version.xml.in b/docs/libudev/version.xml.in
deleted file mode 100644
index d78bda9342..0000000000
--- a/docs/libudev/version.xml.in
+++ /dev/null
@@ -1 +0,0 @@
-@VERSION@
diff --git a/hwdb/20-OUI.hwdb b/hwdb/20-OUI.hwdb
index 6976bdf649..fa4633dc16 100644
--- a/hwdb/20-OUI.hwdb
+++ b/hwdb/20-OUI.hwdb
@@ -2267,7 +2267,7 @@ OUI:0050C22FC*
ID_OUI_FROM_DATABASE=Blackline Systems Corporation
OUI:0050C22FD*
- ID_OUI_FROM_DATABASE=American Microsystems LTD
+ ID_OUI_FROM_DATABASE=American Microsystems, Ltd.
OUI:0050C22FE*
ID_OUI_FROM_DATABASE=Saab AB
@@ -2942,7 +2942,7 @@ OUI:0050C23DD*
ID_OUI_FROM_DATABASE=ELMIC GmbH
OUI:0050C23DE*
- ID_OUI_FROM_DATABASE=ABB Power Technologies
+ ID_OUI_FROM_DATABASE=ABB Power Technologies S.p.A. Unità Operativa SACE (PTMV)
OUI:0050C23DF*
ID_OUI_FROM_DATABASE=BiODE Inc.
@@ -3146,7 +3146,7 @@ OUI:0050C2421*
ID_OUI_FROM_DATABASE=EFSYS
OUI:0050C2422*
- ID_OUI_FROM_DATABASE=Gekeler Martina
+ ID_OUI_FROM_DATABASE=ads-tec GmbH
OUI:0050C2423*
ID_OUI_FROM_DATABASE=Power-One Inc.
@@ -3299,7 +3299,7 @@ OUI:0050C2454*
ID_OUI_FROM_DATABASE=Brivo Systems, LLC
OUI:0050C2455*
- ID_OUI_FROM_DATABASE=AirCell, Inc.
+ ID_OUI_FROM_DATABASE=Aircell
OUI:0050C2456*
ID_OUI_FROM_DATABASE=DRDC Valcartier
@@ -3461,7 +3461,7 @@ OUI:0050C248A*
ID_OUI_FROM_DATABASE=Mobile Matrix, Inc.
OUI:0050C248B*
- ID_OUI_FROM_DATABASE=ADS-TEC GmbH
+ ID_OUI_FROM_DATABASE=ads-tec GmbH
OUI:0050C248C*
ID_OUI_FROM_DATABASE=UNITON AG
@@ -3704,7 +3704,7 @@ OUI:0050C24DB*
ID_OUI_FROM_DATABASE=Alfing Montagetechnik GmbH
OUI:0050C24DC*
- ID_OUI_FROM_DATABASE=Ace Electronics Inc.
+ ID_OUI_FROM_DATABASE=Ace Electronics, Inc.
OUI:0050C24DD*
ID_OUI_FROM_DATABASE=Truteq Wireless (PTY) Ltd.
@@ -4898,7 +4898,7 @@ OUI:0050C2669*
ID_OUI_FROM_DATABASE=DSP DESIGN
OUI:0050C266A*
- ID_OUI_FROM_DATABASE=ABB Xiamen Transmission and Distribution Automation Equipmen
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C266B*
ID_OUI_FROM_DATABASE=flsystem
@@ -4952,7 +4952,7 @@ OUI:0050C267B*
ID_OUI_FROM_DATABASE=Sparton Electronics
OUI:0050C267C*
- ID_OUI_FROM_DATABASE=AirCell, Inc.
+ ID_OUI_FROM_DATABASE=Aircell
OUI:0050C267D*
ID_OUI_FROM_DATABASE=ESA Messtechnik GmbH
@@ -5648,7 +5648,7 @@ OUI:0050C2763*
ID_OUI_FROM_DATABASE=XtendWave
OUI:0050C2764*
- ID_OUI_FROM_DATABASE=Argus-Spectrum
+ ID_OUI_FROM_DATABASE=ARGUS-SPECTRUM
OUI:0050C2765*
ID_OUI_FROM_DATABASE=Phytec Messtechnik GmbH
@@ -5837,7 +5837,7 @@ OUI:0050C27A2*
ID_OUI_FROM_DATABASE=RaySat Israel LTD
OUI:0050C27A3*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiam
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C27A4*
ID_OUI_FROM_DATABASE=Calibre UK LTD
@@ -5966,7 +5966,7 @@ OUI:0050C27CD*
ID_OUI_FROM_DATABASE=Precision MicroControl Corporation
OUI:0050C27CE*
- ID_OUI_FROM_DATABASE=AirCell Inc.
+ ID_OUI_FROM_DATABASE=Aircell
OUI:0050C27CF*
ID_OUI_FROM_DATABASE=Emitech Corporation
@@ -6380,7 +6380,7 @@ OUI:0050C2859*
ID_OUI_FROM_DATABASE=Nuvation
OUI:0050C285A*
- ID_OUI_FROM_DATABASE=ART s.r.l.
+ ID_OUI_FROM_DATABASE=ART Spa
OUI:0050C285B*
ID_OUI_FROM_DATABASE=Boreste
@@ -6521,7 +6521,7 @@ OUI:0050C2888*
ID_OUI_FROM_DATABASE=IADEA CORPORATION
OUI:0050C2889*
- ID_OUI_FROM_DATABASE=ACS MOTION CONTROL
+ ID_OUI_FROM_DATABASE=ACS Motion Control Ltd.
OUI:0050C288A*
ID_OUI_FROM_DATABASE=Continental Electronics Corp.
@@ -7625,7 +7625,7 @@ OUI:0050C29F8*
ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd
OUI:0050C29F9*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China)
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C29FA*
ID_OUI_FROM_DATABASE=Teranex A Division of Silicon Optix
@@ -7676,7 +7676,7 @@ OUI:0050C2A09*
ID_OUI_FROM_DATABASE=Innovative American Technology
OUI:0050C2A0A*
- ID_OUI_FROM_DATABASE=ACD Elektronik Gmbh
+ ID_OUI_FROM_DATABASE=ACD Elektronik GmbH
OUI:0050C2A0B*
ID_OUI_FROM_DATABASE=I.D.S. Ingegneria Dei Sistemi S.p.A.
@@ -8372,7 +8372,7 @@ OUI:0050C2AF1*
ID_OUI_FROM_DATABASE=Green Goose
OUI:0050C2AF2*
- ID_OUI_FROM_DATABASE=ACD Elektronik Gmbh
+ ID_OUI_FROM_DATABASE=ACD Elektronik GmbH
OUI:0050C2AF3*
ID_OUI_FROM_DATABASE=Palomar Products, Inc.
@@ -8666,7 +8666,7 @@ OUI:0050C2B53*
ID_OUI_FROM_DATABASE=Prodco
OUI:0050C2B54*
- ID_OUI_FROM_DATABASE=APG Cash Drawer, LLC
+ ID_OUI_FROM_DATABASE=APG CASH DRAWER
OUI:0050C2B55*
ID_OUI_FROM_DATABASE=SANYO ELECTRONIC INDUSTRIES CO.,LTD
@@ -8849,7 +8849,7 @@ OUI:0050C2B91*
ID_OUI_FROM_DATABASE=Finnet-Service Ltd.
OUI:0050C2B92*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China)
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C2B93*
ID_OUI_FROM_DATABASE=EMC PARTNER AG
@@ -9203,7 +9203,7 @@ OUI:0050C2C09*
ID_OUI_FROM_DATABASE=Globe Wireless
OUI:0050C2C0A*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China)
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C2C0B*
ID_OUI_FROM_DATABASE=ProSourcing GmbH
@@ -9818,7 +9818,7 @@ OUI:0050C2CDB*
ID_OUI_FROM_DATABASE=RUTTER INC
OUI:0050C2CDC*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China)
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C2CDD*
ID_OUI_FROM_DATABASE=K.C.C. SHOKAI LIMITED
@@ -9890,7 +9890,7 @@ OUI:0050C2CF4*
ID_OUI_FROM_DATABASE=Baudisch Electronic GmbH
OUI:0050C2CF5*
- ID_OUI_FROM_DATABASE=AirCell Inc.
+ ID_OUI_FROM_DATABASE=Aircell
OUI:0050C2CF6*
ID_OUI_FROM_DATABASE=Epec Oy
@@ -10316,7 +10316,7 @@ OUI:0050C2D83*
ID_OUI_FROM_DATABASE=Blankom
OUI:0050C2D84*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China)
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C2D85*
ID_OUI_FROM_DATABASE=VITEC
@@ -10595,7 +10595,7 @@ OUI:0050C2DE0*
ID_OUI_FROM_DATABASE=INTERNET PROTOCOLO LOGICA SL
OUI:0050C2DE1*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Auto Eqip(Xiamen.China)
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C2DE2*
ID_OUI_FROM_DATABASE=SEQUTEC INC
@@ -11516,7 +11516,7 @@ OUI:0050C2F16*
ID_OUI_FROM_DATABASE=Peter Huber Kältemaschinenbau GmbH
OUI:0050C2F17*
- ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd
+ ID_OUI_FROM_DATABASE=ABB Transmission and Distribution Automation Equipment (Xiamen) Co., Ltd.
OUI:0050C2F18*
ID_OUI_FROM_DATABASE=Vitec Multimedia
@@ -12599,7 +12599,7 @@ OUI:40D855081*
ID_OUI_FROM_DATABASE=Sicon srl
OUI:40D855082*
- ID_OUI_FROM_DATABASE=ard sa
+ ID_OUI_FROM_DATABASE=ARD SA
OUI:40D855083*
ID_OUI_FROM_DATABASE=DELOPT
@@ -13061,7 +13061,7 @@ OUI:40D85511C*
ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH
OUI:40D85511D*
- ID_OUI_FROM_DATABASE=ACD Elektronik GmBH
+ ID_OUI_FROM_DATABASE=ACD Elektronik GmbH
OUI:40D85511E*
ID_OUI_FROM_DATABASE=CEMSI, Inc.
@@ -17150,7 +17150,7 @@ OUI:00048C*
ID_OUI_FROM_DATABASE=Nayna Networks, Inc.
OUI:00048D*
- ID_OUI_FROM_DATABASE=Tone Commander Systems, Inc.
+ ID_OUI_FROM_DATABASE=Teo Technologies, Inc
OUI:00048E*
ID_OUI_FROM_DATABASE=Ohm Tech Labs, Inc.
@@ -24935,7 +24935,7 @@ OUI:000ED7*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
OUI:000ED8*
- ID_OUI_FROM_DATABASE=Aktino, Inc.
+ ID_OUI_FROM_DATABASE=Positron Access Solutions Corp
OUI:000ED9*
ID_OUI_FROM_DATABASE=Aksys, Ltd.
@@ -26846,7 +26846,7 @@ OUI:001156*
ID_OUI_FROM_DATABASE=Pharos Systems NZ
OUI:001157*
- ID_OUI_FROM_DATABASE=OF Networks Co., Ltd.
+ ID_OUI_FROM_DATABASE=Oki Electric Industry Co., Ltd.
OUI:001158*
ID_OUI_FROM_DATABASE=Nortel Networks
@@ -28829,7 +28829,7 @@ OUI:0013EB*
ID_OUI_FROM_DATABASE=Sysmaster Corporation
OUI:0013EC*
- ID_OUI_FROM_DATABASE=Sunbay Software AG
+ ID_OUI_FROM_DATABASE=Netsnapper Technologies SARL
OUI:0013ED*
ID_OUI_FROM_DATABASE=PSIA
@@ -32654,7 +32654,7 @@ OUI:0018EA*
ID_OUI_FROM_DATABASE=Alltec GmbH
OUI:0018EB*
- ID_OUI_FROM_DATABASE=BroVis Wireless Networks
+ ID_OUI_FROM_DATABASE=Blue Zen Enterprises Private Limited
OUI:0018EC*
ID_OUI_FROM_DATABASE=Welding Technology Corporation
@@ -37544,7 +37544,7 @@ OUI:001F48*
ID_OUI_FROM_DATABASE=Mojix Inc.
OUI:001F49*
- ID_OUI_FROM_DATABASE=Eurosat Distribution Ltd
+ ID_OUI_FROM_DATABASE=Manhattan Technology Limited
OUI:001F4A*
ID_OUI_FROM_DATABASE=Albentia Systems S.A.
@@ -40382,7 +40382,7 @@ OUI:0022FD*
ID_OUI_FROM_DATABASE=Nokia Danmark A/S
OUI:0022FE*
- ID_OUI_FROM_DATABASE=Microprocessor Designs Inc
+ ID_OUI_FROM_DATABASE=Advanced Illumination
OUI:0022FF*
ID_OUI_FROM_DATABASE=iWDL Technologies
@@ -40838,7 +40838,7 @@ OUI:002397*
ID_OUI_FROM_DATABASE=Westell Technologies Inc.
OUI:002398*
- ID_OUI_FROM_DATABASE=Sky Control
+ ID_OUI_FROM_DATABASE=Vutlan sro
OUI:002399*
ID_OUI_FROM_DATABASE=VD Division, Samsung Electronics Co.
@@ -44296,12 +44296,18 @@ OUI:0030FE*
OUI:0030FF*
ID_OUI_FROM_DATABASE=DATAFAB SYSTEMS, INC.
+OUI:00323A*
+ ID_OUI_FROM_DATABASE=so-logic
+
OUI:00336C*
ID_OUI_FROM_DATABASE=SynapSense Corporation
OUI:0034F1*
ID_OUI_FROM_DATABASE=Radicom Research, Inc.
+OUI:0034FE*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:003532*
ID_OUI_FROM_DATABASE=Electro-Metrics Corporation
@@ -44513,7 +44519,7 @@ OUI:004035*
ID_OUI_FROM_DATABASE=OPCOM
OUI:004036*
- ID_OUI_FROM_DATABASE=TRIBE COMPUTER WORKS, INC.
+ ID_OUI_FROM_DATABASE=Zoom Telephonics, Inc
OUI:004037*
ID_OUI_FROM_DATABASE=SEA-ILAN, INC.
@@ -45218,7 +45224,7 @@ OUI:00501C*
ID_OUI_FROM_DATABASE=JATOM SYSTEMS, INC.
OUI:00501E*
- ID_OUI_FROM_DATABASE=Miranda Technologies, Inc.
+ ID_OUI_FROM_DATABASE=Grass Valley, A Belden Brand
OUI:00501F*
ID_OUI_FROM_DATABASE=MRG SYSTEMS, LTD.
@@ -48863,7 +48869,7 @@ OUI:00A0C4*
ID_OUI_FROM_DATABASE=CRISTIE ELECTRONICS LTD.
OUI:00A0C5*
- ID_OUI_FROM_DATABASE=ZYXEL COMMUNICATION
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
OUI:00A0C6*
ID_OUI_FROM_DATABASE=QUALCOMM INCORPORATED
@@ -49054,6 +49060,9 @@ OUI:00A2FF*
OUI:00A509*
ID_OUI_FROM_DATABASE=WigWag Inc.
+OUI:00A784*
+ ID_OUI_FROM_DATABASE=ITX security
+
OUI:00AA00*
ID_OUI_FROM_DATABASE=INTEL CORPORATION
@@ -49076,7 +49085,7 @@ OUI:00AEFA*
ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd.
OUI:00B009*
- ID_OUI_FROM_DATABASE=Grass Valley Group
+ ID_OUI_FROM_DATABASE=Grass Valley, A Belden Brand
OUI:00B017*
ID_OUI_FROM_DATABASE=InfoGear Technology Corp.
@@ -50288,7 +50297,7 @@ OUI:00D05B*
ID_OUI_FROM_DATABASE=ACROLOOP MOTION CONTROL
OUI:00D05C*
- ID_OUI_FROM_DATABASE=TECHNOTREND SYSTEMTECHNIK GMBH
+ ID_OUI_FROM_DATABASE=KATHREIN TechnoTrend GmbH
OUI:00D05D*
ID_OUI_FROM_DATABASE=INTELLIWORXX, INC.
@@ -50438,7 +50447,7 @@ OUI:00D08D*
ID_OUI_FROM_DATABASE=PHOENIX GROUP, INC.
OUI:00D08E*
- ID_OUI_FROM_DATABASE=NVISION INC.
+ ID_OUI_FROM_DATABASE=Grass Valley, A Belden Brand
OUI:00D08F*
ID_OUI_FROM_DATABASE=ARDENT TECHNOLOGIES, INC.
@@ -50456,7 +50465,7 @@ OUI:00D093*
ID_OUI_FROM_DATABASE=TQ - COMPONENTS GMBH
OUI:00D094*
- ID_OUI_FROM_DATABASE=TIMELINE VISTA, INC.
+ ID_OUI_FROM_DATABASE=Seeion Control LLC
OUI:00D095*
ID_OUI_FROM_DATABASE=Alcatel-Lucent, Enterprise Business Group
@@ -51664,6 +51673,9 @@ OUI:00F4B9*
OUI:00F76F*
ID_OUI_FROM_DATABASE=Apple
+OUI:00F81C*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:00F860*
ID_OUI_FROM_DATABASE=PT. Panggung Electric Citrabuana
@@ -51676,6 +51688,9 @@ OUI:00FC58*
OUI:00FC70*
ID_OUI_FROM_DATABASE=Intrepid Control Systems, Inc.
+OUI:00FC8D*
+ ID_OUI_FROM_DATABASE=Hitron Technologies. Inc
+
OUI:00FD4C*
ID_OUI_FROM_DATABASE=NEVATEC
@@ -51718,6 +51733,9 @@ OUI:02CF1C*
OUI:02E6D3*
ID_OUI_FROM_DATABASE=NIXDORF COMPUTER CORPORATION
+OUI:04021F*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:040A83*
ID_OUI_FROM_DATABASE=Alcatel-Lucent
@@ -51754,6 +51772,9 @@ OUI:041D10*
OUI:041E64*
ID_OUI_FROM_DATABASE=Apple
+OUI:041E7A*
+ ID_OUI_FROM_DATABASE=DSPWorks
+
OUI:04209A*
ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company
@@ -51835,6 +51856,9 @@ OUI:045D56*
OUI:045FA7*
ID_OUI_FROM_DATABASE=Shenzhen Yichen Technology Development Co.,LTD
+OUI:046169*
+ ID_OUI_FROM_DATABASE=MEDIA GLOBAL LINKS CO., LTD.
+
OUI:0462D7*
ID_OUI_FROM_DATABASE=ALSTOM HYDRO FRANCE
@@ -51949,6 +51973,9 @@ OUI:04C09C*
OUI:04C1B9*
ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd.
+OUI:04C23E*
+ ID_OUI_FROM_DATABASE=HTC Corporation
+
OUI:04C5A4*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -52561,6 +52588,9 @@ OUI:082719*
OUI:082AD0*
ID_OUI_FROM_DATABASE=SRD Innovations Inc.
+OUI:082CB0*
+ ID_OUI_FROM_DATABASE=Network Instruments
+
OUI:082E5F*
ID_OUI_FROM_DATABASE=Hewlett Packard
@@ -52576,6 +52606,9 @@ OUI:08379C*
OUI:0838A5*
ID_OUI_FROM_DATABASE=Funkwerk plettac electronic GmbH
+OUI:083A5C*
+ ID_OUI_FROM_DATABASE=Junilab, Inc.
+
OUI:083AB8*
ID_OUI_FROM_DATABASE=Shinoda Plasma Co., Ltd.
@@ -52648,6 +52681,9 @@ OUI:086DF2*
OUI:087045*
ID_OUI_FROM_DATABASE=Apple
+OUI:087402*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:0874F6*
ID_OUI_FROM_DATABASE=Winterhalter Gastronom GmbH
@@ -52699,6 +52735,12 @@ OUI:088E4F*
OUI:088F2C*
ID_OUI_FROM_DATABASE=Hills Sound Vision & Lighting
+OUI:0894EF*
+ ID_OUI_FROM_DATABASE=Wistron Infocomm (Zhongshan) Corporation
+
+OUI:08952A*
+ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc
+
OUI:0896D7*
ID_OUI_FROM_DATABASE=AVM GmbH
@@ -52804,6 +52846,9 @@ OUI:08EB74*
OUI:08EBED*
ID_OUI_FROM_DATABASE=World Elite Technology Co.,LTD
+OUI:08ECA9*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:08EDB9*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
@@ -52978,6 +53023,9 @@ OUI:0C74C2*
OUI:0C7523*
ID_OUI_FROM_DATABASE=BEIJING GEHUA CATV NETWORK CO.,LTD
+OUI:0C756C*
+ ID_OUI_FROM_DATABASE=Anaren Microwave, Inc.
+
OUI:0C771A*
ID_OUI_FROM_DATABASE=Apple
@@ -53020,6 +53068,9 @@ OUI:0C8CDC*
OUI:0C8D98*
ID_OUI_FROM_DATABASE=TOP EIGHT IND CORP
+OUI:0C9160*
+ ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD
+
OUI:0C924E*
ID_OUI_FROM_DATABASE=Rice Lake Weighing Systems
@@ -53131,6 +53182,9 @@ OUI:0CD502*
OUI:0CD696*
ID_OUI_FROM_DATABASE=Amimon Ltd
+OUI:0CD6BD*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:0CD7C2*
ID_OUI_FROM_DATABASE=Axium Technologies, Inc.
@@ -53161,6 +53215,9 @@ OUI:0CE5D3*
OUI:0CE709*
ID_OUI_FROM_DATABASE=Fox Crypto B.V.
+OUI:0CE725*
+ ID_OUI_FROM_DATABASE=Microsoft Corporation
+
OUI:0CE82F*
ID_OUI_FROM_DATABASE=Bonfiglioli Vectron GmbH
@@ -53200,6 +53257,9 @@ OUI:0CF893*
OUI:0CFC83*
ID_OUI_FROM_DATABASE=Airoha Technology Corp.,
+OUI:0CFE45*
+ ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc.
+
OUI:10005A*
ID_OUI_FROM_DATABASE=IBM Corp
@@ -53212,6 +53272,12 @@ OUI:1000FD*
OUI:1001CA*
ID_OUI_FROM_DATABASE=Ashley Butterworth
+OUI:1002B5*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
+OUI:1005B1*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
OUI:1005CA*
ID_OUI_FROM_DATABASE=Cisco
@@ -53320,6 +53386,9 @@ OUI:103DEA*
OUI:1040F3*
ID_OUI_FROM_DATABASE=Apple
+OUI:10417F*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:104369*
ID_OUI_FROM_DATABASE=Soundmax Electronic Limited
@@ -53417,11 +53486,14 @@ OUI:107A86*
ID_OUI_FROM_DATABASE=U&U ENGINEERING INC.
OUI:107BEF*
- ID_OUI_FROM_DATABASE=ZyXEL Communications Corp
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
OUI:1083D2*
ID_OUI_FROM_DATABASE=Microseven Systems, LLC
+OUI:10868C*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
OUI:10880F*
ID_OUI_FROM_DATABASE=Daruma Telecomunicações e Informática S.A.
@@ -53539,6 +53611,9 @@ OUI:10DDF4*
OUI:10DEE4*
ID_OUI_FROM_DATABASE=automationNEXT GmbH
+OUI:10DF8B*
+ ID_OUI_FROM_DATABASE=Shenzhen CareDear Communication Technology Co.,Ltd
+
OUI:10E2D5*
ID_OUI_FROM_DATABASE=Qi Hardware Inc.
@@ -53611,6 +53686,9 @@ OUI:141330*
OUI:14144B*
ID_OUI_FROM_DATABASE=FUJIAN STAR-NET COMMUNICATION CO.,LTD
+OUI:14157C*
+ ID_OUI_FROM_DATABASE=TOKYO COSMOS ELECTRIC CO.,LTD.
+
OUI:141A51*
ID_OUI_FROM_DATABASE=Treetech Sistemas Digitais
@@ -53656,6 +53734,9 @@ OUI:14307A*
OUI:1430C6*
ID_OUI_FROM_DATABASE=Motorola Mobility LLC
+OUI:1432D1*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:14358B*
ID_OUI_FROM_DATABASE=Mediabridge Products, LLC.
@@ -53680,6 +53761,9 @@ OUI:143DF2*
OUI:143E60*
ID_OUI_FROM_DATABASE=Alcatel-Lucent
+OUI:143EBF*
+ ID_OUI_FROM_DATABASE=zte corporation
+
OUI:144146*
ID_OUI_FROM_DATABASE=Honeywell (China) Co., LTD
@@ -53716,6 +53800,9 @@ OUI:1458D0*
OUI:145A05*
ID_OUI_FROM_DATABASE=Apple
+OUI:145A83*
+ ID_OUI_FROM_DATABASE=Logi-D inc
+
OUI:145BD1*
ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
@@ -53770,6 +53857,9 @@ OUI:148FC6*
OUI:149090*
ID_OUI_FROM_DATABASE=KongTop industrial(shen zhen)CO.,LTD
+OUI:149182*
+ ID_OUI_FROM_DATABASE=Belkin International Inc.
+
OUI:149448*
ID_OUI_FROM_DATABASE=BLU CASTLE S.A.
@@ -53806,6 +53896,9 @@ OUI:14B126*
OUI:14B1C8*
ID_OUI_FROM_DATABASE=InfiniWing, Inc.
+OUI:14B370*
+ ID_OUI_FROM_DATABASE=Gigaset Digital Technology (Shenzhen) Co., Ltd.
+
OUI:14B484*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -53851,6 +53944,9 @@ OUI:14DAE9*
OUI:14DB85*
ID_OUI_FROM_DATABASE=S NET MEDIA
+OUI:14DDA9*
+ ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+
OUI:14E4EC*
ID_OUI_FROM_DATABASE=mLogic LLC
@@ -53929,6 +54025,9 @@ OUI:181420*
OUI:181456*
ID_OUI_FROM_DATABASE=Nokia Corporation
+OUI:1816C9*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:181714*
ID_OUI_FROM_DATABASE=DAEWOOIS
@@ -54031,6 +54130,9 @@ OUI:184A6F*
OUI:184E94*
ID_OUI_FROM_DATABASE=MESSOA TECHNOLOGIES INC.
+OUI:184F32*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+
OUI:185253*
ID_OUI_FROM_DATABASE=Pixord Corporation
@@ -54049,6 +54151,12 @@ OUI:185936*
OUI:185AE8*
ID_OUI_FROM_DATABASE=Zenotech.Co.,Ltd
+OUI:185D9A*
+ ID_OUI_FROM_DATABASE=BobjGear LLC
+
+OUI:185E0F*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:18622C*
ID_OUI_FROM_DATABASE=SAGEMCOM SAS
@@ -54121,12 +54229,21 @@ OUI:188796*
OUI:188857*
ID_OUI_FROM_DATABASE=Beijing Jinhong Xi-Dian Information Technology Corp.
+OUI:18895B*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:1889DF*
ID_OUI_FROM_DATABASE=CerebrEX Inc.
+OUI:188B9D*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:188ED5*
ID_OUI_FROM_DATABASE=TP Vision Belgium N.V. - innovation site Brugge
+OUI:188EF9*
+ ID_OUI_FROM_DATABASE=G2C Co. Ltd.
+
OUI:18922C*
ID_OUI_FROM_DATABASE=Virtual Instruments
@@ -54361,6 +54478,9 @@ OUI:1C3DE7*
OUI:1C3E84*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+OUI:1C4024*
+ ID_OUI_FROM_DATABASE=Dell Inc
+
OUI:1C4158*
ID_OUI_FROM_DATABASE=Gemalto M2M GmbH
@@ -54376,6 +54496,9 @@ OUI:1C4840*
OUI:1C48F9*
ID_OUI_FROM_DATABASE=GN Netcom A/S
+OUI:1C497B*
+ ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd.
+
OUI:1C4AF7*
ID_OUI_FROM_DATABASE=AMON INC
@@ -54394,6 +54517,9 @@ OUI:1C5216*
OUI:1C52D6*
ID_OUI_FROM_DATABASE=FLAT DISPLAY TECHNOLOGY CORPORATION
+OUI:1C56FE*
+ ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
+
OUI:1C5A3E*
ID_OUI_FROM_DATABASE=Samsung Eletronics Co., Ltd (Visual Display Divison)
@@ -54532,6 +54658,9 @@ OUI:1CAB01*
OUI:1CABA7*
ID_OUI_FROM_DATABASE=Apple
+OUI:1CADD1*
+ ID_OUI_FROM_DATABASE=Bosung Electronics Co., Ltd.
+
OUI:1CAF05*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -54751,6 +54880,9 @@ OUI:2053CA*
OUI:205476*
ID_OUI_FROM_DATABASE=Sony Mobile Communications AB
+OUI:205531*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:205721*
ID_OUI_FROM_DATABASE=Salix Technology CO., Ltd.
@@ -54769,6 +54901,9 @@ OUI:205CFA*
OUI:206274*
ID_OUI_FROM_DATABASE=Microsoft Corporation
+OUI:20635F*
+ ID_OUI_FROM_DATABASE=Abeeway
+
OUI:206432*
ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO.,LTD.
@@ -54802,6 +54937,9 @@ OUI:207600*
OUI:207693*
ID_OUI_FROM_DATABASE=Lenovo (Beijing) Limited.
+OUI:2078F0*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:207C8F*
ID_OUI_FROM_DATABASE=Quanta Microsystems,Inc.
@@ -54937,6 +55075,9 @@ OUI:20DCE6*
OUI:20DF3F*
ID_OUI_FROM_DATABASE=Nanjing SAC Power Grid Automation Co., Ltd.
+OUI:20E407*
+ ID_OUI_FROM_DATABASE=Spark srl
+
OUI:20E52A*
ID_OUI_FROM_DATABASE=NETGEAR INC.,
@@ -54961,6 +55102,12 @@ OUI:20F002*
OUI:20F3A3*
ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+OUI:20F41B*
+ ID_OUI_FROM_DATABASE=Shenzhen Bilian electronic CO.,LTD
+
+OUI:20F510*
+ ID_OUI_FROM_DATABASE=Codex Digital Limited
+
OUI:20F85E*
ID_OUI_FROM_DATABASE=Delta Electronics
@@ -55027,6 +55174,9 @@ OUI:241C04*
OUI:241F2C*
ID_OUI_FROM_DATABASE=Calsys, Inc.
+OUI:241FA0*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:2421AB*
ID_OUI_FROM_DATABASE=Sony Ericsson Mobile Communications
@@ -55069,6 +55219,9 @@ OUI:244B81*
OUI:244F1D*
ID_OUI_FROM_DATABASE=iRule LLC
+OUI:245BF0*
+ ID_OUI_FROM_DATABASE=Liteon, Inc.
+
OUI:245FDF*
ID_OUI_FROM_DATABASE=KYOCERA Corporation
@@ -55093,9 +55246,15 @@ OUI:2469A5*
OUI:246AAB*
ID_OUI_FROM_DATABASE=IT-IS International
+OUI:246E96*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
OUI:247189*
ID_OUI_FROM_DATABASE=Texas Instruments
+OUI:247260*
+ ID_OUI_FROM_DATABASE=IOTTECH Corp
+
OUI:247656*
ID_OUI_FROM_DATABASE=Shanghai Net Miles Fiber Optics Technology Co., LTD.
@@ -55252,6 +55411,9 @@ OUI:24E271*
OUI:24E314*
ID_OUI_FROM_DATABASE=Apple
+OUI:24E5AA*
+ ID_OUI_FROM_DATABASE=Philips Oral Healthcare, Inc.
+
OUI:24E6BA*
ID_OUI_FROM_DATABASE=JSC Zavod im. Kozitsky
@@ -55327,6 +55489,9 @@ OUI:282246*
OUI:2826A6*
ID_OUI_FROM_DATABASE=PBR electronics GmbH
+OUI:2827BF*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:28285D*
ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
@@ -55351,6 +55516,9 @@ OUI:283410*
OUI:2834A2*
ID_OUI_FROM_DATABASE=Cisco
+OUI:283713*
+ ID_OUI_FROM_DATABASE=Shenzhen 3Nod Digital Technology Co., Ltd.
+
OUI:283737*
ID_OUI_FROM_DATABASE=Apple
@@ -55519,6 +55687,9 @@ OUI:28B2BD*
OUI:28B3AB*
ID_OUI_FROM_DATABASE=Genmark Automation
+OUI:28B9D9*
+ ID_OUI_FROM_DATABASE=Radisys Corporation
+
OUI:28BA18*
ID_OUI_FROM_DATABASE=NextNav, LLC
@@ -55639,6 +55810,9 @@ OUI:28ED58*
OUI:28EE2C*
ID_OUI_FROM_DATABASE=Frontline Test Equipment
+OUI:28F076*
+ ID_OUI_FROM_DATABASE=Apple
+
OUI:28F358*
ID_OUI_FROM_DATABASE=2C - Trifonov & Co
@@ -55897,6 +56071,9 @@ OUI:2CA2B4*
OUI:2CA30E*
ID_OUI_FROM_DATABASE=POWER DRAGON DEVELOPMENT LIMITED
+OUI:2CA539*
+ ID_OUI_FROM_DATABASE=Parallel Wireless, Inc
+
OUI:2CA780*
ID_OUI_FROM_DATABASE=True Technologies Inc.
@@ -55936,6 +56113,12 @@ OUI:2CBE97*
OUI:2CC260*
ID_OUI_FROM_DATABASE=Ravello Systems
+OUI:2CC548*
+ ID_OUI_FROM_DATABASE=IAdea Corporation
+
+OUI:2CC5D3*
+ ID_OUI_FROM_DATABASE=Ruckus Wireless
+
OUI:2CCC15*
ID_OUI_FROM_DATABASE=Nokia Corporation
@@ -55948,6 +56131,9 @@ OUI:2CCD43*
OUI:2CCD69*
ID_OUI_FROM_DATABASE=Aqavi.com
+OUI:2CCF58*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:2CD05A*
ID_OUI_FROM_DATABASE=Liteon Technology Corporation
@@ -55999,15 +56185,24 @@ OUI:2CF7F1*
OUI:2CFAA2*
ID_OUI_FROM_DATABASE=Alcatel-Lucent
+OUI:2CFCE4*
+ ID_OUI_FROM_DATABASE=CTEK Sweden AB
+
OUI:30055C*
ID_OUI_FROM_DATABASE=Brother industries, LTD.
OUI:300B9C*
ID_OUI_FROM_DATABASE=Delta Mobile Systems, Inc.
+OUI:300C23*
+ ID_OUI_FROM_DATABASE=zte corporation
+
OUI:300D2A*
ID_OUI_FROM_DATABASE=Zhejiang Wellcom Technology Co.,Ltd.
+OUI:300D43*
+ ID_OUI_FROM_DATABASE=Microsoft Mobile Oy
+
OUI:300ED5*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd
@@ -56092,6 +56287,9 @@ OUI:304225*
OUI:304449*
ID_OUI_FROM_DATABASE=PLATH GmbH
+OUI:304487*
+ ID_OUI_FROM_DATABASE=Hefei Radio Communication Technology Co., Ltd
+
OUI:30469A*
ID_OUI_FROM_DATABASE=NETGEAR
@@ -56173,6 +56371,12 @@ OUI:3078C2*
OUI:307C30*
ID_OUI_FROM_DATABASE=RIM
+OUI:307C5E*
+ ID_OUI_FROM_DATABASE=Juniper Networks
+
+OUI:307CB2*
+ ID_OUI_FROM_DATABASE=ANOV FRANCE
+
OUI:307ECB*
ID_OUI_FROM_DATABASE=SFR
@@ -56185,9 +56389,15 @@ OUI:308730*
OUI:308999*
ID_OUI_FROM_DATABASE=Guangdong East Power Co.,
+OUI:3089D3*
+ ID_OUI_FROM_DATABASE=HONGKONG UCLOUDLINK NETWORK TECHNOLOGY LIMITED
+
OUI:308CFB*
ID_OUI_FROM_DATABASE=Dropcam
+OUI:308D99*
+ ID_OUI_FROM_DATABASE=Hewlett Packard
+
OUI:3090AB*
ID_OUI_FROM_DATABASE=Apple
@@ -56200,6 +56410,9 @@ OUI:3092F6*
OUI:309BAD*
ID_OUI_FROM_DATABASE=BBK Electronics Corp., Ltd.,
+OUI:30A243*
+ ID_OUI_FROM_DATABASE=Shenzhen Prifox Innovation Technology Co., Ltd.
+
OUI:30A8DB*
ID_OUI_FROM_DATABASE=Sony Mobile Communications AB
@@ -56239,6 +56452,9 @@ OUI:30CDA7*
OUI:30D17E*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+OUI:30D32D*
+ ID_OUI_FROM_DATABASE=devolo AG
+
OUI:30D357*
ID_OUI_FROM_DATABASE=Logosol, Inc.
@@ -56281,6 +56497,9 @@ OUI:30F42F*
OUI:30F70D*
ID_OUI_FROM_DATABASE=Cisco Systems
+OUI:30F772*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+
OUI:30F7C5*
ID_OUI_FROM_DATABASE=Apple
@@ -56296,6 +56515,9 @@ OUI:30FAB7*
OUI:30FD11*
ID_OUI_FROM_DATABASE=MACROTECH (USA) INC.
+OUI:30FFF6*
+ ID_OUI_FROM_DATABASE=HangZhou KuoHeng Technology Co.,ltd
+
OUI:3400A3*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
@@ -56320,6 +56542,9 @@ OUI:340AFF*
OUI:340B40*
ID_OUI_FROM_DATABASE=MIOS ELETTRONICA SRL
+OUI:340CED*
+ ID_OUI_FROM_DATABASE=Moduel AB
+
OUI:341298*
ID_OUI_FROM_DATABASE=Apple
@@ -56353,6 +56578,9 @@ OUI:3423BA*
OUI:34255D*
ID_OUI_FROM_DATABASE=Shenzhen Loadcom Technology Co.,Ltd
+OUI:342606*
+ ID_OUI_FROM_DATABASE=CarePredict, Inc.
+
OUI:3428F0*
ID_OUI_FROM_DATABASE=ATN International Limited
@@ -56461,15 +56689,24 @@ OUI:3476C5*
OUI:347877*
ID_OUI_FROM_DATABASE=O-NET Communications(Shenzhen) Limited
+OUI:347A60*
+ ID_OUI_FROM_DATABASE=Pace plc
+
OUI:347E39*
ID_OUI_FROM_DATABASE=Nokia Danmark A/S
+OUI:3480B3*
+ ID_OUI_FROM_DATABASE=XIAOMI INC
+
OUI:348137*
ID_OUI_FROM_DATABASE=UNICARD SA
OUI:3481C4*
ID_OUI_FROM_DATABASE=AVM GmbH
+OUI:3481F4*
+ ID_OUI_FROM_DATABASE=SST Taiwan Ltd.
+
OUI:3482DE*
ID_OUI_FROM_DATABASE=Kayo Technology, Inc.
@@ -56506,6 +56743,9 @@ OUI:3499D7*
OUI:349A0D*
ID_OUI_FROM_DATABASE=ZBD Displays Ltd
+OUI:349B5B*
+ ID_OUI_FROM_DATABASE=Maquet GmbH
+
OUI:349D90*
ID_OUI_FROM_DATABASE=Heinzmann GmbH & CO. KG
@@ -56698,6 +56938,9 @@ OUI:34FC6F*
OUI:34FCEF*
ID_OUI_FROM_DATABASE=LG Electronics
+OUI:380195*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:380197*
ID_OUI_FROM_DATABASE=Toshiba Samsung Storage Technolgoy Korea Corporation
@@ -56716,6 +56959,9 @@ OUI:380A0A*
OUI:380A94*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:380AAB*
+ ID_OUI_FROM_DATABASE=Formlabs
+
OUI:380B40*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -56761,12 +57007,18 @@ OUI:3826CD*
OUI:3828EA*
ID_OUI_FROM_DATABASE=Fujian Netcom Technology Co., LTD
+OUI:382B78*
+ ID_OUI_FROM_DATABASE=ECO PLUGS ENTERPRISE CO., LTD
+
OUI:382C4A*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
OUI:382DD1*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:382DE8*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:3831AC*
ID_OUI_FROM_DATABASE=WEG
@@ -56899,6 +57151,9 @@ OUI:38B1DB*
OUI:38B5BD*
ID_OUI_FROM_DATABASE=E.G.O. Elektro-Ger
+OUI:38B725*
+ ID_OUI_FROM_DATABASE=Wistron Infocomm (Zhongshan) Corporation
+
OUI:38B74D*
ID_OUI_FROM_DATABASE=Fijowave Limited
@@ -56929,6 +57184,9 @@ OUI:38C7BA*
OUI:38C85C*
ID_OUI_FROM_DATABASE=Cisco SPVTG
+OUI:38C986*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:38C9A9*
ID_OUI_FROM_DATABASE=SMART High Reliability Solutions, Inc.
@@ -56971,6 +57229,9 @@ OUI:38EC11*
OUI:38ECE4*
ID_OUI_FROM_DATABASE=Samsung Electronics
+OUI:38ED18*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:38EE9D*
ID_OUI_FROM_DATABASE=Anedo Ltd.
@@ -57094,6 +57355,9 @@ OUI:3C2F3A*
OUI:3C300C*
ID_OUI_FROM_DATABASE=Dewar Electronics Pty Ltd
+OUI:3C3178*
+ ID_OUI_FROM_DATABASE=Qolsys Inc.
+
OUI:3C363D*
ID_OUI_FROM_DATABASE=Nokia Corporation
@@ -57148,6 +57412,9 @@ OUI:3C5A37*
OUI:3C5AB4*
ID_OUI_FROM_DATABASE=Google
+OUI:3C5CC3*
+ ID_OUI_FROM_DATABASE=Shenzhen First Blue Chip Technology Ltd
+
OUI:3C5EC3*
ID_OUI_FROM_DATABASE=Cisco
@@ -57256,6 +57523,9 @@ OUI:3CA10D*
OUI:3CA315*
ID_OUI_FROM_DATABASE=Bless Information & Communications Co., Ltd
+OUI:3CA31A*
+ ID_OUI_FROM_DATABASE=Oilfind International LLC
+
OUI:3CA72B*
ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD
@@ -57343,6 +57613,9 @@ OUI:3CD92B*
OUI:3CD9CE*
ID_OUI_FROM_DATABASE=Eclipse WiFi
+OUI:3CDA2A*
+ ID_OUI_FROM_DATABASE=zte corporation
+
OUI:3CDF1E*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -57463,6 +57736,9 @@ OUI:403004*
OUI:403067*
ID_OUI_FROM_DATABASE=Conlog (Pty) Ltd
+OUI:40331A*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:40336C*
ID_OUI_FROM_DATABASE=Godrej & Boyce Mfg. co. ltd
@@ -57511,6 +57787,9 @@ OUI:40560C*
OUI:405A9B*
ID_OUI_FROM_DATABASE=ANOVO
+OUI:405D82*
+ ID_OUI_FROM_DATABASE=Netgear
+
OUI:405FBE*
ID_OUI_FROM_DATABASE=RIM
@@ -57592,6 +57871,9 @@ OUI:408B07*
OUI:408BF6*
ID_OUI_FROM_DATABASE=Shenzhen TCL New Technology Co; Ltd.
+OUI:408D5C*
+ ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD.
+
OUI:409558*
ID_OUI_FROM_DATABASE=Aisino Corporation
@@ -57712,6 +57994,9 @@ OUI:40D559*
OUI:40E230*
ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc.
+OUI:40E3D6*
+ ID_OUI_FROM_DATABASE=Aruba Networks
+
OUI:40E730*
ID_OUI_FROM_DATABASE=DEY Storage Systems, Inc.
@@ -57772,6 +58057,9 @@ OUI:44184F*
OUI:4419B6*
ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd.
+OUI:441CA8*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+
OUI:441E91*
ID_OUI_FROM_DATABASE=ARVIDA Intelligent Electronics Technology Co.,Ltd.
@@ -57847,6 +58135,9 @@ OUI:444A65*
OUI:444C0C*
ID_OUI_FROM_DATABASE=Apple
+OUI:444CA8*
+ ID_OUI_FROM_DATABASE=Arista Networks
+
OUI:444E1A*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -57883,12 +58174,18 @@ OUI:445EF3*
OUI:445F7A*
ID_OUI_FROM_DATABASE=Shihlin Electric & Engineering Corp.
+OUI:445F8C*
+ ID_OUI_FROM_DATABASE=Intercel Group Limited
+
OUI:446132*
ID_OUI_FROM_DATABASE=ecobee inc
OUI:44619C*
ID_OUI_FROM_DATABASE=FONsystem co. ltd.
+OUI:44656A*
+ ID_OUI_FROM_DATABASE=Mega Video Electronic(HK) Industry Co., Ltd
+
OUI:44666E*
ID_OUI_FROM_DATABASE=IP-LINE
@@ -57973,6 +58270,9 @@ OUI:4495FA*
OUI:44962B*
ID_OUI_FROM_DATABASE=Aidon Oy
+OUI:44975A*
+ ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD
+
OUI:449B78*
ID_OUI_FROM_DATABASE=The Now Factory
@@ -58093,6 +58393,9 @@ OUI:44ED57*
OUI:44EE30*
ID_OUI_FROM_DATABASE=Budelmann Elektronik GmbH
+OUI:44F436*
+ ID_OUI_FROM_DATABASE=zte corporation
+
OUI:44F459*
ID_OUI_FROM_DATABASE=Samsung Electronics
@@ -58105,6 +58408,9 @@ OUI:44F849*
OUI:44FB42*
ID_OUI_FROM_DATABASE=Apple
+OUI:44FDA3*
+ ID_OUI_FROM_DATABASE=Everysight LTD.
+
OUI:48022A*
ID_OUI_FROM_DATABASE=B-Link Electronic Limited
@@ -58117,6 +58423,9 @@ OUI:48066A*
OUI:480C49*
ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS,INC
+OUI:480FCF*
+ ID_OUI_FROM_DATABASE=Hewlett Packard
+
OUI:481249*
ID_OUI_FROM_DATABASE=Luxcom Technologies Inc.
@@ -58153,6 +58462,9 @@ OUI:4833DD*
OUI:48343D*
ID_OUI_FROM_DATABASE=IEP GmbH
+OUI:483974*
+ ID_OUI_FROM_DATABASE=Proware Technologies Co., Ltd.
+
OUI:483D32*
ID_OUI_FROM_DATABASE=Syscor Controls &amp; Automation
@@ -58165,12 +58477,18 @@ OUI:484487*
OUI:4844F7*
ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD
+OUI:484520*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:4846F1*
ID_OUI_FROM_DATABASE=Uros Oy
OUI:4846FB*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+OUI:485073*
+ ID_OUI_FROM_DATABASE=Microsoft Corporation
+
OUI:4851B7*
ID_OUI_FROM_DATABASE=Intel Corporate
@@ -58198,6 +58516,9 @@ OUI:485AB6*
OUI:485B39*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+OUI:485D36*
+ ID_OUI_FROM_DATABASE=Verizon
+
OUI:485D60*
ID_OUI_FROM_DATABASE=Azurewave Technologies, Inc.
@@ -58336,6 +58657,9 @@ OUI:48DF1C*
OUI:48E1AF*
ID_OUI_FROM_DATABASE=Vity
+OUI:48E244*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+
OUI:48E9F1*
ID_OUI_FROM_DATABASE=Apple
@@ -58471,6 +58795,9 @@ OUI:4C322D*
OUI:4C32D9*
ID_OUI_FROM_DATABASE=M Rutty Holdings Pty. Ltd.
+OUI:4C3488*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:4C3909*
ID_OUI_FROM_DATABASE=HPL Electric & Power Private Limited
@@ -58604,7 +58931,7 @@ OUI:4C9EE4*
ID_OUI_FROM_DATABASE=Hanyang Navicom Co.,Ltd.
OUI:4C9EFF*
- ID_OUI_FROM_DATABASE=ZyXEL Communications Corp
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
OUI:4CA515*
ID_OUI_FROM_DATABASE=Baikal Electronics JSC
@@ -58627,6 +58954,9 @@ OUI:4CAB33*
OUI:4CAC0A*
ID_OUI_FROM_DATABASE=ZTE Corporation
+OUI:4CAE31*
+ ID_OUI_FROM_DATABASE=ShengHai Electronics (Shenzhen) Ltd
+
OUI:4CB16C*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
@@ -58636,9 +58966,15 @@ OUI:4CB199*
OUI:4CB4EA*
ID_OUI_FROM_DATABASE=HRD (S) PTE., LTD.
+OUI:4CB76D*
+ ID_OUI_FROM_DATABASE=Novi Security
+
OUI:4CB81C*
ID_OUI_FROM_DATABASE=SAM Electronics GmbH
+OUI:4CB82C*
+ ID_OUI_FROM_DATABASE=Cambridge Mobile Telematics, Inc.
+
OUI:4CB9C8*
ID_OUI_FROM_DATABASE=CONET CO., LTD.
@@ -58660,6 +58996,9 @@ OUI:4CC452*
OUI:4CC602*
ID_OUI_FROM_DATABASE=Radios, Inc.
+OUI:4CC681*
+ ID_OUI_FROM_DATABASE=Shenzhen Aisat Electronic Co., Ltd.
+
OUI:4CC94F*
ID_OUI_FROM_DATABASE=Alcatel-Lucent
@@ -58705,6 +59044,9 @@ OUI:4CEB42*
OUI:4CEDDE*
ID_OUI_FROM_DATABASE=Askey Computer Corp
+OUI:4CEEB0*
+ ID_OUI_FROM_DATABASE=SHC Netzwerktechnik GmbH
+
OUI:4CF02E*
ID_OUI_FROM_DATABASE=Vifa Denmark A/S
@@ -58747,6 +59089,9 @@ OUI:5014B5*
OUI:5017FF*
ID_OUI_FROM_DATABASE=Cisco
+OUI:501AA5*
+ ID_OUI_FROM_DATABASE=GN Netcom A/S
+
OUI:501AC5*
ID_OUI_FROM_DATABASE=Microsoft
@@ -58792,6 +59137,9 @@ OUI:502E5C*
OUI:502ECE*
ID_OUI_FROM_DATABASE=Asahi Electronics Co.,Ltd
+OUI:5031AD*
+ ID_OUI_FROM_DATABASE=ABB Global Industries and Services Private Limited
+
OUI:503275*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
@@ -58807,6 +59155,9 @@ OUI:503DE5*
OUI:503F56*
ID_OUI_FROM_DATABASE=Syncmold Enterprise Corp
+OUI:5045F7*
+ ID_OUI_FROM_DATABASE=Liuhe Intelligence Technology Ltd.
+
OUI:50465D*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
@@ -58876,6 +59227,9 @@ OUI:5067AE*
OUI:5067F0*
ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
+OUI:506A03*
+ ID_OUI_FROM_DATABASE=Netgear
+
OUI:506F9A*
ID_OUI_FROM_DATABASE=Wi-Fi Alliance
@@ -58897,6 +59251,12 @@ OUI:5076A6*
OUI:50795B*
ID_OUI_FROM_DATABASE=Interexport Telecomunicaciones S.A.
+OUI:507A55*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
+OUI:507B9D*
+ ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology co., ltd
+
OUI:507D02*
ID_OUI_FROM_DATABASE=BIODIT
@@ -58951,6 +59311,9 @@ OUI:50A6E3*
OUI:50A715*
ID_OUI_FROM_DATABASE=Aboundi, Inc.
+OUI:50A72B*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:50A733*
ID_OUI_FROM_DATABASE=Ruckus Wireless
@@ -59011,6 +59374,9 @@ OUI:50D274*
OUI:50D6D7*
ID_OUI_FROM_DATABASE=Takahata Precision
+OUI:50DF95*
+ ID_OUI_FROM_DATABASE=Lytx
+
OUI:50E0C7*
ID_OUI_FROM_DATABASE=TurControlSystme AG
@@ -59032,6 +59398,9 @@ OUI:50ED94*
OUI:50F003*
ID_OUI_FROM_DATABASE=Open Stack, Inc.
+OUI:50F0D3*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:50F43C*
ID_OUI_FROM_DATABASE=Leeo Inc
@@ -59086,6 +59455,9 @@ OUI:541B5D*
OUI:541DFB*
ID_OUI_FROM_DATABASE=Freestyle Energy Ltd
+OUI:541E56*
+ ID_OUI_FROM_DATABASE=juniper networks
+
OUI:541FD5*
ID_OUI_FROM_DATABASE=Advantage Electronics
@@ -59126,7 +59498,7 @@ OUI:5435DF*
ID_OUI_FROM_DATABASE=Symeo GmbH
OUI:54369B*
- ID_OUI_FROM_DATABASE=In one network technology (Beijing) Co., Ltd.
+ ID_OUI_FROM_DATABASE=1Verge Internet Technology (Beijing) Co., Ltd.
OUI:543968*
ID_OUI_FROM_DATABASE=Edgewater Networks Inc
@@ -59137,6 +59509,9 @@ OUI:5439DF*
OUI:543D37*
ID_OUI_FROM_DATABASE=Ruckus Wireless
+OUI:5440AD*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:544249*
ID_OUI_FROM_DATABASE=Sony Corporation
@@ -59170,9 +59545,18 @@ OUI:545EBD*
OUI:545FA9*
ID_OUI_FROM_DATABASE=Teracom Limited
+OUI:546009*
+ ID_OUI_FROM_DATABASE=Google Inc
+
+OUI:546172*
+ ID_OUI_FROM_DATABASE=ZODIAC AEROSPACE SAS
+
OUI:5461EA*
ID_OUI_FROM_DATABASE=Zaplox AB
+OUI:5464D9*
+ ID_OUI_FROM_DATABASE=Sagemcom SAS
+
OUI:5465DE*
ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
@@ -59230,6 +59614,9 @@ OUI:549359*
OUI:549478*
ID_OUI_FROM_DATABASE=Silvershore Technology Partners
+OUI:549A11*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:549A16*
ID_OUI_FROM_DATABASE=Uzushio Electric Co.,Ltd.
@@ -59251,9 +59638,15 @@ OUI:54A04F*
OUI:54A050*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+OUI:54A274*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:54A31B*
ID_OUI_FROM_DATABASE=Shenzhen Linkworld Technology Co,.LTD
+OUI:54A3FA*
+ ID_OUI_FROM_DATABASE=BQT Solutions (Australia)Pty Ltd
+
OUI:54A51B*
ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd
@@ -59284,6 +59677,9 @@ OUI:54BEF7*
OUI:54C80F*
ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+OUI:54CD10*
+ ID_OUI_FROM_DATABASE=Panasonic Mobile Communications Co.,Ltd.
+
OUI:54CDA7*
ID_OUI_FROM_DATABASE=Fujian Shenzhou Electronic Co.,Ltd
@@ -59362,6 +59758,9 @@ OUI:54FB58*
OUI:54FDBF*
ID_OUI_FROM_DATABASE=Scheidt & Bachmann GmbH
+OUI:54FF82*
+ ID_OUI_FROM_DATABASE=Davit Solution co.
+
OUI:54FFCF*
ID_OUI_FROM_DATABASE=Mopria Alliance
@@ -59413,6 +59812,9 @@ OUI:581FAA*
OUI:581FEF*
ID_OUI_FROM_DATABASE=Tuttnaer LTD
+OUI:5820B1*
+ ID_OUI_FROM_DATABASE=Hewlett Packard
+
OUI:582136*
ID_OUI_FROM_DATABASE=KMB systems, s.r.o.
@@ -59452,9 +59854,15 @@ OUI:5846E1*
OUI:584704*
ID_OUI_FROM_DATABASE=Shenzhen Webridge Technology Co.,Ltd
+OUI:584822*
+ ID_OUI_FROM_DATABASE=Sony Mobile Communications AB
+
OUI:5848C0*
ID_OUI_FROM_DATABASE=COFLEC
+OUI:584925*
+ ID_OUI_FROM_DATABASE=E3 Enterprise
+
OUI:58493B*
ID_OUI_FROM_DATABASE=Palo Alto Networks
@@ -59476,6 +59884,9 @@ OUI:5850AB*
OUI:5850E6*
ID_OUI_FROM_DATABASE=Best Buy Corporation
+OUI:5853C0*
+ ID_OUI_FROM_DATABASE=Beijing Guang Runtong Technology Development Company co.,Ltd
+
OUI:5855CA*
ID_OUI_FROM_DATABASE=Apple
@@ -59485,6 +59896,9 @@ OUI:5856E8*
OUI:58570D*
ID_OUI_FROM_DATABASE=Danfoss Solar Inverters
+OUI:586356*
+ ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED
+
OUI:58639A*
ID_OUI_FROM_DATABASE=TPL SYSTEMES
@@ -59575,6 +59989,9 @@ OUI:5894CF*
OUI:58971E*
ID_OUI_FROM_DATABASE=Cisco
+OUI:5897BD*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:589835*
ID_OUI_FROM_DATABASE=Technicolor
@@ -59602,6 +60019,9 @@ OUI:58B035*
OUI:58B0D4*
ID_OUI_FROM_DATABASE=ZuniData Systems Inc.
+OUI:58B633*
+ ID_OUI_FROM_DATABASE=Ruckus Wireless
+
OUI:58B961*
ID_OUI_FROM_DATABASE=SOLEM Electronique
@@ -59668,6 +60088,9 @@ OUI:58ECE1*
OUI:58EECE*
ID_OUI_FROM_DATABASE=Icon Time Systems
+OUI:58F102*
+ ID_OUI_FROM_DATABASE=BLU Products Inc.
+
OUI:58F387*
ID_OUI_FROM_DATABASE=HCCP
@@ -59794,6 +60217,9 @@ OUI:5C41E7*
OUI:5C43D2*
ID_OUI_FROM_DATABASE=HAZEMEYER
+OUI:5C4527*
+ ID_OUI_FROM_DATABASE=Juniper Networks
+
OUI:5C4A26*
ID_OUI_FROM_DATABASE=Enguity Technology Corp
@@ -59806,6 +60232,9 @@ OUI:5C5015*
OUI:5C514F*
ID_OUI_FROM_DATABASE=Intel Corporate
+OUI:5C5188*
+ ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
+
OUI:5C56ED*
ID_OUI_FROM_DATABASE=3pleplay Electronics Private Limited
@@ -59911,6 +60340,9 @@ OUI:5CAAFD*
OUI:5CAC4C*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+OUI:5CB395*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:5CB43E*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
@@ -60020,7 +60452,7 @@ OUI:5CF3FC*
ID_OUI_FROM_DATABASE=IBM Corp
OUI:5CF4AB*
- ID_OUI_FROM_DATABASE=ZyXEL Communications Corp
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
OUI:5CF50D*
ID_OUI_FROM_DATABASE=Institute of microelectronic applications
@@ -60205,6 +60637,9 @@ OUI:606BBD*
OUI:606C66*
ID_OUI_FROM_DATABASE=Intel Corporate
+OUI:606DC7*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+
OUI:60735C*
ID_OUI_FROM_DATABASE=Cisco
@@ -60424,6 +60859,9 @@ OUI:60FACD*
OUI:60FB42*
ID_OUI_FROM_DATABASE=Apple
+OUI:60FD56*
+ ID_OUI_FROM_DATABASE=WOORISYSTEMS CO., Ltd
+
OUI:60FE1E*
ID_OUI_FROM_DATABASE=China Palms Telecom.Ltd
@@ -60442,6 +60880,9 @@ OUI:60FFDD*
OUI:64002D*
ID_OUI_FROM_DATABASE=Powerlinq Co., LTD
+OUI:64006A*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
OUI:6400F1*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -60457,6 +60898,9 @@ OUI:640980*
OUI:640B4A*
ID_OUI_FROM_DATABASE=Digital Telecom Technology Limited
+OUI:640DE6*
+ ID_OUI_FROM_DATABASE=Petra Systems
+
OUI:640E36*
ID_OUI_FROM_DATABASE=TAZTAG
@@ -60715,6 +61159,9 @@ OUI:64A341*
OUI:64A3CB*
ID_OUI_FROM_DATABASE=Apple
+OUI:64A651*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:64A769*
ID_OUI_FROM_DATABASE=HTC Corporation
@@ -60757,6 +61204,9 @@ OUI:64BABD*
OUI:64BC11*
ID_OUI_FROM_DATABASE=CombiQ AB
+OUI:64C354*
+ ID_OUI_FROM_DATABASE=Avaya, Inc
+
OUI:64C5AA*
ID_OUI_FROM_DATABASE=South African Broadcasting Corporation
@@ -60859,6 +61309,9 @@ OUI:64F970*
OUI:64F987*
ID_OUI_FROM_DATABASE=Avvasi Inc.
+OUI:64FB81*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:64FC8C*
ID_OUI_FROM_DATABASE=Zonar Systems
@@ -60928,6 +61381,9 @@ OUI:683B1E*
OUI:683C7D*
ID_OUI_FROM_DATABASE=Magic Intelligence Technology Limited
+OUI:683E34*
+ ID_OUI_FROM_DATABASE=Meizu Technology Co., LTD
+
OUI:683EEC*
ID_OUI_FROM_DATABASE=ERECA
@@ -61036,6 +61492,9 @@ OUI:6886E7*
OUI:68876B*
ID_OUI_FROM_DATABASE=INQ Mobile Limited
+OUI:6889C1*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:688AB5*
ID_OUI_FROM_DATABASE=EDP Servicos
@@ -61060,6 +61519,9 @@ OUI:6897E8*
OUI:6899CD*
ID_OUI_FROM_DATABASE=Cisco
+OUI:689AB7*
+ ID_OUI_FROM_DATABASE=Atelier Vision Corporation
+
OUI:689C5E*
ID_OUI_FROM_DATABASE=AcSiP Technology Corp.
@@ -61180,6 +61642,9 @@ OUI:68EC62*
OUI:68ED43*
ID_OUI_FROM_DATABASE=Research In Motion
+OUI:68EDA4*
+ ID_OUI_FROM_DATABASE=Shenzhen Seavo Technology Co.,Ltd
+
OUI:68EE96*
ID_OUI_FROM_DATABASE=Cisco SPVTG
@@ -61201,6 +61666,9 @@ OUI:68F728*
OUI:68F895*
ID_OUI_FROM_DATABASE=Redflow Limited
+OUI:68F956*
+ ID_OUI_FROM_DATABASE=Objetivos y Servicio de Valor Añadido
+
OUI:68FB95*
ID_OUI_FROM_DATABASE=Generalplus Technology Inc.
@@ -61363,6 +61831,9 @@ OUI:6C709F*
OUI:6C71D9*
ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc
+OUI:6C7220*
+ ID_OUI_FROM_DATABASE=D-Link International
+
OUI:6C7660*
ID_OUI_FROM_DATABASE=KYOCERA Corporation
@@ -61417,6 +61888,9 @@ OUI:6C9CE9*
OUI:6C9CED*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
+OUI:6CA100*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:6CA682*
ID_OUI_FROM_DATABASE=EDAM information & communications
@@ -61507,6 +61981,9 @@ OUI:6CD68A*
OUI:6CDC6A*
ID_OUI_FROM_DATABASE=Promethean Limited
+OUI:6CE01E*
+ ID_OUI_FROM_DATABASE=Modcam AB
+
OUI:6CE0B0*
ID_OUI_FROM_DATABASE=SOUND4
@@ -61609,6 +62086,9 @@ OUI:702526*
OUI:702559*
ID_OUI_FROM_DATABASE=CyberTAN Technology, Inc.
+OUI:702A7D*
+ ID_OUI_FROM_DATABASE=EpSpot AB
+
OUI:702B1D*
ID_OUI_FROM_DATABASE=E-Domus International Limited
@@ -61900,6 +62380,9 @@ OUI:70D6B6*
OUI:70D880*
ID_OUI_FROM_DATABASE=Upos System sp. z o.o.
+OUI:70D931*
+ ID_OUI_FROM_DATABASE=Cambridge Industries Group Co Ltd.
+
OUI:70DA9C*
ID_OUI_FROM_DATABASE=TECSEN
@@ -61927,6 +62410,9 @@ OUI:70E72C*
OUI:70E843*
ID_OUI_FROM_DATABASE=Beijing C&W Optical Communication Technology Co.,Ltd.
+OUI:70ECE4*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:70EE50*
ID_OUI_FROM_DATABASE=Netatmo
@@ -61984,6 +62470,9 @@ OUI:7419F8*
OUI:741E93*
ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd.
+OUI:741F4A*
+ ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited
+
OUI:74258A*
ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited
@@ -62098,6 +62587,9 @@ OUI:746F3D*
OUI:7472F2*
ID_OUI_FROM_DATABASE=Chipsip Technology Co., Ltd.
+OUI:747336*
+ ID_OUI_FROM_DATABASE=MICRODIGTAL Inc
+
OUI:747548*
ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
@@ -62119,6 +62611,9 @@ OUI:747E2D*
OUI:748114*
ID_OUI_FROM_DATABASE=Apple
+OUI:74852A*
+ ID_OUI_FROM_DATABASE=PEGATRON CORPORATION
+
OUI:74867A*
ID_OUI_FROM_DATABASE=Dell Inc
@@ -62320,6 +62815,9 @@ OUI:74F726*
OUI:74F85D*
ID_OUI_FROM_DATABASE=Berkeley Nucleonics Corp
+OUI:74F8DB*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:74FDA0*
ID_OUI_FROM_DATABASE=Compupal (Group) Corporation
@@ -62335,6 +62833,9 @@ OUI:78028F*
OUI:780738*
ID_OUI_FROM_DATABASE=Z.U.K. Elzab S.A.
+OUI:780CB8*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:781185*
ID_OUI_FROM_DATABASE=NBS Payment Solutions Inc.
@@ -62518,6 +63019,9 @@ OUI:788C54*
OUI:788DF7*
ID_OUI_FROM_DATABASE=Hitron Technologies. Inc
+OUI:788E33*
+ ID_OUI_FROM_DATABASE=Jiangsu SEUIC Technology Co.,Ltd
+
OUI:78923E*
ID_OUI_FROM_DATABASE=Nokia Corporation
@@ -62548,6 +63052,9 @@ OUI:789ED0*
OUI:789F4C*
ID_OUI_FROM_DATABASE=HOERBIGER Elektronik GmbH
+OUI:789F70*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:789F87*
ID_OUI_FROM_DATABASE=Siemens AG I IA PP PRM
@@ -62620,12 +63127,21 @@ OUI:78B81A*
OUI:78BAD0*
ID_OUI_FROM_DATABASE=Shinybow Technology Co. Ltd.
+OUI:78BAF9*
+ ID_OUI_FROM_DATABASE=Cisco
+
+OUI:78BDBC*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:78BEB6*
ID_OUI_FROM_DATABASE=Enhanced Vision
OUI:78BEBD*
ID_OUI_FROM_DATABASE=STULZ GmbH
+OUI:78C2C0*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:78C40E*
ID_OUI_FROM_DATABASE=H&D Wireless
@@ -62677,6 +63193,9 @@ OUI:78D6F0*
OUI:78D752*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+OUI:78D75F*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:78D99F*
ID_OUI_FROM_DATABASE=NuCom HK Ltd.
@@ -62713,6 +63232,9 @@ OUI:78E980*
OUI:78EB14*
ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD
+OUI:78EB39*
+ ID_OUI_FROM_DATABASE=Instituto Nacional de Tecnología Industrial
+
OUI:78EC22*
ID_OUI_FROM_DATABASE=Shanghai Qihui Telecom Technology Co., LTD
@@ -62782,6 +63304,9 @@ OUI:7C092B*
OUI:7C0A50*
ID_OUI_FROM_DATABASE=J-MEX Inc.
+OUI:7C0BC6*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:7C0ECE*
ID_OUI_FROM_DATABASE=Cisco
@@ -62821,6 +63346,9 @@ OUI:7C2064*
OUI:7C2587*
ID_OUI_FROM_DATABASE=chaowifi.com
+OUI:7C2BE1*
+ ID_OUI_FROM_DATABASE=Shenzhen Ferex Electrical Co.,Ltd
+
OUI:7C2CF3*
ID_OUI_FROM_DATABASE=Secure Electrans Ltd
@@ -62980,12 +63508,21 @@ OUI:7C9A9B*
OUI:7CA15D*
ID_OUI_FROM_DATABASE=GN ReSound A/S
+OUI:7CA237*
+ ID_OUI_FROM_DATABASE=King Slide Technology CO., LTD.
+
+OUI:7CA23E*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:7CA29B*
ID_OUI_FROM_DATABASE=D.SignT GmbH & Co. KG
OUI:7CA61D*
ID_OUI_FROM_DATABASE=MHL, LLC
+OUI:7CAB25*
+ ID_OUI_FROM_DATABASE=MESMO TECHNOLOGY INC.
+
OUI:7CACB2*
ID_OUI_FROM_DATABASE=Bosch Software Innovations GmbH
@@ -63002,7 +63539,10 @@ OUI:7CB21B*
ID_OUI_FROM_DATABASE=Cisco SPVTG
OUI:7CB232*
- ID_OUI_FROM_DATABASE=TCL King High Frequency EI,Co.,LTD
+ ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD
+
+OUI:7CB25C*
+ ID_OUI_FROM_DATABASE=Acacia Communications
OUI:7CB542*
ID_OUI_FROM_DATABASE=ACES Technology
@@ -63046,6 +63586,9 @@ OUI:7CC8D0*
OUI:7CC8D7*
ID_OUI_FROM_DATABASE=Damalisk
+OUI:7CC95A*
+ ID_OUI_FROM_DATABASE=EMC
+
OUI:7CCB0D*
ID_OUI_FROM_DATABASE=Antaira Technologies, LLC
@@ -63133,6 +63676,9 @@ OUI:7CF429*
OUI:7CF854*
ID_OUI_FROM_DATABASE=Samsung Electronics
+OUI:7CF90E*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:7CFADF*
ID_OUI_FROM_DATABASE=Apple
@@ -63142,6 +63688,9 @@ OUI:7CFE28*
OUI:7CFE4E*
ID_OUI_FROM_DATABASE=Shenzhen Safe vision Technology Co.,LTD
+OUI:7CFE90*
+ ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc.
+
OUI:7CFF62*
ID_OUI_FROM_DATABASE=Huizhou Super Electron Technology Co.,Ltd.
@@ -63169,6 +63718,9 @@ OUI:800902*
OUI:800A06*
ID_OUI_FROM_DATABASE=COMTEC co.,ltd
+OUI:800B51*
+ ID_OUI_FROM_DATABASE=Chengdu XGimi Technology Co.,Ltd
+
OUI:800E24*
ID_OUI_FROM_DATABASE=ForgetBox
@@ -63235,6 +63787,9 @@ OUI:8038FD*
OUI:8039E5*
ID_OUI_FROM_DATABASE=PATLITE CORPORATION
+OUI:803B2A*
+ ID_OUI_FROM_DATABASE=ABB Xiamen Low Voltage Equipment Co.,Ltd.
+
OUI:803B9A*
ID_OUI_FROM_DATABASE=ghe-ces electronic ag
@@ -63262,6 +63817,9 @@ OUI:804971*
OUI:804B20*
ID_OUI_FROM_DATABASE=Ventilation Control
+OUI:804E81*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:804F58*
ID_OUI_FROM_DATABASE=ThinkEco, Inc.
@@ -63316,6 +63874,9 @@ OUI:80711F*
OUI:80717A*
ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+OUI:80739F*
+ ID_OUI_FROM_DATABASE=KYOCERA Corporation
+
OUI:807459*
ID_OUI_FROM_DATABASE=K's Co.,Ltd.
@@ -63331,6 +63892,9 @@ OUI:807A7F*
OUI:807B1E*
ID_OUI_FROM_DATABASE=Corsair Components
+OUI:807B85*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:807D1B*
ID_OUI_FROM_DATABASE=Neosystem Co. Ltd.
@@ -63382,9 +63946,15 @@ OUI:80971B*
OUI:809B20*
ID_OUI_FROM_DATABASE=Intel Corporate
+OUI:809FAB*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
OUI:80A1D7*
ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co.,Ltd
+OUI:80A589*
+ ID_OUI_FROM_DATABASE=AzureWave Technologies, Inc.
+
OUI:80A85D*
ID_OUI_FROM_DATABASE=Osterhout Design Group
@@ -63424,6 +63994,9 @@ OUI:80BE05*
OUI:80C16E*
ID_OUI_FROM_DATABASE=Hewlett Packard
+OUI:80C5E6*
+ ID_OUI_FROM_DATABASE=Microsoft Corporation
+
OUI:80C63F*
ID_OUI_FROM_DATABASE=Remec Broadband Wireless , LLC
@@ -63463,18 +64036,30 @@ OUI:80D733*
OUI:80DB31*
ID_OUI_FROM_DATABASE=Power Quotient International Co., Ltd.
+OUI:80E01D*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:80E4DA*
ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
OUI:80E650*
ID_OUI_FROM_DATABASE=Apple
+OUI:80E86F*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
+OUI:80EA23*
+ ID_OUI_FROM_DATABASE=Wistron Neweb Corp.
+
OUI:80EA96*
ID_OUI_FROM_DATABASE=Apple
OUI:80EACA*
ID_OUI_FROM_DATABASE=Dialog Semiconductor Hellas SA
+OUI:80EB77*
+ ID_OUI_FROM_DATABASE=Wistron Corporation
+
OUI:80EE73*
ID_OUI_FROM_DATABASE=Shuttle Inc.
@@ -63514,6 +64099,9 @@ OUI:840B2D*
OUI:840F45*
ID_OUI_FROM_DATABASE=Shanghai GMT Digital Technologies Co., Ltd
+OUI:84119E*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:841715*
ID_OUI_FROM_DATABASE=GP Electronics (HK) Ltd.
@@ -63580,6 +64168,9 @@ OUI:842B50*
OUI:842BBC*
ID_OUI_FROM_DATABASE=Modelleisenbahn GmbH
+OUI:842E27*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:842F75*
ID_OUI_FROM_DATABASE=Innokas Group
@@ -63637,6 +64228,9 @@ OUI:84569C*
OUI:845787*
ID_OUI_FROM_DATABASE=DVR C&C Co., Ltd.
+OUI:845B12*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:845C93*
ID_OUI_FROM_DATABASE=Chabrier Services
@@ -63679,6 +64273,9 @@ OUI:84788B*
OUI:8478AC*
ID_OUI_FROM_DATABASE=Cisco
+OUI:847973*
+ ID_OUI_FROM_DATABASE=Shanghai Baud Data Communication Co.,Ltd.
+
OUI:847A88*
ID_OUI_FROM_DATABASE=HTC Corporation
@@ -63760,6 +64357,9 @@ OUI:84A6C8*
OUI:84A783*
ID_OUI_FROM_DATABASE=Alcatel Lucent
+OUI:84A788*
+ ID_OUI_FROM_DATABASE=Perples
+
OUI:84A8E4*
ID_OUI_FROM_DATABASE=Shenzhen Huawei Communication Technologies Co., Ltd
@@ -63775,6 +64375,9 @@ OUI:84AF1F*
OUI:84B153*
ID_OUI_FROM_DATABASE=Apple
+OUI:84B517*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:84B59C*
ID_OUI_FROM_DATABASE=Juniper networks
@@ -63805,6 +64408,9 @@ OUI:84CFBF*
OUI:84D32A*
ID_OUI_FROM_DATABASE=IEEE 1905.1
+OUI:84D4C8*
+ ID_OUI_FROM_DATABASE=Widex A/S
+
OUI:84D9C8*
ID_OUI_FROM_DATABASE=Unipattern Co.,
@@ -63814,6 +64420,9 @@ OUI:84DB2F*
OUI:84DBAC*
ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+OUI:84DBFC*
+ ID_OUI_FROM_DATABASE=Alcatel-Lucent
+
OUI:84DD20*
ID_OUI_FROM_DATABASE=Texas Instruments
@@ -63943,6 +64552,9 @@ OUI:883612*
OUI:883B8B*
ID_OUI_FROM_DATABASE=Cheering Connection Co. Ltd.
+OUI:884157*
+ ID_OUI_FROM_DATABASE=Shenzhen Atsmart Technology Co.,Ltd.
+
OUI:8841C1*
ID_OUI_FROM_DATABASE=ORBISAT DA AMAZONIA IND E AEROL SA
@@ -63985,6 +64597,9 @@ OUI:885BDD*
OUI:885C47*
ID_OUI_FROM_DATABASE=Alcatel Lucent
+OUI:885D90*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:88615A*
ID_OUI_FROM_DATABASE=Siano Mobile Silicon Ltd.
@@ -64006,6 +64621,9 @@ OUI:88708C*
OUI:8870EF*
ID_OUI_FROM_DATABASE=SC Professional Trading Co., Ltd.
+OUI:887384*
+ ID_OUI_FROM_DATABASE=Toshiba
+
OUI:887398*
ID_OUI_FROM_DATABASE=K2E Tekpoint
@@ -64039,6 +64657,9 @@ OUI:888B5D*
OUI:888C19*
ID_OUI_FROM_DATABASE=Brady Corp Asia Pacific Ltd
+OUI:88908D*
+ ID_OUI_FROM_DATABASE=Cisco
+
OUI:889166*
ID_OUI_FROM_DATABASE=Viewcooper Corp.
@@ -64075,6 +64696,9 @@ OUI:889FFA*
OUI:88A25E*
ID_OUI_FROM_DATABASE=juniper networks
+OUI:88A2D7*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:88A3CC*
ID_OUI_FROM_DATABASE=Amatis Controls
@@ -64120,6 +64744,9 @@ OUI:88C9D0*
OUI:88CB87*
ID_OUI_FROM_DATABASE=Apple
+OUI:88CBA5*
+ ID_OUI_FROM_DATABASE=Suzhou Torchstar Intelligent Technology Co.,Ltd
+
OUI:88CEFA*
ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
@@ -64591,12 +65218,18 @@ OUI:90203A*
OUI:902083*
ID_OUI_FROM_DATABASE=General Engine Management Systems Ltd.
+OUI:902106*
+ ID_OUI_FROM_DATABASE=BSkyB Ltd
+
OUI:902155*
ID_OUI_FROM_DATABASE=HTC Corporation
OUI:902181*
ID_OUI_FROM_DATABASE=Shanghai Huaqin Telecom Technology Co.,Ltd
+OUI:9023EC*
+ ID_OUI_FROM_DATABASE=Availink, Inc.
+
OUI:9027E4*
ID_OUI_FROM_DATABASE=Apple
@@ -64711,12 +65344,18 @@ OUI:9067F3*
OUI:9068C3*
ID_OUI_FROM_DATABASE=Motorola Mobility LLC
+OUI:906CAC*
+ ID_OUI_FROM_DATABASE=Fortinet, Inc.
+
OUI:906DC8*
ID_OUI_FROM_DATABASE=DLG Automação Industrial Ltda
OUI:906EBB*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+OUI:906FA9*
+ ID_OUI_FROM_DATABASE=NANJING PUTIAN TELECOMMUNICATIONS TECHNOLOGY CO.,LTD.
+
OUI:907025*
ID_OUI_FROM_DATABASE=Garea Microsys Co.,Ltd.
@@ -64876,6 +65515,9 @@ OUI:90D7EB*
OUI:90D852*
ID_OUI_FROM_DATABASE=Comtec Co., Ltd.
+OUI:90D8F3*
+ ID_OUI_FROM_DATABASE=zte corporation
+
OUI:90D92C*
ID_OUI_FROM_DATABASE=HUG-WITSCHI AG
@@ -64957,6 +65599,9 @@ OUI:94049C*
OUI:9405B6*
ID_OUI_FROM_DATABASE=Liling FullRiver Electronics & Technology Ltd
+OUI:940937*
+ ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
+
OUI:940B2D*
ID_OUI_FROM_DATABASE=NetView Technologies(Shenzhen) Co., Ltd
@@ -65059,6 +65704,9 @@ OUI:946269*
OUI:9463D1*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:94659C*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:9470D2*
ID_OUI_FROM_DATABASE=WINFIRM TECHNOLOGY
@@ -65113,6 +65761,9 @@ OUI:949BFD*
OUI:949C55*
ID_OUI_FROM_DATABASE=Alta Data Technologies
+OUI:949F3E*
+ ID_OUI_FROM_DATABASE=Sonos, Inc.
+
OUI:949F3F*
ID_OUI_FROM_DATABASE=Optek Digital Technology company limited
@@ -65215,6 +65866,9 @@ OUI:94D723*
OUI:94D771*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:94D859*
+ ID_OUI_FROM_DATABASE=TCT mobile ltd
+
OUI:94D93C*
ID_OUI_FROM_DATABASE=ENELPS
@@ -65254,6 +65908,9 @@ OUI:94E711*
OUI:94E848*
ID_OUI_FROM_DATABASE=FYLDE MICRO LTD
+OUI:94E96A*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:94E98C*
ID_OUI_FROM_DATABASE=Alcatel-Lucent
@@ -65266,12 +65923,18 @@ OUI:94EBCD*
OUI:94F19E*
ID_OUI_FROM_DATABASE=HUIZHOU MAORONG INTELLIGENT TECHNOLOGY CO.,LTD
+OUI:94F278*
+ ID_OUI_FROM_DATABASE=Elma Electronic
+
OUI:94F665*
ID_OUI_FROM_DATABASE=Ruckus Wireless
OUI:94F692*
ID_OUI_FROM_DATABASE=Geminico co.,Ltd.
+OUI:94F6A3*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:94F720*
ID_OUI_FROM_DATABASE=Tianjin Deviser Electronics Instrument Co., Ltd
@@ -65431,6 +66094,9 @@ OUI:986CF5*
OUI:986DC8*
ID_OUI_FROM_DATABASE=TOSHIBA MITSUBISHI-ELECTRIC INDUSTRIAL SYSTEMS CORPORATION
+OUI:9870E8*
+ ID_OUI_FROM_DATABASE=INNATECH SDN BHD
+
OUI:9873C4*
ID_OUI_FROM_DATABASE=Sage Electronic Engineering LLC
@@ -65512,6 +66178,9 @@ OUI:98C0EB*
OUI:98C845*
ID_OUI_FROM_DATABASE=PacketAccess
+OUI:98CB27*
+ ID_OUI_FROM_DATABASE=Galore Networks Pvt. Ltd.
+
OUI:98CDB4*
ID_OUI_FROM_DATABASE=Virident Systems, Inc.
@@ -65800,6 +66469,9 @@ OUI:9C9726*
OUI:9C9811*
ID_OUI_FROM_DATABASE=Guangzhou Sunrise Electronics Development Co., Ltd
+OUI:9C99A0*
+ ID_OUI_FROM_DATABASE=XIAOMI INC
+
OUI:9C9C1D*
ID_OUI_FROM_DATABASE=Starkey Labs Inc.
@@ -65815,6 +66487,9 @@ OUI:9CA3BA*
OUI:9CA577*
ID_OUI_FROM_DATABASE=Osorno Enterprises Inc.
+OUI:9CA69D*
+ ID_OUI_FROM_DATABASE=Whaley Technology Co.Ltd
+
OUI:9CA9E4*
ID_OUI_FROM_DATABASE=zte corporation
@@ -65935,6 +66610,9 @@ OUI:9CF938*
OUI:9CFBF1*
ID_OUI_FROM_DATABASE=MESOMATIC GmbH & Co.KG
+OUI:9CFC01*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:9CFFBE*
ID_OUI_FROM_DATABASE=OTSL Inc.
@@ -65971,18 +66649,27 @@ OUI:A012DB*
OUI:A0133B*
ID_OUI_FROM_DATABASE=HiTi Digital, Inc.
+OUI:A013CB*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
OUI:A0143D*
ID_OUI_FROM_DATABASE=PARROT SA
OUI:A0165C*
ID_OUI_FROM_DATABASE=Triteka LTD
+OUI:A01828*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:A01859*
ID_OUI_FROM_DATABASE=Shenzhen Yidashi Electronics Co Ltd
OUI:A01917*
ID_OUI_FROM_DATABASE=Bertel S.p.a.
+OUI:A01B29*
+ ID_OUI_FROM_DATABASE=SAGEMCOM
+
OUI:A01C05*
ID_OUI_FROM_DATABASE=NIMAX TELECOM CO.,LTD.
@@ -66013,6 +66700,9 @@ OUI:A036F0*
OUI:A036FA*
ID_OUI_FROM_DATABASE=Ettus Research LLC
+OUI:A039F7*
+ ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications)
+
OUI:A03A75*
ID_OUI_FROM_DATABASE=PSS Belgium N.V.
@@ -66178,6 +66868,9 @@ OUI:A0A23C*
OUI:A0A3E2*
ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc
+OUI:A0A65C*
+ ID_OUI_FROM_DATABASE=Supercomputing Systems AG
+
OUI:A0A763*
ID_OUI_FROM_DATABASE=Polytron Vertrieb GmbH
@@ -66328,6 +67021,9 @@ OUI:A0F6FD*
OUI:A0F849*
ID_OUI_FROM_DATABASE=Cisco
+OUI:A0F895*
+ ID_OUI_FROM_DATABASE=Tinno Mobile Technology Corp
+
OUI:A0FC6E*
ID_OUI_FROM_DATABASE=Telegrafia a.s.
@@ -66382,6 +67078,9 @@ OUI:A42305*
OUI:A424B3*
ID_OUI_FROM_DATABASE=FlatFrog Laboratories AB
+OUI:A424DD*
+ ID_OUI_FROM_DATABASE=Cambrionix Ltd
+
OUI:A4251B*
ID_OUI_FROM_DATABASE=Avaya, Inc
@@ -66397,6 +67096,9 @@ OUI:A42B8C*
OUI:A42C08*
ID_OUI_FROM_DATABASE=Masterwork Automodules
+OUI:A43135*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:A433D1*
ID_OUI_FROM_DATABASE=Fibrlink Communications Co.,Ltd.
@@ -66475,6 +67177,9 @@ OUI:A46032*
OUI:A46706*
ID_OUI_FROM_DATABASE=Apple
+OUI:A46C2A*
+ ID_OUI_FROM_DATABASE=Cisco
+
OUI:A46CC1*
ID_OUI_FROM_DATABASE=LTi REEnergy GmbH
@@ -66499,6 +67204,9 @@ OUI:A47AA4*
OUI:A47ACF*
ID_OUI_FROM_DATABASE=VIBICOM COMMUNICATIONS INC.
+OUI:A47B2C*
+ ID_OUI_FROM_DATABASE=Alcatel-Lucent
+
OUI:A47B85*
ID_OUI_FROM_DATABASE=ULTIMEDIA Co Ltd,
@@ -66523,6 +67231,9 @@ OUI:A4895B*
OUI:A48CDB*
ID_OUI_FROM_DATABASE=Lenovo
+OUI:A48D3B*
+ ID_OUI_FROM_DATABASE=Vizio, Inc
+
OUI:A49005*
ID_OUI_FROM_DATABASE=CHINA GREATWALL COMPUTER SHENZHEN CO.,LTD
@@ -66619,6 +67330,9 @@ OUI:A4C0C7*
OUI:A4C0E1*
ID_OUI_FROM_DATABASE=Nintendo Co., Ltd.
+OUI:A4C138*
+ ID_OUI_FROM_DATABASE=Telink Semiconductor (Taipei) Co. Ltd.
+
OUI:A4C2AB*
ID_OUI_FROM_DATABASE=Hangzhou LEAD-IT Information & Technology Co.,Ltd
@@ -66727,6 +67441,9 @@ OUI:A81374*
OUI:A8154D*
ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+OUI:A815D6*
+ ID_OUI_FROM_DATABASE=Shenzhen Meione Technology CO., LTD
+
OUI:A816B2*
ID_OUI_FROM_DATABASE=LG Electronics
@@ -66829,6 +67546,9 @@ OUI:A86A6F*
OUI:A870A5*
ID_OUI_FROM_DATABASE=UniComm Inc.
+OUI:A8741D*
+ ID_OUI_FROM_DATABASE=PHOENIX CONTACT Electronics GmbH
+
OUI:A875D6*
ID_OUI_FROM_DATABASE=FreeTek International Co., Ltd.
@@ -66916,6 +67636,9 @@ OUI:A89FBA*
OUI:A8A668*
ID_OUI_FROM_DATABASE=zte corporation
+OUI:A8A795*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+
OUI:A8AD3D*
ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd
@@ -66964,6 +67687,9 @@ OUI:A8D3C8*
OUI:A8D409*
ID_OUI_FROM_DATABASE=USA 111 Inc
+OUI:A8D828*
+ ID_OUI_FROM_DATABASE=Bayer HealthCare
+
OUI:A8D88A*
ID_OUI_FROM_DATABASE=Wyconn
@@ -67066,6 +67792,9 @@ OUI:AC20AA*
OUI:AC220B*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+OUI:AC293A*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:AC2DA3*
ID_OUI_FROM_DATABASE=TXTR GmbH
@@ -67144,18 +67873,30 @@ OUI:AC562C*
OUI:AC583B*
ID_OUI_FROM_DATABASE=Human Assembler, Inc.
+OUI:AC5A14*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:AC5D10*
ID_OUI_FROM_DATABASE=Pace Americas
OUI:AC5E8C*
ID_OUI_FROM_DATABASE=Utillink
+OUI:AC60B6*
+ ID_OUI_FROM_DATABASE=Ericsson AB
+
OUI:AC6123*
ID_OUI_FROM_DATABASE=Drivven, Inc.
+OUI:AC620D*
+ ID_OUI_FROM_DATABASE=Jabil Circuit (Wuxi) Co. LTD
+
OUI:AC6706*
ID_OUI_FROM_DATABASE=Ruckus Wireless
+OUI:AC676F*
+ ID_OUI_FROM_DATABASE=Electrocompaniet A.S.
+
OUI:AC6BAC*
ID_OUI_FROM_DATABASE=Jenny Science AG
@@ -67180,6 +67921,9 @@ OUI:AC7289*
OUI:AC7A42*
ID_OUI_FROM_DATABASE=iConnectivity
+OUI:AC7A4D*
+ ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD.
+
OUI:AC7BA1*
ID_OUI_FROM_DATABASE=Intel Corporate
@@ -67384,6 +68128,9 @@ OUI:ACE9AA*
OUI:ACEA6A*
ID_OUI_FROM_DATABASE=GENIX INFOCOMM CO., LTD.
+OUI:ACEC80*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
OUI:ACEE3B*
ID_OUI_FROM_DATABASE=6harmonics Inc
@@ -67402,6 +68149,9 @@ OUI:ACF7F3*
OUI:ACF97E*
ID_OUI_FROM_DATABASE=ELESYS INC.
+OUI:ACFD93*
+ ID_OUI_FROM_DATABASE=Weifang GoerTek Electronics Co., Ltd.
+
OUI:ACFDCE*
ID_OUI_FROM_DATABASE=Intel Corporate
@@ -67459,6 +68209,9 @@ OUI:B03829*
OUI:B03850*
ID_OUI_FROM_DATABASE=Nanjing CAS-ZDC IOT SYSTEM CO.,LTD
+OUI:B0411D*
+ ID_OUI_FROM_DATABASE=ITTIM Technologies
+
OUI:B0435D*
ID_OUI_FROM_DATABASE=NuLEDs, Inc.
@@ -67474,6 +68227,9 @@ OUI:B04545*
OUI:B046FC*
ID_OUI_FROM_DATABASE=MitraStar Technology Corp.
+OUI:B047BF*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:B0487A*
ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD.
@@ -67543,6 +68299,9 @@ OUI:B0793C*
OUI:B07994*
ID_OUI_FROM_DATABASE=Motorola Mobility LLC
+OUI:B07D47*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:B07D62*
ID_OUI_FROM_DATABASE=Dipl.-Ing. H. Horstmann GmbH
@@ -67625,7 +68384,7 @@ OUI:B0ADAA*
ID_OUI_FROM_DATABASE=Avaya, Inc
OUI:B0B2DC*
- ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
OUI:B0B32B*
ID_OUI_FROM_DATABASE=Slican Sp. z o.o.
@@ -67657,6 +68416,9 @@ OUI:B0C554*
OUI:B0C559*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:B0C5CA*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:B0C69A*
ID_OUI_FROM_DATABASE=Juniper Networks
@@ -67688,7 +68450,7 @@ OUI:B0D59D*
ID_OUI_FROM_DATABASE=Shenzhen Zowee Technology Co., Ltd
OUI:B0D7C5*
- ID_OUI_FROM_DATABASE=STP KFT
+ ID_OUI_FROM_DATABASE=Logipix Ltd
OUI:B0DA00*
ID_OUI_FROM_DATABASE=CERA ELECTRONIQUE
@@ -67795,6 +68557,9 @@ OUI:B424E7*
OUI:B428F1*
ID_OUI_FROM_DATABASE=E-Prime Co., Ltd.
+OUI:B4293D*
+ ID_OUI_FROM_DATABASE=Shenzhen Urovo Technology Co.,Ltd.
+
OUI:B42A39*
ID_OUI_FROM_DATABASE=ORBIT MERRET, spol. s r. o.
@@ -67822,6 +68587,9 @@ OUI:B435F7*
OUI:B43741*
ID_OUI_FROM_DATABASE=Consert, Inc.
+OUI:B437D1*
+ ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAM public listing for more information.
+
OUI:B43934*
ID_OUI_FROM_DATABASE=Pen Generations, Inc.
@@ -67891,6 +68659,9 @@ OUI:B467E9*
OUI:B46D35*
ID_OUI_FROM_DATABASE=Dalian Seasky Automation Co;Ltd
+OUI:B46D83*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:B47356*
ID_OUI_FROM_DATABASE=Hangzhou Treebear Networking Co., Ltd.
@@ -67975,6 +68746,9 @@ OUI:B4AA4D*
OUI:B4AB2C*
ID_OUI_FROM_DATABASE=MtM Technology Corporation
+OUI:B4AE2B*
+ ID_OUI_FROM_DATABASE=Microsoft
+
OUI:B4AE6F*
ID_OUI_FROM_DATABASE=Circle Reliance, Inc DBA Cranberry Networks
@@ -68123,7 +68897,7 @@ OUI:B827EB*
ID_OUI_FROM_DATABASE=Raspberry Pi Foundation
OUI:B8288B*
- ID_OUI_FROM_DATABASE=Parker Hannifin
+ ID_OUI_FROM_DATABASE=Parker Hannifin Manufacturing (UK) Ltd
OUI:B829F7*
ID_OUI_FROM_DATABASE=Blaster Tech
@@ -68209,6 +68983,9 @@ OUI:B86491*
OUI:B8653B*
ID_OUI_FROM_DATABASE=Bolymin, Inc.
+OUI:B869C2*
+ ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd.
+
OUI:B86B23*
ID_OUI_FROM_DATABASE=Toshiba
@@ -68248,6 +69025,9 @@ OUI:B87AC9*
OUI:B87CF2*
ID_OUI_FROM_DATABASE=Aerohive Networks Inc.
+OUI:B88687*
+ ID_OUI_FROM_DATABASE=Liteon Technology Corporation
+
OUI:B8871E*
ID_OUI_FROM_DATABASE=Good Mind Industries Co., Ltd.
@@ -68257,6 +69037,9 @@ OUI:B887A8*
OUI:B888E3*
ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD
+OUI:B88981*
+ ID_OUI_FROM_DATABASE=Chengdu InnoThings Technology Co., Ltd.
+
OUI:B889CA*
ID_OUI_FROM_DATABASE=ILJIN ELECTRIC Co., Ltd.
@@ -68296,6 +69079,9 @@ OUI:B898F7*
OUI:B89919*
ID_OUI_FROM_DATABASE=7signal Solutions, Inc
+OUI:B899B0*
+ ID_OUI_FROM_DATABASE=Cohere Technologies
+
OUI:B89ACD*
ID_OUI_FROM_DATABASE=ELITE OPTOELECTRONIC(ASIA)CO.,LTD
@@ -68335,6 +69121,9 @@ OUI:B8AF67*
OUI:B8B1C7*
ID_OUI_FROM_DATABASE=BT&COM CO.,LTD
+OUI:B8B3DC*
+ ID_OUI_FROM_DATABASE=DEREK (SHAOGUAN) LIMITED
+
OUI:B8B42E*
ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co,Ltd.ShenZhen
@@ -68569,6 +69358,9 @@ OUI:BC38D2*
OUI:BC39A6*
ID_OUI_FROM_DATABASE=CSUN System Technology Co.,LTD
+OUI:BC3AEA*
+ ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD.
+
OUI:BC3BAF*
ID_OUI_FROM_DATABASE=Apple
@@ -68620,6 +69412,9 @@ OUI:BC5C4C*
OUI:BC5FF4*
ID_OUI_FROM_DATABASE=ASRock Incorporation
+OUI:BC5FF6*
+ ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD.
+
OUI:BC6010*
ID_OUI_FROM_DATABASE=Qingdao Hisense Communications Co.,Ltd
@@ -68734,6 +69529,9 @@ OUI:BCA4E1*
OUI:BCA9D6*
ID_OUI_FROM_DATABASE=Cyber-Rain, Inc.
+OUI:BCADAB*
+ ID_OUI_FROM_DATABASE=Avaya, Inc
+
OUI:BCAEC5*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
@@ -68818,6 +69616,9 @@ OUI:BCEA2B*
OUI:BCEAFA*
ID_OUI_FROM_DATABASE=Hewlett Packard
+OUI:BCEB5F*
+ ID_OUI_FROM_DATABASE=Fujian Beifeng Telecom Technology Co., Ltd.
+
OUI:BCEC23*
ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD
@@ -69001,6 +69802,9 @@ OUI:C07009*
OUI:C07BBC*
ID_OUI_FROM_DATABASE=Cisco
+OUI:C07CD1*
+ ID_OUI_FROM_DATABASE=PEGATRON CORPORATION
+
OUI:C07E40*
ID_OUI_FROM_DATABASE=SHENZHEN XDK COMMUNICATION EQUIPMENT CO.,LTD
@@ -69016,6 +69820,9 @@ OUI:C0847A*
OUI:C0885B*
ID_OUI_FROM_DATABASE=SnD Tech Co., Ltd.
+OUI:C08997*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:C08ADE*
ID_OUI_FROM_DATABASE=Ruckus Wireless
@@ -69082,6 +69889,9 @@ OUI:C0B339*
OUI:C0B357*
ID_OUI_FROM_DATABASE=Yoshiki Electronics Industry Ltd.
+OUI:C0B713*
+ ID_OUI_FROM_DATABASE=Beijing Xiaoyuer Technology Co. Ltd.
+
OUI:C0B8B1*
ID_OUI_FROM_DATABASE=BitBox Ltd
@@ -69145,6 +69955,9 @@ OUI:C0E54E*
OUI:C0EAE4*
ID_OUI_FROM_DATABASE=Sonicwall
+OUI:C0EE40*
+ ID_OUI_FROM_DATABASE=Laird Technologies
+
OUI:C0EEFB*
ID_OUI_FROM_DATABASE=OnePlus Tech (Shenzhen) Ltd
@@ -69184,6 +69997,9 @@ OUI:C401CE*
OUI:C40415*
ID_OUI_FROM_DATABASE=NETGEAR INC.,
+OUI:C4047B*
+ ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd
+
OUI:C40528*
ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
@@ -69211,6 +70027,9 @@ OUI:C40F09*
OUI:C4108A*
ID_OUI_FROM_DATABASE=Ruckus Wireless
+OUI:C412F5*
+ ID_OUI_FROM_DATABASE=D-Link International
+
OUI:C413E2*
ID_OUI_FROM_DATABASE=Aerohive Networks Inc.
@@ -69397,6 +70216,9 @@ OUI:C47B2F*
OUI:C47BA3*
ID_OUI_FROM_DATABASE=NAVIS Inc.
+OUI:C47D46*
+ ID_OUI_FROM_DATABASE=Fujitsu Limited
+
OUI:C47D4F*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -69448,6 +70270,9 @@ OUI:C49805*
OUI:C49A02*
ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communicaitons)
+OUI:C49FF3*
+ ID_OUI_FROM_DATABASE=Mciao Technologies, Inc.
+
OUI:C4A81D*
ID_OUI_FROM_DATABASE=D-Link International
@@ -69520,6 +70345,9 @@ OUI:C4E92F*
OUI:C4E984*
ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+OUI:C4EA1D*
+ ID_OUI_FROM_DATABASE=Technicolor
+
OUI:C4EBE3*
ID_OUI_FROM_DATABASE=RRCN SAS
@@ -69562,6 +70390,9 @@ OUI:C808E9*
OUI:C80AA9*
ID_OUI_FROM_DATABASE=Quanta Computer Inc.
+OUI:C80E14*
+ ID_OUI_FROM_DATABASE=AVM Audiovisuelles Marketing und Computersysteme GmbH
+
OUI:C80E77*
ID_OUI_FROM_DATABASE=Le Shi Zhi Xin Electronic Technology (Tianjin) Co.,Ltd
@@ -69586,6 +70417,9 @@ OUI:C81B6B*
OUI:C81E8E*
ID_OUI_FROM_DATABASE=ADV Security (S) Pte Ltd
+OUI:C81EE7*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
OUI:C81F66*
ID_OUI_FROM_DATABASE=Dell Inc
@@ -69610,6 +70444,9 @@ OUI:C83232*
OUI:C8334B*
ID_OUI_FROM_DATABASE=Apple
+OUI:C8348E*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:C835B8*
ID_OUI_FROM_DATABASE=Ericsson, EAB/RWI/K
@@ -69622,6 +70459,9 @@ OUI:C83B45*
OUI:C83D97*
ID_OUI_FROM_DATABASE=Nokia Corporation
+OUI:C83DFC*
+ ID_OUI_FROM_DATABASE=Pioneer DJ Coroporation
+
OUI:C83E99*
ID_OUI_FROM_DATABASE=Texas Instruments
@@ -69646,6 +70486,9 @@ OUI:C848F5*
OUI:C84C75*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
+OUI:C85195*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:C85645*
ID_OUI_FROM_DATABASE=Intermas France
@@ -69662,7 +70505,7 @@ OUI:C86C1E*
ID_OUI_FROM_DATABASE=Display Systems Ltd
OUI:C86C87*
- ID_OUI_FROM_DATABASE=Zyxel Communications Corp
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
OUI:C86CB6*
ID_OUI_FROM_DATABASE=Optcom Co., Ltd.
@@ -69754,6 +70597,9 @@ OUI:C8A729*
OUI:C8A823*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:C8A9FC*
+ ID_OUI_FROM_DATABASE=Goyoo Networks Inc.
+
OUI:C8AA21*
ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
@@ -69892,6 +70738,9 @@ OUI:C8F733*
OUI:C8F981*
ID_OUI_FROM_DATABASE=Seneca s.r.l.
+OUI:C8F9C8*
+ ID_OUI_FROM_DATABASE=NewSharp Technology(SuZhou)Co,Ltd
+
OUI:C8F9F9*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -69985,6 +70834,9 @@ OUI:CC34D7*
OUI:CC3540*
ID_OUI_FROM_DATABASE=Technicolor USA Inc.
+OUI:CC37AB*
+ ID_OUI_FROM_DATABASE=Edgecore Networks Corportation
+
OUI:CC398C*
ID_OUI_FROM_DATABASE=Shiningtek
@@ -70018,6 +70870,9 @@ OUI:CC4BFB*
OUI:CC4E24*
ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc.
+OUI:CC4EEC*
+ ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
+
OUI:CC501C*
ID_OUI_FROM_DATABASE=KVH Industries, Inc.
@@ -70048,6 +70903,9 @@ OUI:CC5D4E*
OUI:CC5D57*
ID_OUI_FROM_DATABASE=Information System Research Institute,Inc.
+OUI:CC5FBF*
+ ID_OUI_FROM_DATABASE=Topwise 3G Communication Co., Ltd.
+
OUI:CC60BB*
ID_OUI_FROM_DATABASE=Empower RF Systems
@@ -70081,6 +70939,9 @@ OUI:CC7669*
OUI:CC785F*
ID_OUI_FROM_DATABASE=Apple
+OUI:CC794A*
+ ID_OUI_FROM_DATABASE=BLU Products Inc.
+
OUI:CC7A30*
ID_OUI_FROM_DATABASE=CMAX Wireless Co., Ltd.
@@ -70186,6 +71047,9 @@ OUI:CCC50A*
OUI:CCC62B*
ID_OUI_FROM_DATABASE=Tri-Systems Corporation
+OUI:CCC760*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:CCC8D7*
ID_OUI_FROM_DATABASE=CIAS Elettronica srl
@@ -70235,7 +71099,7 @@ OUI:CCEA1C*
ID_OUI_FROM_DATABASE=DCONWORKS Co., Ltd
OUI:CCEED9*
- ID_OUI_FROM_DATABASE=Deto Mechatronic GmbH
+ ID_OUI_FROM_DATABASE=VAHLE DETO GmbH
OUI:CCEF48*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -70279,6 +71143,12 @@ OUI:CCFCB1*
OUI:CCFE3C*
ID_OUI_FROM_DATABASE=Samsung Electronics
+OUI:D0034B*
+ ID_OUI_FROM_DATABASE=Apple Inc
+
+OUI:D00492*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
OUI:D00790*
ID_OUI_FROM_DATABASE=Texas Instruments
@@ -70321,6 +71191,9 @@ OUI:D023DB*
OUI:D02516*
ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD.
+OUI:D02598*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:D02788*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind.Co.Ltd
@@ -70333,6 +71206,12 @@ OUI:D02DB3*
OUI:D03110*
ID_OUI_FROM_DATABASE=Ingenic Semiconductor Co.,Ltd
+OUI:D03311*
+ ID_OUI_FROM_DATABASE=Apple, Inc
+
+OUI:D03742*
+ ID_OUI_FROM_DATABASE=Yulong Computer Telecommunication Scientific(shenzhen)Co.,Lt
+
OUI:D03761*
ID_OUI_FROM_DATABASE=Texas Instruments
@@ -70342,6 +71221,9 @@ OUI:D03972*
OUI:D039B3*
ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+OUI:D0431E*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
OUI:D046DC*
ID_OUI_FROM_DATABASE=Southwest Research Institute
@@ -70351,6 +71233,9 @@ OUI:D048F3*
OUI:D04CC1*
ID_OUI_FROM_DATABASE=SINTRONES Technology Corp.
+OUI:D04D2C*
+ ID_OUI_FROM_DATABASE=Roku, Inc
+
OUI:D04F7E*
ID_OUI_FROM_DATABASE=Apple
@@ -70468,6 +71353,9 @@ OUI:D083D4*
OUI:D084B0*
ID_OUI_FROM_DATABASE=Sagemcom
+OUI:D087E2*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:D08999*
ID_OUI_FROM_DATABASE=APCON, Inc.
@@ -70486,6 +71374,9 @@ OUI:D08CFF*
OUI:D0929E*
ID_OUI_FROM_DATABASE=Microsoft Corporation
+OUI:D09380*
+ ID_OUI_FROM_DATABASE=Ducere Technologies Pvt. Ltd.
+
OUI:D093F8*
ID_OUI_FROM_DATABASE=Stonestreet One LLC
@@ -70501,6 +71392,9 @@ OUI:D09C30*
OUI:D09D0A*
ID_OUI_FROM_DATABASE=LINKCOM
+OUI:D09DAB*
+ ID_OUI_FROM_DATABASE=TCT mobile ltd
+
OUI:D0A0D6*
ID_OUI_FROM_DATABASE=Chengdu TD Tech Ltd.
@@ -70654,6 +71548,9 @@ OUI:D4016D*
OUI:D4024A*
ID_OUI_FROM_DATABASE=Delphian Systems LLC
+OUI:D404CD*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
OUI:D40598*
ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
@@ -70741,9 +71638,15 @@ OUI:D43D67*
OUI:D43D7E*
ID_OUI_FROM_DATABASE=Micro-Star Int'l Co, Ltd
+OUI:D440F0*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:D443A8*
ID_OUI_FROM_DATABASE=Changzhou Haojie Electric Co., Ltd.
+OUI:D445E8*
+ ID_OUI_FROM_DATABASE=Jiangxi Hongpai Technology Co., Ltd.
+
OUI:D44B5E*
ID_OUI_FROM_DATABASE=TAIYO YUDEN CO., LTD.
@@ -70840,6 +71743,9 @@ OUI:D47B35*
OUI:D47B75*
ID_OUI_FROM_DATABASE=HARTING Electronics GmbH
+OUI:D47BB0*
+ ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP
+
OUI:D481CA*
ID_OUI_FROM_DATABASE=iDevices, LLC
@@ -71026,6 +71932,9 @@ OUI:D4F143*
OUI:D4F46F*
ID_OUI_FROM_DATABASE=Apple
+OUI:D4F4BE*
+ ID_OUI_FROM_DATABASE=Palo Alto Networks
+
OUI:D4F513*
ID_OUI_FROM_DATABASE=Texas Instruments
@@ -71131,6 +72040,9 @@ OUI:D842AC*
OUI:D84606*
ID_OUI_FROM_DATABASE=Silicon Valley Global Marketing
+OUI:D84710*
+ ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd.
+
OUI:D8490B*
ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
@@ -71170,6 +72082,9 @@ OUI:D85D84*
OUI:D85DE2*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
+OUI:D85DEF*
+ ID_OUI_FROM_DATABASE=Busch-Jaeger Elektro GmbH
+
OUI:D86194*
ID_OUI_FROM_DATABASE=Objetivos y Sevicios de Valor Añadido
@@ -71230,6 +72145,9 @@ OUI:D881CE*
OUI:D88466*
ID_OUI_FROM_DATABASE=Extreme Networks
+OUI:D888CE*
+ ID_OUI_FROM_DATABASE=RF Technology Pty Ltd
+
OUI:D88A3B*
ID_OUI_FROM_DATABASE=UNIT-EM
@@ -71266,6 +72184,9 @@ OUI:D8977C*
OUI:D897BA*
ID_OUI_FROM_DATABASE=PEGATRON CORPORATION
+OUI:D89A34*
+ ID_OUI_FROM_DATABASE=Beijing SHENQI Technology Co., Ltd.
+
OUI:D89D67*
ID_OUI_FROM_DATABASE=Hewlett Packard
@@ -71299,6 +72220,9 @@ OUI:D8B04C*
OUI:D8B12A*
ID_OUI_FROM_DATABASE=Panasonic Mobile Communications Co., Ltd.
+OUI:D8B190*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:D8B377*
ID_OUI_FROM_DATABASE=HTC Corporation
@@ -71401,6 +72325,9 @@ OUI:D8EB97*
OUI:D8EE78*
ID_OUI_FROM_DATABASE=Moog Protokraft
+OUI:D8EFCD*
+ ID_OUI_FROM_DATABASE=Nokia
+
OUI:D8F0F2*
ID_OUI_FROM_DATABASE=Zeebo Inc
@@ -71518,6 +72445,9 @@ OUI:DC3C2E*
OUI:DC3C84*
ID_OUI_FROM_DATABASE=Ticom Geomatics, Inc.
+OUI:DC3CF6*
+ ID_OUI_FROM_DATABASE=Atomic Rules LLC
+
OUI:DC3E51*
ID_OUI_FROM_DATABASE=Solberg & Andersen AS
@@ -71533,6 +72463,9 @@ OUI:DC49C9*
OUI:DC4EDE*
ID_OUI_FROM_DATABASE=SHINYEI TECHNOLOGY CO., LTD.
+OUI:DC5360*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:DC537C*
ID_OUI_FROM_DATABASE=Compal Broadband Networks, Inc.
@@ -71566,6 +72499,9 @@ OUI:DC7144*
OUI:DC7B94*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
+OUI:DC7FA4*
+ ID_OUI_FROM_DATABASE=2Wire
+
OUI:DC825B*
ID_OUI_FROM_DATABASE=JANUS, spol. s r.o.
@@ -71590,6 +72526,9 @@ OUI:DC9FA4*
OUI:DC9FDB*
ID_OUI_FROM_DATABASE=Ubiquiti Networks, Inc.
+OUI:DCA3AC*
+ ID_OUI_FROM_DATABASE=RBcloudtech
+
OUI:DCA5F4*
ID_OUI_FROM_DATABASE=Cisco
@@ -71668,6 +72607,9 @@ OUI:DCD87F*
OUI:DCDA4F*
ID_OUI_FROM_DATABASE=GETCK TECHNOLOGY, INC
+OUI:DCDB70*
+ ID_OUI_FROM_DATABASE=Tonfunk Systementwicklung und Service GmbH
+
OUI:DCDECA*
ID_OUI_FROM_DATABASE=Akyllor
@@ -71686,6 +72628,9 @@ OUI:DCE578*
OUI:DCE71C*
ID_OUI_FROM_DATABASE=AUG Elektronik GmbH
+OUI:DCEB94*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:DCEC06*
ID_OUI_FROM_DATABASE=Heimi Network Technology Co., Ltd.
@@ -71707,6 +72652,9 @@ OUI:DCFAD5*
OUI:DCFB02*
ID_OUI_FROM_DATABASE=Buffalo Inc.
+OUI:E00370*
+ ID_OUI_FROM_DATABASE=ShenZhen Continental Wireless Technology Co., Ltd.
+
OUI:E005C5*
ID_OUI_FROM_DATABASE=TP-LINK Technologies Co.,Ltd.
@@ -71731,6 +72679,9 @@ OUI:E01877*
OUI:E0191D*
ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+OUI:E01AEA*
+ ID_OUI_FROM_DATABASE=Allied Telesis, Inc.
+
OUI:E01C41*
ID_OUI_FROM_DATABASE=Aerohive Networks Inc.
@@ -71767,12 +72718,18 @@ OUI:E0271A*
OUI:E02A82*
ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd.
+OUI:E02CB2*
+ ID_OUI_FROM_DATABASE=Lenovo Mobile Communication (Wuhan) Company Limited
+
OUI:E02F6D*
ID_OUI_FROM_DATABASE=Cisco
OUI:E03005*
ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd
+OUI:E0319E*
+ ID_OUI_FROM_DATABASE=Valve Corporation
+
OUI:E031D0*
ID_OUI_FROM_DATABASE=SZ Telstar CO., LTD
@@ -71800,12 +72757,18 @@ OUI:E03E7D*
OUI:E03F49*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+OUI:E04136*
+ ID_OUI_FROM_DATABASE=MitraStar Technology Corp.
+
OUI:E0469A*
ID_OUI_FROM_DATABASE=NETGEAR
OUI:E04B45*
ID_OUI_FROM_DATABASE=Hi-P Electronics Pte Ltd
+OUI:E0553D*
+ ID_OUI_FROM_DATABASE=Cisco Meraki
+
OUI:E05597*
ID_OUI_FROM_DATABASE=Emergent Vision Technologies Inc.
@@ -71929,6 +72892,9 @@ OUI:E0AAB0*
OUI:E0ABFE*
ID_OUI_FROM_DATABASE=Orb Networks, Inc.
+OUI:E0ACCB*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:E0ACF1*
ID_OUI_FROM_DATABASE=Cisco
@@ -72028,6 +72994,9 @@ OUI:E0D9A2*
OUI:E0DADC*
ID_OUI_FROM_DATABASE=JVC KENWOOD Corporation
+OUI:E0DB10*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:E0DB55*
ID_OUI_FROM_DATABASE=Dell Inc
@@ -72100,6 +73069,9 @@ OUI:E4121D*
OUI:E41289*
ID_OUI_FROM_DATABASE=topsystem Systemhaus GmbH
+OUI:E41A2C*
+ ID_OUI_FROM_DATABASE=ZPE Systems, Inc.
+
OUI:E41C4B*
ID_OUI_FROM_DATABASE=V2 TECHNOLOGY, INC.
@@ -72280,9 +73252,15 @@ OUI:E496AE*
OUI:E497F0*
ID_OUI_FROM_DATABASE=Shanghai VLC Technologies Ltd. Co.
+OUI:E498D1*
+ ID_OUI_FROM_DATABASE=Microsoft Mobile Oy
+
OUI:E498D6*
ID_OUI_FROM_DATABASE=Apple, Inc
+OUI:E4A32F*
+ ID_OUI_FROM_DATABASE=Shanghai Artimen Technology Co., Ltd.
+
OUI:E4A5EF*
ID_OUI_FROM_DATABASE=TRON LINK ELECTRONICS CO., LTD.
@@ -72367,6 +73345,9 @@ OUI:E4F4C6*
OUI:E4F7A1*
ID_OUI_FROM_DATABASE=Datafox GmbH
+OUI:E4F89C*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:E4F8EF*
ID_OUI_FROM_DATABASE=Samsung Elec Co.,Ltd
@@ -72376,6 +73357,9 @@ OUI:E4F939*
OUI:E4FA1D*
ID_OUI_FROM_DATABASE=PAD Peripheral Advanced Design Inc.
+OUI:E4FAFD*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:E4FED9*
ID_OUI_FROM_DATABASE=EDMI Europe Ltd
@@ -72451,6 +73435,9 @@ OUI:E82E24*
OUI:E83381*
ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+OUI:E8377A*
+ ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation
+
OUI:E83935*
ID_OUI_FROM_DATABASE=Hewlett Packard
@@ -72505,6 +73492,9 @@ OUI:E8519D*
OUI:E85484*
ID_OUI_FROM_DATABASE=NEO INFORMATION SYSTEMS CO., LTD.
+OUI:E855B4*
+ ID_OUI_FROM_DATABASE=SAI Technology Inc.
+
OUI:E856D6*
ID_OUI_FROM_DATABASE=NCTech Ltd
@@ -72535,6 +73525,9 @@ OUI:E86183*
OUI:E861BE*
ID_OUI_FROM_DATABASE=Melec Inc.
+OUI:E86549*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
OUI:E866C4*
ID_OUI_FROM_DATABASE=Datawise Systems
@@ -72634,6 +73627,9 @@ OUI:E8B1FC*
OUI:E8B4AE*
ID_OUI_FROM_DATABASE=Shenzhen C&D Electronics Co.,Ltd
+OUI:E8B4C8*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:E8B748*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
@@ -72646,6 +73642,9 @@ OUI:E8BB3D*
OUI:E8BBA8*
ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD.
+OUI:E8BDD1*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:E8BE81*
ID_OUI_FROM_DATABASE=SAGEMCOM
@@ -72739,6 +73738,12 @@ OUI:E8F1B0*
OUI:E8F226*
ID_OUI_FROM_DATABASE=MILLSON CUSTOM SOLUTIONS INC.
+OUI:E8F2E2*
+ ID_OUI_FROM_DATABASE=LG Innotek
+
+OUI:E8F2E3*
+ ID_OUI_FROM_DATABASE=Starcor Beijing Co.,Limited
+
OUI:E8F928*
ID_OUI_FROM_DATABASE=RFTECH SRL
@@ -72748,6 +73753,9 @@ OUI:E8FC60*
OUI:E8FCAF*
ID_OUI_FROM_DATABASE=NETGEAR INC.,
+OUI:EC0133*
+ ID_OUI_FROM_DATABASE=TRINUS SYSTEMS INC.
+
OUI:EC0EC4*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
@@ -72778,9 +73786,15 @@ OUI:EC1A59*
OUI:EC1D7F*
ID_OUI_FROM_DATABASE=zte corporation
+OUI:EC1F72*
+ ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD.
+
OUI:EC219F*
ID_OUI_FROM_DATABASE=VidaBox LLC
+OUI:EC21E5*
+ ID_OUI_FROM_DATABASE=Toshiba
+
OUI:EC2257*
ID_OUI_FROM_DATABASE=JiangSu NanJing University Electronic Information Technology Co.,Ltd
@@ -72874,6 +73888,9 @@ OUI:EC5A86*
OUI:EC5C69*
ID_OUI_FROM_DATABASE=MITSUBISHI HEAVY INDUSTRIES MECHATRONICS SYSTEMS,LTD.
+OUI:EC60E0*
+ ID_OUI_FROM_DATABASE=AVI-ON LABS
+
OUI:EC6264*
ID_OUI_FROM_DATABASE=Global411 Internet Services, LLC
@@ -72952,6 +73969,9 @@ OUI:ECA29B*
OUI:ECA86B*
ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEMS CO., LTD.
+OUI:ECA9FA*
+ ID_OUI_FROM_DATABASE=GUANGDONG GENIUS TECHNOLOGY CO.,LTD.
+
OUI:ECB106*
ID_OUI_FROM_DATABASE=Acuro Networks, Inc
@@ -73036,6 +74056,9 @@ OUI:ECE9F8*
OUI:ECEA03*
ID_OUI_FROM_DATABASE=DARFON LIGHTING CORP
+OUI:ECEED8*
+ ID_OUI_FROM_DATABASE=ZTLX Network Technology Co.,Ltd
+
OUI:ECF00E*
ID_OUI_FROM_DATABASE=Abocom
@@ -73081,6 +74104,9 @@ OUI:F013C3*
OUI:F015A0*
ID_OUI_FROM_DATABASE=KyungDong One Co., Ltd.
+OUI:F0182B*
+ ID_OUI_FROM_DATABASE=LG Chem
+
OUI:F01C13*
ID_OUI_FROM_DATABASE=LG Electronics
@@ -73096,6 +74122,9 @@ OUI:F01FAF*
OUI:F0219D*
ID_OUI_FROM_DATABASE=Cal-Comp Electronics & Communications Company Ltd.
+OUI:F0224E*
+ ID_OUI_FROM_DATABASE=Esan electronic co.
+
OUI:F02329*
ID_OUI_FROM_DATABASE=SHOWA DENKI CO.,LTD.
@@ -73114,9 +74143,15 @@ OUI:F02572*
OUI:F025B7*
ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD.
+OUI:F02624*
+ ID_OUI_FROM_DATABASE=WAFA TECHNOLOGIES CO., LTD.
+
OUI:F0264C*
ID_OUI_FROM_DATABASE=Dr. Sigrist AG
+OUI:F0272D*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
OUI:F02765*
ID_OUI_FROM_DATABASE=Murata Manufactuaring Co.,Ltd.
@@ -73171,6 +74206,9 @@ OUI:F05849*
OUI:F05A09*
ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+OUI:F05B7B*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:F05D89*
ID_OUI_FROM_DATABASE=Dycon Limited
@@ -73213,6 +74251,9 @@ OUI:F07765*
OUI:F077D0*
ID_OUI_FROM_DATABASE=Xcellen
+OUI:F07816*
+ ID_OUI_FROM_DATABASE=Cisco
+
OUI:F07959*
ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
@@ -73264,6 +74305,9 @@ OUI:F093C5*
OUI:F099BF*
ID_OUI_FROM_DATABASE=Apple
+OUI:F09A51*
+ ID_OUI_FROM_DATABASE=Shanghai Viroyal Electronic Technology Company Limited
+
OUI:F09CBB*
ID_OUI_FROM_DATABASE=RaonThink Inc.
@@ -73279,6 +74323,9 @@ OUI:F09FC2*
OUI:F0A764*
ID_OUI_FROM_DATABASE=GST Co., Ltd.
+OUI:F0AB54*
+ ID_OUI_FROM_DATABASE=MITSUMI ELECTRIC CO.,LTD.
+
OUI:F0ACA4*
ID_OUI_FROM_DATABASE=HBC-radiomatic
@@ -73291,6 +74338,12 @@ OUI:F0AE51*
OUI:F0B052*
ID_OUI_FROM_DATABASE=Ruckus Wireless
+OUI:F0B2E5*
+ ID_OUI_FROM_DATABASE=Cisco Systems
+
+OUI:F0B429*
+ ID_OUI_FROM_DATABASE=XIAOMI Electronics,CO.,LTD
+
OUI:F0B479*
ID_OUI_FROM_DATABASE=Apple
@@ -73420,6 +74473,9 @@ OUI:F0FDA0*
OUI:F0FE6B*
ID_OUI_FROM_DATABASE=Shanghai High-Flying Electronics Technology Co., Ltd
+OUI:F40304*
+ ID_OUI_FROM_DATABASE=Google
+
OUI:F40321*
ID_OUI_FROM_DATABASE=BeNeXt B.V.
@@ -73453,6 +74509,9 @@ OUI:F40F1B*
OUI:F40F9B*
ID_OUI_FROM_DATABASE=WAVELINK
+OUI:F41535*
+ ID_OUI_FROM_DATABASE=SPON Communication Technology Co.,Ltd
+
OUI:F41563*
ID_OUI_FROM_DATABASE=F5 Networks, Inc.
@@ -73549,6 +74608,9 @@ OUI:F4559C*
OUI:F455E0*
ID_OUI_FROM_DATABASE=Niceway CNC Technology Co.,Ltd.Hunan Province
+OUI:F4573E*
+ ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
+
OUI:F45842*
ID_OUI_FROM_DATABASE=Boxx TV Ltd
@@ -73570,6 +74632,9 @@ OUI:F46349*
OUI:F4645D*
ID_OUI_FROM_DATABASE=Toshiba
+OUI:F4672D*
+ ID_OUI_FROM_DATABASE=ShenZhen Topstar Technology Company
+
OUI:F46A92*
ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD
@@ -73606,9 +74671,15 @@ OUI:F48139*
OUI:F48771*
ID_OUI_FROM_DATABASE=Infoblox
+OUI:F48B32*
+ ID_OUI_FROM_DATABASE=XIAOMI INC
+
OUI:F48E09*
ID_OUI_FROM_DATABASE=Nokia Corporation
+OUI:F48E92*
+ ID_OUI_FROM_DATABASE=Huawei Technologies Co., Ltd
+
OUI:F490CA*
ID_OUI_FROM_DATABASE=Tensorcom
@@ -73663,12 +74734,18 @@ OUI:F4B7E2*
OUI:F4B85E*
ID_OUI_FROM_DATABASE=Texas INstruments
+OUI:F4B8A7*
+ ID_OUI_FROM_DATABASE=zte corporation
+
OUI:F4BD7C*
ID_OUI_FROM_DATABASE=Chengdu jinshi communication Co., LTD
OUI:F4C447*
ID_OUI_FROM_DATABASE=Coagent International Enterprise Limited
+OUI:F4C613*
+ ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd
+
OUI:F4C6D7*
ID_OUI_FROM_DATABASE=blackned GmbH
@@ -73720,9 +74797,18 @@ OUI:F4E3FB*
OUI:F4E6D7*
ID_OUI_FROM_DATABASE=Solar Power Technologies, Inc.
+OUI:F4E926*
+ ID_OUI_FROM_DATABASE=Tianjin Zanpu Technology Inc.
+
+OUI:F4E9D4*
+ ID_OUI_FROM_DATABASE=QLogic Corporation
+
OUI:F4EA67*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
+OUI:F4EB38*
+ ID_OUI_FROM_DATABASE=SAGEM
+
OUI:F4EC38*
ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO., LTD.
@@ -73783,6 +74869,9 @@ OUI:F80CF3*
OUI:F80D43*
ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd.
+OUI:F80D60*
+ ID_OUI_FROM_DATABASE=CANON INC.
+
OUI:F80DEA*
ID_OUI_FROM_DATABASE=ZyCast Technology Inc.
@@ -73900,6 +74989,9 @@ OUI:F854AF*
OUI:F8572E*
ID_OUI_FROM_DATABASE=Core Brands, LLC
+OUI:F85B9C*
+ ID_OUI_FROM_DATABASE=SB SYSTEMS Co.,Ltd
+
OUI:F85BC9*
ID_OUI_FROM_DATABASE=M-Cube Spa
@@ -73936,6 +75028,9 @@ OUI:F872EA*
OUI:F87394*
ID_OUI_FROM_DATABASE=NETGEAR INC.,
+OUI:F873A2*
+ ID_OUI_FROM_DATABASE=Avaya, Inc
+
OUI:F8769B*
ID_OUI_FROM_DATABASE=Neopis Co., Ltd.
@@ -73981,6 +75076,9 @@ OUI:F893F3*
OUI:F89550*
ID_OUI_FROM_DATABASE=Proton Products Chengdu Ltd
+OUI:F895C7*
+ ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications)
+
OUI:F897CF*
ID_OUI_FROM_DATABASE=DAESHIN-INFORMATION TECHNOLOGY CO., LTD.
@@ -74032,6 +75130,9 @@ OUI:F8BC12*
OUI:F8BC41*
ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited
+OUI:F8BF09*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
OUI:F8C001*
ID_OUI_FROM_DATABASE=Juniper Networks
@@ -74137,6 +75238,9 @@ OUI:F8F1B6*
OUI:F8F25A*
ID_OUI_FROM_DATABASE=G-Lab GmbH
+OUI:F8F464*
+ ID_OUI_FROM_DATABASE=Rawe Electonic GmbH
+
OUI:F8F7D3*
ID_OUI_FROM_DATABASE=International Communications Corporation
@@ -74248,9 +75352,15 @@ OUI:FC2E2D*
OUI:FC2F40*
ID_OUI_FROM_DATABASE=Calxeda, Inc.
+OUI:FC2FEF*
+ ID_OUI_FROM_DATABASE=UTT Technologies Co., Ltd.
+
OUI:FC3288*
ID_OUI_FROM_DATABASE=CELOT Wireless Co., Ltd
+OUI:FC335F*
+ ID_OUI_FROM_DATABASE=Polyera
+
OUI:FC3598*
ID_OUI_FROM_DATABASE=Favite Inc.
@@ -74290,6 +75400,9 @@ OUI:FC4DD4*
OUI:FC5090*
ID_OUI_FROM_DATABASE=SIMEX Sp. z o.o.
+OUI:FC528D*
+ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
+
OUI:FC52CE*
ID_OUI_FROM_DATABASE=Control iD
@@ -74402,7 +75515,7 @@ OUI:FCAF6A*
ID_OUI_FROM_DATABASE=Qulsar Inc
OUI:FCAFAC*
- ID_OUI_FROM_DATABASE=Panasonic System LSI
+ ID_OUI_FROM_DATABASE=Socionext Inc.
OUI:FCB0C4*
ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co., Ltd
@@ -74416,6 +75529,9 @@ OUI:FCB698*
OUI:FCBBA1*
ID_OUI_FROM_DATABASE=Shenzhen Minicreate Technology Co.,Ltd
+OUI:FCC233*
+ ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+
OUI:FCC23D*
ID_OUI_FROM_DATABASE=Atmel Corporation
@@ -74446,6 +75562,9 @@ OUI:FCD5D9*
OUI:FCD6BD*
ID_OUI_FROM_DATABASE=Robert Bosch GmbH
+OUI:FCD733*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD
+
OUI:FCD817*
ID_OUI_FROM_DATABASE=Beijing Hesun Technologies Co.Ltd.
@@ -74491,6 +75610,9 @@ OUI:FCE998*
OUI:FCEDB9*
ID_OUI_FROM_DATABASE=Arrayent
+OUI:FCF136*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
OUI:FCF152*
ID_OUI_FROM_DATABASE=Sony Corporation
@@ -74515,8 +75637,14 @@ OUI:FCFAF7*
OUI:FCFBFB*
ID_OUI_FROM_DATABASE=CISCO SYSTEMS, INC.
+OUI:FCFC48*
+ ID_OUI_FROM_DATABASE=Apple, Inc.
+
OUI:FCFE77*
ID_OUI_FROM_DATABASE=Hitachi Reftechno, Inc.
+OUI:FCFEC2*
+ ID_OUI_FROM_DATABASE=Invensys Controls UK Limited
+
OUI:FCFFAA*
ID_OUI_FROM_DATABASE=IEEE REGISTRATION AUTHORITY - Please see MAL public listing for more information.
diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb
index fb789fd495..93241ca490 100644
--- a/hwdb/20-bluetooth-vendor-product.hwdb
+++ b/hwdb/20-bluetooth-vendor-product.hwdb
@@ -1237,7 +1237,7 @@ bluetooth:v0199*
ID_VENDOR_FROM_DATABASE=SALTO SYSTEMS S.L.
bluetooth:v019A*
- ID_VENDOR_FROM_DATABASE=T-Engine Forum
+ ID_VENDOR_FROM_DATABASE=TRON Forum (formerly T-Engine Forum)
bluetooth:v019B*
ID_VENDOR_FROM_DATABASE=CUBETECH s.r.o.
@@ -1430,3 +1430,240 @@ bluetooth:v01D9*
bluetooth:v01DA*
ID_VENDOR_FROM_DATABASE=Logitech International SA
+
+bluetooth:v01DB*
+ ID_VENDOR_FROM_DATABASE=Innblue Consulting
+
+bluetooth:v01DC*
+ ID_VENDOR_FROM_DATABASE=iParking Ltd.
+
+bluetooth:v01DD*
+ ID_VENDOR_FROM_DATABASE=Koninklijke Philips Electronics N.V.
+
+bluetooth:v01DE*
+ ID_VENDOR_FROM_DATABASE=Minelab Electronics Pty Limited
+
+bluetooth:v01DF*
+ ID_VENDOR_FROM_DATABASE=Bison Group Ltd.
+
+bluetooth:v01E0*
+ ID_VENDOR_FROM_DATABASE=Widex A/S
+
+bluetooth:v01E1*
+ ID_VENDOR_FROM_DATABASE=Jolla Ltd
+
+bluetooth:v01E2*
+ ID_VENDOR_FROM_DATABASE=Lectronix, Inc.
+
+bluetooth:v01E3*
+ ID_VENDOR_FROM_DATABASE=Caterpillar Inc
+
+bluetooth:v01E4*
+ ID_VENDOR_FROM_DATABASE=Freedom Innovations
+
+bluetooth:v01E5*
+ ID_VENDOR_FROM_DATABASE=Dynamic Devices Ltd
+
+bluetooth:v01E6*
+ ID_VENDOR_FROM_DATABASE=Technology Solutions (UK) Ltd
+
+bluetooth:v01E7*
+ ID_VENDOR_FROM_DATABASE=IPS Group Inc.
+
+bluetooth:v01E8*
+ ID_VENDOR_FROM_DATABASE=STIR
+
+bluetooth:v01E9*
+ ID_VENDOR_FROM_DATABASE=Sano, Inc
+
+bluetooth:v01EA*
+ ID_VENDOR_FROM_DATABASE=Advanced Application Design, Inc.
+
+bluetooth:v01EB*
+ ID_VENDOR_FROM_DATABASE=AutoMap LLC
+
+bluetooth:v01EC*
+ ID_VENDOR_FROM_DATABASE=Spreadtrum Communications Shanghai Ltd
+
+bluetooth:v01ED*
+ ID_VENDOR_FROM_DATABASE=CuteCircuit LTD
+
+bluetooth:v01EE*
+ ID_VENDOR_FROM_DATABASE=Valeo Service
+
+bluetooth:v01EF*
+ ID_VENDOR_FROM_DATABASE=Fullpower Technologies, Inc.
+
+bluetooth:v01F0*
+ ID_VENDOR_FROM_DATABASE=KloudNation
+
+bluetooth:v01F1*
+ ID_VENDOR_FROM_DATABASE=Zebra Technologies Corporation
+
+bluetooth:v01F2*
+ ID_VENDOR_FROM_DATABASE=Itron, Inc.
+
+bluetooth:v01F3*
+ ID_VENDOR_FROM_DATABASE=The University of Tokyo
+
+bluetooth:v01F4*
+ ID_VENDOR_FROM_DATABASE=UTC Fire and Security
+
+bluetooth:v01F5*
+ ID_VENDOR_FROM_DATABASE=Cool Webthings Limited
+
+bluetooth:v01F6*
+ ID_VENDOR_FROM_DATABASE=DJO Global
+
+bluetooth:v01F7*
+ ID_VENDOR_FROM_DATABASE=Gelliner Limited
+
+bluetooth:v01F8*
+ ID_VENDOR_FROM_DATABASE=Anyka (Guangzhou) Microelectronics Technology Co, LTD
+
+bluetooth:v01F9*
+ ID_VENDOR_FROM_DATABASE=Medtronic, Inc.
+
+bluetooth:v01FA*
+ ID_VENDOR_FROM_DATABASE=Gozio, Inc.
+
+bluetooth:v01FB*
+ ID_VENDOR_FROM_DATABASE=Form Lifting, LLC
+
+bluetooth:v01FC*
+ ID_VENDOR_FROM_DATABASE=Wahoo Fitness, LLC
+
+bluetooth:v01FD*
+ ID_VENDOR_FROM_DATABASE=Kontakt Micro-Location Sp. z o.o.
+
+bluetooth:v01FE*
+ ID_VENDOR_FROM_DATABASE=Radio System Corporation
+
+bluetooth:v01FF*
+ ID_VENDOR_FROM_DATABASE=Freescale Semiconductor, Inc.
+
+bluetooth:v0200*
+ ID_VENDOR_FROM_DATABASE=Verifone Systems PTe Ltd. Taiwan Branch
+
+bluetooth:v0201*
+ ID_VENDOR_FROM_DATABASE=AR Timing
+
+bluetooth:v0202*
+ ID_VENDOR_FROM_DATABASE=Rigado LLC
+
+bluetooth:v0203*
+ ID_VENDOR_FROM_DATABASE=Kemppi Oy
+
+bluetooth:v0204*
+ ID_VENDOR_FROM_DATABASE=Tapcentive Inc.
+
+bluetooth:v0205*
+ ID_VENDOR_FROM_DATABASE=Smartbotics Inc.
+
+bluetooth:v0206*
+ ID_VENDOR_FROM_DATABASE=Otter Products, LLC
+
+bluetooth:v0207*
+ ID_VENDOR_FROM_DATABASE=STEMP Inc.
+
+bluetooth:v0208*
+ ID_VENDOR_FROM_DATABASE=LumiGeek LLC
+
+bluetooth:v0209*
+ ID_VENDOR_FROM_DATABASE=InvisionHeart Inc.
+
+bluetooth:v020A*
+ ID_VENDOR_FROM_DATABASE=Macnica Inc.
+
+bluetooth:v020B*
+ ID_VENDOR_FROM_DATABASE=Jaguar Land Rover Limited
+
+bluetooth:v020C*
+ ID_VENDOR_FROM_DATABASE=CoroWare Technologies, Inc
+
+bluetooth:v020D*
+ ID_VENDOR_FROM_DATABASE=Simplo Technology Co., LTD
+
+bluetooth:v020E*
+ ID_VENDOR_FROM_DATABASE=Omron Healthcare Co., LTD
+
+bluetooth:v020F*
+ ID_VENDOR_FROM_DATABASE=Comodule GMBH
+
+bluetooth:v0210*
+ ID_VENDOR_FROM_DATABASE=ikeGPS
+
+bluetooth:v0211*
+ ID_VENDOR_FROM_DATABASE=Telink Semiconductor Co. Ltd
+
+bluetooth:v0212*
+ ID_VENDOR_FROM_DATABASE=Interplan Co., Ltd
+
+bluetooth:v0213*
+ ID_VENDOR_FROM_DATABASE=Wyler AG
+
+bluetooth:v0214*
+ ID_VENDOR_FROM_DATABASE=IK Multimedia Production srl
+
+bluetooth:v0215*
+ ID_VENDOR_FROM_DATABASE=Lukoton Experience Oy
+
+bluetooth:v0216*
+ ID_VENDOR_FROM_DATABASE=MTI Ltd
+
+bluetooth:v0217*
+ ID_VENDOR_FROM_DATABASE=Tech4home, Lda
+
+bluetooth:v0218*
+ ID_VENDOR_FROM_DATABASE=Hiotech AB
+
+bluetooth:v0219*
+ ID_VENDOR_FROM_DATABASE=DOTT Limited
+
+bluetooth:v021A*
+ ID_VENDOR_FROM_DATABASE=Blue Speck Labs, LLC
+
+bluetooth:v021B*
+ ID_VENDOR_FROM_DATABASE=Cisco Systems Inc
+
+bluetooth:v021C*
+ ID_VENDOR_FROM_DATABASE=Mobicomm Inc
+
+bluetooth:v021D*
+ ID_VENDOR_FROM_DATABASE=Edamic
+
+bluetooth:v021E*
+ ID_VENDOR_FROM_DATABASE=Goodnet Ltd
+
+bluetooth:v021F*
+ ID_VENDOR_FROM_DATABASE=Luster Leaf Products Inc
+
+bluetooth:v0220*
+ ID_VENDOR_FROM_DATABASE=Manus Machina BV
+
+bluetooth:v0221*
+ ID_VENDOR_FROM_DATABASE=Mobiquity Networks Inc
+
+bluetooth:v0222*
+ ID_VENDOR_FROM_DATABASE=Praxis Dynamics
+
+bluetooth:v0223*
+ ID_VENDOR_FROM_DATABASE=Philip Morris Products S.A.
+
+bluetooth:v0224*
+ ID_VENDOR_FROM_DATABASE=Comarch SA
+
+bluetooth:v0225*
+ ID_VENDOR_FROM_DATABASE=Nestl Nespresso S.A.
+
+bluetooth:v0226*
+ ID_VENDOR_FROM_DATABASE=Merlinia A/S
+
+bluetooth:v0227*
+ ID_VENDOR_FROM_DATABASE=LifeBEAM Technologies
+
+bluetooth:v0228*
+ ID_VENDOR_FROM_DATABASE=Twocanoes Labs, LLC
+
+bluetooth:v0229*
+ ID_VENDOR_FROM_DATABASE=Muoverti Limited
diff --git a/hwdb/20-pci-vendor-model.hwdb b/hwdb/20-pci-vendor-model.hwdb
index 6c22088873..4cc7cfd65c 100644
--- a/hwdb/20-pci-vendor-model.hwdb
+++ b/hwdb/20-pci-vendor-model.hwdb
@@ -941,6 +941,9 @@ pci:v00001000d0000005C*
pci:v00001000d0000005D*
ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader]
+pci:v00001000d0000005Dsv00001000sd00009361*
+ ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader] (MegaRAID SAS 9361-8i)
+
pci:v00001000d0000005Dsv00001028sd00001F41*
ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3108 [Invader] (PERC H830 Adapter)
@@ -995,6 +998,9 @@ pci:v00001000d0000005Fsv00001028sd00001F4C*
pci:v00001000d0000005Fsv00001028sd00001F4D*
ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3008 [Fury] (PERC H330 Embedded (for monolithic))
+pci:v00001000d0000005Fsv00001054sd0000306A*
+ ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3008 [Fury] (SAS 3004 iMR ROMB)
+
pci:v00001000d00000060*
ID_MODEL_FROM_DATABASE=MegaRAID SAS 1078
@@ -3114,25 +3120,28 @@ pci:v00001002d00004E4B*
ID_MODEL_FROM_DATABASE=R350 GL [FireGL X2 AGP Pro]
pci:v00001002d00004E50*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo]
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700]
pci:v00001002d00004E50sv00001025sd0000005A*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] (TravelMate 290)
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (TravelMate 290)
+
+pci:v00001002d00004E50sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (Extensa 3000 series laptop: ATI RV360/M11 [Mobility Radeon 9700])
pci:v00001002d00004E50sv0000103Csd0000088C*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] (NC8000 laptop)
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (NC8000 laptop)
pci:v00001002d00004E50sv0000103Csd00000890*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] (NC6000 laptop)
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (NC6000 laptop)
pci:v00001002d00004E50sv0000144Dsd0000C00C*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] (P35 notebook)
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (P35 notebook)
pci:v00001002d00004E50sv00001462sd00000311*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] (MSI M510A)
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (MSI M510A)
pci:v00001002d00004E50sv00001734sd00001055*
- ID_MODEL_FROM_DATABASE=RV350/M10 [Mobility Radeon 9600 PRO Turbo] (Amilo M1420W)
+ ID_MODEL_FROM_DATABASE=RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] (Amilo M1420W)
pci:v00001002d00004E51*
ID_MODEL_FROM_DATABASE=RV350 [Radeon 9550/9600/X1050 Series]
@@ -4235,6 +4244,12 @@ pci:v00001002d00006603*
pci:v00001002d00006604*
ID_MODEL_FROM_DATABASE=Opal XT [Radeon R7 M265]
+pci:v00001002d00006604sv0000103Csd00008006*
+ ID_MODEL_FROM_DATABASE=Opal XT [Radeon R7 M265] (FirePro M4170)
+
+pci:v00001002d00006604sv000017AAsd00003643*
+ ID_MODEL_FROM_DATABASE=Opal XT [Radeon R7 M265] (Radeon R7 A360)
+
pci:v00001002d00006605*
ID_MODEL_FROM_DATABASE=Opal PRO [Radeon R7 M260]
@@ -4251,43 +4266,52 @@ pci:v00001002d00006608*
ID_MODEL_FROM_DATABASE=Oland GL [FirePro W2100]
pci:v00001002d00006610*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250]
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X]
pci:v00001002d00006610sv00001019sd00000030*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon HD 8670)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon HD 8670)
+
+pci:v00001002d00006610sv00001028sd00000081*
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon R7 350X)
+
+pci:v00001002d00006610sv00001028sd00000083*
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon R5 340X)
pci:v00001002d00006610sv00001028sd00002120*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon R7 250)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon R7 250)
pci:v00001002d00006610sv00001028sd00002322*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon R7 250)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon R7 250)
pci:v00001002d00006610sv00001462sd00002910*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon HD 8670)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon HD 8670)
pci:v00001002d00006610sv00001462sd00002911*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon HD 8670)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon HD 8670)
pci:v00001002d00006610sv00001642sd00003C81*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon HD 8670)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon HD 8670)
pci:v00001002d00006610sv00001642sd00003C91*
- ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250] (Radeon HD 8670)
+ ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X / R7 250/350X] (Radeon HD 8670)
pci:v00001002d00006611*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240 OEM]
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 OEM]
pci:v00001002d00006611sv00001028sd0000210B*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240 OEM] (Radeon R5 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 OEM] (Radeon R5 240 OEM)
pci:v00001002d00006611sv0000174Bsd00004248*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240 OEM] (Radeon R7 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 OEM] (Radeon R7 240 OEM)
pci:v00001002d00006611sv0000174Bsd0000A240*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240 OEM] (Radeon R7 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 OEM] (Radeon R7 240 OEM)
+
+pci:v00001002d00006611sv0000174Bsd0000D340*
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 OEM] (Radeon R7 340 OEM)
pci:v00001002d00006611sv00001B0Asd000090D3*
- ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240 OEM] (Radeon R7 240 OEM)
+ ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R7 240/340 OEM] (Radeon R7 240 OEM)
pci:v00001002d00006613*
ID_MODEL_FROM_DATABASE=Oland PRO [Radeon R7 240]
@@ -4361,8 +4385,17 @@ pci:v00001002d0000665Csv00001787sd00002329*
pci:v00001002d0000665D*
ID_MODEL_FROM_DATABASE=Bonaire [Radeon R7 200 Series]
+pci:v00001002d0000665F*
+ ID_MODEL_FROM_DATABASE=Tobago PRO [Radeon R9 360]
+
pci:v00001002d00006660*
- ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M]
+ ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330]
+
+pci:v00001002d00006660sv000017AAsd00003809*
+ ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M330)
+
+pci:v00001002d00006660sv000017AAsd0000390C*
+ ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M330)
pci:v00001002d00006663*
ID_MODEL_FROM_DATABASE=Sun PRO [Radeon HD 8570A/8570M]
@@ -4376,15 +4409,15 @@ pci:v00001002d00006664*
pci:v00001002d00006665*
ID_MODEL_FROM_DATABASE=Jet PRO [Radeon R5 M230]
+pci:v00001002d00006665sv000017AAsd0000368F*
+ ID_MODEL_FROM_DATABASE=Jet PRO [Radeon R5 M230] (Radeon R5 A230)
+
pci:v00001002d00006667*
ID_MODEL_FROM_DATABASE=Jet ULT [Radeon R5 M230]
pci:v00001002d0000666F*
ID_MODEL_FROM_DATABASE=Sun LE [Radeon HD 8550M / R5 M230]
-pci:v00001002d00006670*
- ID_MODEL_FROM_DATABASE=Hainan
-
pci:v00001002d00006704*
ID_MODEL_FROM_DATABASE=Cayman PRO GL [FirePro V7900]
@@ -4439,12 +4472,6 @@ pci:v00001002d00006720sv00001558sd00007201*
pci:v00001002d00006720sv0000174Bsd0000E188*
ID_MODEL_FROM_DATABASE=Blackcomb [Radeon HD 6970M/6990M] (Radeon HD 6970M)
-pci:v00001002d00006724*
- ID_MODEL_FROM_DATABASE=Blackcomb [Mobility Radeon HD 6000 series]
-
-pci:v00001002d00006725*
- ID_MODEL_FROM_DATABASE=Blackcomb [Radeon HD 6900M Series]
-
pci:v00001002d00006738*
ID_MODEL_FROM_DATABASE=Barts XT [Radeon HD 6870]
@@ -5676,37 +5703,49 @@ pci:v00001002d00006772*
ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 7450A]
pci:v00001002d00006778*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM]
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM]
pci:v00001002d00006778sv00001019sd00000024*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 7470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 7470)
pci:v00001002d00006778sv00001019sd00000027*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470)
pci:v00001002d00006778sv00001028sd00002120*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 7470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 7470)
pci:v00001002d00006778sv00001462sd0000B491*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470)
pci:v00001002d00006778sv00001462sd0000B492*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470)
pci:v00001002d00006778sv00001462sd0000B493*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470 OEM)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470 OEM)
+
+pci:v00001002d00006778sv00001462sd0000B499*
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon R5 235 OEM)
pci:v00001002d00006778sv00001642sd00003C65*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470)
pci:v00001002d00006778sv00001642sd00003C75*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470)
pci:v00001002d00006778sv0000174Bsd00008145*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 8470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 8470)
+
+pci:v00001002d00006778sv0000174Bsd0000D145*
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon R5 235 OEM)
+
+pci:v00001002d00006778sv0000174Bsd0000D335*
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon R5 310 OEM)
pci:v00001002d00006778sv0000174Bsd0000E145*
- ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235 OEM] (Radeon HD 7470)
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon HD 7470)
+
+pci:v00001002d00006778sv000017AAsd00003694*
+ ID_MODEL_FROM_DATABASE=Caicos XT [Radeon HD 7470/8470 / R5 235/310 OEM] (Radeon R5 A220)
pci:v00001002d00006779*
ID_MODEL_FROM_DATABASE=Caicos [Radeon HD 6450/7450/8450 / R5 230 OEM]
@@ -5814,10 +5853,10 @@ pci:v00001002d00006780*
ID_MODEL_FROM_DATABASE=Tahiti XT GL [FirePro W9000]
pci:v00001002d00006784*
- ID_MODEL_FROM_DATABASE=Tahiti [ATI FirePro V (FireGL V) Graphics Adapter]
+ ID_MODEL_FROM_DATABASE=Tahiti [FirePro Series Graphics Adapter]
pci:v00001002d00006788*
- ID_MODEL_FROM_DATABASE=Tahiti [ATI FirePro V (FireGL V) Graphics Adapter]
+ ID_MODEL_FROM_DATABASE=Tahiti [FirePro Series Graphics Adapter]
pci:v00001002d0000678A*
ID_MODEL_FROM_DATABASE=Tahiti PRO GL [FirePro Series]
@@ -5846,14 +5885,8 @@ pci:v00001002d0000678Asv00001002sd00000B2A*
pci:v00001002d0000678Asv00001028sd0000030C*
ID_MODEL_FROM_DATABASE=Tahiti PRO GL [FirePro Series] (FirePro W8000)
-pci:v00001002d00006790*
- ID_MODEL_FROM_DATABASE=Tahiti
-
-pci:v00001002d00006791*
- ID_MODEL_FROM_DATABASE=Tahiti
-
-pci:v00001002d00006792*
- ID_MODEL_FROM_DATABASE=Tahiti
+pci:v00001002d0000678Asv00001028sd00000710*
+ ID_MODEL_FROM_DATABASE=Tahiti PRO GL [FirePro Series] (FirePro S9000)
pci:v00001002d00006798*
ID_MODEL_FROM_DATABASE=Tahiti XT [Radeon HD 7970/8970 OEM / R9 280X]
@@ -5966,9 +5999,24 @@ pci:v00001002d0000679F*
pci:v00001002d000067A0*
ID_MODEL_FROM_DATABASE=Hawaii XT GL [FirePro W9100]
+pci:v00001002d000067A0sv00001002sd00000335*
+ ID_MODEL_FROM_DATABASE=Hawaii XT GL [FirePro W9100] (FirePro S9150)
+
+pci:v00001002d000067A0sv00001028sd0000031F*
+ ID_MODEL_FROM_DATABASE=Hawaii XT GL [FirePro W9100] (FirePro W9100)
+
+pci:v00001002d000067A0sv00001028sd00000335*
+ ID_MODEL_FROM_DATABASE=Hawaii XT GL [FirePro W9100] (FirePro S9150)
+
pci:v00001002d000067A1*
ID_MODEL_FROM_DATABASE=Hawaii PRO GL [FirePro W8100]
+pci:v00001002d000067A1sv00001002sd00000335*
+ ID_MODEL_FROM_DATABASE=Hawaii PRO GL [FirePro W8100] (FirePro S9100)
+
+pci:v00001002d000067A1sv00001028sd00000335*
+ ID_MODEL_FROM_DATABASE=Hawaii PRO GL [FirePro W8100] (FirePro S9100)
+
pci:v00001002d000067A2*
ID_MODEL_FROM_DATABASE=Hawaii GL
@@ -5984,6 +6032,63 @@ pci:v00001002d000067AA*
pci:v00001002d000067B0*
ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X]
+pci:v00001002d000067B0sv00001043sd0000046A*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X DirectCU II)
+
+pci:v00001002d000067B0sv00001043sd0000046C*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X DirectCU II OC)
+
+pci:v00001002d000067B0sv00001043sd00000474*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Matrix R9 290X Platinum)
+
+pci:v00001002d000067B0sv00001043sd00000476*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (ARES III)
+
+pci:v00001002d000067B0sv00001458sd0000227C*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X OC)
+
+pci:v00001002d000067B0sv00001458sd00002281*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X OC)
+
+pci:v00001002d000067B0sv00001458sd0000228C*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X)
+
+pci:v00001002d000067B0sv00001458sd0000228D*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X OC)
+
+pci:v00001002d000067B0sv00001458sd00002290*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X WindForce 3X)
+
+pci:v00001002d000067B0sv00001462sd00003070*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Lightning)
+
+pci:v00001002d000067B0sv00001462sd00003071*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Lightning)
+
+pci:v00001002d000067B0sv00001462sd00003072*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Lightning LE)
+
+pci:v00001002d000067B0sv00001462sd00003080*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Gaming)
+
+pci:v00001002d000067B0sv00001462sd00003082*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Gaming OC)
+
+pci:v00001002d000067B0sv0000148Csd00002347*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Devil 13 Dual Core R9 290X)
+
+pci:v00001002d000067B0sv00001682sd00009290*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Double Dissipation R9 290X)
+
+pci:v00001002d000067B0sv0000174Bsd0000E282*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (Vapor-X R9 290X Tri-X OC)
+
+pci:v00001002d000067B0sv0000174Bsd0000E285*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X Tri-X OC)
+
+pci:v00001002d000067B0sv00001787sd00002020*
+ ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X] (R9 290X IceQ X² Turbo)
+
pci:v00001002d000067B1*
ID_MODEL_FROM_DATABASE=Hawaii PRO [Radeon R9 290]
@@ -6042,7 +6147,10 @@ pci:v00001002d00006810*
ID_MODEL_FROM_DATABASE=Curacao XT [Radeon R9 270X]
pci:v00001002d00006811*
- ID_MODEL_FROM_DATABASE=Curacao PRO [Radeon R9 270]
+ ID_MODEL_FROM_DATABASE=Curacao PRO [Radeon R9 270/370]
+
+pci:v00001002d00006811sv00001028sd00000B00*
+ ID_MODEL_FROM_DATABASE=Curacao PRO [Radeon R9 270/370] (Trinidad PRO [Radeon R9 370])
pci:v00001002d00006816*
ID_MODEL_FROM_DATABASE=Pitcairn
@@ -6066,25 +6174,28 @@ pci:v00001002d00006819sv0000174Bsd0000E221*
ID_MODEL_FROM_DATABASE=Pitcairn PRO [Radeon HD 7850] (Radeon HD 7850 2GB GDDR5 DVI-I/DVI-D/HDMI/DP)
pci:v00001002d00006820*
- ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X]
+ ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X/M375X]
pci:v00001002d00006820sv0000103Csd00001851*
- ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X] (Radeon HD 7750M)
+ ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X/M375X] (Radeon HD 7750M)
+
+pci:v00001002d00006820sv000017AAsd00003643*
+ ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X/M375X] (Radeon R9 A375)
pci:v00001002d00006820sv000017AAsd00003801*
- ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X] (Radeon R9 M275)
+ ID_MODEL_FROM_DATABASE=Venus XTX [Radeon HD 8890M / R9 M275X/M375X] (Radeon R9 M275)
pci:v00001002d00006821*
- ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X]
+ ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X/M370X]
pci:v00001002d00006821sv00001002sd0000031E*
- ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X] (FirePro SX4000)
+ ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X/M370X] (FirePro SX4000)
pci:v00001002d00006821sv00001028sd000005CC*
- ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X] (FirePro M5100)
+ ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X/M370X] (FirePro M5100)
pci:v00001002d00006821sv00001028sd000015CC*
- ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X] (FirePro M5100)
+ ID_MODEL_FROM_DATABASE=Venus XT [Radeon HD 8870M / R9 M270X/M370X] (FirePro M5100)
pci:v00001002d00006822*
ID_MODEL_FROM_DATABASE=Venus PRO [Radeon E8860]
@@ -6164,15 +6275,6 @@ pci:v00001002d00006837sv0000148Csd00008730*
pci:v00001002d00006837sv00001787sd00003000*
ID_MODEL_FROM_DATABASE=Cape Verde LE [Radeon HD 7730/8730] (Radeon HD 6570)
-pci:v00001002d00006838*
- ID_MODEL_FROM_DATABASE=Cape Verde
-
-pci:v00001002d00006839*
- ID_MODEL_FROM_DATABASE=Cape Verde
-
-pci:v00001002d0000683B*
- ID_MODEL_FROM_DATABASE=Cape Verde [Radeon HD 7700 Series]
-
pci:v00001002d0000683D*
ID_MODEL_FROM_DATABASE=Cape Verde XT [Radeon HD 7770/8760 / R7 250X]
@@ -6195,7 +6297,16 @@ pci:v00001002d0000683Dsv0000174Bsd00008304*
ID_MODEL_FROM_DATABASE=Cape Verde XT [Radeon HD 7770/8760 / R7 250X] (Radeon HD 8760 OEM)
pci:v00001002d0000683F*
- ID_MODEL_FROM_DATABASE=Cape Verde PRO [Radeon HD 7750 / R7 250E]
+ ID_MODEL_FROM_DATABASE=Cape Verde PRO [Radeon HD 7750/8740 / R7 250E]
+
+pci:v00001002d0000683Fsv00001462sd00002790*
+ ID_MODEL_FROM_DATABASE=Cape Verde PRO [Radeon HD 7750/8740 / R7 250E] (Radeon HD 8740)
+
+pci:v00001002d0000683Fsv00001462sd00002791*
+ ID_MODEL_FROM_DATABASE=Cape Verde PRO [Radeon HD 7750/8740 / R7 250E] (Radeon HD 8740)
+
+pci:v00001002d0000683Fsv00001642sd00003B97*
+ ID_MODEL_FROM_DATABASE=Cape Verde PRO [Radeon HD 7750/8740 / R7 250E] (Radeon HD 8740)
pci:v00001002d00006840*
ID_MODEL_FROM_DATABASE=Thames [Radeon HD 7500M/7600M Series]
@@ -7925,12 +8036,12 @@ pci:v00001002d00006900sv00001179sd0000F934*
pci:v00001002d00006901*
ID_MODEL_FROM_DATABASE=Topaz PRO [Radeon R5 M255]
-pci:v00001002d00006920*
- ID_MODEL_FROM_DATABASE=Tonga
-
pci:v00001002d00006921*
ID_MODEL_FROM_DATABASE=Amethyst XT [Radeon R9 M295X]
+pci:v00001002d00006929*
+ ID_MODEL_FROM_DATABASE=Tonga PRO GL [FirePro Series]
+
pci:v00001002d0000692B*
ID_MODEL_FROM_DATABASE=Tonga PRO GL [FirePro W7100]
@@ -9023,24 +9134,9 @@ pci:v00001002d00009838*
pci:v00001002d00009839*
ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8180]
-pci:v00001002d0000983A*
- ID_MODEL_FROM_DATABASE=Kabini
-
-pci:v00001002d0000983B*
- ID_MODEL_FROM_DATABASE=Kabini
-
-pci:v00001002d0000983C*
- ID_MODEL_FROM_DATABASE=Kabini
-
pci:v00001002d0000983D*
ID_MODEL_FROM_DATABASE=Temash [Radeon HD 8250/8280G]
-pci:v00001002d0000983E*
- ID_MODEL_FROM_DATABASE=Kabini
-
-pci:v00001002d0000983F*
- ID_MODEL_FROM_DATABASE=Kabini
-
pci:v00001002d00009840*
ID_MODEL_FROM_DATABASE=Kabini HDMI/DP Audio
@@ -9092,6 +9188,9 @@ pci:v00001002d0000985E*
pci:v00001002d0000985F*
ID_MODEL_FROM_DATABASE=Mullins
+pci:v00001002d00009874*
+ ID_MODEL_FROM_DATABASE=Carrizo
+
pci:v00001002d00009900*
ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7660G]
@@ -10272,10 +10371,10 @@ pci:v00001014d000000A6*
ID_MODEL_FROM_DATABASE=ATM 155MBPS MM Controller (1410a600)
pci:v00001014d000000B7*
- ID_MODEL_FROM_DATABASE=256-bit Graphics Rasterizer [FireGL1]
+ ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter
pci:v00001014d000000B7sv00001092sd000000B8*
- ID_MODEL_FROM_DATABASE=256-bit Graphics Rasterizer [FireGL1] (FireGL1 AGP 32Mb)
+ ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter (FireGL1 AGP 32Mb)
pci:v00001014d000000B8*
ID_MODEL_FROM_DATABASE=GXT2000P Graphics Adapter
@@ -10325,6 +10424,15 @@ pci:v00001014d00000170*
pci:v00001014d00000170sv00001092sd00000172*
ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL2)
+pci:v00001014d00000170sv00001092sd00000173*
+ ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL3)
+
+pci:v00001014d00000170sv00001092sd00000174*
+ ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL4)
+
+pci:v00001014d00000170sv00001092sd00000184*
+ ID_MODEL_FROM_DATABASE=GXT6000P Graphics Adapter (Fire GL4s)
+
pci:v00001014d0000017D*
ID_MODEL_FROM_DATABASE=GXT300P Graphics Adapter
@@ -12011,6 +12119,9 @@ pci:v0000102Bd0000051E*
pci:v0000102Bd0000051F*
ID_MODEL_FROM_DATABASE=MGA 2164W [Millennium II] AGP
+pci:v0000102Bd0000051Fsv0000102Bsd00002100*
+ ID_MODEL_FROM_DATABASE=MGA 2164W [Millennium II] AGP (MGA-2164WA [Millennium II A])
+
pci:v0000102Bd00000520*
ID_MODEL_FROM_DATABASE=MGA G200
@@ -12132,7 +12243,7 @@ pci:v0000102Bd00000521sv0000102Bsd0000FF02*
ID_MODEL_FROM_DATABASE=MGA G200 AGP (Mystique G200 AGP)
pci:v0000102Bd00000521sv0000102Bsd0000FF03*
- ID_MODEL_FROM_DATABASE=MGA G200 AGP (Millennium G200 AGP)
+ ID_MODEL_FROM_DATABASE=MGA G200 AGP (Millennium G200A AGP)
pci:v0000102Bd00000521sv0000102Bsd0000FF04*
ID_MODEL_FROM_DATABASE=MGA G200 AGP (Marvel G200 AGP)
@@ -13193,6 +13304,9 @@ pci:v00001033d00000194sv00001028sd000004DA*
pci:v00001033d00000194sv00001043sd00008413*
ID_MODEL_FROM_DATABASE=uPD720200 USB 3.0 Host Controller (P8P67 Deluxe Motherboard)
+pci:v00001033d00000194sv0000104Dsd0000907A*
+ ID_MODEL_FROM_DATABASE=uPD720200 USB 3.0 Host Controller (Vaio VPCF1)
+
pci:v00001033d00000194sv00001AF4sd00001100*
ID_MODEL_FROM_DATABASE=uPD720200 USB 3.0 Host Controller (QEMU Virtual Machine)
@@ -13238,6 +13352,9 @@ pci:v00001039d00000003*
pci:v00001039d00000004*
ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge
+pci:v00001039d00000004sv00001039sd00000000*
+ ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge (PCIe x16 port)
+
pci:v00001039d00000006*
ID_MODEL_FROM_DATABASE=85C501/2/3
@@ -13250,6 +13367,9 @@ pci:v00001039d00000009*
pci:v00001039d0000000A*
ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge
+pci:v00001039d0000000Asv00001039sd00000000*
+ ID_MODEL_FROM_DATABASE=PCI-to-PCI bridge (PCIe x1 port)
+
pci:v00001039d00000016*
ID_MODEL_FROM_DATABASE=SiS961/2/3 SMBus controller
@@ -13280,6 +13400,9 @@ pci:v00001039d00000190*
pci:v00001039d00000191*
ID_MODEL_FROM_DATABASE=191 Gigabit Ethernet Adapter
+pci:v00001039d00000191sv00001043sd00008139*
+ ID_MODEL_FROM_DATABASE=191 Gigabit Ethernet Adapter (P5SD2-FM/S mainboard)
+
pci:v00001039d00000200*
ID_MODEL_FROM_DATABASE=5597/5598/6326 VGA
@@ -13419,7 +13542,7 @@ pci:v00001039d00000900sv00001019sd00000A14*
ID_MODEL_FROM_DATABASE=SiS900 PCI Fast Ethernet (K7S5A motherboard)
pci:v00001039d00000900sv00001039sd00000900*
- ID_MODEL_FROM_DATABASE=SiS900 PCI Fast Ethernet (SiS900 10/100 Ethernet Adapter onboard [Asus P4SC-EA])
+ ID_MODEL_FROM_DATABASE=SiS900 PCI Fast Ethernet (SiS900 10/100 Ethernet Adapter onboard)
pci:v00001039d00000900sv00001043sd00008035*
ID_MODEL_FROM_DATABASE=SiS900 PCI Fast Ethernet (CUSI-FX motherboard)
@@ -13457,9 +13580,15 @@ pci:v00001039d00001180*
pci:v00001039d00001182*
ID_MODEL_FROM_DATABASE=SATA Controller / RAID mode
+pci:v00001039d00001182sv00001039sd00000180*
+ ID_MODEL_FROM_DATABASE=SATA Controller / RAID mode (SiS 966 4-port SATA controller)
+
pci:v00001039d00001183*
ID_MODEL_FROM_DATABASE=SATA Controller / IDE mode
+pci:v00001039d00001183sv00001039sd00000180*
+ ID_MODEL_FROM_DATABASE=SATA Controller / IDE mode (SiS 966 4-port SATA controller)
+
pci:v00001039d00001184*
ID_MODEL_FROM_DATABASE=AHCI Controller / RAID mode
@@ -13659,7 +13788,7 @@ pci:v00001039d00007012sv00001043sd0000818F*
ID_MODEL_FROM_DATABASE=SiS7012 AC'97 Sound Controller (A8S-X Motherboard)
pci:v00001039d00007012sv000013F6sd00000300*
- ID_MODEL_FROM_DATABASE=SiS7012 AC'97 Sound Controller (CMI9739(A) on ECS K7SOM+ motherboard)
+ ID_MODEL_FROM_DATABASE=SiS7012 AC'97 Sound Controller (CMI9739(A) on ECS K7S series motherboard)
pci:v00001039d00007012sv00001462sd00005850*
ID_MODEL_FROM_DATABASE=SiS7012 AC'97 Sound Controller (MSI 648 Max (MS-6585))
@@ -13766,6 +13895,9 @@ pci:v00001039d00007019*
pci:v00001039d00007502*
ID_MODEL_FROM_DATABASE=Azalia Audio Controller
+pci:v00001039d00007502sv00001043sd000081A1*
+ ID_MODEL_FROM_DATABASE=Azalia Audio Controller (P5SD2-FM/S mainboard)
+
pci:v0000103A*
ID_VENDOR_FROM_DATABASE=Seiko Epson Corporation
@@ -14879,6 +15011,9 @@ pci:v0000104Cd0000802Esv00001028sd0000018D*
pci:v0000104Cd00008031*
ID_MODEL_FROM_DATABASE=PCIxx21/x515 Cardbus Controller
+pci:v0000104Cd00008031sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=PCIxx21/x515 Cardbus Controller (Extensa 3000 series laptop)
+
pci:v0000104Cd00008031sv00001025sd00000080*
ID_MODEL_FROM_DATABASE=PCIxx21/x515 Cardbus Controller (Aspire 5024WLMi)
@@ -14894,6 +15029,9 @@ pci:v0000104Cd00008031sv0000103Csd0000308B*
pci:v0000104Cd00008032*
ID_MODEL_FROM_DATABASE=OHCI Compliant IEEE 1394 Host Controller
+pci:v0000104Cd00008032sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=OHCI Compliant IEEE 1394 Host Controller (Extensa 3000 series laptop)
+
pci:v0000104Cd00008032sv00001025sd00000080*
ID_MODEL_FROM_DATABASE=OHCI Compliant IEEE 1394 Host Controller (Aspire 5024WLMi)
@@ -14909,6 +15047,9 @@ pci:v0000104Cd00008032sv0000103Csd0000308B*
pci:v0000104Cd00008033*
ID_MODEL_FROM_DATABASE=PCIxx21 Integrated FlashMedia Controller
+pci:v0000104Cd00008033sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=PCIxx21 Integrated FlashMedia Controller (Extensa 3000 series laptop)
+
pci:v0000104Cd00008033sv00001025sd00000080*
ID_MODEL_FROM_DATABASE=PCIxx21 Integrated FlashMedia Controller (Aspire 5024WLMi)
@@ -16952,6 +17093,9 @@ pci:v00001077d00008020sv00001077sd0000020F*
pci:v00001077d00008020sv00001077sd00000210*
ID_MODEL_FROM_DATABASE=cLOM8214 1/10GbE Controller (QME8242-k 10GbE Dual Port Mezzanine Card)
+pci:v00001077d00008020sv00001077sd00000233*
+ ID_MODEL_FROM_DATABASE=cLOM8214 1/10GbE Controller (QME8262-k 10GbE Dual Port Mezzanine Card)
+
pci:v00001077d00008021*
ID_MODEL_FROM_DATABASE=8200 Series 10GbE Converged Network Adapter (FCoE)
@@ -23270,6 +23414,9 @@ pci:v000010DEd000000CC*
pci:v000010DEd000000CD*
ID_MODEL_FROM_DATABASE=NV42GL [Quadro FX 3450/4000 SDI]
+pci:v000010DEd000000CDsv000010DEsd0000029B*
+ ID_MODEL_FROM_DATABASE=NV42GL [Quadro FX 3450/4000 SDI] (Quadro FX 3450)
+
pci:v000010DEd000000CE*
ID_MODEL_FROM_DATABASE=NV41GL [Quadro FX 1400]
@@ -24083,6 +24230,12 @@ pci:v000010DEd000001D2*
pci:v000010DEd000001D3*
ID_MODEL_FROM_DATABASE=G72 [GeForce 7200 GS / 7300 SE]
+pci:v000010DEd000001D3sv00001043sd00008203*
+ ID_MODEL_FROM_DATABASE=G72 [GeForce 7200 GS / 7300 SE] (EN7300SE)
+
+pci:v000010DEd000001D3sv00001043sd00008250*
+ ID_MODEL_FROM_DATABASE=G72 [GeForce 7200 GS / 7300 SE] (EN7200GS)
+
pci:v000010DEd000001D5*
ID_MODEL_FROM_DATABASE=G72
@@ -25964,14 +26117,20 @@ pci:v000010DEd0000056A*
pci:v000010DEd0000056Asv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 [nForce 630i] USB 2.0 Controller (EHCI) (MCP73PVT-SM)
+pci:v000010DEd0000056Asv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 [nForce 630i] USB 2.0 Controller (EHCI) (I-N73V motherboard)
+
pci:v000010DEd0000056C*
- ID_MODEL_FROM_DATABASE=MCP73 IDE
+ ID_MODEL_FROM_DATABASE=MCP73 IDE Controller
pci:v000010DEd0000056Csv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=MCP73 IDE (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=MCP73 IDE Controller (MCP73PVT-SM)
+
+pci:v000010DEd0000056Csv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 IDE Controller (I-N73V motherboard)
pci:v000010DEd0000056Csv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=MCP73 IDE (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=MCP73 IDE Controller (JW-IN7150-HD)
pci:v000010DEd0000056D*
ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge
@@ -25979,12 +26138,18 @@ pci:v000010DEd0000056D*
pci:v000010DEd0000056Dsv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge (MCP73PVT-SM)
+pci:v000010DEd0000056Dsv000010DEsd0000CB73*
+ ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge (MCP73 PCIe x1 port)
+
pci:v000010DEd0000056E*
ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge
pci:v000010DEd0000056Esv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge (MCP73PVT-SM)
+pci:v000010DEd0000056Esv000010DEsd00000000*
+ ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge (MCP73 PCIe x16 port)
+
pci:v000010DEd0000056F*
ID_MODEL_FROM_DATABASE=MCP73 PCI Express bridge
@@ -26798,6 +26963,12 @@ pci:v000010DEd000007C1sv00001019sd0000297A*
pci:v000010DEd000007C2*
ID_MODEL_FROM_DATABASE=MCP73 Host Bridge
+pci:v000010DEd000007C3*
+ ID_MODEL_FROM_DATABASE=MCP73 Host Bridge
+
+pci:v000010DEd000007C3sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 Host Bridge (I-N73V motherboard)
+
pci:v000010DEd000007C5*
ID_MODEL_FROM_DATABASE=MCP73 Host Bridge
@@ -26807,89 +26978,119 @@ pci:v000010DEd000007C8*
pci:v000010DEd000007C8sv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 Memory Controller (MCP73PVT-SM)
+pci:v000010DEd000007C8sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 Memory Controller (I-N73V motherboard)
+
pci:v000010DEd000007C8sv00001AFAsd00007150*
ID_MODEL_FROM_DATABASE=MCP73 Memory Controller (JW-IN7150-HD)
pci:v000010DEd000007CB*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007CBsv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007CBsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007CBsv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007CD*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007CDsv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007CDsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007CDsv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007CE*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007CEsv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007CEsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007CEsv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007CF*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007CFsv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007CFsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007CFsv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007D0*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007D0sv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007D0sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007D0sv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007D1*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007D1sv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007D1sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007D1sv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007D2*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007D2sv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007D2sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007D2sv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007D3*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007D3sv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007D3sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007D3sv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007D6*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller
pci:v000010DEd000007D6sv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (MCP73PVT-SM)
+
+pci:v000010DEd000007D6sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (I-N73V motherboard)
pci:v000010DEd000007D6sv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=nForce 630i memory controller (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=nForce 610i/630i memory controller (JW-IN7150-HD)
pci:v000010DEd000007D7*
ID_MODEL_FROM_DATABASE=MCP73 LPC Bridge
@@ -26897,6 +27098,9 @@ pci:v000010DEd000007D7*
pci:v000010DEd000007D7sv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 LPC Bridge (MCP73PVT-SM)
+pci:v000010DEd000007D7sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 LPC Bridge (I-N73V motherboard)
+
pci:v000010DEd000007D7sv00001AFAsd00007150*
ID_MODEL_FROM_DATABASE=MCP73 LPC Bridge (JW-IN7150-HD)
@@ -26906,6 +27110,9 @@ pci:v000010DEd000007D8*
pci:v000010DEd000007D8sv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 SMBus (MCP73PVT-SM)
+pci:v000010DEd000007D8sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 SMBus (I-N73V motherboard)
+
pci:v000010DEd000007D8sv00001AFAsd00007150*
ID_MODEL_FROM_DATABASE=MCP73 SMBus (JW-IN7150-HD)
@@ -26915,6 +27122,9 @@ pci:v000010DEd000007D9*
pci:v000010DEd000007D9sv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=MCP73 Memory Controller (MCP73PVT-SM)
+pci:v000010DEd000007D9sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 Memory Controller (I-N73V motherboard)
+
pci:v000010DEd000007D9sv00001AFAsd00007150*
ID_MODEL_FROM_DATABASE=MCP73 Memory Controller (JW-IN7150-HD)
@@ -26927,6 +27137,9 @@ pci:v000010DEd000007DAsv00001AFAsd00007150*
pci:v000010DEd000007DC*
ID_MODEL_FROM_DATABASE=MCP73 Ethernet
+pci:v000010DEd000007DCsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 Ethernet (I-N73V motherboard)
+
pci:v000010DEd000007DD*
ID_MODEL_FROM_DATABASE=MCP73 Ethernet
@@ -26954,11 +27167,17 @@ pci:v000010DEd000007E2*
pci:v000010DEd000007E3*
ID_MODEL_FROM_DATABASE=C73 [GeForce 7050 / nForce 610i]
+pci:v000010DEd000007E3sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=C73 [GeForce 7050 / nForce 610i] (I-N73V motherboard)
+
pci:v000010DEd000007E5*
ID_MODEL_FROM_DATABASE=C73 [GeForce 7100 / nForce 620i]
pci:v000010DEd000007F0*
- ID_MODEL_FROM_DATABASE=MCP73 IDE
+ ID_MODEL_FROM_DATABASE=MCP73 SATA Controller (IDE mode)
+
+pci:v000010DEd000007F0sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 SATA Controller (IDE mode) (I-N73V motherboard)
pci:v000010DEd000007F4*
ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i SATA
@@ -26966,9 +27185,15 @@ pci:v000010DEd000007F4*
pci:v000010DEd000007F4sv00001019sd0000297A*
ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i SATA (MCP73PVT-SM)
+pci:v000010DEd000007F4sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i SATA (I-N73V motherboard)
+
pci:v000010DEd000007F8*
ID_MODEL_FROM_DATABASE=MCP73 SATA RAID Controller
+pci:v000010DEd000007F8sv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 SATA RAID Controller (I-N73V motherboard)
+
pci:v000010DEd000007FC*
ID_MODEL_FROM_DATABASE=MCP73 High Definition Audio
@@ -26978,14 +27203,20 @@ pci:v000010DEd000007FCsv00001019sd0000297A*
pci:v000010DEd000007FCsv000010DEsd000007FC*
ID_MODEL_FROM_DATABASE=MCP73 High Definition Audio
+pci:v000010DEd000007FCsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 High Definition Audio (I-N73V motherboard)
+
pci:v000010DEd000007FE*
- ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i USB
+ ID_MODEL_FROM_DATABASE=MCP73 OHCI USB 1.1 Controller
pci:v000010DEd000007FEsv00001019sd0000297A*
- ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i USB (MCP73PVT-SM)
+ ID_MODEL_FROM_DATABASE=MCP73 OHCI USB 1.1 Controller (MCP73PVT-SM)
+
+pci:v000010DEd000007FEsv0000147Bsd00001C3E*
+ ID_MODEL_FROM_DATABASE=MCP73 OHCI USB 1.1 Controller (I-N73V motherboard)
pci:v000010DEd000007FEsv00001AFAsd00007150*
- ID_MODEL_FROM_DATABASE=GeForce 7100/nForce 630i USB (JW-IN7150-HD)
+ ID_MODEL_FROM_DATABASE=MCP73 OHCI USB 1.1 Controller (JW-IN7150-HD)
pci:v000010DEd00000840*
ID_MODEL_FROM_DATABASE=C77 [GeForce 8200M]
@@ -27233,6 +27464,9 @@ pci:v000010DEd00000A65*
pci:v000010DEd00000A65sv00001043sd00008334*
ID_MODEL_FROM_DATABASE=GT218 [GeForce 210] (EN210 SILENT)
+pci:v000010DEd00000A65sv00001462sd00008094*
+ ID_MODEL_FROM_DATABASE=GT218 [GeForce 210] (N210 [Geforce 210] PCIe graphics adapter)
+
pci:v000010DEd00000A66*
ID_MODEL_FROM_DATABASE=GT218 [GeForce 310]
@@ -27692,6 +27926,9 @@ pci:v000010DEd00000BE3sv00001028sd0000040B*
pci:v000010DEd00000BE3sv000010DEsd0000066D*
ID_MODEL_FROM_DATABASE=High Definition Audio Controller (G98 [GeForce 8400GS])
+pci:v000010DEd00000BE3sv00001462sd00008094*
+ ID_MODEL_FROM_DATABASE=High Definition Audio Controller (N210 [Geforce 210] PCIe graphics adapter)
+
pci:v000010DEd00000BE4*
ID_MODEL_FROM_DATABASE=High Definition Audio Controller
@@ -28088,6 +28325,9 @@ pci:v000010DEd00000FC6sv00001043sd00008428*
pci:v000010DEd00000FC8*
ID_MODEL_FROM_DATABASE=GK107 [GeForce GT 740]
+pci:v000010DEd00000FC9*
+ ID_MODEL_FROM_DATABASE=GK107 [GeForce GT 730]
+
pci:v000010DEd00000FCD*
ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 755M]
@@ -28187,6 +28427,12 @@ pci:v000010DEd00000FE9*
pci:v000010DEd00000FEA*
ID_MODEL_FROM_DATABASE=GK107M [GeForce GT 755M Mac Edition]
+pci:v000010DEd00000FEC*
+ ID_MODEL_FROM_DATABASE=GK107M [GeForce 710A]
+
+pci:v000010DEd00000FED*
+ ID_MODEL_FROM_DATABASE=GK107M [GeForce 820M]
+
pci:v000010DEd00000FEF*
ID_MODEL_FROM_DATABASE=GK107GL [GRID K340]
@@ -28257,28 +28503,28 @@ pci:v000010DEd00001004sv00003842sd00001788*
ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX 780] (GK110B [GeForce GTX 780 Dual Classified w/ ACX Cooler])
pci:v000010DEd00001005*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan]
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN]
pci:v000010DEd00001005sv00001043sd00008451*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GTXTITAN-6GD5)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GTXTITAN-6GD5)
pci:v000010DEd00001005sv000010DEsd00001035*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GeForce GTX Titan)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GeForce GTX Titan)
pci:v000010DEd00001005sv00003842sd00002790*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GeForce GTX Titan)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GeForce GTX Titan)
pci:v000010DEd00001005sv00003842sd00002791*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GeForce GTX Titan SC)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GeForce GTX Titan SC)
pci:v000010DEd00001005sv00003842sd00002793*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GeForce GTX Titan SC Signature)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GeForce GTX Titan SC Signature)
pci:v000010DEd00001005sv00003842sd00002794*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GeForce GTX Titan SC Hydro Copper)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GeForce GTX Titan SC Hydro Copper)
pci:v000010DEd00001005sv00003842sd00002795*
- ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX Titan] (GeForce GTX Titan SC Hydro Copper Signature)
+ ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX TITAN] (GeForce GTX Titan SC Hydro Copper Signature)
pci:v000010DEd00001007*
ID_MODEL_FROM_DATABASE=GK110 [GeForce GTX 780 Rev. 2]
@@ -28290,7 +28536,7 @@ pci:v000010DEd0000100A*
ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX 780 Ti]
pci:v000010DEd0000100C*
- ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX Titan Black]
+ ID_MODEL_FROM_DATABASE=GK110B [GeForce GTX TITAN Black]
pci:v000010DEd0000101E*
ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20X]
@@ -28542,913 +28788,934 @@ pci:v000010DEd000010D8*
ID_MODEL_FROM_DATABASE=GT218 [NVS 300]
pci:v000010DEd00001140*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M]
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M]
pci:v000010DEd00001140sv00001019sd0000999F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000600*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000606*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd0000064A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd0000064C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd0000067A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000680*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000686*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000689*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000068B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000068D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000068E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000691*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000692*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000694*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000702*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000719*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000725*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000728*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd0000072B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd0000072E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000732*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001025sd00000763*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000773*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000774*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000776*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd0000077A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000077B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000077C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000077D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000077E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd0000077F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000781*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000798*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000799*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd0000079B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd0000079C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000807*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000821*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000823*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000830*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000833*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd00000837*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001025sd0000083E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000841*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001025sd00000854*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000855*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000856*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000857*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000858*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000868*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000869*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 810M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M)
pci:v000010DEd00001140sv00001025sd00000873*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000878*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000087B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000087C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 810M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M)
pci:v000010DEd00001140sv00001025sd00000881*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000088A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000089B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000090F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000921*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000092E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 810M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M)
pci:v000010DEd00001140sv00001025sd0000092F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000093A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000093C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd0000093F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000941*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000945*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000954*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001025sd00000965*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd0000054D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd0000054E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd00000554*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001028sd00000557*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001028sd00000562*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd00000565*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd00000568*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd00000590*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd00000592*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd00000594*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd00000595*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd000005A2*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd000005B1*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd000005B3*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 625M)
pci:v000010DEd00001140sv00001028sd000005DA*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd000005DE*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001028sd000005E0*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001028sd000005E8*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv00001028sd000005F4*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001028sd0000060F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001028sd0000064E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd00000652*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd00000653*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd00000655*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd0000065E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd00000662*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001028sd0000068D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000103Csd000018EF*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000103Csd000018F9*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000103Csd000018FB*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000103Csd000018FD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000103Csd000018FF*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000103Csd00002335*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000103Csd00002337*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000103Csd00002AEF*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A)
pci:v000010DEd00001140sv0000103Csd00002AF9*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710A)
pci:v000010DEd00001140sv00001043sd000010DD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv00001043sd000010ED*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv00001043sd000011FD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd0000124D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd0000126D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd0000131D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd000013FD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd000014C7*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd00001507*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001043sd000015AD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd000015ED*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000160D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000163D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000166D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd000016CD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd000016DD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000170D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000176D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000178D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000179D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd000017DD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd00002132*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001043sd00002136*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv00001043sd000021BA*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd000021FA*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd0000220A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd0000221A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd0000223A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M)
pci:v000010DEd00001140sv00001043sd0000224A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M)
pci:v000010DEd00001140sv00001043sd0000227A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000228A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000232A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000233A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000236A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000238A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd00008595*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd000085EA*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd000085EB*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd000085EC*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd000085EE*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001043sd000085F3*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000860E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000861A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000861B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd00008628*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd00008643*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd0000864C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001043sd00008652*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000105Bsd00000DAC*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv0000105Bsd00000DAD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv0000105Bsd00000EF3*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001072sd0000152D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000010CFsd000017F5*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001179sd0000FA01*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA02*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA03*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA05*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA11*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA13*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA18*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA19*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA21*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA23*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA2A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA32*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA33*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA36*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA38*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA42*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA43*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA45*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA47*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA49*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA58*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA59*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA88*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001179sd0000FA89*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000144Dsd0000B092*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv0000144Dsd0000C0D5*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000144Dsd0000C0D7*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv0000144Dsd0000C0E2*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv0000144Dsd0000C0E3*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv0000144Dsd0000C0E4*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv0000144Dsd0000C10D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000144Dsd0000C652*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv0000144Dsd0000C709*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000144Dsd0000C711*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000144Dsd0000C736*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000144Dsd0000C737*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000144Dsd0000C745*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000144Dsd0000C750*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001462sd000010B8*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 710M)
pci:v000010DEd00001140sv00001462sd000010E9*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001462sd00001116*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001462sd0000AA33*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
pci:v000010DEd00001140sv00001462sd0000AAA2*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001462sd0000AAA3*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001462sd0000ACB2*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001462sd0000ACC1*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001462sd0000AE61*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
pci:v000010DEd00001140sv00001462sd0000AE65*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001462sd0000AE6A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001462sd0000AE71*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000014C0sd00000083*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000152Dsd00000926*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 620M)
pci:v000010DEd00001140sv0000152Dsd00000982*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000152Dsd00000983*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000152Dsd00001005*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 820M)
pci:v000010DEd00001140sv0000152Dsd00001012*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000152Dsd00001019*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000152Dsd00001030*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M)
pci:v000010DEd00001140sv0000152Dsd00001055*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv0000152Dsd00001067*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv0000152Dsd00001072*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv0000152Dsd00001086*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv0000152Dsd00001092*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00002200*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (NVS 5200M)
pci:v000010DEd00001140sv000017AAsd00002213*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00002220*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd0000309C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720A)
pci:v000010DEd00001140sv000017AAsd000030B4*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+
+pci:v000010DEd00001140sv000017AAsd000030B7*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720A)
+
+pci:v000010DEd00001140sv000017AAsd0000361B*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+
+pci:v000010DEd00001140sv000017AAsd0000361C*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd00003656*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv000017AAsd0000365A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
pci:v000010DEd00001140sv000017AAsd0000365E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
+
+pci:v000010DEd00001140sv000017AAsd00003661*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd0000366C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
pci:v000010DEd00001140sv000017AAsd00003685*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
pci:v000010DEd00001140sv000017AAsd00003686*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 800M)
pci:v000010DEd00001140sv000017AAsd00003687*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705A)
pci:v000010DEd00001140sv000017AAsd00003696*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd0000369B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd0000369C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd0000369D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd0000369E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd000036A9*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+
+pci:v000010DEd00001140sv000017AAsd000036AF*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+
+pci:v000010DEd00001140sv000017AAsd000036B0*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
+
+pci:v000010DEd00001140sv000017AAsd000036B6*
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820A)
pci:v000010DEd00001140sv000017AAsd00003800*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003801*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003802*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003803*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003804*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003806*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003808*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd0000380D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd0000380E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd0000380F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003811*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003812*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003813*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003816*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003818*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd0000381A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd0000381C*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003901*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M / GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M / GT 620M)
pci:v000010DEd00001140sv000017AAsd00003902*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd00003903*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M/710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M/710M)
pci:v000010DEd00001140sv000017AAsd00003904*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M/625M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M/625M)
pci:v000010DEd00001140sv000017AAsd00003905*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003907*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003910*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
pci:v000010DEd00001140sv000017AAsd00003912*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 720M)
pci:v000010DEd00001140sv000017AAsd00003913*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003915*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00003977*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00003983*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M)
pci:v000010DEd00001140sv000017AAsd00005001*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 610M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 610M)
pci:v000010DEd00001140sv000017AAsd00005003*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00005005*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
pci:v000010DEd00001140sv000017AAsd0000500D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv000017AAsd00005014*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd00005017*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd00005019*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd0000501A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd0000501F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00005025*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd00005027*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd0000502A*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd0000502B*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd0000502D*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd0000502E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd0000502F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv000017AAsd00005030*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
pci:v000010DEd00001140sv000017AAsd00005031*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 705M)
pci:v000010DEd00001140sv000017AAsd00005032*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00005033*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd0000503E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv000017AAsd0000503F*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv000017AAsd00005040*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001854sd00000177*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001854sd00000180*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 710M)
pci:v000010DEd00001140sv00001854sd00000190*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001854sd00000192*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001B0Asd000020DD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001B0Asd000020DF*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M)
pci:v000010DEd00001140sv00001B0Asd0000210E*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001B0Asd00002202*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M)
pci:v000010DEd00001140sv00001B0Asd000090D7*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001140sv00001B0Asd000090DD*
- ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
+ ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M)
pci:v000010DEd00001180*
ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 680]
@@ -29630,6 +29897,9 @@ pci:v000010DEd000011C3sv000010DEsd00001030*
pci:v000010DEd000011C4*
ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 645 OEM]
+pci:v000010DEd000011C5*
+ ID_MODEL_FROM_DATABASE=GK106 [GeForce GT 740]
+
pci:v000010DEd000011C6*
ID_MODEL_FROM_DATABASE=GK106 [GeForce GTX 650 Ti]
@@ -29654,6 +29924,9 @@ pci:v000010DEd000011E3*
pci:v000010DEd000011E3sv000017AAsd00003683*
ID_MODEL_FROM_DATABASE=GK106M [GeForce GTX 760M] (GeForce GTX 760A)
+pci:v000010DEd000011E7*
+ ID_MODEL_FROM_DATABASE=GK106M
+
pci:v000010DEd000011FA*
ID_MODEL_FROM_DATABASE=GK106GL [Quadro K4000]
@@ -29813,6 +30086,9 @@ pci:v000010DEd00001287*
pci:v000010DEd00001288*
ID_MODEL_FROM_DATABASE=GK208 [GeForce GT 720]
+pci:v000010DEd00001289*
+ ID_MODEL_FROM_DATABASE=GK208 [GeForce GT 710]
+
pci:v000010DEd00001290*
ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 730M]
@@ -29837,6 +30113,9 @@ pci:v000010DEd00001292*
pci:v000010DEd00001292sv000017AAsd00003675*
ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 740M] (GeForce GT 740A)
+pci:v000010DEd00001292sv000017AAsd0000367C*
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 740M] (GeForce GT 740A)
+
pci:v000010DEd00001292sv000017AAsd00003684*
ID_MODEL_FROM_DATABASE=GK208M [GeForce GT 740M] (GeForce GT 740A)
@@ -29850,22 +30129,28 @@ pci:v000010DEd00001295*
ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M]
pci:v000010DEd00001295sv0000103Csd00002B0D*
- ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce GT 710A)
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 710A)
pci:v000010DEd00001295sv0000103Csd00002B0F*
- ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce GT 710A)
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 710A)
pci:v000010DEd00001295sv0000103Csd00002B11*
- ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce GT 710A)
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 710A)
pci:v000010DEd00001295sv0000103Csd00002B20*
ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 810A)
pci:v000010DEd00001295sv0000103Csd00002B21*
- ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce GT 810A)
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 810A)
pci:v000010DEd00001295sv0000103Csd00002B22*
- ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce GT 810A)
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 810A)
+
+pci:v000010DEd00001295sv000017AAsd0000367A*
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 805A)
+
+pci:v000010DEd00001295sv000017AAsd0000367C*
+ ID_MODEL_FROM_DATABASE=GK208M [GeForce 710M] (GeForce 710A)
pci:v000010DEd00001296*
ID_MODEL_FROM_DATABASE=GK208M [GeForce 825M]
@@ -29876,6 +30161,9 @@ pci:v000010DEd00001298*
pci:v000010DEd00001299*
ID_MODEL_FROM_DATABASE=GK208M [GeForce 920M]
+pci:v000010DEd0000129A*
+ ID_MODEL_FROM_DATABASE=GK208GL [N16V-GL]
+
pci:v000010DEd000012A0*
ID_MODEL_FROM_DATABASE=GK208
@@ -29909,6 +30197,9 @@ pci:v000010DEd00001346*
pci:v000010DEd00001347*
ID_MODEL_FROM_DATABASE=GM108M [GeForce 940M]
+pci:v000010DEd0000137A*
+ ID_MODEL_FROM_DATABASE=GM108GLM [Quadro K620M]
+
pci:v000010DEd00001380*
ID_MODEL_FROM_DATABASE=GM107 [GeForce GTX 750 Ti]
@@ -29993,9 +30284,18 @@ pci:v000010DEd000013D8*
pci:v000010DEd000013D9*
ID_MODEL_FROM_DATABASE=GM204M [GeForce GTX 965M]
+pci:v000010DEd000013F2*
+ ID_MODEL_FROM_DATABASE=GM204GL [Tesla M60]
+
pci:v000010DEd00001401*
ID_MODEL_FROM_DATABASE=GM206 [GeForce GTX 960]
+pci:v000010DEd000017C2*
+ ID_MODEL_FROM_DATABASE=GM200 [GeForce GTX TITAN X]
+
+pci:v000010DEd000017C8*
+ ID_MODEL_FROM_DATABASE=GM200 [GeForce GTX 980 Ti]
+
pci:v000010DEd000017F0*
ID_MODEL_FROM_DATABASE=GM200GL [Quadro M6000]
@@ -30005,6 +30305,21 @@ pci:v000010DF*
pci:v000010DFd00000720*
ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk)
+pci:v000010DFd00000720sv0000103Csd00001934*
+ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (HP FlexFabric 20Gb 2-port 650M Adapter)
+
+pci:v000010DFd00000720sv0000103Csd00001935*
+ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (HP FlexFabric 20Gb 2-port 650FLB Adapter)
+
+pci:v000010DFd00000720sv0000103Csd000021D4*
+ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (HP StoreFabric CN1200E 10Gb Converged Network Adapter)
+
+pci:v000010DFd00000720sv0000103Csd0000220A*
+ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (HP FlexFabric 10Gb 2-port 556FLR-SFP+ Adapter)
+
+pci:v000010DFd00000720sv0000103Csd0000803F*
+ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (HP Ethernet 10Gb 2-port 557SFP+ Adapter)
+
pci:v000010DFd00000720sv000017AAsd00001056*
ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (ThinkServer OCm14102-UX-L AnyFabric)
@@ -30014,6 +30329,9 @@ pci:v000010DFd00000720sv000017AAsd00001057*
pci:v000010DFd00000720sv000017AAsd00001059*
ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (ThinkServer OCm14104-UT-L AnyFabric)
+pci:v000010DFd00000720sv000017AAsd00004014*
+ ID_MODEL_FROM_DATABASE=OneConnect NIC (Skyhawk) (ThinkServer OCm14102-NX-L AnyFabric)
+
pci:v000010DFd00000722*
ID_MODEL_FROM_DATABASE=OneConnect iSCSI Initiator (Skyhawk)
@@ -30755,6 +31073,9 @@ pci:v000010ECd00008168sv00001775sd000011CC*
pci:v000010ECd00008168sv00001849sd00008168*
ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Motherboard (one of many))
+pci:v000010ECd00008168sv00007470sd00003468*
+ ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (TG-3468 Gigabit PCI Express Network Adapter)
+
pci:v000010ECd00008168sv00008086sd0000D615*
ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Desktop Board D510MO/D525MW)
@@ -31278,7 +31599,7 @@ pci:v00001102d00007005sv00001102sd00001002*
ID_MODEL_FROM_DATABASE=SB Audigy LS Game Port (SB0312 Audigy LS MIDI/Game port)
pci:v00001102d00007006*
- ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG PCI to PCIe Bridge
+ ID_MODEL_FROM_DATABASE=[SB X-Fi Xtreme Audio] CA0110-IBG PCIe to PCI Bridge
pci:v00001102d00008938*
ID_MODEL_FROM_DATABASE=Ectiva EV1938
@@ -31373,12 +31694,21 @@ pci:v00001103d00000622*
pci:v00001103d00000640*
ID_MODEL_FROM_DATABASE=RocketRAID 640 4 Port SATA-III Controller
+pci:v00001103d00000641*
+ ID_MODEL_FROM_DATABASE=RocketRAID 640L 4 Port SATA-III Controller
+
+pci:v00001103d00000642*
+ ID_MODEL_FROM_DATABASE=RocketRAID 642L 2 Port SATA-III Controller (eSATA)
+
pci:v00001103d00000644*
ID_MODEL_FROM_DATABASE=RocketRAID 644 4 Port SATA-III Controller (eSATA)
pci:v00001103d00000645*
ID_MODEL_FROM_DATABASE=RocketRAID 644L 4 Port SATA-III Controller (eSATA)
+pci:v00001103d00000646*
+ ID_MODEL_FROM_DATABASE=RocketRAID 644LS SATA-III Controller (4 eSATA devices connected by 1 SAS cable)
+
pci:v00001103d00001720*
ID_MODEL_FROM_DATABASE=RocketRAID 1720 (2x SATA II RAID Controller)
@@ -31956,7 +32286,7 @@ pci:v00001106d00003038*
ID_MODEL_FROM_DATABASE=VT82xxxxx UHCI USB 1.1 Controller
pci:v00001106d00003038sv00000925sd00001234*
- ID_MODEL_FROM_DATABASE=VT82xxxxx UHCI USB 1.1 Controller (VA-502 Mainboard)
+ ID_MODEL_FROM_DATABASE=VT82xxxxx UHCI USB 1.1 Controller (onboard UHCI USB 1.1 Controller)
pci:v00001106d00003038sv00001019sd00000985*
ID_MODEL_FROM_DATABASE=VT82xxxxx UHCI USB 1.1 Controller (P6VXA Motherboard)
@@ -32043,7 +32373,7 @@ pci:v00001106d00003044sv0000103Csd00002A3B*
ID_MODEL_FROM_DATABASE=VT6306/7/8 [Fire II(M)] IEEE 1394 OHCI Controller (Media Center PC m7590n)
pci:v00001106d00003044sv00001043sd0000808A*
- ID_MODEL_FROM_DATABASE=VT6306/7/8 [Fire II(M)] IEEE 1394 OHCI Controller (A8V/A8N/P4P800 series motherboard)
+ ID_MODEL_FROM_DATABASE=VT6306/7/8 [Fire II(M)] IEEE 1394 OHCI Controller (A8V/A8N/P4P800/P5SD2 series motherboard)
pci:v00001106d00003044sv00001043sd000081FE*
ID_MODEL_FROM_DATABASE=VT6306/7/8 [Fire II(M)] IEEE 1394 OHCI Controller (Motherboard)
@@ -32141,6 +32471,9 @@ pci:v00001106d00003058sv00001462sd00003092*
pci:v00001106d00003058sv00001462sd00003300*
ID_MODEL_FROM_DATABASE=VT82C686 AC97 Audio Controller (MS-6330 Onboard Audio)
+pci:v00001106d00003058sv00001462sd00003400*
+ ID_MODEL_FROM_DATABASE=VT82C686 AC97 Audio Controller (MS-6340 (VT8363) motherboard)
+
pci:v00001106d00003058sv000015DDsd00007609*
ID_MODEL_FROM_DATABASE=VT82C686 AC97 Audio Controller (Onboard Audio)
@@ -32306,6 +32639,9 @@ pci:v00001106d00003103*
pci:v00001106d00003104*
ID_MODEL_FROM_DATABASE=USB 2.0
+pci:v00001106d00003104sv00000925sd00001234*
+ ID_MODEL_FROM_DATABASE=USB 2.0 (onboard EHCI USB 2.0 Controller)
+
pci:v00001106d00003104sv00001019sd00000A81*
ID_MODEL_FROM_DATABASE=USB 2.0 (L7VTA v1.0 Motherboard (KT400-8235))
@@ -32711,6 +33047,9 @@ pci:v00001106d00003456*
pci:v00001106d0000345B*
ID_MODEL_FROM_DATABASE=VX11 Miscellaneous Bus
+pci:v00001106d00003483*
+ ID_MODEL_FROM_DATABASE=VL805 USB 3.0 Host Controller
+
pci:v00001106d00003A01*
ID_MODEL_FROM_DATABASE=VX11 Graphics [Chrome 645/640]
@@ -33896,6 +34235,9 @@ pci:v0000111Dd00008088sv00001093sd00007600*
pci:v0000111Dd00008088sv00001093sd00007602*
ID_MODEL_FROM_DATABASE=PES32NT8BG2 PCI Express Switch (PXIe-8384)
+pci:v0000111Dd0000808F*
+ ID_MODEL_FROM_DATABASE=PES32NT8AG2
+
pci:v0000111E*
ID_VENDOR_FROM_DATABASE=Eldec
@@ -34664,9 +35006,12 @@ pci:v00001131d00007164sv00000070sd000089A0*
pci:v00001131d00007164sv00000070sd000089A1*
ID_MODEL_FROM_DATABASE=SAA7164 (WinTV HVR-2200)
-pci:v00001131d00007164sv00000070sd0000F123*
+pci:v00001131d00007164sv00000070sd0000F120*
ID_MODEL_FROM_DATABASE=SAA7164 (WinTV HVR-2205)
+pci:v00001131d00007164sv00000070sd0000F123*
+ ID_MODEL_FROM_DATABASE=SAA7164 (WinTV HVR-2215)
+
pci:v00001131d00007231*
ID_MODEL_FROM_DATABASE=SAA7231
@@ -37274,6 +37619,9 @@ pci:v000011ABd00002A55*
pci:v000011ABd00002B36*
ID_MODEL_FROM_DATABASE=88W8764 [Avastar] 802.11n Wireless
+pci:v000011ABd00002B38*
+ ID_MODEL_FROM_DATABASE=88W8897 [AVASTAR] 802.11ac Wireless
+
pci:v000011ABd00004101*
ID_MODEL_FROM_DATABASE=OLPC Cafe Controller Secure Digital Controller
@@ -39923,6 +40271,15 @@ pci:v0000125E*
pci:v0000125F*
ID_VENDOR_FROM_DATABASE=Concurrent Technologies, Inc.
+pci:v0000125Fd00002071*
+ ID_MODEL_FROM_DATABASE=CC PMC/232
+
+pci:v0000125Fd00002084*
+ ID_MODEL_FROM_DATABASE=CC PMC/23P
+
+pci:v0000125Fd00002091*
+ ID_MODEL_FROM_DATABASE=CC PMC/422
+
pci:v00001260*
ID_VENDOR_FROM_DATABASE=Intersil Corporation
@@ -40124,6 +40481,9 @@ pci:v0000126Fd00000720*
pci:v0000126Fd00000730*
ID_MODEL_FROM_DATABASE=SM731 Cougar3DR
+pci:v0000126Fd00000750*
+ ID_MODEL_FROM_DATABASE=SM750
+
pci:v0000126Fd00000810*
ID_MODEL_FROM_DATABASE=SM810 LynxE
@@ -43145,17 +43505,56 @@ pci:v00001397*
pci:v00001397d000008B4*
ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S]
+pci:v00001397d000008B4sv00001397sd000008B4*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Cologne Chip HFC-4S Eval. Board])
+
+pci:v00001397d000008B4sv00001397sd0000B51A*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Allo.com BRI card])
+
pci:v00001397d000008B4sv00001397sd0000B520*
ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [IOB4ST])
pci:v00001397d000008B4sv00001397sd0000B540*
- ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Swyx 4xS0 SX2 QuadBri])
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Swyx SX2 QuadBri])
pci:v00001397d000008B4sv00001397sd0000B550*
- ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns quadBRI])
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET quadBRI])
pci:v00001397d000008B4sv00001397sd0000B556*
- ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns DuoDBRI])
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET duoBRI])
+
+pci:v00001397d000008B4sv00001397sd0000B559*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET duoBRI miniPCI])
+
+pci:v00001397d000008B4sv00001397sd0000B560*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN4S0])
+
+pci:v00001397d000008B4sv00001397sd0000B566*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN2S0])
+
+pci:v00001397d000008B4sv00001397sd0000B567*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN1S0 miniPCI])
+
+pci:v00001397d000008B4sv00001397sd0000B568*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN4S0 miniPCI])
+
+pci:v00001397d000008B4sv00001397sd0000B569*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN2S0 miniPCI])
+
+pci:v00001397d000008B4sv00001397sd0000B620*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S)
+
+pci:v00001397d000008B4sv00001397sd0000B752*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [Junghanns.NET quadBRI PCIe])
+
+pci:v00001397d000008B4sv00001397sd0000B761*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN2S0 PCIe])
+
+pci:v00001397d000008B4sv00001397sd0000B762*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [BeroNet BN4S0 PCIe])
+
+pci:v00001397d000008B4sv00001397sd0000E884*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [OpenVox B200P])
pci:v00001397d000008B4sv00001397sd0000E888*
ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-4S] (HFC-4S [OpenVox B200P / B400P])
@@ -43163,9 +43562,33 @@ pci:v00001397d000008B4sv00001397sd0000E888*
pci:v00001397d000016B8*
ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S]
-pci:v00001397d000016B8sv00001397sd0000B562*
+pci:v00001397d000016B8sv00001397sd000016B8*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [Cologne Chip HFC-8S Eval. Board])
+
+pci:v00001397d000016B8sv00001397sd0000B521*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [IOB4ST Recording])
+
+pci:v00001397d000016B8sv00001397sd0000B522*
ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [IOB8ST])
+pci:v00001397d000016B8sv00001397sd0000B552*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [Junghanns.NET octoBRI])
+
+pci:v00001397d000016B8sv00001397sd0000B55B*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [Junghanns.NET octoBRI])
+
+pci:v00001397d000016B8sv00001397sd0000B562*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [BeroNet BN8S0])
+
+pci:v00001397d000016B8sv00001397sd0000B56B*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [BeroNet BN8S0+])
+
+pci:v00001397d000016B8sv00001397sd0000B622*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S)
+
+pci:v00001397d000016B8sv00001397sd0000E998*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-8S] (HFC-8S [OpenVox B800P])
+
pci:v00001397d00002BD0*
ID_MODEL_FROM_DATABASE=ISDN network controller [HFC-PCI]
@@ -43184,6 +43607,42 @@ pci:v00001397d00002BD0sv0000E4BFsd00001000*
pci:v00001397d000030B1*
ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1]
+pci:v00001397d000030B1sv00001397sd000030B1*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Cologne Chip HFC-E1 Eval. Board])
+
+pci:v00001397d000030B1sv00001397sd0000B523*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [IOB1E1])
+
+pci:v00001397d000030B1sv00001397sd0000B543*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Swyx SX2 SinglePRI V2])
+
+pci:v00001397d000030B1sv00001397sd0000B544*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Swyx SX2 DualPRI V2])
+
+pci:v00001397d000030B1sv00001397sd0000B553*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET singleE1])
+
+pci:v00001397d000030B1sv00001397sd0000B554*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET doubleE1])
+
+pci:v00001397d000030B1sv00001397sd0000B555*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET doubleE1 2.0])
+
+pci:v00001397d000030B1sv00001397sd0000B55A*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [Junghanns.NET singleE1 miniPCI])
+
+pci:v00001397d000030B1sv00001397sd0000B563*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN1E1])
+
+pci:v00001397d000030B1sv00001397sd0000B564*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN2E1])
+
+pci:v00001397d000030B1sv00001397sd0000B565*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN2E1+])
+
+pci:v00001397d000030B1sv00001397sd0000B56A*
+ ID_MODEL_FROM_DATABASE=ISDN network Controller [HFC-E1] (HFC-E1 [beroNet BN1E1 miniPCI])
+
pci:v00001397d0000B700*
ID_MODEL_FROM_DATABASE=ISDN network controller PrimuX S0 [HFC-PCI]
@@ -45206,6 +45665,9 @@ pci:v00001425d00005088*
pci:v00001425d00005089*
ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller
+pci:v00001425d00005090*
+ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller
+
pci:v00001425d00005401*
ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller
@@ -45299,6 +45761,9 @@ pci:v00001425d00005488*
pci:v00001425d00005489*
ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller
+pci:v00001425d00005490*
+ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller
+
pci:v00001425d00005501*
ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller
@@ -45392,6 +45857,9 @@ pci:v00001425d00005588*
pci:v00001425d00005589*
ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Storage Controller
+pci:v00001425d00005590*
+ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Storage Controller
+
pci:v00001425d00005601*
ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller
@@ -45485,6 +45953,9 @@ pci:v00001425d00005688*
pci:v00001425d00005689*
ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Storage Controller
+pci:v00001425d00005690*
+ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Storage Controller
+
pci:v00001425d00005701*
ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller
@@ -45578,6 +46049,9 @@ pci:v00001425d00005788*
pci:v00001425d00005789*
ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller
+pci:v00001425d00005790*
+ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller
+
pci:v00001425d00005801*
ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller [VF]
@@ -45671,6 +46145,9 @@ pci:v00001425d00005888*
pci:v00001425d00005889*
ID_MODEL_FROM_DATABASE=T520-5089 Unified Wire Ethernet Controller [VF]
+pci:v00001425d00005890*
+ ID_MODEL_FROM_DATABASE=T540-5090 Unified Wire Ethernet Controller [VF]
+
pci:v00001425d0000A000*
ID_MODEL_FROM_DATABASE=PE10K Unified Wire Ethernet Controller
@@ -46115,9 +46592,6 @@ pci:v0000148E*
pci:v0000148F*
ID_VENDOR_FROM_DATABASE=Plant Equipment, Inc.
-pci:v0000148Fd00005370*
- ID_MODEL_FROM_DATABASE=Dexlink AUWL15I1
-
pci:v00001490*
ID_VENDOR_FROM_DATABASE=Stone Microsystems PTY Ltd.
@@ -48365,6 +48839,9 @@ pci:v000014E4d00004401*
pci:v000014E4d00004401sv00001025sd00000035*
ID_MODEL_FROM_DATABASE=BCM4401 100Base-T (TravelMate 660)
+pci:v000014E4d00004401sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=BCM4401 100Base-T (Extensa 3000 series laptop)
+
pci:v000014E4d00004401sv0000103Csd000008B0*
ID_MODEL_FROM_DATABASE=BCM4401 100Base-T (tc1100 tablet)
@@ -49376,6 +49853,9 @@ pci:v000014F1d00008852sv00004254sd0000980C*
pci:v000014F1d00008880*
ID_MODEL_FROM_DATABASE=CX23887/8 PCIe Broadcast Audio and Video Decoder with 3D Comb
+pci:v000014F1d00008880sv00000070sd00002259*
+ ID_MODEL_FROM_DATABASE=CX23887/8 PCIe Broadcast Audio and Video Decoder with 3D Comb (WinTV HVR-1250)
+
pci:v000014F1d00008880sv00000070sd0000C108*
ID_MODEL_FROM_DATABASE=CX23887/8 PCIe Broadcast Audio and Video Decoder with 3D Comb (WinTV-HVR-4400-HD model 1278)
@@ -50441,6 +50921,9 @@ pci:v000015B3d000001FF*
pci:v000015B3d00000209*
ID_MODEL_FROM_DATABASE=MT27700 Family [ConnectX-4 Flash Recovery]
+pci:v000015B3d0000020B*
+ ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx Flash Recovery]
+
pci:v000015B3d00001002*
ID_MODEL_FROM_DATABASE=MT25400 Family [ConnectX-2 Virtual Function]
@@ -50453,6 +50936,12 @@ pci:v000015B3d00001003sv0000103Csd00001777*
pci:v000015B3d00001003sv0000103Csd000017C9*
ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3] (Infiniband QDR/Ethernet 10Gb 2-port 544i Adapter)
+pci:v000015B3d00001003sv0000103Csd000018CE*
+ ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3] (InfiniBand QDR/EN 10Gb Dual Port 544M Adapter)
+
+pci:v000015B3d00001003sv0000103Csd000018CF*
+ ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3] (InfiniBand FDR/EN 10/40Gb Dual Port 544M Adapter)
+
pci:v000015B3d00001003sv0000103Csd000018D6*
ID_MODEL_FROM_DATABASE=MT27500 Family [ConnectX-3] (InfiniBand FDR/EN 10/40Gb Dual Port 544QSFP Adapter)
@@ -50468,6 +50957,24 @@ pci:v000015B3d00001006*
pci:v000015B3d00001007*
ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro]
+pci:v000015B3d00001007sv0000103Csd000022F3*
+ ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (InfiniBand FDR/Ethernet 10Gb/40Gb 2-port 544+QSFP Adapter)
+
+pci:v000015B3d00001007sv0000103Csd000022F4*
+ ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (InfiniBand FDR/Ethernet 10Gb/40Gb 2-port 544+FLR-QSFP Adapter)
+
+pci:v000015B3d00001007sv0000117Csd00000090*
+ ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (FastFrame NQ41)
+
+pci:v000015B3d00001007sv0000117Csd00000091*
+ ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (FastFrame NQ42)
+
+pci:v000015B3d00001007sv0000117Csd00000092*
+ ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (FastFrame NQ11)
+
+pci:v000015B3d00001007sv0000117Csd00000093*
+ ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (FastFrame NQ12)
+
pci:v000015B3d00001009*
ID_MODEL_FROM_DATABASE=MT27530 Family
@@ -50505,10 +51012,10 @@ pci:v000015B3d00001014*
ID_MODEL_FROM_DATABASE=MT27700 Family [ConnectX-4 Virtual Function]
pci:v000015B3d00001015*
- ID_MODEL_FROM_DATABASE=MT27630 Family
+ ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx]
pci:v000015B3d00001016*
- ID_MODEL_FROM_DATABASE=MT27631 Family
+ ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx Virtual Function]
pci:v000015B3d00001017*
ID_MODEL_FROM_DATABASE=MT27640 Family
@@ -50564,6 +51071,12 @@ pci:v000015B3d00006732*
pci:v000015B3d0000673C*
ID_MODEL_FROM_DATABASE=MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE]
+pci:v000015B3d0000673Csv0000103Csd00001782*
+ ID_MODEL_FROM_DATABASE=MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE] (4X QDR InfiniBand Mezzanine HCA for c-Class BladeSystem)
+
+pci:v000015B3d0000673Csv000015B3sd00000021*
+ ID_MODEL_FROM_DATABASE=MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE] (HP InfiniBand 4X QDR CX-2 PCI-e G2 Dual Port HCA)
+
pci:v000015B3d00006746*
ID_MODEL_FROM_DATABASE=MT26438 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virtualization+]
@@ -50576,6 +51089,9 @@ pci:v000015B3d00006746sv0000103Csd00003349*
pci:v000015B3d00006750*
ID_MODEL_FROM_DATABASE=MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s]
+pci:v000015B3d00006750sv000015B3sd00000018*
+ ID_MODEL_FROM_DATABASE=MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] (HP 10 GbE PCI-e G2 Dual-Port NIC (rev C1))
+
pci:v000015B3d0000675A*
ID_MODEL_FROM_DATABASE=MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe Gen2 5GT/s]
@@ -51191,6 +51707,207 @@ pci:v0000165Ad0000D300*
pci:v0000165Ad0000EB01*
ID_MODEL_FROM_DATABASE=PIXCI(R) EB1 PCI Camera Link Video Capture Board
+pci:v0000165C*
+ ID_VENDOR_FROM_DATABASE=Gidel Ltd.
+
+pci:v0000165Cd00005361*
+ ID_MODEL_FROM_DATABASE=PROCStarII60-1
+
+pci:v0000165Cd00005362*
+ ID_MODEL_FROM_DATABASE=PROCStarII60-2
+
+pci:v0000165Cd00005364*
+ ID_MODEL_FROM_DATABASE=PROCStarII60-4
+
+pci:v0000165Cd00005435*
+ ID_MODEL_FROM_DATABASE=ProcSparkII
+
+pci:v0000165Cd00005661*
+ ID_MODEL_FROM_DATABASE=ProcE60
+
+pci:v0000165Cd000056E1*
+ ID_MODEL_FROM_DATABASE=ProcE180
+
+pci:v0000165Cd00005911*
+ ID_MODEL_FROM_DATABASE=ProcStarIII110-1
+
+pci:v0000165Cd00005912*
+ ID_MODEL_FROM_DATABASE=ProcStarIII110-2
+
+pci:v0000165Cd00005913*
+ ID_MODEL_FROM_DATABASE=ProcStarIII110-3
+
+pci:v0000165Cd00005914*
+ ID_MODEL_FROM_DATABASE=ProcStarIII110-4
+
+pci:v0000165Cd00005921*
+ ID_MODEL_FROM_DATABASE=ProcStarIII150-1
+
+pci:v0000165Cd00005922*
+ ID_MODEL_FROM_DATABASE=ProcStarIII150-2
+
+pci:v0000165Cd00005923*
+ ID_MODEL_FROM_DATABASE=ProcStarIII150-3
+
+pci:v0000165Cd00005924*
+ ID_MODEL_FROM_DATABASE=ProcStarIII150-4
+
+pci:v0000165Cd00005931*
+ ID_MODEL_FROM_DATABASE=ProcStarIII260-1
+
+pci:v0000165Cd00005932*
+ ID_MODEL_FROM_DATABASE=ProcStarIII260-2
+
+pci:v0000165Cd00005933*
+ ID_MODEL_FROM_DATABASE=ProcStarIII260-3
+
+pci:v0000165Cd00005934*
+ ID_MODEL_FROM_DATABASE=ProcStarIII260-4
+
+pci:v0000165Cd00005941*
+ ID_MODEL_FROM_DATABASE=ProcStarIII340-1
+
+pci:v0000165Cd00005942*
+ ID_MODEL_FROM_DATABASE=ProcStarIII340-2
+
+pci:v0000165Cd00005943*
+ ID_MODEL_FROM_DATABASE=ProcStarIII340-3
+
+pci:v0000165Cd00005944*
+ ID_MODEL_FROM_DATABASE=ProcStarIII340-4
+
+pci:v0000165Cd00005A01*
+ ID_MODEL_FROM_DATABASE=ProceIII80
+
+pci:v0000165Cd00005A11*
+ ID_MODEL_FROM_DATABASE=ProceIII110
+
+pci:v0000165Cd00005A21*
+ ID_MODEL_FROM_DATABASE=ProceIII150
+
+pci:v0000165Cd00005A31*
+ ID_MODEL_FROM_DATABASE=ProceIII260
+
+pci:v0000165Cd00005A41*
+ ID_MODEL_FROM_DATABASE=ProceIII340
+
+pci:v0000165Cd00005B51*
+ ID_MODEL_FROM_DATABASE=ProceIV360
+
+pci:v0000165Cd00005B61*
+ ID_MODEL_FROM_DATABASE=ProceIV530
+
+pci:v0000165Cd00005B71*
+ ID_MODEL_FROM_DATABASE=ProceIV820
+
+pci:v0000165Cd00005C01*
+ ID_MODEL_FROM_DATABASE=ProcStarIV80-1
+
+pci:v0000165Cd00005C02*
+ ID_MODEL_FROM_DATABASE=ProcStarIV80-2
+
+pci:v0000165Cd00005C03*
+ ID_MODEL_FROM_DATABASE=ProcStarIV80-3
+
+pci:v0000165Cd00005C04*
+ ID_MODEL_FROM_DATABASE=ProcStarIV80-4
+
+pci:v0000165Cd00005C11*
+ ID_MODEL_FROM_DATABASE=ProcStarIV110-1
+
+pci:v0000165Cd00005C12*
+ ID_MODEL_FROM_DATABASE=ProcStarIV110-2
+
+pci:v0000165Cd00005C13*
+ ID_MODEL_FROM_DATABASE=ProcStarIV110-3
+
+pci:v0000165Cd00005C14*
+ ID_MODEL_FROM_DATABASE=ProcStarIV110-4
+
+pci:v0000165Cd00005C51*
+ ID_MODEL_FROM_DATABASE=ProcStarIV360-1
+
+pci:v0000165Cd00005C52*
+ ID_MODEL_FROM_DATABASE=ProcStarIV360-2
+
+pci:v0000165Cd00005C53*
+ ID_MODEL_FROM_DATABASE=ProcStarIV360-3
+
+pci:v0000165Cd00005C54*
+ ID_MODEL_FROM_DATABASE=ProcStarIV360-4
+
+pci:v0000165Cd00005C61*
+ ID_MODEL_FROM_DATABASE=ProcStarIV530-1
+
+pci:v0000165Cd00005C62*
+ ID_MODEL_FROM_DATABASE=ProcStarIV530-2
+
+pci:v0000165Cd00005C63*
+ ID_MODEL_FROM_DATABASE=ProcStarIV530-3
+
+pci:v0000165Cd00005C64*
+ ID_MODEL_FROM_DATABASE=ProcStarIV530-4
+
+pci:v0000165Cd00005C71*
+ ID_MODEL_FROM_DATABASE=ProcStarIV820-1
+
+pci:v0000165Cd00005C72*
+ ID_MODEL_FROM_DATABASE=ProcStarIV820-2
+
+pci:v0000165Cd00005C73*
+ ID_MODEL_FROM_DATABASE=ProcStarIV820-3
+
+pci:v0000165Cd00005C74*
+ ID_MODEL_FROM_DATABASE=ProcStarIV820-4
+
+pci:v0000165Cd00005D01*
+ ID_MODEL_FROM_DATABASE=Proc10480
+
+pci:v0000165Cd00005D11*
+ ID_MODEL_FROM_DATABASE=Proc104110
+
+pci:v0000165Cd00005F01*
+ ID_MODEL_FROM_DATABASE=ProceV_A3
+
+pci:v0000165Cd00005F11*
+ ID_MODEL_FROM_DATABASE=ProceV_A7
+
+pci:v0000165Cd00005F21*
+ ID_MODEL_FROM_DATABASE=ProceV_AB
+
+pci:v0000165Cd00005F31*
+ ID_MODEL_FROM_DATABASE=ProceV_D5
+
+pci:v0000165Cd00005F41*
+ ID_MODEL_FROM_DATABASE=ProceV_D8
+
+pci:v0000165Cd00006732*
+ ID_MODEL_FROM_DATABASE=Proc6M
+
+pci:v0000165Cd00006832*
+ ID_MODEL_FROM_DATABASE=Proc12M
+
+pci:v0000165Cd00007101*
+ ID_MODEL_FROM_DATABASE=Proc10a_27
+
+pci:v0000165Cd00007111*
+ ID_MODEL_FROM_DATABASE=Proc10a_48
+
+pci:v0000165Cd00007121*
+ ID_MODEL_FROM_DATABASE=Proc10a_66
+
+pci:v0000165Cd00007141*
+ ID_MODEL_FROM_DATABASE=Proc10a_115
+
+pci:v0000165Cd00007181*
+ ID_MODEL_FROM_DATABASE=Proc10a_27S
+
+pci:v0000165Cd00007191*
+ ID_MODEL_FROM_DATABASE=Proc10a_48S
+
+pci:v0000165Cd000071A1*
+ ID_MODEL_FROM_DATABASE=Proc10a_66S
+
pci:v0000165D*
ID_VENDOR_FROM_DATABASE=Hsing Tech. Enterprise Co., Ltd.
@@ -51927,10 +52644,13 @@ pci:v0000168Cd00000037sv00001A3Bsd00002100*
ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter (AW-NB100H 802.11n Wireless Mini PCIe Card)
pci:v0000168Cd0000003C*
- ID_MODEL_FROM_DATABASE=QCA988x 802.11ac Wireless Network Adapter
+ ID_MODEL_FROM_DATABASE=QCA986x/988x 802.11ac Wireless Network Adapter
pci:v0000168Cd0000003E*
- ID_MODEL_FROM_DATABASE=Killer N1525 Wireless-AC
+ ID_MODEL_FROM_DATABASE=QCA6174 802.11ac Wireless Network Adapter
+
+pci:v0000168Cd0000003Esv00001A56sd00001525*
+ ID_MODEL_FROM_DATABASE=QCA6174 802.11ac Wireless Network Adapter (Killer N1525 Wireless-AC)
pci:v0000168Cd00000207*
ID_MODEL_FROM_DATABASE=AR5210 Wireless Network Adapter [AR5000 802.11a]
@@ -52719,7 +53439,10 @@ pci:v00001796d00000015*
ID_MODEL_FROM_DATABASE=SIS8100 [Gigabit link, MicroTCA]
pci:v00001797*
- ID_VENDOR_FROM_DATABASE=Techwell Inc.
+ ID_VENDOR_FROM_DATABASE=Intersil Techwell
+
+pci:v00001797d00005864*
+ ID_MODEL_FROM_DATABASE=TW5864 multimedia video controller
pci:v00001797d00006801*
ID_MODEL_FROM_DATABASE=TW6802 multimedia video card
@@ -53375,6 +54098,9 @@ pci:v00001814d00005360sv00001186sd00003C05*
pci:v00001814d00005360sv000020F4sd0000703A*
ID_MODEL_FROM_DATABASE=RT5360 Wireless 802.11n 1T/1R (TEW-703PI N150 Wireless PCI Adapter)
+pci:v00001814d00005362*
+ ID_MODEL_FROM_DATABASE=RT5362 PCI 802.11n Wireless Network Adapter
+
pci:v00001814d00005390*
ID_MODEL_FROM_DATABASE=RT5390 Wireless 802.11n 1T/1R PCIe
@@ -53930,6 +54656,9 @@ pci:v000018F4d00000145*
pci:v000018F4d00000155*
ID_MODEL_FROM_DATABASE=NT100E3-1-PTP Network Adapter 1x100Gb
+pci:v000018F4d00000175*
+ ID_MODEL_FROM_DATABASE=NT20E3-2-PTP Network Adapter 2x10Gb
+
pci:v000018F6*
ID_VENDOR_FROM_DATABASE=NextIO
@@ -54326,12 +55055,24 @@ pci:v00001924d00000903sv00001924sd00008009*
pci:v00001924d00000903sv00001924sd0000800A*
ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x02F-R2 Flareon 7000 Series 10G Adapter)
+pci:v00001924d00000903sv00001924sd0000800B*
+ ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x22F-R3 Flareon Ultra 7000 Series 10G Adapter)
+
+pci:v00001924d00000903sv00001924sd0000800C*
+ ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x22F-R3 Flareon Ultra 7000 Series 10G Adapter)
+
+pci:v00001924d00000903sv00001924sd0000800D*
+ ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x02F-R3 Flareon 7000 Series 10G Adapter)
+
pci:v00001924d00000923*
ID_MODEL_FROM_DATABASE=SFC9140
pci:v00001924d00000923sv00001924sd0000800B*
ID_MODEL_FROM_DATABASE=SFC9140 (SFN7x42Q-R1 Flareon Ultra 7000 Series 10/40G Adapter)
+pci:v00001924d00000923sv00001924sd0000800E*
+ ID_MODEL_FROM_DATABASE=SFC9140 (SFN7x42Q-R2 Flareon Ultra 7000 Series 10/40G Adapter)
+
pci:v00001924d00001803*
ID_MODEL_FROM_DATABASE=SFC9020 Virtual Function [Solarstorm]
@@ -54719,6 +55460,9 @@ pci:v00001957d0000C006*
pci:v00001957d0000C006sv00001A56sd00001201*
ID_MODEL_FROM_DATABASE=MPC8308 (Killer E2100 Gigabit Ethernet Controller)
+pci:v00001957d0000FC02*
+ ID_MODEL_FROM_DATABASE=RedStone
+
pci:v00001958*
ID_VENDOR_FROM_DATABASE=Faster Technology, LLC.
@@ -55703,6 +56447,9 @@ pci:v00001B21d00001080sv00001849sd00001080*
pci:v00001B21d00001142*
ID_MODEL_FROM_DATABASE=ASM1042A USB 3.0 Host Controller
+pci:v00001B21d00001242*
+ ID_MODEL_FROM_DATABASE=ASM1142 USB 3.1 Host Controller
+
pci:v00001B2C*
ID_VENDOR_FROM_DATABASE=Opal-RT Technologies Inc.
@@ -55940,6 +56687,27 @@ pci:v00001BB0d00000002*
pci:v00001BB0d00000010*
ID_MODEL_FROM_DATABASE=OmniCube Accelerator OA-3000-2
+pci:v00001BB1*
+ ID_VENDOR_FROM_DATABASE=Seagate Technology PLC
+
+pci:v00001BB1d0000005D*
+ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage
+
+pci:v00001BB1d0000005Dsv00001BB1sd00006501*
+ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XP6500-8A1536 1.5TB)
+
+pci:v00001BB1d0000005Dsv00001BB1sd00006502*
+ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XP6500-8A2048)
+
+pci:v00001BB1d0000005Dsv00001BB1sd00006503*
+ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XP6500-8A4096)
+
+pci:v00001BB1d0000005Dsv00001BB1sd00006511*
+ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XH6550-2GB DRAM)
+
+pci:v00001BB1d0000005Dsv00001BB1sd00006512*
+ ID_MODEL_FROM_DATABASE=Nytro PCIe Flash Storage (Nytro XH6550-8GB DRAM)
+
pci:v00001BB3*
ID_VENDOR_FROM_DATABASE=Bluecherry
@@ -55997,6 +56765,18 @@ pci:v00001BF4d00000001*
pci:v00001BFD*
ID_VENDOR_FROM_DATABASE=EeeTOP
+pci:v00001C09*
+ ID_VENDOR_FROM_DATABASE=CSP, Inc.
+
+pci:v00001C09d00004254*
+ ID_MODEL_FROM_DATABASE=10G-PCIE3-8D-2S
+
+pci:v00001C09d00004255*
+ ID_MODEL_FROM_DATABASE=10G-PCIE3-8D-Q
+
+pci:v00001C09d00004256*
+ ID_MODEL_FROM_DATABASE=10G-PCIE3-8D-2S
+
pci:v00001C1C*
ID_VENDOR_FROM_DATABASE=Symphony
@@ -56060,6 +56840,12 @@ pci:v00001C44*
pci:v00001C44d00008000*
ID_MODEL_FROM_DATABASE=8000 Storage IO Controller
+pci:v00001C58*
+ ID_VENDOR_FROM_DATABASE=HGST, Inc.
+
+pci:v00001C58d00000003*
+ ID_MODEL_FROM_DATABASE=Ultrastar SN100 Series NVMe SSD
+
pci:v00001C7E*
ID_VENDOR_FROM_DATABASE=TTTech Computertechnik AG
@@ -56117,6 +56903,9 @@ pci:v00001D26d00000040*
pci:v00001D26d0000E004*
ID_MODEL_FROM_DATABASE=AB01/EMB01 Development Board
+pci:v00001D40*
+ ID_VENDOR_FROM_DATABASE=Techman Electronics (Changshu) Co., Ltd.
+
pci:v00001D44*
ID_VENDOR_FROM_DATABASE=DPT
@@ -56231,6 +57020,15 @@ pci:v00001FC9d00003314sv00000000sd00003012*
pci:v00001FC9d00003314sv00000000sd00003014*
ID_MODEL_FROM_DATABASE=10-Giga TOE Dual Port Low Profile SmartNIC (10-Giga TOE Dual Port CX4 Low Profile SmartNIC)
+pci:v00001FCC*
+ ID_VENDOR_FROM_DATABASE=StreamLabs
+
+pci:v00001FCCd0000F416*
+ ID_MODEL_FROM_DATABASE=MS416
+
+pci:v00001FCCd0000FB01*
+ ID_MODEL_FROM_DATABASE=MH4LM
+
pci:v00001FCE*
ID_VENDOR_FROM_DATABASE=Cognio Inc.
@@ -56729,6 +57527,30 @@ pci:v00004254*
pci:v00004321*
ID_VENDOR_FROM_DATABASE=Tata Power Strategic Electronics Division
+pci:v00004348*
+ ID_VENDOR_FROM_DATABASE=WCH.CN
+
+pci:v00004348d00002273*
+ ID_MODEL_FROM_DATABASE=CH351 PCI Dual Serial Port Controller
+
+pci:v00004348d00003253*
+ ID_MODEL_FROM_DATABASE=CH352 PCI Dual Serial Port Controller
+
+pci:v00004348d00003453*
+ ID_MODEL_FROM_DATABASE=CH353 PCI Quad Serial Port Controller
+
+pci:v00004348d00005053*
+ ID_MODEL_FROM_DATABASE=CH352 PCI Serial and Parallel Port Controller
+
+pci:v00004348d00007053*
+ ID_MODEL_FROM_DATABASE=CH353 PCI Dual Serial and Parallel Ports Controller
+
+pci:v00004348d00007073*
+ ID_MODEL_FROM_DATABASE=CH356 PCI Quad Serial and Parallel Ports Controller
+
+pci:v00004348d00007173*
+ ID_MODEL_FROM_DATABASE=CH355 PCI Quad Serial Port Controller
+
pci:v0000434E*
ID_VENDOR_FROM_DATABASE=CAST Navigation LLC
@@ -57791,6 +58613,9 @@ pci:v00005853*
pci:v00005853d00000001*
ID_MODEL_FROM_DATABASE=Xen Platform Device
+pci:v00005853d0000C000*
+ ID_MODEL_FROM_DATABASE=Citrix XenServer PCI Device for Windows Update
+
pci:v00005853d0000C110*
ID_MODEL_FROM_DATABASE=Virtualized HID
@@ -57905,6 +58730,9 @@ pci:v00007401*
pci:v00007401d0000E100*
ID_MODEL_FROM_DATABASE=PTP3100 PCIe PTP Slave Clock
+pci:v00007470*
+ ID_VENDOR_FROM_DATABASE=TP-LINK Technologies Co., Ltd.
+
pci:v00007604*
ID_VENDOR_FROM_DATABASE=O.N. Electronic Co Ltd.
@@ -58434,13 +59262,13 @@ pci:v00008086d00000341*
ID_MODEL_FROM_DATABASE=41210 [Lanai] Serial to Parallel PCI Bridge (B-Segment Bridge)
pci:v00008086d00000370*
- ID_MODEL_FROM_DATABASE=80333 Segment-A PCI Express-to-PCI Express Bridge
+ ID_MODEL_FROM_DATABASE=80333 Segment-A PCIe Express to PCI-X bridge
pci:v00008086d00000371*
ID_MODEL_FROM_DATABASE=80333 A-Bus IOAPIC
pci:v00008086d00000372*
- ID_MODEL_FROM_DATABASE=80333 Segment-B PCI Express-to-PCI Express Bridge
+ ID_MODEL_FROM_DATABASE=80333 Segment-B PCIe Express to PCI-X bridge
pci:v00008086d00000373*
ID_MODEL_FROM_DATABASE=80333 B-Bus IOAPIC
@@ -58472,11 +59300,11 @@ pci:v00008086d0000041A*
pci:v00008086d0000041E*
ID_MODEL_FROM_DATABASE=4th Generation Core Processor Family Integrated Graphics Controller
-pci:v00008086d00000433*
- ID_MODEL_FROM_DATABASE=Coleto Creek ACC - ME/CPM interface
+pci:v00008086d00000434*
+ ID_MODEL_FROM_DATABASE=DH89XXCC Series QAT
pci:v00008086d00000435*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCIe Endpoint
+ ID_MODEL_FROM_DATABASE=DH895XCC Series QAT
pci:v00008086d00000436*
ID_MODEL_FROM_DATABASE=DH8900CC Null Device
@@ -58493,6 +59321,12 @@ pci:v00008086d0000043C*
pci:v00008086d00000440*
ID_MODEL_FROM_DATABASE=DH8900CC Series Gigabit SFP Network Connection
+pci:v00008086d00000442*
+ ID_MODEL_FROM_DATABASE=DH89XXCC Series QAT Virtual Function
+
+pci:v00008086d00000443*
+ ID_MODEL_FROM_DATABASE=DH895XCC Series QAT Virtual Function
+
pci:v00008086d00000482*
ID_MODEL_FROM_DATABASE=82375EB/SB PCI to EISA Bridge
@@ -59432,6 +60266,18 @@ pci:v00008086d00000C49*
pci:v00008086d00000C4E*
ID_MODEL_FROM_DATABASE=Atom Processor S1200 NTB Primary
+pci:v00008086d00000C50*
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QuickData Technology Device
+
+pci:v00008086d00000C51*
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QuickData Technology Device
+
+pci:v00008086d00000C52*
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QuickData Technology Device
+
+pci:v00008086d00000C53*
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QuickData Technology Device
+
pci:v00008086d00000C54*
ID_MODEL_FROM_DATABASE=Atom Processor S1200 Internal
@@ -62285,6 +63131,9 @@ pci:v00008086d00001521sv0000103Csd00003380*
pci:v00008086d00001521sv0000103Csd0000339E*
ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Ethernet 1Gb 2-port 361T Adapter)
+pci:v00008086d00001521sv0000103Csd00008157*
+ ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Ethernet 1Gb 4-port 366T Adapter)
+
pci:v00008086d00001521sv0000108Esd00007B16*
ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (Quad Port GbE PCIe 2.0 ExpressModule, UTP)
@@ -62420,6 +63269,9 @@ pci:v00008086d00001528sv0000103Csd00002004*
pci:v00008086d00001528sv0000103Csd0000211A*
ID_MODEL_FROM_DATABASE=Ethernet Controller 10-Gigabit X540-AT2 (Ethernet 10Gb 2-port 561T Adapter)
+pci:v00008086d00001528sv0000108Esd00004853*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller 10-Gigabit X540-AT2
+
pci:v00008086d00001528sv0000108Esd00007B14*
ID_MODEL_FROM_DATABASE=Ethernet Controller 10-Gigabit X540-AT2 (Sun Dual Port 10 GbE PCIe 2.0 ExpressModule, Base-T)
@@ -62450,6 +63302,9 @@ pci:v00008086d00001528sv00008086sd00001F61*
pci:v00008086d00001528sv00008086sd00005003*
ID_MODEL_FROM_DATABASE=Ethernet Controller 10-Gigabit X540-AT2 (Ethernet 10G 2P X540-t Adapter)
+pci:v00008086d00001528sv00008086sd00005004*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller 10-Gigabit X540-AT2 (Ethernet 10G 2P X540-t Adapter)
+
pci:v00008086d00001529*
ID_MODEL_FROM_DATABASE=82599 10 Gigabit Dual Port Network Connection with FCoE
@@ -62588,6 +63443,18 @@ pci:v00008086d00001572*
pci:v00008086d00001572sv00001028sd00001F99*
ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet 10G 4P X710/I350 rNDC)
+pci:v00008086d00001572sv0000103Csd000022FC*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (HP Ethernet 10Gb 2-port 562FLR-SFP+ Adapter)
+
+pci:v00008086d00001572sv0000103Csd000022FD*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (HP Ethernet 10Gb 2-port 562SFP+ Adapter)
+
+pci:v00008086d00001572sv00001137sd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Converged NIC X710-4)
+
+pci:v00008086d00001572sv00001137sd0000013B*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Converged NIC X710-4)
+
pci:v00008086d00001572sv000017AAsd00000000*
ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (ThinkServer XL710 AnyFabric)
@@ -62618,6 +63485,21 @@ pci:v00008086d00001572sv00008086sd00000007*
pci:v00008086d00001572sv00008086sd00000008*
ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Converged Network Adapter X710-2)
+pci:v00008086d00001572sv00008086sd00000009*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+
+
+pci:v00008086d00001572sv00008086sd0000000A*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+
+
+pci:v00008086d00001572sv00008086sd0000000D*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+
+
+pci:v00008086d00001572sv00008086sd00004005*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Controller XL710 for 10 Gigabit SFP+)
+
+pci:v00008086d00001572sv00008086sd00004006*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+
+
pci:v00008086d0000157B*
ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection
@@ -62636,6 +63518,24 @@ pci:v00008086d00001581sv00001028sd00001F98*
pci:v00008086d00001583*
ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+
+pci:v00008086d00001583sv00001028sd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet 40G 2P XL710 QSFP+ rNDC)
+
+pci:v00008086d00001583sv00001028sd00001F9F*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet 40G 2P XL710 QSFP+ rNDC)
+
+pci:v00008086d00001583sv0000108Esd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Oracle 10 Gb and 40 Gb Ethernet Adapter)
+
+pci:v00008086d00001583sv0000108Esd00007B1B*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Oracle 10 Gb and 40 Gb Ethernet Adapter)
+
+pci:v00008086d00001583sv00001137sd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged NIC XL710-Q2)
+
+pci:v00008086d00001583sv00001137sd0000013C*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged NIC XL710-Q2)
+
pci:v00008086d00001583sv00008086sd00000000*
ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged Network Adapter XL710-Q2)
@@ -62648,6 +63548,9 @@ pci:v00008086d00001583sv00008086sd00000002*
pci:v00008086d00001583sv00008086sd00000003*
ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet I/O Module XL710-Q2)
+pci:v00008086d00001583sv00008086sd00000006*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet Converged Network Adapter XL710-Q2)
+
pci:v00008086d00001584*
ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+
@@ -62664,7 +63567,49 @@ pci:v00008086d00001584sv00008086sd00000003*
ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 40GbE QSFP+ (Ethernet I/O Module XL710-Q1)
pci:v00008086d00001585*
- ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 10GbE QSFP+
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE QSFP+
+
+pci:v00008086d00001586*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T
+
+pci:v00008086d00001586sv0000108Esd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T
+
+pci:v00008086d00001586sv0000108Esd00004857*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T
+
+pci:v00008086d00001587*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane
+
+pci:v00008086d00001587sv0000103Csd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane (HP Flex-20 20Gb 2-port 660FLB Adapter)
+
+pci:v00008086d00001587sv0000103Csd000022FE*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane (HP Flex-20 20Gb 2-port 660FLB Adapter)
+
+pci:v00008086d00001587sv0000103Csd000022FF*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane (HP Flex-20 20Gb 2-port 660M Adapter)
+
+pci:v00008086d00001588*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane
+
+pci:v00008086d00001588sv0000103Csd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane (HP Flex-20 20Gb 2-port 660M Adapter)
+
+pci:v00008086d00001588sv0000103Csd000022FF*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XL710 for 20GbE backplane (HP Flex-20 20Gb 2-port 660M Adapter)
+
+pci:v00008086d00001589*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710/X557-AT 10GBASE-T
+
+pci:v00008086d00001589sv00008086sd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710/X557-AT 10GBASE-T (Ethernet Converged Network Adapter X710-T)
+
+pci:v00008086d00001589sv00008086sd00000001*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710/X557-AT 10GBASE-T (Ethernet Converged Network Adapter X710-T4)
+
+pci:v00008086d00001589sv00008086sd00000002*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710/X557-AT 10GBASE-T (Ethernet Converged Network Adapter X710-T4)
pci:v00008086d000015A0*
ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I218-LM
@@ -62759,6 +63704,9 @@ pci:v00008086d00001614*
pci:v00008086d00001616*
ID_MODEL_FROM_DATABASE=Broadwell-U Integrated Graphics
+pci:v00008086d00001616sv0000103Csd00002216*
+ ID_MODEL_FROM_DATABASE=Broadwell-U Integrated Graphics (ZBook 15u G2 Mobile Workstation)
+
pci:v00008086d00001618*
ID_MODEL_FROM_DATABASE=Broadwell-U Host Bridge - DMI
@@ -62963,6 +63911,9 @@ pci:v00008086d00001A30*
pci:v00008086d00001A30sv00001028sd0000010E*
ID_MODEL_FROM_DATABASE=82845 845 [Brookdale] Chipset Host Bridge (Optiplex GX240)
+pci:v00008086d00001A30sv0000147Bsd00000505*
+ ID_MODEL_FROM_DATABASE=82845 845 [Brookdale] Chipset Host Bridge (BL7 motherboard)
+
pci:v00008086d00001A30sv000015D9sd00003280*
ID_MODEL_FROM_DATABASE=82845 845 [Brookdale] Chipset Host Bridge (Supermicro P4SBE Mainboard)
@@ -63972,10 +64923,10 @@ pci:v00008086d00001F16*
ID_MODEL_FROM_DATABASE=Atom processor C2000 RCEC
pci:v00008086d00001F18*
- ID_MODEL_FROM_DATABASE=Atom processor C2000 nCPM
+ ID_MODEL_FROM_DATABASE=Atom processor C2000 QAT
pci:v00008086d00001F19*
- ID_MODEL_FROM_DATABASE=Atom processor C2000 nCPM
+ ID_MODEL_FROM_DATABASE=Atom processor C2000 QAT
pci:v00008086d00001F20*
ID_MODEL_FROM_DATABASE=Atom processor C2000 4-Port IDE SATA2 Controller
@@ -64248,64 +65199,64 @@ pci:v00008086d00002365*
ID_MODEL_FROM_DATABASE=DH89xxCC MEI 1
pci:v00008086d00002390*
- ID_MODEL_FROM_DATABASE=Coleto Creek LPC Controller
+ ID_MODEL_FROM_DATABASE=DH895XCC Series LPC Controller
pci:v00008086d000023A1*
- ID_MODEL_FROM_DATABASE=Coleto Creek 2-Port SATA Controller [IDE Mode]
+ ID_MODEL_FROM_DATABASE=DH895XCC Series 2-Port SATA Controller [IDE Mode]
pci:v00008086d000023A3*
- ID_MODEL_FROM_DATABASE=Coleto Creek 4-Port SATA Controller [AHCI Mode]
+ ID_MODEL_FROM_DATABASE=DH895XCC Series 4-Port SATA Controller [AHCI Mode]
pci:v00008086d000023A6*
- ID_MODEL_FROM_DATABASE=Coleto Creek 2-Port SATA Controller [IDE Mode]
+ ID_MODEL_FROM_DATABASE=DH895XCC Series 2-Port SATA Controller [IDE Mode]
pci:v00008086d000023B0*
- ID_MODEL_FROM_DATABASE=Coleto Creek SMBus Controller
+ ID_MODEL_FROM_DATABASE=DH895XCC Series SMBus Controller
pci:v00008086d000023B1*
- ID_MODEL_FROM_DATABASE=Coleto Creek CHAP Counter
+ ID_MODEL_FROM_DATABASE=DH895XCC Series CHAP Counter
pci:v00008086d000023B2*
- ID_MODEL_FROM_DATABASE=Coleto Creek Thermal Management Controller
+ ID_MODEL_FROM_DATABASE=DH895XCC Series Thermal Management Controller
pci:v00008086d000023B4*
- ID_MODEL_FROM_DATABASE=Coleto Creek USB2 Enhanced Host Controller #1
+ ID_MODEL_FROM_DATABASE=DH895XCC Series USB2 Enhanced Host Controller #1
pci:v00008086d000023B5*
- ID_MODEL_FROM_DATABASE=Coleto Creek USB2 Enhanced Host Controller #1
+ ID_MODEL_FROM_DATABASE=DH895XCC Series USB2 Enhanced Host Controller #1
pci:v00008086d000023C2*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #1
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #1
pci:v00008086d000023C3*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #1
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #1
pci:v00008086d000023C4*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #2
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #2
pci:v00008086d000023C5*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #2
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #2
pci:v00008086d000023C6*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #3
+ ID_MODEL_FROM_DATABASE=CDH895XCC Series PCI Express Root Port #3
pci:v00008086d000023C7*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #3
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #3
pci:v00008086d000023C8*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #4
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #4
pci:v00008086d000023C9*
- ID_MODEL_FROM_DATABASE=Coleto Creek PCI Express Root Port #4
+ ID_MODEL_FROM_DATABASE=DH895XCC Series PCI Express Root Port #4
pci:v00008086d000023E0*
- ID_MODEL_FROM_DATABASE=Coleto Creek Watchdog Timer
+ ID_MODEL_FROM_DATABASE=DH895XCC Series Watchdog Timer
pci:v00008086d000023E4*
- ID_MODEL_FROM_DATABASE=Coleto Creek MEI Controller #1
+ ID_MODEL_FROM_DATABASE=DH895XCC Series MEI Controller #1
pci:v00008086d000023E5*
- ID_MODEL_FROM_DATABASE=Coleto Creek MEI Controller #2
+ ID_MODEL_FROM_DATABASE=DH895XCC Series MEI Controller #2
pci:v00008086d00002410*
ID_MODEL_FROM_DATABASE=82801AA ISA Bridge (LPC)
@@ -64386,43 +65337,46 @@ pci:v00008086d00002440sv00008086sd00005744*
ID_MODEL_FROM_DATABASE=82801BA ISA Bridge (LPC) (S845WD1-E)
pci:v00008086d00002442*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1
pci:v00008086d00002442sv00001014sd000001C6*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Netvista A40/A40p)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Netvista A40/A40p)
pci:v00008086d00002442sv00001025sd00001016*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Travelmate 612 TX)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Travelmate 612 TX)
pci:v00008086d00002442sv00001028sd000000C7*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Dimension 8100)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Dimension 8100)
pci:v00008086d00002442sv00001028sd000000D8*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Precision 530)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Precision 530)
pci:v00008086d00002442sv00001028sd0000010E*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Optiplex GX240)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Optiplex GX240)
pci:v00008086d00002442sv0000103Csd0000126F*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (e-pc 40)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (e-pc 40)
pci:v00008086d00002442sv00001043sd00008027*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (TUSL2-C Mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (TUSL2-C Mainboard)
pci:v00008086d00002442sv0000104Dsd000080DF*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Vaio PCG-FX403)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Vaio PCG-FX403)
+
+pci:v00008086d00002442sv0000147Bsd00000505*
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (BL7 motherboard)
pci:v00008086d00002442sv0000147Bsd00000507*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (TH7II-RAID)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (TH7II-RAID)
pci:v00008086d00002442sv00008086sd00004532*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (D815EEA2 mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (D815EEA2 mainboard)
pci:v00008086d00002442sv00008086sd00004557*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (D815EGEW Mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (D815EGEW Mainboard)
pci:v00008086d00002442sv00008086sd00005744*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (S845WD1-E mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (S845WD1-E mainboard)
pci:v00008086d00002443*
ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller
@@ -64451,6 +65405,9 @@ pci:v00008086d00002443sv00001043sd00008027*
pci:v00008086d00002443sv0000104Dsd000080DF*
ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (Vaio PCG-FX403)
+pci:v00008086d00002443sv0000147Bsd00000505*
+ ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (BL7 motherboard)
+
pci:v00008086d00002443sv0000147Bsd00000507*
ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (TH7II-RAID)
@@ -64467,37 +65424,40 @@ pci:v00008086d00002443sv00008086sd00005744*
ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (S845WD1-E mainboard)
pci:v00008086d00002444*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2
pci:v00008086d00002444sv00001025sd00001016*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Travelmate 612 TX)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (Travelmate 612 TX)
pci:v00008086d00002444sv00001028sd000000C7*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Dimension 8100)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (Dimension 8100)
pci:v00008086d00002444sv00001028sd000000D8*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Precision 530)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (Precision 530)
pci:v00008086d00002444sv00001028sd0000010E*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Optiplex GX240)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (Optiplex GX240)
pci:v00008086d00002444sv0000103Csd0000126F*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (e-pc 40)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (e-pc 40)
pci:v00008086d00002444sv00001043sd00008027*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (TUSL2-C Mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (TUSL2-C Mainboard)
pci:v00008086d00002444sv0000104Dsd000080DF*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (Vaio PCG-FX403)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (Vaio PCG-FX403)
+
+pci:v00008086d00002444sv0000147Bsd00000505*
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (BL7 motherboard)
pci:v00008086d00002444sv0000147Bsd00000507*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (TH7II-RAID)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (TH7II-RAID)
pci:v00008086d00002444sv00008086sd00004532*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (D815EEA2 mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (D815EEA2 mainboard)
pci:v00008086d00002444sv00008086sd00005744*
- ID_MODEL_FROM_DATABASE=82801BA/BAM USB Controller #1 (S845WD1-E mainboard)
+ ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (S845WD1-E mainboard)
pci:v00008086d00002445*
ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller
@@ -64526,6 +65486,9 @@ pci:v00008086d00002445sv0000104Dsd000080DF*
pci:v00008086d00002445sv00001462sd00003370*
ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (STAC9721 AC)
+pci:v00008086d00002445sv0000147Bsd00000505*
+ ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (BL7 motherboard)
+
pci:v00008086d00002445sv0000147Bsd00000507*
ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (TH7II-RAID)
@@ -64727,6 +65690,9 @@ pci:v00008086d0000244Bsv0000103Csd0000126F*
pci:v00008086d0000244Bsv00001043sd00008027*
ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (TUSL2-C Mainboard)
+pci:v00008086d0000244Bsv0000147Bsd00000505*
+ ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (BL7 motherboard)
+
pci:v00008086d0000244Bsv0000147Bsd00000507*
ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (TH7II-RAID)
@@ -65006,6 +65972,9 @@ pci:v00008086d000024C2sv00001014sd0000052D*
pci:v00008086d000024C2sv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (TravelMate 290)
+pci:v00008086d000024C2sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024C2sv00001028sd00000126*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (Optiplex GX260)
@@ -65081,6 +66050,9 @@ pci:v00008086d000024C3sv00001014sd0000052D*
pci:v00008086d000024C3sv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller (TravelMate 290)
+pci:v00008086d000024C3sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024C3sv00001028sd00000126*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller (Optiplex GX260)
@@ -65144,6 +66116,9 @@ pci:v00008086d000024C4sv00001014sd0000052D*
pci:v00008086d000024C4sv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (TravelMate 290)
+pci:v00008086d000024C4sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024C4sv00001028sd00000126*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (Optiplex GX260)
@@ -65216,6 +66191,9 @@ pci:v00008086d000024C5sv00001014sd0000055F*
pci:v00008086d000024C5sv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (TravelMate 290)
+pci:v00008086d000024C5sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024C5sv00001028sd00000139*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Latitude D400)
@@ -65294,6 +66272,9 @@ pci:v00008086d000024C6sv00001025sd0000003C*
pci:v00008086d000024C6sv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller (TravelMate 290)
+pci:v00008086d000024C6sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024C6sv00001028sd00000196*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller (Inspiron 5160)
@@ -65339,6 +66320,9 @@ pci:v00008086d000024C7sv00001014sd0000052D*
pci:v00008086d000024C7sv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (TravelMate 290)
+pci:v00008086d000024C7sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024C7sv00001028sd00000126*
ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (Optiplex GX260)
@@ -65402,6 +66386,9 @@ pci:v00008086d000024CAsv00001014sd0000052D*
pci:v00008086d000024CAsv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DBM (ICH4-M) IDE Controller (TravelMate 290)
+pci:v00008086d000024CAsv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DBM (ICH4-M) IDE Controller (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024CAsv00001028sd0000014F*
ID_MODEL_FROM_DATABASE=82801DBM (ICH4-M) IDE Controller (Latitude X300)
@@ -65492,6 +66479,9 @@ pci:v00008086d000024CDsv00001014sd0000052E*
pci:v00008086d000024CDsv00001025sd0000005A*
ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller (TravelMate 290)
+pci:v00008086d000024CDsv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller (Extensa 3000 series laptop: Intel 82801DBM (ICH4-M))
+
pci:v00008086d000024CDsv00001028sd0000011D*
ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller (Latitude D600)
@@ -68663,6 +69653,9 @@ pci:v00008086d00002822sv00001028sd0000020D*
pci:v00008086d00002822sv0000103Csd00002A6F*
ID_MODEL_FROM_DATABASE=SATA Controller [RAID mode] (Asus IPIBL-LB Motherboard)
+pci:v00008086d00002822sv00001043sd00008277*
+ ID_MODEL_FROM_DATABASE=SATA Controller [RAID mode] (P5K PRO Motherboard)
+
pci:v00008086d00002823*
ID_MODEL_FROM_DATABASE=C610/X99 series chipset sSATA Controller [RAID mode]
@@ -69350,6 +70343,9 @@ pci:v00008086d00002921sv00001462sd00007360*
pci:v00008086d00002922*
ID_MODEL_FROM_DATABASE=82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]
+pci:v00008086d00002922sv00001043sd00008277*
+ ID_MODEL_FROM_DATABASE=82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] (P5K PRO Motherboard)
+
pci:v00008086d00002922sv00001AF4sd00001100*
ID_MODEL_FROM_DATABASE=82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] (QEMU Virtual Machine)
@@ -70758,13 +71754,13 @@ pci:v00008086d00002D10*
ID_MODEL_FROM_DATABASE=Core Processor QPI Link 0
pci:v00008086d00002D11*
- ID_MODEL_FROM_DATABASE=1st Generation Core Processor QPI Physical 0
+ ID_MODEL_FROM_DATABASE=1st Generation Core i3/5/7 Processor QPI Physical 0
pci:v00008086d00002D12*
- ID_MODEL_FROM_DATABASE=1st Generation Core Processor Reserved
+ ID_MODEL_FROM_DATABASE=1st Generation Core i3/5/7 Processor Reserved
pci:v00008086d00002D13*
- ID_MODEL_FROM_DATABASE=1st Generation Core Processor Reserved
+ ID_MODEL_FROM_DATABASE=1st Generation Core i3/5/7 Processor Reserved
pci:v00008086d00002D81*
ID_MODEL_FROM_DATABASE=Xeon 5600 Series QuickPath Architecture System Address Decoder
@@ -71873,6 +72869,9 @@ pci:v00008086d00003580*
pci:v00008086d00003580sv00001014sd0000055C*
ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (ThinkPad R50e)
+pci:v00008086d00003580sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (Extensa 3000 series laptop)
+
pci:v00008086d00003580sv00001028sd00000139*
ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (Latitude D400)
@@ -71969,6 +72968,9 @@ pci:v00008086d00003584*
pci:v00008086d00003584sv00001014sd0000055D*
ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (ThinkPad R50e)
+pci:v00008086d00003584sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (Extensa 3000 series laptop)
+
pci:v00008086d00003584sv00001028sd00000139*
ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (Latitude D400)
@@ -72011,6 +73013,9 @@ pci:v00008086d00003585*
pci:v00008086d00003585sv00001014sd0000055E*
ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (ThinkPad R50e)
+pci:v00008086d00003585sv00001025sd00000064*
+ ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (Extensa 3000 series laptop)
+
pci:v00008086d00003585sv00001028sd00000139*
ID_MODEL_FROM_DATABASE=82852/82855 GM/GME/PM/GMV Processor to I/O Controller (Latitude D400)
@@ -73500,7 +74505,7 @@ pci:v00008086d00004220sv0000103Csd000012F6*
ID_MODEL_FROM_DATABASE=PRO/Wireless 2200BG [Calexico2] Network Connection (nc6120/nx8220/nw8240)
pci:v00008086d00004220sv00008086sd00002701*
- ID_MODEL_FROM_DATABASE=PRO/Wireless 2200BG [Calexico2] Network Connection (WM3B2300BG Mini-PCI Card)
+ ID_MODEL_FROM_DATABASE=PRO/Wireless 2200BG [Calexico2] Network Connection (WM3B2200BG Mini-PCI Card)
pci:v00008086d00004220sv00008086sd00002712*
ID_MODEL_FROM_DATABASE=PRO/Wireless 2200BG [Calexico2] Network Connection (IBM ThinkPad R50e)
@@ -73977,487 +74982,487 @@ pci:v00008086d000065FF*
ID_MODEL_FROM_DATABASE=5100 Chipset DMA Engine
pci:v00008086d00006F00*
- ID_MODEL_FROM_DATABASE=Broadwell DMI2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DMI2
pci:v00008086d00006F01*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 0
pci:v00008086d00006F02*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 1
pci:v00008086d00006F03*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 1
pci:v00008086d00006F04*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 2
pci:v00008086d00006F05*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 2
pci:v00008086d00006F06*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 2
pci:v00008086d00006F07*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 2
pci:v00008086d00006F08*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 3
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 3
pci:v00008086d00006F09*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 3
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 3
pci:v00008086d00006F0A*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 3
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 3
pci:v00008086d00006F0B*
- ID_MODEL_FROM_DATABASE=Broadwell PCI Express Root Port 3
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family PCI Express Root Port 3
pci:v00008086d00006F10*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F11*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F12*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F13*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F14*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F15*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F16*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F17*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F18*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F19*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F1A*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F1B*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F1C*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Debug
pci:v00008086d00006F1D*
- ID_MODEL_FROM_DATABASE=Broadwell R2PCIe Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R2PCIe Agent
pci:v00008086d00006F1E*
- ID_MODEL_FROM_DATABASE=Broadwell Ubox
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Ubox
pci:v00008086d00006F1F*
- ID_MODEL_FROM_DATABASE=Broadwell Ubox
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Ubox
pci:v00008086d00006F20*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 0
pci:v00008086d00006F21*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 1
pci:v00008086d00006F22*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 2
pci:v00008086d00006F23*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 3
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 3
pci:v00008086d00006F24*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 4
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 4
pci:v00008086d00006F25*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 5
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 5
pci:v00008086d00006F26*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 6
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 6
pci:v00008086d00006F27*
- ID_MODEL_FROM_DATABASE=Broadwell-DE Crystal Beach DMA Channel 7
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Crystal Beach DMA Channel 7
pci:v00008086d00006F28*
- ID_MODEL_FROM_DATABASE=Broadwell Adress Map/VTd_Misc/System Management
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Map/VTd_Misc/System Management
pci:v00008086d00006F29*
- ID_MODEL_FROM_DATABASE=Broadwell IIO Hot Plug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO Hot Plug
pci:v00008086d00006F2A*
- ID_MODEL_FROM_DATABASE=Broadwell IIO RAS/Control Status/Global Errors
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IIO RAS/Control Status/Global Errors
pci:v00008086d00006F2C*
- ID_MODEL_FROM_DATABASE=Broadwell I/O APIC
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family I/O APIC
pci:v00008086d00006F30*
- ID_MODEL_FROM_DATABASE=Broadwell Home Agent 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Home Agent 0
pci:v00008086d00006F32*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 0
pci:v00008086d00006F33*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 1
pci:v00008086d00006F34*
- ID_MODEL_FROM_DATABASE=Broadwell R2PCIe Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R2PCIe Agent
pci:v00008086d00006F36*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link 0/1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link 0/1
pci:v00008086d00006F37*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link 0/1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link 0/1
pci:v00008086d00006F38*
- ID_MODEL_FROM_DATABASE=Broadwell Home Agent 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Home Agent 1
pci:v00008086d00006F39*
- ID_MODEL_FROM_DATABASE=Broadwell IO Performance Monitoring
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family IO Performance Monitoring
pci:v00008086d00006F3A*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 2
pci:v00008086d00006F3E*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link 2
pci:v00008086d00006F3F*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link 2
pci:v00008086d00006F40*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 2
pci:v00008086d00006F41*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link 2
pci:v00008086d00006F43*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 2
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 2
pci:v00008086d00006F45*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 2 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 2 Debug
pci:v00008086d00006F46*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 2 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 2 Debug
pci:v00008086d00006F47*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 2 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 2 Debug
pci:v00008086d00006F60*
- ID_MODEL_FROM_DATABASE=Broadwell Home Agent 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Home Agent 1
pci:v00008086d00006F68*
- ID_MODEL_FROM_DATABASE=Broadwell Target Address/Thermal/RAS
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Target Address/Thermal/RAS
pci:v00008086d00006F6A*
- ID_MODEL_FROM_DATABASE=Broadwell Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Channel Target Address Decoder
pci:v00008086d00006F6B*
- ID_MODEL_FROM_DATABASE=Broadwell Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Channel Target Address Decoder
pci:v00008086d00006F6C*
- ID_MODEL_FROM_DATABASE=Broadwell Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Channel Target Address Decoder
pci:v00008086d00006F6D*
- ID_MODEL_FROM_DATABASE=Broadwell Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Channel Target Address Decoder
pci:v00008086d00006F6E*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 2/3 Broadcast
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 2/3 Broadcast
pci:v00008086d00006F6F*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Global Broadcast
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Global Broadcast
pci:v00008086d00006F70*
- ID_MODEL_FROM_DATABASE=Broadwell Home Agent 0 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Home Agent 0 Debug
pci:v00008086d00006F71*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Target Address/Thermal/RAS
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Target Address/Thermal/RAS
pci:v00008086d00006F76*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link Debug
pci:v00008086d00006F78*
- ID_MODEL_FROM_DATABASE=Broadwell Home Agent 1 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Home Agent 1 Debug
pci:v00008086d00006F79*
- ID_MODEL_FROM_DATABASE=Broadwell Target Address/Thermal/RAS
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Target Address/Thermal/RAS
pci:v00008086d00006F7D*
- ID_MODEL_FROM_DATABASE=Broadwell Ubox
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Ubox
pci:v00008086d00006F7E*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link Debug
pci:v00008086d00006F80*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 0
pci:v00008086d00006F81*
- ID_MODEL_FROM_DATABASE=Broadwell R3 QPI Link 0/1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family R3 QPI Link 0/1
pci:v00008086d00006F83*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 0
pci:v00008086d00006F85*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 0 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 0 Debug
pci:v00008086d00006F86*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 0 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 0 Debug
pci:v00008086d00006F87*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 0 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 0 Debug
pci:v00008086d00006F88*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006F8A*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006F90*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 1
pci:v00008086d00006F93*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 1
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 1
pci:v00008086d00006F95*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 1 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 1 Debug
pci:v00008086d00006F96*
- ID_MODEL_FROM_DATABASE=Broadwell QPI Link 1 Debug
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family QPI Link 1 Debug
pci:v00008086d00006F98*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006F99*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006F9A*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006F9C*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FA0*
- ID_MODEL_FROM_DATABASE=Broadwell Home Agent 0
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Home Agent 0
pci:v00008086d00006FA8*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Target Address/Thermal/RAS
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Target Address/Thermal/RAS
pci:v00008086d00006FAA*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel Target Address Decoder
pci:v00008086d00006FAB*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel Target Address Decoder
pci:v00008086d00006FAC*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel Target Address Decoder
pci:v00008086d00006FAD*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel Target Address Decoder
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel Target Address Decoder
pci:v00008086d00006FAE*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 0/1 Broadcast
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 0/1 Broadcast
pci:v00008086d00006FAF*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Global Broadcast
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Global Broadcast
pci:v00008086d00006FB0*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 0 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 0 Thermal Control
pci:v00008086d00006FB1*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 1 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 1 Thermal Control
pci:v00008086d00006FB2*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 0 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 0 Error
pci:v00008086d00006FB3*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 1 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 1 Error
pci:v00008086d00006FB4*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 2 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 2 Thermal Control
pci:v00008086d00006FB5*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 3 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 3 Thermal Control
pci:v00008086d00006FB6*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 2 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 2 Error
pci:v00008086d00006FB7*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 0 - Channel 3 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 0 - Channel 3 Error
pci:v00008086d00006FB8*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 2/3 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 2/3 Interface
pci:v00008086d00006FB9*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 2/3 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 2/3 Interface
pci:v00008086d00006FBA*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 2/3 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 2/3 Interface
pci:v00008086d00006FBB*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 2/3 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 2/3 Interface
pci:v00008086d00006FBC*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 0/1 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 0/1 Interface
pci:v00008086d00006FBD*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 0/1 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 0/1 Interface
pci:v00008086d00006FBE*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 0/1 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 0/1 Interface
pci:v00008086d00006FBF*
- ID_MODEL_FROM_DATABASE=Broadwell DDRIO Channel 0/1 Interface
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family DDRIO Channel 0/1 Interface
pci:v00008086d00006FC0*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC1*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC2*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC3*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC4*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC5*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC6*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC7*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC8*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FC9*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FCA*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FCB*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FCC*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FCD*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FCE*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FCF*
- ID_MODEL_FROM_DATABASE=Broadwell Power Control Unit
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Power Control Unit
pci:v00008086d00006FD0*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 0 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 0 Thermal Control
pci:v00008086d00006FD1*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 1 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 1 Thermal Control
pci:v00008086d00006FD2*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 0 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 0 Error
pci:v00008086d00006FD3*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 1 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 1 Error
pci:v00008086d00006FD4*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 2 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 2 Thermal Control
pci:v00008086d00006FD5*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 3 Thermal Control
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 3 Thermal Control
pci:v00008086d00006FD6*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 2 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 2 Error
pci:v00008086d00006FD7*
- ID_MODEL_FROM_DATABASE=Broadwell Memory Controller 1 - Channel 3 Error
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Memory Controller 1 - Channel 3 Error
pci:v00008086d00006FE0*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE1*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE2*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE3*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE4*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE5*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE6*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE7*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE8*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FE9*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FEA*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FEB*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FEC*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FED*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FEE*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FEF*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FF0*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FF1*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FF8*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FF9*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FFA*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FFB*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FFC*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FFD*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00006FFE*
- ID_MODEL_FROM_DATABASE=Broadwell Caching Agent
+ ID_MODEL_FROM_DATABASE=Xeon Processor D Family Caching Agent
pci:v00008086d00007000*
ID_MODEL_FROM_DATABASE=82371SB PIIX3 ISA [Natoma/Triton II]
@@ -76106,6 +77111,147 @@ pci:v00008086d0000A16A*
pci:v00008086d0000A170*
ID_MODEL_FROM_DATABASE=Sunrise Point-H HD Audio
+pci:v00008086d0000A182*
+ ID_MODEL_FROM_DATABASE=Lewisburg SATA Controller [AHCI mode]
+
+pci:v00008086d0000A190*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #1
+
+pci:v00008086d0000A191*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #2
+
+pci:v00008086d0000A192*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #3
+
+pci:v00008086d0000A193*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #4
+
+pci:v00008086d0000A194*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #5
+
+pci:v00008086d0000A195*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #6
+
+pci:v00008086d0000A196*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #7
+
+pci:v00008086d0000A197*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #8
+
+pci:v00008086d0000A198*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #9
+
+pci:v00008086d0000A199*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #10
+
+pci:v00008086d0000A19A*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #11
+
+pci:v00008086d0000A19B*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #12
+
+pci:v00008086d0000A19C*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #13
+
+pci:v00008086d0000A19D*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #14
+
+pci:v00008086d0000A19E*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #15
+
+pci:v00008086d0000A19F*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #16
+
+pci:v00008086d0000A1A0*
+ ID_MODEL_FROM_DATABASE=Lewisburg P2SB
+
+pci:v00008086d0000A1A1*
+ ID_MODEL_FROM_DATABASE=Lewisburg PMC
+
+pci:v00008086d0000A1A2*
+ ID_MODEL_FROM_DATABASE=Lewisburg cAVS
+
+pci:v00008086d0000A1A3*
+ ID_MODEL_FROM_DATABASE=Lewisburg SMBus
+
+pci:v00008086d0000A1A4*
+ ID_MODEL_FROM_DATABASE=Lewisburg SPI Controller
+
+pci:v00008086d0000A1AF*
+ ID_MODEL_FROM_DATABASE=Lewisburg USB 3.0 xHCI Controller
+
+pci:v00008086d0000A1BA*
+ ID_MODEL_FROM_DATABASE=Lewisburg CSME: HECI #1
+
+pci:v00008086d0000A1BB*
+ ID_MODEL_FROM_DATABASE=Lewisburg CSME: HECI #2
+
+pci:v00008086d0000A1BC*
+ ID_MODEL_FROM_DATABASE=Lewisburg CSME: IDE-r
+
+pci:v00008086d0000A1BD*
+ ID_MODEL_FROM_DATABASE=Lewisburg CSME: KT Controller
+
+pci:v00008086d0000A1BE*
+ ID_MODEL_FROM_DATABASE=Lewisburg CSME: HECI #3
+
+pci:v00008086d0000A1C1*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1C2*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1C3*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1C4*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1C5*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1C6*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1C7*
+ ID_MODEL_FROM_DATABASE=Lewisburg LPC Controller
+
+pci:v00008086d0000A1D2*
+ ID_MODEL_FROM_DATABASE=Lewisburg SSATA Controller [AHCI mode]
+
+pci:v00008086d0000A1E7*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #17
+
+pci:v00008086d0000A1E8*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #18
+
+pci:v00008086d0000A1E9*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #19
+
+pci:v00008086d0000A1EA*
+ ID_MODEL_FROM_DATABASE=Lewisburg PCI Express Root Port #20
+
+pci:v00008086d0000A1F0*
+ ID_MODEL_FROM_DATABASE=Lewisburg MROM 0
+
+pci:v00008086d0000A1F1*
+ ID_MODEL_FROM_DATABASE=Lewisburg MROM 1
+
+pci:v00008086d0000A1F8*
+ ID_MODEL_FROM_DATABASE=Lewisburg IE: HECI #1
+
+pci:v00008086d0000A1F9*
+ ID_MODEL_FROM_DATABASE=Lewisburg IE: HECI #2
+
+pci:v00008086d0000A1FA*
+ ID_MODEL_FROM_DATABASE=Lewisburg IE: IDE-r
+
+pci:v00008086d0000A1FB*
+ ID_MODEL_FROM_DATABASE=Lewisburg IE: KT Controller
+
+pci:v00008086d0000A1FC*
+ ID_MODEL_FROM_DATABASE=Lewisburg IE: HECI #3
+
pci:v00008086d0000A620*
ID_MODEL_FROM_DATABASE=6400/6402 Advanced Memory Buffer (AMB)
@@ -77396,6 +78542,15 @@ pci:v00009412*
pci:v00009412d00006565*
ID_MODEL_FROM_DATABASE=6565
+pci:v00009413*
+ ID_VENDOR_FROM_DATABASE=Softlogic Co., Ltd.
+
+pci:v00009413d00006010*
+ ID_MODEL_FROM_DATABASE=SOLO6010 MPEG-4 Video encoder/decoder
+
+pci:v00009413d00006110*
+ ID_MODEL_FROM_DATABASE=SOLO6110 H.264 Video encoder/decoder
+
pci:v00009618*
ID_VENDOR_FROM_DATABASE=JusonTech Corporation
@@ -77687,9 +78842,18 @@ pci:v0000BDBDd0000A130*
pci:v0000BDBDd0000A132*
ID_MODEL_FROM_DATABASE=UltraStudio 4K
+pci:v0000BDBDd0000A136*
+ ID_MODEL_FROM_DATABASE=DeckLink 4K Extreme 12G
+
+pci:v0000BDBDd0000A137*
+ ID_MODEL_FROM_DATABASE=DeckLink Studio 4K
+
pci:v0000BDBDd0000A138*
ID_MODEL_FROM_DATABASE=Decklink SDI 4K
+pci:v0000BDBDd0000A139*
+ ID_MODEL_FROM_DATABASE=Intensity Pro 4K
+
pci:v0000C001*
ID_VENDOR_FROM_DATABASE=TSI Telsys
@@ -77969,6 +79133,15 @@ pci:v0000DD01d00000003sv0000DD01sd00000030*
pci:v0000DD01d00000003sv0000DD01sd0000DB03*
ID_MODEL_FROM_DATABASE=Octopus DVB Adapter (Mystique SaTiX-S2 V3 DVB adapter)
+pci:v0000DD01d00000006*
+ ID_MODEL_FROM_DATABASE=Cine V7
+
+pci:v0000DD01d00000007*
+ ID_MODEL_FROM_DATABASE=Max
+
+pci:v0000DD01d00000007sv0000DD01sd00000023*
+ ID_MODEL_FROM_DATABASE=Max (S8 4/8)
+
pci:v0000DD01d00000011*
ID_MODEL_FROM_DATABASE=Octopus CI DVB Adapter
@@ -77978,6 +79151,12 @@ pci:v0000DD01d00000011sv0000DD01sd00000040*
pci:v0000DD01d00000011sv0000DD01sd00000041*
ID_MODEL_FROM_DATABASE=Octopus CI DVB Adapter (Octopus CI Single)
+pci:v0000DD01d00000201*
+ ID_MODEL_FROM_DATABASE=Resi DVB-C Modulator
+
+pci:v0000DD01d00000201sv0000DD01sd00000001*
+ ID_MODEL_FROM_DATABASE=Resi DVB-C Modulator
+
pci:v0000DEAD*
ID_VENDOR_FROM_DATABASE=Indigita Corporation
@@ -77994,7 +79173,7 @@ pci:v0000DEAFd00009052*
ID_MODEL_FROM_DATABASE=PC Weasel Watchdog Timer
pci:v0000DEDA*
- ID_VENDOR_FROM_DATABASE=SoftHard Technology Ltd.
+ ID_VENDOR_FROM_DATABASE=XIMEA
pci:v0000E000*
ID_VENDOR_FROM_DATABASE=Winbond
diff --git a/hwdb/20-sdio-vendor-model.hwdb b/hwdb/20-sdio-vendor-model.hwdb
index 626d673c4d..9cf34b2a39 100644
--- a/hwdb/20-sdio-vendor-model.hwdb
+++ b/hwdb/20-sdio-vendor-model.hwdb
@@ -80,6 +80,36 @@ sdio:c*v02D0*
sdio:c*v02D0d044B*
ID_MODEL_FROM_DATABASE=Nintendo Wii WLAN daughter card
+sdio:c*v02D0dA887*
+ ID_MODEL_FROM_DATABASE=BCM43143 WLAN card
+
+sdio:c*v02D0d4324*
+ ID_MODEL_FROM_DATABASE=BCM43241 WLAN card
+
+sdio:c*v02D0d4329*
+ ID_MODEL_FROM_DATABASE=BCM4329 WLAN card
+
+sdio:c*v02D0d4330*
+ ID_MODEL_FROM_DATABASE=BCM4330 WLAN card
+
+sdio:c*v02D0d4334*
+ ID_MODEL_FROM_DATABASE=BCM4334 WLAN card
+
+sdio:c*v02D0dA94C*
+ ID_MODEL_FROM_DATABASE=BCM43340 WLAN card
+
+sdio:c*v02D0dA94D*
+ ID_MODEL_FROM_DATABASE=BCM43341 WLAN card
+
+sdio:c*v02D0d4335*
+ ID_MODEL_FROM_DATABASE=BCM4335/BCM4339 WLAN card
+
+sdio:c*v02D0dA962*
+ ID_MODEL_FROM_DATABASE=BCM43362 WLAN card
+
+sdio:c*v02D0d4354*
+ ID_MODEL_FROM_DATABASE=BCM4354 WLAN card
+
sdio:c*v02DB*
ID_VENDOR_FROM_DATABASE=SyChip Inc.
diff --git a/hwdb/20-usb-vendor-model.hwdb b/hwdb/20-usb-vendor-model.hwdb
index 94e0269ce7..4d61dd7690 100644
--- a/hwdb/20-usb-vendor-model.hwdb
+++ b/hwdb/20-usb-vendor-model.hwdb
@@ -503,6 +503,9 @@ usb:v03F0p0217*
usb:v03F0p0218*
ID_MODEL_FROM_DATABASE=APOLLO P2500/2600
+usb:v03F0p022A*
+ ID_MODEL_FROM_DATABASE=Laserjet CP1525nw
+
usb:v03F0p0241*
ID_MODEL_FROM_DATABASE=Link-5 micro dongle
@@ -611,6 +614,9 @@ usb:v03F0p0704*
usb:v03F0p0705*
ID_MODEL_FROM_DATABASE=ScanJet 4400c
+usb:v03F0p070C*
+ ID_MODEL_FROM_DATABASE=Personal Media Drive
+
usb:v03F0p0711*
ID_MODEL_FROM_DATABASE=OfficeJet K80
@@ -1320,7 +1326,7 @@ usb:v03F0p4002*
ID_MODEL_FROM_DATABASE=PhotoSmart 635/715/720/735/935 (storage)
usb:v03F0p4004*
- ID_MODEL_FROM_DATABASE=cp1160
+ ID_MODEL_FROM_DATABASE=CP1160
usb:v03F0p4102*
ID_MODEL_FROM_DATABASE=PhotoSmart 618
@@ -1481,6 +1487,9 @@ usb:v03F0p5A11*
usb:v03F0p5B11*
ID_MODEL_FROM_DATABASE=OfficeJet J2100 series
+usb:v03F0p5B12*
+ ID_MODEL_FROM_DATABASE=Officejet Pro 8100
+
usb:v03F0p5C11*
ID_MODEL_FROM_DATABASE=PhotoSmart C4200 Printer series
@@ -2075,6 +2084,9 @@ usb:v0403p1060*
usb:v0403p1234*
ID_MODEL_FROM_DATABASE=IronLogic RFID Adapter [Z-2 USB]
+usb:v0403p1235*
+ ID_MODEL_FROM_DATABASE=Iron Logic Z-397 RS-485/422 converter
+
usb:v0403p6001*
ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC
@@ -2147,6 +2159,9 @@ usb:v0403p8B2B*
usb:v0403p8B2C*
ID_MODEL_FROM_DATABASE=Alpermann+Velte TCC70
+usb:v0403p9090*
+ ID_MODEL_FROM_DATABASE=SNAP Stick 200
+
usb:v0403p9132*
ID_MODEL_FROM_DATABASE=LCD and Temperature Interface
@@ -3311,6 +3326,9 @@ usb:v0411p00E8*
usb:v0411p0105*
ID_MODEL_FROM_DATABASE=External Hard Drive HD-CEU2 [Drive Station]
+usb:v0411p012C*
+ ID_MODEL_FROM_DATABASE=SATA Bridge
+
usb:v0411p012E*
ID_MODEL_FROM_DATABASE=WLI-UC-AG300N Wireless LAN Adapter
@@ -4376,6 +4394,9 @@ usb:v0421p0610*
usb:v0421p0661*
ID_MODEL_FROM_DATABASE=Lumia 920
+usb:v0421p0720*
+ ID_MODEL_FROM_DATABASE=X (RM-980)
+
usb:v0421p0800*
ID_MODEL_FROM_DATABASE=Connectivity Cable DKU-5
@@ -5378,6 +5399,12 @@ usb:v0451p625F*
usb:v0451p8042*
ID_MODEL_FROM_DATABASE=Hub
+usb:v0451p8142*
+ ID_MODEL_FROM_DATABASE=TUSB8041 4-Port Hub
+
+usb:v0451p926B*
+ ID_MODEL_FROM_DATABASE=TUSB9260 Boot Loader
+
usb:v0451pDBC0*
ID_MODEL_FROM_DATABASE=Device Bay Controller
@@ -6696,7 +6723,7 @@ usb:v0461*
ID_VENDOR_FROM_DATABASE=Primax Electronics, Ltd
usb:v0461p0010*
- ID_MODEL_FROM_DATABASE=HP Keyboard
+ ID_MODEL_FROM_DATABASE=HP PR1101U / Primax PMX-KPR1101U Keyboard
usb:v0461p0300*
ID_MODEL_FROM_DATABASE=G2-300 Scanner
@@ -7364,6 +7391,9 @@ usb:v046Dp0A1F*
usb:v046Dp0A29*
ID_MODEL_FROM_DATABASE=H600 [Wireless Headset]
+usb:v046Dp0A37*
+ ID_MODEL_FROM_DATABASE=USB Headset H540
+
usb:v046Dp0A38*
ID_MODEL_FROM_DATABASE=Headset H340
@@ -7389,7 +7419,7 @@ usb:v046DpC000*
ID_MODEL_FROM_DATABASE=N43 [Pilot Mouse]
usb:v046DpC001*
- ID_MODEL_FROM_DATABASE=N48/M-BB48 [FirstMouse Plus]
+ ID_MODEL_FROM_DATABASE=N48/M-BB48/M-UK96A [FirstMouse Plus]
usb:v046DpC002*
ID_MODEL_FROM_DATABASE=M-BA47 [MouseMan Plus]
@@ -7608,7 +7638,7 @@ usb:v046DpC122*
ID_MODEL_FROM_DATABASE=Harmony 650/700 Remote
usb:v046DpC124*
- ID_MODEL_FROM_DATABASE=Harmony 300 Remote
+ ID_MODEL_FROM_DATABASE=Harmony 300/350 Remote
usb:v046DpC125*
ID_MODEL_FROM_DATABASE=Harmony 200 Remote
@@ -8432,6 +8462,9 @@ usb:v0471p20E3*
usb:v0471p20E4*
ID_MODEL_FROM_DATABASE=GoGear ViBE 8GB
+usb:v0471p2160*
+ ID_MODEL_FROM_DATABASE=Mio LINK Heart Rate Monitor
+
usb:v0471p262C*
ID_MODEL_FROM_DATABASE=SPC230NC Webcam
@@ -8834,11 +8867,14 @@ usb:v047FpAC01*
usb:v047FpAD01*
ID_MODEL_FROM_DATABASE=GameCom 777 5.1 Headset
+usb:v047FpC008*
+ ID_MODEL_FROM_DATABASE=Audio 655 DSP
+
usb:v047FpC00E*
ID_MODEL_FROM_DATABASE=Blackwire C310 headset
usb:v0480*
- ID_VENDOR_FROM_DATABASE=Toshiba America Info. Systems, Inc.
+ ID_VENDOR_FROM_DATABASE=Toshiba America Inc
usb:v0480p0001*
ID_MODEL_FROM_DATABASE=InTouch Module
@@ -8873,6 +8909,9 @@ usb:v0480pA00D*
usb:v0480pB001*
ID_MODEL_FROM_DATABASE=Stor.E Partner
+usb:v0480pD000*
+ ID_MODEL_FROM_DATABASE=External Disk 2TB Model DT01ABA200
+
usb:v0480pD010*
ID_MODEL_FROM_DATABASE=External Disk 3TB
@@ -8948,6 +8987,9 @@ usb:v0483p2018*
usb:v0483p2302*
ID_MODEL_FROM_DATABASE=Portable Flash Device (PFD)
+usb:v0483p347B*
+ ID_MODEL_FROM_DATABASE=ST-LINK/V2-1
+
usb:v0483p3744*
ID_MODEL_FROM_DATABASE=STLINK Pseudo disk
@@ -9044,6 +9086,15 @@ usb:v0489pE016*
usb:v0489pE02C*
ID_MODEL_FROM_DATABASE=Atheros AR5BBU12 Bluetooth Device
+usb:v0489pE032*
+ ID_MODEL_FROM_DATABASE=Broadcom BCM20702 Bluetooth
+
+usb:v0489pE042*
+ ID_MODEL_FROM_DATABASE=Broadcom BCM20702 Bluetooth
+
+usb:v0489pE04D*
+ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth
+
usb:v048A*
ID_VENDOR_FROM_DATABASE=S-MOS Systems, Inc.
@@ -12417,7 +12468,7 @@ usb:v04B8p0884*
ID_MODEL_FROM_DATABASE=Stylus NX430W Series
usb:v04B8p0885*
- ID_MODEL_FROM_DATABASE=Stylus NX230 Series
+ ID_MODEL_FROM_DATABASE=Stylus NX230/SX235W Series
usb:v04B8p088F*
ID_MODEL_FROM_DATABASE=Stylus Office BX635FWD
@@ -12815,6 +12866,12 @@ usb:v04CAp1766*
usb:v04CAp2004*
ID_MODEL_FROM_DATABASE=Bluetooth 4.0 [Broadcom BCM20702A0]
+usb:v04CAp300B*
+ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth
+
+usb:v04CAp300D*
+ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth
+
usb:v04CAp7025*
ID_MODEL_FROM_DATABASE=HP HD Webcam
@@ -13277,6 +13334,9 @@ usb:v04D8pF4B5*
usb:v04D8pF8DA*
ID_MODEL_FROM_DATABASE=Hughski Ltd. ColorHug
+usb:v04D8pF8E8*
+ ID_MODEL_FROM_DATABASE=Harmony 300/350 Remote
+
usb:v04D8pF91C*
ID_MODEL_FROM_DATABASE=SPROG IIv3
@@ -13331,6 +13391,9 @@ usb:v04D9p1603*
usb:v04D9p1702*
ID_MODEL_FROM_DATABASE=Keyboard LKS02
+usb:v04D9p2011*
+ ID_MODEL_FROM_DATABASE=Keyboard [Diatec Filco Majestouch 1]
+
usb:v04D9p2013*
ID_MODEL_FROM_DATABASE=Keyboard [Das Keyboard]
@@ -14030,6 +14093,9 @@ usb:v04E8p3297*
usb:v04E8p329F*
ID_MODEL_FROM_DATABASE=CLP-325 Color Laser Printer
+usb:v04E8p3301*
+ ID_MODEL_FROM_DATABASE=ML-1660 Series
+
usb:v04E8p330C*
ID_MODEL_FROM_DATABASE=ML-1865
@@ -14376,7 +14442,7 @@ usb:v04E8p6632*
ID_MODEL_FROM_DATABASE=MITs Sync
usb:v04E8p663E*
- ID_MODEL_FROM_DATABASE=D900e Phone
+ ID_MODEL_FROM_DATABASE=D900e/B2100 Phone
usb:v04E8p663F*
ID_MODEL_FROM_DATABASE=SGH-E720/SGH-E840
@@ -14400,10 +14466,10 @@ usb:v04E8p6734*
ID_MODEL_FROM_DATABASE=Juke
usb:v04E8p6759*
- ID_MODEL_FROM_DATABASE=D900e Media Player
+ ID_MODEL_FROM_DATABASE=D900e/B2100 Media Player
usb:v04E8p675A*
- ID_MODEL_FROM_DATABASE=D900e Mass Storage
+ ID_MODEL_FROM_DATABASE=D900e/B2100 Mass Storage
usb:v04E8p675B*
ID_MODEL_FROM_DATABASE=D900e Camera
@@ -14448,7 +14514,7 @@ usb:v04E8p685E*
ID_MODEL_FROM_DATABASE=GT-I9100 / GT-C3350 Phones (USB Debugging mode)
usb:v04E8p6860*
- ID_MODEL_FROM_DATABASE=GT-I9100 Phone [Galaxy S II], GT-I9300 Phone [Galaxy S III], GT-P7500 [Galaxy Tab 10.1] , GT-I9500 [Galaxy S 4]
+ ID_MODEL_FROM_DATABASE=Galaxy (MTP)
usb:v04E8p6863*
ID_MODEL_FROM_DATABASE=GT-I9500 [Galaxy S4] / GT-I9250 [Galaxy Nexus] (network tethering)
@@ -14825,6 +14891,9 @@ usb:v04F2pB354*
usb:v04F2pB394*
ID_MODEL_FROM_DATABASE=Integrated Camera
+usb:v04F2pB3F6*
+ ID_MODEL_FROM_DATABASE=HD WebCam (Acer)
+
usb:v04F3*
ID_VENDOR_FROM_DATABASE=Elan Microelectronics Corp.
@@ -15234,7 +15303,7 @@ usb:v04F9p0181*
ID_MODEL_FROM_DATABASE=MFC-7820N Port(FaxModem)
usb:v04F9p0182*
- ID_MODEL_FROM_DATABASE=Composite Device
+ ID_MODEL_FROM_DATABASE=DCP-7010
usb:v04F9p0183*
ID_MODEL_FROM_DATABASE=DCP-7020
@@ -17153,6 +17222,9 @@ usb:v054Cp04CB*
usb:v054Cp0541*
ID_MODEL_FROM_DATABASE=DSC-HX100V [Cybershot Digital Still Camera]
+usb:v054Cp05C4*
+ ID_MODEL_FROM_DATABASE=DualShock 4
+
usb:v054Cp0689*
ID_MODEL_FROM_DATABASE=Walkman NWZ-B173F
@@ -17870,6 +17942,9 @@ usb:v056Ap00F6*
usb:v056Ap00F8*
ID_MODEL_FROM_DATABASE=Cintiq 24HD touch (DTH-2400) tablet
+usb:v056Ap0302*
+ ID_MODEL_FROM_DATABASE=Intuos CTH480S2 [Manga]
+
usb:v056Ap0307*
ID_MODEL_FROM_DATABASE=Cintiq Companion Hybrid 13HD (DTH-A1300) tablet
@@ -17885,6 +17960,9 @@ usb:v056Ap0400*
usb:v056Ap4850*
ID_MODEL_FROM_DATABASE=PenPartner 6x8
+usb:v056Ap5010*
+ ID_MODEL_FROM_DATABASE=Thinkpad T550 touchscreen
+
usb:v056B*
ID_VENDOR_FROM_DATABASE=Decicon, Inc.
@@ -18044,6 +18122,9 @@ usb:v0572pC688*
usb:v0572pCAFC*
ID_MODEL_FROM_DATABASE=CX861xx ROM Boot Loader
+usb:v0572pCAFD*
+ ID_MODEL_FROM_DATABASE=CX82310 ROM Boot Loader
+
usb:v0572pCAFE*
ID_MODEL_FROM_DATABASE=AccessRunner ADSL Modem
@@ -19142,11 +19223,17 @@ usb:v0586*
usb:v0586p0025*
ID_MODEL_FROM_DATABASE=802.11b/g/n USB Wireless Network Adapter
+usb:v0586p0100*
+ ID_MODEL_FROM_DATABASE=omni.net
+
usb:v0586p0102*
- ID_MODEL_FROM_DATABASE=omni.net II ISDN TA
+ ID_MODEL_FROM_DATABASE=omni.net II ISDN TA [HFC-S]
+
+usb:v0586p0110*
+ ID_MODEL_FROM_DATABASE=omni.net Plus
usb:v0586p1000*
- ID_MODEL_FROM_DATABASE=Omni NET Modem / ISDN TA
+ ID_MODEL_FROM_DATABASE=omni.net LCD Plus - ISDN TA
usb:v0586p1500*
ID_MODEL_FROM_DATABASE=Omni 56K Plus
@@ -19709,6 +19796,9 @@ usb:v059Fp100C*
usb:v059Fp1010*
ID_MODEL_FROM_DATABASE=Desktop Hard Drive
+usb:v059Fp1018*
+ ID_MODEL_FROM_DATABASE=Desktop Hard Drive
+
usb:v059Fp1019*
ID_MODEL_FROM_DATABASE=Desktop Hard Drive
@@ -19856,6 +19946,9 @@ usb:v05A9p4519*
usb:v05A9p7670*
ID_MODEL_FROM_DATABASE=OV7670 Webcam
+usb:v05A9p8065*
+ ID_MODEL_FROM_DATABASE=GAIA Sensor FPGA Demo Board
+
usb:v05A9p8519*
ID_MODEL_FROM_DATABASE=OV519 Webcam
@@ -20292,7 +20385,7 @@ usb:v05ACp12A6*
ID_MODEL_FROM_DATABASE=iPad 3 (3G, 16 GB)
usb:v05ACp12A8*
- ID_MODEL_FROM_DATABASE=iPhone5/5C/5S
+ ID_MODEL_FROM_DATABASE=iPhone5/5C/5S/6
usb:v05ACp12A9*
ID_MODEL_FROM_DATABASE=iPad 2
@@ -20301,7 +20394,7 @@ usb:v05ACp12AA*
ID_MODEL_FROM_DATABASE=iPod Touch 5.Gen [A1421]
usb:v05ACp12AB*
- ID_MODEL_FROM_DATABASE=iPad 4 (WiFi, 32GB)
+ ID_MODEL_FROM_DATABASE=iPad 4/Mini1
usb:v05ACp1300*
ID_MODEL_FROM_DATABASE=iPod Shuffle
@@ -20511,7 +20604,7 @@ usb:v05B4p4857*
ID_MODEL_FROM_DATABASE=M-Any DAH-210
usb:v05B4p6001*
- ID_MODEL_FROM_DATABASE=Digisette DUO-MP3 AR-100
+ ID_MODEL_FROM_DATABASE=HYUNDAI GDS30C6001 SSFDC / MMC I/F Controller
usb:v05B5*
ID_VENDOR_FROM_DATABASE=Dialogic Corp.
@@ -20618,6 +20711,9 @@ usb:v05C6p9001*
usb:v05C6p9002*
ID_MODEL_FROM_DATABASE=Gobi Wireless Modem
+usb:v05C6p9003*
+ ID_MODEL_FROM_DATABASE=Quectel UC20
+
usb:v05C6p9008*
ID_MODEL_FROM_DATABASE=Gobi Wireless Modem (QDL mode)
@@ -21548,6 +21644,9 @@ usb:v05DCpA813*
usb:v05DCpA815*
ID_MODEL_FROM_DATABASE=JumpDrive V10
+usb:v05DCpA833*
+ ID_MODEL_FROM_DATABASE=JumpDrive S23 64GB
+
usb:v05DCpB002*
ID_MODEL_FROM_DATABASE=USB CF Reader
@@ -21812,6 +21911,9 @@ usb:v05E3p0741*
usb:v05E3p0743*
ID_MODEL_FROM_DATABASE=SDXC and microSDXC CardReader
+usb:v05E3p0745*
+ ID_MODEL_FROM_DATABASE=Logilink CR0012
+
usb:v05E3p0760*
ID_MODEL_FROM_DATABASE=USB 2.0 Card Reader/Writer
@@ -22559,6 +22661,9 @@ usb:v064D*
usb:v064E*
ID_VENDOR_FROM_DATABASE=Suyin Corp.
+usb:v064Ep2100*
+ ID_MODEL_FROM_DATABASE=Sony Visual Communication Camera
+
usb:v064EpA100*
ID_MODEL_FROM_DATABASE=Acer OrbiCam
@@ -22589,6 +22694,9 @@ usb:v064EpA219*
usb:v064EpC107*
ID_MODEL_FROM_DATABASE=HP webcam [dv6-1190en]
+usb:v064EpC335*
+ ID_MODEL_FROM_DATABASE=HP TrueVision HD
+
usb:v064EpD101*
ID_MODEL_FROM_DATABASE=Acer CrystalEye Webcam
@@ -23169,10 +23277,10 @@ usb:v0675p0550*
ID_MODEL_FROM_DATABASE=Vigor550
usb:v0675p1688*
- ID_MODEL_FROM_DATABASE=miniVigor 128 ISDN TA
+ ID_MODEL_FROM_DATABASE=miniVigor 128 ISDN TA [HFC-S]
usb:v0675p6694*
- ID_MODEL_FROM_DATABASE=USB ISDN TA
+ ID_MODEL_FROM_DATABASE=miniVigor 128 ISDN TA
usb:v0676*
ID_VENDOR_FROM_DATABASE=Teles AG
@@ -25221,10 +25329,13 @@ usb:v071D*
ID_VENDOR_FROM_DATABASE=Eicon Networks Corp.
usb:v071Dp1000*
- ID_MODEL_FROM_DATABASE=Diva ISDN TA
+ ID_MODEL_FROM_DATABASE=Diva 2.01 S/T [PSB2115F]
usb:v071Dp1003*
- ID_MODEL_FROM_DATABASE=Diva
+ ID_MODEL_FROM_DATABASE=Diva ISDN 2.0
+
+usb:v071Dp1005*
+ ID_MODEL_FROM_DATABASE=Diva ISDN 4.0 [HFC-S]
usb:v071Dp2000*
ID_MODEL_FROM_DATABASE=Teledat Surf
@@ -25598,6 +25709,18 @@ usb:v073E*
usb:v073Ep0301*
ID_MODEL_FROM_DATABASE=Game Pad
+usb:v0742*
+ ID_VENDOR_FROM_DATABASE=Stollmann
+
+usb:v0742p2008*
+ ID_MODEL_FROM_DATABASE=ISDN TA [HFC-S]
+
+usb:v0742p2009*
+ ID_MODEL_FROM_DATABASE=ISDN TA [HFC-S]
+
+usb:v0742p200A*
+ ID_MODEL_FROM_DATABASE=ISDN TA [HFC-S]
+
usb:v0745*
ID_VENDOR_FROM_DATABASE=Syntech Information Co., Ltd
@@ -25850,6 +25973,9 @@ usb:v0764p0005*
usb:v0764p0501*
ID_MODEL_FROM_DATABASE=CP1500 AVR UPS
+usb:v0764p0601*
+ ID_MODEL_FROM_DATABASE=PR1500LCDRT2U UPS
+
usb:v0765*
ID_VENDOR_FROM_DATABASE=X-Rite, Inc.
@@ -25922,6 +26048,9 @@ usb:v076Bp1784*
usb:v076Bp3021*
ID_MODEL_FROM_DATABASE=CardMan 3121
+usb:v076Bp3022*
+ ID_MODEL_FROM_DATABASE=CardMan 3021
+
usb:v076Bp3610*
ID_MODEL_FROM_DATABASE=CardMan 3620
@@ -26763,10 +26892,10 @@ usb:v07B0p0005*
ID_MODEL_FROM_DATABASE=ISDN TA128 SE
usb:v07B0p0006*
- ID_MODEL_FROM_DATABASE=ISDN TA128 CE
+ ID_MODEL_FROM_DATABASE=ISDN TA 128 [HFC-S]
usb:v07B0p0007*
- ID_MODEL_FROM_DATABASE=ISDN TA
+ ID_MODEL_FROM_DATABASE=ISDN TA [HFC-S]
usb:v07B0p0008*
ID_MODEL_FROM_DATABASE=ISDN TA
@@ -26900,6 +27029,9 @@ usb:v07B3p0A06*
usb:v07B3p0B00*
ID_MODEL_FROM_DATABASE=SmartPhoto F50
+usb:v07B3p0C00*
+ ID_MODEL_FROM_DATABASE=OpticPro ST64 Scanner
+
usb:v07B3p0C03*
ID_MODEL_FROM_DATABASE=OpticPro ST64+ Scanner
@@ -26916,7 +27048,7 @@ usb:v07B3p0C2B*
ID_MODEL_FROM_DATABASE=Mobile Office D428 Scanner
usb:v07B3p0E08*
- ID_MODEL_FROM_DATABASE=Plustek OpticBook A300 Scanner
+ ID_MODEL_FROM_DATABASE=OpticBook A300 Scanner
usb:v07B3p1300*
ID_MODEL_FROM_DATABASE=OpticBook 3800 Scanner
@@ -26946,7 +27078,7 @@ usb:v07B4p0112*
ID_MODEL_FROM_DATABASE=MAUSB-100 xD Card Reader
usb:v07B4p0113*
- ID_MODEL_FROM_DATABASE=Mju 500
+ ID_MODEL_FROM_DATABASE=Mju 500 / Stylus Digital Camera (PTP)
usb:v07B4p0114*
ID_MODEL_FROM_DATABASE=C-350Z Camera
@@ -27944,6 +28076,12 @@ usb:v07FA*
usb:v07FAp0778*
ID_MODEL_FROM_DATABASE=miniVigor 128 ISDN TA
+usb:v07FAp0846*
+ ID_MODEL_FROM_DATABASE=ISDN TA [HFC-S]
+
+usb:v07FAp0847*
+ ID_MODEL_FROM_DATABASE=ISDN TA [HFC-S]
+
usb:v07FAp1012*
ID_MODEL_FROM_DATABASE=BeWAN ADSL USB ST (grey)
@@ -28589,6 +28727,9 @@ usb:v0846p9041*
usb:v0846p9042*
ID_MODEL_FROM_DATABASE=On Networks N150MA 802.11bgn [Realtek RTL8188CUS]
+usb:v0846p9043*
+ ID_MODEL_FROM_DATABASE=WNA1000Mv2 802.11bgn [Realtek RTL8188CUS?]
+
usb:v0846p9050*
ID_MODEL_FROM_DATABASE=A6200 802.11a/b/g/n/ac Wireless Adapter [Broadcom BCM43526]
@@ -29427,11 +29568,14 @@ usb:v08E3p0102*
ID_MODEL_FROM_DATABASE=ADSL
usb:v08E3p0301*
- ID_MODEL_FROM_DATABASE=RNIS
+ ID_MODEL_FROM_DATABASE=RNIS ISDN TA [HFC-S]
usb:v08E4*
ID_VENDOR_FROM_DATABASE=Pioneer Corp.
+usb:v08E4p0184*
+ ID_MODEL_FROM_DATABASE=DDJ-WeGO
+
usb:v08E4p0185*
ID_MODEL_FROM_DATABASE=DDJ-WeGO2
@@ -29990,6 +30134,9 @@ usb:v090Cp037A*
usb:v090Cp037B*
ID_MODEL_FROM_DATABASE=Silicon Motion Camera
+usb:v090Cp037C*
+ ID_MODEL_FROM_DATABASE=300k Pixel Camera
+
usb:v090Cp1000*
ID_MODEL_FROM_DATABASE=Flash Drive
@@ -30032,6 +30179,9 @@ usb:v090CpB370*
usb:v090CpB371*
ID_MODEL_FROM_DATABASE=Silicon Motion SM371 Camera
+usb:v090CpF37D*
+ ID_MODEL_FROM_DATABASE=Endoscope camera
+
usb:v090D*
ID_VENDOR_FROM_DATABASE=Multiport Computer Vertriebs GmbH
@@ -30323,6 +30473,9 @@ usb:v0928*
usb:v0928p8000*
ID_MODEL_FROM_DATABASE=Firmware uploader
+usb:v0928pFFFF*
+ ID_MODEL_FROM_DATABASE=Blank Oxford Device
+
usb:v0929*
ID_VENDOR_FROM_DATABASE=American Biometric Co.
@@ -30356,6 +30509,9 @@ usb:v0930p0010*
usb:v0930p0200*
ID_MODEL_FROM_DATABASE=Integrated Bluetooth (Taiyo Yuden)
+usb:v0930p021C*
+ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth
+
usb:v0930p0301*
ID_MODEL_FROM_DATABASE=PCX1100U Cable Modem (WDM)
@@ -30990,7 +31146,7 @@ usb:v0959*
ID_VENDOR_FROM_DATABASE=Cologne Chip AG
usb:v0959p2BD0*
- ID_MODEL_FROM_DATABASE=Intelligent ISDN (Ver. 3.60.04)
+ ID_MODEL_FROM_DATABASE=Intelligent ISDN (Ver. 3.60.04) [HFC-S]
usb:v095A*
ID_VENDOR_FROM_DATABASE=Portsmith
@@ -31565,6 +31721,9 @@ usb:v0A01*
usb:v0A05*
ID_VENDOR_FROM_DATABASE=Unknown Manufacturer
+usb:v0A05p0001*
+ ID_MODEL_FROM_DATABASE=Hub
+
usb:v0A05p7211*
ID_MODEL_FROM_DATABASE=hub
@@ -31730,6 +31889,9 @@ usb:v0A17p003B*
usb:v0A17p003D*
ID_MODEL_FROM_DATABASE=Optio S55
+usb:v0A17p0041*
+ ID_MODEL_FROM_DATABASE=Optio S5z
+
usb:v0A17p0043*
ID_MODEL_FROM_DATABASE=*ist DL
@@ -32141,6 +32303,9 @@ usb:v0A5Cp2151*
usb:v0A5Cp2154*
ID_MODEL_FROM_DATABASE=BCM92046DG-CL1ROM Bluetooth 2.1 UHE Dongle
+usb:v0A5Cp216C*
+ ID_MODEL_FROM_DATABASE=BCM43142A0 Bluetooth Device
+
usb:v0A5Cp217D*
ID_MODEL_FROM_DATABASE=HP Bluethunder
@@ -33212,6 +33377,9 @@ usb:v0B05p17C7*
usb:v0B05p17C9*
ID_MODEL_FROM_DATABASE=USB-AC53 802.11a/b/g/n/ac Wireless Adapter [Broadcom BCM43526]
+usb:v0B05p17CB*
+ ID_MODEL_FROM_DATABASE=Broadcom BCM20702A0 Bluetooth
+
usb:v0B05p17D1*
ID_MODEL_FROM_DATABASE=AC51 802.11a/b/g/n/ac Wireless Adapter [Mediatek MT7610/Ralink RT2870]
@@ -33687,7 +33855,7 @@ usb:v0B7D*
ID_VENDOR_FROM_DATABASE=Astrodesign, Inc.
usb:v0B81*
- ID_VENDOR_FROM_DATABASE=id3 Semiconductors
+ ID_VENDOR_FROM_DATABASE=id3 Technologies
usb:v0B81p0001*
ID_MODEL_FROM_DATABASE=Biothentic II smartcard reader with fingerprint sensor
@@ -34475,6 +34643,9 @@ usb:v0BB4p0CAE*
usb:v0BB4p0DEA*
ID_MODEL_FROM_DATABASE=M7_UL [HTC One]
+usb:v0BB4p0F25*
+ ID_MODEL_FROM_DATABASE=One M8
+
usb:v0BB4p0F64*
ID_MODEL_FROM_DATABASE=Desire 601
@@ -34820,6 +34991,9 @@ usb:v0BDAp2832*
usb:v0BDAp2838*
ID_MODEL_FROM_DATABASE=RTL2838 DVB-T
+usb:v0BDAp5401*
+ ID_MODEL_FROM_DATABASE=RTL 8153 USB 3.0 hub with gigabit ethernet
+
usb:v0BDAp5730*
ID_MODEL_FROM_DATABASE=HP 2.0MP High Definition Webcam
@@ -35774,6 +35948,15 @@ usb:v0C4Bp0500*
usb:v0C4Bp0501*
ID_MODEL_FROM_DATABASE=cyberJack RFID comfort dual interface smartcard reader
+usb:v0C4Bp0502*
+ ID_MODEL_FROM_DATABASE=cyberJack compact
+
+usb:v0C4Bp0504*
+ ID_MODEL_FROM_DATABASE=cyberJack go / go plus
+
+usb:v0C4Bp0505*
+ ID_MODEL_FROM_DATABASE=cyberJack wave
+
usb:v0C4Bp9102*
ID_MODEL_FROM_DATABASE=cyberJack RFID basis contactless smartcard reader
@@ -35981,6 +36164,36 @@ usb:v0C5E*
usb:v0C60*
ID_VENDOR_FROM_DATABASE=Apogee Electronics Corp.
+usb:v0C60p0001*
+ ID_MODEL_FROM_DATABASE=MiniMe
+
+usb:v0C60p0002*
+ ID_MODEL_FROM_DATABASE=MiniDAC
+
+usb:v0C60p0003*
+ ID_MODEL_FROM_DATABASE=ONE
+
+usb:v0C60p0004*
+ ID_MODEL_FROM_DATABASE=GiO
+
+usb:v0C60p0007*
+ ID_MODEL_FROM_DATABASE=Duet
+
+usb:v0C60p0009*
+ ID_MODEL_FROM_DATABASE=Jam
+
+usb:v0C60p000A*
+ ID_MODEL_FROM_DATABASE=Jam Bootloader
+
+usb:v0C60p000B*
+ ID_MODEL_FROM_DATABASE=MiC
+
+usb:v0C60p000C*
+ ID_MODEL_FROM_DATABASE=MiC Bootloader
+
+usb:v0C60p8007*
+ ID_MODEL_FROM_DATABASE=Duet DFU Mode
+
usb:v0C62*
ID_VENDOR_FROM_DATABASE=Chant Sincere Co., Ltd
@@ -37524,7 +37737,7 @@ usb:v0DA3*
ID_VENDOR_FROM_DATABASE=Nippon Electro-Sensory Devices Corp.
usb:v0DA4*
- ID_VENDOR_FROM_DATABASE=Polar Electro OY
+ ID_VENDOR_FROM_DATABASE=Polar Electro Oy
usb:v0DA4p0001*
ID_MODEL_FROM_DATABASE=Interface
@@ -37667,6 +37880,18 @@ usb:v0DB3*
usb:v0DB4*
ID_VENDOR_FROM_DATABASE=Chung Fu Chen Yeh Enterprise Corp.
+usb:v0DB5*
+ ID_VENDOR_FROM_DATABASE=Access IS
+
+usb:v0DB5p0139*
+ ID_MODEL_FROM_DATABASE=LSR116 CDC
+
+usb:v0DB5p013A*
+ ID_MODEL_FROM_DATABASE=LSR116 Keyboard
+
+usb:v0DB5p013B*
+ ID_MODEL_FROM_DATABASE=LSR116 HID
+
usb:v0DB7*
ID_VENDOR_FROM_DATABASE=ELCON Systemtechnik
@@ -38075,6 +38300,9 @@ usb:v0DF6p2208*
usb:v0DF6p2209*
ID_MODEL_FROM_DATABASE=Sitecom bluetooth2.0 class 1 dongle CN-521
+usb:v0DF6p3068*
+ ID_MODEL_FROM_DATABASE=DC-104v2 ISDN Adapter [HFC-S]
+
usb:v0DF6p9071*
ID_MODEL_FROM_DATABASE=WL-113 rev 1 Wireless Network USB Adapter
@@ -38510,6 +38738,9 @@ usb:v0E6Fp0005*
usb:v0E6Fp0006*
ID_MODEL_FROM_DATABASE=Edge wireless Controller
+usb:v0E6Fp0128*
+ ID_MODEL_FROM_DATABASE=Wireless PS3 Controller
+
usb:v0E70*
ID_VENDOR_FROM_DATABASE=Tokyo Electronic Industry Co., Ltd
@@ -38618,6 +38849,9 @@ usb:v0E8Fp0020*
usb:v0E8Fp0021*
ID_MODEL_FROM_DATABASE=Multimedia Keyboard Controller
+usb:v0E8Fp0022*
+ ID_MODEL_FROM_DATABASE=multimedia keyboard controller
+
usb:v0E8Fp0201*
ID_MODEL_FROM_DATABASE=SmartJoy Frag Xpad/PS2 adaptor
@@ -38858,6 +39092,9 @@ usb:v0EE3p1000*
usb:v0EE4*
ID_VENDOR_FROM_DATABASE=Sunrich Technology, Ltd
+usb:v0EE4p0690*
+ ID_MODEL_FROM_DATABASE=SATA 3 Adapter
+
usb:v0EEE*
ID_VENDOR_FROM_DATABASE=Digital Stream Technology, Inc.
@@ -39434,6 +39671,9 @@ usb:v0FCEp00D9*
usb:v0FCEp0112*
ID_MODEL_FROM_DATABASE=W995 Walkman Phone
+usb:v0FCEp014E*
+ ID_MODEL_FROM_DATABASE=J108i Cedar (MTP mode)
+
usb:v0FCEp015A*
ID_MODEL_FROM_DATABASE=Xperia Pro [Media Transfer Protocol]
@@ -39452,6 +39692,9 @@ usb:v0FCEp0172*
usb:v0FCEp0177*
ID_MODEL_FROM_DATABASE=Xperia Ion [Mass Storage]
+usb:v0FCEp01BB*
+ ID_MODEL_FROM_DATABASE=D5803 [Xperia Z3 Compact] (MTP mode)
+
usb:v0FCEp0DDE*
ID_MODEL_FROM_DATABASE=Xperia Mini Pro Bootloader
@@ -39476,6 +39719,9 @@ usb:v0FCEp2138*
usb:v0FCEp2149*
ID_MODEL_FROM_DATABASE=Xperia X8 (debug)
+usb:v0FCEp214E*
+ ID_MODEL_FROM_DATABASE=J108i Cedar (Windows-driver mode)
+
usb:v0FCEp3137*
ID_MODEL_FROM_DATABASE=Xperia X10 mini
@@ -39588,7 +39834,7 @@ usb:v0FCEpD12E*
ID_MODEL_FROM_DATABASE=Xperia X10
usb:v0FCEpD14E*
- ID_MODEL_FROM_DATABASE=J108i Cedar
+ ID_MODEL_FROM_DATABASE=J108i Cedar (modem mode)
usb:v0FCEpE000*
ID_MODEL_FROM_DATABASE=K810 (PictBridge mode)
@@ -39644,6 +39890,9 @@ usb:v0FCEpE12E*
usb:v0FCEpE133*
ID_MODEL_FROM_DATABASE=Vivaz
+usb:v0FCEpE14E*
+ ID_MODEL_FROM_DATABASE=J108i Cedar (mass-storage mode)
+
usb:v0FCEpE14F*
ID_MODEL_FROM_DATABASE=Xperia Arc/X12
@@ -39663,7 +39912,7 @@ usb:v0FCEpE19B*
ID_MODEL_FROM_DATABASE=C2005 [Xperia M dual] (Mass Storage)
usb:v0FCEpF0FA*
- ID_MODEL_FROM_DATABASE=Liveview micro display MN800 in DFU mode
+ ID_MODEL_FROM_DATABASE=MN800 / Smartwatch 2 (DFU mode)
usb:v0FCF*
ID_VENDOR_FROM_DATABASE=Dynastream Innovations, Inc.
@@ -39884,6 +40133,9 @@ usb:v1004p61C6*
usb:v1004p61CC*
ID_MODEL_FROM_DATABASE=Optimus S
+usb:v1004p61DA*
+ ID_MODEL_FROM_DATABASE=G2 Android Phone [tethering mode]
+
usb:v1004p61F1*
ID_MODEL_FROM_DATABASE=Optimus Android Phone [LG Software mode]
@@ -39900,13 +40152,13 @@ usb:v1004p6300*
ID_MODEL_FROM_DATABASE=Optimus Android Phone
usb:v1004p631C*
- ID_MODEL_FROM_DATABASE=Optimus Android Phone [MTP mode]
+ ID_MODEL_FROM_DATABASE=G2/Optimus Android Phone [MTP mode]
usb:v1004p631D*
ID_MODEL_FROM_DATABASE=Optimus Android Phone (Camera/PTP Mode)
usb:v1004p631E*
- ID_MODEL_FROM_DATABASE=Optimus Android Phone [Camera/PTP mode]
+ ID_MODEL_FROM_DATABASE=G2/Optimus Android Phone [Camera/PTP mode]
usb:v1004p631F*
ID_MODEL_FROM_DATABASE=Optimus Android Phone (Charge Mode)
@@ -40241,6 +40493,9 @@ usb:v1046p9967*
usb:v1048*
ID_VENDOR_FROM_DATABASE=Targus Group International
+usb:v1048p2010*
+ ID_MODEL_FROM_DATABASE=4-Port hub
+
usb:v104B*
ID_VENDOR_FROM_DATABASE=Mylex / Buslogic
@@ -40287,13 +40542,28 @@ usb:v1050p0010*
ID_MODEL_FROM_DATABASE=Yubikey
usb:v1050p0110*
- ID_MODEL_FROM_DATABASE=Yubikey NEO OTP
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP
usb:v1050p0111*
- ID_MODEL_FROM_DATABASE=Yubikey NEO OTP+CCID
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP+CCID
usb:v1050p0112*
- ID_MODEL_FROM_DATABASE=Yubikey NEO CCID
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) CCID
+
+usb:v1050p0113*
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) U2F
+
+usb:v1050p0114*
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP+U2F
+
+usb:v1050p0115*
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) U2F+CCID
+
+usb:v1050p0116*
+ ID_MODEL_FROM_DATABASE=Yubikey NEO(-N) OTP+U2F+CCID
+
+usb:v1050p0120*
+ ID_MODEL_FROM_DATABASE=Yubikey Touch U2F Security Key
usb:v1050p0200*
ID_MODEL_FROM_DATABASE=U2F Gnubby
@@ -40388,6 +40658,9 @@ usb:v1058p0810*
usb:v1058p0820*
ID_MODEL_FROM_DATABASE=My Passport Ultra (WDBMWV, WDBZFP)
+usb:v1058p0830*
+ ID_MODEL_FROM_DATABASE=My Passport Ultra (WDBZFP)
+
usb:v1058p0900*
ID_MODEL_FROM_DATABASE=MyBook Essential External HDD
@@ -40478,6 +40751,12 @@ usb:v1059*
usb:v1059p000B*
ID_MODEL_FROM_DATABASE=StarSign Bio Token 3.0
+usb:v105B*
+ ID_VENDOR_FROM_DATABASE=Foxconn International, Inc.
+
+usb:v105BpE065*
+ ID_MODEL_FROM_DATABASE=BCM43142A0 Bluetooth module
+
usb:v105C*
ID_VENDOR_FROM_DATABASE=Hong Ji Electric Wire & Cable (Dongguan) Co., Ltd
@@ -40751,6 +41030,9 @@ usb:v1076p0031*
usb:v1076p0032*
ID_MODEL_FROM_DATABASE=Bluetooth Device
+usb:v1076p8002*
+ ID_MODEL_FROM_DATABASE=LU150 LTE Modem [Yota LU150]
+
usb:v107B*
ID_VENDOR_FROM_DATABASE=Gateway, Inc.
@@ -40793,6 +41075,9 @@ usb:v108A*
usb:v108B*
ID_VENDOR_FROM_DATABASE=Grand-tek Technology Co., Ltd
+usb:v108Bp0005*
+ ID_MODEL_FROM_DATABASE=HID Keyboard/Mouse PS/2 Translator
+
usb:v108C*
ID_VENDOR_FROM_DATABASE=Robert Bosch GmbH
@@ -41115,7 +41400,10 @@ usb:v10C4p8918*
ID_MODEL_FROM_DATABASE=C8051F38x HDMI Audio Extractor [VSA-HA-DP]
usb:v10C4p8973*
- ID_MODEL_FROM_DATABASE=C8051F38x HDMI Splitter [UHBX-8X]
+ ID_MODEL_FROM_DATABASE=C8051F38x HDMI Extender [UHBX-8X]
+
+usb:v10C4p89E1*
+ ID_MODEL_FROM_DATABASE=C8051F38x HDMI Extender [UHBX-SW3-WP]
usb:v10C4pEA60*
ID_MODEL_FROM_DATABASE=CP210x UART Bridge / myAVR mySmartUSB light
@@ -41189,6 +41477,12 @@ usb:v10D1p0202*
usb:v10D1p0301*
ID_MODEL_FROM_DATABASE=CP42 - Communication Processor
+usb:v10D2*
+ ID_VENDOR_FROM_DATABASE=RayComposer - R. Adams
+
+usb:v10D2p5243*
+ ID_MODEL_FROM_DATABASE=RayComposer
+
usb:v10D4*
ID_VENDOR_FROM_DATABASE=Man Boon Manufactory, Ltd
@@ -41207,6 +41501,9 @@ usb:v10D5p55A2*
usb:v10D6*
ID_VENDOR_FROM_DATABASE=Actions Semiconductor Co., Ltd
+usb:v10D6p0C02*
+ ID_MODEL_FROM_DATABASE=BioniQ 1001 Tablet
+
usb:v10D6p1000*
ID_MODEL_FROM_DATABASE=MP3 Player
@@ -41420,6 +41717,9 @@ usb:v112F*
usb:v1130*
ID_VENDOR_FROM_DATABASE=Tenx Technology, Inc.
+usb:v1130p0001*
+ ID_MODEL_FROM_DATABASE=BlyncLight
+
usb:v1130p0002*
ID_MODEL_FROM_DATABASE=iBuddy
@@ -41933,6 +42233,72 @@ usb:v1209p1004*
usb:v1209p1005*
ID_MODEL_FROM_DATABASE=IBSecureCam-N
+usb:v1209p1006*
+ ID_MODEL_FROM_DATABASE=Mini IO-Board
+
+usb:v1209p2000*
+ ID_MODEL_FROM_DATABASE=Zygmunt Krynicki Lantern Brightness Sensor
+
+usb:v1209p2048*
+ ID_MODEL_FROM_DATABASE=Housedillon.com MRF49XA Transciever
+
+usb:v1209p2222*
+ ID_MODEL_FROM_DATABASE=LabConnect Signalgenerator
+
+usb:v1209p2300*
+ ID_MODEL_FROM_DATABASE=Keyboardio Keyboardio Model 01 Bootloader
+
+usb:v1209p2301*
+ ID_MODEL_FROM_DATABASE=Keyboardio Keyboardio Model 01
+
+usb:v1209p2337*
+ ID_MODEL_FROM_DATABASE=/Dev or SlashDev /Net
+
+usb:v1209p3000*
+ ID_MODEL_FROM_DATABASE=lloyd3000
+
+usb:v1209p3333*
+ ID_MODEL_FROM_DATABASE=LabConnect Digitalnetzteil
+
+usb:v1209p5222*
+ ID_MODEL_FROM_DATABASE=telavivmakers attami
+
+usb:v1209p5A22*
+ ID_MODEL_FROM_DATABASE=ikari_01 sd2snes
+
+usb:v1209p7BD0*
+ ID_MODEL_FROM_DATABASE=pokey9000 Tiny Bit Dingus
+
+usb:v1209pABD0*
+ ID_MODEL_FROM_DATABASE=tibounise ADB converter
+
+usb:v1209pBEEF*
+ ID_MODEL_FROM_DATABASE=Modal MC-USB
+
+usb:v1209pC0F5*
+ ID_MODEL_FROM_DATABASE=unethi PERswitch
+
+usb:v1209pCA1C*
+ ID_MODEL_FROM_DATABASE=KnightOS Hub
+
+usb:v1209pCA1D*
+ ID_MODEL_FROM_DATABASE=KnightOS MTP Device
+
+usb:v1209pCAFE*
+ ID_MODEL_FROM_DATABASE=ii iigadget
+
+usb:v1209pDADA*
+ ID_MODEL_FROM_DATABASE=Rebel Technology OWL
+
+usb:v1209pDEAD*
+ ID_MODEL_FROM_DATABASE=chaosfield.at AVR-Ruler
+
+usb:v1209pFA11*
+ ID_MODEL_FROM_DATABASE=moonglow OpenXHC
+
+usb:v1209pFEED*
+ ID_MODEL_FROM_DATABASE=ProgramGyar AVR-IR Sender
+
usb:v120E*
ID_VENDOR_FROM_DATABASE=Hudson Soft Co., Ltd
@@ -41963,6 +42329,12 @@ usb:v121E*
usb:v121Ep3403*
ID_MODEL_FROM_DATABASE=Muzio JM250 Audio Player
+usb:v1221*
+ ID_VENDOR_FROM_DATABASE=Unknown manufacturer
+
+usb:v1221p3234*
+ ID_MODEL_FROM_DATABASE=Disk (Thumb drive)
+
usb:v1223*
ID_VENDOR_FROM_DATABASE=SKYCABLE ENTERPRISE. CO., LTD.
@@ -42525,10 +42897,10 @@ usb:v12D1p1412*
ID_MODEL_FROM_DATABASE=EC168c
usb:v12D1p1436*
- ID_MODEL_FROM_DATABASE=E173 3G Modem (modem-mode)
+ ID_MODEL_FROM_DATABASE=Broadband stick
usb:v12D1p1446*
- ID_MODEL_FROM_DATABASE=E1552/E1800/E173 (HSPA modem)
+ ID_MODEL_FROM_DATABASE=Broadband stick (modem on)
usb:v12D1p1465*
ID_MODEL_FROM_DATABASE=K3765 HSPA
@@ -42588,7 +42960,7 @@ usb:v12D1p1805*
ID_MODEL_FROM_DATABASE=AT&T Go Phone U2800A phone
usb:v12D1p1C05*
- ID_MODEL_FROM_DATABASE=E173s 3G broadband stick (modem on)
+ ID_MODEL_FROM_DATABASE=Broadband stick (modem on)
usb:v12D1p1C0B*
ID_MODEL_FROM_DATABASE=E173s 3G broadband stick (modem off)
@@ -43139,6 +43511,9 @@ usb:v1390p0001*
usb:v1390p5454*
ID_MODEL_FROM_DATABASE=Blue & Me 2
+usb:v1390p7474*
+ ID_MODEL_FROM_DATABASE=GPS Sport Watch [Runner, Multi-Sport]
+
usb:v1391*
ID_VENDOR_FROM_DATABASE=IdealTEK, Inc.
@@ -43430,6 +43805,9 @@ usb:v13D3p3306*
usb:v13D3p3315*
ID_MODEL_FROM_DATABASE=Bluetooth module
+usb:v13D3p3362*
+ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth 4.0 Adapter
+
usb:v13D3p3375*
ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth 4.0 Adapter
@@ -43439,6 +43817,9 @@ usb:v13D3p3392*
usb:v13D3p3394*
ID_MODEL_FROM_DATABASE=Bluetooth
+usb:v13D3p3474*
+ ID_MODEL_FROM_DATABASE=Atheros AR3012 Bluetooth
+
usb:v13D3p5070*
ID_MODEL_FROM_DATABASE=Webcam
@@ -44243,9 +44624,6 @@ usb:v14E1*
usb:v14E1p5000*
ID_MODEL_FROM_DATABASE=PenMount 5000 Touch Controller
-usb:v14E4*
- ID_VENDOR_FROM_DATABASE=Broadcom Corp.
-
usb:v14E5*
ID_VENDOR_FROM_DATABASE=SAIN Information & Communications Co., Ltd.
@@ -44348,6 +44726,9 @@ usb:v1519*
usb:v1519p0020*
ID_MODEL_FROM_DATABASE=HSIC Device
+usb:v1519p0443*
+ ID_MODEL_FROM_DATABASE=Telit LN930
+
usb:v1520*
ID_VENDOR_FROM_DATABASE=Bitwire Corp.
@@ -44375,6 +44756,9 @@ usb:v1529p3100*
usb:v152A*
ID_VENDOR_FROM_DATABASE=Thesycon Systemsoftware & Consulting GmbH
+usb:v152Ap8350*
+ ID_MODEL_FROM_DATABASE=NET Gmbh iCube Camera
+
usb:v152Ap8400*
ID_MODEL_FROM_DATABASE=INI DVS128
@@ -44384,11 +44768,80 @@ usb:v152Ap840D*
usb:v152Ap841A*
ID_MODEL_FROM_DATABASE=INI DAViS FX3
+usb:v152B*
+ ID_VENDOR_FROM_DATABASE=MIR Srl
+
+usb:v152Bp0001*
+ ID_MODEL_FROM_DATABASE=spirobank II
+
+usb:v152Bp0002*
+ ID_MODEL_FROM_DATABASE=spirolab III
+
+usb:v152Bp0003*
+ ID_MODEL_FROM_DATABASE=MiniSpir
+
+usb:v152Bp0004*
+ ID_MODEL_FROM_DATABASE=Oxi
+
+usb:v152Bp0005*
+ ID_MODEL_FROM_DATABASE=spiros II
+
+usb:v152Bp0006*
+ ID_MODEL_FROM_DATABASE=smiths spirobank II
+
+usb:v152Bp0007*
+ ID_MODEL_FROM_DATABASE=smiths spirobank G-USB
+
+usb:v152Bp0008*
+ ID_MODEL_FROM_DATABASE=smiths MiniSpir
+
+usb:v152Bp0009*
+ ID_MODEL_FROM_DATABASE=spirobank G-USB
+
+usb:v152Bp000A*
+ ID_MODEL_FROM_DATABASE=smiths Oxi
+
+usb:v152Bp000B*
+ ID_MODEL_FROM_DATABASE=smiths spirolab III
+
+usb:v152Bp000C*
+ ID_MODEL_FROM_DATABASE=chorus III
+
+usb:v152Bp000D*
+ ID_MODEL_FROM_DATABASE=spirolab III Bw
+
+usb:v152Bp000E*
+ ID_MODEL_FROM_DATABASE=spirolab III
+
+usb:v152Bp000F*
+ ID_MODEL_FROM_DATABASE=easySpiro
+
+usb:v152Bp0010*
+ ID_MODEL_FROM_DATABASE=Spirotel converter
+
+usb:v152Bp0011*
+ ID_MODEL_FROM_DATABASE=spirobank
+
+usb:v152Bp0012*
+ ID_MODEL_FROM_DATABASE=spiro3 Zimmer
+
+usb:v152Bp0013*
+ ID_MODEL_FROM_DATABASE=spirotel serial
+
+usb:v152Bp0014*
+ ID_MODEL_FROM_DATABASE=spirotel II
+
+usb:v152Bp0015*
+ ID_MODEL_FROM_DATABASE=spirodoc
+
usb:v152D*
ID_VENDOR_FROM_DATABASE=JMicron Technology Corp. / JMicron USA Technology Corp.
usb:v152Dp0539*
- ID_MODEL_FROM_DATABASE=JMS539 SuperSpeed SATA II 3.0G Bridge
+ ID_MODEL_FROM_DATABASE=JMS539/567 SuperSpeed SATA II/III 3.0G/6.0G Bridge
+
+usb:v152Dp0567*
+ ID_MODEL_FROM_DATABASE=JMS567 SATA 6.0Gb/s bridge
usb:v152Dp0770*
ID_MODEL_FROM_DATABASE=Alienware Integrated Webcam
@@ -44417,6 +44870,18 @@ usb:v152Dp2352*
usb:v152Dp2509*
ID_MODEL_FROM_DATABASE=JMS539 SuperSpeed SATA II 3.0G Bridge
+usb:v152Dp2551*
+ ID_MODEL_FROM_DATABASE=JMS551 SATA 3Gb/s bridge
+
+usb:v152Dp2566*
+ ID_MODEL_FROM_DATABASE=JMS566 SATA 3Gb/s bridge
+
+usb:v152Dp3562*
+ ID_MODEL_FROM_DATABASE=JMS567 SATA 6.0Gb/s bridge
+
+usb:v152Dp3569*
+ ID_MODEL_FROM_DATABASE=ATA/ATAPI Bridge [AdPlus SuperVer]
+
usb:v152E*
ID_VENDOR_FROM_DATABASE=LG (HLDS)
@@ -44489,6 +44954,9 @@ usb:v153Bp1182*
usb:v1546*
ID_VENDOR_FROM_DATABASE=U-Blox AG
+usb:v1546p01A5*
+ ID_MODEL_FROM_DATABASE=NL-402U
+
usb:v1547*
ID_VENDOR_FROM_DATABASE=SG Intec Ltd & Co KG
@@ -44513,15 +44981,27 @@ usb:v154Bp0048*
usb:v154Bp004D*
ID_MODEL_FROM_DATABASE=8 GB Flash Drive
+usb:v154Bp0053*
+ ID_MODEL_FROM_DATABASE=Flash Drive
+
usb:v154Bp0057*
ID_MODEL_FROM_DATABASE=32GB Micro Slide Attache Flash Drive
+usb:v154Bp005B*
+ ID_MODEL_FROM_DATABASE=Flash Drive
+
+usb:v154Bp0062*
+ ID_MODEL_FROM_DATABASE=Flash Drive
+
usb:v154Bp007A*
- ID_MODEL_FROM_DATABASE=8GB Classic Attache Flash Drive
+ ID_MODEL_FROM_DATABASE=Classic Attache Flash Drive
usb:v154Bp6545*
ID_MODEL_FROM_DATABASE=FD Device
+usb:v154BpFA05*
+ ID_MODEL_FROM_DATABASE=Flash Drive
+
usb:v154D*
ID_VENDOR_FROM_DATABASE=ConnectCounty Holdings Berhad
@@ -44699,6 +45179,9 @@ usb:v15A9p0010*
usb:v15A9p0012*
ID_MODEL_FROM_DATABASE=WUBR-208N 802.11abgn Wireless Adapter [Ralink RT2870]
+usb:v15A9p002D*
+ ID_MODEL_FROM_DATABASE=WLTUBA-107 [Yota 4G LTE]
+
usb:v15AA*
ID_VENDOR_FROM_DATABASE=Gearway Electronics (Dong Guan) Co., Ltd.
@@ -45239,6 +45722,12 @@ usb:v1614p0600*
usb:v1614p0804*
ID_MODEL_FROM_DATABASE=WP-S1 Phone
+usb:v1617*
+ ID_VENDOR_FROM_DATABASE=Sony Corp.
+
+usb:v1617p2002*
+ ID_MODEL_FROM_DATABASE=NVX-P1 Personal Navigation System
+
usb:v1619*
ID_VENDOR_FROM_DATABASE=L & K Precision Technology Co., Ltd.
@@ -45276,7 +45765,7 @@ usb:v1631pC019*
ID_MODEL_FROM_DATABASE=RT2573
usb:v1645*
- ID_VENDOR_FROM_DATABASE=Cross Match Technologies GmbH
+ ID_VENDOR_FROM_DATABASE=Entrega [hex]
usb:v1645p0001*
ID_MODEL_FROM_DATABASE=1S Serial Port
@@ -45392,6 +45881,12 @@ usb:v165Cp0002*
usb:v1660*
ID_VENDOR_FROM_DATABASE=Creatix Polymedia GmbH
+usb:v1667*
+ ID_VENDOR_FROM_DATABASE=GIGA-TMS INC.
+
+usb:v1667p0005*
+ ID_MODEL_FROM_DATABASE=PCR330A RFID Reader (125 kHz, keyboard emulation)
+
usb:v1668*
ID_VENDOR_FROM_DATABASE=Actiontec Electronics, Inc. [hex]
@@ -45812,6 +46307,12 @@ usb:v16C0p06B4*
usb:v16C0p06B5*
ID_MODEL_FROM_DATABASE=USB2LPT with 3 interfaces (native, HID, printer)
+usb:v16C0p074E*
+ ID_MODEL_FROM_DATABASE=DSP-Weuffen USB-HPI-Programmer
+
+usb:v16C0p074F*
+ ID_MODEL_FROM_DATABASE=DSP-Weuffen USB2-HPI-Programmer
+
usb:v16C0p0762*
ID_MODEL_FROM_DATABASE=Osmocom SIMtrace
@@ -46031,6 +46532,9 @@ usb:v170D*
usb:v1711*
ID_VENDOR_FROM_DATABASE=Leica Microsystems
+usb:v1711p0101*
+ ID_MODEL_FROM_DATABASE=DFC-365FX camera
+
usb:v1711p3020*
ID_MODEL_FROM_DATABASE=IC80 HD Camera
@@ -46190,14 +46694,23 @@ usb:v1748p0101*
usb:v174C*
ID_VENDOR_FROM_DATABASE=ASMedia Technology Inc.
+usb:v174Cp1153*
+ ID_MODEL_FROM_DATABASE=ASM2115 SATA 6Gb/s bridge
+
+usb:v174Cp2074*
+ ID_MODEL_FROM_DATABASE=ASM1074 High-Speed hub
+
+usb:v174Cp3074*
+ ID_MODEL_FROM_DATABASE=ASM1074 SuperSpeed hub
+
usb:v174Cp5106*
- ID_MODEL_FROM_DATABASE=Transcend StoreJet 25M3
+ ID_MODEL_FROM_DATABASE=ASM1051 SATA 3Gb/s bridge
usb:v174Cp5136*
ID_MODEL_FROM_DATABASE=ASM1053 SATA 6Gb/s bridge
usb:v174Cp55AA*
- ID_MODEL_FROM_DATABASE=ASM1051 SATA 3Gb/s bridge
+ ID_MODEL_FROM_DATABASE=ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge
usb:v174F*
ID_VENDOR_FROM_DATABASE=Syntek
@@ -46316,6 +46829,36 @@ usb:v1781p083F*
usb:v1781p0938*
ID_MODEL_FROM_DATABASE=Iguanaworks USB IR Transceiver
+usb:v1781p0A96*
+ ID_MODEL_FROM_DATABASE=raphnet.net usb_game12
+
+usb:v1781p0A97*
+ ID_MODEL_FROM_DATABASE=raphnet.net SNES mouse adapter
+
+usb:v1781p0A98*
+ ID_MODEL_FROM_DATABASE=raphnet.net USBTenki
+
+usb:v1781p0A99*
+ ID_MODEL_FROM_DATABASE=raphnet.net NES
+
+usb:v1781p0A9A*
+ ID_MODEL_FROM_DATABASE=raphnet.net Gamecube/N64 controller
+
+usb:v1781p0A9B*
+ ID_MODEL_FROM_DATABASE=raphnet.net DB9Joy
+
+usb:v1781p0A9C*
+ ID_MODEL_FROM_DATABASE=raphnet.net Intellivision
+
+usb:v1781p0A9D*
+ ID_MODEL_FROM_DATABASE=raphnet.net 4nes4snes
+
+usb:v1781p0A9E*
+ ID_MODEL_FROM_DATABASE=raphnet.net Megadrive multitap
+
+usb:v1781p0A9F*
+ ID_MODEL_FROM_DATABASE=raphnet.net MultiDB9joy
+
usb:v1781p0C30*
ID_MODEL_FROM_DATABASE=Telldus TellStick
@@ -46328,6 +46871,12 @@ usb:v1781p0C9F*
usb:v1781p1EEF*
ID_MODEL_FROM_DATABASE=OpenAPC SecuKey
+usb:v1781p1EF0*
+ ID_MODEL_FROM_DATABASE=E1701 Modular Controller Card
+
+usb:v1781p1EF1*
+ ID_MODEL_FROM_DATABASE=E1701 Modular Controller Card
+
usb:v1782*
ID_VENDOR_FROM_DATABASE=Spreadtrum Communications Inc.
@@ -47369,6 +47918,18 @@ usb:v1995p3202*
usb:v1995p3203*
ID_MODEL_FROM_DATABASE=REC-A-ADPT-USB (recorder)
+usb:v1996*
+ ID_VENDOR_FROM_DATABASE=PixeLINK
+
+usb:v1996p3010*
+ ID_MODEL_FROM_DATABASE=Camera Release 4
+
+usb:v1996p3011*
+ ID_MODEL_FROM_DATABASE=OEM Camera
+
+usb:v1996p3012*
+ ID_MODEL_FROM_DATABASE=e-ImageData Corp. ScanPro
+
usb:v199B*
ID_VENDOR_FROM_DATABASE=MicroStrain, Inc.
@@ -49910,6 +50471,36 @@ usb:v2101*
usb:v2101p0201*
ID_MODEL_FROM_DATABASE=SIIG 4-to-2 Printer Switch
+usb:v2109*
+ ID_VENDOR_FROM_DATABASE=VIA Labs, Inc.
+
+usb:v2109p0700*
+ ID_MODEL_FROM_DATABASE=VL700 SATA 3Gb/s bridge
+
+usb:v2109p0701*
+ ID_MODEL_FROM_DATABASE=VL701 SATA 3Gb/s bridge
+
+usb:v2109p0810*
+ ID_MODEL_FROM_DATABASE=VL81x Hub
+
+usb:v2109p0811*
+ ID_MODEL_FROM_DATABASE=Hub
+
+usb:v2109p0812*
+ ID_MODEL_FROM_DATABASE=VL812 Hub
+
+usb:v2109p2811*
+ ID_MODEL_FROM_DATABASE=Hub
+
+usb:v2109p2812*
+ ID_MODEL_FROM_DATABASE=VL812 Hub
+
+usb:v2109p3431*
+ ID_MODEL_FROM_DATABASE=Hub
+
+usb:v2109p8110*
+ ID_MODEL_FROM_DATABASE=Hub
+
usb:v2149*
ID_VENDOR_FROM_DATABASE=Advanced Silicon S.A.
@@ -50492,6 +51083,15 @@ usb:v2478p2008*
usb:v249C*
ID_VENDOR_FROM_DATABASE=M2Tech s.r.l.
+usb:v24E1*
+ ID_VENDOR_FROM_DATABASE=Paratronic
+
+usb:v24E1p3001*
+ ID_MODEL_FROM_DATABASE=Adp-usb
+
+usb:v24E1p3005*
+ ID_MODEL_FROM_DATABASE=Radius
+
usb:v2632*
ID_VENDOR_FROM_DATABASE=TwinMOS
@@ -50762,6 +51362,54 @@ usb:v2899*
usb:v2899p012C*
ID_MODEL_FROM_DATABASE=Camera Device
+usb:v289B*
+ ID_VENDOR_FROM_DATABASE=Dracal/Raphnet technologies
+
+usb:v289Bp0001*
+ ID_MODEL_FROM_DATABASE=Gamecube/N64 controller v2.2
+
+usb:v289Bp0002*
+ ID_MODEL_FROM_DATABASE=2nes2snes
+
+usb:v289Bp0003*
+ ID_MODEL_FROM_DATABASE=4nes4snes
+
+usb:v289Bp0004*
+ ID_MODEL_FROM_DATABASE=Gamecube/N64 controller v2.3
+
+usb:v289Bp0005*
+ ID_MODEL_FROM_DATABASE=Saturn (Joystick mode)
+
+usb:v289Bp0006*
+ ID_MODEL_FROM_DATABASE=Saturn (Mouse mode)
+
+usb:v289Bp0007*
+ ID_MODEL_FROM_DATABASE=Famicom controller
+
+usb:v289Bp0008*
+ ID_MODEL_FROM_DATABASE=Dreamcast (Joystick mode)
+
+usb:v289Bp0009*
+ ID_MODEL_FROM_DATABASE=Dreamcast (Mouse mode)
+
+usb:v289Bp000A*
+ ID_MODEL_FROM_DATABASE=Dreamcast (Keyboard mode)
+
+usb:v289Bp000B*
+ ID_MODEL_FROM_DATABASE=Gamecube/N64 controller v2.9 (Keyboard mode)
+
+usb:v289Bp000C*
+ ID_MODEL_FROM_DATABASE=Gamecube/N64 controller v2.9 (Joystick mode)
+
+usb:v289Bp0100*
+ ID_MODEL_FROM_DATABASE=Dual-relay board
+
+usb:v289Bp0500*
+ ID_MODEL_FROM_DATABASE=Energy meter
+
+usb:v289Bp0502*
+ ID_MODEL_FROM_DATABASE=Precision barometer
+
usb:v2931*
ID_VENDOR_FROM_DATABASE=Jolla Oy
@@ -50777,6 +51425,111 @@ usb:v2931p0A05*
usb:v2931p0AFE*
ID_MODEL_FROM_DATABASE=Jolla charging only
+usb:v2A03*
+ ID_VENDOR_FROM_DATABASE=dog hunter AG
+
+usb:v2A03p0001*
+ ID_MODEL_FROM_DATABASE=Linino ONE (bootloader)
+
+usb:v2A03p0036*
+ ID_MODEL_FROM_DATABASE=Arduino Leonardo (bootloader)
+
+usb:v2A03p0037*
+ ID_MODEL_FROM_DATABASE=Arduino Micro (bootloader)
+
+usb:v2A03p0038*
+ ID_MODEL_FROM_DATABASE=Arduino Robot Control (bootloader)
+
+usb:v2A03p0039*
+ ID_MODEL_FROM_DATABASE=Arduino Robot Motor (bootloader)
+
+usb:v2A03p003A*
+ ID_MODEL_FROM_DATABASE=Arduino Micro ADK rev3 (bootloader)
+
+usb:v2A03p003B*
+ ID_MODEL_FROM_DATABASE=Arduino Serial
+
+usb:v2A03p003C*
+ ID_MODEL_FROM_DATABASE=Arduino Explora (bootloader)
+
+usb:v2A03p003D*
+ ID_MODEL_FROM_DATABASE=Arduino Due (usb2serial)
+
+usb:v2A03p003E*
+ ID_MODEL_FROM_DATABASE=Arduino Due
+
+usb:v2A03p0041*
+ ID_MODEL_FROM_DATABASE=Arduino Yun (bootloader)
+
+usb:v2A03p0042*
+ ID_MODEL_FROM_DATABASE=Arduino Mega 2560 Rev3
+
+usb:v2A03p0043*
+ ID_MODEL_FROM_DATABASE=Arduino Uno Rev3
+
+usb:v2A03p004D*
+ ID_MODEL_FROM_DATABASE=Arduino Zero Pro (bootloader)
+
+usb:v2A03p8001*
+ ID_MODEL_FROM_DATABASE=Linino ONE (CDC ACM)
+
+usb:v2A03p8036*
+ ID_MODEL_FROM_DATABASE=Arduino Leonardo (CDC ACM)
+
+usb:v2A03p8037*
+ ID_MODEL_FROM_DATABASE=Arduino Micro (CDC ACM)
+
+usb:v2A03p8038*
+ ID_MODEL_FROM_DATABASE=Arduino Robot Control (CDC ACM)
+
+usb:v2A03p8039*
+ ID_MODEL_FROM_DATABASE=Arduino Robot Motor (CDC ACM)
+
+usb:v2A03p803A*
+ ID_MODEL_FROM_DATABASE=Arduino Micro ADK rev3 (CDC ACM)
+
+usb:v2A03p803C*
+ ID_MODEL_FROM_DATABASE=Arduino Explora (CDC ACM)
+
+usb:v2A03p8041*
+ ID_MODEL_FROM_DATABASE=Arduino Yun (CDC ACM)
+
+usb:v2A03p804D*
+ ID_MODEL_FROM_DATABASE=Arduino Zero Pro (CDC ACM)
+
+usb:v2A37*
+ ID_VENDOR_FROM_DATABASE=RTD Embedded Technologies, Inc.
+
+usb:v2A37p5110*
+ ID_MODEL_FROM_DATABASE=UPS35110/UPS25110
+
+usb:v2A45*
+ ID_VENDOR_FROM_DATABASE=Meizu Corp.
+
+usb:v2A45p0001*
+ ID_MODEL_FROM_DATABASE=MX Phone (BICR)
+
+usb:v2A45p0C02*
+ ID_MODEL_FROM_DATABASE=MX Phone (MTP & ADB)
+
+usb:v2A45p0C03*
+ ID_MODEL_FROM_DATABASE=MX Phone (BICR & ADB)
+
+usb:v2A45p2008*
+ ID_MODEL_FROM_DATABASE=MX Phone (MTP)
+
+usb:v2A45p200A*
+ ID_MODEL_FROM_DATABASE=MX Phone (MTP & ACM & ADB)
+
+usb:v2A45p200B*
+ ID_MODEL_FROM_DATABASE=MX Phone (PTP)
+
+usb:v2A45p200C*
+ ID_MODEL_FROM_DATABASE=MX Phone (PTP & ADB)
+
+usb:v2A45p2012*
+ ID_MODEL_FROM_DATABASE=MX Phone (MTP & ACM)
+
usb:v2C02*
ID_VENDOR_FROM_DATABASE=Planex Communications
diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb
new file mode 100644
index 0000000000..815ac24511
--- /dev/null
+++ b/hwdb/60-evdev.hwdb
@@ -0,0 +1,104 @@
+# This file is part of systemd.
+#
+# The lookup keys are composed in:
+# 60-evdev.rules
+#
+# Note: The format of the "evdev:" prefix match key is a
+# contract between the rules file and the hardware data, it might
+# change in later revisions to support more or better matches, it
+# is not necessarily expected to be a stable ABI.
+#
+# Match string formats:
+# evdev:<modalias>
+# evdev:name:<device name>:dmi:<dmi string>
+#
+# To add local entries, create a new file
+# /etc/udev/hwdb.d/61-evdev-local.hwdb
+# and add your rules there. To load the new rules execute (as root):
+# udevadm hwdb --update
+# udevadm trigger /dev/input/eventXX
+# where /dev/input/eventXX is the device in question. If in
+# doubt, simply use /dev/input/event* to reload all input rules.
+#
+# If your changes are generally applicable, open a bug report on
+# http://bugs.freedesktop.org/enter_bug.cgi?product=systemd
+# and include your new rules, a description of the device, and the
+# output of
+# udevadm info /dev/input/eventXX
+# (or /dev/input/event*).
+#
+# Allowed properties are:
+# EVDEV_ABS_<axis>=<min>:<max>:<res>:<fuzz>:<flat>
+#
+# where <axis> is the hexadecimal EV_ABS code as listed in linux/input.h
+# and min, max, res, fuzz, flat are the decimal values to the respective
+# fields of the struct input_absinfo as listed in linux/input.h.
+# If a field is missing the field will be left as-is. Not all fields need to
+# be present. e.g. ::45 sets the resolution to 45 units/mm.
+
+#
+# Sort by brand, model
+
+#########################################
+# Apple
+#########################################
+
+# Macbook5,1 (unibody), aka wellspring3
+evdev:input:b0003v05ACp0236*
+evdev:input:b0003v05ACp0237*
+evdev:input:b0003v05ACp0238*
+ EVDEV_ABS_00=::92
+ EVDEV_ABS_01=::90
+ EVDEV_ABS_35=::92
+ EVDEV_ABS_36=::90
+
+# Macbook8 (unibody, March 2011)
+evdev:input:b0003v05ACp0245*
+evdev:input:b0003v05ACp0246*
+evdev:input:b0003v05ACp0247*
+ EVDEV_ABS_00=::92
+ EVDEV_ABS_01=::91
+ EVDEV_ABS_35=::92
+ EVDEV_ABS_36=::91
+
+# Macbook8,2 (unibody)
+evdev:input:b0003v05ACp0252*
+evdev:input:b0003v05ACp0253*
+evdev:input:b0003v05ACp0254*
+ EVDEV_ABS_00=::94
+ EVDEV_ABS_01=::92
+ EVDEV_ABS_35=::94
+ EVDEV_ABS_36=::92
+
+# MacbookPro10,1 (unibody, June 2012)
+evdev:input:b0003v05ACp0259*
+evdev:input:b0003v05ACp025a*
+evdev:input:b0003v05ACp025b*
+# MacbookPro10,2 (unibody, October 2012)
+evdev:input:b0003v05ACp0259*
+evdev:input:b0003v05ACp025a*
+evdev:input:b0003v05ACp025b*
+ EVDEV_ABS_00=::94
+ EVDEV_ABS_01=::92
+ EVDEV_ABS_35=::94
+ EVDEV_ABS_36=::92
+
+#########################################
+# Google
+#########################################
+
+# Chromebook Pixel (2015) - Samus
+evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus*
+ EVDEV_ABS_00=::10
+ EVDEV_ABS_01=::10
+ EVDEV_ABS_35=::10
+ EVDEV_ABS_36=::10
+
+#########################################
+# Lenovo
+#########################################
+
+# Lenovo X230 series
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230*
+ EVDEV_ABS_01=::100
+ EVDEV_ABS_36=::100
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 1b7d87101a..9c7e553a41 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -6,24 +6,26 @@
# The lookup keys are composed in:
# 60-keyboard.rules
#
-# Note: The format of the "keyboard:" prefix match key is a
+# Note: The format of the "evdev:" prefix match key is a
# contract between the rules file and the hardware data, it might
# change in later revisions to support more or better matches, it
# is not necessarily expected to be a stable ABI.
#
# Supported hardware matches are:
-# - USB keyboards identified by the usb kernel modalias:
-# keyboard:usb:vXXXXpYYYY*
-# XXXX is the 4-digit hex uppercase vendor, and YYYY
-# the 4-digit hex uppercase product.
+# - Generic input devices match:
+# evdev:input:bZZZZvYYYYpXXXXeWWWW-VVVV
+# This matches on the kernel modalias of the input-device, mainly:
+# ZZZZ is the bus-id (see /usr/include/linux/input.h BUS_*), YYYY, XXXX and
+# WWW are the 4-digit hex uppercase vendor, product and version ID and VVVV
+# is an arbitrary length input-modalias describing the device capabilities.
#
# - AT keyboard DMI data matches:
-# keyboard:dmi:bvn*:bvr*:bd*:svn<vendor>:pn<product>:pvr*
+# evdev:atkbd:dmi:bvn*:bvr*:bd*:svn<vendor>:pn<product>:pvr*
# <vendor> and <product> are the firmware-provided strings
# exported by the kernel DMI modalias.
#
-# - Platform driver device name and DMI data match:
-# keyboard:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*
+# - Input driver device name and DMI data match:
+# evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*
# <input device name> is the name device specified by the
# driver, <vendor> is the firmware-provided string exported
# by the kernel DMI modalias.
@@ -61,9 +63,9 @@
##########################################
# common keys
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*
-keyboard:dmi:bvn*:bvr*:bd*:svnGateway*:pnA0A1*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGateway*:pnA0A1*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:pvr*
KEYBOARD_KEY_a5=help # Fn+F1
KEYBOARD_KEY_a6=setup # Fn+F2 Acer eSettings
KEYBOARD_KEY_a7=battery # Fn+F3 Power Management
@@ -88,33 +90,33 @@ keyboard:dmi:bvn*:bvr*:bd*:svneMachines:pneMachines*E725:pvr*
KEYBOARD_KEY_f8=fn
KEYBOARD_KEY_f9=prog1 # Launch NTI shadow
-# Acer platform kernel driver
-keyboard:name:Acer WMI hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnAcer*:pvr*
+# Acer kernel driver
+evdev:name:Acer WMI hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnAcer*:pvr*
KEYBOARD_KEY_82=f21 # Touchpad toggle
# Aspire models
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*:pvr*
KEYBOARD_KEY_84=bluetooth # sent when bluetooth module missing, and key pressed
KEYBOARD_KEY_d9=bluetooth # Bluetooth off
KEYBOARD_KEY_92=media # Acer arcade
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5720*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnZG8*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5720*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnZG8*:pvr*
KEYBOARD_KEY_f4=prog3 # e-key
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5920G:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*5920G:*
KEYBOARD_KEY_8a=media
KEYBOARD_KEY_a6=setup
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*6920:*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*8930:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*6920:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*8930:*
KEYBOARD_KEY_ca=prog3 # key 'HOLD' on CineDash Media Console
KEYBOARD_KEY_83=rewind
KEYBOARD_KEY_89=fastforward
KEYBOARD_KEY_9e=back
# Travelmate C300
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr*
KEYBOARD_KEY_67=f24 # FIXME: rotate screen
KEYBOARD_KEY_68=up
KEYBOARD_KEY_69=down
@@ -122,66 +124,66 @@ keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*C3[01]0*:pvr*
KEYBOARD_KEY_6c=screenlock # FIXME: lock tablet device/buttons
# on some models this isn't brightnessup
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5210*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5220*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5610*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5620*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5720*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*4720*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*6593:*
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*1640:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5210*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5220*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5610*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5620*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pn*5720*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*4720*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnTravelMate*6593:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAspire*1640:*
KEYBOARD_KEY_ee=screenlock
-keyboard:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:pvr*
KEYBOARD_KEY_a9=!switchvideomode # Fn+F5
###########################################################
# Alienware
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*
KEYBOARD_KEY_8a=ejectcd
###########################################################
# Asus
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnASUS:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnASUS:pn*
KEYBOARD_KEY_ed=volumeup
KEYBOARD_KEY_ee=volumedown
KEYBOARD_KEY_ef=mute
-keyboard:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
-keyboard:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
-keyboard:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
+evdev:name:Asus WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
+evdev:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
+evdev:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
KEYBOARD_KEY_6b=f21 # Touchpad Toggle
###########################################################
# BenQ
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svn*BenQ*:pn*Joybook*R22*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*BenQ*:pn*Joybook*R22*:pvr*
KEYBOARD_KEY_6e=wlan
###########################################################
# Compal
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnCOMPAL:pnHEL80I:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCOMPAL:pnHEL80I:*
KEYBOARD_KEY_84=wlan
###########################################################
# COMPAQ
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*E500*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*Evo*N*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*E500*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnCompaq*:pn*Evo*N*:pvr*
KEYBOARD_KEY_a3=www # I key
KEYBOARD_KEY_9a=search
KEYBOARD_KEY_9e=email
KEYBOARD_KEY_9f=homepage
-keyboard:usb:v049Fp0051d*dc*dsc*dp*ic*isc*ip*in01*
+evdev:input:b0003v049Fp0051*
KEYBOARD_KEY_0c0011=presentation
KEYBOARD_KEY_0c0012=addressbook
KEYBOARD_KEY_0c0013=info
@@ -192,7 +194,7 @@ keyboard:usb:v049Fp0051d*dc*dsc*dp*ic*isc*ip*in01*
# Dell
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*
KEYBOARD_KEY_81=playpause # Play/Pause
KEYBOARD_KEY_82=stopcd # Stop
KEYBOARD_KEY_83=previoussong # Previous song
@@ -224,52 +226,53 @@ keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pn*
KEYBOARD_KEY_d9=f21 # Touchpad toggle
#
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*910:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*101[012]:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1110:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1210:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*910:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*101[012]:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1110:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1210:pvr*
KEYBOARD_KEY_84=wlan
# Dell Inspiron 1520
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:pvr*
KEYBOARD_KEY_85=unknown # Brightness Down, also emitted by acpi-video, ignore
KEYBOARD_KEY_86=unknown # Brightness Up, also emitted by acpi-video, ignore
# Latitude XT2
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*XT2:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*XT2:pvr*
KEYBOARD_KEY_9b=up # tablet rocker up
KEYBOARD_KEY_9e=enter # tablet rocker press
KEYBOARD_KEY_9f=back # tablet back
KEYBOARD_KEY_a3=down # tablet rocker down
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnStudio*155[78]:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnStudio*155[78]:pvr*
KEYBOARD_KEY_a0=! # mute
KEYBOARD_KEY_ae=! # volume down
KEYBOARD_KEY_b0=! # volume up
# Dell Touchpad
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:pvr*
+ KEYBOARD_KEY_88=! # wireless switch
KEYBOARD_KEY_9e=!f21
# Dell XPS
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS*:pvr*
KEYBOARD_KEY_8c=!unknown
# Dell XPS12 9Q33
-keyboard:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnXPS12-9Q33*:pvr*
KEYBOARD_KEY_88=wlan
- KEYBOARD_KEY_65=switchvideomode # Screen Rotate
+ KEYBOARD_KEY_65=direction # Screen Rotate
# Dell Latitude microphone mute
-keyboard:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*
+evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*
KEYBOARD_KEY_150=f20 # Mic mute toggle, should be micmute
###########################################################
# Everex
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:pvr*
KEYBOARD_KEY_5c=media
KEYBOARD_KEY_65=f21 # Fn+F5 Touchpad toggle
KEYBOARD_KEY_67=prog3 # Fan speed control button
@@ -282,39 +285,39 @@ keyboard:dmi:bvn*:bvr*:bd*:svnEverex:pnXT5000*:pvr*
# Fujitsu
##########################################
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*M*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*M*:pvr*
KEYBOARD_KEY_97=prog2
KEYBOARD_KEY_9f=prog1
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAmilo*Li*1718:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAmilo*Li*1718:*
KEYBOARD_KEY_d6=wlan
# Amilo Li 2732
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*Li*2732:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pnAMILO*Li*2732:*
KEYBOARD_KEY_d9=brightnessdown # Fn+F8 brightness down
KEYBOARD_KEY_ef=brightnessup # Fn+F9 brightness up
KEYBOARD_KEY_a9=switchvideomode # Fn+F10 Cycle between available video outputs
# Amilo Pa 2548
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pa*2548*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pa*2548*:pvr*
KEYBOARD_KEY_e0=volumedown
KEYBOARD_KEY_e1=volumeup
KEYBOARD_KEY_e5=prog1
# Amilo Pro Edition V3505
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*Edition*V3505*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*Edition*V3505*:pvr*
KEYBOARD_KEY_a5=help # Fn+F1
KEYBOARD_KEY_a9=switchvideomode # Fn+F3
KEYBOARD_KEY_d9=brightnessdown # Fn+F8
KEYBOARD_KEY_e0=brightnessup # Fn+F9
# Amilo Pro v3205
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*V3205*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*AMILO*Pro*V3205*:pvr*
KEYBOARD_KEY_f4=f21 # FIXME: silent-mode decrease CPU/GPU clock
KEYBOARD_KEY_f7=switchvideomode # Fn+F3
# Amilo Si 1520
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:pvr*
KEYBOARD_KEY_e1=wlan
KEYBOARD_KEY_f3=wlan
KEYBOARD_KEY_ee=brightnessdown
@@ -323,14 +326,14 @@ keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*Amilo*Si*1520*:pvr*
KEYBOARD_KEY_f7=video
# Esprimo Mobile V5
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V5*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V5*:pvr*
KEYBOARD_KEY_a9=switchvideomode
KEYBOARD_KEY_d9=brightnessdown
KEYBOARD_KEY_df=sleep
KEYBOARD_KEY_ef=brightnessup
# Esprimo Mobile V6
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V6*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V6*:pvr*
KEYBOARD_KEY_ce=brightnessup
KEYBOARD_KEY_ef=brightnessdown
@@ -338,7 +341,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*:pn*ESPRIMO*Mobile*V6*:pvr*
# GIGABYTE
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pnU2442:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pnU2442:*
KEYBOARD_KEY_a0=! # mute
###########################################################
@@ -346,7 +349,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pnU2442:*
###########################################################
# Slimstar 320
-keyboard:usb:v0458p0708d*dc*dsc*dp*ic*isc*ip*in01*
+evdev:input:b0003v0458p0708*
KEYBOARD_KEY_0900f0=scrollup
KEYBOARD_KEY_0900f1=scrolldown
KEYBOARD_KEY_0900f3=back
@@ -366,7 +369,7 @@ keyboard:usb:v0458p0708d*dc*dsc*dp*ic*isc*ip*in01*
# Hewlett Packard
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:pvr*
KEYBOARD_KEY_81=fn_esc
KEYBOARD_KEY_89=battery # Fn+F8
KEYBOARD_KEY_8a=screenlock # Fn+F6
@@ -381,7 +384,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:pvr*
KEYBOARD_KEY_ee=switchvideomode # Fn+F4
# Tablet
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:pvr*
KEYBOARD_KEY_82=prog2 # Funny Key
KEYBOARD_KEY_83=prog1 # Q
KEYBOARD_KEY_84=tab
@@ -390,55 +393,55 @@ keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][aA][bB][lL][eE][tT]*:pvr*
KEYBOARD_KEY_87=pagedown
# Pavilion
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*:pvr*
KEYBOARD_KEY_88=media # FIXME: quick play
KEYBOARD_KEY_b7=print
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:pvr*
KEYBOARD_KEY_b7=print
KEYBOARD_KEY_c2=media # FIXME: quick play
KEYBOARD_KEY_c6=break
KEYBOARD_KEY_94=reserved
# Elitebook
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2230s*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2230s*:pvr*
KEYBOARD_KEY_88=presentation
KEYBOARD_KEY_d9=help # I key (high keycode: "info")
# Presario
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Presario*CQ*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Presario*CQ*:pvr*
KEYBOARD_KEY_d8=f21
KEYBOARD_KEY_d9=f21
# 2510p 2530p
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2510p*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2530p*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*G60*Notebook*PC:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2510p*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2530p*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*G60*Notebook*PC:pvr*
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
# 2570p
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2570p*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*2570p*:pvr*
KEYBOARD_KEY_f8=wlan # Wireless HW switch button
# TX2
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][xX]2*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[tT][xX]2*:pvr*
KEYBOARD_KEY_c2=media
KEYBOARD_KEY_d8=!f23 # Toggle touchpad button on tx2 (OFF)
KEYBOARD_KEY_d9=!f22 # Toggle touchpad button on tx2 (ON)
# Presario 2100
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnPresario*2100*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnPresario*2100*:pvr*
KEYBOARD_KEY_f0=help
KEYBOARD_KEY_f1=screenlock
KEYBOARD_KEY_f3=search
# Elitebook 8440p
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:pvr*
KEYBOARD_KEY_88=www
KEYBOARD_KEY_a0=mute
KEYBOARD_KEY_ae=volumedown
@@ -446,20 +449,20 @@ keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8440p:pvr*
KEYBOARD_KEY_ec=mail
# Elitebook 8460p
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8460p:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*EliteBook*8460p:pvr*
KEYBOARD_KEY_f8=wlan # Wireless HW switch button
KEYBOARD_KEY_b3=prog1 # Fn+F11 - Ambient Light Sensor button
KEYBOARD_KEY_b1=prog2 # Fn+ESC - System information button
# HDX9494nr
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHDX9494NR:pvr*
KEYBOARD_KEY_b2=www # Fn+F3
KEYBOARD_KEY_d8=!f23 # touchpad off
KEYBOARD_KEY_d9=!f22 # touchpad on
# Chromebook 14
# Top row keys (between ESC and power button)
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:pvr*
KEYBOARD_KEY_3b=back
KEYBOARD_KEY_3c=forward
KEYBOARD_KEY_3d=refresh
@@ -474,11 +477,13 @@ keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:pvr*
# HP EliteBook 725 G2
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:pvr*
# HP ProBook 440 G2
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP440G2:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP440G2:pvr*
# HP ProBook 445 G1
-keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook445G1NotebookPC:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook445G1NotebookPC:pvr*
+# HP ProBook 450 G0
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook450G0:pvr*
KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute
###########################################################
@@ -486,7 +491,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook445G1NotebookPC:pvr*
###########################################################
# thinkpad_acpi driver
-keyboard:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:pvr*
+evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:pvr*
KEYBOARD_KEY_01=battery # Fn+F2
KEYBOARD_KEY_02=screenlock # Fn+F3
KEYBOARD_KEY_03=sleep # Fn+F4
@@ -505,7 +510,7 @@ keyboard:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnIBM*:pn*:pvr*
KEYBOARD_KEY_17=prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor")
# IBM Thinkpad USB Keyboard Trackpoint
-keyboard:usb:v04B3p301[89]*
+evdev:input:b0003v04B3p301[89]*
KEYBOARD_KEY_900f0=screenlock
KEYBOARD_KEY_900f1=wlan
KEYBOARD_KEY_900f2=switchvideomode
@@ -519,7 +524,7 @@ keyboard:usb:v04B3p301[89]*
###########################################################
# Symphony
-keyboard:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:pvr*
KEYBOARD_KEY_f3=prog2
KEYBOARD_KEY_f4=prog1
@@ -528,7 +533,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnINVENTEC:pnSYMPHONY*6.0/7.0:pvr*
###########################################################
# thinkpad_acpi driver
-keyboard:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
+evdev:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
KEYBOARD_KEY_01=screenlock
KEYBOARD_KEY_02=battery
KEYBOARD_KEY_03=sleep
@@ -548,7 +553,7 @@ keyboard:name:ThinkPad Extra Buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
KEYBOARD_KEY_1a=f20 # Microphone mute button; should be micmute
# ThinkPad Keyboard with TrackPoint
-keyboard:usb:v17EFp6009*
+evdev:input:b0003v17EFp6009*
KEYBOARD_KEY_090012=screenlock # Fn+F2
KEYBOARD_KEY_090013=battery # Fn+F3
KEYBOARD_KEY_090014=wlan # Fn+F5
@@ -563,7 +568,7 @@ keyboard:usb:v17EFp6009*
KEYBOARD_KEY_090010=f20 # Microphone mute button; should be micmute
# Lenovo 3000
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr*
KEYBOARD_KEY_8b=switchvideomode # Fn+F7 video
KEYBOARD_KEY_96=wlan # Fn+F5 wireless
KEYBOARD_KEY_97=sleep # Fn+F4 suspend
@@ -571,12 +576,12 @@ keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*3000*:pvr*
KEYBOARD_KEY_b4=prog1 # Lenovo Care
# "Lenovo Care" Key of the 3000 N200
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO:pn0769AP2:pvr3000N200:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn0769AP2:pvr3000N200:*
KEYBOARD_KEY_b4=prog1
# lenovo-ideapad
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr*
KEYBOARD_KEY_81=rfkill # does nothing in BIOS
KEYBOARD_KEY_83=display_off # BIOS toggles screen state
KEYBOARD_KEY_b9=brightnessup # does nothing in BIOS
@@ -586,8 +591,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnS10-*:pvr*
KEYBOARD_KEY_f3=f21
# Thinkpad X200_Tablet
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X2*Tablet*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*
KEYBOARD_KEY_5d=menu
KEYBOARD_KEY_63=fn
KEYBOARD_KEY_66=screenlock
@@ -596,7 +600,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X2*Tablet*
KEYBOARD_KEY_6c=direction # rotate screen
# ThinkPad X6 Tablet
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X6*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPad*X6*Tablet*
KEYBOARD_KEY_6c=direction # rotate
KEYBOARD_KEY_68=leftmeta # toolbox
KEYBOARD_KEY_6b=esc # escape
@@ -607,36 +611,36 @@ keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pnThinkPad*X6*:pvr*
KEYBOARD_KEY_69=enter # enter on d-pad
# ThinkPad X41 Tablet
-keyboard:dmi:bvn*:bvr*:bd*:svnIBM*:pn18666TU:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnIBM*:pn18666TU:pvr*
KEYBOARD_KEY_6c=direction # rotate
KEYBOARD_KEY_68=leftmeta # toolbox
KEYBOARD_KEY_6b=esc # escape
KEYBOARD_KEY_69=enter # enter on d-pad
# IdeaPad
-keyboard:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
+evdev:name:Ideapad extra buttons:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*
KEYBOARD_KEY_42=f23
KEYBOARD_KEY_43=f22
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*Y550*:pvr*
KEYBOARD_KEY_95=media
KEYBOARD_KEY_a3=play
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*IdeaPad*U300s*:pvr*
KEYBOARD_KEY_f1=f21
KEYBOARD_KEY_ce=f20 # micmute
-keyboard:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
KEYBOARD_KEY_a0=!mute
KEYBOARD_KEY_ae=!volumedown
KEYBOARD_KEY_b0=!volumeup
# V480
-keyboard:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
KEYBOARD_KEY_f1=f21
# enhanced USB keyboard
-keyboard:usb:v04B3p301B*
+evdev:input:b0003v04B3p301B*
KEYBOARD_KEY_90001=prog1 # ThinkVantage
KEYBOARD_KEY_90002=screenlock
KEYBOARD_KEY_90003=file
@@ -652,7 +656,7 @@ keyboard:usb:v04B3p301B*
###########################################################
# iTouch
-keyboard:usb:v046DpC308*
+evdev:input:b0003v046DpC308*
KEYBOARD_KEY_90001=shop # Shopping
KEYBOARD_KEY_90002=config # iTouch
KEYBOARD_KEY_90003=finance # Finance
@@ -661,12 +665,12 @@ keyboard:usb:v046DpC308*
KEYBOARD_KEY_C0183=media # Media
# Cordless Desktop S510
-keyboard:usb:v046DpC50C*
+evdev:input:b0003v046DpC50C*
KEYBOARD_KEY_d4=zoomin
KEYBOARD_KEY_cc=zoomout
# Wave cordless
-keyboard:usb:v046DpC317*
+evdev:input:b0003v046DpC317*
KEYBOARD_KEY_9001c=scale # expo
KEYBOARD_KEY_9001f=zoomout
KEYBOARD_KEY_90020=zoomin
@@ -685,7 +689,7 @@ keyboard:usb:v046DpC317*
KEYBOARD_KEY_9004c=ejectclosecd
# Wave cordless
-keyboard:usb:v046DpC517*
+evdev:input:b0003v046DpC517*
KEYBOARD_KEY_c101f=zoomout
KEYBOARD_KEY_c1020=zoomin
KEYBOARD_KEY_c1005=camera
@@ -701,7 +705,7 @@ keyboard:usb:v046DpC517*
KEYBOARD_KEY_c104c=ejectclosecd
# Cordless Wave Pro
-keyboard:usb:v046DpC52[9B]*
+evdev:input:b0003v046DpC52[9B]*
KEYBOARD_KEY_0c01b6=camera
KEYBOARD_KEY_0c0183=media
KEYBOARD_KEY_0c0184=wordprocessor
@@ -716,13 +720,13 @@ keyboard:usb:v046DpC52[9B]*
KEYBOARD_KEY_0c022e=zoomout
# Logitech Presenter R400
-keyboard:usb:v046DpC52Dd*dc*dsc*dp*ic*isc*ip*in00*
+evdev:input:b0003v046DpC52D*
KEYBOARD_KEY_070029=presentation
KEYBOARD_KEY_07003e=presentation
KEYBOARD_KEY_070037=displaytoggle
# Internet Navigator
-keyboard:usb:v046DpC309*
+evdev:input:b0003v046DpC309*
KEYBOARD_KEY_90001=chat # Messenger/SMS
KEYBOARD_KEY_90002=camera # webcam
KEYBOARD_KEY_90003=prog1 # iTouch
@@ -746,7 +750,7 @@ keyboard:usb:v046DpC309*
###########################################################
# Pro 7000
-keyboard:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr*
KEYBOARD_KEY_97=prog2
KEYBOARD_KEY_9f=prog1
KEYBOARD_KEY_a0=mute # Fn+F5
@@ -762,12 +766,12 @@ keyboard:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr*
###########################################################
# FID2060
-keyboard:dmi:bvn*:bvr*:bd*:svnMEDION*:pn*FID2060*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDION*:pn*FID2060*:pvr*
KEYBOARD_KEY_6b=channeldown # Thottle Down
KEYBOARD_KEY_6d=channelup # Thottle Up
# NB-A555
-keyboard:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:pvr*
KEYBOARD_KEY_63=www # N button
KEYBOARD_KEY_66=prog1 # link 1 button
KEYBOARD_KEY_67=email # envelope button
@@ -778,7 +782,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnMEDIONNB:pnA555*:pvr*
###########################################################
# Microsoft Natural Ergonomic Keyboard 4000
-keyboard:usb:v045Ep00DB*
+evdev:input:b0003v045Ep00DB*
KEYBOARD_KEY_c022d=zoomin
KEYBOARD_KEY_c022e=zoomout
@@ -786,8 +790,8 @@ keyboard:usb:v045Ep00DB*
# Micro Star
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*
-keyboard:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*
KEYBOARD_KEY_a0=mute # Fn+F9
KEYBOARD_KEY_ae=volumedown # Fn+F7
KEYBOARD_KEY_b0=volumeup # Fn+F8
@@ -803,29 +807,29 @@ keyboard:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*
KEYBOARD_KEY_f9=search
#
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE60*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE70*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE60*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnGE70*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*:pvr*
KEYBOARD_KEY_c2=ejectcd
# some MSI models generate ACPI/input events on the LNXVIDEO input devices,
# plus some extra synthesized ones on atkbd as an echo of actually changing the
# brightness; so ignore those atkbd ones, to avoid loops
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U-100*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U100*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*N033:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U-100*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*U100*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pn*N033:*
KEYBOARD_KEY_f7=reserved
KEYBOARD_KEY_f8=reserved
# MSI Wind U90/U100 generates separate touchpad on/off keycodes so ignore touchpad toggle keycode
-keyboard:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMICRO-STAR*:pnU90/U100:*
KEYBOARD_KEY_e4=reserved
###########################################################
# MSI
###########################################################
-keyboard:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][aA][rR]*:pvr*
+evdev:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][aA][rR]*:pvr*
KEYBOARD_KEY_0213=f22
KEYBOARD_KEY_0214=f23
@@ -834,7 +838,7 @@ keyboard:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT
###########################################################
# XO
-keyboard:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
KEYBOARD_KEY_59=fn
KEYBOARD_KEY_81=fn_esc
KEYBOARD_KEY_f9=camera
@@ -894,7 +898,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
# Onkyo
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnONKYO*CORPORATION:pnONKYOPC:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnONKYO*CORPORATION:pnONKYOPC:*
KEYBOARD_KEY_a0=mute # Fn+D
KEYBOARD_KEY_ae=volumedown # Fn+F
KEYBOARD_KEY_b0=volumeup # Fn+G
@@ -915,7 +919,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnONKYO*CORPORATION:pnONKYOPC:*
###########################################################
# Model 2
-keyboard:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:pvr*
KEYBOARD_KEY_8e=wlan
KEYBOARD_KEY_f0=switchvideomode
KEYBOARD_KEY_f1=mute
@@ -927,21 +931,21 @@ keyboard:dmi:bvn*:bvr*:bd*:svnOQO*Inc.*:pnOQO*Model*2*:pvr*
###########################################################
# Plantronics .Audio 626 DSP
-keyboard:usb:v047FpC006*
+evdev:input:b0003v047FpC006*
KEYBOARD_KEY_b002f=f20 # Microphone mute button; should be micmute
###########################################################
# Quanta
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*:rvnQuanta:rn30B7:rvr65.2B:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*:rvnQuanta:rn30B7:rvr65.2B:*
KEYBOARD_KEY_88=media # "quick play
###########################################################
# Samsung
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*
KEYBOARD_KEY_74=prog1 # User key
KEYBOARD_KEY_75=www
KEYBOARD_KEY_78=mail
@@ -960,26 +964,26 @@ keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*
KEYBOARD_KEY_f9=!f23 # Fn+F10 Touchpad off
# Series 3
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*200E[45]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*200E[45]*:pvr*
KEYBOARD_KEY_ce=! # Fn+F1 launch control setting
# Series 5
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*530U*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*530U*:pvr*
KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
KEYBOARD_KEY_a8=! # Fn Lock - Function lock on
KEYBOARD_KEY_a9=! # Fn Lock - Function lock off
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*550P*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*550P*:pvr*
KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
KEYBOARD_KEY_a8=! # Fn Lock - Function lock on
KEYBOARD_KEY_a9=! # Fn Lock - Function lock off
# Series 7 / 9
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700Z*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700G*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34]*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700Z*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700G*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr*
KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
KEYBOARD_KEY_a0=!mute # Fn+F6 mute
KEYBOARD_KEY_ae=!volumedown # Fn+F7
@@ -988,14 +992,14 @@ keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:pvr*
KEYBOARD_KEY_96=!kbdillumup # Fn+F10 keyboard backlight up
KEYBOARD_KEY_b3=!prog3 # Fn+F11 fan/cooling mode changer
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][AB]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][AB]*:pvr*
KEYBOARD_KEY_ce=! # Fn+F8 keyboard backlight up
KEYBOARD_KEY_8d=! # Fn+F7 keyboard backlight down
KEYBOARD_KEY_96=! # Fn+F1 performance mode (?)
KEYBOARD_KEY_97=! # Fn+F12 Wi-Fi toggle
KEYBOARD_KEY_d5=! # Fn+F6 battery life extender
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:pvr*
KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
KEYBOARD_KEY_8d=!prog3 # Fn+F6 performance mode
KEYBOARD_KEY_97=!kbdillumdown # Fn+F7 keyboard backlight down
@@ -1003,15 +1007,21 @@ keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*90X3A*:pvr*
KEYBOARD_KEY_d5=!wlan # Fn+F12 Wi-Fi toggle
# Series 7 Ultra
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*7[34]0U3E*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*7[34]0U3E*:pvr*
KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
KEYBOARD_KEY_97=!kbdillumdown # Fn+F9 keyboard backlight down
KEYBOARD_KEY_96=!kbdillumup # Fn+F10 keyboard backlight up
KEYBOARD_KEY_b3=!prog3 # Fn+F11 fan/cooling mode changer
KEYBOARD_KEY_d5=!wlan # Fn+F12 wlan/airplane switch
+# ATIV Book 6 / 8
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*[68][78]0Z*:pvr*
+ KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings
+ KEYBOARD_KEY_96=!kbdillumup # Fn+F10 keyboard backlight up
+ KEYBOARD_KEY_97=!kbdillumdown # Fn+F9 keyboard backlight down
+
# SQ1US
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:pvr*
KEYBOARD_KEY_d4=menu
KEYBOARD_KEY_d8=f1
KEYBOARD_KEY_d9=f10
@@ -1021,13 +1031,13 @@ keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pnSQ1US:pvr*
KEYBOARD_KEY_ee=f11
# SX20S
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*SX20S*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*SX20S*:pvr*
KEYBOARD_KEY_74=mute
KEYBOARD_KEY_75=mute
KEYBOARD_KEY_77=f22 # Touchpad on
KEYBOARD_KEY_79=f23 # Touchpad off
-keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:pvr*
KEYBOARD_KEY_ad=leftmeta
###########################################################
@@ -1035,7 +1045,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*700T*:pvr*
###########################################################
# sony-laptop driver
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*
KEYBOARD_KEY_06=mute # Fn+F2
KEYBOARD_KEY_07=volumedown # Fn+F3
KEYBOARD_KEY_08=volumeup # Fn+F4
@@ -1045,22 +1055,22 @@ keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*
KEYBOARD_KEY_0e=zoom # Fn+F10
KEYBOARD_KEY_10=suspend # Fn+F12
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-C1*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-K25*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-F[1-6]*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FX*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FRV*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-GR*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-TR*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-NV*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-Z*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*VGN-S360*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-C1*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-K25*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-F[1-6]*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FX*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-FRV*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-GR*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-TR*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-NV*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*PCG-Z*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pn*VGN-S360*:pvr*
KEYBOARD_KEY_06=battery
KEYBOARD_KEY_07=mute
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-AR71*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW*:pvr*
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-AR71*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:pvr*
KEYBOARD_KEY_00=brightnessdown # Fn+F5
KEYBOARD_KEY_10=brightnessup # Fn+F6
KEYBOARD_KEY_11=switchvideomode # Fn+F7
@@ -1070,10 +1080,10 @@ keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-Z21*:pvr*
KEYBOARD_KEY_17=prog1
KEYBOARD_KEY_20=media
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW250*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVGN-FW250*:pvr*
KEYBOARD_KEY_10=suspend # Fn+F12
-keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:pvr*
+evdev:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:pvr*
KEYBOARD_KEY_05=f21 # Fn+F1 -> KEY_F21 (The actual touchpad toggle)
KEYBOARD_KEY_0d=zoomout # Fn+F9
KEYBOARD_KEY_0e=zoomin # Fn+F10
@@ -1083,12 +1093,12 @@ keyboard:name:Sony Vaio Keys:dmi:bvn*:bvr*:bd*:svnSony*:pnVPC*:pvr*
###########################################################
# Satellite A100
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITE*A100:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITE*A100:pvr*
KEYBOARD_KEY_a4=stopcd
KEYBOARD_KEY_b2=www
# Satellite A110
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:pvr*
KEYBOARD_KEY_92=stop
KEYBOARD_KEY_93=www
KEYBOARD_KEY_94=media
@@ -1101,7 +1111,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*A110:pvr*
KEYBOARD_KEY_f7=playpause
# Satellite M30X
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:pvr*
KEYBOARD_KEY_ef=brightnessdown
KEYBOARD_KEY_d9=brightnessup
KEYBOARD_KEY_ee=screenlock
@@ -1110,21 +1120,21 @@ keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*M30X:pvr*
KEYBOARD_KEY_9f=f23 # touchpad disable
# Satellite P75-A
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr*
KEYBOARD_KEY_ef=brightnessdown
KEYBOARD_KEY_ee=brightnessup
KEYBOARD_KEY_a9=switchvideomode # switch display outputs
KEYBOARD_KEY_d4=wlan # RF Switch Off
# Satellite U940
-keyboard:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITEU940:pvr*
+evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSATELLITEU940:pvr*
KEYBOARD_KEY_13c=brightnessdown
KEYBOARD_KEY_13d=brightnessup
KEYBOARD_KEY_13e=switchvideomode
KEYBOARD_KEY_13f=f21 # Touchpad toggle
# Satellite P75-A7200
-keyboard:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr*
+evdev:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75-A:pvr*
KEYBOARD_KEY_13c=brightnessdown
KEYBOARD_KEY_13d=brightnessup
KEYBOARD_KEY_13e=switchvideomode
@@ -1135,7 +1145,7 @@ keyboard:name:Toshiba*input*device:dmi:bvn*:bvr*:bd*:svnTOSHIBA*:pnSatellite*P75
# VIA
###########################################################
-keyboard:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:pvr*
KEYBOARD_KEY_81=prog1
###########################################################
@@ -1143,7 +1153,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnVIA:pnK8N800:pvr*
###########################################################
# Znote
-keyboard:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote:*
KEYBOARD_KEY_93=switchvideomode # Fn+F3 Toggle Video Output
KEYBOARD_KEY_95=brightnessdown # Fn+F4 Brightness Down
KEYBOARD_KEY_91=brightnessup # Fn+F5 Brightness Up
@@ -1160,7 +1170,7 @@ keyboard:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote:*
KEYBOARD_KEY_b0=! # volume up
# Znote 6615WD
-keyboard:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote*6615WD:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote*6615WD:*
KEYBOARD_KEY_a0=! # mute
KEYBOARD_KEY_ae=! # volume down
KEYBOARD_KEY_b0=! # volume up
@@ -1170,21 +1180,21 @@ keyboard:dmi:bvn*:bvr*:bd*:svnZepto:pnZnote*6615WD:*
###########################################################
# Common Volume Keys
-keyboard:dmi:bvn*:bvr*:bd*:svnFUJITSU*SIEMENS:pnAMILO*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnFOXCONN:pnQBOOK:*
-keyboard:dmi:bvn*:bvr*:bd*:svnMTC:pn*:pvrA0:*
-keyboard:dmi:bvn*:bvr*:bd*:svnMio*Technology:pnN890:*
-keyboard:dmi:bvn*:bvr*:bd*:svnPEGATRON*CORP.:pnSpring*Peak:*
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*[uU][35]0[05]*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSATELLITE*[uU][35]0[05]*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*Pro*[uU]300*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnEQUIUM [uU][35]0[05]*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnViooo*Corporation:pnPT17:*
-keyboard:dmi:bvn*:bvr*:bd*:svnHANNspree:pnSN10E100:*
-keyboard:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pni1520M:*
-keyboard:dmi:bvn*:bvr*:bd*:svnBenQ:pn*nScreen*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnBenQ:pnJoybook*Lite*:pvr*
-keyboard:dmi:bvn*:bvr*:bd*:svnDIXONSP:pnDIXON*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFUJITSU*SIEMENS:pnAMILO*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnFOXCONN:pnQBOOK:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMTC:pn*:pvrA0:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMio*Technology:pnN890:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPEGATRON*CORP.:pnSpring*Peak:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*[uU][35]0[05]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSATELLITE*[uU][35]0[05]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnSatellite*Pro*[uU]300*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnTOSHIBA:pnEQUIUM [uU][35]0[05]*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnViooo*Corporation:pnPT17:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHANNspree:pnSN10E100:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnGIGABYTE:pni1520M:*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnBenQ:pn*nScreen*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnBenQ:pnJoybook*Lite*:pvr*
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDIXONSP:pnDIXON*:pvr*
KEYBOARD_KEY_a0=! # mute
KEYBOARD_KEY_ae=! # volume down
KEYBOARD_KEY_b0=! # volume up
diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb
index a62ebc497d..2784b941a1 100644
--- a/hwdb/70-mouse.hwdb
+++ b/hwdb/70-mouse.hwdb
@@ -98,10 +98,20 @@
#
#
-# Sort by by brand, type (usb, bluetooth), DPI, frequency.
+# Sort by brand, type (usb, bluetooth), DPI, frequency.
# For mice with switchable resolution, sort by the starred entry.
##########################################
+# Apple
+##########################################
+
+# Apple MagicMouse
+# Note: this device changes name once connected to a mac, the name ends up
+# as $username`s mouse
+mouse:bluetooth:v05acp030d:name:*:
+ MOUSE_DPI=1300@1000
+
+##########################################
# Chicony
##########################################
@@ -125,6 +135,14 @@ mouse:usb:v0461p4d16:name:USB Optical Mouse:
MOUSE_DPI=500@125
##########################################
+# HP
+##########################################
+
+# HP X1000
+mouse:usb:v093ap2510:name:PixArt USB Optical Mouse:
+ MOUSE_DPI=1000@125
+
+##########################################
# Lenovo
##########################################
@@ -190,12 +208,18 @@ mouse:usb:v046dpc245:name:Logitech Gaming Mouse G400:
mouse:usb:v046dpc24c:name:Logitech G400s Optical Gaming Mouse:
MOUSE_DPI=400@1000 *800@1000 2000@1000 4000@1000
+# Logitech M570 trackball
+mouse:usb:v046dp1028:name:Logitech M570:
+ MOUSE_DPI=540@167
+
# Logitech Wireless Mouse M185
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4008:
# Logitech M705 (marathon mouse)
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:101b:
MOUSE_DPI=800@166
+# Logitech G5 Laser Mouse
+mouse:usb:v046dpc049:name:Logitech USB Gaming Mouse:
# Logitech G500s Laser Gaming Mouse
mouse:usb:v046dpc24e:name:Logitech G500s Laser Gaming Mouse:
MOUSE_DPI=400@500 *800@500 2000@500
@@ -266,6 +290,10 @@ mouse:usb:v045ep07b1:name:Microsoft Microsoft® Nano Transceiver v1.0:
mouse:bluetooth:v045ep0702:name:Microsoft Wireless Laser Mouse 8000:
MOUSE_DPI=1000@1000
+# Microsoft Arc Touch Mouse SE:
+mouse:bluetooth:v045ep07f3:name:Arc Touch Mouse SE:
+ MOUSE_DPI=1000@2000
+
##########################################
# Oklick
##########################################
@@ -281,3 +309,12 @@ mouse:bluetooth:v056ep0061:name:Laser BTmouse:
# Razer Abyssus
mouse:usb:v1532p0042:name:Razer Razer Abyssus:
MOUSE_DPI=3500@1000
+
+##########################################
+# Roccat
+##########################################
+
+# Roccat Lua (ROC-11-310)
+mouse:usb:v1e7dp2c2e:name:ROCCAT ROCCAT Lua:
+ MOUSE_DPI=250@125 500@125 1000@125 1250@125 1500@125 1750@125 2000@125 250@250 500@250 1000@250 1250@250 1500@250 1750@250 2000@250 250@500 500@500 1000@500 1250@500 1500@500 1750@500 2000@500 250@1000 500@1000 *1000@1000 1250@1000 1500@1000 1750@1000 2000@1000
+ MOUSE_WHEEL_CLICK_ANGLE=15
diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb
new file mode 100644
index 0000000000..a8c21a2ee6
--- /dev/null
+++ b/hwdb/70-pointingstick.hwdb
@@ -0,0 +1,107 @@
+# This file is part of systemd.
+#
+# Pointingstick const-accel configuration, to make different brand / model
+# laptop pointingsticks have the same speed / feel, and per model adjustment
+# of the IBM TrackPoint driver's sensitivity setting
+#
+# The lookup keys are composed in:
+# 60-evdev.rules
+#
+# Note: The format of the "evdev:" prefix match key is a contract between the
+# rules file and the hardware data, it might change in later revisions to
+# support more or better matches, it is not necessarily a stable ABI.
+#
+# Supported hardware matches are:
+# - Generic input devices match:
+# evdev:input:bZZZZvYYYYpXXXXeWWWW-VVVV
+# This matches on the kernel modalias of the input-device, mainly:
+# ZZZZ is the bus-id (see /usr/include/linux/input.h BUS_*), YYYY, XXXX and
+# WWW are the 4-digit hex uppercase vendor, product and version ID and VVVV
+# is an arbitrary length input-modalias describing the device capabilities.
+#
+# - Input driver device name and DMI data match:
+# evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*
+# <input device name> is the name device specified by the driver,
+# <vendor> is the firmware-provided string from the kernel DMI modalias.
+#
+# To add local entries, create a new file
+# /etc/udev/hwdb.d/71-pointingstick-local.hwdb
+# and add your rules there. To load the new rules execute (as root):
+# udevadm hwdb --update
+# udevadm trigger /dev/input/eventXX
+# where /dev/input/eventXX is the pointingstick in question. If in
+# doubt, simply use /dev/input/event* to reload all input rules.
+#
+# If your changes are generally applicable, open a bug report on
+# http://bugs.freedesktop.org/enter_bug.cgi?product=systemd
+# and include your new rules, a description of the device, and the
+# output of
+# udevadm info /dev/input/eventXX
+# (or /dev/input/event*).
+#
+# Allowed properties are:
+# POINTINGSTICK_CONST_ACCEL
+# POINTINGSTICK_SENSITIVITY
+#
+# Entries should be sorted with growing _SENSITIVITY and _CONST_ACCEL.
+#
+#########################################
+# POINTINGSTICK_CONST_ACCEL #
+#########################################
+#
+# Trackpoint const accel settings are specified as
+# POINTINGSTICK_CONST_ACCEL=<accel>
+#
+# Where <accel> is a floating point number, using a '.' seperator, specifying
+# by how much to multiply deltas generated by the pointingstick to get
+# normalized deltas.
+#
+#########################################
+# POINTINGSTICK_SENSITIVITY #
+#########################################
+#
+# TPPS/2 IBM TrackPoint driver sensitivity sysfs setting
+# POINTINGSTICK_SENSITIVITY=<sensitivity>
+#
+# Where <sensitivity> is a number between 0 and 255, note this property
+# only applies to TPPS/2 IBM TrackPoint devices, see
+# drivers/input/mouse/trackpoint.c in the Linux kernel sources.
+#
+
+#
+# Sort by by brand, model
+
+#########################################
+# Dell
+#########################################
+
+# Latitude D620
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeD620*:pvr*
+ POINTINGSTICK_CONST_ACCEL=0.5
+
+# Latitude E6400
+evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:pvr*
+ POINTINGSTICK_CONST_ACCEL=1.5
+
+#########################################
+# Lenovo
+#########################################
+
+# Lenovo Thinkpad X230 tablet
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX230Tablet:*
+# Lenovo Thinkpad X240
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX240:*
+# Lenovo Thinkpad T440s
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT440s:*
+# Lenovo Thinkpad T540p
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT540p:*
+ POINTINGSTICK_SENSITIVITY=200
+ POINTINGSTICK_CONST_ACCEL=1.0
+
+# Lenovo Thinkpad X200s / X201s
+# Note these come with 2 revisions of keyboard, with the trackpoints having a
+# different sensitivity in the different revisions. 1.25 is a bit slow for the
+# least sensitive revision, but it is better to be a bit slow than too fast.
+evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX20?s:*
+ POINTINGSTICK_SENSITIVITY=200
+ POINTINGSTICK_CONST_ACCEL=1.25
diff --git a/hwdb/70-touchpad.hwdb b/hwdb/70-touchpad.hwdb
index bbf44db778..8a324466b3 100644
--- a/hwdb/70-touchpad.hwdb
+++ b/hwdb/70-touchpad.hwdb
@@ -36,4 +36,8 @@
# Lenovo X1 Carbon 3rd
touchpad:pnpid:*LEN0048*:
+# Lenovo W541
+touchpad:pnpid:*LEN004a*:
+# Lenovo T450s
+touchpad:pnpid:*LEN200f*:
TOUCHPAD_HAS_TRACKPOINT_BUTTONS=1
diff --git a/hwdb/sdio.ids b/hwdb/sdio.ids
index 8a4c7136d2..d61729744e 100644
--- a/hwdb/sdio.ids
+++ b/hwdb/sdio.ids
@@ -34,6 +34,16 @@
5347 GDM72xx WiMAX
02d0 Broadcom Corp.
044b Nintendo Wii WLAN daughter card
+ a887 BCM43143 WLAN card
+ 4324 BCM43241 WLAN card
+ 4329 BCM4329 WLAN card
+ 4330 BCM4330 WLAN card
+ 4334 BCM4334 WLAN card
+ a94c BCM43340 WLAN card
+ a94d BCM43341 WLAN card
+ 4335 BCM4335/BCM4339 WLAN card
+ a962 BCM43362 WLAN card
+ 4354 BCM4354 WLAN card
02db SyChip Inc.
0002 Pegasus WLAN SDIO Card (6060SD)
02df Marvell Technology Group Ltd.
diff --git a/m4/.gitignore b/m4/.gitignore
index cf35a86e88..55eaa803a1 100644
--- a/m4/.gitignore
+++ b/m4/.gitignore
@@ -4,4 +4,3 @@ ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
-gtk-doc.m4
diff --git a/m4/arch.m4 b/m4/arch.m4
new file mode 100644
index 0000000000..f17b4278eb
--- /dev/null
+++ b/m4/arch.m4
@@ -0,0 +1,13 @@
+
+dnl SET_ARCH(ARCHNAME, PATTERN)
+dnl
+dnl Define ARCH_<archname> condition if the pattern match with the current
+dnl architecture
+dnl
+AC_DEFUN([SET_ARCH], [
+ cpu_$1=false
+ case "$host" in
+ $2) cpu_$1=true ;;
+ esac
+ AM_CONDITIONAL(AS_TR_CPP(ARCH_$1), [test "x$cpu_$1" = xtrue])
+])
diff --git a/m4/attributes.m4 b/m4/attributes.m4
index ac3c6624cd..97f094b07a 100644
--- a/m4/attributes.m4
+++ b/m4/attributes.m4
@@ -34,14 +34,15 @@ dnl this special exception to the GPL to apply to your modified version as
dnl well.
dnl Check if FLAG in ENV-VAR is supported by compiler and append it
-dnl to WHERE-TO-APPEND variable
+dnl to WHERE-TO-APPEND variable. Note that we invert -Wno-* checks to
+dnl -W* as gcc cannot test for negated warnings.
dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG])
AC_DEFUN([CC_CHECK_FLAG_APPEND], [
AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2],
AS_TR_SH([cc_cv_$2_$3]),
[eval "AS_TR_SH([cc_save_$2])='${$2}'"
- eval "AS_TR_SH([$2])='-Werror $3'"
+ eval "AS_TR_SH([$2])='-Werror `echo "$3" | sed 's/^-Wno-/-W/'`'"
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; } ])],
[eval "AS_TR_SH([cc_cv_$2_$3])='yes'"],
[eval "AS_TR_SH([cc_cv_$2_$3])='no'"])
diff --git a/m4/ax_normalize_path.m4 b/m4/ax_normalize_path.m4
new file mode 100644
index 0000000000..e8f9973e35
--- /dev/null
+++ b/m4/ax_normalize_path.m4
@@ -0,0 +1,115 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_normalize_path.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_NORMALIZE_PATH(VARNAME, [REFERENCE_STRING])
+#
+# DESCRIPTION
+#
+# Perform some cleanups on the value of $VARNAME (interpreted as a path):
+#
+# - empty paths are changed to '.'
+# - trailing slashes are removed
+# - repeated slashes are squeezed except a leading doubled slash '//'
+# (which might indicate a networked disk on some OS).
+#
+# REFERENCE_STRING is used to turn '/' into '\' and vice-versa: if
+# REFERENCE_STRING contains some backslashes, all slashes and backslashes
+# are turned into backslashes, otherwise they are all turned into slashes.
+#
+# This makes processing of DOS filenames quite easier, because you can
+# turn a filename to the Unix notation, make your processing, and turn it
+# back to original notation.
+#
+# filename='A:\FOO\\BAR\'
+# old_filename="$filename"
+# # Switch to the unix notation
+# AX_NORMALIZE_PATH([filename], ["/"])
+# # now we have $filename = 'A:/FOO/BAR' and we can process it as if
+# # it was a Unix path. For instance let's say that you want
+# # to append '/subpath':
+# filename="$filename/subpath"
+# # finally switch back to the original notation
+# AX_NORMALIZE_PATH([filename], ["$old_filename"])
+# # now $filename equals to 'A:\FOO\BAR\subpath'
+#
+# One good reason to make all path processing with the unix convention is
+# that backslashes have a special meaning in many cases. For instance
+#
+# expr 'A:\FOO' : 'A:\Foo'
+#
+# will return 0 because the second argument is a regex in which
+# backslashes have to be backslashed. In other words, to have the two
+# strings to match you should write this instead:
+#
+# expr 'A:\Foo' : 'A:\\Foo'
+#
+# Such behavior makes DOS filenames extremely unpleasant to work with. So
+# temporary turn your paths to the Unix notation, and revert them to the
+# original notation after the processing. See the macro
+# AX_COMPUTE_RELATIVE_PATHS for a concrete example of this.
+#
+# REFERENCE_STRING defaults to $VARIABLE, this means that slashes will be
+# converted to backslashes if $VARIABLE already contains some backslashes
+# (see $thirddir below).
+#
+# firstdir='/usr/local//share'
+# seconddir='C:\Program Files\\'
+# thirddir='C:\home/usr/'
+# AX_NORMALIZE_PATH([firstdir])
+# AX_NORMALIZE_PATH([seconddir])
+# AX_NORMALIZE_PATH([thirddir])
+# # $firstdir = '/usr/local/share'
+# # $seconddir = 'C:\Program Files'
+# # $thirddir = 'C:\home\usr'
+#
+# LICENSE
+#
+# Copyright (c) 2008 Alexandre Duret-Lutz <adl@gnu.org>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 5
+
+AU_ALIAS([ADL_NORMALIZE_PATH], [AX_NORMALIZE_PATH])
+AC_DEFUN([AX_NORMALIZE_PATH],
+[case ":[$]$1:" in
+# change empty paths to '.'
+ ::) $1='.' ;;
+# strip trailing slashes
+ :*[[\\/]]:) $1=`echo "[$]$1" | sed 's,[[\\/]]*[$],,'` ;;
+ :*:) ;;
+esac
+# squeze repeated slashes
+case ifelse($2,,"[$]$1",$2) in
+# if the path contains any backslashes, turn slashes into backslashes
+ *\\*) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1\\\\,g'` ;;
+# if the path contains slashes, also turn backslashes into slashes
+ *) $1=`echo "[$]$1" | sed 's,\(.\)[[\\/]][[\\/]]*,\1/,g'` ;;
+esac])
diff --git a/man/binfmt.d.xml b/man/binfmt.d.xml
index 5b63cfb4c3..3aa5eb1859 100644
--- a/man/binfmt.d.xml
+++ b/man/binfmt.d.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/bootchart.conf.xml b/man/bootchart.conf.xml
index 8d9700d300..b383f6e24d 100644
--- a/man/bootchart.conf.xml
+++ b/man/bootchart.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -52,24 +55,23 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/bootchart.conf</filename></para>
- <para><filename>/etc/systemd/bootchart.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/bootchart.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/bootchart.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/bootchart.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/bootchart.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/bootchart.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>When starting, systemd-bootchart will read the configuration
- file <filename>/etc/systemd/bootchart.conf</filename>, followed by
+ file <filename>&pkgsysconfdir;/bootchart.conf</filename>, followed by
the files in the <filename>bootchart.conf.d</filename>
directories. These configuration files determine logging
parameters and graph output.</para>
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
@@ -123,10 +125,10 @@
<term><varname>Init=[path]</varname></term>
<listitem><para>Configures bootchart to run a non-standard
binary instead of
- <filename>/usr/lib/systemd/systemd</filename>. This option is
+ <filename>&rootlibexecdir;/systemd</filename>. This option is
only relevant if bootchart was invoked from the kernel command
line with
- init=/usr/lib/systemd/systemd-bootchart.</para></listitem>
+ init=&rootlibexecdir;/systemd-bootchart.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/bootctl.xml b/man/bootctl.xml
index 00f54c73fc..c7c65aa4b2 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -21,7 +24,6 @@
<refentry id="bootctl" conditional='ENABLE_EFI'
xmlns:xi="http://www.w3.org/2001/XInclude">
-
<refentryinfo>
<title>bootctl</title>
<productname>systemd</productname>
@@ -48,65 +50,82 @@
<refsynopsisdiv>
<cmdsynopsis>
- <command>bootctl</command>
- <arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="req">COMMAND</arg>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>status</command>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>update</command>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>install</command>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>bootctl <arg choice="opt" rep="repeat">OPTIONS</arg>remove</command>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><command>bootctl</command> may be used to query or (in the
- future) change the firmware and boot manager settings.</para>
-
- <para>Firmware information is available only on EFI systems.
- </para>
-
- <para>Currently, only the
- <citerefentry project='gummiboot'><refentrytitle>gummiboot</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- boot manager implements the required boot loader interface to
- provide complete boot manager information.</para>
+ <para><command>bootctl</command> checks, updates,
+ installs or removes the boot loader from the current
+ system.</para>
+
+ <para><command>bootctl status</command> checks and prints the
+ currently installed versions of the boot loader binaries and the
+ all current EFI boot variables.</para>
+
+ <para><command>bootctl update</command> updates all installed
+ versions of systemd-boot, if the current version is newer than the
+ version installed in the EFI system partition. This also includes
+ the EFI default/fallback loader at /EFI/Boot/boot*.efi. A
+ systemd-boot entry in the EFI boot variables is created, if there
+ is no current entry. The created entry will be added to the end of
+ the boot order list.</para>
+
+ <para><command>bootctl install</command> installs systemd-boot into
+ the EFI system partition. A copy of systemd-boot will be stored as
+ the EFI default/fallback loader at /EFI/Boot/boot*.efi. A systemd-boot
+ entry in the EFI boot variables is created and added to the top
+ of the boot order list.</para>
+
+ <para><command>bootctl remove</command> removes all installed
+ versions of systemd-boot from the EFI system partition, and removes
+ systemd-boot from the EFI boot variables.</para>
+
+ <para>If no command is passed <command>status</command> is
+ implied.</para>
</refsect1>
<refsect1>
<title>Options</title>
-
<para>The following options are understood:</para>
<variablelist>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
- </variablelist>
-
- <para>The following commands are understood:</para>
-
- <variablelist>
<varlistentry>
- <term><command>status</command></term>
+ <term><option>--path</option></term>
+ <listitem><para>Path to the EFI system partition. The default is /boot.</para></listitem>
+ </varlistentry>
- <listitem><para>Show firmware and boot manager information
- about the system, including secure boot mode status and
- selected firmware entry (where available).</para></listitem>
+ <varlistentry>
+ <term><option>--no-variables</option></term>
+ <listitem><para>Do not touch the EFI boot variables.</para></listitem>
</varlistentry>
</variablelist>
-
</refsect1>
<refsect1>
<title>Exit status</title>
-
- <para>On success, 0 is returned, a non-zero failure code
- otherwise.</para>
+ <para>On success 0 is returned, a non-zero failure
+ code otherwise.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
- <ulink url="http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface">Boot loader interface</ulink>,
- <ulink url="http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec">Boot loader specification</ulink>,
- <ulink url="http://www.freedesktop.org/wiki/Software/gummiboot/">gummiboot</ulink>
+ <ulink url="http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec">Boot loader specification</ulink>
+ <ulink url="http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface">Systemd boot loader interface</ulink>
</para>
</refsect1>
-
</refentry>
diff --git a/man/bootup.xml b/man/bootup.xml
index d97d550236..de34a59a72 100644
--- a/man/bootup.xml
+++ b/man/bootup.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -134,7 +137,7 @@
v v | v <emphasis>rescue.target</emphasis>
timers.target paths.target | sockets.target
| | | |
- v |_________________ | ___________________/
+ v \_________________ | ___________________/
\|/
v
basic.target
diff --git a/man/busctl.xml b/man/busctl.xml
index 251233bb96..08303b4dd8 100644
--- a/man/busctl.xml
+++ b/man/busctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -288,7 +291,7 @@
url="http://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap
File Format</ulink> description. Make sure to redirect the
output to STDOUT to a file. Tools like
- <citerefentry><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
may be used to dissect and view the generated
files.</para></listitem>
</varlistentry>
@@ -465,14 +468,14 @@ o "/org/freedesktop/systemd1/job/42684"</programlisting>
<title>See Also</title>
<para>
- <citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
<ulink url="https://code.google.com/p/d-bus/">kdbus</ulink>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-bus-proxyd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml
index 3d325e6ad7..4c65c1cf03 100644
--- a/man/coredump.conf.xml
+++ b/man/coredump.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -49,10 +52,10 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/coredump.conf</filename></para>
- <para><filename>/etc/systemd/coredump.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/coredump.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/coredump.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/coredump.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/coredump.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/coredump.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -63,8 +66,7 @@
a handler for core dumps invoked by the kernel.</para>
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
@@ -135,7 +137,9 @@
by coredumps might temporarily exceed these limits while
coredumps are processed. Note that old coredumps are also
removed based on time via
- <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
+ <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Set
+ either value to 0 to turn off size based
+ clean-up.</para></listitem>
</varlistentry>
</variablelist>
diff --git a/man/coredumpctl.xml b/man/coredumpctl.xml
index efbc655a76..4bd1a7e67f 100644
--- a/man/coredumpctl.xml
+++ b/man/coredumpctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/crypttab.xml b/man/crypttab.xml
index aeacc57973..d403e71bef 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -75,7 +78,7 @@
<para>Setting up encrypted block devices using this file supports
three encryption modes: LUKS, TrueCrypt and plain. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for more information about each mode. When no mode is specified in
the options field and the block device contains a LUKS signature,
it is opened as a LUKS device; otherwise, it is assumed to be in
@@ -117,7 +120,7 @@
<term><option>cipher=</option></term>
<listitem><para>Specifies the cipher to use. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this option. A
cipher with unpredictable IV values, such as
<literal>aes-cbc-essiv:sha256</literal>, is
@@ -129,7 +132,7 @@
<listitem><para>Specifies the hash to use for password
hashing. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this
option.</para></listitem>
</varlistentry>
@@ -140,17 +143,41 @@
<listitem><para>Use a detached (separated) metadata device or
file where the LUKS header is stored. This option is only
relevant for LUKS devices. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this
option.</para></listitem>
</varlistentry>
<varlistentry>
+ <term><option>offset=</option></term>
+
+ <listitem><para>Start offset in the backend device, in 512-byte sectors.
+ This option is only relevant for plain devices.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>skip=</option></term>
+
+ <listitem><para>How many 512-byte sectors of the encrypted data to skip
+ at the beginning. This is different from the <option>--offset</option>
+ option with respect to the sector numbers used in initialization vector
+ (IV) calculation. Using <option>--offset</option> will shift the IV
+ calculation by the same negative amount. Hence, if <option>--offset n</option>,
+ sector n will get a sector number of 0 for the IV calculation.
+ Using <option>--skip</option> causes sector n to also be the first
+ sector of the mapped device, but with its number for IV generation is n.</para>
+
+ <para>This option is only relevant for plain devices.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>keyfile-offset=</option></term>
<listitem><para>Specifies the number of bytes to skip at the
start of the key file. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this
option.</para></listitem>
</varlistentry>
@@ -160,7 +187,7 @@
<listitem><para>Specifies the maximum number of bytes to read
from the key file. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this option. This
option is ignored in plain encryption mode, as the key file
size is then given by the key size.</para></listitem>
@@ -174,7 +201,7 @@
given passphrase or key, but another would, the setup of the
device will fail regardless. This option implies
<option>luks</option>. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values. The default is to try all key slots in
sequential order.</para></listitem>
</varlistentry>
@@ -221,7 +248,7 @@
<term><option>size=</option></term>
<listitem><para>Specifies the key size in bits. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for possible values and the default value of this
option.</para></listitem>
</varlistentry>
@@ -278,7 +305,7 @@
volume provided in the second field. Please note that there is
no protection for the hidden volume if the outer volume is
mounted instead. See
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for more information on this limitation.</para></listitem>
</varlistentry>
@@ -383,7 +410,7 @@ hidden /mnt/tc_hidden /dev/null tcrypt-hidden,tcrypt-keyfile=/etc/keyfil
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkswap</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mke2fs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
diff --git a/man/custom-html.xsl b/man/custom-html.xsl
index 32299db710..0856c1f29c 100644
--- a/man/custom-html.xsl
+++ b/man/custom-html.xsl
@@ -87,8 +87,30 @@
</a>
</xsl:template>
-<xsl:template match="citerefentry[@project='gummiboot']">
- <xsl:call-template name="inline.charseq"/>
+<xsl:template match="citerefentry[@project='freebsd']">
+ <a>
+ <xsl:attribute name="href">
+ <xsl:text>https://www.freebsd.org/cgi/man.cgi?</xsl:text>
+ <xsl:value-of select="refentrytitle"/>
+ <xsl:text>(</xsl:text>
+ <xsl:value-of select="manvolnum"/>
+ <xsl:text>)</xsl:text>
+ </xsl:attribute>
+ <xsl:call-template name="inline.charseq"/>
+ </a>
+</xsl:template>
+
+<xsl:template match="citerefentry[@project='dbus']">
+ <a>
+ <xsl:attribute name="href">
+ <xsl:text>http://dbus.freedesktop.org/doc/</xsl:text>
+ <xsl:value-of select="refentrytitle"/>
+ <xsl:text>.</xsl:text>
+ <xsl:value-of select="manvolnum"/>
+ <xsl:text>.html</xsl:text>
+ </xsl:attribute>
+ <xsl:call-template name="inline.charseq"/>
+ </a>
</xsl:template>
<xsl:template match="refsect1/title|refsect1/info/title">
@@ -210,18 +232,6 @@
</xsl:attribute>
<xsl:text>Python </xsl:text>
</a>·
- <a>
- <xsl:attribute name="href">
- <xsl:text>../libudev/index.html</xsl:text>
- </xsl:attribute>
- <xsl:text>libudev </xsl:text>
- </a>·
- <a>
- <xsl:attribute name="href">
- <xsl:text>../libudev/index.html</xsl:text>
- </xsl:attribute>
- <xsl:text>gudev </xsl:text>
- </a>
<span style="float:right">
<xsl:text>systemd </xsl:text>
diff --git a/man/daemon.xml b/man/daemon.xml
index a8bbfc055b..38d458e05d 100644
--- a/man/daemon.xml
+++ b/man/daemon.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml
index e9c894f5c8..f73a3edc06 100644
--- a/man/file-hierarchy.xml
+++ b/man/file-hierarchy.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -256,9 +259,8 @@
used for package-specific data, unless this data is
architecture-dependent, too. To query
<varname>$libdir</varname> for the primary architecture of the
- system, invoke: <programlisting># pkg-config --variable=libdir
- systemd</programlisting> or <programlisting># systemd-path
- system-library-arch</programlisting> </para></listitem>
+ system, invoke:
+ <programlisting># systemd-path system-library-arch</programlisting></para></listitem>
</varlistentry>
@@ -397,7 +399,7 @@
<term><filename>/dev/shm</filename></term>
<listitem><para>Place for POSIX shared memory segments, as
created via
- <citerefentry><refentrytitle>shm_open</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='die-net'><refentrytitle>shm_open</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This directory is flushed on boot, and is a
<literal>tmpfs</literal> file system. Since all users have
write access to this directory, special care should be taken
diff --git a/man/halt.xml b/man/halt.xml
index a06dbd0097..f425ebdb8e 100644
--- a/man/halt.xml
+++ b/man/halt.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/hostname.xml b/man/hostname.xml
index 5d3d46d8ce..34aaca1acd 100644
--- a/man/hostname.xml
+++ b/man/hostname.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -57,11 +60,12 @@
name of the local system that is set during boot using the
<citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call. It should contain a single newline-terminated
- hostname string. The hostname may be a free-form string up to 64
- characters in length; however, it is recommended that it consists
- only of 7-bit ASCII lower-case characters and no spaces or dots,
- and limits itself to the format allowed for DNS domain name
- labels, even though this is not a strict requirement.</para>
+ hostname string. Comments (lines starting with a `#') are ignored.
+ The hostname may be a free-form string up to 64 characters in length;
+ however, it is recommended that it consists only of 7-bit ASCII lower-case
+ characters and no spaces or dots, and limits itself to the format allowed
+ for DNS domain name labels, even though this is not a strict
+ requirement.</para>
<para>Depending on the operating system, other configuration files
might be checked for configuration of the hostname as well,
diff --git a/man/hostnamectl.xml b/man/hostnamectl.xml
index b1f038156d..93934668cc 100644
--- a/man/hostnamectl.xml
+++ b/man/hostnamectl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/hwdb.xml b/man/hwdb.xml
index b4460c1aee..e6215df738 100644
--- a/man/hwdb.xml
+++ b/man/hwdb.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refentry id="hwdb" conditional="ENABLE_HWDB">
<refentryinfo>
@@ -40,17 +43,17 @@
<refsect1><title>Hardware Database Files</title>
<para>The hwdb files are read from the files located in the
- system hwdb directory <filename>/usr/lib/udev/hwdb.d</filename>,
+ system hwdb directory <filename>&udevlibexecdir;/hwdb.d</filename>,
the volatile runtime directory <filename>/run/udev/hwdb.d</filename>
and the local administration directory <filename>/etc/udev/hwdb.d</filename>.
All hwdb files are collectively sorted and processed in lexical order,
regardless of the directories in which they live. However, files with
identical filenames replace each other. Files in <filename>/etc</filename>
have the highest priority, files in <filename>/run</filename> take precedence
- over files with the same name in <filename>/usr/lib</filename>. This can be
+ over files with the same name in <filename>&rootprefix;/lib</filename>. This can be
used to override a system-supplied hwdb file with a local file if needed;
a symlink in <filename>/etc</filename> with the same name as a hwdb file in
- <filename>/usr/lib</filename>, pointing to <filename>/dev/null</filename>,
+ <filename>&rootprefix;/lib</filename>, pointing to <filename>/dev/null</filename>,
disables the hwdb file entirely. hwdb files must have the extension
<filename>.hwdb</filename>; other extensions are ignored.</para>
@@ -58,7 +61,7 @@
associated key-value pairs. Every record in the hwdb starts with one or
more match string, specifying a shell glob to compare the database
lookup string against. Multiple match lines are specified in additional
- consecutive lines. Every match line is compared indivdually, they are
+ consecutive lines. Every match line is compared individually, they are
combined by OR. Every match line must start at the first character of
the line.</para>
@@ -70,7 +73,7 @@
<para>The content of all hwdb files is read by
<citerefentry><refentrytitle>systemd-hwdb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
and compiled to a binary database located at <filename>/etc/udev/hwdb.bin</filename>,
- or alternatively <filename>/usr/lib/udev/hwdb.bin</filename> if you want ship the compiled
+ or alternatively <filename>&udevlibexecdir;/hwdb.bin</filename> if you want ship the compiled
database in an immutable image.
During runtime only the binary database is used.</para>
</refsect1>
diff --git a/man/journal-remote.conf.xml b/man/journal-remote.conf.xml
new file mode 100644
index 0000000000..948dfa531d
--- /dev/null
+++ b/man/journal-remote.conf.xml
@@ -0,0 +1,117 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
+
+<!--
+ This file is part of systemd.
+
+ Copyright 2015 Chris Morgan
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="journal-remote.conf" conditional='HAVE_MICROHTTPD'
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <refentryinfo>
+ <title>journal-remote.conf</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Chris</firstname>
+ <surname>Morgan</surname>
+ <email>chmorgan@gmail.com</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>journal-remote.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>journal-remote.conf</refname>
+ <refname>journal-remote.conf.d</refname>
+ <refpurpose>Journal remote service configuration files</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>&pkgsysconfdir;/journal-remote.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/journald.conf.d/*.conf</filename></para>
+ <para><filename>/run/systemd/journald.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/journald.conf.d/*.conf</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>These files configure various parameters of the systemd-remote-journal
+ application,
+ <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+ </refsect1>
+
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+ <refsect1>
+ <title>Options</title>
+
+ <para>All options are configured in the
+ <literal>[Remote]</literal> section:</para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><varname>SplitMode=</varname></term>
+
+ <listitem><para>One of <literal>host</literal> or <literal>none</literal>.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ServerKeyFile=</varname></term>
+
+ <listitem><para>SSL key in PEM format.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ServerCertificateFile=</varname></term>
+
+ <listitem><para>SSL CA certificate in PEM format.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>TrustedCertificateFile=</varname></term>
+
+ <listitem><para>SSL CA certificate.</para></listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/journalctl.xml b/man/journalctl.xml
index 770cf9bb29..d67d9606be 100644
--- a/man/journalctl.xml
+++ b/man/journalctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -817,11 +820,6 @@
<programlisting>journalctl /usr/bin/dbus-daemon</programlisting>
- <para>Show all logs of the kernel device node
- <filename noindex='true'>/dev/sda</filename>:</para>
-
- <programlisting>journalctl /dev/sda</programlisting>
-
<para>Show all kernel logs from previous boot:</para>
<programlisting>journalctl -k -b -1</programlisting>
diff --git a/man/journald.conf.xml b/man/journald.conf.xml
index 364b58f07e..8d0dbb0133 100644
--- a/man/journald.conf.xml
+++ b/man/journald.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -49,10 +52,10 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/journald.conf</filename></para>
- <para><filename>/etc/systemd/journald.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/journald.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/journald.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/journald.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/journald.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/journald.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -64,8 +67,7 @@
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
@@ -98,7 +100,7 @@
needed, so that its existence controls where log data goes.
<literal>none</literal> turns off all storage, all log data
received will be dropped. Forwarding to other targets, such as
- the console, the kernel log buffer or a syslog daemon will
+ the console, the kernel log buffer, or a syslog socket will
still work however. Defaults to
<literal>auto</literal>.</para></listitem>
</varlistentry>
@@ -221,27 +223,19 @@
journald will stop using more space, but it will not be
removing existing files to go reduce footprint either.</para>
- <para><varname>SystemMaxFileSize=</varname>
- and
- <varname>RuntimeMaxFileSize=</varname>
- control how large individual journal
- files may grow at maximum. This
- influences the granularity in which
- disk space is made available through
- rotation, i.e. deletion of historic
- data. Defaults to one eighth of the
- values configured with
+ <para><varname>SystemMaxFileSize=</varname> and
+ <varname>RuntimeMaxFileSize=</varname> control how large
+ individual journal files may grow at maximum. This influences
+ the granularity in which disk space is made available through
+ rotation, i.e. deletion of historic data. Defaults to one
+ eighth of the values configured with
<varname>SystemMaxUse=</varname> and
- <varname>RuntimeMaxUse=</varname>, so
- that usually seven rotated journal
- files are kept as history. Specify
- values in bytes or use K, M, G, T, P,
- E as units for the specified sizes
- (equal to 1024, 1024²,... bytes).
- Note that size limits are enforced
- synchronously when journal files are
- extended, and no explicit rotation
- step triggered by time is
+ <varname>RuntimeMaxUse=</varname>, so that usually seven
+ rotated journal files are kept as history. Specify values in
+ bytes or use K, M, G, T, P, E as units for the specified sizes
+ (equal to 1024, 1024²,... bytes). Note that size limits are
+ enforced synchronously when journal files are extended, and no
+ explicit rotation step triggered by time is
needed.</para></listitem>
</varlistentry>
@@ -309,13 +303,13 @@
daemon, to the kernel log buffer (kmsg), to the system
console, or sent as wall messages to all logged-in users.
These options take boolean arguments. If forwarding to syslog
- is enabled but no syslog daemon is running, the respective
- option has no effect. By default, only forwarding wall is
- enabled. These settings may be overridden at boot time with
- the kernel command line options
+ is enabled but nothing reads messages from the socket,
+ forwarding to syslog has no effect. By default, only
+ forwarding to wall is enabled. These settings may be
+ overridden at boot time with the kernel command line options
<literal>systemd.journald.forward_to_syslog=</literal>,
<literal>systemd.journald.forward_to_kmsg=</literal>,
- <literal>systemd.journald.forward_to_console=</literal> and
+ <literal>systemd.journald.forward_to_console=</literal>, and
<literal>systemd.journald.forward_to_wall=</literal>. When
forwarding to the console, the TTY to log to can be changed
with <varname>TTYPath=</varname>, described
@@ -367,6 +361,32 @@
</refsect1>
<refsect1>
+ <title>Forwarding to traditional syslog daemons</title>
+
+ <para>
+ Journal events can be transferred to a different logging daemon
+ in two different ways. In the first method, messages are
+ immediately forwarded to a socket
+ (<filename>/run/systemd/journal/syslog</filename>), where the
+ traditional syslog daemon can read them. This method is
+ controlled by <varname>ForwardToSyslog=</varname> option. In a
+ second method, a syslog daemon behaves like a normal journal
+ client, and reads messages from the journal files, similarly to
+ <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+ In this method, messages do not have to be read immediately,
+ which allows a logging daemon which is only started late in boot
+ to access all messages since the start of the system. In
+ addition, full structured meta-data is available to it. This
+ method of course is available only if the messages are stored in
+ a journal file at all. So it will not work if
+ <varname>Storage=none</varname> is set. It should be noted that
+ usually the <emphasis>second</emphasis> method is used by syslog
+ daemons, so the <varname>Storage=</varname> option, and not the
+ <varname>ForwardToSyslog=</varname> option, is relevant for them.
+ </para>
+ </refsect1>
+
+ <refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml
index 3741cf9cc2..6490123a53 100644
--- a/man/kernel-command-line.xml
+++ b/man/kernel-command-line.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -295,7 +298,7 @@
<varlistentry>
<term><varname>root=</varname></term>
<term><varname>rootfstype=</varname></term>
- <term><varname>rootfsflags=</varname></term>
+ <term><varname>rootflags=</varname></term>
<term><varname>ro</varname></term>
<term><varname>rw</varname></term>
@@ -336,7 +339,7 @@
<listitem>
<para>Enables resume from hibernation using the specified
device. All
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-like
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-like
paths are supported. For details, see
<citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</listitem>
diff --git a/man/kernel-install.xml b/man/kernel-install.xml
index d4d01807a4..8891bae71e 100644
--- a/man/kernel-install.xml
+++ b/man/kernel-install.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2013 Harald Hoyer
+ Copyright 2013 Harald Hoyer
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="kernel-install">
diff --git a/man/less-variables.xml b/man/less-variables.xml
index 0fb4d7fbcf..e344c62e1a 100644
--- a/man/less-variables.xml
+++ b/man/less-variables.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refsect1>
<title>Environment</title>
diff --git a/man/libsystemd-pkgconfig.xml b/man/libsystemd-pkgconfig.xml
index 272da64cd7..3620f47316 100644
--- a/man/libsystemd-pkgconfig.xml
+++ b/man/libsystemd-pkgconfig.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refsect1>
<title>Notes</title>
diff --git a/man/locale.conf.xml b/man/locale.conf.xml
index 48c0006db2..8af49af7f2 100644
--- a/man/locale.conf.xml
+++ b/man/locale.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -91,7 +94,7 @@
might be checked for locale configuration as well, however only as
fallback.</para>
- <para><citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <para><citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
may be used to alter the settings in this file during runtime from
the command line. Use
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
@@ -121,7 +124,7 @@
Note that <varname>LC_ALL</varname> may not be configured in this
file. For details about the meaning and semantics of these
settings, refer to
- <citerefentry><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
+ <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@@ -142,8 +145,8 @@ LC_MESSAGES=en_US.UTF-8</programlisting>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
diff --git a/man/localectl.xml b/man/localectl.xml
index aae6e0629c..caf963ae5e 100644
--- a/man/localectl.xml
+++ b/man/localectl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -124,7 +127,7 @@
<listitem><para>Set the system locale. This takes one or more
assignments such as "LANG=de_DE.utf8",
"LC_MESSAGES=en_GB.utf8", and so on. See
- <citerefentry><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details on the available settings and their meanings. Use
<command>list-locales</command> for a list of available
locales (see below). </para></listitem>
@@ -204,10 +207,10 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>vconsole.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>kbd</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
<ulink url="http://www.x.org/releases/current/doc/xorg-docs/input/XKB-Config.html">
The XKB Configuration Guide
diff --git a/man/localtime.xml b/man/localtime.xml
index 2827da6e93..1740dde9eb 100644
--- a/man/localtime.xml
+++ b/man/localtime.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/loginctl.xml b/man/loginctl.xml
index 9dda14d454..d0529c160e 100644
--- a/man/loginctl.xml
+++ b/man/loginctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
index ffaec50351..96ebd6eed0 100644
--- a/man/logind.conf.xml
+++ b/man/logind.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -49,20 +52,22 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/logind.conf</filename></para>
- <para><filename>/etc/systemd/logind.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/logind.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/logind.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/logind.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/logind.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/logind.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para>These files configure various parameters of the systemd login manager, <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+ <para>These files configure various parameters of the systemd
+ login manager,
+ <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ </para>
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
@@ -124,7 +129,7 @@
<para>Note that setting <varname>KillUserProcesses=1</varname>
will break tools like
- <citerefentry><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
+ <citerefentry project='die-net'><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -249,6 +254,21 @@
</varlistentry>
<varlistentry>
+ <term><varname>HoldoffTimeoutSec=</varname></term>
+
+ <listitem><para>Specifies the timeout after system startup or
+ system resume in which systemd will hold off on reacting to
+ LID events. This is required for the system to properly
+ detect any hotplugged devices so systemd can ignore LID events
+ if external monitors, or docks, are connected. If set to 0,
+ systemd will always react immediately, possibly before the
+ kernel fully probed all hotplugged devices. This is safe, as
+ long as you do not care for systemd to account for devices
+ that have been plugged or unplugged while the system was off.
+ Defaults to 30s.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>RuntimeDirectorySize=</varname></term>
<listitem><para>Sets the size limit on the
diff --git a/man/machine-id.xml b/man/machine-id.xml
index 83e0b26ced..bb7cd7f060 100644
--- a/man/machine-id.xml
+++ b/man/machine-id.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -75,7 +78,7 @@
globally unique ID in the network, which does not change even if
the local network configuration changes. Due to this and its
greater length, it is a more useful replacement for the
- <citerefentry><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call that POSIX specifies.</para>
<para>The
@@ -127,7 +130,7 @@ id[8] = (id[8] &amp; 0x3F) | 0x80;</programlisting>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>gethostid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
diff --git a/man/machine-info.xml b/man/machine-info.xml
index 916f1dab66..a6db1e0317 100644
--- a/man/machine-info.xml
+++ b/man/machine-info.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/machinectl.xml b/man/machinectl.xml
index 9b07af4226..18ef6a5780 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -214,6 +217,18 @@
URL.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--format=</option></term>
+
+ <listitem><para>When used with the <option>export-tar</option>
+ or <option>export-raw</option> commands specifies the
+ compression format to use for the resulting file. Takes one of
+ <literal>uncompressed</literal>, <literal>xz</literal>,
+ <literal>gzip</literal>, <literal>bzip2</literal>. By default
+ the format is determined automatically from the image file
+ name passed.</para></listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />
@@ -469,19 +484,25 @@
<varlistentry>
<term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
- <listitem><para>Clones a container or disk image. The
+ <listitem><para>Clones a container or VM image. The
arguments specify the name of the image to clone and the name
of the newly cloned image. Note that plain directory container
images are cloned into subvolume images with this command.
Note that cloning a container or VM image is optimized for
btrfs file systems, and might not be efficient on others, due
- to file system limitations.</para></listitem>
+ to file system limitations.</para>
+
+ <para>Note that this command leaves host name, machine ID and
+ all other settings that could identify the instance
+ unmodified. The original image and the cloned copy will hence
+ share these credentials, and it might be necessary to manually
+ change them in the copy.</para></listitem>
</varlistentry>
<varlistentry>
<term><command>rename</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
- <listitem><para>Renames a container or disk image. The
+ <listitem><para>Renames a container or VM image. The
arguments specify the name of the image to rename and the new
name of the image.</para></listitem>
</varlistentry>
@@ -489,22 +510,53 @@
<varlistentry>
<term><command>read-only</command> <replaceable>NAME</replaceable> [<replaceable>BOOL</replaceable>]</term>
- <listitem><para>Marks or (unmarks) a container or disk image
+ <listitem><para>Marks or (unmarks) a container or VM image
read-only. Takes a VM or container image name, followed by a
boolean as arguments. If the boolean is omitted, positive is
implied, i.e. the image is marked read-only.</para></listitem>
</varlistentry>
-
<varlistentry>
<term><command>remove</command> <replaceable>NAME</replaceable>...</term>
- <listitem><para>Removes one or more container or disk images.
+ <listitem><para>Removes one or more container or VM images.
The special image <literal>.host</literal>, which refers to
the host's own directory tree may not be
removed.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><command>set-limit</command> [<replaceable>NAME</replaceable>] <replaceable>BYTES</replaceable></term>
+
+ <listitem><para>Sets the maximum size in bytes a specific
+ container or VM image, or all images may grow up to on disk
+ (disk quota). Takes either one or two parameters. The first,
+ optional parameter refers to a container or VM image name. If
+ specified the size limit of the specified image is changed. If
+ omitted the overall size limit of the sum of all images stored
+ locally is changed. The final argument specifies the size
+ limit in bytes, possibly suffixed by the usual K, M, G, T
+ units. If the size limit shall be disabled, specify
+ <literal>-</literal> as size.</para>
+
+ <para>Note that per-container size limits are only supported
+ on btrfs file systems. Also note that if
+ <command>set-limit</command> is invoked without image
+ parameter, and <filename>/var/lib/machines</filename> is
+ empty, and the directory is not located on btrfs, a btrfs
+ loopback file is implicitly created as
+ <filename>/var/lib/machines.raw</filename> with the given
+ size, and mounted to
+ <filename>/var/lib/machines</filename>. The size of the
+ loopback may later be readjusted with
+ <command>set-limit</command>, as well. If such a
+ loopback-mounted <filename>/var/lib/machines</filename>
+ directory is used <command>set-limit</command> without image
+ name alters both the quota setting within the file system as
+ well as the loopback file and file system size
+ itself.</para></listitem>
+ </varlistentry>
+
</variablelist></refsect2>
<refsect2><title>Image Transfer Commands</title><variablelist>
@@ -519,7 +571,7 @@
<literal>https://</literal>, and must refer to a
<filename>.tar</filename>, <filename>.tar.gz</filename>,
<filename>.tar.xz</filename> or <filename>.tar.bz2</filename>
- archive file. If the local machine name is omitted the name it
+ archive file. If the local machine name is omitted it
is automatically derived from the last component of the URL,
with its suffix removed.</para>
@@ -536,8 +588,8 @@
first verified with detached GPG signature file
<filename>SHA256SUMS.gpg</filename>. The public key for this
verification step needs to be available in
- <filename>/usr/lib/systemd/import-pubring.gpg</filename> or
- <filename>/etc/systemd/import-pubring.gpg</filename>.</para>
+ <filename>&rootlibexecdir;/import-pubring.gpg</filename> or
+ <filename>&pkgsysconfdir;/import-pubring.gpg</filename>.</para>
<para>The container image will be downloaded and stored in a
read-only subvolume in
@@ -551,7 +603,7 @@
specify <literal>-</literal> as local machine name.</para>
<para>Note that the read-only subvolume is prefixed with
- <filename>.tar-</filename>, and is thus now shown by
+ <filename>.tar-</filename>, and is thus not shown by
<command>list-images</command>, unless <option>--all</option>
is passed.</para>
@@ -572,7 +624,7 @@
be a <filename>.qcow2</filename> or raw disk image, optionally
compressed as <filename>.gz</filename>,
<filename>.xz</filename>, or <filename>.bz2</filename>. If the
- local machine name is omitted the name it is automatically
+ local machine name is omitted it is automatically
derived from the last component of the URL, with its suffix
removed.</para>
@@ -580,7 +632,7 @@
(see above).</para>
<para>If the the downloaded image is in
- <filename>.qcow2</filename> format it es converted into a raw
+ <filename>.qcow2</filename> format it is converted into a raw
image file before it is made available.</para>
<para>Downloaded images of this type will be placed as
@@ -592,7 +644,7 @@
<para>Similar to the behaviour of <command>pull-tar</command>,
the read-only image is prefixed with
- <filename>.raw-</filename>, and thus now shown by
+ <filename>.raw-</filename>, and thus not shown by
<command>list-images</command>, unless <option>--all</option>
is passed.</para>
@@ -624,7 +676,7 @@
<literal>-</literal> as local machine name.</para>
<para>The read-only layer subvolumes are prefixed with
- <filename>.dkr-</filename>, and thus now shown by
+ <filename>.dkr-</filename>, and thus not shown by
<command>list-images</command>, unless <option>--all</option>
is passed.</para>
@@ -639,18 +691,77 @@
</varlistentry>
<varlistentry>
+ <term><command>import-tar</command> <replaceable>FILE</replaceable> [<replaceable>NAME</replaceable>]</term>
+ <term><command>import-raw</command> <replaceable>FILE</replaceable> [<replaceable>NAME</replaceable>]</term>
+ <listitem><para>Imports a TAR or RAW container or VM image,
+ and places it under the specified name in
+ <filename>/var/lib/machines/</filename>. When
+ <command>import-tar</command> is used the file specified as
+ first argument should be a tar archive, possibly compressed
+ with xz, gzip or bzip2. It will then be unpacked into its own
+ subvolume in <filename>/var/lib/machines</filename>. When
+ <command>import-raw</command> is used the file should be a
+ qcow2 or raw disk image, possibly compressed with xz, gzip or
+ bzip2. If the second argument (the resulting image name) is
+ not specified it is automatically derived from the file
+ name. If the file name is passed as <literal>-</literal> the
+ image is read from standard input, in which case the second
+ argument is mandatory.</para>
+
+ <para>Similar as with <command>pull-tar</command>,
+ <command>pull-raw</command> the file system
+ <filename>/var/lib/machines.raw</filename> is increased in
+ size of necessary and appropriate. Optionally the
+ <option>--read-only</option> switch may be used to create a
+ read-only container or VM image. No cryptographic validation
+ is done when importing the images.</para>
+
+ <para>Much like image downloads, ongoing imports may be listed
+ with <command>list-transfers</command> and aborted with
+ <command>cancel-transfer</command>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><command>export-tar</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
+ <term><command>export-raw</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
+ <listitem><para>Exports a TAR or RAW container or VM image and
+ stores it in the specified file. The first parameter should be
+ a VM or container image name. The second parameter should be a
+ file path the TAR or RAW image is written to. If the path ends
+ in <literal>.gz</literal> the file is compressed with gzip, if
+ it ends in <literal>.xz</literal> with xz, and if it ends in
+ <literal>.bz2</literal> with bzip2. If the path ends in
+ neither the file is left uncompressed. If the second argument
+ is missing the image is written to standard output. The
+ compression may also be explicitly selected with the
+ <option>--format=</option> switch. This is in particular
+ useful if the second parameter is left unspecified.</para>
+
+ <para>Much like image downloads and imports, ongoing exports
+ may be listed with <command>list-transfers</command> and
+ aborted with
+ <command>cancel-transfer</command>.</para>
+
+ <para>Note that currently only directory and subvolume images
+ may be exported as TAR images, and only raw disk images as RAW
+ images.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><command>list-transfers</command></term>
<listitem><para>Shows a list of container or VM image
- downloads that are currently in progress.</para></listitem>
+ downloads, imports and exports that are currently in
+ progress.</para></listitem>
</varlistentry>
<varlistentry>
<term><command>cancel-transfers</command> <replaceable>ID</replaceable>...</term>
- <listitem><para>Aborts download of the container or VM image
- with the specified ID. To list ongoing transfers and their
- IDs, use <command>list-transfers</command>. </para></listitem>
+ <listitem><para>Aborts a download, import or export of the
+ container or VM image with the specified ID. To list ongoing
+ transfers and their IDs, use
+ <command>list-transfers</command>. </para></listitem>
</varlistentry>
</variablelist></refsect2>
@@ -671,6 +782,19 @@
<filename>/var/lib/machines/</filename> to make them available for
control with <command>machinectl</command>.</para>
+ <para>Note that many image operations are only supported,
+ efficient or atomic on btrfs file systems. Due to this, if the
+ <command>pull-tar</command>, <command>pull-raw</command>,
+ <command>pull-dkr</command>, <command>import-tar</command>,
+ <command>import-raw</command> and <command>set-limit</command>
+ commands notice that <filename>/var/lib/machines</filename> is
+ empty and not located on btrfs, they will implicitly set up a
+ loopback file <filename>/var/lib/machines.raw</filename>
+ containing a btrfs file system that is mounted to
+ <filename>/var/lib/machines</filename>. The size of this loopback
+ file may be controlled dynamically with
+ <command>set-limit</command>.</para>
+
<para>Disk images are understood by
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
and <command>machinectl</command> in three formats:</para>
@@ -715,11 +839,12 @@
<title>Download a Fedora image, set a root password in it, start
it as service</title>
- <programlisting># machinectl pull-raw --verify=no
- http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz
- # systemd-nspawn -M Fedora-Cloud-Base-20141203-21 # passwd #
- exit # machinectl start Fedora-Cloud-Base-20141203-21 #
- machinectl login Fedora-Cloud-Base-20141203-21</programlisting>
+ <programlisting># machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz
+# systemd-nspawn -M Fedora-Cloud-Base-20141203-21
+# passwd
+# exit
+# machinectl start Fedora-Cloud-Base-20141203-21
+# machinectl login Fedora-Cloud-Base-20141203-21</programlisting>
<para>This downloads the specified <filename>.raw</filename>
image with verification disabled. Then a shell is opened in it
@@ -739,6 +864,17 @@
index server to be specified with the
<literal>--dkr-index-url=</literal>.</para>
</example>
+
+ <example>
+ <title>Exports a container image as tar file</title>
+
+ <programlisting># machinectl export-tar fedora myfedora.tar.xz</programlisting>
+
+ <para>Exports the container <literal>fedora</literal> in an
+ xz-compress tar file <filename>myfedora.tar.xz</filename> in the
+ current directory.</para>
+ </example>
+
</refsect1>
<refsect1>
@@ -755,7 +891,11 @@
<para>
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>tar</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>xz</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>gzip</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>bzip2</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/modules-load.d.xml b/man/modules-load.d.xml
index 34a937db68..82a98be666 100644
--- a/man/modules-load.d.xml
+++ b/man/modules-load.d.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -94,7 +97,7 @@ virtio-net</programlisting>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-modules-load.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>modprobe</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>modprobe</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/networkctl.xml b/man/networkctl.xml
index d11d60f2a9..402698cb12 100644
--- a/man/networkctl.xml
+++ b/man/networkctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml
index cf2b0200f2..7379213f81 100644
--- a/man/nss-myhostname.xml
+++ b/man/nss-myhostname.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -90,7 +93,7 @@
requires a writable <filename>/etc</filename> file system and is
fragile because the file might be edited by the administrator at
the same time. With <command>nss-myhostname</command> enabled
- changing <filename>/etc/hosts</filename> is unncessary, and on
+ changing <filename>/etc/hosts</filename> is unnecessary, and on
many systems the file becomes entirely optional.</para>
<para>To activate the NSS modules, <literal>myhostname</literal>
diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml
index eb1ed2592b..a3e6c75d1b 100644
--- a/man/nss-mymachines.xml
+++ b/man/nss-mymachines.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/os-release.xml b/man/os-release.xml
index 1b71a49d05..6ce5885812 100644
--- a/man/os-release.xml
+++ b/man/os-release.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -104,8 +107,7 @@
<para>For a longer rationale for <filename>os-release</filename>
please refer to the <ulink
- url="http://0pointer.de/blog/projects/os-release">Announcement of
- <filename>/etc/os-release</filename></ulink>.</para>
+ url="http://0pointer.de/blog/projects/os-release">Announcement of <filename>/etc/os-release</filename></ulink>.</para>
</refsect1>
<refsect1>
@@ -274,6 +276,41 @@
</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>VARIANT=</varname></term>
+
+ <listitem><para>
+ A string identifying a specific variant or edition of the
+ operating system suitable for presentation to the user. This
+ field may be used to inform the user that the configuration of
+ this system is subject to a specific divergent set of rules or
+ default configuration settings. This field is optional and may
+ not be implemented on all systems.
+ Examples:
+ <literal>VARIANT="Server Edition"</literal>,
+ <literal>VARIANT="Smart Refrigerator Edition"</literal>
+ Note: this field is for display purposes only. The
+ <varname>VARIANT_ID</varname> field should be used for making
+ programmatic decisions.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>VARIANT_ID=</varname></term>
+
+ <listitem><para>
+ A lower-case string (no spaces or other characters outside of
+ 0-9, a-z, ".", "_" and "-"), identifying a specific variant or
+ edition of the operating system. This may be interpreted by
+ other packages in order to determine a divergent default
+ configuration. This field is optional and may not be
+ implemented on all systems.
+ Examples:
+ <literal>VARIANT_ID=server</literal>,
+ <literal>VARIANT_ID=embedded</literal>
+ </para></listitem>
+ </varlistentry>
+
</variablelist>
<para>If you are reading this file from C code or a shell script
@@ -316,7 +353,7 @@ BUG_REPORT_URL="https://bugzilla.redhat.com/"</programlisting>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>lsb_release</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>lsb_release</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>
diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml
index b4a3f502b4..6fdbcf91e0 100644
--- a/man/pam_systemd.xml
+++ b/man/pam_systemd.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml
index 36cae2706c..52329eba56 100644
--- a/man/resolved.conf.xml
+++ b/man/resolved.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -49,10 +52,10 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/resolved.conf</filename></para>
- <para><filename>/etc/systemd/resolved.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/resolved.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/resolved.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/resolved.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/resolved.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/resolved.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -63,8 +66,7 @@
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
diff --git a/man/runlevel.xml b/man/runlevel.xml
index fc1f523855..f34f9583e8 100644
--- a/man/runlevel.xml
+++ b/man/runlevel.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml
index b7ba363656..686ba0cefe 100644
--- a/man/sd-daemon.xml
+++ b/man/sd-daemon.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd-id128.xml b/man/sd-id128.xml
index ea7972055d..067d43b432 100644
--- a/man/sd-id128.xml
+++ b/man/sd-id128.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd-journal.xml b/man/sd-journal.xml
index 9b1a52207f..165284c0ae 100644
--- a/man/sd-journal.xml
+++ b/man/sd-journal.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd-login.xml b/man/sd-login.xml
index 328f71164d..4c4e5f0077 100644
--- a/man/sd-login.xml
+++ b/man/sd-login.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_booted.xml b/man/sd_booted.xml
index 4dd674b8ea..235e78d083 100644
--- a/man/sd_booted.xml
+++ b/man/sd_booted.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml
index d61ec19cb8..54714dea1d 100644
--- a/man/sd_bus_creds_get_pid.xml
+++ b/man/sd_bus_creds_get_pid.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_bus_creds_get_pid" conditional="ENABLE_KDBUS">
@@ -44,9 +47,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<refnamediv>
<refname>sd_bus_creds_get_pid</refname>
+ <refname>sd_bus_creds_get_ppid</refname>
<refname>sd_bus_creds_get_tid</refname>
<refname>sd_bus_creds_get_uid</refname>
+ <refname>sd_bus_creds_get_euid</refname>
+ <refname>sd_bus_creds_get_suid</refname>
+ <refname>sd_bus_creds_get_fsuid</refname>
<refname>sd_bus_creds_get_gid</refname>
+ <refname>sd_bus_creds_get_egid</refname>
+ <refname>sd_bus_creds_get_sgid</refname>
+ <refname>sd_bus_creds_get_fsgid</refname>
+ <refname>sd_bus_creds_get_supplementary_gids</refname>
<refname>sd_bus_creds_get_comm</refname>
<refname>sd_bus_creds_get_tid_comm</refname>
<refname>sd_bus_creds_get_exe</refname>
@@ -64,9 +75,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<refname>sd_bus_creds_get_selinux_context</refname>
<refname>sd_bus_creds_get_audit_session_id</refname>
<refname>sd_bus_creds_get_audit_login_uid</refname>
+ <refname>sd_bus_creds_get_tty</refname>
<refname>sd_bus_creds_get_unique_name</refname>
<refname>sd_bus_creds_get_well_known_names</refname>
- <refname>sd_bus_creds_get_connection_name</refname>
+ <refname>sd_bus_creds_get_description</refname>
<refpurpose>Retrieve fields from a credentials object</refpurpose>
</refnamediv>
@@ -82,13 +94,37 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</funcprototype>
<funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_ppid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>pid_t *<parameter>ppid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_bus_creds_get_tid</function></funcdef>
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
<paramdef>pid_t *<parameter>tid</parameter></paramdef>
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_creds_get_pid</function></funcdef>
+ <funcdef>int <function>sd_bus_creds_get_uid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>uid_t *<parameter>uid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_euid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>uid_t *<parameter>uid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_suid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>uid_t *<parameter>uid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_fsuid</function></funcdef>
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
<paramdef>uid_t *<parameter>uid</parameter></paramdef>
</funcprototype>
@@ -100,6 +136,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</funcprototype>
<funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_egid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>gid_t *<parameter>gid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_sgid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>gid_t *<parameter>gid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_fsgid</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>gid_t *<parameter>gid</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_supplementary_gids</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>const gid_t **<parameter>gids</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_bus_creds_get_comm</function></funcdef>
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
<paramdef>const char **<parameter>comm</parameter></paramdef>
@@ -202,6 +262,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</funcprototype>
<funcprototype>
+ <funcdef>int <function>sd_bus_creds_get_tty</function></funcdef>
+ <paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
+ <paramdef>const char **<parameter>tty</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_bus_creds_get_unique_name</function></funcdef>
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
<paramdef>const char **<parameter>name</parameter></paramdef>
@@ -214,7 +280,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_creds_get_connection_name</function></funcdef>
+ <funcdef>int <function>sd_bus_creds_get_description</function></funcdef>
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
<paramdef>const char **<parameter>name</parameter></paramdef>
</funcprototype>
@@ -226,26 +292,43 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<title>Description</title>
<para>These functions return information from an
- <parameter>sd_bus_creds</parameter> object. It may be created with
+ <parameter>sd_bus_creds</parameter> credential object. Credential
+ objects may be created with
<citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- in which case it will describe the specified process, or it may be
- created by
+ in which case they describe the credentials of the process
+ identified by the specified PID, with
+ <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ in which case they describe the credentials of a bus peer
+ identified by the specified bus name, or with
<citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- in which case it will describe the process at the other endpoint
- of a connection.
- </para>
+ in which case they describe the credentials of the creator of a
+ bus.</para>
- <para><function>sd_bus_creds_get_pid()</function> will retrieve the
- PID (process identifier).</para>
+ <para><function>sd_bus_creds_get_pid()</function> will retrieve
+ the PID (process identifier). Similar,
+ <function>sd_bus_creds_get_ppid()</function> will retrieve the
+ parent PID. Note that PID 1 has no parent process, in which case
+ -ENXIO is returned.</para>
<para><function>sd_bus_creds_get_tid()</function> will retrieve the
TID (thread identifier).</para>
- <para><function>sd_bus_creds_get_uid()</function> will retrieve the
- numeric UID (user identifier).</para>
+ <para><function>sd_bus_creds_get_uid()</function> will retrieve
+ the numeric UID (user identifier). Similar,
+ <function>sd_bus_creds_get_euid()</function> returns the effective
+ UID, <function>sd_bus_creds_get_suid()</function> the saved UID
+ and <function>sd_bus_creds_get_fsuid()</function> the file system
+ UID.</para>
<para><function>sd_bus_creds_get_gid()</function> will retrieve the
- numeric GID (group identifier).</para>
+ numeric GID (group identifier). Similar,
+ <function>sd_bus_creds_get_egid()</function> returns the effective
+ GID, <function>sd_bus_creds_get_sgid()</function> the saved GID
+ and <function>sd_bus_creds_get_fsgid()</function> the file system
+ GID.</para>
+
+ <para><function>sd_bus_creds_get_supplementary_gids()</function>
+ will retrieve the supplementary GIDs list.</para>
<para><function>sd_bus_creds_get_comm()</function> will retrieve the
comm field (truncated name of the executable, as stored in
@@ -257,32 +340,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<filename>/proc/<replaceable>pid</replaceable>/task/<replaceable>tid</replaceable>/comm</filename>).
</para>
- <para><function>sd_bus_creds_get_exe()</function> will retrieve the
- path to the program (as stored in the
+ <para><function>sd_bus_creds_get_exe()</function> will retrieve
+ the path to the program executable (as stored in the
<filename>/proc/<replaceable>pid</replaceable>/exe</filename>
- link, but with <literal> (deleted)</literal> suffix removed).
- </para>
+ link, but with <literal> (deleted)</literal> suffix removed). Note
+ that kernel threads do not have an executable path, in which case
+ -ENXIO is returned.</para>
- <para><function>sd_bus_creds_get_cmdline()</function> will retrieve
- an array of command line arguments (as stored in
- <filename>/proc/<replaceable>pid</replaceable>/cmdline</filename>).
- </para>
+ <para><function>sd_bus_creds_get_cmdline()</function> will
+ retrieve an array of command line arguments (as stored in
+ <filename>/proc/<replaceable>pid</replaceable>/cmdline</filename>). Note
+ that kernel threads do not have a command line, in which case
+ -ENXIO is returned.</para>
<para><function>sd_bus_creds_get_cgroup()</function> will retrieve
the cgroup path. See <ulink
url="https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt">cgroups.txt</ulink>.
</para>
- <para><function>sd_bus_creds_get_unit()</function> will retrieve the
- systemd unit name (in the system instance of systemd) that the
+ <para><function>sd_bus_creds_get_unit()</function> will retrieve
+ the systemd unit name (in the system instance of systemd) that the
process is part of. See
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
+ processes that are not part of a unit returns -ENXIO.
</para>
<para><function>sd_bus_creds_get_user_unit()</function> will
retrieve the systemd unit name (in the user instance of systemd)
that the process is part of. See
- <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
+ processes that are not part of a user unit returns -ENXIO.
</para>
<para><function>sd_bus_creds_get_slice()</function> will retrieve
@@ -291,17 +378,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
- <para><function>sd_bus_creds_get_session()</function> will retrieve
- the logind session that the process is part of. See
- <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ <para><function>sd_bus_creds_get_session()</function> will
+ retrieve the logind session that the process is part of. See
+ <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. For
+ processes that are not part of a session returns -ENXIO.
</para>
- <para><function>sd_bus_creds_get_owner_uid()</function> will retrieve
- the numeric UID (user identifier) of the user who owns the slice
- that the process is part of. See
+ <para><function>sd_bus_creds_get_owner_uid()</function> will
+ retrieve the numeric UID (user identifier) of the user who owns
+ the session that the process is part of. See
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- <!-- and
- <citerefentry><refentrytitle>systemd-user-sessions.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> -->.
+ For processes that are not part of a session returns -ENXIO.
</para>
<para><function>sd_bus_creds_has_effective_cap()</function> will
@@ -331,12 +418,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<para><function>sd_bus_creds_get_selinux_context()</function> will
retrieve the SELinux security context (label) of the process.</para>
- <para><function>sd_bus_creds_get_audit_session_id()</function> will
- retrieve the audit session identifier of the process.</para>
+ <para><function>sd_bus_creds_get_audit_session_id()</function>
+ will retrieve the audit session identifier of the process. Returns
+ -ENXIO for processes that are not part of an audit session.</para>
<para><function>sd_bus_creds_get_audit_login_uid()</function> will
retrieve the audit user login identifier (the identifier of the
- user who is "responsible" for the session).</para>
+ user who is "responsible" for the session). Returns -ENXIO for
+ processes that are not part of an audit session.</para>
+
+ <para><function>sd_bus_creds_get_tty()</function> will retrieve
+ the controlling TTY. Returns -ENXIO for processes that have no
+ controlling TTY.</para>
<para><function>sd_bus_creds_get_unique_name()</function> will
retrieve the D-Bus unique name. See <ulink
@@ -348,11 +441,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
url="http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus">The
D-Bus specification</ulink>.</para>
- <para><function>sd_bus_creds_get_connection_name()</function> will
+ <para><function>sd_bus_creds_get_description()</function> will
retrieve a descriptive name of the bus connection of the
peer. This name is useful to discern multiple bus connections by
the same peer, and may be altered by the peer with the
- <citerefentry><refentrytitle>sd_bus_set_name()</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_bus_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call.</para>
<para>All functions that take a <parameter>const
@@ -363,7 +456,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<para>All functions that take a <parameter>char***</parameter>
parameter will store the answer there as an address of a an array
- of strings. Each invidividual string is NUL-terminated, and the
+ of strings. Each individual string is NUL-terminated, and the
array is NULL-terminated as a whole. It will be valid as long as
<parameter>c</parameter> remains valid, and should not be freed or
modified by the caller.</para>
@@ -386,34 +479,37 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<varlistentry>
<term><constant>-ENODATA</constant></term>
- <listitem><para>Given field is not available in
- <parameter>c</parameter>.</para>
+ <listitem><para>Given field is not available in the
+ credentials object <parameter>c</parameter>.</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><constant>-ENOENT</constant></term>
+ <term><constant>-ENXIO</constant></term>
- <listitem><para>Given field is not specified for the sender.
- This will be returned by <function>sd_bus_get_unit()</function>,
+ <listitem><para>Given field is not specified for the described
+ process or peer. This will be returned by
+ <function>sd_bus_get_unit()</function>,
<function>sd_bus_get_user_unit()</function>,
<function>sd_bus_get_slice()</function>,
<function>sd_bus_get_session()</function>, and
- <function>sd_bus_get_name_creds_uid()</function> if the sender is not
- part of a systemd system unit, systemd user unit, systemd
- slice, logind session, or a systemd user session.</para>
+ <function>sd_bus_get_owner_uid()</function> if the process is
+ not part of a systemd system unit, systemd user unit, systemd
+ slice, or logind session. It will also be returned by
+ <function>sd_bus_creds_get_exe()</function> and
+ <function>sd_bus_creds_get_cmdline()</function> for kernel
+ threads (since these aren't started from an executable binary
+ or have a command line),
+ <function>sd_bus_creds_get_audit_session_id()</function> and
+ <function>sd_bus_creds_get_audit_login_uid()</function> when
+ the process is not part of an audit session, and
+ <function>sd_bus_creds_get_tty()</function> if the process has
+ no controlling TTY.
+ </para>
</listitem>
</varlistentry>
<varlistentry>
- <term><constant>-ENXIO</constant></term>
-
- <listitem><para>An error occurred in parsing cgroup paths.
- <filename>libsystemd</filename> might be out of sync with
- the running systemd version.</para></listitem>
- </varlistentry>
-
- <varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>Specified pointer parameter is <constant>NULL</constant>.
@@ -449,7 +545,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<citerefentry project='man-pages'><refentrytitle>credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd.journald-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/sd_bus_creds_new_from_pid.xml b/man/sd_bus_creds_new_from_pid.xml
index 518a95abd0..695d4e1f5a 100644
--- a/man/sd_bus_creds_new_from_pid.xml
+++ b/man/sd_bus_creds_new_from_pid.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_open_user.xml b/man/sd_bus_default.xml
index e7a765962a..55f1b8bb69 100644
--- a/man/sd_bus_open_user.xml
+++ b/man/sd_bus_default.xml
@@ -1,30 +1,33 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
-<refentry id="sd_bus_open_user" conditional="ENABLE_KDBUS">
+<refentry id="sd_bus_default" conditional="ENABLE_KDBUS">
<refentryinfo>
- <title>sd_bus_open_user</title>
+ <title>sd_bus_default</title>
<productname>systemd</productname>
<authorgroup>
@@ -38,20 +41,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</refentryinfo>
<refmeta>
- <refentrytitle>sd_bus_open_user</refentrytitle>
+ <refentrytitle>sd_bus_default</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
+ <refname>sd_bus_default</refname>
+ <refname>sd_bus_default_user</refname>
+ <refname>sd_bus_default_system</refname>
+
+ <refname>sd_bus_open</refname>
<refname>sd_bus_open_user</refname>
<refname>sd_bus_open_system</refname>
<refname>sd_bus_open_system_remote</refname>
- <refname>sd_bus_open_system_container</refname>
-
- <refname>sd_bus_default_user</refname>
- <refname>sd_bus_default_system</refname>
+ <refname>sd_bus_open_system_machine</refname>
- <refpurpose>Open a connection to the system or user bus</refpurpose>
+ <refpurpose>Acquire a connection to a system or user bus</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -59,47 +64,90 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<funcprototype>
- <funcdef>int <function>sd_bus_open_user</function></funcdef>
+ <funcdef>int <function>sd_bus_default</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_open_system</function></funcdef>
+ <funcdef>int <function>sd_bus_default_user</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_open_system_remote</function></funcdef>
- <paramdef>const char *<parameter>host</parameter></paramdef>
+ <funcdef>int <function>sd_bus_default_system</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_open_system_container</function></funcdef>
- <paramdef>const char *<parameter>machine</parameter></paramdef>
+ <funcdef>int <function>sd_bus_open</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_default_user</function></funcdef>
+ <funcdef>int <function>sd_bus_open_user</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
<funcprototype>
- <funcdef>int <function>sd_bus_default_system</function></funcdef>
+ <funcdef>int <function>sd_bus_open_system</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
</funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_open_system_remote</function></funcdef>
+ <paramdef>sd_bus **<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>host</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_open_system_machine</function></funcdef>
+ <paramdef>sd_bus **<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>machine</parameter></paramdef>
+ </funcprototype>
+
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_bus_open_user()</function> creates a new bus
- object and opens a connection to the user bus.
- <function>sd_bus_open_system()</function> does the same, but
+ <para><function>sd_bus_default()</function> acquires a bus
+ connection object to the user bus when invoked in user context or
+ to the system bus otherwise. The connection object is associated
+ to the calling thread. Each time the function is invoked from the
+ same thread the same object is returned, but its reference count
+ increased by one, as long as at least one reference is kept. When
+ the last reference to the connection is dropped (using the
+ <function>sd_bus_unref()</function> call), the connection is
+ terminated. Note that the connection is not automatically
+ terminated when the associated thread ends. It is important to
+ drop the last reference to the bus connection explicitly before
+ the thread ends or otherwise the connection will be leaked.</para>
+
+ <para><function>sd_bus_default_user()</function> returns a user
+ bus connection object associated to the calling thread.
+ <function>sd_bus_default_system()</function> is similar, but
connects to the system bus.</para>
+ <para><function>sd_bus_open()</function> creates a new,
+ independent bus connection to the user bus when invoked in user
+ context or the system bus
+ otherwise. <function>sd_bus_open_user()</function> is similar, but
+ connects only to the user bus.
+ <function>sd_bus_open_system()</function> does the same, but
+ connects to the system bus. In contrast to
+ <function>sd_bus_default()</function>,
+ <function>sd_bus_default_user()</function>,
+ <function>sd_bus_default_system()</function> these calls return
+ new, independent connection objects that are not associated with
+ the invoking thread and are not shared between multiple
+ invocations. It is recommended to share connections per thread to
+ efficiently make use the available resources. Thus, it is
+ recommended to use <function>sd_bus_default()</function>,
+ <function>sd_bus_default_user()</function>,
+ <function>sd_bus_default_system()</function> to connect to the
+ user or system buses.</para>
+
<para>If the <varname>$DBUS_SESSION_BUS_ADDRESS</varname> environment
variable is set
(cf. <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>),
@@ -108,10 +156,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
this variable is not set, a suitable default for the default user
D-Bus instance will be used.</para>
- <para>If the <varname>$DBUS_SYSTEM_BUS_ADDRESS</varname> environment
- variable is set, it will be used as the address of the system
- bus. This variable uses the same syntax as
- <varname>$DBUS_SESSION_BUS_ADDRESS</varname>/. If this variable is
+ <para>If the <varname>$DBUS_SYSTEM_BUS_ADDRESS</varname>
+ environment variable is set, it will be used as the address of the
+ system bus. This variable uses the same syntax as
+ <varname>$DBUS_SESSION_BUS_ADDRESS</varname>. If this variable is
not set, a suitable default for the default system D-Bus instance
will be used.</para>
@@ -123,20 +171,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<para><function>sd_bus_open_system_container()</function> connects
to the system bus in the specified <parameter>machine</parameter>,
- where <parameter>machine</parameter> is the name of a container.
- See
+ where <parameter>machine</parameter> is the name of a local
+ container. See
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for more information about "machines".</para>
- <para><function>sd_bus_default_user()</function> returns a bus
- object connected to the user bus. Each thread has its own object, but it
- may be passed around. It is created on the first invocation of
- <function>sd_bus_default_user()</function>, and subsequent
- invocations returns a reference to the same object.</para>
-
- <para><function>sd_bus_default_system()</function> is similar to
- <function>sd_bus_default_user()</function>, but connects to the
- system bus.</para>
</refsect1>
<refsect1>
@@ -149,7 +188,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<refsect1>
<title>Reference ownership</title>
- <para>Functions <function>sd_bus_open_user()</function>,
+ <para>The functions <function>sd_bus_open_user()</function>,
+ <function>sd_bus_open()</function>,
<function>sd_bus_open_system()</function>,
<function>sd_bus_open_system_remote()</function>, and
<function>sd_bus_open_system_machine()</function> return a new
@@ -158,9 +198,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
- <para>The functions <function>sd_bus_default_user()</function> and
- <function>sd_bus_default_system()</function> do not create a new
- reference.</para>
+ <para>The functions <function>sd_bus_default()</function>,
+ <function>sd_bus_default_user()</function> and
+ <function>sd_bus_default_system()</function> do not necessarily
+ create a new object, but increase the connection reference by
+ one. Use
+ <citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ to drop the reference.</para>
</refsect1>
<refsect1>
@@ -173,9 +217,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<varlistentry>
<term><constant>-EINVAL</constant></term>
- <listitem><para>Specified parameter is invalid
- (<constant>NULL</constant> in case of output
- parameters).</para></listitem>
+ <listitem><para>The specified parameters are invalid.</para></listitem>
</varlistentry>
<varlistentry>
@@ -184,18 +226,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
- <para>In addition, any further connection-related errors may be
- by returned. See <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+ <varlistentry>
+ <term><constant>-ESOCKTNOSUPPORT</constant></term>
+
+ <listitem><para>The protocol version required to connect to the selected bus is not supported.</para></listitem>
+ </varlistentry>
</variablelist>
+
+ <para>In addition, any further connection-related errors may be
+ by returned. See <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
<title>Notes</title>
- <para><function>sd_bus_open_user()</function> and other functions
- described here are available as a shared library, which can be
- compiled and linked to with the
- <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <para><function>sd_bus_open_user()</function> and the other
+ functions described here are available as a shared library, which
+ can be compiled and linked to with the
+ <constant>libsystemd</constant> <citerefentry
+ project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
file.</para>
</refsect1>
@@ -208,7 +257,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml
index d1929c217a..bd2a27984c 100644
--- a/man/sd_bus_error.xml
+++ b/man/sd_bus_error.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_bus_error" conditional="ENABLE_KDBUS">
@@ -281,7 +284,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<para><function>sd_bus_error_set_errno</function> will set
<structfield>name</structfield> based on an errno-like value.
- <citerefentry><refentrytitle>strerror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>strerror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
will be used to set <structfield>message</structfield>. Well-known
D-Bus error names will be used for <structfield>name</structfield>
if available, otherwise a name in the
@@ -408,7 +411,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>strerror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>strerror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/sd_bus_message_append.xml b/man/sd_bus_message_append.xml
index 0c49a0c7c9..91a80792e1 100644
--- a/man/sd_bus_message_append.xml
+++ b/man/sd_bus_message_append.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -87,7 +90,7 @@
Arguments corresponding to this nested sequence follow the same
rules as if they were not nested.</para>
- <para>A variant is denoted by <literal>v</literal>. Correspoding
+ <para>A variant is denoted by <literal>v</literal>. Corresponding
arguments must include a format string denoting a complete type,
and following that, arguments corresponding to the specified type.
</para>
@@ -245,7 +248,7 @@ sd_bus_message_append(m, "ynqiuxtd", y, n, q, i, u, x, t, d);</programlisting>
<citerefentry><refentrytitle>sd_bus_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
diff --git a/man/sd_bus_message_append_array.xml b/man/sd_bus_message_append_array.xml
index fe81affdc4..5409893374 100644
--- a/man/sd_bus_message_append_array.xml
+++ b/man/sd_bus_message_append_array.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_bus_message_append_array" conditional="ENABLE_KDBUS"
diff --git a/man/sd_bus_message_append_basic.xml b/man/sd_bus_message_append_basic.xml
index 344b7791fa..81ac6de952 100644
--- a/man/sd_bus_message_append_basic.xml
+++ b/man/sd_bus_message_append_basic.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_message_append_string_memfd.xml b/man/sd_bus_message_append_string_memfd.xml
index 5b4a792cd7..1fecbd5773 100644
--- a/man/sd_bus_message_append_string_memfd.xml
+++ b/man/sd_bus_message_append_string_memfd.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_bus_message_append_string_memfd" conditional="ENABLE_KDBUS"
diff --git a/man/sd_bus_message_append_strv.xml b/man/sd_bus_message_append_strv.xml
index b91406f275..d986b06a41 100644
--- a/man/sd_bus_message_append_strv.xml
+++ b/man/sd_bus_message_append_strv.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_message_get_cookie.xml b/man/sd_bus_message_get_cookie.xml
index 02374d7508..7795acfec3 100644
--- a/man/sd_bus_message_get_cookie.xml
+++ b/man/sd_bus_message_get_cookie.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_message_get_monotonic_usec.xml b/man/sd_bus_message_get_monotonic_usec.xml
index 42842116a0..c109fe10a3 100644
--- a/man/sd_bus_message_get_monotonic_usec.xml
+++ b/man/sd_bus_message_get_monotonic_usec.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -94,7 +97,7 @@
a global, monotonically increasing sequence number to all messages
transmitted on the local system, at the time the message was sent.
This sequence number is useful for determining message send order,
- even across different busses of the local system. The sequence
+ even across different buses of the local system. The sequence
number combined with the boot ID of the system (as returned by
<citerefentry><refentrytitle>sd_id128_get_boot</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
is a suitable globally unique identifier for bus messages.</para>
diff --git a/man/sd_bus_negotiate_fds.xml b/man/sd_bus_negotiate_fds.xml
index 4babae5e2b..4f9204e7bc 100644
--- a/man/sd_bus_negotiate_fds.xml
+++ b/man/sd_bus_negotiate_fds.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Lennart Poettering
+ Copyright 2014 Lennart Poettering
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_bus_negotiate_fds" conditional="ENABLE_KDBUS">
@@ -105,7 +108,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
this is disabled,
<citerefentry><refentrytitle>sd_bus_message_get_monotonic_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_message_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_bus_message_get_seqno</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_bus_message_get_seqnum</refentrytitle><manvolnum>3</manvolnum></citerefentry>
fail with <constant>-ENODATA</constant> on incoming messages. Note
that not all transports support timestamping of messages. On local
transports, the timestamping is applied by the kernel and cannot
diff --git a/man/sd_bus_new.xml b/man/sd_bus_new.xml
index 91ca8161dc..bc91dd2665 100644
--- a/man/sd_bus_new.xml
+++ b/man/sd_bus_new.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_path_encode.xml b/man/sd_bus_path_encode.xml
index 69cda53bf4..0a6ac80473 100644
--- a/man/sd_bus_path_encode.xml
+++ b/man/sd_bus_path_encode.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_bus_request_name.xml b/man/sd_bus_request_name.xml
index 6aa132bb26..78b440b7db 100644
--- a/man/sd_bus_request_name.xml
+++ b/man/sd_bus_request_name.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml
index cf8ed0af6c..7de9f409e9 100644
--- a/man/sd_event_add_child.xml
+++ b/man/sd_event_add_child.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_event_add_child" conditional="ENABLE_KDBUS">
diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml
index dd5d19b519..4aabc0793a 100644
--- a/man/sd_event_add_defer.xml
+++ b/man/sd_event_add_defer.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml
index 0299aa5a53..e84d5c7200 100644
--- a/man/sd_event_add_signal.xml
+++ b/man/sd_event_add_signal.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_event_add_signal" conditional="ENABLE_KDBUS">
@@ -86,7 +89,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
the <parameter>source</parameter> parameter. The
<parameter>signal</parameter> parameter specifies the signal to be handled
(see
- <citerefentry><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>).
+ <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>).
The <parameter>handler</parameter> must reference a function to
call when the signal is delivered or be <constant>NULL</constant>.
The handler function will be passed the
@@ -94,7 +97,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
freely by the caller. The handler also receives a pointer to a
<structname>const struct signalfd_siginfo</structname> containing
the information about the received signal. See
- <citerefentry><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for further information.</para>
<para>Only a single handler may be installed for a specific
diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml
index c975f07de5..3c5de48cab 100644
--- a/man/sd_event_add_time.xml
+++ b/man/sd_event_add_time.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -223,7 +226,7 @@
</varlistentry>
<varlistentry>
- <term><constant>-ENOTSUP</constant></term>
+ <term><constant>-EOPNOTSUPP</constant></term>
<listitem><para>The selected clock is not supported by the event loop implementation.</para></listitem>
diff --git a/man/sd_event_get_fd.xml b/man/sd_event_get_fd.xml
index ff2f5f8668..8f74c1e5c4 100644
--- a/man/sd_event_get_fd.xml
+++ b/man/sd_event_get_fd.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_event_get_fd" conditional="ENABLE_KDBUS"
diff --git a/man/sd_event_new.xml b/man/sd_event_new.xml
index 854a887bce..d225330023 100644
--- a/man/sd_event_new.xml
+++ b/man/sd_event_new.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_event_run.xml b/man/sd_event_run.xml
new file mode 100644
index 0000000000..036887d9f0
--- /dev/null
+++ b/man/sd_event_run.xml
@@ -0,0 +1,186 @@
+<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
+
+<!--
+ This file is part of systemd.
+
+ Copyright 2015 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_event_run" conditional="ENABLE_KDBUS">
+
+ <refentryinfo>
+ <title>sd_event_run</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Tom</firstname>
+ <surname>Gundersen</surname>
+ <email>teg@jklm.no</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_event_run</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_event_run</refname>
+ <refname>sd_event_loop</refname>
+
+ <refpurpose>Run libsystemd event loop</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-event.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_event_run</function></funcdef>
+ <paramdef>sd_event *<parameter>event</parameter></paramdef>
+ <paramdef>uint64_t <parameter>timeout</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_event_loop</function></funcdef>
+ <paramdef>sd_event *<parameter>event</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_event_run()</function> can be used to run one
+ iteration of the event loop of libsystemd. This function waits
+ until an event to process is available and dispatches a handler
+ for it. Parameter <parameter>timeout</parameter> specifices the
+ maximum time (in microseconds) to wait. <constant>(uint64_t)
+ -1</constant> may be used to specify an infinite timeout.</para>
+
+ <para><function>sd_event_loop</function> runs
+ <function>sd_event_wait</function> in a loop with a timeout of
+ infinity. This makes it suitable for the main event loop of a
+ program.</para>
+
+ <para>The event loop object <parameter>event</parameter> is
+ created with
+ <function>sd_event_new</function>.
+ Events to wait for and their handlers can be registered with
+ <function>sd_event_add_time</function>,
+ <function>sd_event_add_child</function>,
+ <function>sd_event_add_signal</function>,
+ <function>sd_event_add_defer</function>,
+ <function>sd_event_add_exit</function>,
+ and
+ <function>sd_event_add_post</function>.
+ </para>
+
+ <para>For more fine-grained control,
+ <function>sd_event_prepare</function>,
+ <function>sd_event_wait</function>, and
+ <function>sd_event_dispatch</function> may be used. Along with
+ <function>sd_event_get_fd</function>, those functions make it
+ possible to integrate the libsystemd loop inside of another event
+ loop.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return 0 or a positive integer.
+ On failure, they return a negative errno-style error code.
+ <function>sd_event_run</function> returns 0 if the event loop is
+ finished, and a positive value if it can be continued.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>Parameter <parameter>event</parameter> is
+ <constant>NULL</constant>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EBUSY</constant></term>
+
+ <listitem><para>The event loop object is not in the right
+ state (see
+ <citerefentry><refentrytitle>sd_event_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ for an explanation of possible states).</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ESTALE</constant></term>
+
+ <listitem><para>The event loop is already terminated.</para></listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The event loop has been created in a different process.</para></listitem>
+
+ </varlistentry>
+
+ </variablelist>
+
+ <para>Other errors are possible too.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para><function>sd_event_run()</function> and
+ <function>sd_event_loop()</function> are available
+ as a shared library, which can be compiled and linked to with the
+ <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <ulink url="https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html">GLIb Main Event Loop</ulink>.
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/sd_event_set_name.xml b/man/sd_event_set_name.xml
index 627ebe479e..0b46414bba 100644
--- a/man/sd_event_set_name.xml
+++ b/man/sd_event_set_name.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="sd_event_set_name" conditional="ENABLE_KDBUS"
diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml
new file mode 100644
index 0000000000..db74a96e8e
--- /dev/null
+++ b/man/sd_event_wait.xml
@@ -0,0 +1,216 @@
+<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
+
+<!--
+ This file is part of systemd.
+
+ Copyright 2015 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="sd_event_wait" conditional="ENABLE_KDBUS">
+
+ <refentryinfo>
+ <title>sd_event_wait</title>
+ <productname>systemd</productname>
+
+ <authorgroup>
+ <author>
+ <contrib>Developer</contrib>
+ <firstname>Tom</firstname>
+ <surname>Gundersen</surname>
+ <email>teg@jklm.no</email>
+ </author>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_event_wait</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_event_wait</refname>
+ <refname>sd_event_prepare</refname>
+ <refname>sd_event_dispatch</refname>
+
+ <refpurpose>Run parts of libsystemd event loop</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-event.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>int <function>sd_event_prepare</function></funcdef>
+ <paramdef>sd_event *<parameter>event</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_event_wait</function></funcdef>
+ <paramdef>sd_event *<parameter>event</parameter></paramdef>
+ <paramdef>uint64_t <parameter>timeout</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_event_dispatch</function></funcdef>
+ <paramdef>sd_event *<parameter>event</parameter></paramdef>
+ </funcprototype>
+
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>Functions described here form parts of an event loop.</para>
+
+ <para><function>sd_event_prepare</function> checks for pending
+ events and arms necessary timers. If any events are ready to be
+ processed, it returns a positive value, and the events should be
+ processed with <function>sd_event_dispatch</function>.
+ <function>sd_event_dispatch</function> runs a handler for one of
+ the events from the sources with the highest priority. On success,
+ <function>sd_event_dispatch</function> returns either 0, which
+ means that the loop is finished, or a positive value, which means
+ that the loop is again in the initial state and
+ <function>sd_event_prepare</function> should be called again.
+ </para>
+
+ <para>In case <function>sd_event_prepare</function> returned 0,
+ <function>sd_event_wait</function> should be called to wait for
+ events or a timeout. If any events are ready to be processed, it
+ returns a positive value, and the events should be processed with
+ <function>sd_event_dispatch</function>. Otherwise, the loop is
+ back in the initial state and <function>sd_event_prepare</function>
+ should be called again.</para>
+
+ <programlisting>
+ ┌──────────┐
+ │ initial ├──←←←←←←←←←←←←←←←←←←←─┐
+ └───┬──────┘ ↑
+ │ ↑
+ sd_event_prepare ┌─────────┐ ↑
+ ├ 0 →→→→→→→──┤ armed │ ↑
+ 1 └───┬─────┘ ↑
+ ↓ │ ↑
+ ↓ sd_event_wait ↑
+ ├───←←←←←←←─── 1 ┴─ 0 →→→→→→→─┘
+ ┌───┴──────┐ ↑
+ │ pending │ ↑
+ └───┬──────┘ ↑
+ │ ↑
+ sd_event_dispatch ↑
+ ↓ ↑
+ ├ 1 ──────────→→→→→→→─────────┘
+ 0
+ ↓
+ ┌───┴──────┐
+ │ finished │
+ └──────────┘
+ </programlisting>
+
+ <para>All three functions as the first argument take the event
+ loop object <parameter>event</parameter> that is created with with
+ <function>sd_event_new</function>. The timeout for
+ <function>sd_event_wait</function> is specified with
+ <parameter>timeout</parameter> in milliseconds.
+ <constant>(uint64_t) -1</constant> may be used to specify an
+ infinite timeout.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, these functions return 0 or a positive integer.
+ On failure, they return a negative errno-style error code. In case
+ of <function>sd_event_prepare</function> and
+ <function>sd_event_wait</function> a positive value means that
+ events are ready to be processed and 0 means that no events are
+ ready. In case of <function>sd_event_dispatch</function> a
+ positive value means that the loop is again in the initial state
+ and 0 means the loop is finished. For any of those functions, a
+ negative return value means the loop must be aborted.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>Parameter <parameter>event</parameter> is
+ <constant>NULL</constant>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EBUSY</constant></term>
+
+ <listitem><para>The event loop object is not in the right
+ state.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ESTALE</constant></term>
+
+ <listitem><para>The event loop is already terminated.</para></listitem>
+
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The event loop has been created in a different process.</para></listitem>
+
+ </varlistentry>
+
+ </variablelist>
+
+ <para>Other errors are possible too.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>Functions described here are available
+ as a shared library, which can be compiled and linked to with the
+ <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ </para>
+ </refsect1>
+
+</refentry>
diff --git a/man/sd_get_seats.xml b/man/sd_get_seats.xml
index 4390d36ebe..3f2c666c61 100644
--- a/man/sd_get_seats.xml
+++ b/man/sd_get_seats.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index 2ad1f8f728..02fa2da283 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_id128_randomize.xml b/man/sd_id128_randomize.xml
index ab449d2937..c4d7c42106 100644
--- a/man/sd_id128_randomize.xml
+++ b/man/sd_id128_randomize.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_id128_to_string.xml b/man/sd_id128_to_string.xml
index e70c80892e..988a646d84 100644
--- a/man/sd_id128_to_string.xml
+++ b/man/sd_id128_to_string.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_is_fifo.xml b/man/sd_is_fifo.xml
index 627cb87aaf..57dd6afc89 100644
--- a/man/sd_is_fifo.xml
+++ b/man/sd_is_fifo.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_add_match.xml b/man/sd_journal_add_match.xml
index 420f56356a..fe89cbf75c 100644
--- a/man/sd_journal_add_match.xml
+++ b/man/sd_journal_add_match.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_get_catalog.xml b/man/sd_journal_get_catalog.xml
index 1dcbadd186..2ff3fc2826 100644
--- a/man/sd_journal_get_catalog.xml
+++ b/man/sd_journal_get_catalog.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -130,7 +133,7 @@
<citerefentry><refentrytitle>sd_journal_open</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/sd_journal_get_cursor.xml b/man/sd_journal_get_cursor.xml
index 2b7f443f29..1d38bac7fb 100644
--- a/man/sd_journal_get_cursor.xml
+++ b/man/sd_journal_get_cursor.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -84,7 +87,7 @@
time) available entry. The call takes two arguments: a journal
context object and a pointer to a string pointer where the cursor
string will be placed. The string is allocated via libc
- <citerefentry><refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>malloc</refentrytitle><manvolnum>3</manvolnum></citerefentry>
and should be freed after use with
<citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
diff --git a/man/sd_journal_get_cutoff_realtime_usec.xml b/man/sd_journal_get_cutoff_realtime_usec.xml
index 23e7cc65e8..ae5e638d70 100644
--- a/man/sd_journal_get_cutoff_realtime_usec.xml
+++ b/man/sd_journal_get_cutoff_realtime_usec.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml
index 1afbd7371c..b395fe01c9 100644
--- a/man/sd_journal_get_data.xml
+++ b/man/sd_journal_get_data.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_get_fd.xml b/man/sd_journal_get_fd.xml
index 3a38f733ab..51dcb1aeeb 100644
--- a/man/sd_journal_get_fd.xml
+++ b/man/sd_journal_get_fd.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_get_realtime_usec.xml b/man/sd_journal_get_realtime_usec.xml
index 607d74666b..921aa77ab6 100644
--- a/man/sd_journal_get_realtime_usec.xml
+++ b/man/sd_journal_get_realtime_usec.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_get_usage.xml b/man/sd_journal_get_usage.xml
index 72c804d834..a89b77907c 100644
--- a/man/sd_journal_get_usage.xml
+++ b/man/sd_journal_get_usage.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_next.xml b/man/sd_journal_next.xml
index 115fe26661..216d9a59c6 100644
--- a/man/sd_journal_next.xml
+++ b/man/sd_journal_next.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_open.xml b/man/sd_journal_open.xml
index fb572802a3..f6aac75546 100644
--- a/man/sd_journal_open.xml
+++ b/man/sd_journal_open.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml
index 068b10e7ca..6dbf73f9c1 100644
--- a/man/sd_journal_print.xml
+++ b/man/sd_journal_print.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -119,7 +122,7 @@
<function>sd_journal_print()</function> but takes a variable
argument list encapsulated in an object of type
<varname>va_list</varname> (see
- <citerefentry><refentrytitle>stdarg</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>stdarg</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for more information) instead of the format string. It is
otherwise equivalent in behavior.</para>
@@ -145,7 +148,7 @@
<function>sd_journal_send()</function> but takes an array of
<varname>struct iovec</varname> (as defined in
<filename>uio.h</filename>, see
- <citerefentry><refentrytitle>readv</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>readv</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details) instead of the format string. Each structure should
reference one field of the entry to submit. The second argument
specifies the number of structures in the array.
@@ -154,7 +157,7 @@
necessary.</para>
<para><function>sd_journal_perror()</function> is a similar to
- <citerefentry><refentrytitle>perror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>perror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
and writes a message to the journal that consists of the passed
string, suffixed with ": " and a human readable representation of
the current error code stored in
@@ -219,7 +222,7 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid(
<title>Async signal safety</title>
<para><function>sd_journal_sendv()</function> is "async signal
safe" in the meaning of
- <citerefentry><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
<para><function>sd_journal_print</function>,
@@ -249,11 +252,11 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid(
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_stream_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>perror</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>perror</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/sd_journal_query_unique.xml b/man/sd_journal_query_unique.xml
index ac0e5f633f..5c92f8972e 100644
--- a/man/sd_journal_query_unique.xml
+++ b/man/sd_journal_query_unique.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_seek_head.xml b/man/sd_journal_seek_head.xml
index d74c2d5bbc..d4c13c21f8 100644
--- a/man/sd_journal_seek_head.xml
+++ b/man/sd_journal_seek_head.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_journal_stream_fd.xml b/man/sd_journal_stream_fd.xml
index 2ea7731b48..ae7990e212 100644
--- a/man/sd_journal_stream_fd.xml
+++ b/man/sd_journal_stream_fd.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_listen_fds.xml b/man/sd_listen_fds.xml
index 9b9705eb2e..38e159bb42 100644
--- a/man/sd_listen_fds.xml
+++ b/man/sd_listen_fds.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_login_monitor_new.xml b/man/sd_login_monitor_new.xml
index a7b47a3207..ef97dae1d0 100644
--- a/man/sd_login_monitor_new.xml
+++ b/man/sd_login_monitor_new.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_machine_get_class.xml b/man/sd_machine_get_class.xml
index 5b881ccea1..68babd1981 100644
--- a/man/sd_machine_get_class.xml
+++ b/man/sd_machine_get_class.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index 87e59c9cc2..d563bcf2aa 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_pid_get_session.xml b/man/sd_pid_get_session.xml
index f708d0d5e1..05a396157a 100644
--- a/man/sd_pid_get_session.xml
+++ b/man/sd_pid_get_session.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -148,9 +151,10 @@
not all processes are part of a login session (e.g. system service
processes, user processes that are shared between multiple
sessions of the same user, or kernel threads). For processes not
- being part of a login session this function will fail. The
- returned string needs to be freed with the libc
- <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ being part of a login session this function will fail with
+ -ENXIO. The returned string needs to be freed with the libc
+ <citerefentry
+ project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
<para><function>sd_pid_get_unit()</function> may be used to
@@ -159,11 +163,12 @@
short string, suitable for usage in file system paths. Note that
not all processes are part of a system unit/service (e.g. user
processes, or kernel threads). For processes not being part of a
- systemd system unit this function will fail. (More specifically:
- this call will not work for processes that are part of user units,
- use <function>sd_pid_get_user_unit()</function> for that.) The
- returned string needs to be freed with the libc
- <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ systemd system unit this function will fail with -ENXIO (More
+ specifically: this call will not work for processes that are part
+ of user units, use <function>sd_pid_get_user_unit()</function> for
+ that.) The returned string needs to be freed with the libc
+ <citerefentry
+ project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
<para><function>sd_pid_get_user_unit()</function> may be used to
@@ -179,14 +184,16 @@
login sessions of the same user, where
<function>sd_pid_get_session()</function> will fail. For processes
not being part of a login session and not being a shared process
- of a user this function will fail.</para>
+ of a user this function will fail with -ENXIO.</para>
<para><function>sd_pid_get_machine_name()</function> may be used
to determine the name of the VM or container is a member of. The
machine name is a short string, suitable for usage in file system
paths. The returned string needs to be freed with the libc
- <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- call after use.</para>
+ <citerefentry
+ project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ call after use. For processes not part of a VM or containers this
+ function fails with -ENXIO.</para>
<para><function>sd_pid_get_slice()</function> may be used to
determine the slice unit the process is a member of. See
@@ -219,6 +226,37 @@
</refsect1>
<refsect1>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><constant>-ENXIO</constant></term>
+
+ <listitem><para>Given field is not specified for the described
+ process or peer.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ESRCH</constant></term>
+
+ <listitem><para>The specified PID does not refer to a running
+ process.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOMEM</constant></term>
+
+ <listitem><para>Memory allocation failed.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
<title>Notes</title>
<para>The <function>sd_pid_get_session()</function>,
diff --git a/man/sd_seat_get_active.xml b/man/sd_seat_get_active.xml
index 3c57ec9ea4..74b4ed5fc1 100644
--- a/man/sd_seat_get_active.xml
+++ b/man/sd_seat_get_active.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_session_is_active.xml b/man/sd_session_is_active.xml
index 4ca3a6c150..e3af2b39c9 100644
--- a/man/sd_session_is_active.xml
+++ b/man/sd_session_is_active.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_uid_get_state.xml b/man/sd_uid_get_state.xml
index b158f3528c..18a3427026 100644
--- a/man/sd_uid_get_state.xml
+++ b/man/sd_uid_get_state.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/sd_watchdog_enabled.xml b/man/sd_watchdog_enabled.xml
index 991431f33b..41850106e6 100644
--- a/man/sd_watchdog_enabled.xml
+++ b/man/sd_watchdog_enabled.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/shutdown.xml b/man/shutdown.xml
index a8af387c67..9bf599b372 100644
--- a/man/shutdown.xml
+++ b/man/shutdown.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/standard-conf.xml b/man/standard-conf.xml
index b87d7e955b..123877a0a5 100644
--- a/man/standard-conf.xml
+++ b/man/standard-conf.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refsection PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refsection>
<refsection id='confd'>
@@ -33,13 +36,39 @@
configuration file.</para>
</refsection>
- <refsection id='conf'>
- <title>Configuration File</title>
+ <refsection id='main-conf'>
+ <title>Configuration Directories and Precedence</title>
+
+ <para>Default configuration is defined during compilation, so a
+ configuration file is only needed when it is necessary to deviate
+ from those defaults. By default the configuration file in
+ <filename>&pkgsysconfdir;/</filename> contains commented out entries
+ showing the defaults as a guide to the administrator. This file
+ can be edited to create local overrides.
+ </para>
+
+ <para>When packages need to customize the configuration, they can
+ install configuration snippets in
+ <filename>&rootlibexecdir;/*.conf.d/</filename>. Files in
+ <filename>/etc/</filename> are reserved for the local
+ administrator, who may use this logic to override the
+ configuration files installed by vendor packages. The main
+ configuration file is read before any of the configuration
+ directories, and has the lowest precedence; entries in a file in
+ any configuration directory override entries in the single
+ configuration file. Files in the
+ <filename>*.conf.d/</filename> configuration subdirectories
+ are sorted by their filename in lexicographic order, regardless of
+ which of the subdirectories they reside in. If multiple files
+ specify the same option, the entry in the file with the
+ lexicographically latest name takes precedence. It is recommended
+ to prefix all filenames in those subdirectories with a two-digit
+ number and a dash, to simplify the ordering of the files.</para>
- <para>Configuration is also read from a single configuration file in
- <filename>/etc/</filename>. This file is read before any of the
- configuration directories, and has the lowest precedence; entries in a file
- in any configuration directory override entries in the single configuration
- file.</para>
+ <para>To disable a configuration file supplied by the vendor, the
+ recommended way is to place a symlink to
+ <filename>/dev/null</filename> in the configuration directory in
+ <filename>/etc/</filename>, with the same filename as the vendor
+ configuration file.</para>
</refsection>
</refsection>
diff --git a/man/standard-options.xml b/man/standard-options.xml
index f214463392..5adda7c670 100644
--- a/man/standard-options.xml
+++ b/man/standard-options.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<variablelist>
<varlistentry id='help'>
diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml
index 5a35cfe2c8..841cedba3a 100644
--- a/man/sysctl.d.xml
+++ b/man/sysctl.d.xml
@@ -1,5 +1,8 @@
<?xml version="1.0"?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -57,7 +60,7 @@
<para>At boot,
<citerefentry><refentrytitle>systemd-sysctl.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
reads configuration files from the above directories to configure
- <citerefentry><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
kernel parameters.</para>
</refsect1>
@@ -127,7 +130,7 @@
<para><filename>/etc/udev/rules.d/99-bridge.rules</filename>:
</para>
- <programlisting>ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/net/bridge"
+ <programlisting>ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="&rootlibexecdir;/systemd-sysctl --prefix=/net/bridge"
</programlisting>
<para><filename>/etc/sysctl.d/bridge.conf</filename>:
@@ -162,9 +165,9 @@ net.bridge.bridge-nf-call-arptables = 0
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-sysctl.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sysctl.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>modprobe</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>sysctl.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>modprobe</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 338c1d3280..409b6f0895 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -154,7 +157,7 @@
<command>list-dependencies</command>, i.e. follow
dependencies of type <varname>WantedBy=</varname>,
<varname>RequiredBy=</varname>,
- <varname>RequiredByOverrridable=</varname>,
+ <varname>RequiredByOverridable=</varname>,
<varname>PartOf=</varname>, <varname>BoundBy=</varname>,
instead of <varname>Wants=</varname> and similar.
</para>
@@ -316,8 +319,8 @@
<para>Do not synchronously wait for the requested operation
to finish. If this is not specified, the job will be
verified, enqueued and <command>systemctl</command> will
- wait until it is completed. By passing this argument, it is
- only verified and enqueued.</para>
+ wait until the unit's start-up is completed. By passing this
+ argument, it is only verified and enqueued.</para>
</listitem>
</varlistentry>
@@ -410,8 +413,8 @@
processes. Not all unit types manage processes of these
types however. For example, for mount units, control processes
are defined (which are the invocations of
- <filename>/usr/bin/mount</filename> and
- <filename>/usr/bin/umount</filename>), but no main process
+ <filename>&MOUNT_PATH;</filename> and
+ <filename>&UMOUNT_PATH;</filename>), but no main process
is defined. If omitted, defaults to
<option>all</option>.</para>
</listitem>
@@ -456,6 +459,18 @@
</varlistentry>
<varlistentry>
+ <term><option>--now</option></term>
+
+ <listitem>
+ <para>When used with <command>enable</command>, the units
+ will also be started. When used with <command>disable</command> or
+ <command>mask</command>, the units will also be stopped. The start
+ or stop operation is only carried out when the respective enable or
+ disable operation has been successful.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--root=</option></term>
<listitem>
@@ -527,6 +542,18 @@
</varlistentry>
<varlistentry>
+ <term><option>--firmware-setup</option></term>
+
+ <listitem>
+ <para>When used with the <command>reboot</command> command,
+ indicate to the system's firmware to boot into setup
+ mode. Note that this is currently only supported on some EFI
+ systems and only if the system was booted in EFI
+ mode.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--plain</option></term>
<listitem>
@@ -909,11 +936,12 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
the changes are taken into account immediately. Note that
this does <emphasis>not</emphasis> have the effect of also
starting any of the units being enabled. If this
- is desired, a separate <command>start</command> command must
- be invoked for the unit. Also note that in case of instance
- enablement, symlinks named the same as instances are created in
- the install location, however they all point to the same
- template unit file.</para>
+ is desired, either <option>--now</option> should be used
+ together with this command, or an additional <command>start</command>
+ command must be invoked for the unit. Also note that in case of
+ instance enablement, symlinks named the same as instances
+ are created in the install location, however they all point to the
+ same template unit file.</para>
<para>This command will print the actions executed. This
output may be suppressed by passing <option>--quiet</option>.
@@ -968,9 +996,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<command>enable</command>. This call implicitly reloads the
systemd daemon configuration after completing the disabling
of the units. Note that this command does not implicitly
- stop the units that are being disabled. If this is desired,
- an additional <command>stop</command> command should be
- executed afterwards.</para>
+ stop the units that are being disabled. If this is desired, either
+ <option>--now</option> should be used together with this command, or
+ an additional <command>stop</command> command should be executed
+ afterwards.</para>
<para>This command will print the actions executed. This
output may be suppressed by passing <option>--quiet</option>.
@@ -1116,7 +1145,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
activation of the unit, including enablement and manual
activation. Use this option with care. This honors the
<option>--runtime</option> option to only mask temporarily
- until the next reboot of the system.</para>
+ until the next reboot of the system. The <option>--now</option>
+ option can be used to ensure that the units are also stopped.</para>
</listitem>
</varlistentry>
@@ -1495,7 +1525,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<listitem>
<para>Shut down and halt the system. This is mostly equivalent to
- <command>start halt.target --irreversible</command>, but also
+ <command>start halt.target --job-mode=replace-irreversibly</command>, but also
prints a wall message to all users. If combined with
<option>--force</option>, shutdown of all running services is
skipped, however all processes are killed and all file
@@ -1511,7 +1541,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<listitem>
<para>Shut down and power-off the system. This is mostly
- equivalent to <command>start poweroff.target --irreversible</command>,
+ equivalent to <command>start poweroff.target --job-mode=replace-irreversibly</command>,
but also prints a wall message to all users. If combined with
<option>--force</option>, shutdown of all running services is
skipped, however all processes are killed and all file
@@ -1527,7 +1557,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<listitem>
<para>Shut down and reboot the system. This is mostly
- equivalent to <command>start reboot.target --irreversible</command>,
+ equivalent to <command>start reboot.target --job-mode=replace-irreversibly</command>,
but also prints a wall message to all users. If combined with
<option>--force</option>, shutdown of all running services is
skipped, however all processes are killed and all file
@@ -1554,7 +1584,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<listitem>
<para>Shut down and reboot the system via kexec. This is
- mostly equivalent to <command>start kexec.target --irreversible</command>,
+ mostly equivalent to <command>start kexec.target --job-mode=replace-irreversibly</command>,
but also prints a wall message to all users. If combined
with <option>--force</option>, shutdown of all running
services is skipped, however all processes are killed and
@@ -1703,9 +1733,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<varname>$VISUAL</varname> are present or if it is set to an empty
string or if their execution failed, systemctl will try to execute well
known editors in this order:
- <citerefentry><refentrytitle>nano</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>vim</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>vi</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+ <citerefentry project='die-net'><refentrytitle>editor</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>nano</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>vim</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>vi</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
</variablelist>
@@ -1721,7 +1752,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<citerefentry><refentrytitle>loginctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd.resource-management</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml
index e64894a28b..3aecc40b60 100644
--- a/man/systemd-activate.xml
+++ b/man/systemd-activate.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<cmdsynopsis>
- <command>/usr/lib/systemd/systemd-activate</command>
+ <command>&rootlibexecdir;/systemd-activate</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain"><replaceable>daemon</replaceable></arg>
<arg choice="opt" rep="repeat">OPTIONS</arg>
@@ -66,7 +69,7 @@
of the daemon per connection (inetd-style).
</para>
- <para>The daemon to launch and its options should be specifed
+ <para>The daemon to launch and its options should be specified
after options intended for <command>systemd-activate</command>.
</para>
@@ -76,7 +79,7 @@
inherited, and sockets will be passed through file descriptors 3
and higher. Sockets passed through <varname>$LISTEN_FDS</varname>
to <command>systemd-activate</command> will be passed through to
- the dameon, in the original positions. Other sockets specified
+ the daemon, in the original positions. Other sockets specified
with <option>--listen</option> will use consecutive descriptors.
</para>
</refsect1>
@@ -149,13 +152,13 @@
<example>
<title>Run an echo server on port 2000</title>
- <programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 -a cat</programlisting>
+ <programlisting>$ &rootlibexecdir;/systemd-activate -l 2000 -a cat</programlisting>
</example>
<example>
<title>Run a socket activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title>
- <programlisting>$ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting>
+ <programlisting>$ &rootlibexecdir;/systemd-activate -l 19531 &rootlibexecdir;/systemd-journal-gatewayd</programlisting>
</example>
</refsect1>
@@ -165,7 +168,7 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 1ff81d3d5a..3509d155d3 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -145,7 +148,7 @@
<para><command>systemd-analyze dot</command> generates textual
dependency graph description in dot format for further processing
with the GraphViz
- <citerefentry><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
tool. Use a command line like <command>systemd-analyze dot | dot
-Tsvg > systemd.svg</command> to generate a graphical dependency
tree. Unless <option>--order</option> or
@@ -229,7 +232,7 @@
<command>dot</command> command (see above), this selects which
relationships are shown in the dependency graph. Both options
require a
- <citerefentry><refentrytitle>glob</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>glob</refentrytitle><manvolnum>7</manvolnum></citerefentry>
pattern as an argument, which will be matched against the
left-hand and the right-hand, respectively, nodes of a
relationship.</para>
diff --git a/man/systemd-ask-password-console.service.xml b/man/systemd-ask-password-console.service.xml
index 479e5f2e5b..488a8793dd 100644
--- a/man/systemd-ask-password-console.service.xml
+++ b/man/systemd-ask-password-console.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml
index 877c71af53..2402103719 100644
--- a/man/systemd-ask-password.xml
+++ b/man/systemd-ask-password.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-backlight@.service.xml b/man/systemd-backlight@.service.xml
index a259f5d583..123576255d 100644
--- a/man/systemd-backlight@.service.xml
+++ b/man/systemd-backlight@.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-backlight@.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-backlight</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-backlight</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-binfmt.service.xml b/man/systemd-binfmt.service.xml
index 66d264389e..8659e63ebc 100644
--- a/man/systemd-binfmt.service.xml
+++ b/man/systemd-binfmt.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-binfmt.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-binfmt</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-binfmt</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-bootchart.xml b/man/systemd-bootchart.xml
index 538666760a..ea8a783601 100644
--- a/man/systemd-bootchart.xml
+++ b/man/systemd-bootchart.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -60,7 +63,7 @@
usage, as well as per-process information from a running system.
Collected results are output as an SVG graph. Normally,
systemd-bootchart is invoked by the kernel by passing
- <option>init=<filename>/usr/lib/systemd/systemd-bootchart</filename></option>
+ <option>init=<filename>&rootlibexecdir;/systemd-bootchart</filename></option>
on the kernel command line. systemd-bootchart will then fork the
real init off to resume normal system startup, while monitoring
and logging startup information in the background.
@@ -106,7 +109,7 @@
<listitem><para>The kernel can invoke
<command>systemd-bootchart</command> instead of the init
process. In turn, <command>systemd-bootchart</command> will
- invoke <command>/usr/lib/systemd/systemd</command>.
+ invoke <command>&rootlibexecdir;/systemd</command>.
</para></listitem>
</varlistentry>
@@ -128,7 +131,7 @@
<title>Options</title>
<para>These options can also be set in the
- <filename>/etc/systemd/bootchart.conf</filename> file. See
+ <filename>&pkgsysconfdir;/bootchart.conf</filename> file. See
<citerefentry project='man-pages'><refentrytitle>bootchart.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
@@ -201,7 +204,7 @@
<term><option>-i</option></term>
<term><option>--init <replaceable>path</replaceable></option></term>
<listitem><para>Use this init binary. Defaults to
- <command>/usr/lib/systemd/systemd</command>.
+ <command>&rootlibexecdir;/systemd</command>.
</para></listitem>
</varlistentry>
diff --git a/man/systemd-bus-proxyd.xml b/man/systemd-bus-proxyd.xml
index 2c7764047b..bbcf3d0981 100644
--- a/man/systemd-bus-proxyd.xml
+++ b/man/systemd-bus-proxyd.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2013 Zbigniew Jędrzejewski-Szmek
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd-bus-proxyd" conditional="ENABLE_KDBUS"
@@ -50,7 +53,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<refsynopsisdiv>
<cmdsynopsis>
- <command>/usr/lib/systemd/systemd-bus-proxyd</command>
+ <command>&rootlibexecdir;/systemd-bus-proxyd</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt"><replaceable>PLACEHOLDER</replaceable></arg>
</cmdsynopsis>
@@ -101,7 +104,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<title>See Also</title>
<para>
- <citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
<ulink url="https://code.google.com/p/d-bus/">kdbus</ulink>
</para>
diff --git a/man/systemd-bus-proxyd@.service.xml b/man/systemd-bus-proxyd@.service.xml
index 141b43f6d9..9dabc4dd5f 100644
--- a/man/systemd-bus-proxyd@.service.xml
+++ b/man/systemd-bus-proxyd@.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -73,7 +76,7 @@
<para>
<citerefentry><refentrytitle>systemd-bus-proxyd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='dbus'><refentrytitle>dbus-daemon</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<ulink url="http://freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
<ulink url="https://code.google.com/p/d-bus/">kdbus</ulink>
</para>
diff --git a/man/systemd-cat.xml b/man/systemd-cat.xml
index 38ddf66d27..d51acd7cf8 100644
--- a/man/systemd-cat.xml
+++ b/man/systemd-cat.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -171,7 +174,7 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>logger</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>logger</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-cgls.xml b/man/systemd-cgls.xml
index e8f0368f48..d3b2404a76 100644
--- a/man/systemd-cgls.xml
+++ b/man/systemd-cgls.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml
index f1ff218c39..b0c88001d4 100644
--- a/man/systemd-cgtop.xml
+++ b/man/systemd-cgtop.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml
index 6a7ced19a6..d40562b5e1 100644
--- a/man/systemd-coredump.xml
+++ b/man/systemd-coredump.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -49,7 +52,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/systemd-coredump</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-coredump</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -64,7 +67,7 @@
<filename>/usr/lib/sysctl.d/50-coredump.conf</filename> which
configures <varname>kernel.core_pattern</varname> to invoke
<command>systemd-coredump</command>. This file may be masked or
- overriden to use a different setting following normal
+ overridden to use a different setting following normal
<citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> rules.</para>
<para>The behaviour of a specific program upon reception of a
diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml
index 0e48e79346..c4747f72d3 100644
--- a/man/systemd-cryptsetup-generator.xml
+++ b/man/systemd-cryptsetup-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -46,7 +49,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-cryptsetup-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-cryptsetup-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -59,10 +62,8 @@
<citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
units as necessary.</para>
- <para><filename>systemd-cryptsetup-generator</filename>
- implements the <ulink
- url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <para><filename>systemd-cryptsetup-generator</filename> implements
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@@ -187,7 +188,7 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-cryptsetup@.service.xml b/man/systemd-cryptsetup@.service.xml
index bd03637deb..efc213a917 100644
--- a/man/systemd-cryptsetup@.service.xml
+++ b/man/systemd-cryptsetup@.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-cryptsetup@.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-cryptsetup</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-cryptsetup</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -78,7 +81,7 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-debug-generator.xml b/man/systemd-debug-generator.xml
index 74c3b2620e..075ec58e7e 100644
--- a/man/systemd-debug-generator.xml
+++ b/man/systemd-debug-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -47,7 +50,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-debug-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-debug-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -79,10 +82,8 @@
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
<command>enable</command> command.</para>
- <para><filename>systemd-debug-generator</filename> implements the
- <ulink
- url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <para><filename>systemd-debug-generator</filename> implements
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd-delta.xml b/man/systemd-delta.xml
index fd81b2c907..69ea0411e6 100644
--- a/man/systemd-delta.xml
+++ b/man/systemd-delta.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -69,7 +72,7 @@
certain configuration files can have <literal>.d</literal>
directories which contain "drop-in" files with configuration
snippets which augment the main configuration file. "Drop-in"
- files can be overriden in the same way by placing files with the
+ files can be overridden in the same way by placing files with the
same name in a directory of higher priority (except that in case
of "drop-in" files, both the "drop-in" file name and the name of
the containing directory, which corresponds to the name of the
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml
index 40755a24d0..16ac4f3091 100644
--- a/man/systemd-detect-virt.xml
+++ b/man/systemd-detect-virt.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-efi-boot-generator.xml b/man/systemd-efi-boot-generator.xml
index b2d8d65e3d..1f8194dd62 100644
--- a/man/systemd-efi-boot-generator.xml
+++ b/man/systemd-efi-boot-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-efi-boot-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-efi-boot-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -62,15 +65,13 @@
does not communicate the used ESP to the OS, on systems where
<filename>/boot</filename> is an explicitly configured mount (for
example, listed in
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>)
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>)
or where the <filename>/boot</filename> mount point is non-empty.
Since this generator creates an automount unit, the mount will
only be activated on-demand, when accessed.</para>
<para><filename>systemd-efi-boot-generator</filename> implements
- the <ulink
- url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@@ -80,8 +81,7 @@
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>gummiboot</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-escape.xml b/man/systemd-escape.xml
index 0c3b230526..6680bcf963 100644
--- a/man/systemd-escape.xml
+++ b/man/systemd-escape.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml
index 67d38ba31f..6ec54bf1c3 100644
--- a/man/systemd-firstboot.xml
+++ b/man/systemd-firstboot.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -91,7 +94,7 @@
<para>Note that this tool operates directly on the file system and
does not involve any running system services, unlike
- <citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>timedatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
or
<citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
@@ -125,7 +128,7 @@
<varname>LANG=</varname> and <varname>LC_MESSAGES</varname>
settings. The argument should be a valid locale identifier,
such as <literal>de_DE.UTF-8</literal>. This controls the
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
configuration file.</para></listitem>
</varlistentry>
@@ -163,7 +166,7 @@
<listitem><para>Sets the password of the system's root user.
This creates a
- <citerefentry><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>
file. This setting exists in two forms:
<option>--root-password=</option> accepts the password to set
directly on the command line,
@@ -171,7 +174,7 @@
Note that it is not recommended specifying passwords on the
command line as other users might be able to see them simply
by invoking
- <citerefentry><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
+ <citerefentry project='die-net'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -244,13 +247,13 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>localtime</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>timedatectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
diff --git a/man/systemd-fsck@.service.xml b/man/systemd-fsck@.service.xml
index 88e11e89d4..7286cd8803 100644
--- a/man/systemd-fsck@.service.xml
+++ b/man/systemd-fsck@.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-fsck@.service</filename></para>
<para><filename>systemd-fsck-root.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-fsck</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-fsck</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -80,11 +83,9 @@
the filesystem should actually be checked based on the time since
last check, number of mounts, unclean unmount, etc.</para>
- <para><filename>systemd-fsck</filename> will forward file system
- checking progress to the console. If a file system check fails for
- a service without <option>nofail</option>, emergency mode is
- activated, by isolating to
- <filename>emergency.target</filename>.</para>
+ <para>If a file system check fails for a service without
+ <option>nofail</option>, emergency mode is activated, by isolating
+ to <filename>emergency.target</filename>.</para>
</refsect1>
<refsect1>
@@ -125,16 +126,16 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-quotacheck.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fsck.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fsck.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fsck.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml
index 8f82e33304..383aab70ff 100644
--- a/man/systemd-fstab-generator.xml
+++ b/man/systemd-fstab-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -46,7 +49,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-fstab-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-fstab-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -54,7 +57,7 @@
<para><filename>systemd-fstab-generator</filename> is a generator
that translates <filename>/etc/fstab</filename> (see
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details) into native systemd units early at boot and when
configuration of the system manager is reloaded. This will
instantiate mount and swap units as necessary.</para>
@@ -71,10 +74,8 @@
for more information about special <filename>/etc/fstab</filename>
mount options this generator understands.</para>
- <para><filename>systemd-fstab-generator</filename> implements the
- <ulink
- url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <para><filename>systemd-fstab-generator</filename> implements
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@@ -158,7 +159,7 @@
<listitem><para>Takes the <filename>/usr</filename> filesystem
mount options to use. If <varname>mount.usr=</varname> or
<varname>mount.usrfstype=</varname> is set, then
- <varname>mount.usrflages=</varname> will default to the value
+ <varname>mount.usrflags=</varname> will default to the value
set in <varname>rootflags=</varname>.</para>
<para>Otherwise this value will be read from the
@@ -175,7 +176,7 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.swap</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
diff --git a/man/systemd-getty-generator.xml b/man/systemd-getty-generator.xml
index 0b5b2f2a71..12127d9c2a 100644
--- a/man/systemd-getty-generator.xml
+++ b/man/systemd-getty-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -47,7 +50,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-getty-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-getty-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -75,9 +78,8 @@
for more information on the <varname>console=</varname> kernel
parameter.</para>
- <para><filename>systemd-getty-generator</filename> implements the
- <ulink url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <para><filename>systemd-getty-generator</filename> implements
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<para>Further information about configuration of gettys you may
find in
diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml
index 9c706df246..16ff100d73 100644
--- a/man/systemd-gpt-auto-generator.xml
+++ b/man/systemd-gpt-auto-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-gpt-auto-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-gpt-auto-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -66,7 +69,7 @@
Partitions Specification</ulink>. Note that this generator has no
effect on non-GPT systems, on systems where the units are
explicitly configured (for example, listed in
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
or where the mount points are non-empty.</para>
<para>This generator will only look for root partitions on the
@@ -157,9 +160,7 @@
using <command>btrfs subvolume set-default</command>.</para>
<para><filename>systemd-gpt-auto-generator</filename> implements
- the
- <ulink url="http://www.freedesktop.org/wiki/Software/systemd/Generators">Generator
- Specification</ulink>.</para>
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@@ -171,9 +172,9 @@
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-efi-boot-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-halt.service.xml b/man/systemd-halt.service.xml
index c94e2a1820..7e83a88fab 100644
--- a/man/systemd-halt.service.xml
+++ b/man/systemd-halt.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -56,7 +59,7 @@
<para><filename>systemd-poweroff.service</filename></para>
<para><filename>systemd-reboot.service</filename></para>
<para><filename>systemd-kexec.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-shutdown</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-shutdown</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -75,7 +78,7 @@
<para>When these services are run, they ensure that PID 1 is
replaced by the
- <filename>/usr/lib/systemd/systemd-shutdown</filename> tool which
+ <filename>&rootlibexecdir;/systemd-shutdown</filename> tool which
is then responsible for the actual shutdown. Before shutting down,
this binary will try to unmount all remaining file systems,
disable all remaining swap devices, detach all remaining storage
@@ -90,7 +93,7 @@
<para>Immediately before executing the actual system
halt/poweroff/reboot/kexec <filename>systemd-shutdown</filename>
will run all executables in
- <filename>/usr/lib/systemd/system-shutdown/</filename> and pass
+ <filename>&rootlibexecdir;/system-shutdown/</filename> and pass
one arguments to them: either <literal>halt</literal>,
<literal>poweroff</literal>, <literal>reboot</literal> or
<literal>kexec</literal>, depending on the chosen action. All
diff --git a/man/systemd-hibernate-resume-generator.xml b/man/systemd-hibernate-resume-generator.xml
index a21782cbf9..52837bc3f0 100644
--- a/man/systemd-hibernate-resume-generator.xml
+++ b/man/systemd-hibernate-resume-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -46,7 +49,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-hibernate-resume-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-hibernate-resume-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -73,7 +76,7 @@
<listitem><para>Takes a path to the resume device. Both
persistent block device paths like
<filename>/dev/disk/by-foo/bar</filename> and
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-style
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>-style
specifiers like <literal>FOO=bar</literal> are
supported.</para></listitem>
</varlistentry>
diff --git a/man/systemd-hibernate-resume@.service.xml b/man/systemd-hibernate-resume@.service.xml
index 7d00827447..bca08b5fd5 100644
--- a/man/systemd-hibernate-resume@.service.xml
+++ b/man/systemd-hibernate-resume@.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-hibernate-resume@.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-hibernate-resume</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-hibernate-resume</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-hostnamed.service.xml b/man/systemd-hostnamed.service.xml
index 6990d41b02..2db1d035b1 100644
--- a/man/systemd-hostnamed.service.xml
+++ b/man/systemd-hostnamed.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-hostnamed.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-hostnamed</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-hostnamed</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-hwdb.xml b/man/systemd-hwdb.xml
index f1a14025b0..9a58776af2 100644
--- a/man/systemd-hwdb.xml
+++ b/man/systemd-hwdb.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refentry id="systemd-hwdb" conditional="ENABLE_HWDB">
<refentryinfo>
@@ -57,7 +60,7 @@
<varlistentry>
<term><option>--usr</option></term>
<listitem>
- <para>Generate in /usr/lib/udev instead of /etc/udev.</para>
+ <para>Generate in &udevlibexecdir; instead of /etc/udev.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd-inhibit.xml b/man/systemd-inhibit.xml
index 9d85908f97..6ff07210d3 100644
--- a/man/systemd-inhibit.xml
+++ b/man/systemd-inhibit.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-initctl.service.xml b/man/systemd-initctl.service.xml
index 5c7f9a4a16..95288d068f 100644
--- a/man/systemd-initctl.service.xml
+++ b/man/systemd-initctl.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -52,7 +55,7 @@
<refsynopsisdiv>
<para><filename>systemd-initctl.service</filename></para>
<para><filename>systemd-initctl.socket</filename></para>
- <para><filename>/usr/lib/systemd/systemd-initctl</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-initctl</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-journal-gatewayd.service.xml b/man/systemd-journal-gatewayd.service.xml
index 7420b59c95..f7588794cd 100644
--- a/man/systemd-journal-gatewayd.service.xml
+++ b/man/systemd-journal-gatewayd.service.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2012 Zbigniew Jędrzejewski-Szmek
+ Copyright 2012 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd-journal-gatewayd.service" conditional='HAVE_MICROHTTPD'
@@ -54,7 +57,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<para><filename>systemd-journal-gatewayd.service</filename></para>
<para><filename>systemd-journal-gatewayd.socket</filename></para>
<cmdsynopsis>
- <command>/usr/lib/systemd/systemd-journal-gatewayd</command>
+ <command>&rootlibexecdir;/systemd-journal-gatewayd</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
</cmdsynopsis>
</refsynopsisdiv>
diff --git a/man/systemd-journal-remote.xml b/man/systemd-journal-remote.xml
index 2687662a14..596479edb1 100644
--- a/man/systemd-journal-remote.xml
+++ b/man/systemd-journal-remote.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -156,7 +159,7 @@
<varname>$LISTEN_FDS</varname>/<varname>$LISTEN_PID</varname>.
In the second case, an HTTP or HTTPS server will be spawned on
this port, respectively for <option>--listen-http</option> and
- <option>--listen-https</option>. Currenntly, only POST requests
+ <option>--listen-https</option>. Currently, only POST requests
to <filename>/upload</filename> with <literal>Content-Type:
application/vnd.fdo.journal</literal> are supported.</para>
</listitem>
@@ -310,6 +313,7 @@ systemd-journal-remote --url http://some.host:19531/
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-journal-gatewayd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
diff --git a/man/systemd-journal-upload.xml b/man/systemd-journal-upload.xml
index 607167d274..5398ff42e2 100644
--- a/man/systemd-journal-upload.xml
+++ b/man/systemd-journal-upload.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2014 Zbigniew Jędrzejewski-Szmek
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd-journal-upload" conditional='HAVE_MICROHTTPD'
@@ -243,8 +246,8 @@ openssl ca -batch -config ca.conf -notext -in $CLIENT.csr -out $CLIENT.pem
<varname>TrustedCertificateFile=</varname>,
<varname>ServerCertificateFile=</varname>,
<varname>ServerKeyFile=</varname>, in
- <filename>/etc/systemd/journal-remote.conf</filename> and
- <filename>/etc/systemd/journal-upload.conf</filename>
+ <filename>&pkgsysconfdir;/journal-remote.conf</filename> and
+ <filename>&pkgsysconfdir;/journal-upload.conf</filename>
respectively. The default locations can be queried by using
<command>systemd-journal-remote --help</command> and
<command>systemd-journal-upload --help</command>.</para>
diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml
index 6b250b65e6..ead1eee3fb 100644
--- a/man/systemd-journald.service.xml
+++ b/man/systemd-journald.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -54,7 +57,7 @@
<para><filename>systemd-journald.service</filename></para>
<para><filename>systemd-journald.socket</filename></para>
<para><filename>systemd-journald-dev-log.socket</filename></para>
- <para><filename>/usr/lib/systemd/systemd-journald</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-journald</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -199,7 +202,7 @@
<variablelist>
<varlistentry>
- <term><filename>/etc/systemd/journald.conf</filename></term>
+ <term><filename>&pkgsysconfdir;/journald.conf</filename></term>
<listitem><para>Configure
<command>systemd-journald</command>
@@ -241,7 +244,7 @@
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
<command>pydoc systemd.journal</command>.
</para>
diff --git a/man/systemd-localed.service.xml b/man/systemd-localed.service.xml
index 8999166383..1628054a3b 100644
--- a/man/systemd-localed.service.xml
+++ b/man/systemd-localed.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-localed.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-localed</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-localed</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -64,7 +67,7 @@
unused.</para>
<para>The tool
- <citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
is a command line client to this service.</para>
<para>See the <ulink
@@ -77,10 +80,10 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>vconsole.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-logind.service.xml b/man/systemd-logind.service.xml
index 5733e42cd1..1416d884ce 100644
--- a/man/systemd-logind.service.xml
+++ b/man/systemd-logind.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-logind.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-logind</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-logind</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-machine-id-commit.service.xml b/man/systemd-machine-id-commit.service.xml
index 7c8fc0874e..7bda76c4e5 100644
--- a/man/systemd-machine-id-commit.service.xml
+++ b/man/systemd-machine-id-commit.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -47,7 +50,7 @@
<refsynopsisdiv>
<para><filename>systemd-machine-id-commit.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-machine-id-commit</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-machine-id-commit</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-machine-id-commit.xml b/man/systemd-machine-id-commit.xml
index cfb1722063..0ebbfe7f07 100644
--- a/man/systemd-machine-id-commit.xml
+++ b/man/systemd-machine-id-commit.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml
index 22bad3e5f4..5a84a3b36c 100644
--- a/man/systemd-machine-id-setup.xml
+++ b/man/systemd-machine-id-setup.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -122,7 +125,7 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>dbus-uuidgen</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='dbus'><refentrytitle>dbus-uuidgen</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-machined.service.xml b/man/systemd-machined.service.xml
index 999aeee1c6..a62e42c35b 100644
--- a/man/systemd-machined.service.xml
+++ b/man/systemd-machined.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-machined.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-machined</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-machined</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-modules-load.service.xml b/man/systemd-modules-load.service.xml
index dacd083bad..dc9e2a8554 100644
--- a/man/systemd-modules-load.service.xml
+++ b/man/systemd-modules-load.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-modules-load.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-modules-load</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-modules-load</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-networkd-wait-online.service.xml b/man/systemd-networkd-wait-online.service.xml
index f53b337daa..157671d6b2 100644
--- a/man/systemd-networkd-wait-online.service.xml
+++ b/man/systemd-networkd-wait-online.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-networkd-wait-online.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-networkd-wait-online</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-networkd-wait-online</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml
index 0bfe5519bc..1eef5b745b 100644
--- a/man/systemd-networkd.service.xml
+++ b/man/systemd-networkd.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-networkd.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-networkd</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-networkd</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -75,10 +78,10 @@
<refsect1><title>Configuration Files</title>
<para>The configuration files are read from the files located in the
- system network directory <filename>/usr/lib/systemd/network</filename>,
+ system network directory <filename>&rootlibexecdir;/network</filename>,
the volatile runtime network directory
<filename>/run/systemd/network</filename> and the local administration
- network directory <filename>/etc/systemd/network</filename>.</para>
+ network directory <filename>&pkgsysconfdir;/network</filename>.</para>
<para>Networks are configured in <filename>.network</filename>
files, see
diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml
index 06d5ae5319..1158473117 100644
--- a/man/systemd-notify.xml
+++ b/man/systemd-notify.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 4a936d326f..218c7291e0 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -84,13 +87,10 @@
kernel modules may not be loaded from within the container.</para>
<para>Note that even though these security precautions are taken
- <command>systemd-nspawn</command> is not suitable for secure
+ <command>systemd-nspawn</command> is not suitable for fully secure
container setups. Many of the security features may be
circumvented and are hence primarily useful to avoid accidental
- changes to the host system from the container. The intended use of
- this program is debugging and testing as well as building of
- packages, distributions and software involved with boot and
- systems management.</para>
+ changes to the host system from the container.</para>
<para>In contrast to
<citerefentry project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>1</manvolnum></citerefentry> <command>systemd-nspawn</command>
@@ -144,7 +144,7 @@
<replaceable>COMMAND</replaceable> specifies the program to launch
in the container, and the remaining arguments are used as
arguments for this program. If <option>-b</option> is not used and
- no arguments are specifed, a shell is launched in the
+ no arguments are specified, a shell is launched in the
container.</para>
<para>The following options are understood:</para>
@@ -190,7 +190,11 @@
system, so that the <literal>btrfs</literal> subvolume may be
created. May not be specified together with
<option>--image=</option> or
- <option>--ephemeral</option>.</para></listitem>
+ <option>--ephemeral</option>.</para>
+
+ <para>Note that this switch leaves host name, machine ID and
+ all other settings that could identify the instance
+ unmodified.</para></listitem>
</varlistentry>
<varlistentry>
@@ -204,7 +208,10 @@
This option is only supported if the root file system is
<literal>btrfs</literal>. May not be specified together with
<option>--image=</option> or
- <option>--template=</option>.</para></listitem>
+ <option>--template=</option>.</para>
+ <para>Note that this switch leaves host name, machine ID and
+ all other settings that could identify the instance
+ unmodified.</para></listitem>
</varlistentry>
<varlistentry>
@@ -297,11 +304,62 @@
<listitem><para>Make the container part of the specified
slice, instead of the default
- <filename>machine.slice</filename>.</para>
+ <filename>machine.slice</filename>. This is only applies if
+ the machine is run in its own scope unit, i.e. if
+ <option>--keep-unit</option> is not used.</para>
</listitem>
</varlistentry>
<varlistentry>
+ <term><option>--property=</option></term>
+
+ <listitem><para>Set a unit property on the scope unit to
+ register for the machine. This only applies if the machine is
+ run in its own scope unit, i.e. if
+ <option>--keep-unit</option> is not used. Takes unit property
+ assignments in the same format as <command>systemctl
+ set-property</command>. This is useful to set memory limits
+ and similar for machines.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--private-users=</option></term>
+
+ <listitem><para>Enables user namespacing. If enabled the
+ container will run with its own private set of Unix user and
+ group ids (UIDs and GIDs). Takes none, one or two
+ colon-separated parameters: the first parameter specifies the
+ first host UID to assign to the container, the second
+ parameter specifies the number of host UIDs to assign to the
+ container. If the second parameter is omitted, 65536 UIDs are
+ assigned. If the first parameter is also omitted (and hence
+ no parameter passed at all), the first UID assigned to the
+ container is read from the owner of the root directory of the
+ container's directory tree. By default no user namespacing is
+ applied.</para>
+
+ <para>Note that user namespacing currently requires OS trees
+ that are prepared for the UID shift that is being applied:
+ UIDs and GIDs used for file ownership or in file ACL entries
+ must be shifted to the container UID base that is
+ used during container runtime.</para>
+
+ <para>It is recommended to assign as least 65536 UIDs to each
+ container, so that the usable UID range in the container
+ covers 16bit. For best security do not assign overlapping UID
+ ranges to multiple containers. It is hence a good idea to use
+ the upper 16bit of the host 32bit UIDs as container
+ identifier, while the lower 16bit encode the container UID
+ used.</para>
+
+ <para>When user namespaces are used the GID range assigned to
+ each container is always chosen identical to the UID
+ range.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
<term><option>--private-network</option></term>
<listitem><para>Disconnect networking of the container from
@@ -399,7 +457,7 @@
container port number in the range from 1 to 65535. The
protocol specifier and its separating colon may be omitted, in
which case <literal>tcp</literal> is assumed. The container
- port number and its colon may be ommitted, in which case the
+ port number and its colon may be omitted, in which case the
same port as the host port is implied. This option is only
supported if private networking is used, such as
<option>--network-veth</option> or
@@ -456,6 +514,19 @@
</varlistentry>
<varlistentry>
+ <term><option>--kill-signal=</option></term>
+
+ <listitem><para>Specify the process signal to send to the
+ container's PID 1 when nspawn itself receives SIGTERM, in
+ order to trigger an orderly shutdown of the
+ container. Defaults to SIGRTMIN+3 if <option>--boot</option>
+ is used (on systemd-compatible init systems SIGRTMIN+3
+ triggers an orderly shutdown). Takes a signal name like
+ <literal>SIGHUP</literal>, <literal>SIGTERM</literal> or
+ similar as argument.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--link-journal=</option></term>
<listitem><para>Control whether the container's journal shall
@@ -510,8 +581,10 @@
same path in the container --, or a colon-separated pair of
paths -- in which case the first specified path is the source
in the host, and the second path is the destination in the
- container. The <option>--bind-ro=</option> option creates
- read-only bind mounts.</para></listitem>
+ container. This option may be specified multiple times for
+ creating multiple independent bind mount points. The
+ <option>--bind-ro=</option> option creates read-only bind
+ mounts.</para></listitem>
</varlistentry>
<varlistentry>
@@ -531,6 +604,52 @@
</varlistentry>
<varlistentry>
+ <term><option>--overlay=</option></term>
+ <term><option>--overlay-ro=</option></term>
+
+ <listitem><para>Combine multiple directory trees into one
+ overlay file system and mount it into the container. Takes a
+ list of colon-separated paths to the directory trees to
+ combine and the destination mount point.</para>
+
+ <para>If three or more paths are specified, then the last
+ specified path is the destination mount point in the
+ container, all paths specified before refer to directory trees
+ on the host and are combined in the specified order into one
+ overlay file system. The left-most path is hence the lowest
+ directory tree, the second-to-last path the highest directory
+ tree in the stacking order. If <option>--overlay-ro=</option>
+ is used instead of <option>--overlay=</option> a read-only
+ overlay file system is created. If a writable overlay file
+ system is created all changes made to it are written to the
+ highest directory tree in the stacking order, i.e. the
+ second-to-last specified.</para>
+
+ <para>If only two paths are specified, then the second
+ specified path is used both as the top-level directory tree in
+ the stacking order as seen from the host, as well as the mount
+ point for the overlay file system in the container. At least
+ two paths have to be specified.</para>
+
+ <para>For details about overlay file systems, see <ulink
+ url="https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt">overlayfs.txt</ulink>. Note
+ that the semantics of overlay file systems are substantially
+ different from normal file systems, in particular regarding
+ reported device and inode information. Device and inode
+ information may change for a file while it is being written
+ to, and processes might see out-of-date versions of files at
+ times. Note that this switch automatically derives the
+ <literal>workdir=</literal> mount option for the overlay file
+ system from the top-level directory tree, making it a sibling
+ of it. It is hence essential that the top-level directory tree
+ is not a mount point itself (since the working directory must
+ be on the same file system as the top-most directory
+ tree). Also note that the <literal>lowerdir=</literal> mount
+ option receives the paths to stack in the opposite order of
+ this switch.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--setenv=</option></term>
<listitem><para>Specifies an environment variable assignment
@@ -598,7 +717,7 @@
<listitem><para>Control the architecture ("personality")
reported by
- <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
in the container. Currently, only <literal>x86</literal> and
<literal>x86-64</literal> are supported. This is useful when
running a 32-bit container on a 64-bit host. If this setting
@@ -693,7 +812,7 @@
<programlisting># pacstrap -c -d ~/arch-tree/ base
# systemd-nspawn -bD ~/arch-tree/</programlisting>
- <para>This installs a mimimal Arch Linux distribution into the
+ <para>This installs a minimal Arch Linux distribution into the
directory <filename>~/arch-tree/</filename> and then boots an OS
in a namespace container in it.</para>
</example>
@@ -735,7 +854,7 @@
<citerefentry project='archlinux'><refentrytitle>pacman</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-path.xml b/man/systemd-path.xml
index dfc75ee0ff..185a0cc901 100644
--- a/man/systemd-path.xml
+++ b/man/systemd-path.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-quotacheck.service.xml b/man/systemd-quotacheck.service.xml
index 2179f11e95..7673635a68 100644
--- a/man/systemd-quotacheck.service.xml
+++ b/man/systemd-quotacheck.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-quotacheck.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-quotacheck</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-quotacheck</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -86,7 +89,7 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>quotacheck</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>quotacheck</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fsck@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-random-seed.service.xml b/man/systemd-random-seed.service.xml
index 8c836688fe..580c3518c3 100644
--- a/man/systemd-random-seed.service.xml
+++ b/man/systemd-random-seed.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-random-seed.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-random-seed</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-random-seed</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-remount-fs.service.xml b/man/systemd-remount-fs.service.xml
index 7b88ac3f3c..c8c3d16157 100644
--- a/man/systemd-remount-fs.service.xml
+++ b/man/systemd-remount-fs.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-remount-fs.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-remount-fs</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-remount-fs</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -56,12 +59,12 @@
<para><filename>systemd-remount-fs.service</filename> is an
early-boot service that applies mount options listed in
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- to the root file system, the <filename>/usr</filename> file system
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ to the root file system, the <filename>/usr</filename> file system,
and the kernel API file systems. This is required so that the
- mount options of these file systems -- which are pre-mounted by
+ mount options of these file systems — which are pre-mounted by
the kernel, the initial RAM disk, container environments or system
- manager code -- are updated to those listed in
+ manager code — are updated to those listed in
<filename>/etc/fstab</filename>. This service ignores normal file
systems and only changes the root file system (i.e.
<filename>/</filename>), <filename>/usr</filename> and the virtual
@@ -80,8 +83,8 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
index 89ec5f8b19..892ebff7ad 100644
--- a/man/systemd-resolved.service.xml
+++ b/man/systemd-resolved.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-resolved.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-resolved</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-resolved</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-rfkill@.service.xml b/man/systemd-rfkill@.service.xml
index 709b09d818..befe001f29 100644
--- a/man/systemd-rfkill@.service.xml
+++ b/man/systemd-rfkill@.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-rfkill@.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-rfkill</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-rfkill</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-run.xml b/man/systemd-run.xml
index febcdb0262..ddd08e5b51 100644
--- a/man/systemd-run.xml
+++ b/man/systemd-run.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -294,6 +297,18 @@
<command>set-property</command> command.</para> </listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--no-block</option></term>
+
+ <listitem>
+ <para>Do not synchronously wait for the requested operation
+ to finish. If this is not specified, the job will be
+ verified, enqueued and <command>systemd-run</command> will
+ wait until the unit's start-up is completed. By passing this
+ argument, it is only verified and enqueued.</para>
+ </listitem>
+ </varlistentry>
+
<xi:include href="user-system-options.xml" xpointer="user" />
<xi:include href="user-system-options.xml" xpointer="system" />
<xi:include href="user-system-options.xml" xpointer="host" />
@@ -346,11 +361,11 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.
Mon Dec 8 20:44:24 KST 2014
Running as unit run-71.timer.
Will run as unit run-71.service.
-# journalctl -b -u run-73.timer
+# journalctl -b -u run-71.timer
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
Dec 08 20:44:38 container systemd[1]: Starting /bin/touch /tmp/foo.
Dec 08 20:44:38 container systemd[1]: Started /bin/touch /tmp/foo.
-# journalctl -b -u run-73.service
+# journalctl -b -u run-71.service
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
Dec 08 20:44:48 container systemd[1]: Starting /bin/touch /tmp/foo...
Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisting>
diff --git a/man/systemd-shutdownd.service.xml b/man/systemd-shutdownd.service.xml
deleted file mode 100644
index 756949ce55..0000000000
--- a/man/systemd-shutdownd.service.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
--->
-
-<refentry id="systemd-shutdownd.service">
-
- <refentryinfo>
- <title>systemd-shutdownd.service</title>
- <productname>systemd</productname>
-
- <authorgroup>
- <author>
- <contrib>Developer</contrib>
- <firstname>Lennart</firstname>
- <surname>Poettering</surname>
- <email>lennart@poettering.net</email>
- </author>
- </authorgroup>
- </refentryinfo>
-
- <refmeta>
- <refentrytitle>systemd-shutdownd.service</refentrytitle>
- <manvolnum>8</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname>systemd-shutdownd.service</refname>
- <refname>systemd-shutdownd.socket</refname>
- <refname>systemd-shutdownd</refname>
- <refpurpose>Scheduled shutdown service</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
- <para><filename>systemd-shutdownd.service</filename></para>
- <para><filename>systemd-shutdownd.socket</filename></para>
- <para><filename>/usr/lib/systemd/systemd-shutdownd</filename></para>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Description</title>
-
- <para><filename>systemd-shutdownd.service</filename> is a system
- service that implements scheduled shutdowns, as exposed by
- <citerefentry><refentrytitle>shutdown</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
- <filename>systemd-shutdownd.service</filename> is automatically
- activated on request and terminates itself when it is
- unused.</para>
- </refsect1>
-
- <refsect1>
- <title>See Also</title>
- <para>
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>shutdown</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- </para>
- </refsect1>
-
-</refentry>
diff --git a/man/systemd-sleep.conf.xml b/man/systemd-sleep.conf.xml
index 433f2f83a0..c5d26d0649 100644
--- a/man/systemd-sleep.conf.xml
+++ b/man/systemd-sleep.conf.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2013 Zbigniew Jędrzejewski-Szmek
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd-sleep.conf"
@@ -49,10 +52,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/sleep.conf</filename></para>
- <para><filename>/etc/systemd/sleep.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/sleep.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/sleep.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/sleep.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/sleep.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/sleep.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -112,15 +115,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
attempts to suspend or hibernate the machine.</para>
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
<para>The following options can be configured in the
<literal>[Sleep]</literal> section of
- <filename>/etc/systemd/sleep.conf</filename> or a
+ <filename>&pkgsysconfdir;/sleep.conf</filename> or a
<filename>sleep.conf.d</filename> file:</para>
<variablelist class='systemd-directives'>
diff --git a/man/systemd-socket-proxyd.xml b/man/systemd-socket-proxyd.xml
index 1c78b656e1..dc3baefe38 100644
--- a/man/systemd-socket-proxyd.xml
+++ b/man/systemd-socket-proxyd.xml
@@ -1,7 +1,10 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -72,7 +75,7 @@
to a configured server for each client, and then bidirectionally
forwards data between the two.</para>
<para>This utility's behavior is similar to
- <citerefentry><refentrytitle>socat</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+ <citerefentry project='die-net'><refentrytitle>socat</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
The main differences for <command>systemd-socket-proxyd</command>
are support for socket activation with
<literal>Accept=false</literal> and an event-driven
@@ -113,7 +116,7 @@ Requires=nginx.service
After=nginx.service
[Service]
-ExecStart=/usr/lib/systemd/systemd-socket-proxyd /tmp/nginx.sock
+ExecStart=]]>&rootlibexecdir;<![CDATA[/systemd-socket-proxyd /tmp/nginx.sock
PrivateTmp=yes
PrivateNetwork=yes]]></programlisting>
</example>
@@ -156,7 +159,7 @@ After=nginx.service
JoinsNamespaceOf=nginx.service
[Service]
-ExecStart=/usr/lib/systemd/systemd-socket-proxyd 127.0.0.1:8080
+ExecStart=]]>&rootlibexecdir;<![CDATA[/systemd-socket-proxyd 127.0.0.1:8080
PrivateTmp=yes
PrivateNetwork=yes]]></programlisting>
</example>
@@ -165,7 +168,6 @@ PrivateNetwork=yes]]></programlisting>
<programlisting><![CDATA[[...]
server {
listen 8080;
- listen unix:/tmp/nginx.sock;
[...]]]></programlisting>
</example>
<example>
@@ -183,9 +185,9 @@ $ curl http://localhost:80/]]></programlisting>
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>socat</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>nginx</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>curl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>socat</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>nginx</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>curl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
diff --git a/man/systemd-suspend.service.xml b/man/systemd-suspend.service.xml
index a8beb86f4d..2722d1840a 100644
--- a/man/systemd-suspend.service.xml
+++ b/man/systemd-suspend.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -56,7 +59,7 @@
<para><filename>systemd-suspend.service</filename></para>
<para><filename>systemd-hibernate.service</filename></para>
<para><filename>systemd-hybrid-sleep.service</filename></para>
- <para><filename>/usr/lib/systemd/system-sleep</filename></para>
+ <para><filename>&rootlibexecdir;/system-sleep</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -75,7 +78,7 @@
<para>Immediately before entering system suspend and/or
hibernation <filename>systemd-suspend.service</filename> (and the
other mentioned units, respectively) will run all executables in
- <filename>/usr/lib/systemd/system-sleep/</filename> and pass two
+ <filename>&rootlibexecdir;/system-sleep/</filename> and pass two
arguments to them. The first argument will be
<literal>pre</literal>, the second either
<literal>suspend</literal>, <literal>hibernate</literal>, or
@@ -87,7 +90,7 @@
until all executables have finished.</para>
<para>Note that scripts or binaries dropped in
- <filename>/usr/lib/systemd/system-sleep/</filename> are intended
+ <filename>&rootlibexecdir;/system-sleep/</filename> are intended
for local use only and should be considered hacks. If applications
want to be notified of system suspend/hibernation and resume,
there are much nicer interfaces available.</para>
@@ -104,7 +107,7 @@
<literal>mem</literal> into <filename>/sys/power/state</filename>,
to trigger the actual system suspend. What exactly is written
where can be configured in the <literal>[Sleep]</literal> section
- of <filename>/etc/systemd/sleep.conf</filename> or a
+ of <filename>&pkgsysconfdir;/sleep.conf</filename> or a
<filename>sleep.conf.d</filename> file. See
<citerefentry><refentrytitle>systemd-sleep.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml
index f35a18a4d4..f7da4cd71a 100644
--- a/man/systemd-sysctl.service.xml
+++ b/man/systemd-sysctl.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-sysctl.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-sysctl</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-sysctl</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -56,11 +59,11 @@
<para><filename>systemd-sysctl.service</filename> is an early-boot
service that configures
- <citerefentry><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
kernel parameters.</para>
<para>See
- <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for information about the configuration of this service.</para>
</refsect1>
@@ -68,8 +71,8 @@
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
</para>
</refsect1>
diff --git a/man/systemd-system-update-generator.xml b/man/systemd-system-update-generator.xml
index 3eec1d7b93..5c593b3906 100644
--- a/man/systemd-system-update-generator.xml
+++ b/man/systemd-system-update-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -46,7 +49,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-system-update-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-system-update-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -61,10 +64,8 @@
Updates Specification</ulink>.
</para>
- <para><filename>systemd-system-update-generator</filename>
- implements the
- <ulink url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <para><filename>systemd-system-update-generator</filename> implements
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 7c3f237567..5aa5da4706 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -51,14 +54,14 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/system.conf</filename></para>
- <para><filename>/etc/systemd/system.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/system.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/system.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/system.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
- <para><filename>/etc/systemd/user.conf</filename></para>
- <para><filename>/etc/systemd/user.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/system.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/user.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/user.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/user.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/user.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -74,8 +77,7 @@
operations.</para>
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
@@ -173,7 +175,7 @@
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details. Takes a whitespace-separated list of capability
names as read by
- <citerefentry><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='mankier'><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
Capabilities listed will be included in the bounding set, all
others are removed. If the list of capabilities is prefixed
with ~, all but the listed capabilities will be included, the
@@ -261,7 +263,11 @@
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-unit settings). For non-service units,
<varname>DefaultTimeoutStartSec=</varname> sets the default
- <varname>TimeoutSec=</varname> value. </para></listitem>
+ <varname>TimeoutSec=</varname>
+ value. <varname>DefaultTimeoutStartSec=</varname> and
+ <varname>DefaultTimeoutStopSec=</varname> default to
+ 90s. <varname>DefaultRestartSec=</varname> defaults to
+ 100ms.</para></listitem>
</varlistentry>
<varlistentry>
@@ -273,7 +279,10 @@
<varname>StartLimitInterval=</varname> and
<varname>StartLimitBurst=</varname>. See
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details on the per-service settings.</para></listitem>
+ for details on the per-service settings.
+ <varname>DefaultStartLimitInterval=</varname> defaults to
+ 10s. <varname>DefaultStartLimitBurst=</varname> defaults to
+ 5.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd-sysusers.xml b/man/systemd-sysusers.xml
index a0c0f996ac..cbe4f2f9cb 100644
--- a/man/systemd-sysusers.xml
+++ b/man/systemd-sysusers.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-sysv-generator.xml b/man/systemd-sysv-generator.xml
index e619b1bc2e..e7592d6692 100644
--- a/man/systemd-sysv-generator.xml
+++ b/man/systemd-sysv-generator.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -46,7 +49,7 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/systemd/system-generators/systemd-sysv-generator</filename></para>
+ <para><filename>&rootlibexecdir;/system-generators/systemd-sysv-generator</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -81,10 +84,8 @@
part of early boot, so all wrapper units are ordered after
<filename>basic.target</filename>.</para>
- <para><filename>systemd-sysv-generator</filename>
- implements the <ulink
- url="http://www.freedesktop.org/wiki/Software/systemd/Generators">generator
- specification</ulink>.</para>
+ <para><filename>systemd-sysv-generator</filename> implements
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd-timedated.service.xml b/man/systemd-timedated.service.xml
index e44163aefb..3598490d14 100644
--- a/man/systemd-timedated.service.xml
+++ b/man/systemd-timedated.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-timedated.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-timedated</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-timedated</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-timesyncd.service.xml b/man/systemd-timesyncd.service.xml
index ac1af2d136..a1b364534b 100644
--- a/man/systemd-timesyncd.service.xml
+++ b/man/systemd-timesyncd.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -50,7 +53,7 @@
<refsynopsisdiv>
<para><filename>systemd-timesyncd.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-timesyncd</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-timesyncd</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
index ceec06f840..f12f997f93 100644
--- a/man/systemd-tmpfiles.xml
+++ b/man/systemd-tmpfiles.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-tty-ask-password-agent.xml b/man/systemd-tty-ask-password-agent.xml
index 2876fab644..dac3a3c02c 100644
--- a/man/systemd-tty-ask-password-agent.xml
+++ b/man/systemd-tty-ask-password-agent.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd-udevd.service.xml b/man/systemd-udevd.service.xml
index b18b22871f..c0d323033c 100644
--- a/man/systemd-udevd.service.xml
+++ b/man/systemd-udevd.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refentry id="systemd-udevd.service"
xmlns:xi="http://www.w3.org/2001/XInclude">
@@ -37,7 +40,7 @@
<para><filename>systemd-udevd-kernel.socket</filename></para>
<cmdsynopsis>
- <command>/usr/lib/systemd/systemd-udevd</command>
+ <command>&rootlibexecdir;/systemd-udevd</command>
<arg><option>--daemon</option></arg>
<arg><option>--debug</option></arg>
<arg><option>--children-max=</option></arg>
diff --git a/man/systemd-update-done.service.xml b/man/systemd-update-done.service.xml
index d65f175418..3f121582e9 100644
--- a/man/systemd-update-done.service.xml
+++ b/man/systemd-update-done.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-update-done.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-update-done</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-update-done</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/man/systemd-update-utmp.service.xml b/man/systemd-update-utmp.service.xml
index b842d29721..285691849f 100644
--- a/man/systemd-update-utmp.service.xml
+++ b/man/systemd-update-utmp.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -51,7 +54,7 @@
<refsynopsisdiv>
<para><filename>systemd-update-utmp.service</filename></para>
<para><filename>systemd-update-utmp-runlevel.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-update-utmp</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-update-utmp</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -69,7 +72,7 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>utmp</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>auditd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>auditd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd-user-sessions.service.xml b/man/systemd-user-sessions.service.xml
index 9d796b1ae1..620648cfe8 100644
--- a/man/systemd-user-sessions.service.xml
+++ b/man/systemd-user-sessions.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,20 +51,19 @@
<refsynopsisdiv>
<para><filename>systemd-user-sessions.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-user-sessions</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-user-sessions</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><filename>systemd-user-sessions.service</filename> is a
- service that controls user logins. After basic system
- initialization is complete it removes
+ service that controls user logins through
+ <citerefentry project='man-pages'><refentrytitle>pam_nologin</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+ After basic system initialization is complete it removes
<filename>/run/nologin</filename>, thus permitting logins. Before
system shutdown it creates <filename>/run/nologin</filename>, thus
- prohibiting further logins. At the same time it also kills all
- user processes, so that system shutdown may proceed without any
- remaining user processes around.</para>
+ prohibiting further logins.</para>
</refsect1>
<refsect1>
diff --git a/man/systemd-vconsole-setup.service.xml b/man/systemd-vconsole-setup.service.xml
index 59bb5e4e8c..6c6d8e2af0 100644
--- a/man/systemd-vconsole-setup.service.xml
+++ b/man/systemd-vconsole-setup.service.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -48,7 +51,7 @@
<refsynopsisdiv>
<para><filename>systemd-vconsole-setup.service</filename></para>
- <para><filename>/usr/lib/systemd/systemd-vconsole-setup</filename></para>
+ <para><filename>&rootlibexecdir;/systemd-vconsole-setup</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -57,9 +60,9 @@
<para><filename>systemd-vconsole-setup.service</filename> is an
early-boot service that configures the virtual console font and
console keymap. Internally it calls
- <citerefentry><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>
and
- <citerefentry><refentrytitle>setfont</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+ <citerefentry project='die-net'><refentrytitle>setfont</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para>See
<citerefentry><refentrytitle>vconsole.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
@@ -105,8 +108,8 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>vconsole.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>setfont</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>setfont</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml
index 3db65d988d..18c10d00f5 100644
--- a/man/systemd.automount.xml
+++ b/man/systemd.automount.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -96,7 +99,7 @@
<para>Automount units may either be configured via unit files, or
via <filename>/etc/fstab</filename> (see
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details).</para>
<para>For details how systemd parses
@@ -135,6 +138,14 @@
creating these directories. Takes an access mode in octal
notation. Defaults to 0755.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>TimeoutIdleSec=</varname></term>
+ <listitem><para>Configures an idleness timeout. Once the mount has been
+ idle for the specified time, systemd will attempt to unmount. Takes a
+ unit-less value in seconds, or a time span value such as "5min 20s".
+ Pass 0 to disable the timeout logic. The timeout is disabled by
+ default.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -145,8 +156,8 @@
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>automount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>automount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd.device.xml b/man/systemd.device.xml
index ac6deafb18..96a20d14d1 100644
--- a/man/systemd.device.xml
+++ b/man/systemd.device.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 11b160e58f..ea53722f0f 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1,5 +1,8 @@
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -283,7 +286,9 @@
shortly before the process is executed (more specifically,
after all processes from a previous unit state terminated.
This means you can generate these files in one unit state, and
- read it with this option in the next). Settings from these
+ read it with this option in the next).</para>
+
+ <para>Settings from these
files override settings made with
<varname>Environment=</varname>. If the same variable is set
twice from these files, the files will be read in the order
@@ -334,7 +339,7 @@
service was activated from, which is primarily useful for
compatibility with daemons designed for use with the
traditional
- <citerefentry><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
daemon.</para>
<para>This setting defaults to
@@ -661,7 +666,7 @@
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details. Takes a whitespace-separated list of capability
names as read by
- <citerefentry><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry project='mankier'><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
e.g. <constant>CAP_SYS_ADMIN</constant>,
<constant>CAP_DAC_OVERRIDE</constant>,
<constant>CAP_SYS_PTRACE</constant>. Capabilities listed will
@@ -709,7 +714,7 @@
set for the executed process. Take a capability string
describing the effective, permitted and inherited capability
sets as documented in
- <citerefentry><refentrytitle>cap_from_text</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='mankier'><refentrytitle>cap_from_text</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
Note that these capability sets are usually influenced (and
filtered) by the capabilities attached to the executed file.
Due to that <varname>CapabilityBoundingSet=</varname> is
@@ -879,7 +884,7 @@
<option>private</option>, which control whether mounts in the
file system namespace set up for this unit's processes will
receive or propagate mounts or unmounts. See
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>2</manvolnum></citerefentry>
for details. Defaults to <option>shared</option>. Use
<option>shared</option> to ensure that mounts and unmounts are
propagated from the host to the container and vice versa. Use
@@ -927,7 +932,7 @@
authorize the transition. This directive is ignored if SELinux
is disabled. If prefixed by <literal>-</literal>, all errors
will be ignored. See
- <citerefentry><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
@@ -1074,7 +1079,7 @@
prefixed with <constant>~</constant> the listed address
families will be applied as blacklist, otherwise as whitelist.
Note that this restricts access to the
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call only. Sockets passed into the process by other
means (for example, by using socket activation with socket
units, see
@@ -1102,7 +1107,7 @@
<term><varname>Personality=</varname></term>
<listitem><para>Controls which kernel architecture
- <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
shall report, when invoked by unit processes. Takes one of
<constant>x86</constant> and <constant>x86-64</constant>. This
is useful when running 32-bit services on a 64-bit host
@@ -1164,7 +1169,7 @@
<term><varname>$LANG</varname></term>
<listitem><para>Locale. Can be set in
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
or on the kernel command line (see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
and
@@ -1182,7 +1187,7 @@
login shell. The variables are set for the units that have
<varname>User=</varname> set, which includes user
<command>systemd</command> instances. See
- <citerefentry><refentrytitle>passwd</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ <citerefentry project='die-net'><refentrytitle>passwd</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml
index ccb698752a..5ce0592a6e 100644
--- a/man/systemd.generator.xml
+++ b/man/systemd.generator.xml
@@ -59,14 +59,14 @@
<para>
<literallayout><filename>/run/systemd/system-generators/*</filename>
-<filename>/etc/systemd/system-generators/*</filename>
+<filename>&pkgsysconfdir;/system-generators/*</filename>
<filename>/usr/local/lib/systemd/system-generators/*</filename>
<filename>&systemgeneratordir;/*</filename></literallayout>
</para>
<para>
<literallayout><filename>/run/systemd/user-generators/*</filename>
-<filename>/etc/systemd/user-generators/*</filename>
+<filename>&pkgsysconfdir;/user-generators/*</filename>
<filename>/usr/local/lib/systemd/user-generators/*</filename>
<filename>&usergeneratordir;/*</filename></literallayout>
</para>
@@ -140,7 +140,7 @@
<listitem>
<para><parameter>late-dir</parameter></para>
<para>argv[3] may be used to extend the unit file tree without
- overridding any other unit files. Any native configuration
+ overriding any other unit files. Any native configuration
files supplied by the vendor or user/administrator take
precedence over the generated ones placed in this directory.
</para>
@@ -333,7 +333,7 @@ find $dir</programlisting>
<citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-efi-boot-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-getty-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
diff --git a/man/systemd.journal-fields.xml b/man/systemd.journal-fields.xml
index 1fd46de31f..2cb010c0be 100644
--- a/man/systemd.journal-fields.xml
+++ b/man/systemd.journal-fields.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -134,7 +137,7 @@
derived from glibc's
<varname>program_invocation_short_name</varname> variable,
see
- <citerefentry><refentrytitle>program_invocation_short_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.)</para>
+ <citerefentry project='die-net'><refentrytitle>program_invocation_short_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.)</para>
</listitem>
</varlistentry>
@@ -390,7 +393,7 @@
</varlistentry>
</variablelist>
- <para>Priviledged programs (currently UID 0) may attach
+ <para>Privileged programs (currently UID 0) may attach
<varname>OBJECT_PID=</varname> to a message. This will instruct
<command>systemd-journald</command> to attach additional fields on
behalf of the caller:</para>
diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml
index c974e22489..ef828e081c 100644
--- a/man/systemd.kill.xml
+++ b/man/systemd.kill.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -135,7 +138,7 @@
of shutting down a unit (see above), and is usually followed
by <constant>SIGKILL</constant> (see above and below). For a
list of valid signals, see
- <citerefentry><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
Defaults to <constant>SIGTERM</constant>. </para></listitem>
</varlistentry>
@@ -176,7 +179,7 @@
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 3fac760b01..5db06842bd 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -56,21 +59,21 @@
<command>net_setup_link</command> udev builtin.</para>
<para>The link files are read from the files located in the system
- network directory <filename>/usr/lib/systemd/network</filename>,
+ network directory <filename>&rootlibexecdir;/network</filename>,
the volatile runtime network directory
<filename>/run/systemd/network</filename>, and the local
administration network directory
- <filename>/etc/systemd/network</filename>. Link files must have
+ <filename>&pkgsysconfdir;/network</filename>. Link files must have
the extension <filename>.link</filename>; other extensions are
ignored. All link files are collectively sorted and processed in
lexical order, regardless of the directories in which they live.
However, files with identical filenames replace each other. Files
in <filename>/etc</filename> have the highest priority, files in
<filename>/run</filename> take precedence over files with the same
- name in <filename>/usr/lib</filename>. This can be used to
+ name in <filename>&rootprefix;/lib</filename>. This can be used to
override a system-supplied link file with a local file if needed;
a symlink in <filename>/etc</filename> with the same name as a
- link file in <filename>/usr/lib</filename>, pointing to
+ link file in <filename>&rootprefix;/lib</filename>, pointing to
<filename>/dev/null</filename>, disables the link file
entirely.</para>
@@ -382,7 +385,7 @@
<refsect1>
<title>Example</title>
<example>
- <title>/etc/systemd/network/wireless.link</title>
+ <title>&pkgsysconfdir;/network/wireless.link</title>
<programlisting>[Match]
MACAddress=12:34:56:78:9a:bc
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index 5cbde8b84c..f22c86adc1 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -68,7 +71,7 @@
<para>Additional options are listed in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which define the execution environment the
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
binary is executed in, and in
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which define the way the processes are terminated, and in
@@ -78,7 +81,7 @@
particularly useful for mount units specifying a
<literal>Type=</literal> option or using configuration not
specified in <filename>/etc/fstab</filename>;
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
will refuse options that are not listed in
<filename>/etc/fstab</filename> if it is not run as UID 0.</para>
@@ -106,7 +109,7 @@
</para>
<para>Some file systems have special semantics as API file systems
- for kernel-to-userspace and userspace-to-userpace interfaces. Some
+ for kernel-to-userspace and userspace-to-userspace interfaces. Some
of them may not be changed via mount units, and cannot be
disabled. For a longer discussion see <ulink
url="http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems">API
@@ -118,7 +121,7 @@
<para>Mount units may either be configured via unit files, or via
<filename>/etc/fstab</filename> (see
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details). Mounts listed in <filename>/etc/fstab</filename>
will be converted into native units dynamically at boot and when
the configuration of the system manager is reloaded. In general,
@@ -139,6 +142,36 @@
<variablelist class='fstab-options'>
<varlistentry>
+ <term><option>x-systemd.requires=</option></term>
+
+ <listitem><para>Configures a <varname>Requires=</varname> and
+ an <varname>After=</varname> dependency between the created
+ mount unit and another systemd unit, such as a device or mount
+ unit. The argument should be a unit name, or an absolute path
+ to a device node or mount point. This option may be specified
+ more than once. This option is particularly useful for mount
+ point declarations that need an additional device to be around
+ (such as an external journal device for journal file systems)
+ or an additional mount to be in place (such as an overlay file
+ system that merges multiple mount points). See
+ <varname>After=</varname> and <varname>Requires=</varname> in
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>x-systemd.requires-mounts-for=</option></term>
+
+ <listitem><para>Configures a
+ <varname>RequiresMountsFor=</varname> dependency between the
+ created mount unit and other mount units. The argument must be
+ an absolute path. This option may be specified more than once.
+ See <varname>RequiresMountsFor=</varname> in
+ <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>x-systemd.automount</option></term>
<listitem><para>An automount unit will be created for the file
@@ -148,6 +181,15 @@
</varlistentry>
<varlistentry>
+ <term><option>x-systemd.idle-timeout=</option></term>
+
+ <listitem><para>Configures the idleness timeout of the
+ automount unit. See <varname>TimeoutIdleSec=</varname> in
+ <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>x-systemd.device-timeout=</option></term>
<listitem><para>Configure how long systemd should wait for a
@@ -231,7 +273,7 @@
<term><varname>What=</varname></term>
<listitem><para>Takes an absolute path of a device node, file
or other resource to mount. See
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details. If this refers to a device node, a dependency on
the respective device unit is automatically created. (See
<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
@@ -251,7 +293,7 @@
<varlistentry>
<term><varname>Type=</varname></term>
<listitem><para>Takes a string for the file system type. See
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details. This setting is optional.</para></listitem>
</varlistentry>
@@ -270,7 +312,7 @@
the options specified in <varname>Options=</varname> is
relaxed, and unknown mount options are tolerated. This
corresponds with
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
<parameter>-s</parameter> switch. Defaults to
off.</para></listitem>
</varlistentry>
@@ -321,7 +363,7 @@
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 4480e1999d..786c7d478a 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -68,20 +71,20 @@
<para>The <filename>.netdev</filename> files are read from the
files located in the system network directory
- <filename>/usr/lib/systemd/network</filename>, the volatile
+ <filename>&rootlibexecdir;/network</filename>, the volatile
runtime network directory
<filename>/run/systemd/network</filename> and the local
administration network directory
- <filename>/etc/systemd/network</filename>. All configuration files
+ <filename>&pkgsysconfdir;/network</filename>. All configuration files
are collectively sorted and processed in lexical order, regardless
of the directories in which they live. However, files with
identical filenames replace each other. Files in
<filename>/etc</filename> have the highest priority, files in
<filename>/run</filename> take precedence over files with the same
- name in <filename>/usr/lib</filename>. This can be used to
+ name in <filename>&rootprefix;/lib</filename>. This can be used to
override a system-supplied configuration file with a local file if
needed; a symlink in <filename>/etc</filename> with the same name
- as a configuration file in <filename>/usr/lib</filename>, pointing
+ as a configuration file in <filename>&rootprefix;/lib</filename>, pointing
to <filename>/dev/null</filename>, disables the configuration file
entirely.</para>
@@ -108,7 +111,7 @@
<entry>A bond device is an aggregation of all its slave devices. See <ulink url="https://www.kernel.org/doc/Documentation/networking/bonding.txt">Linux Ethernet Bonding Driver HOWTO</ulink> for details.Local configuration</entry></row>
<row><entry><varname>bridge</varname></entry>
- <entry>A bridge devcie is a software switch, each of its slave devices and the bridge itself are ports of the switch.</entry></row>
+ <entry>A bridge device is a software switch, each of its slave devices and the bridge itself are ports of the switch.</entry></row>
<row><entry><varname>dummy</varname></entry>
<entry>A dummy device drops all packets sent to it.</entry></row>
@@ -155,6 +158,9 @@
<row><entry><varname>vti</varname></entry>
<entry>An IPv4 over IPSec tunnel.</entry></row>
+ <row><entry><varname>vti6</varname></entry>
+ <entry>An IPv6 over IPSec tunnel.</entry></row>
+
<row><entry><varname>vxlan</varname></entry>
<entry>A virtual extensible LAN (vxlan), for connecting Cloud computing deployments.</entry></row>
</tbody>
@@ -253,7 +259,7 @@
<para>The maximum transmission unit in bytes to set for
the device. The usual suffixes K, M, G, are supported and
are understood to the base of 1024. This key is not
- currently suported for <literal>tun</literal> or
+ currently supported for <literal>tun</literal> or
<literal>tap</literal> devices.
</para>
</listitem>
@@ -265,7 +271,7 @@
given, one is generated based on the interface name and
the
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
- This key is not currently suported for
+ This key is not currently supported for
<literal>tun</literal> or <literal>tap</literal> devices.
</para>
</listitem>
@@ -410,6 +416,24 @@
on.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>UDPCheckSum=</varname></term>
+ <listitem>
+ <para>A boolean. When true transmitting UDP checksums when doing VXLAN/IPv4 is turned on.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>UDP6ZeroChecksumTx=</varname></term>
+ <listitem>
+ <para>A boolean. When true sending zero checksums in VXLAN/IPv6 is turned on.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>UDP6ZeroCheckSumRx=</varname></term>
+ <listitem>
+ <para>A boolean. When true receiving zero checksums in VXLAN/IPv6 is turned on.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<refsect1>
@@ -423,7 +447,8 @@
<literal>gretap</literal>,
<literal>ip6gre</literal>,
<literal>ip6gretap</literal>,
- <literal>vti</literal>, and
+ <literal>vti</literal>,
+ <literal>vti6</literal>, and
<literal>ip6tnl</literal> and accepts
the following keys:</para>
@@ -534,7 +559,7 @@
<varlistentry>
<term><varname>PacketInfo=</varname></term>
<listitem><para>Takes a boolean argument. Configures whether
- packets should be prepened with four extra bytes (two flag
+ packets should be prepended with four extra bytes (two flag
bytes and two protocol bytes). If disabled it indicates that
the packets will be pure IP packets. Defaults to
<literal>no</literal>.</para>
@@ -647,13 +672,180 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>LearnPacketIntervalSec=</varname></term>
+ <listitem>
+ <para>Specifies the number of seconds between instances where the bonding
+ driver sends learning packets to each slaves peer switch.
+ The valid range is 1 - 0x7fffffff; the default value is 1. This Option
+ has effect only in balance-tlb and balance-alb modes.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>AdSelect=</varname></term>
+ <listitem>
+ <para>Specifies the 802.3ad aggregation selection logic to use. Possible values are
+ <literal>stable</literal>,
+ <literal>bandwidth</literal>,
+ <literal>count</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>FailOverMACPolicy=</varname></term>
+ <listitem>
+ <para>Specifies whether active-backup mode should set all slaves to
+ the same MAC address at enslavement or, when enabled, perform special handling of the
+ bond's MAC address in accordance with the selected policy. The default policy is none.
+ Possible values are
+ <literal>none</literal>,
+ <literal>active</literal>,
+ <literal>follow</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ARPValidate=</varname></term>
+ <listitem>
+ <para>Specifies whether or not ARP probes and replies should be
+ validated in any mode that supports ARP monitoring, or whether
+ non-ARP traffic should be filtered (disregarded) for link
+ monitoring purposes. Possible values are
+ <literal>none</literal>,
+ <literal>active</literal>,
+ <literal>backup</literal>,
+ <literal>all</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ARPIntervalSec=</varname></term>
+ <listitem>
+ <para>Specifies the ARP link monitoring frequency in milliseconds.
+ A value of 0 disables ARP monitoring. The default value is 0.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ARPIPTargets=</varname></term>
+ <listitem>
+ <para>Specifies the IP addresses to use as ARP monitoring peers when
+ ARPIntervalSec is greater than 0. These are the targets of the ARP request
+ sent to determine the health of the link to the targets.
+ Specify these values in ipv4 dotted decimal format. At least one IP
+ address must be given for ARP monitoring to function. The
+ maximum number of targets that can be specified is 16. The
+ default value is no IP addresses.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ARPAllTargets=</varname></term>
+ <listitem>
+ <para>Specifies the quantity of ARPIPTargets that must be reachable
+ in order for the ARP monitor to consider a slave as being up.
+ This option affects only active-backup mode for slaves with
+ ARPValidate enabled. Possible values are
+ <literal>any</literal>,
+ <literal>all</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>PrimaryReselectPolicy=</varname></term>
+ <listitem>
+ <para>Specifies the reselection policy for the primary slave. This
+ affects how the primary slave is chosen to become the active slave
+ when failure of the active slave or recovery of the primary slave
+ occurs. This option is designed to prevent flip-flopping between
+ the primary slave and other slaves. Possible values are
+ <literal>always</literal>,
+ <literal>better</literal>,
+ <literal>failure</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>ResendIGMP=</varname></term>
+ <listitem>
+ <para>Specifies the number of IGMP membership reports to be issued after
+ a failover event. One membership report is issued immediately after
+ the failover, subsequent packets are sent in each 200ms interval.
+ The valid range is (0 - 255). Defaults to 1. A value of 0
+ prevents the IGMP membership report from being issued in response
+ to the failover event.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>PacketsPerSlave=</varname></term>
+ <listitem>
+ <para> Specify the number of packets to transmit through a slave before
+ moving to the next one. When set to 0 then a slave is chosen at
+ random.The valid range is (0 - 65535). Defaults to 1. This option
+ has effect only in balance-rr mode.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>GratuitousARP=</varname></term>
+ <listitem>
+ <para>Specify the number of peer notifications (gratuitous ARPs and
+ unsolicited IPv6 Neighbor Advertisements) to be issued after a
+ failover event. As soon as the link is up on the new slave
+ a peer notification is sent on the bonding device and each
+ VLAN sub-device. This is repeated at each link monitor interval
+ (ARPIntervalSec or MIIMonitorSec, whichever is active) if the number is
+ greater than 1. The valid range is (0 - 255). Default value is 1.
+ These options affect only the active-backup mode.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>AllSlavesActive=</varname></term>
+ <listitem>
+ <para> A boolean. Specifies that duplicate frames (received on inactive ports)
+ should be dropped false or delivered true. Normally, bonding will drop
+ duplicate frames (received on inactive ports), which is desirable for
+ most users. But there are some times it is nice to allow duplicate
+ frames to be delivered. The default value is false (drop duplicate frames
+ received on inactive ports).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>MinLinks=</varname></term>
+ <listitem>
+ <para>Specifies the minimum number of links that must be active before
+ asserting carrier. The default value is 0.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
+
+ <para>For more detail information see
+ <ulink url="https://www.kernel.org/doc/Documentation/networking/bonding.txt">
+ Linux Ethernet Bonding Driver HOWTO</ulink></para>
+
</refsect1>
<refsect1>
<title>Example</title>
<example>
- <title>/etc/systemd/network/bridge.netdev</title>
+ <title>&pkgsysconfdir;/network/bridge.netdev</title>
<programlisting>[NetDev]
Name=bridge0
@@ -661,7 +853,7 @@ Kind=bridge</programlisting>
</example>
<example>
- <title>/etc/systemd/network/vlan1.netdev</title>
+ <title>&pkgsysconfdir;/network/vlan1.netdev</title>
<programlisting>[Match]
Virtualization=no
@@ -674,7 +866,7 @@ Kind=vlan
Id=1</programlisting>
</example>
<example>
- <title>/etc/systemd/network/ipip.netdev</title>
+ <title>&pkgsysconfdir;/network/ipip.netdev</title>
<programlisting>[NetDev]
Name=ipip-tun
Kind=ipip
@@ -686,7 +878,7 @@ Remote=192.169.224.239
TTL=64</programlisting>
</example>
<example>
- <title>/etc/systemd/network/tap.netdev</title>
+ <title>&pkgsysconfdir;/network/tap.netdev</title>
<programlisting>[NetDev]
Name=tap-test
Kind=tap
@@ -696,7 +888,7 @@ MultiQueue=true
PacketInfo=true</programlisting> </example>
<example>
- <title>/etc/systemd/network/sit.netdev</title>
+ <title>&pkgsysconfdir;/network/sit.netdev</title>
<programlisting>[NetDev]
Name=sit-tun
Kind=sit
@@ -708,7 +900,7 @@ Remote=10.65.223.239</programlisting>
</example>
<example>
- <title>/etc/systemd/network/gre.netdev</title>
+ <title>&pkgsysconfdir;/network/gre.netdev</title>
<programlisting>[NetDev]
Name=gre-tun
Kind=gre
@@ -720,7 +912,7 @@ Remote=10.65.223.239</programlisting>
</example>
<example>
- <title>/etc/systemd/network/vti.netdev</title>
+ <title>&pkgsysconfdir;/network/vti.netdev</title>
<programlisting>[NetDev]
Name=vti-tun
@@ -733,7 +925,7 @@ Remote=10.65.223.239</programlisting>
</example>
<example>
- <title>/etc/systemd/network/veth.netdev</title>
+ <title>&pkgsysconfdir;/network/veth.netdev</title>
<programlisting>[NetDev]
Name=veth-test
Kind=veth
@@ -743,7 +935,7 @@ Name=veth-peer</programlisting>
</example>
<example>
- <title>/etc/systemd/network/dummy.netdev</title>
+ <title>&pkgsysconfdir;/network/dummy.netdev</title>
<programlisting>[NetDev]
Name=dummy-test
Kind=dummy
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 485876b6ac..54fef4c9c4 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -64,20 +67,20 @@
<para>The <filename>.network</filename> files are read from the
files located in the system network directory
- <filename>/usr/lib/systemd/network</filename>, the volatile
+ <filename>&rootlibexecdir;/network</filename>, the volatile
runtime network directory
<filename>/run/systemd/network</filename> and the local
administration network directory
- <filename>/etc/systemd/network</filename>. All configuration files
+ <filename>&pkgsysconfdir;/network</filename>. All configuration files
are collectively sorted and processed in lexical order, regardless
of the directories in which they live. However, files with
identical filenames replace each other. Files in
<filename>/etc</filename> have the highest priority, files in
<filename>/run</filename> take precedence over files with the same
- name in <filename>/usr/lib</filename>. This can be used to
+ name in <filename>&rootprefix;/lib</filename>. This can be used to
override a system-supplied configuration file with a local file if
needed; a symlink in <filename>/etc</filename> with the same name
- as a configuration file in <filename>/usr/lib</filename>, pointing
+ as a configuration file in <filename>&rootprefix;/lib</filename>, pointing
to <filename>/dev/null</filename>, disables the configuration file
entirely.</para>
@@ -91,7 +94,8 @@
to a given device; and a <literal>[Network]</literal> section
specifying how the device should be configured. The first (in
lexical order) of the network files that matches a given device
- is applied.</para>
+ is applied, all later files are ignored, even if they match as
+ well.</para>
<para>A network file is said to match a device if each of the
entries in the <literal>[Match]</literal> section matches, or if
@@ -227,6 +231,10 @@
<para>Enables DHCPv4 and/or DHCPv6 support. Accepts
<literal>yes</literal>, <literal>no</literal>,
<literal>ipv4</literal>, or <literal>ipv6</literal>.</para>
+
+ <para>Please note that by default the domain name
+ specified through DHCP is not used for name resolution.
+ See option <option>UseDomains=</option> below.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -280,13 +288,24 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>BindCarrier=</varname></term>
+ <listitem>
+ <para>A port or a list of ports. When set, controls the
+ behaviour of the current interface. When all ports in the list
+ are in an operational down state, the current interface is brought
+ down. When at least one port has carrier, the current interface
+ is brought up.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Address=</varname></term>
<listitem>
<para>A static IPv4 or IPv6 address and its prefix length,
separated by a <literal>/</literal> character. Specify
this key more than once to configure several addresses.
The format of the address must be as described in
- <citerefentry><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This is a short-hand for an [Address] section only
containing an Address key (see below). This option may be
specified more than once.
@@ -312,7 +331,7 @@
<listitem>
<para>The gateway address, which must be in the format
described in
- <citerefentry><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This is a short-hand for a [Route] section only containing
a Gateway key. This option may be specified more than
once.</para>
@@ -323,7 +342,7 @@
<listitem>
<para>A DNS server address, which must be in the format
described in
- <citerefentry><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This option may be specified more than once.</para>
</listitem>
</varlistentry>
@@ -347,7 +366,23 @@
the routing table. Takes either a boolean argument, or the
values <literal>ipv4</literal> or <literal>ipv6</literal>,
which only enables IP forwarding for the specified address
- family.</para></listitem>
+ family, or <literal>kernel</literal>, which preserves existing sysctl settings.
+ This controls the
+ <filename>net.ipv4.conf.&lt;interface&gt;.forwarding</filename>
+ and
+ <filename>net.ipv6.conf.&lt;interface&gt;.forwarding</filename>
+ sysctl options of the network interface (see <ulink
+ url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink>
+ for details about sysctl options). Defaults to
+ <literal>no</literal>.</para>
+
+ <para>Note: unless this option is turned on, or set to <literal>kernel</literal>,
+ no IP forwarding is done on this interface, even if this is
+ globally turned on in the kernel, with the
+ <filename>net.ipv4.ip_forward</filename> and
+ <filename>net.ipv4.ip_forward</filename> sysctl
+ options.</para>
+ </listitem>
</varlistentry>
<varlistentry>
<term><varname>IPMasquerade=</varname></term>
@@ -355,7 +390,8 @@
interface. If enabled packets forwarded from the network
interface will be appear as coming from the local host.
Takes a boolean argument. Implies
- <varname>IPForward=yes</varname>.</para></listitem>
+ <varname>IPForward=ipv4</varname>. Defaults to
+ <literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>Bridge=</varname></term>
@@ -429,7 +465,7 @@
<listitem>
<para>The broadcast address, which must be in the format
described in
- <citerefentry><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This key only applies to IPv4 addresses. If it is not
given, it is derived from the <literal>Address</literal>
key.</para>
@@ -501,6 +537,17 @@
<para>When true (the default), the DNS servers received
from the DHCP server will be used and take precedence over
any statically configured ones.</para>
+
+ <para>This corresponds to the <option>nameserver</option>
+ option in <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>UseNTP=</varname></term>
+ <listitem>
+ <para>When true (the default), the NTP servers received
+ from the DHCP server will be used by systemd-timesyncd
+ and take precedence over any statically configured ones.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -531,7 +578,13 @@
<listitem>
<para>When true (not the default), the domain name
received from the DHCP server will be used for DNS
- resolution over this link.</para>
+ resolution over this link. When a name cannot be resolved
+ as specified, the domain name will be used a suffix and
+ name resolution of that will be attempted.</para>
+
+ <para>This corresponds to the <option>domain</option>
+ option in <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ and should not be enabled on untrusted networks.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -553,6 +606,14 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>ClientIdentifier=</varname></term>
+ <listitem>
+ <para>DHCP client identifier to use. Either <literal>mac</literal>
+ to use the MAC address of the link or <literal>duid</literal>
+ (the default) to use a RFC4361-compliant Client ID.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>VendorClassIdentifier=</varname></term>
<listitem>
<para>The vendor class identifier used to identify vendor
@@ -626,7 +687,7 @@
<refsect1>
<title>Example</title>
<example>
- <title>/etc/systemd/network/50-static.network</title>
+ <title>&pkgsysconfdir;/network/50-static.network</title>
<programlisting>[Match]
Name=enp2s0
@@ -637,17 +698,17 @@ Gateway=192.168.0.1</programlisting>
</example>
<example>
- <title>/etc/systemd/network/80-dhcp.network</title>
+ <title>&pkgsysconfdir;/network/80-dhcp.network</title>
<programlisting>[Match]
Name=en*
[Network]
-DHCP=both</programlisting>
+DHCP=yes</programlisting>
</example>
<example>
- <title>/etc/systemd/network/bridge-static.network</title>
+ <title>&pkgsysconfdir;/network/bridge-static.network</title>
<programlisting>[Match]
Name=bridge0
@@ -659,7 +720,7 @@ DNS=192.168.0.1</programlisting>
</example>
<example>
- <title>/etc/systemd/network/bridge-slave-interface.network</title>
+ <title>&pkgsysconfdir;/network/bridge-slave-interface.network</title>
<programlisting>[Match]
Name=enp2s0
@@ -668,7 +729,7 @@ Name=enp2s0
Bridge=bridge0</programlisting>
</example>
<example>
- <title>/etc/systemd/network/ipip.network</title>
+ <title>&pkgsysconfdir;/network/ipip.network</title>
<programlisting>[Match]
Name=em1
@@ -678,7 +739,7 @@ Tunnel=ipip-tun</programlisting>
</example>
<example>
- <title>/etc/systemd/network/sit.network</title>
+ <title>&pkgsysconfdir;/network/sit.network</title>
<programlisting>[Match]
Name=em1
@@ -688,7 +749,7 @@ Tunnel=sit-tun</programlisting>
</example>
<example>
- <title>/etc/systemd/network/gre.network</title>
+ <title>&pkgsysconfdir;/network/gre.network</title>
<programlisting>[Match]
Name=em1
@@ -698,7 +759,7 @@ Tunnel=gre-tun</programlisting>
</example>
<example>
- <title>/etc/systemd/network/vti.network</title>
+ <title>&pkgsysconfdir;/network/vti.network</title>
<programlisting>[Match]
Name=em1
diff --git a/man/systemd.path.xml b/man/systemd.path.xml
index 08a7ec8975..03b626b560 100644
--- a/man/systemd.path.xml
+++ b/man/systemd.path.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -74,7 +77,7 @@
(see below).</para>
<para>Internally, path units use the
- <citerefentry><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry>
API to monitor file systems. Due to that, it suffers by the same
limitations as inotify, and for example cannot be used to monitor
files or directories changed by other machines on remote NFS file
@@ -187,7 +190,7 @@
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>inotify</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd.preset.xml b/man/systemd.preset.xml
index 2f9add8d6c..4667f9d616 100644
--- a/man/systemd.preset.xml
+++ b/man/systemd.preset.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -46,12 +49,12 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/system-preset/*.preset</filename></para>
+ <para><filename>&pkgsysconfdir;/system-preset/*.preset</filename></para>
<para><filename>/run/systemd/system-preset/*.preset</filename></para>
- <para><filename>/usr/lib/systemd/system-preset/*.preset</filename></para>
- <para><filename>/etc/systemd/user-preset/*.preset</filename></para>
+ <para><filename>&rootlibexecdir;/system-preset/*.preset</filename></para>
+ <para><filename>&pkgsysconfdir;/user-preset/*.preset</filename></para>
<para><filename>/run/systemd/user-preset/*.preset</filename></para>
- <para><filename>/usr/lib/systemd/user-preset/*.preset</filename></para>
+ <para><filename>&rootlibexecdir;/user-preset/*.preset</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -125,7 +128,7 @@
<para>If the administrator wants to disable a preset file supplied
by the vendor, the recommended way is to place a symlink to
<filename>/dev/null</filename> in
- <filename>/etc/systemd/system-preset/</filename> bearing the same
+ <filename>&pkgsysconfdir;/system-preset/</filename> bearing the same
filename.</para>
</refsect1>
@@ -133,7 +136,7 @@
<title>Example</title>
<example>
- <title>Default off example <filename>/usr/lib/systemd/system-preset/99-default.preset</filename>:</title>
+ <title>Default off example <filename>&rootlibexecdir;/system-preset/99-default.preset</filename>:</title>
<programlisting>disable *</programlisting>
</example>
@@ -144,7 +147,7 @@
suchlike.</para>
<example>
- <title>A GNOME spin example <filename>/usr/lib/systemd/system-preset/50-gnome.preset</filename>:</title>
+ <title>A GNOME spin example <filename>&rootlibexecdir;/system-preset/50-gnome.preset</filename>:</title>
<programlisting>enable gdm.service
enable colord.service
@@ -162,7 +165,7 @@ enable avahi-daemon.*</programlisting>
example like the one from the first example above.</para>
<example>
- <title>Administrator policy <filename>/etc/systemd/system-preset/00-lennart.preset</filename>:</title>
+ <title>Administrator policy <filename>&pkgsysconfdir;/system-preset/00-lennart.preset</filename>:</title>
<programlisting>enable httpd.service
enable sshd.service
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 8f4e7a3f16..82e21c6906 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.scope.xml b/man/systemd.scope.xml
index 59eede9596..f137cb7391 100644
--- a/man/systemd.scope.xml
+++ b/man/systemd.scope.xml
@@ -1,24 +1,27 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
-This file is part of systemd.
+ This file is part of systemd.
-Copyright 2013 Zbigniew Jędrzejewski-Szmek
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
-systemd is free software; you can redistribute it and/or modify it
-under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 2.1 of the License, or
-(at your option) any later version.
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
-systemd is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
-You should have received a copy of the GNU Lesser General Public License
-along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="systemd.scope">
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index c03b4e8a54..0fe694ab7e 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -334,6 +337,11 @@
<para>If any of those commands (not prefixed with
<literal>-</literal>) fail, the rest are not executed and the
unit is considered failed.</para>
+
+ <para>Note that <varname>ExecStartPre=</varname> may not be
+ used to start long-running processes. All processes forked
+ off by processes invoked via <varname>ExecStartPre=</varname> will
+ be killed before the next service process is run.</para>
</listitem>
</varlistentry>
@@ -508,7 +516,7 @@
<option>on-failure</option>, the service will be restarted
when the process exits with a non-zero exit code, is
terminated by a signal (including on core dump, but excluding
- the aforementiond four signals), when an operation (such as
+ the aforementioned four signals), when an operation (such as
service reload) times out, and when the configured watchdog
timeout is triggered. If set to <option>on-abnormal</option>,
the service will be restarted when the process is terminated
@@ -886,7 +894,7 @@
<title>Command lines</title>
<para>This section describes command line parsing and
- variable and specifier substitions for
+ variable and specifier substitutions for
<varname>ExecStart=</varname>,
<varname>ExecStartPre=</varname>,
<varname>ExecStartPost=</varname>,
@@ -1126,7 +1134,7 @@ WantedBy=multi-user.target</programlisting>
<varname>Type=</varname><option>oneshot</option> exists. Units
of this type will wait until the process specified terminates
and then fall back to being inactive. The following unit will
- perform a clenaup action:</para>
+ perform a cleanup action:</para>
<programlisting>[Unit]
Description=Cleanup old Foo data
diff --git a/man/systemd.slice.xml b/man/systemd.slice.xml
index f0bac41763..c443528ab1 100644
--- a/man/systemd.slice.xml
+++ b/man/systemd.slice.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -90,7 +93,7 @@
slice specific configuration options are configured in
the [Slice] section. Currently, only generic resource control settings
as described in
- <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>7</manvolnum></citerefentry> are allowed.
+ <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> are allowed.
</para>
<para>Unless <varname>DefaultDependencies=false</varname>
diff --git a/man/systemd.snapshot.xml b/man/systemd.snapshot.xml
index 96069c324a..4c1f40e814 100644
--- a/man/systemd.snapshot.xml
+++ b/man/systemd.snapshot.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 3938345fac..1d0fa1bd16 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -127,7 +130,7 @@
(see
<citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details) or via the traditional
- <citerefentry><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>-style
+ <citerefentry project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>-style
socket passing (i.e. sockets passed in via standard input and
output, using <varname>StandardInput=socket</varname> in the
service file).</para>
@@ -265,7 +268,7 @@
<listitem><para>Takes a one of <option>default</option>,
<option>both</option> or <option>ipv6-only</option>. Controls
the IPV6_V6ONLY socket option (see
- <citerefentry><refentrytitle>ipv6</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>ipv6</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details). If <option>both</option>, IPv6 sockets bound
will be accessible via both IPv4 and IPv6. If
<option>ipv6-only</option>, they will be accessible via IPv6
@@ -294,7 +297,7 @@
this socket to. If set, traffic will only be accepted from the
specified network interfaces. This controls the
SO_BINDTODEVICE socket option (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details). If this option is used, an automatic dependency
from this socket unit on the network interface device unit
(<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
@@ -355,9 +358,14 @@
<varname>Accept=true</varname> set. Setting
<varname>Accept=true</varname> is mostly useful to allow
daemons designed for usage with
- <citerefentry><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='freebsd'><refentrytitle>inetd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
to work unmodified with systemd socket
- activation.</para></listitem>
+ activation.</para>
+
+ <para>For IPv4 and IPv6 connections the <varname>REMOTE_ADDR</varname>
+ environment variable will contain the remote IP, and <varname>REMOTE_PORT</varname>
+ will contain the remote port. This is the same as the format used by CGI.
+ For SOCK_RAW the port is the IP protocol.</para></listitem>
</varlistentry>
<varlistentry>
@@ -380,7 +388,7 @@
<filename>/proc/sys/net/ipv4/tcp_keepalive_time</filename>)
for all TCP streams accepted on this socket. This controls the
SO_KEEPALIVE socket option (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and the <ulink
url="http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/">TCP
Keepalive HOWTO</ulink> for details.) Defaults to
@@ -392,7 +400,7 @@
<listitem><para>Takes time (in seconds) as argument . The connection needs to remain
idle before TCP starts sending keepalive probes. This controls the TCP_KEEPIDLE
socket option (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and the <ulink
url="http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/">TCP
Keepalive HOWTO</ulink> for details.)
@@ -405,7 +413,7 @@
individual keepalive probes, if the socket option SO_KEEPALIVE
has been set on this socket seconds as argument. This controls
the TCP_KEEPINTVL socket option (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and the <ulink
url="http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/">TCP
Keepalive HOWTO</ulink> for details.) Defaults value is 75
@@ -418,7 +426,7 @@
unacknowledged probes to send before considering the
connection dead and notifying the application layer. This
controls the TCP_KEEPCNT socket option (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and the <ulink
url="http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/">TCP
Keepalive HOWTO</ulink> for details.) Defaults value is
@@ -431,7 +439,7 @@
algorithm works by combining a number of small outgoing
messages, and sending them all at once. This controls the
TCP_NODELAY socket option (see
- <citerefentry><refentrytitle>tcp</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>tcp</refentrytitle><manvolnum>7</manvolnum></citerefentry>
Defaults to <option>false</option>.</para></listitem>
</varlistentry>
@@ -440,7 +448,7 @@
<listitem><para>Takes an integer argument controlling the
priority for all traffic sent from this socket. This controls
the SO_PRIORITY socket option (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.).</para></listitem>
</varlistentry>
@@ -453,7 +461,7 @@
established. When this option is set, the
<constant>TCP_DEFER_ACCEPT</constant> socket option will be
used (see
- <citerefentry><refentrytitle>tcp</refentrytitle><manvolnum>7</manvolnum></citerefentry>),
+ <citerefentry project='die-net'><refentrytitle>tcp</refentrytitle><manvolnum>7</manvolnum></citerefentry>),
and the kernel will ignore initial ACK packets without any
data. The argument specifies the approximate amount of time
the kernel should wait for incoming data before falling back
@@ -480,7 +488,7 @@
<listitem><para>Takes an integer argument controlling the
receive or send buffer sizes of this socket, respectively.
This controls the SO_RCVBUF and SO_SNDBUF socket options (see
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.). The usual suffixes K, M, G are supported and
are understood to the base of 1024.</para></listitem>
</varlistentry>
@@ -490,7 +498,7 @@
<listitem><para>Takes an integer argument controlling the IP
Type-Of-Service field for packets generated from this socket.
This controls the IP_TOS socket option (see
- <citerefentry><refentrytitle>ip</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>ip</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.). Either a numeric string or one of
<option>low-delay</option>, <option>throughput</option>,
<option>reliability</option> or <option>low-cost</option> may
@@ -503,9 +511,9 @@
Time-To-Live/IPv6 Hop-Count field for packets generated from
this socket. This sets the IP_TTL/IPV6_UNICAST_HOPS socket
options (see
- <citerefentry><refentrytitle>ip</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>ip</refentrytitle><manvolnum>7</manvolnum></citerefentry>
and
- <citerefentry><refentrytitle>ipv6</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>ipv6</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.)</para></listitem>
</varlistentry>
@@ -515,7 +523,7 @@
mark of packets generated by this socket. This can be used in
the firewall logic to filter packets from this socket. This
sets the SO_MARK socket option. See
- <citerefentry><refentrytitle>iptables</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>iptables</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
@@ -526,7 +534,7 @@
<citerefentry><refentrytitle>bind</refentrytitle><manvolnum>2</manvolnum></citerefentry>s
to this TCP or UDP port. This controls the SO_REUSEPORT socket
option. See
- <citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
@@ -578,7 +586,7 @@
control the mq_maxmsg field or the mq_msgsize field,
respectively, when creating the message queue. Note that
either none or both of these variables need to be set. See
- <citerefentry><refentrytitle>mq_setattr</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>mq_setattr</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index cf76aaf607..8db3050b58 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml
index 23b9c712ed..d3ddc1ab4d 100644
--- a/man/systemd.swap.xml
+++ b/man/systemd.swap.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -69,7 +72,7 @@
<para>Additional options are listed in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which define the execution environment the
- <citerefentry><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
binary is executed in, and in
<citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
which define the way the processes are terminated, and in
@@ -100,7 +103,7 @@
<para>Swap units may either be configured via unit files, or via
<filename>/etc/fstab</filename> (see
- <citerefentry><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details). Swaps listed in <filename>/etc/fstab</filename> will
be converted into native units dynamically at boot and when the
configuration of the system manager is reloaded. See
@@ -161,7 +164,7 @@
<term><varname>What=</varname></term>
<listitem><para>Takes an absolute path of a device node or
file to use for paging. See
- <citerefentry><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details. If this refers to a device node, a dependency on
the respective device unit is automatically created. (See
<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
@@ -177,7 +180,8 @@
<listitem><para>Swap priority to use when activating the swap
device or file. This takes an integer. This setting is
- optional.</para></listitem>
+ optional and ignored when priotiry is set by <option>pri=</option> in the
+ <varname>Options=</varname> option.</para></listitem>
</varlistentry>
<varlistentry>
@@ -187,7 +191,7 @@
device. This may be used for controlling discard options among
other functionality, if the swap backing device supports the
discard or trim operation. (See
- <citerefentry><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for more information.) </para></listitem>
</varlistentry>
@@ -229,7 +233,7 @@
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
diff --git a/man/systemd.target.xml b/man/systemd.target.xml
index e790e9b77a..884177e9fa 100644
--- a/man/systemd.target.xml
+++ b/man/systemd.target.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.time.xml b/man/systemd.time.xml
index da0729725d..570a20e5cf 100644
--- a/man/systemd.time.xml
+++ b/man/systemd.time.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 20890f2270..5f7e80425e 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 09e11b4711..8286cf3f78 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -64,20 +64,20 @@
<filename><replaceable>slice</replaceable>.slice</filename>,
<filename><replaceable>scope</replaceable>.scope</filename></para>
- <para><literallayout><filename>/etc/systemd/system/*</filename>
+ <para><literallayout><filename>&pkgsysconfdir;/system/*</filename>
<filename>/run/systemd/system/*</filename>
-<filename>/usr/lib/systemd/system/*</filename>
+<filename>&rootlibexecdir;/system/*</filename>
<filename>...</filename>
</literallayout></para>
<para><literallayout><filename>$XDG_CONFIG_HOME/systemd/user/*</filename>
<filename>$HOME/.config/systemd/user/*</filename>
-<filename>/etc/systemd/user/*</filename>
+<filename>&pkgsysconfdir;/user/*</filename>
<filename>$XDG_RUNTIME_DIR/systemd/user/*</filename>
<filename>/run/systemd/user/*</filename>
<filename>$XDG_DATA_HOME/systemd/user/*</filename>
<filename>$HOME/.local/share/systemd/user/*</filename>
-<filename>/usr/lib/systemd/user/*</filename>
+<filename>&rootlibexecdir;/user/*</filename>
<filename>...</filename>
</literallayout></para>
</refsynopsisdiv>
@@ -287,7 +287,7 @@
</thead>
<tbody>
<row>
- <entry><filename>/etc/systemd/system</filename></entry>
+ <entry><filename>&pkgsysconfdir;/system</filename></entry>
<entry>Local configuration</entry>
</row>
<row>
@@ -295,7 +295,7 @@
<entry>Runtime units</entry>
</row>
<row>
- <entry><filename>/usr/lib/systemd/system</filename></entry>
+ <entry><filename>&rootlibexecdir;/system</filename></entry>
<entry>Units of installed packages</entry>
</row>
</tbody>
@@ -326,7 +326,7 @@
<entry>User configuration (only used when $XDG_CONFIG_HOME is not set)</entry>
</row>
<row>
- <entry><filename>/etc/systemd/user</filename></entry>
+ <entry><filename>&pkgsysconfdir;/user</filename></entry>
<entry>Local configuration</entry>
</row>
<row>
@@ -346,7 +346,7 @@
<entry>Units of packages that have been installed in the home directory (only used when $XDG_DATA_HOME is not set)</entry>
</row>
<row>
- <entry><filename>/usr/lib/systemd/user</filename></entry>
+ <entry><filename>&rootlibexecdir;/user</filename></entry>
<entry>Units of packages that have been installed system-wide</entry>
</row>
</tbody>
@@ -357,8 +357,8 @@
from directories not on the unit load path. See the
<command>link</command> command for
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
- Also, some units are dynamically created via generators <ulink
- url="http://www.freedesktop.org/wiki/Software/systemd/Generators/">Generators</ulink>.
+ Also, some units are dynamically created via a
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para>
</refsect1>
@@ -826,7 +826,7 @@
<varname>cris</varname> to test
against a specific architecture. The architecture is
determined from the information returned by
- <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
and is thus subject to
<citerefentry><refentrytitle>personality</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
Note that a <varname>Personality=</varname> setting in the
@@ -1250,7 +1250,7 @@
<row>
<entry><literal>%H</literal></entry>
<entry>Host name</entry>
- <entry>The hostname of the running system at the point in time the unit configuation is loaded.</entry>
+ <entry>The hostname of the running system at the point in time the unit configuration is loaded.</entry>
</row>
<row>
<entry><literal>%v</literal></entry>
@@ -1296,7 +1296,7 @@ ExecStart=/usr/sbin/foo-daemon
<para>After running <command>systemctl enable</command>, a
symlink
- <filename>/etc/systemd/system/multi-user.target.wants/foo.service</filename>
+ <filename>&pkgsysconfdir;/system/multi-user.target.wants/foo.service</filename>
linking to the actual unit will be created. It tells systemd to
pull in the unit when starting
<filename>multi-user.target</filename>. The inverse
@@ -1309,11 +1309,11 @@ ExecStart=/usr/sbin/foo-daemon
<para>There are two methods of overriding vendor settings in
unit files: copying the unit file from
- <filename>/usr/lib/systemd/system</filename> to
- <filename>/etc/systemd/system</filename> and modifying the
+ <filename>&rootlibexecdir;/system</filename> to
+ <filename>&pkgsysconfdir;/system</filename> and modifying the
chosen settings. Alternatively, one can create a directory named
<filename><replaceable>unit</replaceable>.d/</filename> within
- <filename>/etc/systemd/system</filename> and place a drop-in
+ <filename>&pkgsysconfdir;/system</filename> and place a drop-in
file <filename><replaceable>name</replaceable>.conf</filename>
there that only changes the specific settings one is interested
in. Note that multiple such drop-in files are read if
@@ -1343,7 +1343,7 @@ ExecStart=/usr/sbin/foo-daemon
load paths for further details.</para>
<para>Suppose there is a vendor-supplied unit
- <filename>/usr/lib/systemd/system/httpd.service</filename> with
+ <filename>&rootlibexecdir;/system/httpd.service</filename> with
the following contents:</para>
<programlisting>[Unit]
@@ -1375,7 +1375,7 @@ WantedBy=multi-user.target</programlisting>
the niceness of the service to its default value of 0.</para>
<para>The first possibility is to copy the unit file to
- <filename>/etc/systemd/system/httpd.service</filename> and
+ <filename>&pkgsysconfdir;/system/httpd.service</filename> and
change the chosen settings:</para>
<programlisting>[Unit]
@@ -1395,7 +1395,7 @@ WantedBy=multi-user.target</programlisting>
<para>Alternatively, the administrator could create a drop-in
file
- <filename>/etc/systemd/system/httpd.service.d/local.conf</filename>
+ <filename>&pkgsysconfdir;/system/httpd.service.d/local.conf</filename>
with the following contents:</para>
<programlisting>[Unit]
@@ -1438,7 +1438,7 @@ PrivateTmp=yes</programlisting>
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>uname</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/systemd.xml b/man/systemd.xml
index 80591dc732..5fa65a3631 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -415,9 +418,8 @@
<para>Units may be generated dynamically at boot and system
manager reload time, for example based on other configuration
- files or parameters passed on the kernel command line. For details
- see the
- <ulink url="http://www.freedesktop.org/wiki/Software/systemd/Generators">Generators Specification</ulink>.</para>
+ files or parameters passed on the kernel command line. For details see
+ <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<para>Systems which invoke systemd in a container or initrd
environment should implement the
@@ -439,7 +441,7 @@
by <command>pkg-config systemd
--variable=systemdsystemunitdir</command>. Other directories
checked are <filename>/usr/local/lib/systemd/system</filename>
- and <filename>/usr/lib/systemd/system</filename>. User
+ and <filename>&rootlibexecdir;/system</filename>. User
configuration always takes precedence. <command>pkg-config
systemd --variable=systemdsystemconfdir</command> returns the
path of the system configuration directory. Packages should
@@ -1013,9 +1015,9 @@
<listitem><para>Set the system locale to use. This overrides
the settings in <filename>/etc/locale.conf</filename>. For
more information see
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
and
- <citerefentry><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
</variablelist>
@@ -1040,16 +1042,6 @@
</varlistentry>
<varlistentry>
- <term><filename>/run/systemd/shutdownd</filename></term>
-
- <listitem><para>Used internally by the
- <citerefentry><refentrytitle>shutdown</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- tool to implement delayed shutdowns. This is an
- <constant>AF_UNIX</constant> datagram
- socket.</para></listitem>
- </varlistentry>
-
- <varlistentry>
<term><filename>/run/systemd/private</filename></term>
<listitem><para>Used internally as communication channel
@@ -1078,7 +1070,7 @@
<para>
The <ulink url="http://www.freedesktop.org/wiki/Software/systemd/">systemd Homepage</ulink>,
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-notify</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml
index 99aa07a1cc..3085f3dd01 100644
--- a/man/sysusers.d.xml
+++ b/man/sysusers.d.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/telinit.xml b/man/telinit.xml
index 02d31fbd46..ec7e8eace4 100644
--- a/man/telinit.xml
+++ b/man/telinit.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/timedatectl.xml b/man/timedatectl.xml
index 98ec013ebb..d7bd052eff 100644
--- a/man/timedatectl.xml
+++ b/man/timedatectl.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -103,9 +106,14 @@
<varlistentry>
<term><command>status</command></term>
- <listitem><para>Show current settings
- of the system clock and
- RTC.</para></listitem>
+ <listitem><para>Show current settings of the system clock and
+ RTC, including whether network time synchronization is
+ on. Note that whether network time synchronization is on
+ simply reflects whether the
+ <filename>systemd-timesyncd.service</filename> unit is
+ enabled. Even if this command shows the status as off a
+ different service might still synchronize the clock with the
+ network.</para></listitem>
</varlistentry>
<varlistentry>
@@ -160,9 +168,13 @@
<varlistentry>
<term><command>set-ntp [BOOL]</command></term>
- <listitem><para>Takes a boolean argument. Controls whether NTP
- based network time synchronization is enabled (if
- available).</para></listitem>
+ <listitem><para>Takes a boolean argument. Controls whether
+ network time synchronization is enabled (if available). This
+ enables or disables the
+ <filename>systemd-timesyncd.service</filename> unit. Note that
+ even if this command turns time synchronization off a
+ different system service might still synchronize the clock
+ with the network.</para></listitem>
</varlistentry>
</variablelist>
@@ -182,25 +194,16 @@
<title>Examples</title>
<para>Show current settings:
<programlisting>$ timedatectl
- Local time: Fri, 2012-11-02 09:26:46 CET
- Universal time: Fri, 2012-11-02 08:26:46 UTC
- RTC time: Fri, 2012-11-02 08:26:45
- Timezone: Europe/Warsaw
- UTC offset: +0100
- NTP enabled: no
-NTP synchronized: no
- RTC in local TZ: no
- DST active: no
- Last DST change: CEST → CET, DST became inactive
- Sun, 2012-10-28 02:59:59 CEST
- Sun, 2012-10-28 02:00:00 CET
- Next DST change: CET → CEST, DST will become active
- the clock will jump one hour forward
- Sun, 2013-03-31 01:59:59 CET
- Sun, 2013-03-31 03:00:00 CEST</programlisting>
+ Local time: Di 2015-04-07 16:26:56 CEST
+ Universal time: Di 2015-04-07 14:26:56 UTC
+ RTC time: Di 2015-04-07 14:26:56
+ Time zone: Europe/Berlin (CEST, +0200)
+ Network time on: yes
+NTP synchronized: yes
+ RTC in local TZ: no</programlisting>
</para>
- <para>Enable an NTP daemon (chronyd):
+ <para>Enable network time synchronization:
<programlisting>$ timedatectl set-ntp true
==== AUTHENTICATING FOR org.freedesktop.timedate1.set-ntp ===
Authentication is required to control whether network time synchronization shall be enabled.
@@ -208,10 +211,15 @@ Authenticating as: user
Password: ********
==== AUTHENTICATION COMPLETE ===</programlisting>
- <programlisting>$ systemctl status chronyd.service
-chronyd.service - NTP client/server
- Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled)
- Active: active (running) since Fri, 2012-11-02 09:36:25 CET; 5s ago
+ <programlisting>$ systemctl status systemd-timesyncd.service
+● systemd-timesyncd.service - Network Time Synchronization
+ Loaded: loaded (&rootlibexecdir;/system/systemd-timesyncd.service; enabled)
+ Active: active (running) since Mo 2015-03-30 14:20:38 CEST; 5s ago
+ Docs: man:systemd-timesyncd.service(8)
+ Main PID: 595 (systemd-timesyn)
+ Status: "Using Time Server 216.239.38.15:123 (time4.google.com)."
+ CGroup: /system.slice/systemd-timesyncd.service
+ └─595 &rootlibexecdir;/systemd-timesyncd
...</programlisting>
</para>
</refsect1>
@@ -225,6 +233,7 @@ chronyd.service - NTP client/server
<citerefentry><refentrytitle>localtime</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-timedated.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/timesyncd.conf.xml b/man/timesyncd.conf.xml
index 1127970a18..c297d3254c 100644
--- a/man/timesyncd.conf.xml
+++ b/man/timesyncd.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -49,10 +52,10 @@
</refnamediv>
<refsynopsisdiv>
- <para><filename>/etc/systemd/timesyncd.conf</filename></para>
- <para><filename>/etc/systemd/timesyncd.conf.d/*.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/timesyncd.conf</filename></para>
+ <para><filename>&pkgsysconfdir;/timesyncd.conf.d/*.conf</filename></para>
<para><filename>/run/systemd/timesyncd.conf.d/*.conf</filename></para>
- <para><filename>/usr/lib/systemd/timesyncd.conf.d/*.conf</filename></para>
+ <para><filename>&rootlibexecdir;/timesyncd.conf.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1>
@@ -63,8 +66,7 @@
</refsect1>
- <xi:include href="standard-conf.xml" xpointer="confd" />
- <xi:include href="standard-conf.xml" xpointer="conf" />
+ <xi:include href="standard-conf.xml" xpointer="main-conf" />
<refsect1>
<title>Options</title>
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 8815bf9970..c37de65229 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -101,9 +104,12 @@
the lexicographically earliest name will be applied. All other
conflicting entries will be logged as errors. When two lines are
prefix and suffix of each other, then the prefix is always
- processed first, the suffix later. Otherwise, the
- files/directories are processed in the order they are
- listed.</para>
+ processed first, the suffix later. Lines that take globs are
+ applied after those accepting no globs. If multiple operations
+ shall be applied on the same file (such as ACL, xattr, file
+ attribute adjustments) these are always done in the same fixed
+ order. Otherwise, the files/directories are processed in the order
+ they are listed.</para>
<para>If the administrator wants to disable a configuration file
supplied by the vendor, the recommended way is to place a symlink
@@ -118,6 +124,8 @@
d /run/user 0755 root root 10d -
L /tmp/foobar - - - - /dev/null</programlisting>
+ <para>Fields may be enclosed within quotes and contain C-style escapes.</para>
+
<refsect2>
<title>Type</title>
@@ -131,13 +139,13 @@
<term><varname>f</varname></term>
<listitem><para>Create a file if it does not exist yet. If
the argument parameter is given, it will be written to the
- file.</para></listitem>
+ file. Does not follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>F</varname></term>
<listitem><para>Create or truncate a file. If the argument
- parameter is given, it will be written to the file.</para>
+ parameter is given, it will be written to the file. Does not follow symlinks.</para>
</listitem>
</varlistentry>
@@ -147,7 +155,8 @@
the file exists. Lines of this type accept shell-style
globs in place of normal path names. The argument parameter
will be written without a trailing newline. C-style
- backslash escapes are interpreted.</para></listitem>
+ backslash escapes are interpreted. Follows
+ symlinks.</para></listitem>
</varlistentry>
<varlistentry>
@@ -225,7 +234,7 @@
copy operation is skipped. If the argument is omitted, files
from the source directory
<filename>/usr/share/factory/</filename> with the same name
- are copied.</para></listitem>
+ are copied. Does not follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
@@ -257,7 +266,7 @@
This may not be used to remove non-empty directories, use
<varname>R</varname> for that. Lines of this type accept
shell-style globs in place of normal path
- names.</para></listitem>
+ names. Does not follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
@@ -265,7 +274,7 @@
<listitem><para>Recursively remove a path and all its
subdirectories (if it is a directory). Lines of this type
accept shell-style globs in place of normal path
- names.</para></listitem>
+ names. Does not follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
@@ -273,7 +282,7 @@
<listitem><para>Adjust the access mode, group and user, and
restore the SELinux security context of a file or directory,
if it exists. Lines of this type accept shell-style globs in
- place of normal path names.</para></listitem>
+ place of normal path names. Does not follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
@@ -282,23 +291,56 @@
user, and restore the SELinux security context of a file or
directory if it exists, as well as of its subdirectories and
the files contained therein (if applicable). Lines of this
- type accept shell-style globs in place of normal path names.
- </para></listitem>
+ type accept shell-style globs in place of normal path
+ names. Does not follow symlinks. </para></listitem>
</varlistentry>
<varlistentry>
<term><varname>t</varname></term>
<listitem><para>Set extended attributes. Lines of this type
accept shell-style globs in place of normal path names.
- This can be useful for setting SMACK labels.
- </para></listitem>
+ This can be useful for setting SMACK labels. Does not follow
+ symlinks.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>T</varname></term>
<listitem><para>Recursively set extended attributes. Lines
of this type accept shell-style globs in place of normal
- path names. This can be useful for setting SMACK labels.
+ path names. This can be useful for setting SMACK
+ labels. Does not follow symlinks. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>h</varname></term>
+ <listitem><para>Set file/directory attributes. Lines of this type
+ accept shell-style globs in place of normal path names.</para>
+
+ <para>The format of the argument field is
+ <varname>[+-=][aAcCdDeijsStTu] </varname>. The prefix
+ <varname>+</varname> (the default one) causes the
+ attribute(s) to be added; <varname>-</varname> causes the
+ attribute(s) to be removed; <varname>=</varname> causes the
+ attributes to set exactly as the following letters. The
+ letters <literal>aAcCdDeijsStTu</literal> select the new
+ attributes for the files, see
+ <citerefentry><refentrytitle>chattr</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry> for further information.
+ </para>
+ <para>Passing only <varname>=</varname> as argument resets
+ all the file attributes listed above. It has to be pointed
+ out that the <varname>=</varname> prefix, limits itself to
+ the attributes corresponding to the letters listed here. All
+ other attributes will be left untouched. Does not follow
+ symlinks.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>H</varname></term>
+ <listitem><para>Recursively set file/directory attributes. Lines
+ of this type accept shell-style globs in place of normal
+ path names. Does not follow symlinks.
</para></listitem>
</varlistentry>
@@ -315,14 +357,15 @@
specified explicitly or already present. Lines of this type
accept shell-style globs in place of normal path names. This
can be useful for allowing additional access to certain
- files.</para></listitem>
+ files. Does not follow symlinks.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>A</varname></term>
<term><varname>A+</varname></term>
<listitem><para>Same as <varname>a</varname> and
- <varname>a+</varname>, but recursive.</para></listitem>
+ <varname>a+</varname>, but recursive. Does not follow
+ symlinks.</para></listitem>
</varlistentry>
</variablelist>
@@ -443,23 +486,22 @@
delete when cleaning. If a file or directory is older than the
current time minus the age field, it is deleted. The field
format is a series of integers each followed by one of the
- following postfixes for the respective time units:</para>
-
- <variablelist>
- <varlistentry>
- <term><varname>s</varname></term>
- <term><varname>min</varname></term>
- <term><varname>h</varname></term>
- <term><varname>d</varname></term>
- <term><varname>w</varname></term>
- <term><varname>ms</varname></term>
- <term><varname>m</varname></term>
- <term><varname>us</varname></term></varlistentry>
- </variablelist>
+ following postfixes for the respective time units:
+ <constant>s</constant>,
+ <constant>m</constant> or <constant>min</constant>,
+ <constant>h</constant>,
+ <constant>d</constant>,
+ <constant>w</constant>,
+ <constant>ms</constant>,
+ <constant>us</constant>,
+ respectively meaning seconds, minutes, hours, days, weeks,
+ milliseconds, and microseconds. Full names of the time units can
+ be used too.
+ </para>
<para>If multiple integers and units are specified, the time
- values are summed up. If an integer is given without a unit,
- <varname>s</varname> is assumed.
+ values are summed. If an integer is given without a unit,
+ <constant>s</constant> is assumed.
</para>
<para>When the age is set to zero, the files are cleaned
@@ -490,9 +532,12 @@
<varname>w</varname> may be used to specify a short string that
is written to the file, suffixed by a newline. For
<varname>C</varname>, specifies the source file or
- directory. For <varname>t</varname> determines extended
- attributes to be set. For <varname>a</varname> determines
- ACL attributes to be set. Ignored for all other lines.</para>
+ directory. For <varname>t</varname>, <varname>T</varname>
+ determines extended attributes to be set. For
+ <varname>a</varname>, <varname>A</varname> determines ACL
+ attributes to be set. For <varname>h</varname>,
+ <varname>H</varname> determines the file attributes to
+ set. Ignored for all other lines.</para>
</refsect2>
</refsect1>
@@ -505,15 +550,15 @@
boot with specific modes and ownership.</para>
<programlisting>d /run/screens 1777 root root 10d
- d /run/uscreens 0755 root root 10d12h
- t /run/screen - - - - user.name="John Smith" security.SMACK64=screen</programlisting>
+d /run/uscreens 0755 root root 10d12h
+t /run/screen - - - - user.name="John Smith" security.SMACK64=screen</programlisting>
</example>
<example>
<title>/etc/tmpfiles.d/abrt.conf example</title>
<para><command>abrt</command> needs a directory created at boot with specific mode and ownership and its content should be preserved.</para>
<programlisting>d /var/tmp/abrt 0755 abrt abrt
- x /var/tmp/abrt/*</programlisting>
+x /var/tmp/abrt/*</programlisting>
</example>
</refsect1>
@@ -528,7 +573,8 @@
<citerefentry project='man-pages'><refentrytitle>getfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>setfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry project='man-pages'><refentrytitle>getfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ <citerefentry project='man-pages'><refentrytitle>getfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/udev.conf.xml b/man/udev.conf.xml
index e104e53f5d..a10cc3cebe 100644
--- a/man/udev.conf.xml
+++ b/man/udev.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
diff --git a/man/udev.xml b/man/udev.xml
index a948ea79a9..d5d8a17cdb 100644
--- a/man/udev.xml
+++ b/man/udev.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refentry id="udev">
<refentryinfo>
@@ -55,17 +58,17 @@
<refsect1><title>Rules Files</title>
<para>The udev rules are read from the files located in the
- system rules directory <filename>/usr/lib/udev/rules.d</filename>,
+ system rules directory <filename>&udevlibexecdir;/rules.d</filename>,
the volatile runtime directory <filename>/run/udev/rules.d</filename>
and the local administration directory <filename>/etc/udev/rules.d</filename>.
All rules files are collectively sorted and processed in lexical order,
regardless of the directories in which they live. However, files with
identical filenames replace each other. Files in <filename>/etc</filename>
have the highest priority, files in <filename>/run</filename> take precedence
- over files with the same name in <filename>/usr/lib</filename>. This can be
+ over files with the same name in <filename>&rootprefix;/lib</filename>. This can be
used to override a system-supplied rules file with a local file if needed;
a symlink in <filename>/etc</filename> with the same name as a rules file in
- <filename>/usr/lib</filename>, pointing to <filename>/dev/null</filename>,
+ <filename>&rootprefix;/lib</filename>, pointing to <filename>/dev/null</filename>,
disables the rules file entirely. Rule files must have the extension
<filename>.rules</filename>; other extensions are ignored.</para>
@@ -193,6 +196,11 @@
value itself contains trailing whitespace.
</para>
</listitem>
+ <term><varname>SYSCTL{<replaceable>kernel parameter</replaceable>}</varname></term>
+ <listitem>
+ <para>Match a kernel parameter value.
+ </para>
+ </listitem>
</varlistentry>
<varlistentry>
@@ -375,6 +383,13 @@
</varlistentry>
<varlistentry>
+ <term><varname>SYSCTL{<replaceable>kernel parameter</replaceable>}</varname></term>
+ <listitem>
+ <para>The value that should be written to kernel parameter.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>ENV{<replaceable>key</replaceable>}</varname></term>
<listitem>
<para>Set a device property value. Property names with a leading <literal>.</literal>
@@ -409,7 +424,7 @@
<listitem>
<para>Execute an external program specified as the assigned
value. If no absolute path is given, the program is expected
- to live in <filename>/usr/lib/udev</filename>; otherwise, the
+ to live in <filename>&udevlibexecdir;</filename>; otherwise, the
absolute path must be specified.</para>
<para>This is the default if no <replaceable>type</replaceable>
is specified.</para>
diff --git a/man/udevadm.xml b/man/udevadm.xml
index 8ef9e23aa2..c7ef7279c9 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<refentry id="udevadm">
<refentryinfo>
diff --git a/man/user-system-options.xml b/man/user-system-options.xml
index 8616c54249..1e415ddd4c 100644
--- a/man/user-system-options.xml
+++ b/man/user-system-options.xml
@@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<variablelist>
<varlistentry id='user'>
diff --git a/man/vconsole.conf.xml b/man/vconsole.conf.xml
index 17bea8b682..1c3bdd2e54 100644
--- a/man/vconsole.conf.xml
+++ b/man/vconsole.conf.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
<!--
This file is part of systemd.
@@ -129,9 +132,9 @@ FONT=eurlatgr</programlisting>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-vconsole-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>setfont</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>setfont</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/po/LINGUAS b/po/LINGUAS
index 2ec9f827dc..562c5627be 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -8,3 +8,4 @@ pt_BR
ru
uk
sv
+es
diff --git a/po/de.po b/po/de.po
index 69c1fb9f86..dcaff30ea6 100644
--- a/po/de.po
+++ b/po/de.po
@@ -10,8 +10,8 @@ msgstr ""
"Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?"
"product=systemd&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2015-01-22 14:27+0000\n"
-"PO-Revision-Date: 2015-01-29 19:00+0100\n"
-"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
+"PO-Revision-Date: 2015-02-18 17:08+0100\n"
+"Last-Translator: Martin Pitt <martin.pitt@ubuntu.com>\n"
"Language-Team: German <gnome-de@gnome.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
@@ -454,5 +454,16 @@ msgstr ""
"Legitimierung ist zum Festlegen, ob Netzwerkzeitabgeich eingeschaltet sein "
"soll, erforderlich."
+#: ../src/fsckd/fsckd.c:186
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr "Strl+C drücken um laufende Dateisystem-Prüfungen abzubrechen"
+
+#: ../src/fsckd/fsckd.c:227
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Prüfe %d Laufwerk (%3.1f%% fertig)"
+msgstr[1] "Prüfe %d Laufwerke (%3.1f%% fertig)"
+
#~ msgid "Privileged system and service manager access"
#~ msgstr "Privilegierter Zugriff auf die System- und Dienstverwaltung"
diff --git a/po/el.po b/po/el.po
index 8f7a0edb21..14ee497889 100644
--- a/po/el.po
+++ b/po/el.po
@@ -402,3 +402,14 @@ msgid "Authentication is required to access the system and service manager."
msgstr ""
"Απαιτείται πιστοποίηση για να προσπελάσετε τον διαχειριστή συστήματος και "
"υπηρεσιών."
+
+#: ../src/fsckd/fsckd.c:186
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+
+#: ../src/fsckd/fsckd.c:227
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] ""
+msgstr[1] ""
diff --git a/po/es.po b/po/es.po
new file mode 100644
index 0000000000..811e36e81f
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,532 @@
+# Spanish translation for systemd.
+# Copyright (C) 2015 systemd's COPYRIGHT HOLDER
+# This file is distributed under the same license as the systemd package.
+# Alex Puchades <alex94puchades@gmail.com>, 2015.
+# Daniel Mustieles <daniel.mustieles@gmail.com>, 2015.
+# Álex Puchades <alex94puchades@gmail.com>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: systemd master\n"
+"Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?"
+"product=systemd&keywords=I18N+L10N&component=general\n"
+"POT-Creation-Date: 2015-04-23 23:43+0000\n"
+"PO-Revision-Date: 2015-04-24 13:26+0200\n"
+"Last-Translator: Álex Puchades <alex94puchades@gmail.com>\n"
+"Language-Team: Español; Castellano <gnome-es-list@gnome.org>\n"
+"Language: es\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: Gtranslator 2.91.7\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Devolver contraseña al sistema"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr ""
+"Se requiere autenticación para devolver la contraseña introducida al sistema."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "Administrar servicios del sistema u otras unidades"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr ""
+"Se requiere autenticación para administrar los servicios de sistema u otras "
+"unidades."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Administrar servicio del sistema o archivos de unidad"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr ""
+"Se requiere autenticación para administrar el servicio de sistema o los "
+"archivos de unidad."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr "Administrar variables de entorno del sistema y del gestor de servicios"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Se requiere autenticación para administrar las variables de entorno del "
+"sistema y del gestor de servicios."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "Recargar el estado de systemd"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "Se requiere autenticación para recargar el estado de systemd."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
+msgid "Set host name"
+msgstr "Establecer nombre del equipo"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
+msgid "Authentication is required to set the local host name."
+msgstr "Se requiere autenticación para establecer el nombre de equipo local."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
+msgid "Set static host name"
+msgstr "Establecer nombre estático del equipo"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
+msgid ""
+"Authentication is required to set the statically configured local host name, "
+"as well as the pretty host name."
+msgstr ""
+"Se requiere autenticación para establecer el nombre estático de equipo "
+"local, así como el nombre visible del equipo."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
+msgid "Set machine information"
+msgstr "Establecer información del sistema"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
+msgid "Authentication is required to set local machine information."
+msgstr ""
+"Se requiere autenticación para establecer la información de sistema local."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Importar una imagen de máquina virtual o de contenedor"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr ""
+"Se requiere autenticación para importar una imagen de máquina virtual o de "
+"contenedor"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Exportar imagen de máquina virtual o de contenedor"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr ""
+"Se requiere autenticación para exportar una imagen de máquina virtual o de "
+"contenedor"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
+msgid "Download a VM or container image"
+msgstr "Descargar una imagen de máquina virtual o de contenedor"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
+msgid "Authentication is required to download a VM or container image"
+msgstr ""
+"Se requiere autenticación para descargar una imagen de máquina virtual o de "
+"contenedor"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
+msgid "Set system locale"
+msgstr "Establecer región del sistema"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
+msgid "Authentication is required to set the system locale."
+msgstr "Se requiere autenticación para establecer la región del sistema"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
+msgid "Set system keyboard settings"
+msgstr "Configurar teclado"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
+msgid "Authentication is required to set the system keyboard settings."
+msgstr "Se requiere autenticación para configurar el teclado del sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:1
+msgid "Allow applications to inhibit system shutdown"
+msgstr "Permitir que las aplicaciones impidan el apagado del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:2
+msgid ""
+"Authentication is required for an application to inhibit system shutdown."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida el apagado del "
+"sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:3
+msgid "Allow applications to delay system shutdown"
+msgstr "Permitir a las aplicaciones retrasar el apagado del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:4
+msgid "Authentication is required for an application to delay system shutdown."
+msgstr ""
+"Se requiere autenticación para que una aplicación retrase el apagado del "
+"sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:5
+msgid "Allow applications to inhibit system sleep"
+msgstr "Permitir a las aplicaciones impedir la hibernación del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:6
+msgid "Authentication is required for an application to inhibit system sleep."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida la hibernación del "
+"sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:7
+msgid "Allow applications to delay system sleep"
+msgstr "Permitir a las aplicaciones retrasar la hibernación del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:8
+msgid "Authentication is required for an application to delay system sleep."
+msgstr ""
+"Se requiere autenticación para que una aplicación retrase la hibernación del "
+"sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:9
+msgid "Allow applications to inhibit automatic system suspend"
+msgstr ""
+"Permitir a las aplicaciones impedir la suspensión automática del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:10
+msgid ""
+"Authentication is required for an application to inhibit automatic system "
+"suspend."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida la suspensión "
+"automática del sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:11
+msgid "Allow applications to inhibit system handling of the power key"
+msgstr ""
+"Permitir a las aplicaciones impedir el manejo de la tecla de encendido/"
+"apagado por parte del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:12
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the power key."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida el manejo de la "
+"tecla de encendido/apagado por parte del sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:13
+msgid "Allow applications to inhibit system handling of the suspend key"
+msgstr ""
+"Permitir a las aplicaciones impedir el manejo de la tecla de suspensión por "
+"parte del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:14
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the suspend key."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida el manejo de la "
+"tecla de suspensión por parte del sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:15
+msgid "Allow applications to inhibit system handling of the hibernate key"
+msgstr ""
+"Permitir a las aplicaciones impedir el manejo de la tecla de hibernación por "
+"parte del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:16
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the hibernate key."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida el manejo de la "
+"tecla de hibernación por parte del sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:17
+msgid "Allow applications to inhibit system handling of the lid switch"
+msgstr ""
+"Permitir a las aplicaciones impedir el manejo del cierre de la tapa del "
+"portátil por parte del sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:18
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the lid switch."
+msgstr ""
+"Se requiere autenticación para que una aplicación impida el manejo del "
+"cierre de la tapa del portátil por parte del sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in users to run programs"
+msgstr "Permitir la ejecución de programas a usuarios no conectados"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Authentication is required to run programs as a non-logged-in user."
+msgstr ""
+"Se requiere autenticación para la ejecución de programas por usuarios no "
+"conectados."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
+msgid "Allow attaching devices to seats"
+msgstr "Permitir la conexión de dispositivos a los puestos de trabajo"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
+msgid "Authentication is required for attaching a device to a seat."
+msgstr ""
+"Se requiere autenticación para conectar un dispositivo a un puesto de "
+"trabajo."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
+msgid "Flush device to seat attachments"
+msgstr "Refrescar los dispositivos asociados a cada puesto de trabajo"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
+msgid ""
+"Authentication is required for resetting how devices are attached to seats."
+msgstr ""
+"Se requiere autenticación para reconfigurar los dispositivos asociados a "
+"cada puesto de trabajo."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
+msgid "Power off the system"
+msgstr "Apagar el sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
+msgid "Authentication is required for powering off the system."
+msgstr "Se requiere autenticación para apagar el sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
+msgid "Power off the system while other users are logged in"
+msgstr "Apagar el sistema mientras todavía hay usuarios conectados"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
+msgid ""
+"Authentication is required for powering off the system while other users are "
+"logged in."
+msgstr ""
+"Se requiere autenticación para apagar el sistema mientras todavía hay "
+"usuarios conectados."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
+msgid "Power off the system while an application asked to inhibit it"
+msgstr "Apagar el sistema a pesar de que una aplicación lo impide"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
+msgid ""
+"Authentication is required for powering off the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Se requiere autenticación para apagar el sistema a pesar de que una "
+"aplicación lo impide."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
+msgid "Reboot the system"
+msgstr "Reiniciar el sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
+msgid "Authentication is required for rebooting the system."
+msgstr "Se requiere autenticación para reiniciar el sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
+msgid "Reboot the system while other users are logged in"
+msgstr "Reiniciar el sistema mientras todavía hay usuarios conectados"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
+msgid ""
+"Authentication is required for rebooting the system while other users are "
+"logged in."
+msgstr ""
+"Se requiere autenticación para reiniciar el sistema mientras todavía hay "
+"usuarios conectados."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
+msgid "Reboot the system while an application asked to inhibit it"
+msgstr "Reiniciar el sistema a pesar de que una aplicación lo impide"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
+msgid ""
+"Authentication is required for rebooting the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Se requiere autenticación para reiniciar el sistema a pesar de que una "
+"aplicación lo impide."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
+msgid "Suspend the system"
+msgstr "Suspender el sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
+msgid "Authentication is required for suspending the system."
+msgstr "Se requiere autenticación para suspender el sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
+msgid "Suspend the system while other users are logged in"
+msgstr "Suspender el sistema mientras todavía hay usuarios conectados"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
+msgid ""
+"Authentication is required for suspending the system while other users are "
+"logged in."
+msgstr ""
+"Se requiere autenticación para suspender el sistema mientras todavía hay "
+"usuarios conectados."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
+msgid "Suspend the system while an application asked to inhibit it"
+msgstr "Suspender el sistema a pesar de que una aplicación lo impide"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
+msgid ""
+"Authentication is required for suspending the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Se requiere autenticación para suspender el sistema a pesar de que una "
+"aplicación lo impide."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
+msgid "Hibernate the system"
+msgstr "Hibernar el sistema"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
+msgid "Authentication is required for hibernating the system."
+msgstr "Se requiere autenticación para hibernar el sistema."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
+msgid "Hibernate the system while other users are logged in"
+msgstr "Hibernar el sistema mientras todavía hay usuarios conectados"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
+msgid ""
+"Authentication is required for hibernating the system while other users are "
+"logged in."
+msgstr ""
+"Se requiere autenticación para hibernar el sistema mientras todavía hay "
+"usuarios conectados."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
+msgid "Hibernate the system while an application asked to inhibit it"
+msgstr "Hibernar el sistema a pesar de que una aplicación lo impide"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
+msgid ""
+"Authentication is required for hibernating the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Se requiere autenticación para hibernar el sistema a pesar de que una "
+"aplicación lo impide"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Administrar sesiones activas, usuarios y puestos de trabajo"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Se requiere autenticación para administrar las sesiones activas, usuarios y "
+"puestos de trabajo."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Bloquear/desbloquear sesiones activas"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr "Se requiere autenticación para bloquear/desbloquear sesiones activas."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr ""
+"Permitir indicación al firmware para arrancar la interfaz de configuración"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr ""
+"Se requiere autenticación para indicar al firmware que arranque la interfaz "
+"de configuración."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
+msgid "Log into a local container"
+msgstr "Conectarse a un contenedor local"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
+msgid "Authentication is required to log into a local container."
+msgstr "Se requiere autenticación para conectarse a un contenedor local."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Manage local virtual machines and containers"
+msgstr "Administrar máquinas virtuales y contenedores locales"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Se requiere autenticación para administrar las máquinas virtuales y los "
+"contenedores locales."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Manage local virtual machine and container images"
+msgstr "Administrar imágenes de máquina virtual y de contenedor locales"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Se requiere autenticación para administrar las imágenes de máquina virtual y "
+"de contenedor locales."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
+msgid "Set system time"
+msgstr "Establecer fecha y hora del sistema"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
+msgid "Authentication is required to set the system time."
+msgstr "Se requiere autenticación para establecer la fecha y hora del sistema."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
+msgid "Set system timezone"
+msgstr "Establecer la zona horaria del sistema"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
+msgid "Authentication is required to set the system timezone."
+msgstr "Se requiere autenticación para establecer la zona horaria del sistema."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
+msgid "Set RTC to local timezone or UTC"
+msgstr "Establecer reloj del sistema en formato de hora local/tiempo UTC"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6
+msgid ""
+"Authentication is required to control whether the RTC stores the local or "
+"UTC time."
+msgstr ""
+"Se requiere autenticación para establecer el reloj del sistema en formato de "
+"hora local / tiempo UTC."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
+msgid "Turn network time synchronization on or off"
+msgstr "Activar/desactivar la sincronización de hora por red"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
+msgid ""
+"Authentication is required to control whether network time synchronization "
+"shall be enabled."
+msgstr ""
+"Se requiere autenticación para activar/desactivar la sincronización de hora "
+"por red."
+
+#: ../src/fsckd/fsckd.c:297
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+"Presione Ctrl+C para cancelar todas las comprobaciones del sistema de "
+"archivos en curso"
+
+#: ../src/fsckd/fsckd.c:343
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Comprobando progreso en %d disco (%3.1f %% completado)"
+msgstr[1] "Comprobando progreso en %d discos (%3.1f %% completado)"
diff --git a/po/fr.po b/po/fr.po
index 4d4fc6b356..69862fb4c2 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-01-22 16:03+0100\n"
+"POT-Creation-Date: 2015-04-07 20:05+0200\n"
"PO-Revision-Date: 2014-12-28 13:04+0100\n"
"Last-Translator: Sylvain Plantefève <sylvain.plantefeve@gmail.com>\n"
"Language-Team: French\n"
@@ -27,11 +27,11 @@ msgid ""
msgstr "Authentification requise pour renvoyer la phrase secrète au système."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-msgid "Manage system services or units"
+msgid "Manage system services or other units"
msgstr "Gérer les services système ou les unités"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-msgid "Authentication is required to manage system services or units."
+msgid "Authentication is required to manage system services or other units."
msgstr ""
"Authentification requise pour gérer les services système ou les unités."
@@ -46,10 +46,24 @@ msgstr ""
"unités."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr ""
+"Définir ou supprimer des variables d'environnement du système ou du "
+"gestionnaire de services"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Authentification requise pour définir ou supprimer des variables "
+"d'environnement du système ou du gestionnaire de services."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
msgid "Reload the systemd state"
msgstr "Recharger l'état de systemd"
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
msgid "Authentication is required to reload the systemd state."
msgstr "Authentification requise pour recharger l'état de systemd"
@@ -83,14 +97,34 @@ msgstr ""
"Authentification requise pour définir les informations sur la machine locale."
#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Importer une image de machine virtuelle (VM) ou de conteneur"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr ""
+"Authentification requise pour importer une image de machine virtuelle (VM) "
+"ou de conteneur."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Exporter une image de machine virtuelle (VM) ou de conteneur"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr ""
+"Authentification requise pour exporter une image de machine virtuelle (VM) "
+"ou de conteneur."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
msgid "Download a VM or container image"
msgstr "Télécharger une image de machine virtuelle (VM) ou de conteneur"
-#: ../src/import/org.freedesktop.import1.policy.in.h:2
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
msgid "Authentication is required to download a VM or container image"
msgstr ""
-"Authentification requise pour télécharger une image de "
-"machine virtuelle (VM) ou de conteneur."
+"Authentification requise pour télécharger une image de machine virtuelle "
+"(VM) ou de conteneur."
#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
msgid "Set system locale"
@@ -383,15 +417,73 @@ msgstr ""
"Authentification requise pour mettre le système en hibernation alors qu'une "
"application a demandé de l'empêcher."
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Gérer les sessions actives, les utilisateurs et les postes (seats)"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Authentification requise pour gérer les sessions actives, les utilisateurs "
+"et les postes (seats)."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Verrouiller ou déverrouiller des sessions actives"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr ""
+"Authentification requise pour verrouiller ou déverrouiller des sessions "
+"actives."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr ""
+"Permet d'indiquer au micrologiciel de démarrer sur l'interface de "
+"configuration"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr ""
+"Authentification requise pour indiquer au micrologiciel de démarrer sur "
+"l'interface de configuration."
+
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "Connexion dans un conteneur local"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
-msgid "Authentication is required to log into a local container"
+msgid "Authentication is required to log into a local container."
msgstr ""
"Authentification requise pour permettre la connexion dans un conteneur local."
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Manage local virtual machines and containers"
+msgstr "Gérer les machines virtuelles (VM) et conteneurs locaux"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Authentification requise pour gérer les machines virtuelles (VM) et les "
+"conteneurs locaux."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Manage local virtual machine and container images"
+msgstr "Gérer les images locales de machines virtuelles (VM) et de conteneurs"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Authentification requise pour gérer les images locales de machines "
+"virtuelles (VM) et de conteneurs."
+
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
msgstr "Définir l'heure du système"
@@ -433,3 +525,16 @@ msgid ""
msgstr ""
"Authentification requise pour activer ou désactiver la synchronisation de "
"l'heure avec le réseau."
+
+#: ../src/fsckd/fsckd.c:297
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+"Appuyez sur Ctrl+C pour annuler toutes vérifications en cours du système de "
+"fichiers"
+
+#: ../src/fsckd/fsckd.c:343
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Vérification en cours sur %d disque (%3.1f%% complété)"
+msgstr[1] "Vérification en cours sur %d disques (%3.1f%% complété)"
diff --git a/po/hu.po b/po/hu.po
index a914b3c73b..308e03d418 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -411,3 +411,14 @@ msgstr "A systemd állapotának újratöltése"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
msgid "Authentication is required to reload the systemd state."
msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez."
+
+#: ../src/fsckd/fsckd.c:186
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+
+#: ../src/fsckd/fsckd.c:227
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] ""
+msgstr[1] ""
diff --git a/po/it.po b/po/it.po
index 93a1e79b10..80ef7f5938 100644
--- a/po/it.po
+++ b/po/it.po
@@ -7,16 +7,67 @@ msgid ""
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-01-05 09:26+0100\n"
-"PO-Revision-Date: 2015-01-05 10:19+0100\n"
+"POT-Creation-Date: 2015-02-19 16:03+0100\n"
+"PO-Revision-Date: 2015-02-19 16:34+0100\n"
"Last-Translator: Daniele Medri <dmedri@gmail.com>\n"
"Language-Team: Italian\n"
"Language: it\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: Poedit 1.5.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 1.7.3\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Inviare la frase segreta (passphrase) al sistema"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr ""
+"Autenticazione richiesta per inviare la frase segreta (passphrase) al "
+"sistema."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "Gestisci i servizi o le altre unità di sistema"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr ""
+"Autenticazione richiesta per gestire i servizi o le altre unità di sistema."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Gestisci i file dei servizi o delle unità di sistema"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr ""
+"Autenticazione richiesta per gestire i file dei servizi o delle unità di "
+"sistema."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr ""
+"Configura le variabili d'ambiente per la gestione dei servizi e del sistema"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Autenticazione richiesta per configurare le variabili d'ambiente per la "
+"gestione dei servizi e del sistema"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "Riavviare lo stato di systemd"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "Autenticazione richiesta per riavviare lo stato di sistemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
msgid "Set host name"
@@ -48,6 +99,14 @@ msgstr ""
"Autenticazione richiesta per configurare le informazioni sulla macchina "
"locale."
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Download a VM or container image"
+msgstr "Scarica un'immagine VM o un container"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to download a VM or container image"
+msgstr "Autenticazione richiesta per scaricare un'immagine VM o un container"
+
#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
msgid "Set system locale"
msgstr "Configura le impostazioni regionali di sistema"
@@ -335,13 +394,54 @@ msgstr ""
"Autenticazione richiesta per ibernare il sistema mentre un'applicazione "
"chiede di inibirne l'azione."
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Gestione delle sessioni attive, utenti e postazioni"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Autenticazione richiesta per gestire le sessioni attive, gli utenti e le "
+"postazioni."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Blocca/sblocca sessioni attive"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr "Autenticazione richiesta per bloccare o sbloccare le sessioni attive."
+
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "Accedi in un container locale"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
-msgid "Authentication is required to log into a local container"
-msgstr "Autenticazione richiesta per accedere in un container locale"
+msgid "Authentication is required to log into a local container."
+msgstr "Autenticazione richiesta per accedere in un container locale."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Manage local virtual machines and containers"
+msgstr "Gestisci le virtual machine e i container locali"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Autenticazione richiesta per gestire le virtual machine e i container locali."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Manage local virtual machine and container images"
+msgstr "Gestisci le immagini locali delle virtual machine e dei container"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Autenticazione richiesta per gestire le immagini delle virtual machine e dei "
+"container locali."
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
@@ -385,42 +485,13 @@ msgstr ""
"Autenticazione richiesta per verificare se la sincronizzazione dell'orario "
"in rete possa essere attivata."
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
-msgid "Send passphrase back to system"
-msgstr "Inviare la frase segreta (passphrase) al sistema"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
-msgid ""
-"Authentication is required to send the entered passphrase back to the system."
-msgstr ""
-"Autenticazione richiesta per inviare la frase segreta (passphrase) al "
-"sistema."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-msgid "Manage system services or units"
-msgstr "Gestisci i servizi o le unità di sistema"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-msgid "Authentication is required to manage system services or units."
-msgstr "Autenticazione richiesta per gestire servizi e unità di sistema."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
-msgid "Manage system service or unit files"
-msgstr "Gestisci i file dei servizi o delle unità di sistema"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
-msgid "Authentication is required to manage system service or unit files."
-msgstr ""
-"Autenticazione richiesta per gestire i file dei servizi o delle unità di "
-"sistema."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
-msgid "Reload the systemd state"
-msgstr "Riavviare lo stato di systemd"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
-msgid "Authentication is required to reload the systemd state."
-msgstr "Autenticazione richiesta per riavviare lo stato di sistemd."
+#: ../src/fsckd/fsckd.c:186
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr "Premere Ctrl+C per annullare i controlli in corso sul filesystem"
-#~ msgid "Privileged system and service manager access"
-#~ msgstr "Accesso privilegiato per la gestione del sistema e dei servizi"
+#: ../src/fsckd/fsckd.c:227
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Controllo in corso sul disco %d (%3.1f%% completato)"
+msgstr[1] "Controllo in corso sui dischi %d (%3.1f%% completato)"
diff --git a/po/pl.po b/po/pl.po
index e5987be256..186f1d1561 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -6,14 +6,16 @@ msgid ""
msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-01-22 15:18+0100\n"
-"PO-Revision-Date: 2015-01-22 15:12+0100\n"
+"POT-Creation-Date: 2015-04-12 01:40+0200\n"
+"PO-Revision-Date: 2015-04-12 01:44+0200\n"
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
"Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
msgid "Send passphrase back to system"
@@ -27,14 +29,14 @@ msgstr ""
"systemu."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-msgid "Manage system services or units"
-msgstr "Zarządzanie usługami lub jednostkami systemu"
+msgid "Manage system services or other units"
+msgstr "Zarządzanie usługami lub innymi jednostkami systemu"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-msgid "Authentication is required to manage system services or units."
+msgid "Authentication is required to manage system services or other units."
msgstr ""
-"Wymagane jest uwierzytelnienie, aby zarządzać usługami lub jednostkami "
-"systemu."
+"Wymagane jest uwierzytelnienie, aby zarządzać usługami lub innymi "
+"jednostkami systemu."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
msgid "Manage system service or unit files"
@@ -47,10 +49,23 @@ msgstr ""
"systemu."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr ""
+"Ustawienie lub usunięcie zmiennych środowiskowych menedżera systemu i usług"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby ustawić lub usunąć zmienne środowiskowe "
+"menedżera systemu i usług."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
msgid "Reload the systemd state"
msgstr "Ponowne wczytanie stanu systemd"
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
msgid "Authentication is required to reload the systemd state."
msgstr "Wymagane jest uwierzytelnienie, aby ponownie wczytać stan systemd."
@@ -84,10 +99,30 @@ msgstr ""
"Wymagane jest uwierzytelnienie, aby ustawić informacje o lokalnym komputerze."
#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Import obrazu maszyny wirtualnej lub kontenera"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zaimportować obraz maszyny wirtualnej "
+"lub kontenera"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Eksport obrazu maszyny wirtualnej lub kontenera"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby wyeksportować obraz maszyny wirtualnej "
+"lub kontenera"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
msgid "Download a VM or container image"
msgstr "Pobranie obrazu maszyny wirtualnej lub kontenera"
-#: ../src/import/org.freedesktop.import1.policy.in.h:2
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
msgid "Authentication is required to download a VM or container image"
msgstr ""
"Wymagane jest uwierzytelnienie, aby pobrać obraz maszyny wirtualnej lub "
@@ -363,14 +398,69 @@ msgstr ""
"Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy program "
"zażądał jej wstrzymania."
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Zarządzanie aktywnymi sesjami, użytkownikami i stanowiskami"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zarządzać aktywnymi sesjami, "
+"użytkownikami i stanowiskami."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Zablokowanie lub odblokowanie aktywnych sesji"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zablokować lub odblokować aktywne sesje."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr "Wskazanie oprogramowaniu sprzętowemu, aby uruchomić interfejs ustawień"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby wskazać oprogramowaniu sprzętowemu, że "
+"należy uruchomić interfejs ustawień."
+
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "Logowanie do lokalnego kontenera"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
-msgid "Authentication is required to log into a local container"
+msgid "Authentication is required to log into a local container."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zalogować się do lokalnego kontenera."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Manage local virtual machines and containers"
+msgstr "Zarządzanie lokalnymi maszynami wirtualnymi i kontenerami"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
msgstr ""
-"Wymagane jest uwierzytelnienie, aby zalogować się do lokalnego kontenera"
+"Wymagane jest uwierzytelnienie, aby zarządzać lokalnymi maszynami "
+"wirtualnymi i kontenerami."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Manage local virtual machine and container images"
+msgstr "Zarządzanie lokalnymi obrazami maszyn wirtualnych i kontenerów"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby zarządzać lokalnymi obrazami maszyn "
+"wirtualnych i kontenerów."
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
@@ -411,3 +501,17 @@ msgid ""
msgstr ""
"Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
"czasu przez sieć."
+
+#: ../src/fsckd/fsckd.c:297
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+"Naciśnięcie klawiszy Ctrl+C anuluje wszystkie trwające procesy sprawdzania "
+"systemów plików"
+
+#: ../src/fsckd/fsckd.c:343
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Trwa sprawdzanie %d dysku (ukończono %3.1f%%)"
+msgstr[1] "Trwa sprawdzanie %d dysków (ukończono %3.1f%%)"
+msgstr[2] "Trwa sprawdzanie %d dysków (ukończono %3.1f%%)"
diff --git a/po/pt_BR.po b/po/pt_BR.po
index 5204047509..072b8d3379 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -419,3 +419,14 @@ msgstr "É necessária autenticação para recarregar o estado do sistema."
#~ msgid "Privileged system and service manager access"
#~ msgstr "Acesso privilegiado ao gerenciador de serviço e de sistema"
+
+#: ../src/fsckd/fsckd.c:186
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+
+#: ../src/fsckd/fsckd.c:227
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] ""
+msgstr[1] ""
diff --git a/po/ru.po b/po/ru.po
index 4dda60480b..76825135e5 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -7,12 +7,53 @@ msgstr ""
"Project-Id-Version: systemd\n"
"Report-Msgid-Bugs-To: 0comffdiz@inbox.ru\n"
"POT-Creation-Date: 2013-03-24 19:22+0300\n"
-"PO-Revision-Date: 2015-01-23 20:55+0300\n"
+"PO-Revision-Date: 2015-03-22 21:53+0300\n"
"Last-Translator: Sergey Ptashnick <0comffdiz@inbox.ru>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Отправить пароль системе"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid "Authentication is required to send the entered passphrase back to the system."
+msgstr "Чтобы отправить пароль системе, необходимо пройти аутентификацию."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or units"
+msgstr "Управление системными службами и юнитами"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or units."
+msgstr "Для управления системными службами и юнитами, необходимо пройти аутентификацию."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Управление файлами конфигурации системных служб и юнитов"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr "Для управления файлами конфигурации системных служб и юнитов, необходимо пройти аутентификацию."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr "Настроить переменные окружения для системного менеджера"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid "Authentication is required to set or unset system and service manager environment variables."
+msgstr "Чтобы настроить переменные окружения для системного менеджера, необходимо пройти аутентификацию."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "Перечитать конфигурацию systemd"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "Чтобы заставить systemd перечитать конфигурацию, необходимо пройти аутентификацию."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
msgid "Set host name"
@@ -39,10 +80,26 @@ msgid "Authentication is required to set local machine information."
msgstr "Чтобы настроить информацию о компьютере, необходимо пройти аутентификацию."
#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Импортировать образ виртуальной машины или контейнера"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr "Чтобы импортировать образ виртуальной машины или контейнера, необходимо пройти аутентификацию."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Экспортировать образ виртуальной машины или контейнера"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr "Чтобы экспортировать образ виртуальной машины или контейнера, необходимо пройти аутентификацию."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
msgid "Download a VM or container image"
msgstr "Загрузить образ виртуальной машины или контейнера"
-#: ../src/import/org.freedesktop.import1.policy.in.h:2
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
msgid "Authentication is required to download a VM or container image"
msgstr "Чтобы загрузить образ виртуальной машины или контейнера, необходимо пройти аутентификацию."
@@ -254,6 +311,22 @@ msgstr "Перевести систему в спящий режим, несмо
msgid "Authentication is required for hibernating the system while an application asked to inhibit it."
msgstr "Чтобы перевести систему в спящий режим, несмотря на то, что приложение запросило блокировку, необходимо пройти аутентификацию."
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Управление текущими сеансами, пользователями и рабочими местами"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid "Authentication is required for managing active sessions, users and seats."
+msgstr "Для управления текущими сеансами, пользователями и рабочими местами, необходимо пройти аутентификацию."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Заблокировать или разблокировать текущие сеансы"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr "Чтобы заблокировать или разблокировать текущие сеансы, необходимо пройти аутентификацию."
+
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "Зайти в локальный контейнер"
@@ -262,6 +335,22 @@ msgstr "Зайти в локальный контейнер"
msgid "Authentication is required to log into a local container."
msgstr "Чтобы зайти в локальный контейнер, необходимо пройти аутентификацию."
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Manage local virtual machines and containers"
+msgstr "Управление виртуальными машинами и контейнерами"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid "Authentication is required to manage local virtual machines and containers."
+msgstr "Для управления виртуальными машинами и контейнерами, необходимо пройти аутентификацию."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Manage local virtual machine and container images"
+msgstr "Управление образами виртуальных машин и контейнеров"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid "Authentication is required to manage local virtual machine and container images."
+msgstr "Для управления образами виртуальных машин и контейнеров, необходимо пройти аутентификацию."
+
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
msgstr "Настроить системное время"
@@ -294,34 +383,15 @@ msgstr "Включить или выключить синхронизацию в
msgid "Authentication is required to control whether network time synchronization shall be enabled."
msgstr "Чтобы включить или выключить синхронизацию времени по сети, необходимо пройти аутентификацию."
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
-msgid "Send passphrase back to system"
-msgstr "Отправить пароль системе"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
-msgid "Authentication is required to send the entered passphrase back to the system."
-msgstr "Чтобы отправить пароль системе, необходимо пройти аутентификацию."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-msgid "Manage system services or units"
-msgstr "Управление системными службами и юнитами"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-msgid "Authentication is required to manage system services or units."
-msgstr "Для управления системными службами и юнитами, необходимо пройти аутентификацию."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
-msgid "Manage system service or unit files"
-msgstr "Управление файлами конфигурации системных служб и юнитов"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
-msgid "Authentication is required to manage system service or unit files."
-msgstr "Для управления файлами конфигурации системных служб и юнитов, необходимо пройти аутентификацию."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
-msgid "Reload the systemd state"
-msgstr "Перечитать конфигурацию systemd"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
-msgid "Authentication is required to reload the systemd state."
-msgstr "Чтобы заставить systemd перечитать конфигурацию, необходимо пройти аутентификацию."
+#: ../src/fsckd/fsckd.c:297
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr "Чтобы прервать все запущенные проверки файловых систем, нажмите Ctrl+C"
+
+# There is no difference between "на 2 дисках" (plural==1) and "на 5 дисках" (plural==2)
+#: ../src/fsckd/fsckd.c:343
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Проверяется целостность файловой системы на %d диске (выполнено %3.1f%%)"
+msgstr[1] "Проверяется целостность файловых систем на %d дисках (выполнено %3.1f%%)"
+msgstr[2] "Проверяется целостность файловых систем на %d дисках (выполнено %3.1f%%)"
diff --git a/po/sv.po b/po/sv.po
index 25d4ae8251..f4c9f5d775 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -2,21 +2,70 @@
# Copyright © 2015 systemd's COPYRIGHT HOLDER
# This file is distributed under the same license as the systemd package.
# Josef Andersson <josef.andersson@fripost.org>, 2015.
+# Sebastian Rasmussen <sebras@gmail.com>, 2015.
msgid ""
msgstr ""
"Project-Id-Version: systemd master\n"
-"Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?product=sys"
-"temd&keywords=I18N+L10N&component=general\n"
-"POT-Creation-Date: 2015-01-04 11:43+0000\n"
-"PO-Revision-Date: 2015-01-05 13:38+0200\n"
-"Last-Translator: Josef Andersson <josef.andersson@fripost.org>\n"
+"Report-Msgid-Bugs-To: https://bugs.freedesktop.org/enter_bug.cgi?"
+"product=systemd&keywords=I18N+L10N&component=general\n"
+"POT-Creation-Date: 2015-03-13 23:56+0000\n"
+"PO-Revision-Date: 2015-03-14 11:09+0100\n"
+"Last-Translator: Sebastian Rasmussen <sebras@gmail.com>\n"
"Language-Team: Swedish\n"
"Language: sv\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: Virtaal 0.7.1\n"
+"X-Generator: Poedit 1.6.10\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Skicka tillbaka lösenfras till system"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr ""
+"Autentisering krävs för att skicka tillbaka den angivna lösenfrasen till "
+"systemet."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "Hantera systemtjänster eller andra enheter"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr ""
+"Autentisering krävs för att hantera systemtjänster eller andra enheter."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Hantera systemtjänster eller enhetsfiler"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr "Autentisering krävs för att hantera systemtjänster eller enhetsfiler."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr "Ställ in eller ta bort miljövariabler för system- och servicehanterare"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Autentisering krävs för att ställa in eller ta bort miljövariabler för "
+"system- och servicehanterare."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "Läs om tillståndet för systemd"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "Autentisering krävs för att läsa om tillståndet för systemd."
#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
msgid "Set host name"
@@ -46,6 +95,30 @@ msgstr "Ange datorinformation"
msgid "Authentication is required to set local machine information."
msgstr "Autentisering krävs för att ange lokal datorinformation."
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Importera en VM eller behållaravbildning"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr "Autentisering krävs för att importera en VM eller behållaravbildning"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Exportera en VM eller behållaravbildning"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr "Autentisering krävs för att exportera en VM eller behållaravbildning"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
+msgid "Download a VM or container image"
+msgstr "Hämta ner en VM eller behållaravbildning"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
+msgid "Authentication is required to download a VM or container image"
+msgstr "Autentisering krävs för att hämta ner en VM eller behållaravbildning"
+
#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
msgid "Set system locale"
msgstr "Ange systemlokal"
@@ -243,7 +316,7 @@ msgstr ""
#: ../src/login/org.freedesktop.login1.policy.in.h:35
msgid "Reboot the system while an application asked to inhibit it"
-msgstr "Starta om systemet även då ett program hindrar det."
+msgstr "Starta om systemet även då ett program hindrar det"
#: ../src/login/org.freedesktop.login1.policy.in.h:36
msgid ""
@@ -317,13 +390,53 @@ msgstr ""
"Autentisering krävs för att försätta ett program i viloläge även då ett "
"program hindrar det."
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Hantera aktiva sessioner, användare och platser"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Autentisering krävs för att hantera aktiva sessioner, användare och platser."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Lås eller lås upp aktiva sessioner"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr "Autentisering krävs för att låsa eller låsa upp aktiva sessioner."
+
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "Logga till en lokal behållare"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
-msgid "Authentication is required to log into a local container"
-msgstr "Autentisering krävs för att tillåta loggning till en lokal behållare."
+msgid "Authentication is required to log into a local container."
+msgstr "Autentisering krävs för att logga till en lokal behållare"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Manage local virtual machines and containers"
+msgstr "Hantera lokala virtuella maskiner och behållare"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Autentisering krävs för att hantera lokala virtuella maskiner och behållare."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Manage local virtual machine and container images"
+msgstr "Hantera lokala virtuella maskin- och behållaravbildningar"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Autentisering krävs för att hantera lokala virtuella maskin- och "
+"behållaravbildningar."
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
@@ -367,37 +480,13 @@ msgstr ""
"Autentisering krävs för att kontrollera huruvida synkronisering av "
"nätverkstid ska vara aktiverat."
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
-msgid "Send passphrase back to system"
-msgstr "Skicka tillbaka lösenfras till system"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
-msgid ""
-"Authentication is required to send the entered passphrase back to the system."
-msgstr ""
-"Autentisering krävs för att skicka tillbaka den angivna lösenfrasen till "
-"systemet."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-msgid "Manage system services or units"
-msgstr "Hantera systemtjänster eller enheter"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-msgid "Authentication is required to manage system services or units."
-msgstr "Autentisering krävs för att hantera systemtjänster eller enheter."
+#: ../src/fsckd/fsckd.c:291
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr "Tryck Ctrl+C för att avbryta alla pågående filsystemskontroller."
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
-msgid "Manage system service or unit files"
-msgstr "Hantera systemtjänster eller enhetsfiler"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
-msgid "Authentication is required to manage system service or unit files."
-msgstr "Autentisering krävs för att hantera systemtjänster eller enhetsfiler."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
-msgid "Reload the systemd state"
-msgstr "Läs om tillståndet för systemd"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
-msgid "Authentication is required to reload the systemd state."
-msgstr "Autentisering krävs för att läsa om tillståndet för systemd."
+#: ../src/fsckd/fsckd.c:336
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] "Kontroll pågår på %d disk (%3.1f%% klart)"
+msgstr[1] "Kontroll pågår på %d diskar (%3.1f%% klart)"
diff --git a/po/uk.po b/po/uk.po
index 6e32236c38..3603999f5d 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -375,3 +375,15 @@ msgstr "Привілейований доступ до менеджера сис
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
msgid "Authentication is required to access the system and service manager."
msgstr "Засвідчення потрібно, щоб доступитись до менеджера системи і служб."
+
+#: ../src/fsckd/fsckd.c:186
+msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+msgstr ""
+
+#: ../src/fsckd/fsckd.c:227
+#, c-format
+msgid "Checking in progress on %d disk (%3.1f%% complete)"
+msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
diff --git a/rules/42-usb-hid-pm.rules b/rules/42-usb-hid-pm.rules
index 4c300da8c8..3721219098 100644
--- a/rules/42-usb-hid-pm.rules
+++ b/rules/42-usb-hid-pm.rules
@@ -28,9 +28,9 @@ ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="14dd", ATTR{idProduct}=="0002"
# USB HID devices that are internal to the machine should also be safe to autosuspend
-ACTION=="add", SUBSYSTEM=="usb", SUBSYSTEMS=="usb", ATTRS{removable}=="removable", GOTO="usb_hid_pm_end"
-ACTION=="add", SUBSYSTEM=="usb", SUBSYSTEMS=="usb", ATTRS{removable}=="unknown", GOTO="usb_hid_pm_end"
+ACTION=="add", SUBSYSTEM=="usb", SUBSYSTEMS=="usb", ATTR{../removable}=="removable", GOTO="usb_hid_pm_end"
+ACTION=="add", SUBSYSTEM=="usb", SUBSYSTEMS=="usb", ATTR{../removable}=="unknown", GOTO="usb_hid_pm_end"
-ACTION=="add", SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="03", ATTRS{removable}=="fixed", TEST=="../power/control", ATTR{../power/control}="auto"
+ACTION=="add", SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="03", ATTR{../removable}=="fixed", TEST=="../power/control", ATTR{../power/control}="auto"
LABEL="usb_hid_pm_end"
diff --git a/rules/50-udev-default.rules b/rules/50-udev-default.rules
index 2bf9c1ec7e..e9eeb8518e 100644
--- a/rules/50-udev-default.rules
+++ b/rules/50-udev-default.rules
@@ -1,5 +1,9 @@
# do not edit this file, it will be overwritten on update
+# run a command on remove events
+ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
+ACTION=="remove", GOTO="default_end"
+
SUBSYSTEM=="virtio-ports", KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}"
# select "system RTC" or just use the first one
@@ -10,7 +14,7 @@ SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{b
SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
-ACTION!="add", GOTO="default_permissions_end"
+ACTION!="add", GOTO="default_end"
SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666"
SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666"
@@ -27,7 +31,6 @@ SUBSYSTEM=="input", GROUP="input"
SUBSYSTEM=="input", KERNEL=="js[0-9]*", MODE="0664"
SUBSYSTEM=="video4linux", GROUP="video"
-SUBSYSTEM=="misc", KERNEL=="agpgart", GROUP="video"
SUBSYSTEM=="graphics", GROUP="video"
SUBSYSTEM=="drm", GROUP="video"
SUBSYSTEM=="dvb", GROUP="video"
@@ -71,4 +74,4 @@ KERNEL=="tun", MODE="0666", OPTIONS+="static_node=net/tun"
KERNEL=="fuse", MODE="0666", OPTIONS+="static_node=fuse"
-LABEL="default_permissions_end"
+LABEL="default_end"
diff --git a/rules/60-block.rules b/rules/60-block.rules
new file mode 100644
index 0000000000..a69d648023
--- /dev/null
+++ b/rules/60-block.rules
@@ -0,0 +1,11 @@
+# do not edit this file, it will be overwritten on update
+
+# enable in-kernel media-presence polling
+ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_poll_msecs}=="0", \
+ ATTR{parameters/events_dfl_poll_msecs}="2000"
+
+# forward scsi device event to corresponding block device
+ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
+
+# watch metadata changes, caused by tools closing the device node which was opened for writing
+ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*", OPTIONS+="watch"
diff --git a/rules/60-evdev.rules b/rules/60-evdev.rules
new file mode 100644
index 0000000000..ade7e7f646
--- /dev/null
+++ b/rules/60-evdev.rules
@@ -0,0 +1,19 @@
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="evdev_end"
+KERNEL!="event*", GOTO="evdev_end"
+
+# skip later rules when we find something for this input device
+IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=evdev:", \
+ RUN{builtin}+="keyboard", GOTO="evdev_end"
+
+# AT keyboard matching by the machine's DMI data
+ENV{ID_INPUT_KEY}=="?*", DRIVERS=="atkbd", \
+ IMPORT{builtin}="hwdb 'evdev:atkbd:$attr{[dmi/id]modalias}'", \
+ RUN{builtin}+="keyboard", GOTO="evdev_end"
+
+# device matching the input device name and the machine's DMI data
+KERNELS=="input*", IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:$attr{[dmi/id]modalias}'", \
+ RUN{builtin}+="keyboard", GOTO="evdev_end"
+
+LABEL="evdev_end"
diff --git a/rules/60-keyboard.rules b/rules/60-keyboard.rules
deleted file mode 100644
index 22f71e7792..0000000000
--- a/rules/60-keyboard.rules
+++ /dev/null
@@ -1,22 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-ACTION=="remove", GOTO="keyboard_end"
-KERNEL!="event*", GOTO="keyboard_end"
-ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end"
-
-# ignore all bluetooth devices
-SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"
-
-# import key mapping for USB device
-SUBSYSTEMS=="usb", IMPORT{builtin}="hwdb --subsystem=usb --lookup-prefix=keyboard:", \
- RUN{builtin}+="keyboard", GOTO="keyboard_end"
-
-# import key mapping for AT keyboard from DMI data
-DRIVERS=="atkbd", IMPORT{builtin}="hwdb 'keyboard:$attr{[dmi/id]modalias}'", \
- RUN{builtin}+="keyboard", GOTO="keyboard_end"
-
-# import key mapping for platform input device
-KERNELS=="input*", IMPORT{builtin}="hwdb 'keyboard:name:$attr{name}:$attr{[dmi/id]modalias}'", \
- RUN{builtin}+="keyboard", GOTO="keyboard_end"
-
-LABEL="keyboard_end"
diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules
index 25b44a55cb..64c5f1cfdd 100644
--- a/rules/60-persistent-storage.rules
+++ b/rules/60-persistent-storage.rules
@@ -3,18 +3,10 @@
# persistent storage links: /dev/disk/{by-id,by-uuid,by-label,by-path}
# scheme based on "Linux persistent device names", 2004, Hannes Reinecke <hare@suse.de>
-# forward scsi device event to corresponding block device
-ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
-
ACTION=="remove", GOTO="persistent_storage_end"
-# enable in-kernel media-presence polling
-ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_poll_msecs}=="0", ATTR{parameters/events_dfl_poll_msecs}="2000"
-
SUBSYSTEM!="block", GOTO="persistent_storage_end"
-
-# skip rules for inappropriate block devices
-KERNEL=="fd*|mtd*|nbd*|gnbd*|btibm*|dm-*|md*|zram*|mmcblk[0-9]*rpmb", GOTO="persistent_storage_end"
+KERNEL!="loop*|mmcblk*[0-9]|msblk*[0-9]|mspblk*[0-9]|nvme*|sd*|sr*|vd*|bcache*|xvd*", GOTO="persistent_storage_end"
# ignore partitions that span the entire disk
TEST=="whole_disk", GOTO="persistent_storage_end"
@@ -26,39 +18,42 @@ ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*"
KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"
KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n"
-# ATA devices using the "scsi" subsystem
+# ATA
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", IMPORT{program}="ata_id --export $devnode"
-# ATA/ATAPI devices (SPC-3 or later) using the "scsi" subsystem
+
+# ATAPI devices (SPC-3 or later)
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", IMPORT{program}="ata_id --export $devnode"
# Run ata_id on non-removable USB Mass Storage (SATA/PATA disks in enclosures)
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=="usb", IMPORT{program}="ata_id --export $devnode"
-# Otherwise, fall back to using usb_id for USB devices
+
+# Fall back usb_id for USB devices
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
-# scsi devices
+# SCSI devices
KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi"
-KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss"
-KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
-KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
+KERNEL=="sd*|sr*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
+KERNEL=="sd*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
-# firewire
+# FireWire
KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}"
KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n"
-KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}"
+# MMC
+KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ATTRS{serial}=="?*", \
+ ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}"
KERNEL=="mmcblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
-KERNEL=="mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"
-KERNEL=="mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
-# by-path (parent device path)
+# Memstick
+KERNEL=="msblk[0-9]|mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", \
+ ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"
+KERNEL=="msblk[0-9]p[0-9]|mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
+
+# by-path
ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id"
ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
-# skip unpartitioned removable media devices from drivers which do not send "change" events
-ENV{DEVTYPE}=="disk", KERNEL!="sd*|sr*", ATTR{removable}=="1", GOTO="persistent_storage_end"
-
# probe filesystem metadata of optical drives which have a media inserted
KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \
IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}"
@@ -69,9 +64,6 @@ KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DAT
# probe filesystem metadata of disks
KERNEL!="sr*", IMPORT{builtin}="blkid"
-# watch metadata changes by tools closing the device after writing
-KERNEL!="sr*", OPTIONS+="watch"
-
# by-label/by-uuid links (filesystem metadata)
ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
diff --git a/rules/60-persistent-serial.rules b/rules/60-serial.rules
index 2948200c53..f303e27fd5 100644
--- a/rules/60-persistent-serial.rules
+++ b/rules/60-serial.rules
@@ -1,8 +1,14 @@
# do not edit this file, it will be overwritten on update
-ACTION=="remove", GOTO="persistent_serial_end"
-SUBSYSTEM!="tty", GOTO="persistent_serial_end"
-KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="persistent_serial_end"
+ACTION=="remove", GOTO="serial_end"
+SUBSYSTEM!="tty", GOTO="serial_end"
+
+SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
+SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
+SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
+
+# /dev/serial/by-path/, /dev/serial/by-id/ for USB devices
+KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="serial_end"
SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}"
@@ -11,10 +17,10 @@ ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="", SYMLINK+="serial/by-path/$env{ID_PATH}"
ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-path/$env{ID_PATH}-port$env{.ID_PORT}"
IMPORT{builtin}="usb_id"
-ENV{ID_SERIAL}=="", GOTO="persistent_serial_end"
+ENV{ID_SERIAL}=="", GOTO="serial_end"
SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACE_NUM}="$attr{bInterfaceNumber}"
-ENV{ID_USB_INTERFACE_NUM}=="", GOTO="persistent_serial_end"
+ENV{ID_USB_INTERFACE_NUM}=="", GOTO="serial_end"
ENV{.ID_PORT}=="", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}"
ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}-port$env{.ID_PORT}"
-LABEL="persistent_serial_end"
+LABEL="serial_end"
diff --git a/rules/75-tty-description.rules b/rules/75-tty-description.rules
deleted file mode 100644
index 11277b7d6f..0000000000
--- a/rules/75-tty-description.rules
+++ /dev/null
@@ -1,12 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-ACTION=="remove", GOTO="tty_end"
-SUBSYSTEM!="tty", GOTO="tty_end"
-
-SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
-SUBSYSTEMS=="usb", GOTO="tty_end"
-
-SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
-SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"
-
-LABEL="tty_end"
diff --git a/rules/78-sound-card.rules b/rules/78-sound-card.rules
index 295f490150..04740e8b97 100644
--- a/rules/78-sound-card.rules
+++ b/rules/78-sound-card.rules
@@ -41,16 +41,19 @@ IMPORT{builtin}="hwdb"
SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
SUBSYSTEMS=="usb", GOTO="skip_pci"
-SUBSYSTEMS=="firewire", ATTRS{vendor_name}=="?*", ATTRS{model_name}=="?*", \
- ENV{ID_BUS}="firewire", ENV{ID_VENDOR}="$attr{vendor_name}", ENV{ID_MODEL}="$attr{model_name}"
-SUBSYSTEMS=="firewire", ATTRS{guid}=="?*", ENV{ID_ID}="firewire-$attr{guid}"
+SUBSYSTEMS=="firewire", ATTRS{guid}=="?*", \
+ ENV{ID_BUS}="firewire", ENV{ID_SERIAL}="$attr{guid}", ENV{ID_SERIAL_SHORT}="$attr{guid}", \
+ ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{model}", \
+ ENV{ID_VENDOR}="$attr{vendor_name}", ENV{ID_MODEL}="$attr{model_name}"
SUBSYSTEMS=="firewire", GOTO="skip_pci"
SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
LABEL="skip_pci"
-ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}-$attr{id}"
-ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$attr{id}"
+# Define ID_ID if ID_BUS and ID_SERIAL are set. This will work for both
+# USB and firewire.
+ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}"
+ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}"
IMPORT{builtin}="path_id"
diff --git a/rules/95-udev-late.rules b/rules/95-udev-late.rules
deleted file mode 100644
index eca0faa5c5..0000000000
--- a/rules/95-udev-late.rules
+++ /dev/null
@@ -1,4 +0,0 @@
-# do not edit this file, it will be overwritten on update
-
-# run a command on remove events
-ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in
index b66d727a48..10b90b8133 100644
--- a/rules/99-systemd.rules.in
+++ b/rules/99-systemd.rules.in
@@ -8,15 +8,14 @@
ACTION=="remove", GOTO="systemd_end"
SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270/tty[0-9]*", TAG+="systemd"
-
KERNEL=="vport*", TAG+="systemd"
-SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd"
-SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", TAG+="systemd"
+SUBSYSTEM=="block", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
# Ignore encrypted devices with no identified superblock on it, since
# we are probably still calling mke2fs or mkswap on it.
-SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
# Ignore raid devices that are not yet assembled and started
SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0"
@@ -29,15 +28,13 @@ SUBSYSTEM=="block", KERNEL=="loop[0-9]*", ENV{DEVTYPE}=="disk", TEST!="loop/back
ACTION=="add", SUBSYSTEM=="block", KERNEL=="nbd*", ENV{SYSTEMD_READY}="0"
# We need a hardware independent way to identify network devices. We
-# use the /sys/subsystem path for this. Current vanilla kernels don't
-# actually support that hierarchy right now, however upcoming kernels
-# will. HAL and udev internally support /sys/subsystem already, hence
-# it should be safe to use this here, too. This is mostly just an
-# identification string for systemd, so whether the path actually is
+# use the /sys/subsystem/ path for this. Kernel "bus" and "class" names
+# should be treated as one namespace, like udev handles it. This is mostly
+# just an identification string for systemd, so whether the path actually is
# accessible or not does not matter as long as it is unique and in the
# filesystem namespace.
#
-# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n922
+# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n955
SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name"
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k"
@@ -51,12 +48,10 @@ SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.ta
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"
# Apply sysctl variables to network devices (and only to those) as they appear.
-
ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/net/ipv4/conf/$name --prefix=/net/ipv4/neigh/$name --prefix=/net/ipv6/conf/$name --prefix=/net/ipv6/neigh/$name"
# Pull in backlight save/restore for all backlight devices and
# keyboard backlights
-
SUBSYSTEM=="backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@backlight:$name.service"
SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@leds:$name.service"
@@ -64,9 +59,7 @@ SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="pa
SUBSYSTEM=="rfkill", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/rfkill/devices/%k", ENV{SYSTEMD_WANTS}+="systemd-rfkill@$name.service"
-# Asynchronously mount file systems implemented by these modules as
-# soon as they are loaded.
-
+# Asynchronously mount file systems implemented by these modules as soon as they are loaded.
SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount"
SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount"
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
index 8063316ec6..c2707ba3a6 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -90,10 +90,10 @@ _systemctl () {
local i verb comps mode
local -A OPTS=(
- [STANDALONE]='--all -a --reverse --after --before --defaults --fail --ignore-dependencies --failed --force -f --full -l --global
+ [STANDALONE]='--all -a --reverse --after --before --defaults --failed --force -f --full -l --global
--help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall
- --quiet -q --privileged -P --system --user --version --runtime --recursive -r'
- [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root'
+ --quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware-setup'
+ [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root'
)
if __contains_word "--user" ${COMP_WORDS[*]}; then
@@ -115,6 +115,10 @@ _systemctl () {
active inactive
dead elapsed exited listening mounted plugged running waiting'
;;
+ --job-mode)
+ comps='fail replace replace-irreversibly isolate
+ ignore-dependencies ignore-requirements flush'
+ ;;
--kill-who)
comps='all control main'
;;
@@ -160,7 +164,7 @@ _systemctl () {
reboot rescue show-environment suspend get-default
is-system-running'
[NAME]='snapshot'
- [FILE]='link'
+ [FILE]='link switch-root'
[TARGETS]='set-default'
)
diff --git a/shell-completion/zsh/_bootctl b/shell-completion/zsh/_bootctl
index 7d2453cc2c..0e1b0a5562 100644
--- a/shell-completion/zsh/_bootctl
+++ b/shell-completion/zsh/_bootctl
@@ -4,7 +4,10 @@
{
local -a _bootctl_cmds
_bootctl_cmds=(
- "status:Show current firmware and boot settings"
+ "status:Show status of installed systemd-boot and EFI variables"
+ "install:Install systemd-boot to the ESP and EFI variables"
+ "update:Update systemd-boot in the ESP and EFI variables"
+ "remove:Remove systemd-boot from the ESP and EFI variables"
)
if (( CURRENT == 1 )); then
_describe -t commands 'bootctl command' _bootctl_cmds || compadd "$@"
@@ -22,4 +25,6 @@
_arguments \
{-h,--help}'[Prints a short help text and exits.]' \
'--version[Prints a short version string and exits.]' \
+ '--path=[Path to the EFI System Partition (ESP)]:path:_directories' \
+ '--no-variables[Do not touch EFI variables]' \
'*::bootctl command:_bootctl_command'
diff --git a/shell-completion/zsh/_hostnamectl b/shell-completion/zsh/_hostnamectl
index a7217a1999..7528e0649d 100644
--- a/shell-completion/zsh/_hostnamectl
+++ b/shell-completion/zsh/_hostnamectl
@@ -33,6 +33,14 @@ _hostnamectl_set-deployment() {
fi
}
+_hostnamectl_set-location() {
+ if (( CURRENT <= 3 )); then
+ _message "new location"
+ else
+ _message "no more options"
+ fi
+}
+
_hostnamectl_command() {
local -a _hostnamectl_cmds
_hostnamectl_cmds=(
@@ -40,7 +48,8 @@ _hostnamectl_command() {
"set-hostname:Set system hostname"
"set-icon-name:Set icon name for host"
"set-chassis:Set chassis type for host"
- "set-deployment:Set deployment environment"
+ "set-deployment:Set deployment environment for host"
+ "set-location:Set location for host"
)
if (( CURRENT == 1 )); then
_describe -t commands 'hostnamectl commands' _hostnamectl_cmds || compadd "$@"
@@ -67,4 +76,5 @@ _arguments -s \
'--pretty[Only set pretty hostname]' \
'--no-ask-password[Do not prompt for password]' \
{-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \
+ {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \
'*::hostnamectl commands:_hostnamectl_command'
diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl
index a469bbc9a7..863348e050 100644
--- a/shell-completion/zsh/_journalctl
+++ b/shell-completion/zsh/_journalctl
@@ -76,6 +76,7 @@ _arguments -s \
{-F,--field=}'[List all values a certain field takes]:Fields:_list_fields' \
'--system[Show system and kernel messages]' \
'--user[Show messages from user services]' \
+ {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \
{-D+,--directory=}'[Show journal files from directory]:directories:_directories' \
'--file=[Operate on specified journal files]:file:_files' \
'--root=[Operate on catalog hierarchy under specified directory]:directories:_directories' \
diff --git a/shell-completion/zsh/_loginctl b/shell-completion/zsh/_loginctl
index 0de66e191f..bd33b66fae 100644
--- a/shell-completion/zsh/_loginctl
+++ b/shell-completion/zsh/_loginctl
@@ -102,10 +102,11 @@ _arguments -s \
'--kill-who=[Who to send signal to]:killwho:(main control all)' \
{-s+,--signal=}'[Which signal to send]:signal:_signals' \
{-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \
- {-M+,--machine=}'[Operate on local container]:machine' \
- {-P,--privileged}'[Acquire privileges before execution]' \
+ {-M+,--machine=}'[Operate on local container]:machine:_sd_machines' \
{-l,--full}'[Do not ellipsize output]' \
'--no-pager[Do not pipe output into a pager]' \
'--no-legend[Do not show the headers and footers]' \
'--no-ask-password[Do not ask for system passwords]' \
+ {-n+,--lines=}'[Number of journal entries to show]' \
+ {-o+,--output=}'[Change journal output mode]:output modes:_sd_outputmodes' \
'*::loginctl command:_loginctl_command'
diff --git a/shell-completion/zsh/_machinectl b/shell-completion/zsh/_machinectl
index c666b7eb43..7898d7c05b 100644
--- a/shell-completion/zsh/_machinectl
+++ b/shell-completion/zsh/_machinectl
@@ -1,5 +1,20 @@
#compdef machinectl
+__get_available_machines () {
+ machinectl --no-legend list-images | {while read -r a b; do echo $a; done;}
+}
+
+_available_machines() {
+ local -a _machines
+ _machines=("${(fo)$(__get_available_machines)}")
+ typeset -U _machines
+ if [[ -n "$_machines" ]]; then
+ _describe 'machines' _machines
+ else
+ _message 'no machines'
+ fi
+}
+
(( $+functions[_machinectl_command] )) || _machinectl_command()
{
local -a _machinectl_cmds
@@ -7,23 +22,55 @@
"list:List currently running VMs/containers"
"status:Show VM/container status"
"show:Show properties of one or more VMs/containers"
+ "start:Start container as a service"
"login:Get a login prompt on a VM/container"
+ "enable:Enable automatic container start at boot"
+ "disable:Disable automatic container start at boot"
"poweroff:Power off one or more VMs/containers"
"reboot:Reboot one or more VMs/containers"
"terminate:Terminate one or more VMs/containers"
"kill:Send signal to process or a VM/container"
+ "copy-to:Copy files from the host to a container"
+ "copy-from:Copy files from a container to the host"
+ "bind:Bind mount a path from the host into a container"
+
+ "list-images:Show available container and VM images"
+ "image-status:Show image details"
+ "show-image:Show properties of image"
+ "clone:Clone an image"
+ "rename:Rename an image"
+ "read-only:Mark or unmark image read-only"
+ "remove:Remove an image"
+
+ "pull-tar:Download a TAR container image"
+ "pull-raw:Download a RAW container or VM image"
+ "pull-dkr:Download a DKR container image"
+ "list-transfers:Show list of downloads in progress"
+ "cancel-transfer:Cancel a download"
)
+
if (( CURRENT == 1 )); then
_describe -t commands 'machinectl command' _machinectl_cmds || compadd "$@"
else
local curcontext="$curcontext"
cmd="${${_machinectl_cmds[(r)$words[1]:*]%%:*}}"
if (( $#cmd )); then
- case $cmd in
- list) msg="no options" ;;
- *)
- _sd_machines
- esac
+ if (( CURRENT == 2 )); then
+ case $cmd in
+ list*|cancel-transfer|pull-tar|pull-raw|pull-dkr)
+ msg="no options" ;;
+ start)
+ _available_machines ;;
+ *)
+ _sd_machines
+ esac
+ else
+ case $cmd in
+ copy-to|copy-from|bind)
+ _files ;;
+ *) msg="no options"
+ esac
+ fi
else
_message "no more options"
fi
@@ -33,13 +80,22 @@
_arguments \
{-h,--help}'[Prints a short help text and exits.]' \
'--version[Prints a short version string and exits.]' \
- \*{-p+,--property=}'[Limit output to specified property.]:property:(Name Id Timestamp TimestampMonotonic Service Scope Leader Class State RootDirectory)' \
- {-a,--all}'[Show all proerties]' \
- (-l,--full)'[Do not ellipsize cgroup members]' \
- '--no-pager[Do not pipe output into a pager]' \
- '--no-ask-password[Do not ask for system passwords]' \
- '--kill-who=[Who to send signal to]:killwho:(leader all)' \
- {-s+,--signal=}'[Which signal to send]:signal:_signals' \
- {-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \
- {-P,--privileged}'[Acquire privileges before execution]' \
+ '--no-pager[Do not pipe output into a pager.]' \
+ '--no-legend[Do not show the headers and footers.]' \
+ '--no-ask-password[Do not ask for system passwords.]' \
+ {-H+,--host=}'[Operate on remote host.]:userathost:_sd_hosts_or_user_at_host' \
+ {-M+,--machine=}'[Operate on local container.]:machine:_sd_machines' \
+ {-p+,--property=}'[Limit output to specified property.]:property:(Name Id Timestamp TimestampMonotonic Service Scope Leader Class State RootDirectory)' \
+ {-a,--all}'[Show all proerties.]' \
+ {-q,--quiet}'[Suppress output.]' \
+ {-l,--full}'[Do not ellipsize cgroup members.]' \
+ '--kill-who=[Who to send signal to.]:killwho:(leader all)' \
+ {-s+,--signal=}'[Which signal to send.]:signal:_signals' \
+ '--read-only[Create read-only bind mount.]' \
+ '--mkdir[Create directory before bind mounting, if missing.]' \
+ {-n+,--lines=}'[Number of journal entries to show.]:integer' \
+ {-o+,--output=}'[Change journal output mode.]:output modes:_sd_outputmodes' \
+ '--verify=[Verification mode for downloaded images.]:verify:(no checksum signature)' \
+ '--force[Download image even if already exists.]' \
+ '--dkr-index-url=[Specify the index URL to use for DKR image downloads.]' \
'*::machinectl command:_machinectl_command'
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 7f2d5ac0fa..17736de01c 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -59,12 +59,13 @@
"reboot:Shut down and reboot the system"
"kexec:Shut down and reboot the system with kexec"
"exit:Ask for user instance termination"
+ "switch-root:Change root directory"
)
if (( CURRENT == 1 )); then
_describe -t commands 'systemctl command' _systemctl_cmds || compadd "$@"
else
- local curcontext="$curcontext"
+ local curcontext="$curcontext" expl
cmd="${${_systemctl_cmds[(r)$words[1]:*]%%:*}}"
# Deal with any aliases
@@ -92,9 +93,7 @@
__systemctl()
{
- local -a _modes
- _modes=("--user" "--system")
- systemctl ${words:*_modes} --full --no-legend --no-pager "$@"
+ systemctl $_sys_service_mgr --full --no-legend --no-pager "$@"
}
@@ -104,7 +103,7 @@ _systemctl_all_units()
if ( [[ ${+_sys_all_units} -eq 0 ]] || _cache_invalid SYS_ALL_UNITS ) &&
! _retrieve_cache SYS_ALL_UNITS;
then
- _sys_all_units=( $(__systemctl list-units --all | { while read -r a b; do echo -E - " $a"; done; }) )
+ _sys_all_units=( ${${(f)"$(__systemctl list-units --all)"}%% *} )
_store_cache SYS_ALL_UNITS _sys_all_units
fi
}
@@ -117,7 +116,7 @@ _systemctl_really_all_units()
if ( [[ ${+_sys_really_all_units} -eq 0 ]] || _cache_invalid SYS_REALLY_ALL_UNITS ) &&
! _retrieve_cache SYS_REALLY_ALL_UNITS;
then
- all_unit_files=( $(__systemctl list-unit-files | { while read -r a b; do echo -E - " $a"; done; }) )
+ all_unit_files=( ${${(f)"$(__systemctl list-unit-files)"}%% *} )
_systemctl_all_units
really_all_units=($_sys_all_units $all_unit_files)
_sys_really_all_units=(${(u)really_all_units})
@@ -142,84 +141,89 @@ _filter_units_by_property() {
done
}
-_systemctl_get_template_names() { __systemctl list-unit-files | { while read -r a b; do [[ $a =~ @\. ]] && echo -E - " ${a%%@.*}@"; done; } }
+_systemctl_get_template_names() { echo -E - ${^${(M)${(f)"$(__systemctl list-unit-files)"}##*@.[^[:space:]]##}%%@.*}\@ }
-_systemctl_active_units() {_sys_active_units=( $(__systemctl list-units | { while read -r a b; do echo -E - " $a"; done; }) )}
+_systemctl_active_units() {_sys_active_units=( ${${(f)"$(__systemctl list-units)"}%% *} )}
_systemctl_startable_units(){
- _sys_startable_units=(_filter_units_by_property ActiveState inactive $(
+ _sys_startable_units=( $( _filter_units_by_property ActiveState inactive $(
_filter_units_by_property CanStart yes $(
__systemctl $mode list-unit-files --state enabled,disabled,static | \
{ while read -r a b; do [[ $a =~ @\. ]] || echo -E - " $a"; done; }
__systemctl $mode list-units --state inactive,failed | \
- { while read -r a b; do echo -E - " $a"; done; } )))
+ { while read -r a b; do echo -E - " $a"; done; } )) ) )
}
_systemctl_restartable_units(){
- _sys_restartable_units=(_filter_units_by_property CanStart yes $(
+ _sys_restartable_units=( $(_filter_units_by_property CanStart yes $(
__systemctl $mode list-unit-files --state enabled,disabled,static | \
{ while read -r a b; do [[ $a =~ @\. ]] || echo -E - " $a"; done; }
__systemctl $mode list-units | \
- { while read -r a b; do echo -E - " $a"; done; } ))
+ { while read -r a b; do echo -E - " $a"; done; } )) )
}
-_systemctl_failed_units() {_sys_failed_units=( $(__systemctl list-units --failed | { while read -r a b; do echo -E - " $a"; done; }) )}
-_systemctl_enabled_units() {_sys_enabled_units=( $(__systemctl list-unit-files | { while read -r a b; do [[ $b == "enabled" ]] && echo -E - " $a"; done; }) )}
-_systemctl_disabled_units(){_sys_disabled_units=($(__systemctl list-unit-files | { while read -r a b; do [[ $b == "disabled" ]] && echo -E - " $a"; done; }) )}
-_systemctl_masked_units() {_sys_masked_units=( $(__systemctl list-unit-files | { while read -r a b; do [[ $b == "masked" ]] && echo -E - " $a"; done; }) )}
+_systemctl_failed_units() {_sys_failed_units=( ${${(f)"$(__systemctl list-units --failed)"}%% *} ) }
+_systemctl_unit_state() { typeset -gA _sys_unit_state; _sys_unit_state=( $(__systemctl list-unit-files) ) }
+local fun
# Completion functions for ALL_UNITS
for fun in is-active is-failed is-enabled status show cat mask preset help list-dependencies edit ; do
(( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
{
_systemctl_really_all_units
- compadd "$@" -a - _sys_really_all_units
+ _wanted systemd-units expl unit \
+ compadd "$@" -a - _sys_really_all_units
}
done
# Completion functions for ENABLED_UNITS
(( $+functions[_systemctl_disable] )) || _systemctl_disable()
{
- _systemctl_enabled_units
- compadd "$@" -a - _sys_enabled_units
+ local _sys_unit_state; _systemctl_unit_state
+ _wanted systemd-units expl 'enabled unit' \
+ compadd "$@" - ${(k)_sys_unit_state[(R)enabled]}
}
(( $+functions[_systemctl_reenable] )) || _systemctl_reenable()
{
- _systemctl_enabled_units
- _systemctl_disabled_units
- compadd "$@" -a - _sys_enabled_units _sys_disabled_units $(_systemctl_get_template_names)
+ local _sys_unit_state; _systemctl_unit_state
+ _wanted systemd-units expl 'enabled/disabled unit' \
+ compadd "$@" - ${(k)_sys_unit_state[(R)(enabled|disabled)]} $(_systemctl_get_template_names)
}
# Completion functions for DISABLED_UNITS
(( $+functions[_systemctl_enable] )) || _systemctl_enable()
{
- _systemctl_disabled_units
- compadd "$@" -a - _sys_disabled_units $(_systemctl_get_template_names)
+ local _sys_unit_state; _systemctl_unit_state
+ _wanted systemd-units expl 'disabled unit' \
+ compadd "$@" - ${(k)_sys_unit_state[(R)disabled]} $(_systemctl_get_template_names)
}
# Completion functions for FAILED_UNITS
(( $+functions[_systemctl_reset-failed] )) || _systemctl_reset-failed()
{
- _systemctl_failed_units
- compadd "$@" -a - _sys_failed_units || _message "no failed unit found"
+ local _sys_failed_units; _systemctl_failed_units
+ _wanted systemd-units expl 'failed unit' \
+ compadd "$@" -a - _sys_failed_units || _message "no failed unit found"
}
# Completion functions for STARTABLE_UNITS
(( $+functions[_systemctl_start] )) || _systemctl_start()
{
- _systemctl_startable_units
- compadd "$@" - ${_sys_startable_units[*]} $(_systemctl_get_template_names)
+ local _sys_startable_units; _systemctl_startable_units
+ _wanted systemd-units expl 'startable unit' \
+ compadd "$@" - ${_sys_startable_units[*]} $(_systemctl_get_template_names)
}
# Completion functions for STOPPABLE_UNITS
for fun in stop kill try-restart condrestart ; do
(( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
{
- _systemctl_active_units
- compadd "$@" - $( _filter_units_by_property CanStop yes \
- ${_sys_active_units[*]} )
+ local _sys_active_units; _systemctl_active_units
+ _wanted systemd-units expl 'stoppable unit' \
+ compadd "$@" - $( _filter_units_by_property CanStop yes \
+ ${_sys_active_units[*]} )
}
done
@@ -227,17 +231,19 @@ done
(( $+functions[_systemctl_isolate] )) || _systemctl_isolate()
{
_systemctl_all_units
- compadd "$@" - $( _filter_units_by_property AllowIsolate yes \
- ${_sys_all_units[*]} )
+ _wanted systemd-units expl 'isolatable unit' \
+ compadd "$@" - $( _filter_units_by_property AllowIsolate yes \
+ ${_sys_all_units[*]} )
}
# Completion functions for RELOADABLE_UNITS
for fun in reload reload-or-try-restart force-reload ; do
(( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
{
- _systemctl_active_units
- compadd "$@" - $( _filter_units_by_property CanReload yes \
- ${_sys_active_units[*]} )
+ local _sys_active_units; _systemctl_active_units
+ _wanted systemd-units expl 'reloadable unit' \
+ compadd "$@" - $( _filter_units_by_property CanReload yes \
+ ${_sys_active_units[*]} )
}
done
@@ -245,37 +251,42 @@ done
for fun in restart reload-or-restart ; do
(( $+functions[_systemctl_$fun] )) || _systemctl_$fun()
{
- _systemctl_restartable_units
- compadd "$@" - ${_sys_restartable_units[*]} $(_systemctl_get_template_names)
+ local _sys_restartable_units; _systemctl_restartable_units
+ _wanted systemd-units expl 'restartable unit' \
+ compadd "$@" - ${_sys_restartable_units[*]} $(_systemctl_get_template_names)
}
done
# Completion functions for MASKED_UNITS
(( $+functions[_systemctl_unmask] )) || _systemctl_unmask()
{
- _systemctl_masked_units
- compadd "$@" -a - _sys_masked_units || _message "no masked units found"
+ local _sys_unit_state; _systemctl_unit_state
+ _wanted systemd-units expl 'masked unit' \
+ compadd "$@" - ${(k)_sys_unit_state[(R)masked]} || _message "no masked units found"
}
# Completion functions for JOBS
(( $+functions[_systemctl_cancel] )) || _systemctl_cancel()
{
- compadd "$@" - $(__systemctl list-jobs \
- | cut -d' ' -f1 2>/dev/null ) || _message "no jobs found"
+ _wanted systemd-jobs expl job \
+ compadd "$@" - ${${(f)"$(__systemctl list-jobs)"}%% *} ||
+ _message "no jobs found"
}
# Completion functions for SNAPSHOTS
(( $+functions[_systemctl_delete] )) || _systemctl_delete()
{
- compadd "$@" - $(__systemctl list-units --type snapshot --all \
- | cut -d' ' -f1 2>/dev/null ) || _message "no snapshots found"
+ _wanted systemd-snapshots expl snapshot \
+ compadd "$@" - ${${(f)"$(__systemctl list-units --type snapshot --all)"}%% *} ||
+ _message "no snapshots found"
}
# Completion functions for TARGETS
(( $+functions[_systemctl_set-default] )) || _systemctl_set-default()
{
- compadd "$@" - $(__systemctl list-unit-files --type target --all \
- | cut -d' ' -f1 2>/dev/null ) || _message "no targets found"
+ _wanted systemd-targets expl target \
+ compadd "$@" - ${${(f)"$(__systemctl list-unit-files --type target --all)"}%% *} ||
+ _message "no targets found"
}
# Completion functions for ENVS
@@ -287,9 +298,8 @@ for fun in set-environment unset-environment ; do
if [[ "${fun}" = "set-environment" ]]; then
suf='-S='
fi
-
- compadd "$@" ${suf} - $(systemctl show-environment \
- | while read line; do echo " ${line%%\=}";done )
+ _wanted systemd-environment expl 'environment variable' \
+ compadd "$@" ${suf} - ${${(f)"$(systemctl show-environment)"}%%=*}
}
done
@@ -297,6 +307,10 @@ done
_sd_unit_files
}
+(( $+functions[_systemctl_switch-root] )) || _systemctl_switch-root() {
+ _files
+}
+
# no systemctl completion for:
# [STANDALONE]='daemon-reexec daemon-reload default
# emergency exit halt kexec list-jobs list-units
@@ -312,7 +326,7 @@ _systemctl_caching_policy()
oldcache=( "$1"(mh+1) )
(( $#oldcache )) && return 0
- _sysunits=($(__systemctl --all | cut -d' ' -f1))
+ _sysunits=(${${(f)"$(__systemctl --all)"}%% *})
if (( $#_sysunits )); then
for unit in $_sysunits; do
@@ -339,20 +353,28 @@ _unit_properties() {
if ( [[ ${+_sys_all_properties} -eq 0 ]] || _cache_invalid SYS_ALL_PROPERTIES ) &&
! _retrieve_cache SYS_ALL_PROPERTIES;
then
- _sys_all_properties=( $( {__systemctl show --all;
- @rootlibexecdir@/systemd --dump-configuration-items; } | {
- while IFS='=' read -r a b; do [ -n "$b" ] && echo "$a"; done
- }) )
+ _sys_all_properties=( ${${(M)${(f)"$(__systemctl show --all;
+ @rootlibexecdir@/systemd --dump-configuration-items)"}##[[:alnum:]]##=*}%%=*}
+ )
_store_cache SYS_ALL_PROPRTIES _sys_all_properties
fi
_values -s , "${_sys_all_properties[@]}"
}
+_job_modes() {
+ local -a _modes
+ _modes=(fail replace replace-irreversibly isolate ignore-dependencies ignore-requirements flush)
+ _values -s , "${_modes[@]}"
+}
+
+local -a _modes; _modes=("--user" "--system")
+local _sys_service_mgr=${${words:*_modes}[(R)(${(j.|.)_modes})]:---system}
_arguments -s \
{-h,--help}'[Show help]' \
'--version[Show package version]' \
{-t+,--type=}'[List only units of a particular type]:unit type:_unit_types' \
- '--state=[Display units in the specifyied state]:unit state:_unit_states' \
+ '--state=[Display units in the specified state]:unit state:_unit_states' \
+ '--job-mode=[Specify how to deal with other jobs]:mode:_job_modes' \
{-p+,--property=}'[Show only properties by specific name]:unit property:_unit_properties' \
{-a,--all}'[Show all units/properties, including dead/empty ones]' \
'--reverse[Show reverse dependencies]' \
@@ -360,10 +382,7 @@ _arguments -s \
'--before[Show units ordered before]' \
'--failed[Show only failed units]' \
{-l,--full}"[Don't ellipsize unit names on output]" \
- '--fail[When queueing a new job, fail if conflicting jobs are pending]' \
'--show-types[When showing sockets, show socket type]' \
- '--irreversible[Mark transactions as irreversible]' \
- '--ignore-dependencies[When queueing a new job, ignore all its dependencies]' \
{-i,--ignore-inhibitors}'[When executing a job, ignore jobs dependencies]' \
{-q,--quiet}'[Suppress output]' \
'--no-block[Do not wait until operation finished]' \
@@ -384,5 +403,6 @@ _arguments -s \
{-P,--privileged}'[Acquire privileges before execution]' \
{-n+,--lines=}'[Journal entries to show]:number of entries' \
{-o+,--output=}'[Change journal output mode]:modes:_sd_outputmodes' \
+ '--firmware-setup[Tell the firmware to show the setup menu on next boot]' \
'--plain[When used with list-dependencies, print output as a list]' \
'*::systemctl command:_systemctl_command'
diff --git a/shell-completion/zsh/_systemd-analyze b/shell-completion/zsh/_systemd-analyze
index 2c0e5433eb..efafddc686 100644
--- a/shell-completion/zsh/_systemd-analyze
+++ b/shell-completion/zsh/_systemd-analyze
@@ -54,5 +54,5 @@ _arguments \
'--from-pattern=[When generating a dependency graph, filter only origins]:GLOB' \
'--to-pattern=[When generating a dependency graph, filter only destinations]:GLOB' \
{-H+,--host=}'[Operate on remote host]:userathost:_sd_hosts_or_user_at_host' \
- {-M+,--machine=}'[Operate on local container]:machine' \
+ {-M+,--machine=}'[Operate on local container]:machine:_sd_machines' \
'*::systemd-analyze commands:_systemd_analyze_command'
diff --git a/shell-completion/zsh/_systemd-nspawn b/shell-completion/zsh/_systemd-nspawn
index ceedb2c5a0..08f5696acb 100644
--- a/shell-completion/zsh/_systemd-nspawn
+++ b/shell-completion/zsh/_systemd-nspawn
@@ -11,34 +11,38 @@ _nspawn-caps(){
}
_arguments \
- {-h,--help}'[Show this help]' \
+ {-h,--help}'[Show this help.]' \
+ '--version[Print a short version string and exit.]' \
+ {--quiet,-q}'[Turns off any status output by the tool itself.]' \
{--directory=,-D+}'[Directory to use as file system root for the namespace container. If omitted the current directory will be used.]:directories:_directories' \
+ '--template=[Initialize root directory from template directory, if missing.]:template:_directories' \
+ {--ephemeral,-x}'[Run container with snapshot of root directory, and remove it after exit.]' \
{--image=,-i+}'[Disk image to mount the root directory for the container from.]' \
{--boot=,-b+}'[Automatically search for an init binary and invoke it instead of a shell or a user supplied program.]' \
{--user=,-u+}'[Run the command under specified user, create home directory and cd into it.]' \
{--machine=,-M+}'[Sets the machine name for this container.]' \
'--uuid=[Set the specified uuid for the container.]' \
- '--slice=[Make the container part of the specified slice, instead of the default machine.slice.]' \
- '--private-network[Turn off networking in the container. This makes all network interfaces unavailable in the container, with the exception of the loopback device.]' \
+ {--slice=,-S+}'[Make the container part of the specified slice, instead of the default machine.slice.]' \
'--private-network[Disconnect networking of the container from the host.]' \
'--network-interface=[Assign the specified network interface to the container.]' \
'--network-macvlan=[Create a "macvlan" interface of the specified Ethernet network interface and add it to the container.]' \
- '--network-veth[Create a virtual Ethernet link (veth) between host and container.]' \
+ '--network-ipvlan=[Create a ipvlan network interface based on an existing network interface to the container.]' \
+ {--network-veth,-n}'[Create a virtual Ethernet link (veth) between host and container.]' \
'--network-bridge=[Adds the host side of the Ethernet link created with --network-veth to the specified bridge.]' \
+ {--port=,-p+}'[Expose a container IP port on the host.]' \
{--selinux-context=,-Z+}'[Sets the SELinux security context to be used to label processes in the container.]' \
{--selinux-apifs-context=,-L+}'[Sets the SELinux security context to be used to label files in the virtual API file systems in the container.]' \
'--capability=[List one or more additional capabilities to grant the container.]:capabilities:_nspawn-caps' \
- '--drop-capability=[Specify one or more additional capabilities to drop for the container]' \
- "--link-journal=[Control whether the container's journal shall be made visible to the host system.]:options:(no, host, guest, auto)" \
+ '--drop-capability=[Specify one or more additional capabilities to drop for the containerm]:capabilities:_nspawn-caps' \
+ "--link-journal=[Control whether the container's journal shall be made visible to the host system.]:options:(no host guest auto)" \
'-j[Equivalent to --link-journal=guest.]' \
'--read-only[Mount the root file system read only for the container.]' \
'--bind=[Bind mount a file or directory from the host into the container.]' \
'--bind-ro=[Bind mount a file or directory from the host into the container (read-only).]' \
+ '--tmpfs=[Mount an empty tmpfs to the specified directory.]' \
'--setenv=[Specifies an environment variable assignment to pass to the init process in the container, in the format "NAME=VALUE".]' \
'--share-system[Allows the container to share certain system facilities with the host.]' \
'--register=[Controls whether the container is registered with systemd-machined(8).]' \
'--keep-unit[Instead of creating a transient scope unit to run the container in, simply register the service or scope unit systemd-nspawn has been invoked in with systemd-machined(8).]' \
'--personality=[Control the architecture ("personality") reported by uname(2) in the container.]' \
- {--quiet,-q}'[Turns off any status output by the tool itself.]' \
- {--help,-h}'[Print a short help text and exit.]' \
- '--version[Print a short version string and exit.]'
+ '--volatile=[Run the system in volatile mode.]:volatile:(no yes state)'
diff --git a/src/activate/activate.c b/src/activate/activate.c
index 2689934c40..d345e28567 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -20,7 +20,6 @@
***/
#include <unistd.h>
-#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
#include <sys/socket.h>
diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c
index f569109268..f4255f979e 100644
--- a/src/analyze/analyze-verify.c
+++ b/src/analyze/analyze-verify.c
@@ -20,13 +20,11 @@
***/
#include <stdlib.h>
-#include <getopt.h>
#include "manager.h"
#include "bus-util.h"
#include "log.h"
#include "strv.h"
-#include "build.h"
#include "pager.h"
#include "analyze-verify.h"
@@ -74,8 +72,7 @@ static int verify_socket(Unit *u) {
/* This makes sure instance is created if necessary. */
r = socket_instantiate_service(SOCKET(u));
if (r < 0) {
- log_unit_error(u->id, "Socket %s cannot be started, failed to create instance.",
- u->id);
+ log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m");
return r;
}
@@ -84,11 +81,10 @@ static int verify_socket(Unit *u) {
Service *service;
service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
- log_unit_debug(u->id, "%s uses %s", u->id, UNIT(service)->id);
+ log_unit_debug(u, "Using %s", UNIT(service)->id);
if (UNIT(service)->load_state != UNIT_LOADED) {
- log_unit_error(u->id, "Service %s not loaded, %s cannot be started.",
- UNIT(service)->id, u->id);
+ log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id);
return -ENOENT;
}
}
@@ -100,11 +96,8 @@ static int verify_executable(Unit *u, ExecCommand *exec) {
if (exec == NULL)
return 0;
- if (access(exec->path, X_OK) < 0) {
- log_unit_error(u->id, "%s: command %s is not executable: %m",
- u->id, exec->path);
- return -errno;
- }
+ if (access(exec->path, X_OK) < 0)
+ return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
return 0;
}
@@ -145,16 +138,15 @@ static int verify_documentation(Unit *u, bool check_man) {
int r = 0, k;
STRV_FOREACH(p, u->documentation) {
- log_unit_debug(u->id, "%s: found documentation item %s.", u->id, *p);
+ log_unit_debug(u, "Found documentation item: %s", *p);
+
if (check_man && startswith(*p, "man:")) {
k = show_man_page(*p + 4, true);
if (k != 0) {
if (k < 0)
- log_unit_error(u->id, "%s: can't show %s: %s",
- u->id, *p, strerror(-r));
+ log_unit_error_errno(u, r, "Can't show %s: %m", *p);
else {
- log_unit_error(u->id, "%s: man %s command failed with code %d",
- u->id, *p + 4, k);
+ log_unit_error_errno(u, r, "man %s command failed with code %d", *p + 4, k);
k = -ENOEXEC;
}
if (r == 0)
@@ -178,14 +170,12 @@ static int verify_unit(Unit *u, bool check_man) {
if (log_get_max_level() >= LOG_DEBUG)
unit_dump(u, stdout, "\t");
- log_unit_debug(u->id, "Creating %s/start job", u->id);
+ log_unit_debug(u, "Creating %s/start job", u->id);
r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
if (sd_bus_error_is_set(&err))
- log_unit_error(u->id, "Error: %s: %s",
- err.name, err.message);
+ log_unit_error(u, "Error: %s: %s", err.name, err.message);
if (r < 0)
- log_unit_error(u->id, "Failed to create %s/start: %s",
- u->id, strerror(-r));
+ log_unit_error_errno(u, r, "Failed to create %s/start: %m", u->id);
k = verify_socket(u);
if (k < 0 && r == 0)
@@ -202,7 +192,7 @@ static int verify_unit(Unit *u, bool check_man) {
return r;
}
-int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man) {
+int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
_cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
Manager *m = NULL;
FILE *serial = NULL;
@@ -228,7 +218,7 @@ int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man)
r = manager_new(running_as, true, &m);
if (r < 0)
- return log_error_errno(r, "Failed to initalize manager: %m");
+ return log_error_errno(r, "Failed to initialize manager: %m");
log_debug("Starting manager...");
diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h
index f10c34c4ae..d2d4a7f190 100644
--- a/src/analyze/analyze-verify.h
+++ b/src/analyze/analyze-verify.h
@@ -25,4 +25,4 @@
#include "path-lookup.h"
-int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man);
+int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 591b4ab14e..9583458f72 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -24,23 +24,21 @@
#include <stdlib.h>
#include <getopt.h>
#include <locale.h>
-#include <sys/utsname.h>
#include "sd-bus.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "install.h"
#include "log.h"
#include "build.h"
#include "util.h"
#include "strxcpyx.h"
-#include "fileio.h"
#include "strv.h"
#include "unit-name.h"
#include "special.h"
#include "hashmap.h"
#include "pager.h"
#include "analyze-verify.h"
+#include "terminal-util.h"
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
@@ -1330,7 +1328,7 @@ int main(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "verify"))
r = verify_units(argv+optind+1,
- arg_user ? SYSTEMD_USER : SYSTEMD_SYSTEM,
+ arg_user ? MANAGER_USER : MANAGER_SYSTEM,
arg_man);
else {
_cleanup_bus_close_unref_ sd_bus *bus = NULL;
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c
index ad8ad659d2..2cbed293ba 100644
--- a/src/ask-password/ask-password.c
+++ b/src/ask-password/ask-password.c
@@ -19,25 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <string.h>
#include <errno.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/signalfd.h>
#include <getopt.h>
-#include <termios.h>
-#include <limits.h>
#include <stddef.h>
#include "log.h"
#include "macro.h"
-#include "util.h"
#include "strv.h"
#include "ask-password-api.h"
#include "def.h"
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 089b7754a4..6028ed68c0 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -25,11 +25,9 @@
#include <string.h>
#include <stdio.h>
#include <limits.h>
-#include <stdarg.h>
#include <getopt.h>
#include "log.h"
-#include "hashmap.h"
#include "strv.h"
#include "util.h"
#include "conf-files.h"
diff --git a/src/boot/boot-efi.c b/src/boot/boot-efi.c
deleted file mode 100644
index bd0c59bd5a..0000000000
--- a/src/boot/boot-efi.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Kay Sievers
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <locale.h>
-#include <string.h>
-#include <fnmatch.h>
-#include <fcntl.h>
-#include <sys/timex.h>
-
-#include "boot.h"
-#include "boot-loader.h"
-#include "build.h"
-#include "util.h"
-#include "strv.h"
-#include "efivars.h"
-#include "conf-files.h"
-
-static char *tilt_slashes(char *s) {
- char *p;
-
- if (!s)
- return NULL;
-
- for (p = s; *p; p++)
- if (*p == '\\')
- *p = '/';
- return s;
-}
-
-static int get_boot_entries(struct boot_info *info) {
- uint16_t *list = NULL;
- int i, n;
- int err = 0;
-
- n = efi_get_boot_options(&list);
- if (n < 0)
- return n;
-
- for (i = 0; i < n; i++) {
- struct boot_info_entry *e;
-
- e = realloc(info->fw_entries, (info->fw_entries_count+1) * sizeof(struct boot_info_entry));
- if (!e) {
- err = -ENOMEM;
- break;
- }
- info->fw_entries = e;
-
- e = &info->fw_entries[info->fw_entries_count];
- memzero(e, sizeof(struct boot_info_entry));
- e->order = -1;
-
- err = efi_get_boot_option(list[i], &e->title, &e->part_uuid, &e->path);
- if (err < 0)
- continue;
-
- if (isempty(e->title)) {
- free(e->title);
- e->title = NULL;
- }
- tilt_slashes(e->path);
-
- e->id = list[i];
- info->fw_entries_count++;
- }
-
- free(list);
- return err;
-}
-
-static int find_active_entry(struct boot_info *info) {
- uint16_t boot_cur;
- void *buf;
- size_t l;
- size_t i;
- int err;
-
- err = efi_get_variable(EFI_VENDOR_GLOBAL, "BootCurrent", NULL, &buf, &l);
- if (err < 0)
- return err;
-
- memcpy(&boot_cur, buf, sizeof(uint16_t));
- for (i = 0; i < info->fw_entries_count; i++) {
- if (info->fw_entries[i].id != boot_cur)
- continue;
- info->fw_entry_active = i;
- err = 0;
- break;
- }
- free(buf);
- return err;
-}
-
-static int get_boot_order(struct boot_info *info) {
- size_t i, k;
- int r;
-
- r = efi_get_boot_order(&info->fw_entries_order);
- if (r < 0)
- return r;
-
- info->fw_entries_order_count = r;
-
- for (i = 0; i < info->fw_entries_order_count; i++) {
- for (k = 0; k < info->fw_entries_count; k++) {
- if (info->fw_entries[k].id != info->fw_entries_order[i])
- continue;
- info->fw_entries[k].order = i;
- break;
- }
- }
-
- return 0;
-}
-
-static int entry_cmp(const void *a, const void *b) {
- const struct boot_info_entry *e1 = a;
- const struct boot_info_entry *e2 = b;
-
- /* boot order of active entries */
- if (e1->order > 0 && e2->order > 0)
- return e1->order - e2->order;
-
- /* sort active entries before inactive ones */
- if (e1->order > 0)
- return 1;
- if (e2->order > 0)
- return -1;
-
- /* order of inactive entries */
- return e1->id - e2->id;
-}
-
-int boot_info_query(struct boot_info *info) {
- char str[64];
- char buf[64];
- char *loader_active = NULL;
-
- info->fw_secure_boot = is_efi_secure_boot();
- info->fw_secure_boot_setup_mode = is_efi_secure_boot_setup_mode();
-
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info->loader);
-
- get_boot_entries(info);
- if (info->fw_entries_count > 0) {
- get_boot_order(info);
- qsort(info->fw_entries, info->fw_entries_count, sizeof(struct boot_info_entry), entry_cmp);
- find_active_entry(info);
- }
-
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &info->fw_type);
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &info->fw_info);
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &info->loader_image_path);
- tilt_slashes(info->loader_image_path);
- efi_loader_get_device_part_uuid(&info->loader_part_uuid);
-
- boot_loader_read_entries(info);
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntrySelected", &loader_active);
- if (loader_active) {
- boot_loader_find_active_entry(info, loader_active);
- free(loader_active);
- }
-
- snprintf(str, sizeof(str), "LoaderEntryOptions-%s", sd_id128_to_string(info->machine_id, buf));
- efi_get_variable_string(EFI_VENDOR_LOADER, str, &info->loader_options_added);
-
- return 0;
-}
diff --git a/src/boot/boot-loader.c b/src/boot/boot-loader.c
deleted file mode 100644
index d44fdb3aef..0000000000
--- a/src/boot/boot-loader.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Kay Sievers
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <locale.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/timex.h>
-
-#include "boot.h"
-#include "boot-loader.h"
-#include "build.h"
-#include "util.h"
-#include "strv.h"
-#include "conf-files.h"
-
-static char *loader_fragment_read_title(const char *fragment) {
- FILE *f;
- char line[LINE_MAX];
- char *title = NULL;
-
- f = fopen(fragment, "re");
- if (!f)
- return NULL;
-
- while (fgets(line, sizeof(line), f) != NULL) {
- char *s;
- size_t l;
-
- l = strlen(line);
- if (l < 1)
- continue;
- if (line[l-1] == '\n')
- line[l-1] = '\0';
-
- s = line;
- while (isspace(s[0]))
- s++;
-
- if (s[0] == '#')
- continue;
-
- if (!startswith(s, "title"))
- continue;
-
- s += strlen("title");
- if (!isspace(s[0]))
- continue;
- while (isspace(s[0]))
- s++;
-
- title = strdup(s);
- break;
- }
-
- fclose(f);
- return title;
-}
-
-int boot_loader_read_entries(struct boot_info *info) {
- _cleanup_strv_free_ char **files = NULL;
- static const char *loader_dir[] = { "/boot/loader/entries", NULL};
- unsigned int count;
- unsigned int i;
- int err;
-
- err = conf_files_list_strv(&files, ".conf", NULL, loader_dir);
- if (err < 0)
- return err;
-
- count = strv_length(files);
- info->loader_entries = new0(struct boot_info_entry, count);
- if (!info->loader_entries)
- return -ENOMEM;
-
- for (i = 0; i < count; i++) {
- info->loader_entries[i].title = loader_fragment_read_title(files[i]);
- info->loader_entries[i].path = strdup(files[i]);
- if (!info->loader_entries[i].title || !info->loader_entries[i].path) {
- free(info->loader_entries[i].title);
- free(info->loader_entries[i].path);
- return -ENOMEM;
- }
- info->loader_entries_count++;
- }
-
- return 0;
-}
-
-int boot_loader_find_active_entry(struct boot_info *info, const char *loader_active) {
- char *fn;
- unsigned int i;
-
- if (!loader_active)
- return -ENOENT;
- if (info->loader_entries_count == 0)
- return -ENOENT;
-
- if (asprintf(&fn, "/boot/loader/entries/%s.conf", loader_active) < 0)
- return -ENOMEM;
-
- for (i = 0; i < info->loader_entries_count; i++) {
- if (streq(fn, info->loader_entries[i].path)) {
- info->loader_entry_active = i;
- break;
- }
- }
-
- free(fn);
- return 0;
-}
diff --git a/src/boot/boot.h b/src/boot/boot.h
deleted file mode 100644
index bd8dc69d3d..0000000000
--- a/src/boot/boot.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2013 Kay Sievers
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-id128.h"
-
-/*
- * Firmware and boot manager information to be filled in
- * by the platform.
- *
- * This is partly EFI specific, if you add things, keep this
- * as generic as possible to be able to re-use it on other
- * platforms.
- */
-
-struct boot_info_entry {
- uint16_t id;
- uint16_t order;
- char *title;
- sd_id128_t part_uuid;
- char *path;
-};
-
-struct boot_info {
- sd_id128_t machine_id;
- sd_id128_t boot_id;
- char *fw_type;
- char *fw_info;
- int fw_secure_boot;
- int fw_secure_boot_setup_mode;
- struct boot_info_entry *fw_entries;
- size_t fw_entries_count;
- uint16_t *fw_entries_order;
- size_t fw_entries_order_count;
- ssize_t fw_entry_active;
- char *loader;
- char *loader_image_path;
- sd_id128_t loader_part_uuid;
- struct boot_info_entry *loader_entries;
- size_t loader_entries_count;
- ssize_t loader_entry_active;
- char *loader_options_added;
-};
-
-int boot_info_query(struct boot_info *info);
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 51b51c4254..1e65597acf 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -3,7 +3,8 @@
/***
This file is part of systemd.
- Copyright 2013 Kay Sievers
+ Copyright 2013-2015 Kay Sievers
+ Copyright 2013 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -19,249 +20,1115 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
+#include <stdio.h>
#include <getopt.h>
-#include <locale.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/statfs.h>
+#include <sys/stat.h>
+#include <errno.h>
#include <string.h>
-#include <sys/timex.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <limits.h>
+#include <ftw.h>
+#include <stdbool.h>
+#include <blkid/blkid.h>
-#include "boot.h"
+#include "efivars.h"
#include "build.h"
#include "util.h"
-#include "utf8.h"
+#include "rm-rf.h"
+#include "blkid-util.h"
-static void help(void) {
- printf("%s [OPTIONS...] COMMAND ...\n\n"
- "Query or change firmware and boot manager settings.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- "Commands:\n"
- " status Show current boot settings\n"
- , program_invocation_short_name);
+static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
+ struct statfs sfs;
+ struct stat st, st2;
+ _cleanup_free_ char *t = NULL;
+ _cleanup_blkid_free_probe_ blkid_probe b = NULL;
+ int r;
+ const char *v, *t2;
+
+ if (statfs(p, &sfs) < 0)
+ return log_error_errno(errno, "Failed to check file system type of \"%s\": %m", p);
+
+ if (sfs.f_type != 0x4d44) {
+ log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
+ return -ENODEV;
+ }
+
+ if (stat(p, &st) < 0)
+ return log_error_errno(errno, "Failed to determine block device node of \"%s\": %m", p);
+
+ if (major(st.st_dev) == 0) {
+ log_error("Block device node of %p is invalid.", p);
+ return -ENODEV;
+ }
+
+ t2 = strjoina(p, "/..");
+ r = stat(t2, &st2);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to determine block device node of parent of \"%s\": %m", p);
+
+ if (st.st_dev == st2.st_dev) {
+ log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p);
+ return -ENODEV;
+ }
+
+ r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
+ if (r < 0)
+ return log_oom();
+
+ errno = 0;
+ b = blkid_new_probe_from_filename(t);
+ if (!b) {
+ if (errno == 0)
+ return log_oom();
+
+ return log_error_errno(errno, "Failed to open file system \"%s\": %m", p);
+ }
+
+ blkid_probe_enable_superblocks(b, 1);
+ blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
+ blkid_probe_enable_partitions(b, 1);
+ blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
+
+ errno = 0;
+ r = blkid_do_safeprobe(b);
+ if (r == -2) {
+ log_error("File system \"%s\" is ambigious.", p);
+ return -ENODEV;
+ } else if (r == 1) {
+ log_error("File system \"%s\" does not contain a label.", p);
+ return -ENODEV;
+ } else if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe file system \"%s\": %m", p);
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe file system type \"%s\": %m", p);
+ }
+
+ if (!streq(v, "vfat")) {
+ log_error("File system \"%s\" is not FAT.", p);
+ return -ENODEV;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe partition scheme \"%s\": %m", p);
+ }
+
+ if (!streq(v, "gpt")) {
+ log_error("File system \"%s\" is not on a GPT partition table.", p);
+ return -ENODEV;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe partition type UUID \"%s\": %m", p);
+ }
+
+ if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
+ log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p);
+ return -ENODEV;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe partition entry UUID \"%s\": %m", p);
+ }
+
+ r = sd_id128_from_string(v, uuid);
+ if (r < 0) {
+ log_error("Partition \"%s\" has invalid UUID \"%s\".", p, v);
+ return -EIO;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe partition number \"%s\": m", p);
+ }
+ *part = strtoul(v, NULL, 10);
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe partition offset \"%s\": %m", p);
+ }
+ *pstart = strtoul(v, NULL, 10);
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
+ if (r != 0) {
+ r = errno ? -errno : -EIO;
+ return log_error_errno(r, "Failed to probe partition size \"%s\": %m", p);
+ }
+ *psize = strtoul(v, NULL, 10);
+
+ return 0;
}
-static int parse_argv(int argc, char *argv[]) {
- enum {
- ARG_VERSION = 0x100,
- };
+/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
+static int get_file_version(int fd, char **v) {
+ struct stat st;
+ char *buf;
+ const char *s, *e;
+ char *x = NULL;
+ int r = 0;
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- {}
- };
+ assert(fd >= 0);
+ assert(v);
- int c;
+ if (fstat(fd, &st) < 0)
+ return -errno;
- assert(argc >= 0);
- assert(argv);
+ if (st.st_size < 27)
+ return 0;
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+ buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (buf == MAP_FAILED)
+ return -errno;
- switch (c) {
+ s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
+ if (!s)
+ goto finish;
+ s += 17;
- case 'h':
- help();
+ e = memmem(s, st.st_size - (s - buf), " ####", 5);
+ if (!e || e - s < 3) {
+ log_error("Malformed version string.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ x = strndup(s, e - s);
+ if (!x) {
+ r = log_oom();
+ goto finish;
+ }
+ r = 1;
+
+finish:
+ munmap(buf, st.st_size);
+ *v = x;
+ return r;
+}
+
+static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
+ char *p;
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r = 0, c = 0;
+
+ p = strjoina(esp_path, "/", path);
+ d = opendir(p);
+ if (!d) {
+ if (errno == ENOENT)
return 0;
- case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
+ return log_error_errno(errno, "Failed to read \"%s\": %m", p);
+ }
+
+ while ((de = readdir(d))) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *v = NULL;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (!endswith_no_case(de->d_name, ".efi"))
+ continue;
+
+ if (prefix && !startswith_no_case(de->d_name, prefix))
+ continue;
+
+ fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
+
+ r = get_file_version(fd, &v);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ printf(" File: └─/%s/%s (%s)\n", path, de->d_name, v);
+ else
+ printf(" File: └─/%s/%s\n", path, de->d_name);
+ c++;
+ }
+
+ return c;
+}
+
+static int status_binaries(const char *esp_path, sd_id128_t partition) {
+ int r;
+
+ printf("Boot Loader Binaries:\n");
+
+ printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
+
+ r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
+ if (r == 0)
+ log_error("systemd-boot not installed in ESP.");
+ else if (r < 0)
+ return r;
+
+ r = enumerate_binaries(esp_path, "EFI/Boot", "boot");
+ if (r == 0)
+ log_error("No default/fallback boot loader installed in ESP.");
+ else if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int print_efi_option(uint16_t id, bool in_order) {
+ _cleanup_free_ char *title = NULL;
+ _cleanup_free_ char *path = NULL;
+ sd_id128_t partition;
+ bool active;
+ int r = 0;
+
+ r = efi_get_boot_option(id, &title, &partition, &path, &active);
+ if (r < 0)
+ return r;
+
+ /* print only configured entries with partition information */
+ if (!path || sd_id128_equal(partition, SD_ID128_NULL))
+ return 0;
+
+ efi_tilt_backslashes(path);
+
+ printf(" Title: %s\n", strna(title));
+ printf(" ID: 0x%04X\n", id);
+ printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
+ printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
+ printf(" File: └─%s\n", path);
+ printf("\n");
+
+ return 0;
+}
+
+static int status_variables(void) {
+ int n_options, n_order;
+ _cleanup_free_ uint16_t *options = NULL, *order = NULL;
+ int i;
+
+ if (!is_efi_boot()) {
+ log_notice("Not booted with EFI, not showing EFI variables.");
+ return 0;
+ }
+
+ n_options = efi_get_boot_options(&options);
+ if (n_options == -ENOENT)
+ return log_error_errno(ENOENT, "Failed to access EFI variables, efivarfs"
+ " needs to be available at /sys/firmware/efi/efivars/.");
+ else if (n_options < 0)
+ return log_error_errno(n_options, "Failed to read EFI boot entries: %m");
+
+ n_order = efi_get_boot_order(&order);
+ if (n_order == -ENOENT)
+ n_order = 0;
+ else if (n_order < 0)
+ return log_error_errno(n_order, "Failed to read EFI boot order.");
+
+ /* print entries in BootOrder first */
+ printf("Boot Loader Entries in EFI Variables:\n");
+ for (i = 0; i < n_order; i++)
+ print_efi_option(order[i], true);
+
+ /* print remaining entries */
+ for (i = 0; i < n_options; i++) {
+ int j;
+
+ for (j = 0; j < n_order; j++)
+ if (options[i] == order[j])
+ goto next;
+
+ print_efi_option(options[i], false);
+ next:
+ continue;
+ }
+
+ return 0;
+}
+
+static int compare_product(const char *a, const char *b) {
+ size_t x, y;
+
+ assert(a);
+ assert(b);
+
+ x = strcspn(a, " ");
+ y = strcspn(b, " ");
+ if (x != y)
+ return x < y ? -1 : x > y ? 1 : 0;
+
+ return strncmp(a, b, x);
+}
+
+static int compare_version(const char *a, const char *b) {
+ assert(a);
+ assert(b);
+
+ a += strcspn(a, " ");
+ a += strspn(a, " ");
+ b += strcspn(b, " ");
+ b += strspn(b, " ");
+
+ return strverscmp(a, b);
+}
+
+static int version_check(int fd, const char *from, const char *to) {
+ _cleanup_free_ char *a = NULL, *b = NULL;
+ _cleanup_close_ int fd2 = -1;
+ int r;
+
+ assert(fd >= 0);
+ assert(from);
+ assert(to);
+
+ r = get_file_version(fd, &a);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_error("Source file \"%s\" does not carry version information!", from);
+ return -EINVAL;
+ }
+
+ fd2 = open(to, O_RDONLY|O_CLOEXEC);
+ if (fd2 < 0) {
+ if (errno == ENOENT)
return 0;
- case '?':
- return -EINVAL;
+ return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", to);
+ }
- default:
- assert_not_reached("Unhandled option");
+ r = get_file_version(fd2, &b);
+ if (r < 0)
+ return r;
+ if (r == 0 || compare_product(a, b) != 0) {
+ log_notice("Skipping \"%s\", since it's owned by another boot loader.", to);
+ return -EEXIST;
+ }
+
+ if (compare_version(a, b) < 0) {
+ log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to);
+ return -ESTALE;
+ }
+
+ return 0;
+}
+
+static int copy_file(const char *from, const char *to, bool force) {
+ _cleanup_fclose_ FILE *f = NULL, *g = NULL;
+ char *p;
+ int r;
+ struct timespec t[2];
+ struct stat st;
+
+ assert(from);
+ assert(to);
+
+ f = fopen(from, "re");
+ if (!f)
+ return log_error_errno(errno, "Failed to open \"%s\" for reading: %m", from);
+
+ if (!force) {
+ /* If this is an update, then let's compare versions first */
+ r = version_check(fileno(f), from, to);
+ if (r < 0)
+ return r;
+ }
+
+ p = strjoina(to, "~");
+ g = fopen(p, "wxe");
+ if (!g) {
+ /* Directory doesn't exist yet? Then let's skip this... */
+ if (!force && errno == ENOENT)
+ return 0;
+
+ return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", to);
+ }
+
+ rewind(f);
+ do {
+ size_t k;
+ uint8_t buf[32*1024];
+
+ k = fread(buf, 1, sizeof(buf), f);
+ if (ferror(f)) {
+ r = log_error_errno(EIO, "Failed to read \"%s\": %m", from);
+ goto error;
}
- return 1;
+ if (k == 0)
+ break;
+
+ fwrite(buf, 1, k, g);
+ if (ferror(g)) {
+ r = log_error_errno(EIO, "Failed to write \"%s\": %m", to);
+ goto error;
+ }
+ } while (!feof(f));
+
+ fflush(g);
+ if (ferror(g)) {
+ r = log_error_errno(EIO, "Failed to write \"%s\": %m", to);
+ goto error;
+ }
+
+ r = fstat(fileno(f), &st);
+ if (r < 0) {
+ r = log_error_errno(errno, "Failed to get file timestamps of \"%s\": %m", from);
+ goto error;
+ }
+
+ t[0] = st.st_atim;
+ t[1] = st.st_mtim;
+
+ r = futimens(fileno(g), t);
+ if (r < 0) {
+ r = log_error_errno(errno, "Failed to set file timestamps on \"%s\": %m", p);
+ goto error;
+ }
+
+ if (rename(p, to) < 0) {
+ r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", p, to);
+ goto error;
+ }
+
+ log_info("Copied \"%s\" to \"%s\".", from, to);
+ return 0;
+
+error:
+ unlink(p);
+ return r;
}
-static int boot_info_new(struct boot_info **info) {
- struct boot_info *in;
- int err;
+static char* strupper(char *s) {
+ char *p;
- in = new0(struct boot_info, 1);
- if (!in)
- return -ENOMEM;
+ for (p = s; *p; p++)
+ *p = toupper(*p);
- err = sd_id128_get_machine(&in->machine_id);
- if (err < 0)
- goto err;
+ return s;
+}
- err = sd_id128_get_boot(&in->boot_id);
- if (err < 0)
- goto err;
+static int mkdir_one(const char *prefix, const char *suffix) {
+ char *p;
- in->fw_entry_active = -1;
- in->loader_entry_active = -1;
+ p = strjoina(prefix, "/", suffix);
+ if (mkdir(p, 0700) < 0) {
+ if (errno != EEXIST)
+ return log_error_errno(errno, "Failed to create \"%s\": %m", p);
+ } else
+ log_info("Created \"%s\".", p);
- *info = in;
return 0;
-err:
- free(in);
- return err;
}
-static void boot_info_entries_free(struct boot_info_entry *entries, size_t n) {
- size_t i;
+static const char *efi_subdirs[] = {
+ "EFI",
+ "EFI/systemd",
+ "EFI/Boot",
+ "loader",
+ "loader/entries"
+};
- for (i = 0; i < n; i++) {
- free(entries[i].title);
- free(entries[i].path);
+static int create_dirs(const char *esp_path) {
+ int r;
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(efi_subdirs); i++) {
+ r = mkdir_one(esp_path, efi_subdirs[i]);
+ if (r < 0)
+ return r;
}
- free(entries);
+
+ return 0;
}
-static void boot_info_free(struct boot_info *info) {
- free(info->fw_type);
- free(info->fw_info);
- boot_info_entries_free(info->fw_entries, info->fw_entries_count);
- free(info->fw_entries_order);
- free(info->loader);
- free(info->loader_image_path);
- free(info->loader_options_added);
- boot_info_entries_free(info->loader_entries, info->loader_entries_count);
- free(info);
+static int copy_one_file(const char *esp_path, const char *name, bool force) {
+ char *p, *q;
+ int r;
+
+ p = strjoina(BOOTLIBDIR "/", name);
+ q = strjoina(esp_path, "/EFI/systemd/", name);
+ r = copy_file(p, q, force);
+
+ if (startswith(name, "systemd-boot")) {
+ int k;
+ char *v;
+
+ /* Create the EFI default boot loader name (specified for removable devices) */
+ v = strjoina(esp_path, "/EFI/Boot/BOOT", name + strlen("systemd-boot"));
+ strupper(strrchr(v, '/') + 1);
+
+ k = copy_file(p, v, force);
+ if (k < 0 && r == 0)
+ r = k;
+ }
+
+ return r;
+}
+
+static int install_binaries(const char *esp_path, bool force) {
+ struct dirent *de;
+ _cleanup_closedir_ DIR *d = NULL;
+ int r = 0;
+
+ if (force) {
+ /* Don't create any of these directories when we are
+ * just updating. When we update we'll drop-in our
+ * files (unless there are newer ones already), but we
+ * won't create the directories for them in the first
+ * place. */
+ r = create_dirs(esp_path);
+ if (r < 0)
+ return r;
+ }
+
+ d = opendir(BOOTLIBDIR);
+ if (!d)
+ return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m");
+
+ while ((de = readdir(d))) {
+ int k;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (!endswith_no_case(de->d_name, ".efi"))
+ continue;
+
+ k = copy_one_file(esp_path, de->d_name, force);
+ if (k < 0 && r == 0)
+ r = k;
+ }
+
+ return r;
+}
+
+static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
+ _cleanup_free_ char *opath = NULL;
+ sd_id128_t ouuid;
+ int r;
+
+ r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
+ if (r < 0)
+ return false;
+ if (!sd_id128_equal(uuid, ouuid))
+ return false;
+ if (!streq_ptr(path, opath))
+ return false;
+
+ return true;
+}
+
+static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
+ _cleanup_free_ uint16_t *options = NULL;
+ int n, i;
+
+ n = efi_get_boot_options(&options);
+ if (n < 0)
+ return n;
+
+ /* find already existing systemd-boot entry */
+ for (i = 0; i < n; i++)
+ if (same_entry(options[i], uuid, path)) {
+ *id = options[i];
+ return 1;
+ }
+
+ /* find free slot in the sorted BootXXXX variable list */
+ for (i = 0; i < n; i++)
+ if (i != options[i]) {
+ *id = i;
+ return 1;
+ }
+
+ /* use the next one */
+ if (i == 0xffff)
+ return -ENOSPC;
+ *id = i;
+ return 0;
}
-static int show_status(char **args, unsigned n) {
- char buf[64];
- struct boot_info *info;
- int err;
+static int insert_into_order(uint16_t slot, bool first) {
+ _cleanup_free_ uint16_t *order = NULL;
+ uint16_t *t;
+ int n, i;
+
+ n = efi_get_boot_order(&order);
+ if (n <= 0)
+ /* no entry, add us */
+ return efi_set_boot_order(&slot, 1);
+
+ /* are we the first and only one? */
+ if (n == 1 && order[0] == slot)
+ return 0;
+
+ /* are we already in the boot order? */
+ for (i = 0; i < n; i++) {
+ if (order[i] != slot)
+ continue;
+
+ /* we do not require to be the first one, all is fine */
+ if (!first)
+ return 0;
- err = boot_info_new(&info);
- if (err < 0)
+ /* move us to the first slot */
+ memmove(order + 1, order, i * sizeof(uint16_t));
+ order[0] = slot;
+ return efi_set_boot_order(order, n);
+ }
+
+ /* extend array */
+ t = realloc(order, (n + 1) * sizeof(uint16_t));
+ if (!t)
return -ENOMEM;
+ order = t;
- err = boot_info_query(info);
-
- printf("System:\n");
- printf(" Machine ID: %s\n", sd_id128_to_string(info->machine_id, buf));
- printf(" Boot ID: %s\n", sd_id128_to_string(info->boot_id, buf));
- if (info->fw_type)
- printf(" Firmware: %s (%s)\n", info->fw_type, strna(info->fw_info));
- if (info->fw_secure_boot >= 0)
- printf(" Secure Boot: %s\n", info->fw_secure_boot ? "enabled" : "disabled");
- if (info->fw_secure_boot_setup_mode >= 0)
- printf(" Setup Mode: %s\n", info->fw_secure_boot_setup_mode ? "setup" : "user");
- printf("\n");
+ /* add us to the top or end of the list */
+ if (first) {
+ memmove(order + 1, order, n * sizeof(uint16_t));
+ order[0] = slot;
+ } else
+ order[n] = slot;
+
+ return efi_set_boot_order(order, n + 1);
+}
+
+static int remove_from_order(uint16_t slot) {
+ _cleanup_free_ uint16_t *order = NULL;
+ int n, i;
+
+ n = efi_get_boot_order(&order);
+ if (n <= 0)
+ return n;
- if (info->fw_entry_active >= 0) {
- printf("Selected Firmware Entry:\n");
- printf(" Title: %s\n", strna(info->fw_entries[info->fw_entry_active].title));
- if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].part_uuid, SD_ID128_NULL))
- printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
- SD_ID128_FORMAT_VAL(info->fw_entries[info->fw_entry_active].part_uuid));
+ for (i = 0; i < n; i++) {
+ if (order[i] != slot)
+ continue;
+
+ if (i + 1 < n)
+ memmove(order + i, order + i+1, (n - i) * sizeof(uint16_t));
+ return efi_set_boot_order(order, n - 1);
+ }
+
+ return 0;
+}
+
+static int install_variables(const char *esp_path,
+ uint32_t part, uint64_t pstart, uint64_t psize,
+ sd_id128_t uuid, const char *path,
+ bool first) {
+ char *p;
+ uint16_t slot;
+ int r;
+
+ if (!is_efi_boot()) {
+ log_warning("Not booted with EFI, skipping EFI variable setup.");
+ return 0;
+ }
+
+ p = strjoina(esp_path, path);
+ if (access(p, F_OK) < 0) {
+ if (errno == ENOENT)
+ return 0;
else
- printf(" Partition: n/a\n");
- if (info->fw_entries[info->fw_entry_active].path)
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), info->fw_entries[info->fw_entry_active].path);
+ return log_error_errno(errno, "Cannot access \"%s\": %m", p);
}
- printf("\n");
- if (info->loader) {
- printf("Boot Loader:\n");
- printf(" Product: %s\n", info->loader);
- if (!sd_id128_equal(info->loader_part_uuid, SD_ID128_NULL))
- printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
- SD_ID128_FORMAT_VAL(info->loader_part_uuid));
- else
- printf(" Partition: n/a\n");
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(info->loader_image_path));
- printf("\n");
-
- if (info->loader_entry_active >= 0) {
- printf("Selected Boot Loader Entry:\n");
- printf(" Title: %s\n", strna(info->loader_entries[info->loader_entry_active].title));
- printf(" File: %s\n", info->loader_entries[info->loader_entry_active].path);
- if (info->loader_options_added)
- printf(" Options: %s\n", info->loader_options_added);
+ r = find_slot(uuid, path, &slot);
+ if (r < 0)
+ return log_error_errno(r,
+ r == -ENOENT ?
+ "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
+ "Failed to determine current boot order: %m");
+
+ if (first || r == false) {
+ r = efi_add_boot_option(slot, "Linux Boot Manager",
+ part, pstart, psize,
+ uuid, path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
+
+ log_info("Created EFI boot entry \"Linux Boot Manager\".");
+ }
+
+ return insert_into_order(slot, first);
+}
+
+static int remove_boot_efi(const char *esp_path) {
+ char *p;
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r, c = 0;
+
+ p = strjoina(esp_path, "/EFI/Boot");
+ d = opendir(p);
+ if (!d) {
+ if (errno == ENOENT)
+ return 0;
+
+ return log_error_errno(errno, "Failed to open directory \"%s\": %m", p);
+ }
+
+ while ((de = readdir(d))) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *v = NULL;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (!endswith_no_case(de->d_name, ".efi"))
+ continue;
+
+ if (!startswith_no_case(de->d_name, "Boot"))
+ continue;
+
+ fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open \"%s/%s\" for reading: %m", p, de->d_name);
+
+ r = get_file_version(fd, &v);
+ if (r < 0)
+ return r;
+ if (r > 0 && startswith(v, "systemd-boot ")) {
+ r = unlinkat(dirfd(d), de->d_name, 0);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to remove \"%s/%s\": %m", p, de->d_name);
+
+ log_info("Removed \"%s/\%s\".", p, de->d_name);
}
+
+ c++;
+ }
+
+ return c;
+}
+
+static int rmdir_one(const char *prefix, const char *suffix) {
+ char *p;
+
+ p = strjoina(prefix, "/", suffix);
+ if (rmdir(p) < 0) {
+ if (!IN_SET(errno, ENOENT, ENOTEMPTY))
+ return log_error_errno(errno, "Failed to remove \"%s\": %m", p);
} else
- printf("No suitable data is provided by the boot manager. See:\n"
- " http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n"
- " http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n"
- "for details.\n");
- printf("\n");
+ log_info("Removed \"%s\".", p);
- boot_info_free(info);
- return err;
+ return 0;
}
-static int bootctl_main(int argc, char *argv[]) {
- static const struct {
- const char* verb;
- const enum {
- MORE,
- LESS,
- EQUAL
- } argc_cmp;
- const int argc;
- int (* const dispatch)(char **args, unsigned n);
- } verbs[] = {
- { "status", LESS, 1, show_status },
+static int remove_binaries(const char *esp_path) {
+ char *p;
+ int r, q;
+ unsigned i;
+
+ p = strjoina(esp_path, "/EFI/systemd");
+ r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
+
+ q = remove_boot_efi(esp_path);
+ if (q < 0 && r == 0)
+ r = q;
+
+ for (i = ELEMENTSOF(efi_subdirs); i > 0; i--) {
+ q = rmdir_one(esp_path, efi_subdirs[i-1]);
+ if (q < 0 && r == 0)
+ r = q;
+ }
+
+ return r;
+}
+
+static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
+ uint16_t slot;
+ int r;
+
+ if (!is_efi_boot())
+ return 0;
+
+ r = find_slot(uuid, path, &slot);
+ if (r != 1)
+ return 0;
+
+ r = efi_remove_boot_option(slot);
+ if (r < 0)
+ return r;
+
+ if (in_order)
+ return remove_from_order(slot);
+ else
+ return 0;
+}
+
+static int install_loader_config(const char *esp_path) {
+ char *p;
+ char line[64];
+ char *machine = NULL;
+ _cleanup_fclose_ FILE *f = NULL, *g = NULL;
+
+ f = fopen("/etc/machine-id", "re");
+ if (!f)
+ return -errno;
+
+ if (fgets(line, sizeof(line), f) != NULL) {
+ char *s;
+
+ s = strchr(line, '\n');
+ if (s)
+ s[0] = '\0';
+ if (strlen(line) == 32)
+ machine = line;
+ }
+
+ if (!machine)
+ return -ESRCH;
+
+ p = strjoina(esp_path, "/loader/loader.conf");
+ g = fopen(p, "wxe");
+ if (g) {
+ fprintf(g, "#timeout 3\n");
+ fprintf(g, "default %s-*\n", machine);
+ if (ferror(g))
+ return log_error_errno(EIO, "Failed to write \"%s\": %m", p);
+ }
+
+ return 0;
+}
+
+static int help(void) {
+ printf("%s [COMMAND] [OPTIONS...]\n"
+ "\n"
+ "Install, update or remove the sdboot EFI boot manager.\n\n"
+ " -h --help Show this help\n"
+ " --version Print version\n"
+ " --path=PATH Path to the EFI System Partition (ESP)\n"
+ " --no-variables Don't touch EFI variables\n"
+ "\n"
+ "Commands:\n"
+ " status Show status of installed systemd-boot and EFI variables\n"
+ " install Install systemd-boot to the ESP and EFI variables\n"
+ " update Update systemd-boot in the ESP and EFI variables\n"
+ " remove Remove systemd-boot from the ESP and EFI variables\n",
+ program_invocation_short_name);
+
+ return 0;
+}
+
+static const char *arg_path = "/boot";
+static bool arg_touch_variables = true;
+
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_PATH = 0x100,
+ ARG_VERSION,
+ ARG_NO_VARIABLES,
};
- int left;
- unsigned i;
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "path", required_argument, NULL, ARG_PATH },
+ { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int c;
assert(argc >= 0);
assert(argv);
- left = argc - optind;
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+ switch (c) {
- if (left <= 0)
- /* Special rule: no arguments means "status" */
- i = 0;
- else {
- if (streq(argv[optind], "help")) {
+ case 'h':
help();
return 0;
+
+ case ARG_VERSION:
+ printf(VERSION "\n");
+ return 0;
+
+ case ARG_PATH:
+ arg_path = optarg;
+ break;
+
+ case ARG_NO_VARIABLES:
+ arg_touch_variables = false;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unknown option");
}
- for (i = 0; i < ELEMENTSOF(verbs); i++)
- if (streq(argv[optind], verbs[i].verb))
- break;
+ return 1;
+}
+
+static void read_loader_efi_var(const char *name, char **var) {
+ int r;
+
+ r = efi_get_variable_string(EFI_VENDOR_LOADER, name, var);
+ if (r < 0 && r != -ENOENT)
+ log_warning_errno(r, "Failed to read EFI variable %s: %m", name);
+}
+static int bootctl_main(int argc, char*argv[]) {
+ enum action {
+ ACTION_STATUS,
+ ACTION_INSTALL,
+ ACTION_UPDATE,
+ ACTION_REMOVE
+ } arg_action = ACTION_STATUS;
+ static const struct {
+ const char* verb;
+ enum action action;
+ } verbs[] = {
+ { "status", ACTION_STATUS },
+ { "install", ACTION_INSTALL },
+ { "update", ACTION_UPDATE },
+ { "remove", ACTION_REMOVE },
+ };
+
+ sd_id128_t uuid = {};
+ uint32_t part = 0;
+ uint64_t pstart = 0, psize = 0;
+ int r, q;
+
+ if (argv[optind]) {
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(verbs); i++) {
+ if (!streq(argv[optind], verbs[i].verb))
+ continue;
+ arg_action = verbs[i].action;
+ break;
+ }
if (i >= ELEMENTSOF(verbs)) {
- log_error("Unknown operation %s", argv[optind]);
+ log_error("Unknown operation \"%s\"", argv[optind]);
return -EINVAL;
}
}
- switch (verbs[i].argc_cmp) {
+ if (geteuid() != 0)
+ return log_error_errno(EPERM, "Need to be root.");
- case EQUAL:
- if (left != verbs[i].argc) {
- log_error("Invalid number of arguments.");
- return -EINVAL;
- }
+ r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
+ if (r == -ENODEV && !arg_path)
+ log_notice("You might want to use --path= to indicate the path to your ESP, in case it is not mounted on /boot.");
+ if (r < 0)
+ return r;
+
+ switch (arg_action) {
+ case ACTION_STATUS: {
+ _cleanup_free_ char *fw_type = NULL;
+ _cleanup_free_ char *fw_info = NULL;
+ _cleanup_free_ char *loader = NULL;
+ _cleanup_free_ char *loader_path = NULL;
+ sd_id128_t loader_part_uuid = {};
+
+ if (is_efi_boot()) {
+ read_loader_efi_var("LoaderFirmwareType", &fw_type);
+ read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
+ read_loader_efi_var("LoaderInfo", &loader);
+ read_loader_efi_var("LoaderImageIdentifier", &loader_path);
+ if (loader_path)
+ efi_tilt_backslashes(loader_path);
+ r = efi_loader_get_device_part_uuid(&loader_part_uuid);
+ if (r < 0 && r == -ENOENT)
+ log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");
+
+ printf("System:\n");
+ printf(" Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));
+
+ r = is_efi_secure_boot();
+ if (r < 0)
+ log_warning_errno(r, "Failed to query secure boot status: %m");
+ else
+ printf(" Secure Boot: %s\n", r ? "enabled" : "disabled");
+
+ r = is_efi_secure_boot_setup_mode();
+ if (r < 0)
+ log_warning_errno(r, "Failed to query secure boot mode: %m");
+ else
+ printf(" Setup Mode: %s\n", r ? "setup" : "user");
+ printf("\n");
+
+ printf("Loader:\n");
+ printf(" Product: %s\n", strna(loader));
+ if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
+ printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ SD_ID128_FORMAT_VAL(loader_part_uuid));
+ else
+ printf(" Partition: n/a\n");
+ printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
+ printf("\n");
+ } else
+ printf("System:\n Not booted with EFI\n");
+
+ r = status_binaries(arg_path, uuid);
+ if (r < 0)
+ return r;
+
+ if (arg_touch_variables)
+ r = status_variables();
break;
+ }
- case MORE:
- if (left < verbs[i].argc) {
- log_error("Too few arguments.");
- return -EINVAL;
+ case ACTION_INSTALL:
+ case ACTION_UPDATE:
+ umask(0002);
+
+ r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
+ if (r < 0)
+ return r;
+
+ if (arg_action == ACTION_INSTALL) {
+ r = install_loader_config(arg_path);
+ if (r < 0)
+ return r;
}
+
+ if (arg_touch_variables)
+ r = install_variables(arg_path,
+ part, pstart, psize, uuid,
+ "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
+ arg_action == ACTION_INSTALL);
break;
- case LESS:
- if (left > verbs[i].argc) {
- log_error("Too many arguments.");
- return -EINVAL;
+ case ACTION_REMOVE:
+ r = remove_binaries(arg_path);
+
+ if (arg_touch_variables) {
+ q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
+ if (q < 0 && r == 0)
+ r = q;
}
break;
-
- default:
- assert_not_reached("Unknown comparison operator.");
}
- return verbs[i].dispatch(argv + optind, left);
+ return r;
}
int main(int argc, char *argv[]) {
diff --git a/src/boot/efi/.gitignore b/src/boot/efi/.gitignore
new file mode 100644
index 0000000000..e193acbe12
--- /dev/null
+++ b/src/boot/efi/.gitignore
@@ -0,0 +1,2 @@
+/systemd_boot.so
+/stub.so
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
new file mode 100644
index 0000000000..eb1a4e3b66
--- /dev/null
+++ b/src/boot/efi/boot.c
@@ -0,0 +1,1834 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2015 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012-2015 Harald Hoyer <harald@redhat.com>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "console.h"
+#include "graphics.h"
+#include "pefile.h"
+#include "linux.h"
+
+#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
+#endif
+
+/* magic string to find in the binary image */
+static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot " VERSION " ####";
+
+static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
+
+enum loader_type {
+ LOADER_UNDEFINED,
+ LOADER_EFI,
+ LOADER_LINUX
+};
+
+typedef struct {
+ CHAR16 *file;
+ CHAR16 *title_show;
+ CHAR16 *title;
+ CHAR16 *version;
+ CHAR16 *machine_id;
+ EFI_HANDLE *device;
+ enum loader_type type;
+ CHAR16 *loader;
+ CHAR16 *options;
+ CHAR16 key;
+ EFI_STATUS (*call)(VOID);
+ BOOLEAN no_autoselect;
+ BOOLEAN non_unique;
+} ConfigEntry;
+
+typedef struct {
+ ConfigEntry **entries;
+ UINTN entry_count;
+ INTN idx_default;
+ INTN idx_default_efivar;
+ UINTN timeout_sec;
+ UINTN timeout_sec_config;
+ INTN timeout_sec_efivar;
+ CHAR16 *entry_default_pattern;
+ CHAR16 *entry_oneshot;
+ CHAR16 *options_edit;
+ BOOLEAN no_editor;
+} Config;
+
+static VOID cursor_left(UINTN *cursor, UINTN *first)
+{
+ if ((*cursor) > 0)
+ (*cursor)--;
+ else if ((*first) > 0)
+ (*first)--;
+}
+
+static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len)
+{
+ if ((*cursor)+1 < x_max)
+ (*cursor)++;
+ else if ((*first) + (*cursor) < len)
+ (*first)++;
+}
+
+static BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) {
+ CHAR16 *line;
+ UINTN size;
+ UINTN len;
+ UINTN first;
+ CHAR16 *print;
+ UINTN cursor;
+ UINTN clear;
+ BOOLEAN exit;
+ BOOLEAN enter;
+
+ if (!line_in)
+ line_in = L"";
+ size = StrLen(line_in) + 1024;
+ line = AllocatePool(size * sizeof(CHAR16));
+ StrCpy(line, line_in);
+ len = StrLen(line);
+ print = AllocatePool((x_max+1) * sizeof(CHAR16));
+
+ uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
+
+ first = 0;
+ cursor = 0;
+ clear = 0;
+ enter = FALSE;
+ exit = FALSE;
+ while (!exit) {
+ EFI_STATUS err;
+ UINT64 key;
+ UINTN i;
+
+ i = len - first;
+ if (i >= x_max-1)
+ i = x_max-1;
+ CopyMem(print, line + first, i * sizeof(CHAR16));
+ while (clear > 0 && i < x_max-1) {
+ clear--;
+ print[i++] = ' ';
+ }
+ print[i] = '\0';
+
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_pos);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, print);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
+
+ err = console_key_read(&key, TRUE);
+ if (EFI_ERROR(err))
+ continue;
+
+ switch (key) {
+ case KEYPRESS(0, SCAN_ESC, 0):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'c'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'g'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('c')):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('g')):
+ exit = TRUE;
+ break;
+
+ case KEYPRESS(0, SCAN_HOME, 0):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'a'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('a')):
+ /* beginning-of-line */
+ cursor = 0;
+ first = 0;
+ continue;
+
+ case KEYPRESS(0, SCAN_END, 0):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'e'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('e')):
+ /* end-of-line */
+ cursor = len - first;
+ if (cursor+1 >= x_max) {
+ cursor = x_max-1;
+ first = len - (x_max-1);
+ }
+ continue;
+
+ case KEYPRESS(0, SCAN_DOWN, 0):
+ case KEYPRESS(EFI_ALT_PRESSED, 0, 'f'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_RIGHT, 0):
+ /* forward-word */
+ while (line[first + cursor] && line[first + cursor] == ' ')
+ cursor_right(&cursor, &first, x_max, len);
+ while (line[first + cursor] && line[first + cursor] != ' ')
+ cursor_right(&cursor, &first, x_max, len);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
+ continue;
+
+ case KEYPRESS(0, SCAN_UP, 0):
+ case KEYPRESS(EFI_ALT_PRESSED, 0, 'b'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_LEFT, 0):
+ /* backward-word */
+ if ((first + cursor) > 0 && line[first + cursor-1] == ' ') {
+ cursor_left(&cursor, &first);
+ while ((first + cursor) > 0 && line[first + cursor] == ' ')
+ cursor_left(&cursor, &first);
+ }
+ while ((first + cursor) > 0 && line[first + cursor-1] != ' ')
+ cursor_left(&cursor, &first);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
+ continue;
+
+ case KEYPRESS(0, SCAN_RIGHT, 0):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'f'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('f')):
+ /* forward-char */
+ if (first + cursor == len)
+ continue;
+ cursor_right(&cursor, &first, x_max, len);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
+ continue;
+
+ case KEYPRESS(0, SCAN_LEFT, 0):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'b'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('b')):
+ /* backward-char */
+ cursor_left(&cursor, &first);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
+ continue;
+
+ case KEYPRESS(EFI_ALT_PRESSED, 0, 'd'):
+ /* kill-word */
+ clear = 0;
+ for (i = first + cursor; i < len && line[i] == ' '; i++)
+ clear++;
+ for (; i < len && line[i] != ' '; i++)
+ clear++;
+
+ for (i = first + cursor; i + clear < len; i++)
+ line[i] = line[i + clear];
+ len -= clear;
+ line[len] = '\0';
+ continue;
+
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'w'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('w')):
+ case KEYPRESS(EFI_ALT_PRESSED, 0, CHAR_BACKSPACE):
+ /* backward-kill-word */
+ clear = 0;
+ if ((first + cursor) > 0 && line[first + cursor-1] == ' ') {
+ cursor_left(&cursor, &first);
+ clear++;
+ while ((first + cursor) > 0 && line[first + cursor] == ' ') {
+ cursor_left(&cursor, &first);
+ clear++;
+ }
+ }
+ while ((first + cursor) > 0 && line[first + cursor-1] != ' ') {
+ cursor_left(&cursor, &first);
+ clear++;
+ }
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
+
+ for (i = first + cursor; i + clear < len; i++)
+ line[i] = line[i + clear];
+ len -= clear;
+ line[len] = '\0';
+ continue;
+
+ case KEYPRESS(0, SCAN_DELETE, 0):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'd'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('d')):
+ if (len == 0)
+ continue;
+ if (first + cursor == len)
+ continue;
+ for (i = first + cursor; i < len; i++)
+ line[i] = line[i+1];
+ clear = 1;
+ len--;
+ continue;
+
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'k'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('k')):
+ /* kill-line */
+ line[first + cursor] = '\0';
+ clear = len - (first + cursor);
+ len = first + cursor;
+ continue;
+
+ case KEYPRESS(0, 0, CHAR_LINEFEED):
+ case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
+ if (StrCmp(line, line_in) != 0) {
+ *line_out = line;
+ line = NULL;
+ }
+ enter = TRUE;
+ exit = TRUE;
+ break;
+
+ case KEYPRESS(0, 0, CHAR_BACKSPACE):
+ if (len == 0)
+ continue;
+ if (first == 0 && cursor == 0)
+ continue;
+ for (i = first + cursor-1; i < len; i++)
+ line[i] = line[i+1];
+ clear = 1;
+ len--;
+ if (cursor > 0)
+ cursor--;
+ if (cursor > 0 || first == 0)
+ continue;
+ /* show full line if it fits */
+ if (len < x_max) {
+ cursor = first;
+ first = 0;
+ continue;
+ }
+ /* jump left to see what we delete */
+ if (first > 10) {
+ first -= 10;
+ cursor = 10;
+ } else {
+ cursor = first;
+ first = 0;
+ }
+ continue;
+
+ case KEYPRESS(0, 0, ' ') ... KEYPRESS(0, 0, '~'):
+ case KEYPRESS(0, 0, 0x80) ... KEYPRESS(0, 0, 0xffff):
+ if (len+1 == size)
+ continue;
+ for (i = len; i > first + cursor; i--)
+ line[i] = line[i-1];
+ line[first + cursor] = KEYCHAR(key);
+ len++;
+ line[len] = '\0';
+ if (cursor+1 < x_max)
+ cursor++;
+ else if (first + cursor < len)
+ first++;
+ continue;
+ }
+ }
+
+ uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
+ FreePool(print);
+ FreePool(line);
+ return enter;
+}
+
+static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
+ UINTN i;
+
+ if (key == 0)
+ return -1;
+
+ /* select entry by number key */
+ if (key >= '1' && key <= '9') {
+ i = key - '0';
+ if (i > config->entry_count)
+ i = config->entry_count;
+ return i-1;
+ }
+
+ /* find matching key in config entries */
+ for (i = start; i < config->entry_count; i++)
+ if (config->entries[i]->key == key)
+ return i;
+
+ for (i = 0; i < start; i++)
+ if (config->entries[i]->key == key)
+ return i;
+
+ return -1;
+}
+
+static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
+ UINT64 key;
+ UINTN i;
+ CHAR16 *s;
+ CHAR8 *b;
+ UINTN x;
+ UINTN y;
+ UINTN size;
+
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
+
+ Print(L"systemd-boot version: " VERSION "\n");
+ Print(L"architecture: " EFI_MACHINE_TYPE_NAME "\n");
+ Print(L"loaded image: %s\n", loaded_image_path);
+ Print(L"UEFI specification: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
+ Print(L"firmware vendor: %s\n", ST->FirmwareVendor);
+ Print(L"firmware version: %d.%02d\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
+
+ if (uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x, &y) == EFI_SUCCESS)
+ Print(L"console size: %d x %d\n", x, y);
+
+ if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) {
+ Print(L"SecureBoot: %s\n", yes_no(*b > 0));
+ FreePool(b);
+ }
+
+ if (efivar_get_raw(&global_guid, L"SetupMode", &b, &size) == EFI_SUCCESS) {
+ Print(L"SetupMode: %s\n", *b > 0 ? L"setup" : L"user");
+ FreePool(b);
+ }
+
+ if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) {
+ Print(L"OsIndicationsSupported: %d\n", (UINT64)*b);
+ FreePool(b);
+ }
+ Print(L"\n");
+
+ Print(L"timeout: %d\n", config->timeout_sec);
+ if (config->timeout_sec_efivar >= 0)
+ Print(L"timeout (EFI var): %d\n", config->timeout_sec_efivar);
+ Print(L"timeout (config): %d\n", config->timeout_sec_config);
+ if (config->entry_default_pattern)
+ Print(L"default pattern: '%s'\n", config->entry_default_pattern);
+ Print(L"editor: %s\n", yes_no(!config->no_editor));
+ Print(L"\n");
+
+ Print(L"config entry count: %d\n", config->entry_count);
+ Print(L"entry selected idx: %d\n", config->idx_default);
+ if (config->idx_default_efivar >= 0)
+ Print(L"entry EFI var idx: %d\n", config->idx_default_efivar);
+ Print(L"\n");
+
+ if (efivar_get_int(L"LoaderConfigTimeout", &i) == EFI_SUCCESS)
+ Print(L"LoaderConfigTimeout: %d\n", i);
+ if (config->entry_oneshot)
+ Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot);
+ if (efivar_get(L"LoaderDevicePartUUID", &s) == EFI_SUCCESS) {
+ Print(L"LoaderDevicePartUUID: %s\n", s);
+ FreePool(s);
+ }
+ if (efivar_get(L"LoaderEntryDefault", &s) == EFI_SUCCESS) {
+ Print(L"LoaderEntryDefault: %s\n", s);
+ FreePool(s);
+ }
+
+ Print(L"\n--- press key ---\n\n");
+ console_key_read(&key, TRUE);
+
+ for (i = 0; i < config->entry_count; i++) {
+ ConfigEntry *entry;
+
+ if (key == KEYPRESS(0, SCAN_ESC, 0) || key == KEYPRESS(0, 0, 'q'))
+ break;
+
+ entry = config->entries[i];
+ Print(L"config entry: %d/%d\n", i+1, config->entry_count);
+ if (entry->file)
+ Print(L"file '%s'\n", entry->file);
+ Print(L"title show '%s'\n", entry->title_show);
+ if (entry->title)
+ Print(L"title '%s'\n", entry->title);
+ if (entry->version)
+ Print(L"version '%s'\n", entry->version);
+ if (entry->machine_id)
+ Print(L"machine-id '%s'\n", entry->machine_id);
+ if (entry->device) {
+ EFI_DEVICE_PATH *device_path;
+ CHAR16 *str;
+
+ device_path = DevicePathFromHandle(entry->device);
+ if (device_path) {
+ str = DevicePathToStr(device_path);
+ Print(L"device handle '%s'\n", str);
+ FreePool(str);
+ }
+ }
+ if (entry->loader)
+ Print(L"loader '%s'\n", entry->loader);
+ if (entry->options)
+ Print(L"options '%s'\n", entry->options);
+ Print(L"auto-select %s\n", yes_no(!entry->no_autoselect));
+ if (entry->call)
+ Print(L"internal call yes\n");
+
+ Print(L"\n--- press key ---\n\n");
+ console_key_read(&key, TRUE);
+ }
+
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
+}
+
+static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *loaded_image_path) {
+ EFI_STATUS err;
+ UINTN visible_max;
+ UINTN idx_highlight;
+ UINTN idx_highlight_prev;
+ UINTN idx_first;
+ UINTN idx_last;
+ BOOLEAN refresh;
+ BOOLEAN highlight;
+ UINTN i;
+ UINTN line_width;
+ CHAR16 **lines;
+ UINTN x_start;
+ UINTN y_start;
+ UINTN x_max;
+ UINTN y_max;
+ CHAR16 *status;
+ CHAR16 *clearline;
+ INTN timeout_remain;
+ INT16 idx;
+ BOOLEAN exit = FALSE;
+ BOOLEAN run = TRUE;
+ BOOLEAN wait = FALSE;
+
+ graphics_mode(FALSE);
+ uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
+ uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+
+ /* draw a single character to make ClearScreen work on some firmware */
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L" ");
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
+
+ err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
+ if (EFI_ERROR(err)) {
+ x_max = 80;
+ y_max = 25;
+ }
+
+ /* we check 10 times per second for a keystroke */
+ if (config->timeout_sec > 0)
+ timeout_remain = config->timeout_sec * 10;
+ else
+ timeout_remain = -1;
+
+ idx_highlight = config->idx_default;
+ idx_highlight_prev = 0;
+
+ visible_max = y_max - 2;
+
+ if ((UINTN)config->idx_default >= visible_max)
+ idx_first = config->idx_default-1;
+ else
+ idx_first = 0;
+
+ idx_last = idx_first + visible_max-1;
+
+ refresh = TRUE;
+ highlight = FALSE;
+
+ /* length of the longest entry */
+ line_width = 5;
+ for (i = 0; i < config->entry_count; i++) {
+ UINTN entry_len;
+
+ entry_len = StrLen(config->entries[i]->title_show);
+ if (line_width < entry_len)
+ line_width = entry_len;
+ }
+ if (line_width > x_max-6)
+ line_width = x_max-6;
+
+ /* offsets to center the entries on the screen */
+ x_start = (x_max - (line_width)) / 2;
+ if (config->entry_count < visible_max)
+ y_start = ((visible_max - config->entry_count) / 2) + 1;
+ else
+ y_start = 0;
+
+ /* menu entries title lines */
+ lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count);
+ for (i = 0; i < config->entry_count; i++) {
+ UINTN j, k;
+
+ lines[i] = AllocatePool(((x_max+1) * sizeof(CHAR16)));
+ for (j = 0; j < x_start; j++)
+ lines[i][j] = ' ';
+
+ for (k = 0; config->entries[i]->title_show[k] != '\0' && j < x_max; j++, k++)
+ lines[i][j] = config->entries[i]->title_show[k];
+
+ for (; j < x_max; j++)
+ lines[i][j] = ' ';
+ lines[i][x_max] = '\0';
+ }
+
+ status = NULL;
+ clearline = AllocatePool((x_max+1) * sizeof(CHAR16));
+ for (i = 0; i < x_max; i++)
+ clearline[i] = ' ';
+ clearline[i] = 0;
+
+ while (!exit) {
+ UINT64 key;
+
+ if (refresh) {
+ for (i = 0; i < config->entry_count; i++) {
+ if (i < idx_first || i > idx_last)
+ continue;
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + i - idx_first);
+ if (i == idx_highlight)
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
+ EFI_BLACK|EFI_BACKGROUND_LIGHTGRAY);
+ else
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
+ EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[i]);
+ if ((INTN)i == config->idx_default_efivar) {
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + i - idx_first);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>");
+ }
+ }
+ refresh = FALSE;
+ } else if (highlight) {
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + idx_highlight_prev - idx_first);
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[idx_highlight_prev]);
+ if ((INTN)idx_highlight_prev == config->idx_default_efivar) {
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + idx_highlight_prev - idx_first);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>");
+ }
+
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + idx_highlight - idx_first);
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_BLACK|EFI_BACKGROUND_LIGHTGRAY);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[idx_highlight]);
+ if ((INTN)idx_highlight == config->idx_default_efivar) {
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + idx_highlight - idx_first);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>");
+ }
+ highlight = FALSE;
+ }
+
+ if (timeout_remain > 0) {
+ FreePool(status);
+ status = PoolPrint(L"Boot in %d sec.", (timeout_remain + 5) / 10);
+ }
+
+ /* print status at last line of screen */
+ if (status) {
+ UINTN len;
+ UINTN x;
+
+ /* center line */
+ len = StrLen(status);
+ if (len < x_max)
+ x = (x_max - len) / 2;
+ else
+ x = 0;
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline + (x_max - x));
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, status);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len);
+ }
+
+ err = console_key_read(&key, wait);
+ if (EFI_ERROR(err)) {
+ /* timeout reached */
+ if (timeout_remain == 0) {
+ exit = TRUE;
+ break;
+ }
+
+ /* sleep and update status */
+ if (timeout_remain > 0) {
+ uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
+ timeout_remain--;
+ continue;
+ }
+
+ /* timeout disabled, wait for next key */
+ wait = TRUE;
+ continue;
+ }
+
+ timeout_remain = -1;
+
+ /* clear status after keystroke */
+ if (status) {
+ FreePool(status);
+ status = NULL;
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1);
+ }
+
+ idx_highlight_prev = idx_highlight;
+
+ switch (key) {
+ case KEYPRESS(0, SCAN_UP, 0):
+ case KEYPRESS(0, 0, 'k'):
+ if (idx_highlight > 0)
+ idx_highlight--;
+ break;
+
+ case KEYPRESS(0, SCAN_DOWN, 0):
+ case KEYPRESS(0, 0, 'j'):
+ if (idx_highlight < config->entry_count-1)
+ idx_highlight++;
+ break;
+
+ case KEYPRESS(0, SCAN_HOME, 0):
+ case KEYPRESS(EFI_ALT_PRESSED, 0, '<'):
+ if (idx_highlight > 0) {
+ refresh = TRUE;
+ idx_highlight = 0;
+ }
+ break;
+
+ case KEYPRESS(0, SCAN_END, 0):
+ case KEYPRESS(EFI_ALT_PRESSED, 0, '>'):
+ if (idx_highlight < config->entry_count-1) {
+ refresh = TRUE;
+ idx_highlight = config->entry_count-1;
+ }
+ break;
+
+ case KEYPRESS(0, SCAN_PAGE_UP, 0):
+ if (idx_highlight > visible_max)
+ idx_highlight -= visible_max;
+ else
+ idx_highlight = 0;
+ break;
+
+ case KEYPRESS(0, SCAN_PAGE_DOWN, 0):
+ idx_highlight += visible_max;
+ if (idx_highlight > config->entry_count-1)
+ idx_highlight = config->entry_count-1;
+ break;
+
+ case KEYPRESS(0, 0, CHAR_LINEFEED):
+ case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
+ exit = TRUE;
+ break;
+
+ case KEYPRESS(0, SCAN_F1, 0):
+ case KEYPRESS(0, 0, 'h'):
+ case KEYPRESS(0, 0, '?'):
+ status = StrDuplicate(L"(d)efault, (t/T)timeout, (e)dit, (v)ersion (Q)uit (P)rint (h)elp");
+ break;
+
+ case KEYPRESS(0, 0, 'Q'):
+ exit = TRUE;
+ run = FALSE;
+ break;
+
+ case KEYPRESS(0, 0, 'd'):
+ if (config->idx_default_efivar != (INTN)idx_highlight) {
+ /* store the selected entry in a persistent EFI variable */
+ efivar_set(L"LoaderEntryDefault", config->entries[idx_highlight]->file, TRUE);
+ config->idx_default_efivar = idx_highlight;
+ status = StrDuplicate(L"Default boot entry selected.");
+ } else {
+ /* clear the default entry EFI variable */
+ efivar_set(L"LoaderEntryDefault", NULL, TRUE);
+ config->idx_default_efivar = -1;
+ status = StrDuplicate(L"Default boot entry cleared.");
+ }
+ refresh = TRUE;
+ break;
+
+ case KEYPRESS(0, 0, '-'):
+ case KEYPRESS(0, 0, 'T'):
+ if (config->timeout_sec_efivar > 0) {
+ config->timeout_sec_efivar--;
+ efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE);
+ if (config->timeout_sec_efivar > 0)
+ status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar);
+ else
+ status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
+ } else if (config->timeout_sec_efivar <= 0){
+ config->timeout_sec_efivar = -1;
+ efivar_set(L"LoaderConfigTimeout", NULL, TRUE);
+ if (config->timeout_sec_config > 0)
+ status = PoolPrint(L"Menu timeout of %d sec is defined by configuration file.",
+ config->timeout_sec_config);
+ else
+ status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
+ }
+ break;
+
+ case KEYPRESS(0, 0, '+'):
+ case KEYPRESS(0, 0, 't'):
+ if (config->timeout_sec_efivar == -1 && config->timeout_sec_config == 0)
+ config->timeout_sec_efivar++;
+ config->timeout_sec_efivar++;
+ efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE);
+ if (config->timeout_sec_efivar > 0)
+ status = PoolPrint(L"Menu timeout set to %d sec.",
+ config->timeout_sec_efivar);
+ else
+ status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
+ break;
+
+ case KEYPRESS(0, 0, 'e'):
+ /* only the options of configured entries can be edited */
+ if (config->no_editor || config->entries[idx_highlight]->type == LOADER_UNDEFINED)
+ break;
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1);
+ if (line_edit(config->entries[idx_highlight]->options, &config->options_edit, x_max-1, y_max-1))
+ exit = TRUE;
+ uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
+ uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1);
+ break;
+
+ case KEYPRESS(0, 0, 'v'):
+ status = PoolPrint(L"systemd-boot " VERSION " (" EFI_MACHINE_TYPE_NAME "), UEFI Specification %d.%02d, Vendor %s %d.%02d",
+ ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff,
+ ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
+ break;
+
+ case KEYPRESS(0, 0, 'P'):
+ print_status(config, loaded_image_path);
+ refresh = TRUE;
+ break;
+
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'):
+ case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('l')):
+ refresh = TRUE;
+ break;
+
+ default:
+ /* jump with a hotkey directly to a matching entry */
+ idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key));
+ if (idx < 0)
+ break;
+ idx_highlight = idx;
+ refresh = TRUE;
+ }
+
+ if (idx_highlight > idx_last) {
+ idx_last = idx_highlight;
+ idx_first = 1 + idx_highlight - visible_max;
+ refresh = TRUE;
+ } else if (idx_highlight < idx_first) {
+ idx_first = idx_highlight;
+ idx_last = idx_highlight + visible_max-1;
+ refresh = TRUE;
+ }
+
+ if (!refresh && idx_highlight != idx_highlight_prev)
+ highlight = TRUE;
+ }
+
+ *chosen_entry = config->entries[idx_highlight];
+
+ for (i = 0; i < config->entry_count; i++)
+ FreePool(lines[i]);
+ FreePool(lines);
+ FreePool(clearline);
+
+ uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_WHITE|EFI_BACKGROUND_BLACK);
+ uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
+ return run;
+}
+
+static VOID config_add_entry(Config *config, ConfigEntry *entry) {
+ if ((config->entry_count & 15) == 0) {
+ UINTN i;
+
+ i = config->entry_count + 16;
+ if (config->entry_count == 0)
+ config->entries = AllocatePool(sizeof(VOID *) * i);
+ else
+ config->entries = ReallocatePool(config->entries,
+ sizeof(VOID *) * config->entry_count, sizeof(VOID *) * i);
+ }
+ config->entries[config->entry_count++] = entry;
+}
+
+static VOID config_entry_free(ConfigEntry *entry) {
+ FreePool(entry->title_show);
+ FreePool(entry->title);
+ FreePool(entry->machine_id);
+ FreePool(entry->loader);
+ FreePool(entry->options);
+}
+
+static BOOLEAN is_digit(CHAR16 c)
+{
+ return (c >= '0') && (c <= '9');
+}
+
+static UINTN c_order(CHAR16 c)
+{
+ if (c == '\0')
+ return 0;
+ if (is_digit(c))
+ return 0;
+ else if ((c >= 'a') && (c <= 'z'))
+ return c;
+ else
+ return c + 0x10000;
+}
+
+static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2)
+{
+ CHAR16 *os1 = s1;
+ CHAR16 *os2 = s2;
+
+ while (*s1 || *s2) {
+ INTN first;
+
+ while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
+ INTN order;
+
+ order = c_order(*s1) - c_order(*s2);
+ if (order)
+ return order;
+ s1++;
+ s2++;
+ }
+
+ while (*s1 == '0')
+ s1++;
+ while (*s2 == '0')
+ s2++;
+
+ first = 0;
+ while (is_digit(*s1) && is_digit(*s2)) {
+ if (first == 0)
+ first = *s1 - *s2;
+ s1++;
+ s2++;
+ }
+
+ if (is_digit(*s1))
+ return 1;
+ if (is_digit(*s2))
+ return -1;
+
+ if (first)
+ return first;
+ }
+
+ return StrCmp(os1, os2);
+}
+
+static CHAR8 *line_get_key_value(CHAR8 *content, CHAR8 *sep, UINTN *pos, CHAR8 **key_ret, CHAR8 **value_ret) {
+ CHAR8 *line;
+ UINTN linelen;
+ CHAR8 *value;
+
+skip:
+ line = content + *pos;
+ if (*line == '\0')
+ return NULL;
+
+ linelen = 0;
+ while (line[linelen] && !strchra((CHAR8 *)"\n\r", line[linelen]))
+ linelen++;
+
+ /* move pos to next line */
+ *pos += linelen;
+ if (content[*pos])
+ (*pos)++;
+
+ /* empty line */
+ if (linelen == 0)
+ goto skip;
+
+ /* terminate line */
+ line[linelen] = '\0';
+
+ /* remove leading whitespace */
+ while (strchra((CHAR8 *)" \t", *line)) {
+ line++;
+ linelen--;
+ }
+
+ /* remove trailing whitespace */
+ while (linelen > 0 && strchra(sep, line[linelen-1]))
+ linelen--;
+ line[linelen] = '\0';
+
+ if (*line == '#')
+ goto skip;
+
+ /* split key/value */
+ value = line;
+ while (*value && !strchra(sep, *value))
+ value++;
+ if (*value == '\0')
+ goto skip;
+ *value = '\0';
+ value++;
+ while (*value && strchra(sep, *value))
+ value++;
+
+ /* unquote */
+ if (value[0] == '\"' && line[linelen-1] == '\"') {
+ value++;
+ line[linelen-1] = '\0';
+ }
+
+ *key_ret = line;
+ *value_ret = value;
+ return line;
+}
+
+static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
+ CHAR8 *line;
+ UINTN pos = 0;
+ CHAR8 *key, *value;
+
+ line = content;
+ while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) {
+ if (strcmpa((CHAR8 *)"timeout", key) == 0) {
+ CHAR16 *s;
+
+ s = stra_to_str(value);
+ config->timeout_sec_config = Atoi(s);
+ config->timeout_sec = config->timeout_sec_config;
+ FreePool(s);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"default", key) == 0) {
+ FreePool(config->entry_default_pattern);
+ config->entry_default_pattern = stra_to_str(value);
+ StrLwr(config->entry_default_pattern);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"editor", key) == 0) {
+ BOOLEAN on;
+
+ if (EFI_ERROR(parse_boolean(value, &on)))
+ continue;
+ config->no_editor = !on;
+ }
+ }
+}
+
+static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR16 *file, CHAR8 *content, CHAR16 *loaded_image_path) {
+ ConfigEntry *entry;
+ CHAR8 *line;
+ UINTN pos = 0;
+ CHAR8 *key, *value;
+ UINTN len;
+ CHAR16 *initrd = NULL;
+
+ entry = AllocateZeroPool(sizeof(ConfigEntry));
+
+ line = content;
+ while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) {
+ if (strcmpa((CHAR8 *)"title", key) == 0) {
+ FreePool(entry->title);
+ entry->title = stra_to_str(value);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"version", key) == 0) {
+ FreePool(entry->version);
+ entry->version = stra_to_str(value);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"machine-id", key) == 0) {
+ FreePool(entry->machine_id);
+ entry->machine_id = stra_to_str(value);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"linux", key) == 0) {
+ FreePool(entry->loader);
+ entry->type = LOADER_LINUX;
+ entry->loader = stra_to_path(value);
+ entry->key = 'l';
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"efi", key) == 0) {
+ entry->type = LOADER_EFI;
+ FreePool(entry->loader);
+ entry->loader = stra_to_path(value);
+
+ /* do not add an entry for ourselves */
+ if (StriCmp(entry->loader, loaded_image_path) == 0) {
+ entry->type = LOADER_UNDEFINED;
+ break;
+ }
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"architecture", key) == 0) {
+ /* do not add an entry for an EFI image of architecture not matching with that of the image */
+ if (strcmpa((CHAR8 *)EFI_MACHINE_TYPE_NAME, value) != 0) {
+ entry->type = LOADER_UNDEFINED;
+ break;
+ }
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"initrd", key) == 0) {
+ CHAR16 *new;
+
+ new = stra_to_path(value);
+ if (initrd) {
+ CHAR16 *s;
+
+ s = PoolPrint(L"%s initrd=%s", initrd, new);
+ FreePool(initrd);
+ initrd = s;
+ } else
+ initrd = PoolPrint(L"initrd=%s", new);
+ FreePool(new);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"options", key) == 0) {
+ CHAR16 *new;
+
+ new = stra_to_str(value);
+ if (entry->options) {
+ CHAR16 *s;
+
+ s = PoolPrint(L"%s %s", entry->options, new);
+ FreePool(entry->options);
+ entry->options = s;
+ } else {
+ entry->options = new;
+ new = NULL;
+ }
+ FreePool(new);
+ continue;
+ }
+ }
+
+ if (entry->type == LOADER_UNDEFINED) {
+ config_entry_free(entry);
+ FreePool(initrd);
+ FreePool(entry);
+ return;
+ }
+
+ /* add initrd= to options */
+ if (entry->type == LOADER_LINUX && initrd) {
+ if (entry->options) {
+ CHAR16 *s;
+
+ s = PoolPrint(L"%s %s", initrd, entry->options);
+ FreePool(entry->options);
+ entry->options = s;
+ } else {
+ entry->options = initrd;
+ initrd = NULL;
+ }
+ }
+ FreePool(initrd);
+
+ entry->device = device;
+ entry->file = StrDuplicate(file);
+ len = StrLen(entry->file);
+ /* remove ".conf" */
+ if (len > 5)
+ entry->file[len - 5] = '\0';
+ StrLwr(entry->file);
+
+ config_add_entry(config, entry);
+}
+
+static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) {
+ EFI_FILE_HANDLE entries_dir;
+ EFI_STATUS err;
+ CHAR8 *content = NULL;
+ UINTN sec;
+ UINTN len;
+ UINTN i;
+
+ len = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content);
+ if (len > 0)
+ config_defaults_load_from_file(config, content);
+ FreePool(content);
+
+ err = efivar_get_int(L"LoaderConfigTimeout", &sec);
+ if (!EFI_ERROR(err)) {
+ config->timeout_sec_efivar = sec;
+ config->timeout_sec = sec;
+ } else
+ config->timeout_sec_efivar = -1;
+
+ err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL);
+ if (!EFI_ERROR(err)) {
+ for (;;) {
+ CHAR16 buf[256];
+ UINTN bufsize;
+ EFI_FILE_INFO *f;
+ CHAR8 *content = NULL;
+ UINTN len;
+
+ bufsize = sizeof(buf);
+ err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf);
+ if (bufsize == 0 || EFI_ERROR(err))
+ break;
+
+ f = (EFI_FILE_INFO *) buf;
+ if (f->FileName[0] == '.')
+ continue;
+ if (f->Attribute & EFI_FILE_DIRECTORY)
+ continue;
+
+ len = StrLen(f->FileName);
+ if (len < 6)
+ continue;
+ if (StriCmp(f->FileName + len - 5, L".conf") != 0)
+ continue;
+ if (StrnCmp(f->FileName, L"auto-", 5) == 0)
+ continue;
+
+ len = file_read(entries_dir, f->FileName, 0, 0, &content);
+ if (len > 0)
+ config_entry_add_from_file(config, device, f->FileName, content, loaded_image_path);
+ FreePool(content);
+ }
+ uefi_call_wrapper(entries_dir->Close, 1, entries_dir);
+ }
+
+ /* sort entries after version number */
+ for (i = 1; i < config->entry_count; i++) {
+ BOOLEAN more;
+ UINTN k;
+
+ more = FALSE;
+ for (k = 0; k < config->entry_count - i; k++) {
+ ConfigEntry *entry;
+
+ if (str_verscmp(config->entries[k]->file, config->entries[k+1]->file) <= 0)
+ continue;
+ entry = config->entries[k];
+ config->entries[k] = config->entries[k+1];
+ config->entries[k+1] = entry;
+ more = TRUE;
+ }
+ if (!more)
+ break;
+ }
+}
+
+static VOID config_default_entry_select(Config *config) {
+ CHAR16 *var;
+ EFI_STATUS err;
+ UINTN i;
+
+ /*
+ * The EFI variable to specify a boot entry for the next, and only the
+ * next reboot. The variable is always cleared directly after it is read.
+ */
+ err = efivar_get(L"LoaderEntryOneShot", &var);
+ if (!EFI_ERROR(err)) {
+ BOOLEAN found = FALSE;
+
+ for (i = 0; i < config->entry_count; i++) {
+ if (StrCmp(config->entries[i]->file, var) == 0) {
+ config->idx_default = i;
+ found = TRUE;
+ break;
+ }
+ }
+
+ config->entry_oneshot = StrDuplicate(var);
+ efivar_set(L"LoaderEntryOneShot", NULL, TRUE);
+ FreePool(var);
+ if (found)
+ return;
+ }
+
+ /*
+ * The EFI variable to select the default boot entry overrides the
+ * configured pattern. The variable can be set and cleared by pressing
+ * the 'd' key in the loader selection menu, the entry is marked with
+ * an '*'.
+ */
+ err = efivar_get(L"LoaderEntryDefault", &var);
+ if (!EFI_ERROR(err)) {
+ BOOLEAN found = FALSE;
+
+ for (i = 0; i < config->entry_count; i++) {
+ if (StrCmp(config->entries[i]->file, var) == 0) {
+ config->idx_default = i;
+ config->idx_default_efivar = i;
+ found = TRUE;
+ break;
+ }
+ }
+ FreePool(var);
+ if (found)
+ return;
+ }
+ config->idx_default_efivar = -1;
+
+ if (config->entry_count == 0)
+ return;
+
+ /*
+ * Match the pattern from the end of the list to the start, find last
+ * entry (largest number) matching the given pattern.
+ */
+ if (config->entry_default_pattern) {
+ i = config->entry_count;
+ while (i--) {
+ if (config->entries[i]->no_autoselect)
+ continue;
+ if (MetaiMatch(config->entries[i]->file, config->entry_default_pattern)) {
+ config->idx_default = i;
+ return;
+ }
+ }
+ }
+
+ /* select the last suitable entry */
+ i = config->entry_count;
+ while (i--) {
+ if (config->entries[i]->no_autoselect)
+ continue;
+ config->idx_default = i;
+ return;
+ }
+
+ /* no entry found */
+ config->idx_default = -1;
+}
+
+/* generate a unique title, avoiding non-distinguishable menu entries */
+static VOID config_title_generate(Config *config) {
+ UINTN i, k;
+ BOOLEAN unique;
+
+ /* set title */
+ for (i = 0; i < config->entry_count; i++) {
+ CHAR16 *title;
+
+ FreePool(config->entries[i]->title_show);
+ title = config->entries[i]->title;
+ if (!title)
+ title = config->entries[i]->file;
+ config->entries[i]->title_show = StrDuplicate(title);
+ }
+
+ unique = TRUE;
+ for (i = 0; i < config->entry_count; i++) {
+ for (k = 0; k < config->entry_count; k++) {
+ if (i == k)
+ continue;
+ if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0)
+ continue;
+
+ unique = FALSE;
+ config->entries[i]->non_unique = TRUE;
+ config->entries[k]->non_unique = TRUE;
+ }
+ }
+ if (unique)
+ return;
+
+ /* add version to non-unique titles */
+ for (i = 0; i < config->entry_count; i++) {
+ CHAR16 *s;
+
+ if (!config->entries[i]->non_unique)
+ continue;
+ if (!config->entries[i]->version)
+ continue;
+
+ s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, config->entries[i]->version);
+ FreePool(config->entries[i]->title_show);
+ config->entries[i]->title_show = s;
+ config->entries[i]->non_unique = FALSE;
+ }
+
+ unique = TRUE;
+ for (i = 0; i < config->entry_count; i++) {
+ for (k = 0; k < config->entry_count; k++) {
+ if (i == k)
+ continue;
+ if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0)
+ continue;
+
+ unique = FALSE;
+ config->entries[i]->non_unique = TRUE;
+ config->entries[k]->non_unique = TRUE;
+ }
+ }
+ if (unique)
+ return;
+
+ /* add machine-id to non-unique titles */
+ for (i = 0; i < config->entry_count; i++) {
+ CHAR16 *s;
+ CHAR16 *m;
+
+ if (!config->entries[i]->non_unique)
+ continue;
+ if (!config->entries[i]->machine_id)
+ continue;
+
+ m = StrDuplicate(config->entries[i]->machine_id);
+ m[8] = '\0';
+ s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, m);
+ FreePool(config->entries[i]->title_show);
+ config->entries[i]->title_show = s;
+ config->entries[i]->non_unique = FALSE;
+ FreePool(m);
+ }
+
+ unique = TRUE;
+ for (i = 0; i < config->entry_count; i++) {
+ for (k = 0; k < config->entry_count; k++) {
+ if (i == k)
+ continue;
+ if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0)
+ continue;
+
+ unique = FALSE;
+ config->entries[i]->non_unique = TRUE;
+ config->entries[k]->non_unique = TRUE;
+ }
+ }
+ if (unique)
+ return;
+
+ /* add file name to non-unique titles */
+ for (i = 0; i < config->entry_count; i++) {
+ CHAR16 *s;
+
+ if (!config->entries[i]->non_unique)
+ continue;
+ s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, config->entries[i]->file);
+ FreePool(config->entries[i]->title_show);
+ config->entries[i]->title_show = s;
+ config->entries[i]->non_unique = FALSE;
+ }
+}
+
+static BOOLEAN config_entry_add_call(Config *config, CHAR16 *title, EFI_STATUS (*call)(VOID)) {
+ ConfigEntry *entry;
+
+ entry = AllocateZeroPool(sizeof(ConfigEntry));
+ entry->title = StrDuplicate(title);
+ entry->call = call;
+ entry->no_autoselect = TRUE;
+ config_add_entry(config, entry);
+ return TRUE;
+}
+
+static ConfigEntry *config_entry_add_loader(Config *config, EFI_HANDLE *device,
+ enum loader_type type,CHAR16 *file, CHAR16 key, CHAR16 *title, CHAR16 *loader) {
+ ConfigEntry *entry;
+
+ entry = AllocateZeroPool(sizeof(ConfigEntry));
+ entry->type = type;
+ entry->title = StrDuplicate(title);
+ entry->device = device;
+ entry->loader = StrDuplicate(loader);
+ entry->file = StrDuplicate(file);
+ StrLwr(entry->file);
+ entry->key = key;
+ config_add_entry(config, entry);
+
+ return entry;
+}
+
+static BOOLEAN config_entry_add_loader_auto(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path,
+ CHAR16 *file, CHAR16 key, CHAR16 *title, CHAR16 *loader) {
+ EFI_FILE_HANDLE handle;
+ ConfigEntry *entry;
+ EFI_STATUS err;
+
+ /* do not add an entry for ourselves */
+ if (loaded_image_path && StriCmp(loader, loaded_image_path) == 0)
+ return FALSE;
+
+ /* check existence */
+ err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, loader, EFI_FILE_MODE_READ, 0ULL);
+ if (EFI_ERROR(err))
+ return FALSE;
+ uefi_call_wrapper(handle->Close, 1, handle);
+
+ entry = config_entry_add_loader(config, device, LOADER_UNDEFINED, file, key, title, loader);
+ if (!entry)
+ return FALSE;
+
+ /* do not boot right away into auto-detected entries */
+ entry->no_autoselect = TRUE;
+
+ return TRUE;
+}
+
+static VOID config_entry_add_osx(Config *config) {
+ EFI_STATUS err;
+ UINTN handle_count = 0;
+ EFI_HANDLE *handles = NULL;
+
+ err = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handle_count, &handles);
+ if (!EFI_ERROR(err)) {
+ UINTN i;
+
+ for (i = 0; i < handle_count; i++) {
+ EFI_FILE *root;
+ BOOLEAN found;
+
+ root = LibOpenRoot(handles[i]);
+ if (!root)
+ continue;
+ found = config_entry_add_loader_auto(config, handles[i], root, NULL, L"auto-osx", 'a', L"OS X",
+ L"\\System\\Library\\CoreServices\\boot.efi");
+ uefi_call_wrapper(root->Close, 1, root);
+ if (found)
+ break;
+ }
+
+ FreePool(handles);
+ }
+}
+
+static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) {
+ EFI_FILE_HANDLE linux_dir;
+ EFI_STATUS err;
+
+ err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL);
+ if (!EFI_ERROR(err)) {
+ for (;;) {
+ CHAR16 buf[256];
+ UINTN bufsize;
+ EFI_FILE_INFO *f;
+ CHAR8 *sections[] = {
+ (UINT8 *)".osrel",
+ NULL
+ };
+ UINTN offs[ELEMENTSOF(sections)-1] = {};
+ UINTN szs[ELEMENTSOF(sections)-1] = {};
+ UINTN addrs[ELEMENTSOF(sections)-1] = {};
+ CHAR8 *content = NULL;
+ UINTN len;
+ CHAR8 *line;
+ UINTN pos = 0;
+ CHAR8 *key, *value;
+ CHAR16 *os_name = NULL;
+ CHAR16 *os_id = NULL;
+ CHAR16 *os_version = NULL;
+
+ bufsize = sizeof(buf);
+ err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf);
+ if (bufsize == 0 || EFI_ERROR(err))
+ break;
+
+ f = (EFI_FILE_INFO *) buf;
+ if (f->FileName[0] == '.')
+ continue;
+ if (f->Attribute & EFI_FILE_DIRECTORY)
+ continue;
+ len = StrLen(f->FileName);
+ if (len < 5)
+ continue;
+ if (StriCmp(f->FileName + len - 4, L".efi") != 0)
+ continue;
+
+ /* look for an .osrel section in the .efi binary */
+ err = pefile_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs);
+ if (EFI_ERROR(err))
+ continue;
+
+ len = file_read(linux_dir, f->FileName, offs[0], szs[0], &content);
+ if (len <= 0)
+ continue;
+
+ /* read properties from the embedded os-release file */
+ line = content;
+ while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) {
+ if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) {
+ os_name = stra_to_str(value);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"ID", key) == 0) {
+ os_id = stra_to_str(value);
+ continue;
+ }
+
+ if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) {
+ os_version = stra_to_str(value);
+ continue;
+ }
+ }
+
+ if (os_name && os_id && os_version) {
+ CHAR16 *conf;
+ CHAR16 *path;
+
+ conf = PoolPrint(L"%s-%s", os_id, os_version);
+ path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
+ config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
+ FreePool(conf);
+ FreePool(path);
+ FreePool(os_name);
+ FreePool(os_id);
+ FreePool(os_version);
+ }
+
+ FreePool(content);
+ }
+ uefi_call_wrapper(linux_dir->Close, 1, linux_dir);
+ }
+}
+
+static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, const ConfigEntry *entry) {
+ EFI_HANDLE image;
+ EFI_DEVICE_PATH *path;
+ CHAR16 *options;
+ EFI_STATUS err;
+
+ path = FileDevicePath(entry->device, entry->loader);
+ if (!path) {
+ Print(L"Error getting device path.");
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ err = uefi_call_wrapper(BS->LoadImage, 6, FALSE, parent_image, path, NULL, 0, &image);
+ if (EFI_ERROR(err)) {
+ Print(L"Error loading %s: %r", entry->loader, err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ goto out;
+ }
+
+ if (config->options_edit)
+ options = config->options_edit;
+ else if (entry->options)
+ options = entry->options;
+ else
+ options = NULL;
+ if (options) {
+ EFI_LOADED_IMAGE *loaded_image;
+
+ err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
+ parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(err)) {
+ Print(L"Error getting LoadedImageProtocol handle: %r", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ goto out_unload;
+ }
+ loaded_image->LoadOptions = options;
+ loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16);
+ }
+
+ efivar_set_time_usec(L"LoaderTimeExecUSec", 0);
+ err = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL);
+out_unload:
+ uefi_call_wrapper(BS->UnloadImage, 1, image);
+out:
+ FreePool(path);
+ return err;
+}
+
+static EFI_STATUS reboot_into_firmware(VOID) {
+ CHAR8 *b;
+ UINTN size;
+ UINT64 osind;
+ EFI_STATUS err;
+
+ osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+
+ err = efivar_get_raw(&global_guid, L"OsIndications", &b, &size);
+ if (!EFI_ERROR(err))
+ osind |= (UINT64)*b;
+ FreePool(b);
+
+ err = efivar_set_raw(&global_guid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE);
+ if (EFI_ERROR(err))
+ return err;
+
+ err = uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL);
+ Print(L"Error calling ResetSystem: %r", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+}
+
+static VOID config_free(Config *config) {
+ UINTN i;
+
+ for (i = 0; i < config->entry_count; i++)
+ config_entry_free(config->entries[i]);
+ FreePool(config->entries);
+ FreePool(config->entry_default_pattern);
+ FreePool(config->options_edit);
+ FreePool(config->entry_oneshot);
+}
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+ CHAR16 *s;
+ CHAR8 *b;
+ UINTN size;
+ EFI_LOADED_IMAGE *loaded_image;
+ EFI_FILE *root_dir;
+ CHAR16 *loaded_image_path;
+ EFI_DEVICE_PATH *device_path;
+ EFI_STATUS err;
+ Config config;
+ UINT64 init_usec;
+ BOOLEAN menu = FALSE;
+
+ InitializeLib(image, sys_table);
+ init_usec = time_usec();
+ efivar_set_time_usec(L"LoaderTimeInitUSec", init_usec);
+ efivar_set(L"LoaderInfo", L"systemd-boot " VERSION, FALSE);
+ s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
+ efivar_set(L"LoaderFirmwareInfo", s, FALSE);
+ FreePool(s);
+ s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
+ efivar_set(L"LoaderFirmwareType", s, FALSE);
+ FreePool(s);
+
+ err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
+ image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(err)) {
+ Print(L"Error getting a LoadedImageProtocol handle: %r ", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+ }
+
+ /* export the device path this image is started from */
+ device_path = DevicePathFromHandle(loaded_image->DeviceHandle);
+ if (device_path) {
+ EFI_DEVICE_PATH *path, *paths;
+
+ paths = UnpackDevicePath(device_path);
+ for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) {
+ HARDDRIVE_DEVICE_PATH *drive;
+ CHAR16 uuid[37];
+
+ if (DevicePathType(path) != MEDIA_DEVICE_PATH)
+ continue;
+ if (DevicePathSubType(path) != MEDIA_HARDDRIVE_DP)
+ continue;
+ drive = (HARDDRIVE_DEVICE_PATH *)path;
+ if (drive->SignatureType != SIGNATURE_TYPE_GUID)
+ continue;
+
+ GuidToString(uuid, (EFI_GUID *)&drive->Signature);
+ efivar_set(L"LoaderDevicePartUUID", uuid, FALSE);
+ break;
+ }
+ FreePool(paths);
+ }
+
+ root_dir = LibOpenRoot(loaded_image->DeviceHandle);
+ if (!root_dir) {
+ Print(L"Unable to open root directory: %r ", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return EFI_LOAD_ERROR;
+ }
+
+
+ /* the filesystem path to this image, to prevent adding ourselves to the menu */
+ loaded_image_path = DevicePathToStr(loaded_image->FilePath);
+ efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE);
+
+ /* scan "\loader\entries\*.conf" files */
+ ZeroMem(&config, sizeof(Config));
+ config_load(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
+
+ /* if we find some well-known loaders, add them to the end of the list */
+ config_entry_add_linux(&config, loaded_image, root_dir);
+ config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
+ L"auto-windows", 'w', L"Windows Boot Manager", L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
+ config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
+ L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
+ config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
+ L"auto-efi-default", '\0', L"EFI Default Loader", L"\\EFI\\Boot\\boot" EFI_MACHINE_TYPE_NAME ".efi");
+ config_entry_add_osx(&config);
+
+ if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) {
+ UINT64 osind = (UINT64)*b;
+
+ if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
+ config_entry_add_call(&config, L"Reboot Into Firmware Interface", reboot_into_firmware);
+ FreePool(b);
+ }
+
+ if (config.entry_count == 0) {
+ Print(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ goto out;
+ }
+
+ config_title_generate(&config);
+
+ /* select entry by configured pattern or EFI LoaderDefaultEntry= variable*/
+ config_default_entry_select(&config);
+
+ /* if no configured entry to select from was found, enable the menu */
+ if (config.idx_default == -1) {
+ config.idx_default = 0;
+ if (config.timeout_sec == 0)
+ config.timeout_sec = 10;
+ }
+
+ /* select entry or show menu when key is pressed or timeout is set */
+ if (config.timeout_sec == 0) {
+ UINT64 key;
+
+ err = console_key_read(&key, FALSE);
+ if (!EFI_ERROR(err)) {
+ INT16 idx;
+
+ /* find matching key in config entries */
+ idx = entry_lookup_key(&config, config.idx_default, KEYCHAR(key));
+ if (idx >= 0)
+ config.idx_default = idx;
+ else
+ menu = TRUE;
+ }
+ } else
+ menu = TRUE;
+
+ for (;;) {
+ ConfigEntry *entry;
+
+ entry = config.entries[config.idx_default];
+ if (menu) {
+ efivar_set_time_usec(L"LoaderTimeMenuUSec", 0);
+ uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL);
+ if (!menu_run(&config, &entry, loaded_image_path))
+ break;
+
+ /* run special entry like "reboot" */
+ if (entry->call) {
+ entry->call();
+ continue;
+ }
+ }
+
+ /* export the selected boot entry to the system */
+ efivar_set(L"LoaderEntrySelected", entry->file, FALSE);
+
+ uefi_call_wrapper(BS->SetWatchdogTimer, 4, 5 * 60, 0x10000, 0, NULL);
+ err = image_start(image, &config, entry);
+ if (EFI_ERROR(err)) {
+ graphics_mode(FALSE);
+ Print(L"\nFailed to execute %s (%s): %r\n", entry->title, entry->loader, err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ goto out;
+ }
+
+ menu = TRUE;
+ config.timeout_sec = 0;
+ }
+ err = EFI_SUCCESS;
+out:
+ FreePool(loaded_image_path);
+ config_free(&config);
+ uefi_call_wrapper(root_dir->Close, 1, root_dir);
+ uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
+ return err;
+}
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
new file mode 100644
index 0000000000..66aa88f32e
--- /dev/null
+++ b/src/boot/efi/console.c
@@ -0,0 +1,141 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "console.h"
+
+#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
+ { 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }
+
+struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
+
+typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)(
+ struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ BOOLEAN ExtendedVerification
+);
+
+typedef UINT8 EFI_KEY_TOGGLE_STATE;
+
+typedef struct {
+ UINT32 KeyShiftState;
+ EFI_KEY_TOGGLE_STATE KeyToggleState;
+} EFI_KEY_STATE;
+
+typedef struct {
+ EFI_INPUT_KEY Key;
+ EFI_KEY_STATE KeyState;
+} EFI_KEY_DATA;
+
+typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)(
+ struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ EFI_KEY_DATA *KeyData
+);
+
+typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)(
+ struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ EFI_KEY_TOGGLE_STATE *KeyToggleState
+);
+
+typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)(
+ EFI_KEY_DATA *KeyData
+);
+
+typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)(
+ struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ EFI_KEY_DATA KeyData,
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ VOID **NotifyHandle
+);
+
+typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)(
+ struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ VOID *NotificationHandle
+);
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
+ EFI_INPUT_RESET_EX Reset;
+ EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
+ EFI_EVENT WaitForKeyEx;
+ EFI_SET_STATE SetState;
+ EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
+ EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
+} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
+
+EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
+ EFI_GUID EfiSimpleTextInputExProtocolGuid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+ static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx;
+ static BOOLEAN checked;
+ UINTN index;
+ EFI_INPUT_KEY k;
+ EFI_STATUS err;
+
+ if (!checked) {
+ err = LibLocateProtocol(&EfiSimpleTextInputExProtocolGuid, (VOID **)&TextInputEx);
+ if (EFI_ERROR(err))
+ TextInputEx = NULL;
+
+ checked = TRUE;
+ }
+
+ /* wait until key is pressed */
+ if (wait) {
+ if (TextInputEx)
+ uefi_call_wrapper(BS->WaitForEvent, 3, 1, &TextInputEx->WaitForKeyEx, &index);
+ else
+ uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index);
+ }
+
+ if (TextInputEx) {
+ EFI_KEY_DATA keydata;
+ UINT64 keypress;
+
+ err = uefi_call_wrapper(TextInputEx->ReadKeyStrokeEx, 2, TextInputEx, &keydata);
+ if (!EFI_ERROR(err)) {
+ UINT32 shift = 0;
+
+ /* do not distinguish between left and right keys */
+ if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) {
+ if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED))
+ shift |= EFI_CONTROL_PRESSED;
+ if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED))
+ shift |= EFI_ALT_PRESSED;
+ };
+
+ /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
+ keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar);
+ if (keypress > 0) {
+ *key = keypress;
+ return 0;
+ }
+ }
+ }
+
+ /* fallback for firmware which does not support SimpleTextInputExProtocol
+ *
+ * This is also called in case ReadKeyStrokeEx did not return a key, because
+ * some broken firmwares offer SimpleTextInputExProtocol, but never acually
+ * handle any key. */
+ err = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k);
+ if (EFI_ERROR(err))
+ return err;
+
+ *key = KEYPRESS(0, k.ScanCode, k.UnicodeChar);
+ return 0;
+}
diff --git a/src/boot/efi/console.h b/src/boot/efi/console.h
new file mode 100644
index 0000000000..5c7808a067
--- /dev/null
+++ b/src/boot/efi/console.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ */
+
+#ifndef __SDBOOT_CONSOLE_H
+#define __SDBOOT_CONSOLE_H
+
+#define EFI_SHIFT_STATE_VALID 0x80000000
+#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
+#define EFI_LEFT_CONTROL_PRESSED 0x00000008
+#define EFI_RIGHT_ALT_PRESSED 0x00000010
+#define EFI_LEFT_ALT_PRESSED 0x00000020
+
+#define EFI_CONTROL_PRESSED (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED)
+#define EFI_ALT_PRESSED (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED)
+#define KEYPRESS(keys, scan, uni) ((((UINT64)keys) << 32) | ((scan) << 16) | (uni))
+#define KEYCHAR(k) ((k) & 0xffff)
+#define CHAR_CTRL(c) ((c) - 'a' + 1)
+
+EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait);
+#endif
diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c
new file mode 100644
index 0000000000..2e9c11f5a0
--- /dev/null
+++ b/src/boot/efi/graphics.c
@@ -0,0 +1,91 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ * Copyright (C) 2013 Intel Corporation
+ * Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "graphics.h"
+
+EFI_STATUS graphics_mode(BOOLEAN on) {
+ #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
+ { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } };
+
+ struct _EFI_CONSOLE_CONTROL_PROTOCOL;
+
+ typedef enum {
+ EfiConsoleControlScreenText,
+ EfiConsoleControlScreenGraphics,
+ EfiConsoleControlScreenMaxValue,
+ } EFI_CONSOLE_CONTROL_SCREEN_MODE;
+
+ typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE)(
+ struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
+ BOOLEAN *UgaExists,
+ BOOLEAN *StdInLocked
+ );
+
+ typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE)(
+ struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
+ );
+
+ typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN)(
+ struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ CHAR16 *Password
+ );
+
+ typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
+ EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode;
+ EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
+ EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn;
+ } EFI_CONSOLE_CONTROL_PROTOCOL;
+
+ EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+ EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
+ EFI_CONSOLE_CONTROL_SCREEN_MODE new;
+ EFI_CONSOLE_CONTROL_SCREEN_MODE current;
+ BOOLEAN uga_exists;
+ BOOLEAN stdin_locked;
+ EFI_STATUS err;
+
+ err = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **)&ConsoleControl);
+ if (EFI_ERROR(err)) {
+ /* console control protocol is nonstandard and might not exist. */
+ return err == EFI_NOT_FOUND ? EFI_SUCCESS : err;
+ }
+
+ /* check current mode */
+ err = uefi_call_wrapper(ConsoleControl->GetMode, 4, ConsoleControl, &current, &uga_exists, &stdin_locked);
+ if (EFI_ERROR(err))
+ return err;
+
+ /* do not touch the mode */
+ new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
+ if (new == current)
+ return EFI_SUCCESS;
+
+ err = uefi_call_wrapper(ConsoleControl->SetMode, 2, ConsoleControl, new);
+
+ /* some firmware enables the cursor when switching modes */
+ uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
+
+ return err;
+}
diff --git a/src/boot/efi/graphics.h b/src/boot/efi/graphics.h
new file mode 100644
index 0000000000..3ee4972798
--- /dev/null
+++ b/src/boot/efi/graphics.h
@@ -0,0 +1,24 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ * Copyright (C) 2013 Intel Corporation
+ * Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
+ */
+
+#ifndef __SDBOOT_GRAPHICS_H
+#define __SDBOOT_GRAPHICS_H
+
+EFI_STATUS graphics_mode(BOOLEAN on);
+#endif
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
new file mode 100644
index 0000000000..809c69310e
--- /dev/null
+++ b/src/boot/efi/linux.c
@@ -0,0 +1,130 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "linux.h"
+
+#define SETUP_MAGIC 0x53726448 /* "HdrS" */
+struct SetupHeader {
+ UINT8 boot_sector[0x01f1];
+ UINT8 setup_secs;
+ UINT16 root_flags;
+ UINT32 sys_size;
+ UINT16 ram_size;
+ UINT16 video_mode;
+ UINT16 root_dev;
+ UINT16 signature;
+ UINT16 jump;
+ UINT32 header;
+ UINT16 version;
+ UINT16 su_switch;
+ UINT16 setup_seg;
+ UINT16 start_sys;
+ UINT16 kernel_ver;
+ UINT8 loader_id;
+ UINT8 load_flags;
+ UINT16 movesize;
+ UINT32 code32_start;
+ UINT32 ramdisk_start;
+ UINT32 ramdisk_len;
+ UINT32 bootsect_kludge;
+ UINT16 heap_end;
+ UINT8 ext_loader_ver;
+ UINT8 ext_loader_type;
+ UINT32 cmd_line_ptr;
+ UINT32 ramdisk_max;
+ UINT32 kernel_alignment;
+ UINT8 relocatable_kernel;
+ UINT8 min_alignment;
+ UINT16 xloadflags;
+ UINT32 cmdline_size;
+ UINT32 hardware_subarch;
+ UINT64 hardware_subarch_data;
+ UINT32 payload_offset;
+ UINT32 payload_length;
+ UINT64 setup_data;
+ UINT64 pref_address;
+ UINT32 init_size;
+ UINT32 handover_offset;
+} __attribute__((packed));
+
+#ifdef __x86_64__
+typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup);
+static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) {
+ handover_f handover;
+
+ asm volatile ("cli");
+ handover = (handover_f)((UINTN)setup->code32_start + 512 + setup->handover_offset);
+ handover(image, ST, setup);
+}
+#else
+typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup) __attribute__((regparm(0)));
+static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) {
+ handover_f handover;
+
+ handover = (handover_f)((UINTN)setup->code32_start + setup->handover_offset);
+ handover(image, ST, setup);
+}
+#endif
+
+EFI_STATUS linux_exec(EFI_HANDLE *image,
+ CHAR8 *cmdline, UINTN cmdline_len,
+ UINTN linux_addr,
+ UINTN initrd_addr, UINTN initrd_size) {
+ struct SetupHeader *image_setup;
+ struct SetupHeader *boot_setup;
+ EFI_PHYSICAL_ADDRESS addr;
+ EFI_STATUS err;
+
+ image_setup = (struct SetupHeader *)(linux_addr);
+ if (image_setup->signature != 0xAA55 || image_setup->header != SETUP_MAGIC)
+ return EFI_LOAD_ERROR;
+
+ if (image_setup->version < 0x20b || !image_setup->relocatable_kernel)
+ return EFI_LOAD_ERROR;
+
+ addr = 0x3fffffff;
+ err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(0x4000), &addr);
+ if (EFI_ERROR(err))
+ return err;
+ boot_setup = (struct SetupHeader *)(UINTN)addr;
+ ZeroMem(boot_setup, 0x4000);
+ CopyMem(boot_setup, image_setup, sizeof(struct SetupHeader));
+ boot_setup->loader_id = 0xff;
+
+ boot_setup->code32_start = (UINT32)linux_addr + (image_setup->setup_secs+1) * 512;
+
+ if (cmdline) {
+ addr = 0xA0000;
+ err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(cmdline_len + 1), &addr);
+ if (EFI_ERROR(err))
+ return err;
+ CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
+ ((CHAR8 *)addr)[cmdline_len] = 0;
+ boot_setup->cmd_line_ptr = (UINT32)addr;
+ }
+
+ boot_setup->ramdisk_start = (UINT32)initrd_addr;
+ boot_setup->ramdisk_len = (UINT32)initrd_size;
+
+ linux_efi_handover(image, boot_setup);
+ return EFI_LOAD_ERROR;
+}
diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h
new file mode 100644
index 0000000000..aff69a9778
--- /dev/null
+++ b/src/boot/efi/linux.h
@@ -0,0 +1,24 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
+ */
+
+#ifndef __SDBOOT_kernel_H
+#define __SDBOOT_kernel_H
+
+EFI_STATUS linux_exec(EFI_HANDLE *image,
+ CHAR8 *cmdline, UINTN cmdline_size,
+ UINTN linux_addr,
+ UINTN initrd_addr, UINTN initrd_size);
+#endif
diff --git a/src/boot/efi/pefile.c b/src/boot/efi/pefile.c
new file mode 100644
index 0000000000..e6fedbc929
--- /dev/null
+++ b/src/boot/efi/pefile.c
@@ -0,0 +1,172 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "pefile.h"
+
+struct DosFileHeader {
+ UINT8 Magic[2];
+ UINT16 LastSize;
+ UINT16 nBlocks;
+ UINT16 nReloc;
+ UINT16 HdrSize;
+ UINT16 MinAlloc;
+ UINT16 MaxAlloc;
+ UINT16 ss;
+ UINT16 sp;
+ UINT16 Checksum;
+ UINT16 ip;
+ UINT16 cs;
+ UINT16 RelocPos;
+ UINT16 nOverlay;
+ UINT16 reserved[4];
+ UINT16 OEMId;
+ UINT16 OEMInfo;
+ UINT16 reserved2[10];
+ UINT32 ExeHeader;
+} __attribute__((packed));
+
+#define PE_HEADER_MACHINE_I386 0x014c
+#define PE_HEADER_MACHINE_X64 0x8664
+struct PeFileHeader {
+ UINT16 Machine;
+ UINT16 NumberOfSections;
+ UINT32 TimeDateStamp;
+ UINT32 PointerToSymbolTable;
+ UINT32 NumberOfSymbols;
+ UINT16 SizeOfOptionalHeader;
+ UINT16 Characteristics;
+} __attribute__((packed));
+
+struct PeSectionHeader {
+ UINT8 Name[8];
+ UINT32 VirtualSize;
+ UINT32 VirtualAddress;
+ UINT32 SizeOfRawData;
+ UINT32 PointerToRawData;
+ UINT32 PointerToRelocations;
+ UINT32 PointerToLinenumbers;
+ UINT16 NumberOfRelocations;
+ UINT16 NumberOfLinenumbers;
+ UINT32 Characteristics;
+} __attribute__((packed));
+
+
+EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
+ EFI_FILE_HANDLE handle;
+ struct DosFileHeader dos;
+ uint8_t magic[4];
+ struct PeFileHeader pe;
+ UINTN len;
+ UINTN i;
+ EFI_STATUS err;
+
+ err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
+ if (EFI_ERROR(err))
+ return err;
+
+ /* MS-DOS stub */
+ len = sizeof(dos);
+ err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
+ if (EFI_ERROR(err))
+ goto out;
+ if (len != sizeof(dos)) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ if (CompareMem(dos.Magic, "MZ", 2) != 0) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
+ if (EFI_ERROR(err))
+ goto out;
+
+ /* PE header */
+ len = sizeof(magic);
+ err = uefi_call_wrapper(handle->Read, 3, handle, &len, &magic);
+ if (EFI_ERROR(err))
+ goto out;
+ if (len != sizeof(magic)) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ if (CompareMem(magic, "PE\0\0", 2) != 0) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ len = sizeof(pe);
+ err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
+ if (EFI_ERROR(err))
+ goto out;
+ if (len != sizeof(pe)) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ /* PE32+ Subsystem type */
+ if (pe.Machine != PE_HEADER_MACHINE_X64 &&
+ pe.Machine != PE_HEADER_MACHINE_I386) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ if (pe.NumberOfSections > 96) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+
+ /* the sections start directly after the headers */
+ err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader + sizeof(magic) + sizeof(pe) + pe.SizeOfOptionalHeader);
+ if (EFI_ERROR(err))
+ goto out;
+
+ for (i = 0; i < pe.NumberOfSections; i++) {
+ struct PeSectionHeader sect;
+ UINTN j;
+
+ len = sizeof(sect);
+ err = uefi_call_wrapper(handle->Read, 3, handle, &len, &sect);
+ if (EFI_ERROR(err))
+ goto out;
+ if (len != sizeof(sect)) {
+ err = EFI_LOAD_ERROR;
+ goto out;
+ }
+ for (j = 0; sections[j]; j++) {
+ if (CompareMem(sect.Name, sections[j], strlena(sections[j])) != 0)
+ continue;
+
+ if (addrs)
+ addrs[j] = (UINTN)sect.VirtualAddress;
+ if (offsets)
+ offsets[j] = (UINTN)sect.PointerToRawData;
+ if (sizes)
+ sizes[j] = (UINTN)sect.VirtualSize;
+ }
+ }
+
+out:
+ uefi_call_wrapper(handle->Close, 1, handle);
+ return err;
+}
diff --git a/src/boot/efi/pefile.h b/src/boot/efi/pefile.h
new file mode 100644
index 0000000000..ca2f9a2508
--- /dev/null
+++ b/src/boot/efi/pefile.h
@@ -0,0 +1,22 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
+ */
+
+#ifndef __SDBOOT_PEFILE_H
+#define __SDBOOT_PEFILE_H
+
+EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path,
+ CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes);
+#endif
diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c
new file mode 100644
index 0000000000..470ea3e2cc
--- /dev/null
+++ b/src/boot/efi/splash.c
@@ -0,0 +1,323 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "graphics.h"
+#include "splash.h"
+
+struct bmp_file {
+ CHAR8 signature[2];
+ UINT32 size;
+ UINT16 reserved[2];
+ UINT32 offset;
+} __attribute__((packed));
+
+/* we require at least BITMAPINFOHEADER, later versions are
+ accepted, but their features ignored */
+struct bmp_dib {
+ UINT32 size;
+ UINT32 x;
+ UINT32 y;
+ UINT16 planes;
+ UINT16 depth;
+ UINT32 compression;
+ UINT32 image_size;
+ INT32 x_pixel_meter;
+ INT32 y_pixel_meter;
+ UINT32 colors_used;
+ UINT32 colors_important;
+} __attribute__((packed));
+
+struct bmp_map {
+ UINT8 blue;
+ UINT8 green;
+ UINT8 red;
+ UINT8 reserved;
+} __attribute__((packed));
+
+EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
+ struct bmp_map **ret_map, UINT8 **pixmap) {
+ struct bmp_file *file;
+ struct bmp_dib *dib;
+ struct bmp_map *map;
+ UINTN row_size;
+
+ if (size < sizeof(struct bmp_file) + sizeof(struct bmp_dib))
+ return EFI_INVALID_PARAMETER;
+
+ /* check file header */
+ file = (struct bmp_file *)bmp;
+ if (file->signature[0] != 'B' || file->signature[1] != 'M')
+ return EFI_INVALID_PARAMETER;
+ if (file->size != size)
+ return EFI_INVALID_PARAMETER;
+ if (file->size < file->offset)
+ return EFI_INVALID_PARAMETER;
+
+ /* check device-independent bitmap */
+ dib = (struct bmp_dib *)(bmp + sizeof(struct bmp_file));
+ if (dib->size < sizeof(struct bmp_dib))
+ return EFI_UNSUPPORTED;
+
+ switch (dib->depth) {
+ case 1:
+ case 4:
+ case 8:
+ case 24:
+ if (dib->compression != 0)
+ return EFI_UNSUPPORTED;
+
+ break;
+
+ case 16:
+ case 32:
+ if (dib->compression != 0 && dib->compression != 3)
+ return EFI_UNSUPPORTED;
+
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ row_size = ((UINTN) dib->depth * dib->x + 31) / 32 * 4;
+ if (file->size - file->offset < dib->y * row_size)
+ return EFI_INVALID_PARAMETER;
+ if (row_size * dib->y > 64 * 1024 * 1024)
+ return EFI_INVALID_PARAMETER;
+
+ /* check color table */
+ map = (struct bmp_map *)(bmp + sizeof(struct bmp_file) + dib->size);
+ if (file->offset < sizeof(struct bmp_file) + dib->size)
+ return EFI_INVALID_PARAMETER;
+
+ if (file->offset > sizeof(struct bmp_file) + dib->size) {
+ UINT32 map_count;
+ UINTN map_size;
+
+ if (dib->colors_used)
+ map_count = dib->colors_used;
+ else {
+ switch (dib->depth) {
+ case 1:
+ case 4:
+ case 8:
+ map_count = 1 << dib->depth;
+ break;
+
+ default:
+ map_count = 0;
+ break;
+ }
+ }
+
+ map_size = file->offset - (sizeof(struct bmp_file) + dib->size);
+ if (map_size != sizeof(struct bmp_map) * map_count)
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *ret_map = map;
+ *ret_dib = dib;
+ *pixmap = bmp + file->offset;
+
+ return EFI_SUCCESS;
+}
+
+static VOID pixel_blend(UINT32 *dst, const UINT32 source) {
+ UINT32 alpha, src, src_rb, src_g, dst_rb, dst_g, rb, g;
+
+ alpha = (source & 0xff);
+
+ /* convert src from RGBA to XRGB */
+ src = source >> 8;
+
+ /* decompose into RB and G components */
+ src_rb = (src & 0xff00ff);
+ src_g = (src & 0x00ff00);
+
+ dst_rb = (*dst & 0xff00ff);
+ dst_g = (*dst & 0x00ff00);
+
+ /* blend */
+ rb = ((((src_rb - dst_rb) * alpha + 0x800080) >> 8) + dst_rb) & 0xff00ff;
+ g = ((((src_g - dst_g) * alpha + 0x008000) >> 8) + dst_g) & 0x00ff00;
+
+ *dst = (rb | g);
+}
+
+EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
+ struct bmp_dib *dib, struct bmp_map *map,
+ UINT8 *pixmap) {
+ UINT8 *in;
+ UINTN y;
+
+ /* transform and copy pixels */
+ in = pixmap;
+ for (y = 0; y < dib->y; y++) {
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out;
+ UINTN row_size;
+ UINTN x;
+
+ out = &buf[(dib->y - y - 1) * dib->x];
+ for (x = 0; x < dib->x; x++, in++, out++) {
+ switch (dib->depth) {
+ case 1: {
+ UINTN i;
+
+ for (i = 0; i < 8 && x < dib->x; i++) {
+ out->Red = map[((*in) >> (7 - i)) & 1].red;
+ out->Green = map[((*in) >> (7 - i)) & 1].green;
+ out->Blue = map[((*in) >> (7 - i)) & 1].blue;
+ out++;
+ x++;
+ }
+ out--;
+ x--;
+ break;
+ }
+
+ case 4: {
+ UINTN i;
+
+ i = (*in) >> 4;
+ out->Red = map[i].red;
+ out->Green = map[i].green;
+ out->Blue = map[i].blue;
+ if (x < (dib->x - 1)) {
+ out++;
+ x++;
+ i = (*in) & 0x0f;
+ out->Red = map[i].red;
+ out->Green = map[i].green;
+ out->Blue = map[i].blue;
+ }
+ break;
+ }
+
+ case 8:
+ out->Red = map[*in].red;
+ out->Green = map[*in].green;
+ out->Blue = map[*in].blue;
+ break;
+
+ case 16: {
+ UINT16 i = *(UINT16 *) in;
+
+ out->Red = (i & 0x7c00) >> 7;
+ out->Green = (i & 0x3e0) >> 2;
+ out->Blue = (i & 0x1f) << 3;
+ in += 1;
+ break;
+ }
+
+ case 24:
+ out->Red = in[2];
+ out->Green = in[1];
+ out->Blue = in[0];
+ in += 2;
+ break;
+
+ case 32: {
+ UINT32 i = *(UINT32 *) in;
+
+ pixel_blend((UINT32 *)out, i);
+
+ in += 3;
+ break;
+ }
+ }
+ }
+
+ /* add row padding; new lines always start at 32 bit boundary */
+ row_size = in - pixmap;
+ in += ((row_size + 3) & ~3) - row_size;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel = {};
+ EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
+ struct bmp_dib *dib;
+ struct bmp_map *map;
+ UINT8 *pixmap;
+ UINT64 blt_size;
+ VOID *blt = NULL;
+ UINTN x_pos = 0;
+ UINTN y_pos = 0;
+ EFI_STATUS err;
+
+ if (!background) {
+ if (StriCmp(L"Apple", ST->FirmwareVendor) == 0) {
+ pixel.Red = 0xc0;
+ pixel.Green = 0xc0;
+ pixel.Blue = 0xc0;
+ }
+ background = &pixel;
+ }
+
+ err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR(err))
+ return err;
+
+ err = bmp_parse_header(content, len, &dib, &map, &pixmap);
+ if (EFI_ERROR(err))
+ goto err;
+
+ if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution)
+ x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2;
+ if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution)
+ y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2;
+
+ uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)background,
+ EfiBltVideoFill, 0, 0, 0, 0,
+ GraphicsOutput->Mode->Info->HorizontalResolution,
+ GraphicsOutput->Mode->Info->VerticalResolution, 0);
+
+ /* EFI buffer */
+ blt_size = dib->x * dib->y * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ blt = AllocatePool(blt_size);
+ if (!blt)
+ return EFI_OUT_OF_RESOURCES;
+
+ err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
+ blt, EfiBltVideoToBltBuffer, x_pos, y_pos, 0, 0,
+ dib->x, dib->y, 0);
+ if (EFI_ERROR(err))
+ goto err;
+
+ err = bmp_to_blt(blt, dib, map, pixmap);
+ if (EFI_ERROR(err))
+ goto err;
+
+ err = graphics_mode(TRUE);
+ if (EFI_ERROR(err))
+ goto err;
+
+ err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
+ blt, EfiBltBufferToVideo, 0, 0, x_pos, y_pos,
+ dib->x, dib->y, 0);
+err:
+ FreePool(blt);
+ return err;
+}
diff --git a/src/boot/efi/splash.h b/src/boot/efi/splash.h
new file mode 100644
index 0000000000..0183e79b16
--- /dev/null
+++ b/src/boot/efi/splash.h
@@ -0,0 +1,22 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ */
+
+#ifndef __SDBOOT_SPLASH_H
+#define __SDBOOT_SPLASH_H
+
+EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);
+#endif
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
new file mode 100644
index 0000000000..0b1bc491ed
--- /dev/null
+++ b/src/boot/efi/stub.c
@@ -0,0 +1,113 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "pefile.h"
+#include "graphics.h"
+#include "splash.h"
+#include "linux.h"
+
+/* magic string to find in the binary image */
+static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " VERSION " ####";
+
+static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
+ EFI_LOADED_IMAGE *loaded_image;
+ EFI_FILE *root_dir;
+ CHAR16 *loaded_image_path;
+ CHAR8 *b;
+ UINTN size;
+ BOOLEAN secure = FALSE;
+ CHAR8 *sections[] = {
+ (UINT8 *)".cmdline",
+ (UINT8 *)".linux",
+ (UINT8 *)".initrd",
+ (UINT8 *)".splash",
+ NULL
+ };
+ UINTN addrs[ELEMENTSOF(sections)-1] = {};
+ UINTN offs[ELEMENTSOF(sections)-1] = {};
+ UINTN szs[ELEMENTSOF(sections)-1] = {};
+ CHAR8 *cmdline = NULL;
+ UINTN cmdline_len;
+ EFI_STATUS err;
+
+ InitializeLib(image, sys_table);
+
+ err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
+ image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(err)) {
+ Print(L"Error getting a LoadedImageProtocol handle: %r ", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+ }
+
+ root_dir = LibOpenRoot(loaded_image->DeviceHandle);
+ if (!root_dir) {
+ Print(L"Unable to open root directory: %r ", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return EFI_LOAD_ERROR;
+ }
+
+ loaded_image_path = DevicePathToStr(loaded_image->FilePath);
+
+ if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) {
+ if (*b > 0)
+ secure = TRUE;
+ FreePool(b);
+ }
+
+ err = pefile_locate_sections(root_dir, loaded_image_path, sections, addrs, offs, szs);
+ if (EFI_ERROR(err)) {
+ Print(L"Unable to locate embedded .linux section: %r ", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+ }
+
+ if (szs[0] > 0)
+ cmdline = (CHAR8 *)(loaded_image->ImageBase + addrs[0]);
+
+ cmdline_len = szs[0];
+
+ /* if we are not in secure boot mode, accept a custom command line and replace the built-in one */
+ if (!secure && loaded_image->LoadOptionsSize > 0) {
+ CHAR16 *options;
+ CHAR8 *line;
+ UINTN i;
+
+ options = (CHAR16 *)loaded_image->LoadOptions;
+ cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8);
+ line = AllocatePool(cmdline_len);
+ for (i = 0; i < cmdline_len; i++)
+ line[i] = options[i];
+ cmdline = line;
+ }
+
+ if (szs[3] > 0)
+ graphics_splash((UINT8 *)((UINTN)loaded_image->ImageBase + addrs[3]), szs[3], NULL);
+
+ err = linux_exec(image, cmdline, cmdline_len,
+ (UINTN)loaded_image->ImageBase + addrs[1],
+ (UINTN)loaded_image->ImageBase + addrs[2], szs[2]);
+
+ graphics_mode(FALSE);
+ Print(L"Execution of embedded linux image failed: %r\n", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+}
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
new file mode 100644
index 0000000000..5e374edacf
--- /dev/null
+++ b/src/boot/efi/util.c
@@ -0,0 +1,347 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ */
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "util.h"
+
+/*
+ * Allocated random UUID, intended to be shared across tools that implement
+ * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
+ * associated EFI variables.
+ */
+static const EFI_GUID loader_guid = { 0x4a67b082, 0x0a4c, 0x41cf, {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f} };
+
+#ifdef __x86_64__
+UINT64 ticks_read(VOID) {
+ UINT64 a, d;
+ __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
+ return (d << 32) | a;
+}
+#elif defined(__i386__)
+UINT64 ticks_read(VOID) {
+ UINT64 val;
+ __asm__ volatile ("rdtsc" : "=A" (val));
+ return val;
+}
+#else
+UINT64 ticks_read(VOID) {
+ UINT64 val = 1;
+ return val;
+}
+#endif
+
+/* count TSC ticks during a millisecond delay */
+UINT64 ticks_freq(VOID) {
+ UINT64 ticks_start, ticks_end;
+
+ ticks_start = ticks_read();
+ uefi_call_wrapper(BS->Stall, 1, 1000);
+ ticks_end = ticks_read();
+
+ return (ticks_end - ticks_start) * 1000;
+}
+
+UINT64 time_usec(VOID) {
+ UINT64 ticks;
+ static UINT64 freq;
+
+ ticks = ticks_read();
+ if (ticks == 0)
+ return 0;
+
+ if (freq == 0) {
+ freq = ticks_freq();
+ if (freq == 0)
+ return 0;
+ }
+
+ return 1000 * 1000 * ticks / freq;
+}
+
+EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) {
+ if (strcmpa(v, (CHAR8 *)"1") == 0 ||
+ strcmpa(v, (CHAR8 *)"yes") == 0 ||
+ strcmpa(v, (CHAR8 *)"y") == 0 ||
+ strcmpa(v, (CHAR8 *)"true") == 0) {
+ *b = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ if (strcmpa(v, (CHAR8 *)"0") == 0 ||
+ strcmpa(v, (CHAR8 *)"no") == 0 ||
+ strcmpa(v, (CHAR8 *)"n") == 0 ||
+ strcmpa(v, (CHAR8 *)"false") == 0) {
+ *b = FALSE;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) {
+ UINT32 flags;
+
+ flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ if (persistent)
+ flags |= EFI_VARIABLE_NON_VOLATILE;
+
+ return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf);
+}
+
+EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) {
+ return efivar_set_raw(&loader_guid, name, (CHAR8 *)value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent);
+}
+
+EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) {
+ CHAR16 str[32];
+
+ SPrint(str, 32, L"%d", i);
+ return efivar_set(name, str, persistent);
+}
+
+EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) {
+ CHAR8 *buf;
+ CHAR16 *val;
+ UINTN size;
+ EFI_STATUS err;
+
+ err = efivar_get_raw(&loader_guid, name, &buf, &size);
+ if (EFI_ERROR(err))
+ return err;
+
+ val = StrDuplicate((CHAR16 *)buf);
+ if (!val) {
+ FreePool(buf);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *value = val;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
+ CHAR16 *val;
+ EFI_STATUS err;
+
+ err = efivar_get(name, &val);
+ if (!EFI_ERROR(err)) {
+ *i = Atoi(val);
+ FreePool(val);
+ }
+ return err;
+}
+
+EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
+ CHAR8 *buf;
+ UINTN l;
+ EFI_STATUS err;
+
+ l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
+ buf = AllocatePool(l);
+ if (!buf)
+ return EFI_OUT_OF_RESOURCES;
+
+ err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf);
+ if (!EFI_ERROR(err)) {
+ *buffer = buf;
+ if (size)
+ *size = l;
+ } else
+ FreePool(buf);
+ return err;
+
+}
+
+VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) {
+ CHAR16 str[32];
+
+ if (usec == 0)
+ usec = time_usec();
+ if (usec == 0)
+ return;
+
+ SPrint(str, 32, L"%ld", usec);
+ efivar_set(name, str, FALSE);
+}
+
+static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) {
+ CHAR16 unichar;
+ UINTN len;
+ UINTN i;
+
+ if (stra[0] < 0x80)
+ len = 1;
+ else if ((stra[0] & 0xe0) == 0xc0)
+ len = 2;
+ else if ((stra[0] & 0xf0) == 0xe0)
+ len = 3;
+ else if ((stra[0] & 0xf8) == 0xf0)
+ len = 4;
+ else if ((stra[0] & 0xfc) == 0xf8)
+ len = 5;
+ else if ((stra[0] & 0xfe) == 0xfc)
+ len = 6;
+ else
+ return -1;
+
+ switch (len) {
+ case 1:
+ unichar = stra[0];
+ break;
+ case 2:
+ unichar = stra[0] & 0x1f;
+ break;
+ case 3:
+ unichar = stra[0] & 0x0f;
+ break;
+ case 4:
+ unichar = stra[0] & 0x07;
+ break;
+ case 5:
+ unichar = stra[0] & 0x03;
+ break;
+ case 6:
+ unichar = stra[0] & 0x01;
+ break;
+ }
+
+ for (i = 1; i < len; i++) {
+ if ((stra[i] & 0xc0) != 0x80)
+ return -1;
+ unichar <<= 6;
+ unichar |= stra[i] & 0x3f;
+ }
+
+ *c = unichar;
+ return len;
+}
+
+CHAR16 *stra_to_str(CHAR8 *stra) {
+ UINTN strlen;
+ UINTN len;
+ UINTN i;
+ CHAR16 *str;
+
+ len = strlena(stra);
+ str = AllocatePool((len + 1) * sizeof(CHAR16));
+
+ strlen = 0;
+ i = 0;
+ while (i < len) {
+ INTN utf8len;
+
+ utf8len = utf8_to_16(stra + i, str + strlen);
+ if (utf8len <= 0) {
+ /* invalid utf8 sequence, skip the garbage */
+ i++;
+ continue;
+ }
+
+ strlen++;
+ i += utf8len;
+ }
+ str[strlen] = '\0';
+ return str;
+}
+
+CHAR16 *stra_to_path(CHAR8 *stra) {
+ CHAR16 *str;
+ UINTN strlen;
+ UINTN len;
+ UINTN i;
+
+ len = strlena(stra);
+ str = AllocatePool((len + 2) * sizeof(CHAR16));
+
+ str[0] = '\\';
+ strlen = 1;
+ i = 0;
+ while (i < len) {
+ INTN utf8len;
+
+ utf8len = utf8_to_16(stra + i, str + strlen);
+ if (utf8len <= 0) {
+ /* invalid utf8 sequence, skip the garbage */
+ i++;
+ continue;
+ }
+
+ if (str[strlen] == '/')
+ str[strlen] = '\\';
+ if (str[strlen] == '\\' && str[strlen-1] == '\\') {
+ /* skip double slashes */
+ i += utf8len;
+ continue;
+ }
+
+ strlen++;
+ i += utf8len;
+ }
+ str[strlen] = '\0';
+ return str;
+}
+
+CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
+ do {
+ if (*s == c)
+ return s;
+ } while (*s++);
+ return NULL;
+}
+
+INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content) {
+ EFI_FILE_HANDLE handle;
+ CHAR8 *buf;
+ UINTN buflen;
+ EFI_STATUS err;
+ UINTN len;
+
+ err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL);
+ if (EFI_ERROR(err))
+ return err;
+
+ if (size == 0) {
+ EFI_FILE_INFO *info;
+
+ info = LibFileInfo(handle);
+ buflen = info->FileSize+1;
+ FreePool(info);
+ } else
+ buflen = size;
+
+ if (off > 0) {
+ err = uefi_call_wrapper(handle->SetPosition, 2, handle, off);
+ if (EFI_ERROR(err))
+ return err;
+ }
+
+ buf = AllocatePool(buflen);
+ err = uefi_call_wrapper(handle->Read, 3, handle, &buflen, buf);
+ if (!EFI_ERROR(err)) {
+ buf[buflen] = '\0';
+ *content = buf;
+ len = buflen;
+ } else {
+ len = err;
+ FreePool(buf);
+ }
+
+ uefi_call_wrapper(handle->Close, 1, handle);
+ return len;
+}
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
new file mode 100644
index 0000000000..4727a34d1f
--- /dev/null
+++ b/src/boot/efi/util.h
@@ -0,0 +1,50 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
+ */
+
+#ifndef __SDBOOT_UTIL_H
+#define __SDBOOT_UTIL_H
+
+#include <efi.h>
+#include <efilib.h>
+
+#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
+
+static inline const CHAR16 *yes_no(BOOLEAN b) {
+ return b ? L"yes" : L"no";
+}
+
+EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b);
+
+UINT64 ticks_read(void);
+UINT64 ticks_freq(void);
+UINT64 time_usec(void);
+
+EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent);
+EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent);
+EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent);
+VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec);
+
+EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value);
+EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size);
+EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i);
+
+CHAR8 *strchra(CHAR8 *s, CHAR8 c);
+CHAR16 *stra_to_path(CHAR8 *stra);
+CHAR16 *stra_to_str(CHAR8 *stra);
+
+INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content);
+#endif
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 64a384bacf..45fab92598 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -33,10 +33,7 @@
***/
-#include <sys/time.h>
-#include <sys/types.h>
#include <sys/resource.h>
-#include <sys/stat.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
@@ -61,47 +58,33 @@
#include "bootchart.h"
#include "list.h"
-double graph_start;
-double log_start;
-struct ps_struct *ps_first;
-int pscount;
-int cpus;
-double interval;
-FILE *of = NULL;
-int overrun = 0;
static int exiting = 0;
-int sysfd=-1;
#define DEFAULT_SAMPLES_LEN 500
#define DEFAULT_HZ 25.0
#define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */
#define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */
-#define DEFAULT_INIT ROOTLIBDIR "/systemd/systemd"
+#define DEFAULT_INIT ROOTLIBEXECDIR "/systemd"
#define DEFAULT_OUTPUT "/run/log"
/* graph defaults */
bool arg_entropy = false;
-bool initcall = true;
+bool arg_initcall = true;
bool arg_relative = false;
bool arg_filter = true;
bool arg_show_cmdline = false;
bool arg_show_cgroup = false;
bool arg_pss = false;
bool arg_percpu = false;
-int samples;
int arg_samples_len = DEFAULT_SAMPLES_LEN; /* we record len+1 (1 start sample) */
double arg_hz = DEFAULT_HZ;
double arg_scale_x = DEFAULT_SCALE_X;
double arg_scale_y = DEFAULT_SCALE_Y;
-static struct list_sample_data *sampledata;
-struct list_sample_data *head;
char arg_init_path[PATH_MAX] = DEFAULT_INIT;
char arg_output_path[PATH_MAX] = DEFAULT_OUTPUT;
static void signal_handler(int sig) {
- if (sig++)
- sig--;
exiting = 1;
}
@@ -138,31 +121,30 @@ static void parse_conf(void) {
}
static void help(void) {
- fprintf(stdout,
- "Usage: %s [OPTIONS]\n\n"
- "Options:\n"
- " -r, --rel Record time relative to recording\n"
- " -f, --freq=FREQ Sample frequency [%g]\n"
- " -n, --samples=N Stop sampling at [%d] samples\n"
- " -x, --scale-x=N Scale the graph horizontally [%g] \n"
- " -y, --scale-y=N Scale the graph vertically [%g] \n"
- " -p, --pss Enable PSS graph (CPU intensive)\n"
- " -e, --entropy Enable the entropy_avail graph\n"
- " -o, --output=PATH Path to output files [%s]\n"
- " -i, --init=PATH Path to init executable [%s]\n"
- " -F, --no-filter Disable filtering of unimportant or ephemeral processes\n"
- " -C, --cmdline Display full command lines with arguments\n"
- " -c, --control-group Display process control group\n"
- " --per-cpu Draw each CPU utilization and wait bar also\n"
- " -h, --help Display this message\n\n"
- "See bootchart.conf for more information.\n",
- program_invocation_short_name,
- DEFAULT_HZ,
- DEFAULT_SAMPLES_LEN,
- DEFAULT_SCALE_X,
- DEFAULT_SCALE_Y,
- DEFAULT_OUTPUT,
- DEFAULT_INIT);
+ printf("Usage: %s [OPTIONS]\n\n"
+ "Options:\n"
+ " -r --rel Record time relative to recording\n"
+ " -f --freq=FREQ Sample frequency [%g]\n"
+ " -n --samples=N Stop sampling at [%d] samples\n"
+ " -x --scale-x=N Scale the graph horizontally [%g] \n"
+ " -y --scale-y=N Scale the graph vertically [%g] \n"
+ " -p --pss Enable PSS graph (CPU intensive)\n"
+ " -e --entropy Enable the entropy_avail graph\n"
+ " -o --output=PATH Path to output files [%s]\n"
+ " -i --init=PATH Path to init executable [%s]\n"
+ " -F --no-filter Disable filtering of unimportant or ephemeral processes\n"
+ " -C --cmdline Display full command lines with arguments\n"
+ " -c --control-group Display process control group\n"
+ " --per-cpu Draw each CPU utilization and wait bar also\n"
+ " -h --help Display this message\n\n"
+ "See bootchart.conf for more information.\n",
+ program_invocation_short_name,
+ DEFAULT_HZ,
+ DEFAULT_SAMPLES_LEN,
+ DEFAULT_SCALE_X,
+ DEFAULT_SCALE_Y,
+ DEFAULT_OUTPUT,
+ DEFAULT_INIT);
}
static int parse_argv(int argc, char *argv[]) {
@@ -269,43 +251,41 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
-static void do_journal_append(char *file) {
+static int do_journal_append(char *file) {
+ _cleanup_free_ char *bootchart_message = NULL;
+ _cleanup_free_ char *bootchart_file = NULL;
+ _cleanup_free_ char *p = NULL;
+ _cleanup_close_ int fd = -1;
struct iovec iovec[5];
- int r, f, j = 0;
+ int r, j = 0;
ssize_t n;
- _cleanup_free_ char *bootchart_file = NULL, *bootchart_message = NULL,
- *p = NULL;
bootchart_file = strappend("BOOTCHART_FILE=", file);
- if (bootchart_file)
- IOVEC_SET_STRING(iovec[j++], bootchart_file);
+ if (!bootchart_file)
+ return log_oom();
+ IOVEC_SET_STRING(iovec[j++], bootchart_file);
IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518");
IOVEC_SET_STRING(iovec[j++], "PRIORITY=7");
bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL);
- if (bootchart_message)
- IOVEC_SET_STRING(iovec[j++], bootchart_message);
+ if (!bootchart_message)
+ return log_oom();
- p = malloc(9 + BOOTCHART_MAX);
- if (!p) {
- log_oom();
- return;
- }
+ IOVEC_SET_STRING(iovec[j++], bootchart_message);
+
+ p = malloc(10 + BOOTCHART_MAX);
+ if (!p)
+ return log_oom();
memcpy(p, "BOOTCHART=", 10);
- f = open(file, O_RDONLY|O_CLOEXEC);
- if (f < 0) {
- log_error_errno(errno, "Failed to read bootchart data: %m");
- return;
- }
- n = loop_read(f, p + 10, BOOTCHART_MAX, false);
- if (n < 0) {
- log_error_errno(n, "Failed to read bootchart data: %m");
- close(f);
- return;
- }
- close(f);
+ fd = open(file, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file);
+
+ n = loop_read(fd, p + 10, BOOTCHART_MAX, false);
+ if (n < 0)
+ return log_error_errno(n, "Failed to read bootchart data: %m");
iovec[j].iov_base = p;
iovec[j].iov_len = 10 + n;
@@ -314,26 +294,42 @@ static void do_journal_append(char *file) {
r = sd_journal_sendv(iovec, j);
if (r < 0)
log_error_errno(r, "Failed to send bootchart: %m");
+
+ return 0;
}
int main(int argc, char *argv[]) {
+ static struct list_sample_data *sampledata;
+ _cleanup_closedir_ DIR *proc = NULL;
_cleanup_free_ char *build = NULL;
- struct sigaction sig = {
- .sa_handler = signal_handler,
- };
- struct ps_struct *ps;
+ _cleanup_fclose_ FILE *of = NULL;
+ _cleanup_close_ int sysfd = -1;
+ struct ps_struct *ps_first;
+ double graph_start;
+ double log_start;
+ double interval;
char output_file[PATH_MAX];
char datestr[200];
+ int pscount = 0;
+ int n_cpus = 0;
+ int overrun = 0;
time_t t = 0;
- int r;
+ int r, samples;
+ struct ps_struct *ps;
struct rlimit rlim;
- bool has_procfs = false;
+ struct list_sample_data *head;
+ struct sigaction sig = {
+ .sa_handler = signal_handler,
+ };
parse_conf();
r = parse_argv(argc, argv);
- if (r <= 0)
- return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ if (r < 0)
+ return EXIT_FAILURE;
+
+ if (r == 0)
+ return EXIT_SUCCESS;
/*
* If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then
@@ -365,17 +361,25 @@ int main(int argc, char *argv[]) {
interval = (1.0 / arg_hz) * 1000000000.0;
- log_uptime();
+ if (arg_relative)
+ graph_start = log_start = gettime_ns();
+ else {
+ struct timespec n;
+ double uptime;
- if (graph_start < 0.0) {
- fprintf(stderr,
- "Failed to setup graph start time.\n\nThe system uptime "
- "probably includes time that the system was suspended. "
- "Use --rel to bypass this issue.\n");
- exit (EXIT_FAILURE);
+ clock_gettime(CLOCK_BOOTTIME, &n);
+ uptime = (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC));
+
+ log_start = gettime_ns();
+ graph_start = log_start - uptime;
}
- has_procfs = access("/proc/vmstat", F_OK) == 0;
+ if (graph_start < 0.0) {
+ log_error("Failed to setup graph start time.\n\n"
+ "The system uptime probably includes time that the system was suspended. "
+ "Use --rel to bypass this issue.");
+ return EXIT_FAILURE;
+ }
LIST_HEAD_INIT(head);
@@ -398,15 +402,6 @@ int main(int argc, char *argv[]) {
sampledata->sampletime = gettime_ns();
sampledata->counter = samples;
- if (!of && (access(arg_output_path, R_OK|W_OK|X_OK) == 0)) {
- t = time(NULL);
- r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t));
- assert_se(r > 0);
-
- snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr);
- of = fopen(output_file, "we");
- }
-
if (sysfd < 0)
sysfd = open("/sys", O_RDONLY|O_CLOEXEC);
@@ -415,11 +410,17 @@ int main(int argc, char *argv[]) {
parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL);
}
- if (has_procfs)
- log_sample(samples, &sampledata);
+ if (proc)
+ rewinddir(proc);
else
- /* wait for /proc to become available, discarding samples */
- has_procfs = access("/proc/vmstat", F_OK) == 0;
+ proc = opendir("/proc");
+
+ /* wait for /proc to become available, discarding samples */
+ if (proc) {
+ r = log_sample(proc, samples, ps_first, &sampledata, &pscount, &n_cpus);
+ if (r < 0)
+ return EXIT_FAILURE;
+ }
sample_stop = gettime_ns();
@@ -446,7 +447,7 @@ int main(int argc, char *argv[]) {
break;
}
log_error_errno(errno, "nanosleep() failed: %m");
- exit(EXIT_FAILURE);
+ return EXIT_FAILURE;
}
} else {
overrun++;
@@ -460,12 +461,12 @@ int main(int argc, char *argv[]) {
ps = ps_first;
while (ps->next_ps) {
ps = ps->next_ps;
- if (ps->schedstat)
- close(ps->schedstat);
- if (ps->sched)
- close(ps->sched);
- if (ps->smaps)
+ ps->schedstat = safe_close(ps->schedstat);
+ ps->sched = safe_close(ps->sched);
+ if (ps->smaps) {
fclose(ps->smaps);
+ ps->smaps = NULL;
+ }
}
if (!of) {
@@ -478,22 +479,24 @@ int main(int argc, char *argv[]) {
}
if (!of) {
- fprintf(stderr, "opening output file '%s': %m\n", output_file);
- exit (EXIT_FAILURE);
+ log_error("Error opening output file '%s': %m\n", output_file);
+ return EXIT_FAILURE;
}
- svg_do(strna(build));
-
- fprintf(stderr, "systemd-bootchart wrote %s\n", output_file);
+ r = svg_do(of, strna(build), head, ps_first,
+ samples, pscount, n_cpus, graph_start,
+ log_start, interval, overrun);
- do_journal_append(output_file);
+ if (r < 0) {
+ log_error_errno(r, "Error generating svg file: %m");
+ return EXIT_FAILURE;
+ }
- if (of)
- fclose(of);
+ log_info("systemd-bootchart wrote %s\n", output_file);
- closedir(proc);
- if (sysfd >= 0)
- close(sysfd);
+ r = do_journal_append(output_file);
+ if (r < 0)
+ return EXIT_FAILURE;
/* nitpic cleanups */
ps = ps_first->next_ps;
@@ -513,6 +516,7 @@ int main(int argc, char *argv[]) {
free(old->sample);
free(old);
}
+
free(ps->cgroup);
free(ps->sample);
free(ps);
@@ -524,9 +528,10 @@ int main(int argc, char *argv[]) {
free(old_sampledata);
}
free(sampledata);
+
/* don't complain when overrun once, happens most commonly on 1st sample */
if (overrun > 1)
- fprintf(stderr, "systemd-boochart: Warning: sample time overrun %i times\n", overrun);
+ log_warning("systemd-boochart: sample time overrun %i times\n", overrun);
return 0;
}
diff --git a/src/bootchart/bootchart.conf b/src/bootchart/bootchart.conf
index 2d7cb61217..4f5e50936e 100644
--- a/src/bootchart/bootchart.conf
+++ b/src/bootchart/bootchart.conf
@@ -5,10 +5,11 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/bootchart.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
-# See bootchart.conf(5) for details
+# See bootchart.conf(5) for details.
[Bootchart]
#Samples=500
diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h
index 26de0dd9f8..bdb4b00199 100644
--- a/src/bootchart/bootchart.h
+++ b/src/bootchart/bootchart.h
@@ -24,7 +24,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <stdbool.h>
#include "list.h"
@@ -104,14 +103,6 @@ struct ps_struct {
struct ps_sched_struct *sample;
};
-extern int entropy_avail[];
-
-extern double graph_start;
-extern double log_start;
-extern double sampletime[];
-extern struct ps_struct *ps_first;
-extern struct block_stat_struct blockstat[];
-extern int pscount;
extern bool arg_relative;
extern bool arg_filter;
extern bool arg_show_cmdline;
@@ -119,18 +110,11 @@ extern bool arg_show_cgroup;
extern bool arg_pss;
extern bool arg_entropy;
extern bool arg_percpu;
-extern bool initcall;
-extern int samples;
-extern int cpus;
-extern int arg_samples_len;
+extern bool arg_initcall;
+extern int arg_samples_len;
extern double arg_hz;
extern double arg_scale_x;
extern double arg_scale_y;
-extern int overrun;
-extern double interval;
extern char arg_output_path[PATH_MAX];
extern char arg_init_path[PATH_MAX];
-
-extern FILE *of;
-extern int sysfd;
diff --git a/src/bootchart/store.c b/src/bootchart/store.c
index a66387c304..f159cbafe2 100644
--- a/src/bootchart/store.c
+++ b/src/bootchart/store.c
@@ -25,8 +25,6 @@
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
@@ -47,8 +45,6 @@
*/
static char smaps_buf[4096];
static int skip = 0;
-DIR *proc;
-int procfd = -1;
double gettime_ns(void) {
struct timespec n;
@@ -58,24 +54,6 @@ double gettime_ns(void) {
return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC));
}
-static double gettime_up(void) {
- struct timespec n;
-
- clock_gettime(CLOCK_BOOTTIME, &n);
- return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC));
-}
-
-void log_uptime(void) {
- if (arg_relative)
- graph_start = log_start = gettime_ns();
- else {
- double uptime = gettime_up();
-
- log_start = gettime_ns();
- graph_start = log_start - uptime;
- }
-}
-
static char *bufgetline(char *buf) {
char *c;
@@ -85,16 +63,17 @@ static char *bufgetline(char *buf) {
c = strchr(buf, '\n');
if (c)
c++;
+
return c;
}
-static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) {
+static int pid_cmdline_strscpy(int procfd, char *buffer, size_t buf_len, int pid) {
char filename[PATH_MAX];
- _cleanup_close_ int fd=-1;
+ _cleanup_close_ int fd = -1;
ssize_t n;
sprintf(filename, "%d/cmdline", pid);
- fd = openat(procfd, filename, O_RDONLY);
+ fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return -errno;
@@ -106,12 +85,19 @@ static int pid_cmdline_strscpy(char *buffer, size_t buf_len, int pid) {
buffer[i] = ' ';
buffer[n] = '\0';
}
+
return 0;
}
-void log_sample(int sample, struct list_sample_data **ptr) {
- static int vmstat;
- static int schedstat;
+int log_sample(DIR *proc,
+ int sample,
+ struct ps_struct *ps_first,
+ struct list_sample_data **ptr,
+ int *pscount,
+ int *cpus) {
+
+ static int vmstat = -1;
+ static int schedstat = -1;
char buf[4096];
char key[256];
char val[256];
@@ -121,41 +107,36 @@ void log_sample(int sample, struct list_sample_data **ptr) {
int c;
int p;
int mod;
- static int e_fd;
+ static int e_fd = -1;
ssize_t s;
ssize_t n;
struct dirent *ent;
int fd;
struct list_sample_data *sampledata;
struct ps_sched_struct *ps_prev = NULL;
+ int procfd;
sampledata = *ptr;
- /* all the per-process stuff goes here */
- if (!proc) {
- /* find all processes */
- proc = opendir("/proc");
- if (!proc)
- return;
- procfd = dirfd(proc);
- } else {
- rewinddir(proc);
- }
+ procfd = dirfd(proc);
+ if (procfd < 0)
+ return -errno;
- if (!vmstat) {
+ if (vmstat < 0) {
/* block stuff */
- vmstat = openat(procfd, "vmstat", O_RDONLY);
- if (vmstat == -1) {
- log_error_errno(errno, "Failed to open /proc/vmstat: %m");
- exit(EXIT_FAILURE);
- }
+ vmstat = openat(procfd, "vmstat", O_RDONLY|O_CLOEXEC);
+ if (vmstat < 0)
+ return log_error_errno(errno, "Failed to open /proc/vmstat: %m");
}
n = pread(vmstat, buf, sizeof(buf) - 1, 0);
if (n <= 0) {
- close(vmstat);
- return;
+ vmstat = safe_close(vmstat);
+ if (n < 0)
+ return -errno;
+ return -ENODATA;
}
+
buf[n] = '\0';
m = buf;
@@ -174,20 +155,21 @@ vmstat_next:
break;
}
- if (!schedstat) {
+ if (schedstat < 0) {
/* overall CPU utilization */
- schedstat = openat(procfd, "schedstat", O_RDONLY);
- if (schedstat == -1) {
- log_error_errno(errno, "Failed to open /proc/schedstat: %m");
- exit(EXIT_FAILURE);
- }
+ schedstat = openat(procfd, "schedstat", O_RDONLY|O_CLOEXEC);
+ if (schedstat < 0)
+ return log_error_errno(errno, "Failed to open /proc/schedstat (requires CONFIG_SCHEDSTATS=y in kernel config): %m");
}
n = pread(schedstat, buf, sizeof(buf) - 1, 0);
if (n <= 0) {
- close(schedstat);
- return;
+ schedstat = safe_close(schedstat);
+ if (n < 0)
+ return -errno;
+ return -ENODATA;
}
+
buf[n] = '\0';
m = buf;
@@ -205,8 +187,8 @@ vmstat_next:
sampledata->runtime[c] = atoll(rt);
sampledata->waittime[c] = atoll(wt);
- if (c == cpus)
- cpus = c + 1;
+ if (c == *cpus)
+ *cpus = c + 1;
}
schedstat_next:
m = bufgetline(m);
@@ -215,16 +197,18 @@ schedstat_next:
}
if (arg_entropy) {
- if (!e_fd) {
- e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY);
+ if (e_fd < 0) {
+ e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY|O_CLOEXEC);
+ if (e_fd < 0)
+ return log_error_errno(errno, "Failed to open /proc/sys/kernel/random/entropy_avail: %m");
}
- if (e_fd) {
- n = pread(e_fd, buf, sizeof(buf) - 1, 0);
- if (n > 0) {
- buf[n] = '\0';
- sampledata->entropy_avail = atoi(buf);
- }
+ n = pread(e_fd, buf, sizeof(buf) - 1, 0);
+ if (n <= 0) {
+ e_fd = safe_close(e_fd);
+ } else {
+ buf[n] = '\0';
+ sampledata->entropy_avail = atoi(buf);
}
}
@@ -256,21 +240,21 @@ schedstat_next:
int r;
ps->next_ps = new0(struct ps_struct, 1);
- if (!ps->next_ps) {
- log_oom();
- exit (EXIT_FAILURE);
- }
+ if (!ps->next_ps)
+ return log_oom();
+
ps = ps->next_ps;
ps->pid = pid;
+ ps->sched = -1;
+ ps->schedstat = -1;
ps->sample = new0(struct ps_sched_struct, 1);
- if (!ps->sample) {
- log_oom();
- exit (EXIT_FAILURE);
- }
+ if (!ps->sample)
+ return log_oom();
+
ps->sample->sampledata = sampledata;
- pscount++;
+ (*pscount)++;
/* mark our first sample */
ps->first = ps->last = ps->sample;
@@ -278,16 +262,16 @@ schedstat_next:
ps->sample->waittime = atoll(wt);
/* get name, start time */
- if (!ps->sched) {
+ if (ps->sched < 0) {
sprintf(filename, "%d/sched", pid);
- ps->sched = openat(procfd, filename, O_RDONLY);
- if (ps->sched == -1)
+ ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
+ if (ps->sched < 0)
continue;
}
s = pread(ps->sched, buf, sizeof(buf) - 1, 0);
if (s <= 0) {
- close(ps->sched);
+ ps->sched = safe_close(ps->sched);
continue;
}
buf[s] = '\0';
@@ -299,7 +283,7 @@ schedstat_next:
/* cmdline */
if (arg_show_cmdline)
- pid_cmdline_strscpy(ps->name, sizeof(ps->name), pid);
+ pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid);
/* discard line 2 */
m = bufgetline(buf);
@@ -326,13 +310,19 @@ schedstat_next:
/* ppid */
sprintf(filename, "%d/stat", pid);
- fd = openat(procfd, filename, O_RDONLY);
- st = fdopen(fd, "r");
- if (!st)
+ fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
continue;
- if (!fscanf(st, "%*s %*s %*s %i", &p)) {
+
+ st = fdopen(fd, "re");
+ if (!st) {
+ close(fd);
continue;
}
+
+ if (!fscanf(st, "%*s %*s %*s %i", &p))
+ continue;
+
ps->ppid = p;
/*
@@ -369,6 +359,7 @@ schedstat_next:
children = parent->children;
while (children->next)
children = children->next;
+
children->next = ps;
}
}
@@ -379,32 +370,31 @@ schedstat_next:
* iteration */
/* rt, wt */
- if (!ps->schedstat) {
+ if (ps->schedstat < 0) {
sprintf(filename, "%d/schedstat", pid);
- ps->schedstat = openat(procfd, filename, O_RDONLY);
- if (ps->schedstat == -1)
+ ps->schedstat = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
+ if (ps->schedstat < 0)
continue;
}
+
s = pread(ps->schedstat, buf, sizeof(buf) - 1, 0);
if (s <= 0) {
/* clean up our file descriptors - assume that the process exited */
close(ps->schedstat);
- if (ps->sched)
- close(ps->sched);
- //if (ps->smaps)
- // fclose(ps->smaps);
+ ps->schedstat = -1;
+ ps->sched = safe_close(ps->sched);
continue;
}
+
buf[s] = '\0';
if (!sscanf(buf, "%s %s %*s", rt, wt))
continue;
ps->sample->next = new0(struct ps_sched_struct, 1);
- if (!ps->sample->next) {
- log_oom();
- exit(EXIT_FAILURE);
- }
+ if (!ps->sample->next)
+ return log_oom();
+
ps->sample->next->prev = ps->sample;
ps->sample = ps->sample->next;
ps->last = ps->sample;
@@ -412,9 +402,9 @@ schedstat_next:
ps->sample->waittime = atoll(wt);
ps->sample->sampledata = sampledata;
ps->sample->ps_new = ps;
- if (ps_prev) {
+ if (ps_prev)
ps_prev->cross = ps->sample;
- }
+
ps_prev = ps->sample;
ps->total = (ps->last->runtime - ps->first->runtime)
/ 1000000000.0;
@@ -425,15 +415,19 @@ schedstat_next:
/* Pss */
if (!ps->smaps) {
sprintf(filename, "%d/smaps", pid);
- fd = openat(procfd, filename, O_RDONLY);
- ps->smaps = fdopen(fd, "r");
- if (!ps->smaps)
+ fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ continue;
+ ps->smaps = fdopen(fd, "re");
+ if (!ps->smaps) {
+ close(fd);
continue;
+ }
setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf));
- }
- else {
+ } else {
rewind(ps->smaps);
}
+
/* test to see if we need to skip another field */
if (skip == 0) {
if (fgets(buf, sizeof(buf), ps->smaps) == NULL) {
@@ -450,6 +444,7 @@ schedstat_next:
}
rewind(ps->smaps);
}
+
while (1) {
int pss_kb;
@@ -470,32 +465,32 @@ schedstat_next:
break;
}
}
+
if (ps->sample->pss > ps->pss_max)
ps->pss_max = ps->sample->pss;
catch_rename:
/* catch process rename, try to randomize time */
mod = (arg_hz < 4.0) ? 4.0 : (arg_hz / 4.0);
- if (((samples - ps->pid) + pid) % (int)(mod) == 0) {
+ if (((sample - ps->pid) + pid) % (int)(mod) == 0) {
/* re-fetch name */
/* get name, start time */
- if (!ps->sched) {
+ if (ps->sched < 0) {
sprintf(filename, "%d/sched", pid);
- ps->sched = openat(procfd, filename, O_RDONLY);
- if (ps->sched == -1)
+ ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
+ if (ps->sched < 0)
continue;
}
+
s = pread(ps->sched, buf, sizeof(buf) - 1, 0);
if (s <= 0) {
/* clean up file descriptors */
- close(ps->sched);
- if (ps->schedstat)
- close(ps->schedstat);
- //if (ps->smaps)
- // fclose(ps->smaps);
+ ps->sched = safe_close(ps->sched);
+ ps->schedstat = safe_close(ps->schedstat);
continue;
}
+
buf[s] = '\0';
if (!sscanf(buf, "%s %*s %*s", key))
@@ -505,7 +500,9 @@ catch_rename:
/* cmdline */
if (arg_show_cmdline)
- pid_cmdline_strscpy(ps->name, sizeof(ps->name), pid);
+ pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid);
}
}
+
+ return 0;
}
diff --git a/src/bootchart/store.h b/src/bootchart/store.h
index f211b6f53b..bbb4796efd 100644
--- a/src/bootchart/store.h
+++ b/src/bootchart/store.h
@@ -27,9 +27,11 @@
#include <dirent.h>
#include "bootchart.h"
-extern DIR *proc;
-extern int procfd;
-
double gettime_ns(void);
void log_uptime(void);
-void log_sample(int sample, struct list_sample_data **ptr);
+int log_sample(DIR *proc,
+ int sample,
+ struct ps_struct *ps_first,
+ struct list_sample_data **ptr,
+ int *pscount,
+ int *cpus);
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index e111fa9cce..0132475e10 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -23,17 +23,15 @@
***/
#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <unistd.h>
#include <sys/utsname.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include "util.h"
+#include "fileio.h"
#include "macro.h"
#include "store.h"
#include "svg.h"
@@ -46,10 +44,6 @@
#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001)
#define to_color(n) (192.0 - ((n) * 192.0))
-static char str[8092];
-
-#define svg(a...) do { snprintf(str, 8092, ## a); fputs(str, of); fflush(of); } while (0)
-
static const char * const colorwheel[12] = {
"rgb(255,32,32)", // red
"rgb(32,192,192)", // cyan
@@ -74,9 +68,8 @@ static double ksize = 0;
static double esize = 0;
static struct list_sample_data *sampledata;
static struct list_sample_data *prev_sampledata;
-extern struct list_sample_data *head;
-static void svg_header(void) {
+static void svg_header(FILE *of, struct list_sample_data *head, double graph_start) {
double w;
double h;
struct list_sample_data *sampledata_last;
@@ -99,101 +92,97 @@ static void svg_header(void) {
+ (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */
+ psize + ksize + esize;
- svg("<?xml version=\"1.0\" standalone=\"no\"?>\n");
- svg("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
- svg("\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ fprintf(of, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
+ fprintf(of, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
+ fprintf(of, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
- //svg("<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
- svg("<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ",
- w, h);
- svg("xmlns=\"http://www.w3.org/2000/svg\">\n\n");
+ //fprintf(of, "<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
+ fprintf(of, "<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ", w, h);
+ fprintf(of, "xmlns=\"http://www.w3.org/2000/svg\">\n\n");
/* write some basic info as a comment, including some help */
- svg("<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
- svg("<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n");
- svg("<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n");
- svg("<!-- inkscape, etc. To display the files on your system, just point -->\n");
- svg("<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n");
-
- svg("<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
- svg("<!-- hz=\"%f\" n=\"%d\" -->\n", arg_hz, arg_samples_len);
- svg("<!-- x=\"%f\" y=\"%f\" -->\n", arg_scale_x, arg_scale_y);
- svg("<!-- rel=\"%d\" f=\"%d\" -->\n", arg_relative, arg_filter);
- svg("<!-- p=\"%d\" e=\"%d\" -->\n", arg_pss, arg_entropy);
- svg("<!-- o=\"%s\" i=\"%s\" -->\n\n", arg_output_path, arg_init_path);
+ fprintf(of, "<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
+ fprintf(of, "<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n");
+ fprintf(of, "<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n");
+ fprintf(of, "<!-- inkscape, etc. To display the files on your system, just point -->\n");
+ fprintf(of, "<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n");
+
+ fprintf(of, "<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
+ fprintf(of, "<!-- hz=\"%f\" n=\"%d\" -->\n", arg_hz, arg_samples_len);
+ fprintf(of, "<!-- x=\"%f\" y=\"%f\" -->\n", arg_scale_x, arg_scale_y);
+ fprintf(of, "<!-- rel=\"%d\" f=\"%d\" -->\n", arg_relative, arg_filter);
+ fprintf(of, "<!-- p=\"%d\" e=\"%d\" -->\n", arg_pss, arg_entropy);
+ fprintf(of, "<!-- o=\"%s\" i=\"%s\" -->\n\n", arg_output_path, arg_init_path);
/* style sheet */
- svg("<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
-
- svg(" rect { stroke-width: 1; }\n");
- svg(" rect.bg { fill: rgb(255,255,255); }\n");
- svg(" rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
- svg(" rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
- svg(" rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
- svg(" rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
- svg(" rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
- svg(" rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
- svg(" rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
- svg(" rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
- svg(" line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
- svg("// line.sec1 { }\n");
- svg(" line.sec5 { stroke-width: 2; }\n");
- svg(" line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
- svg(" line.dot { stroke-dasharray: 2 4; }\n");
- svg(" line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
-
- svg(" .run { font-size: 8; font-style: italic; }\n");
- svg(" text { font-family: Verdana, Helvetica; font-size: 10; }\n");
- svg(" text.sec { font-size: 8; }\n");
- svg(" text.t1 { font-size: 24; }\n");
- svg(" text.t2 { font-size: 12; }\n");
- svg(" text.idle { font-size: 18; }\n");
-
- svg(" ]]>\n </style>\n</defs>\n\n");
+ fprintf(of, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
+
+ fprintf(of, " rect { stroke-width: 1; }\n");
+ fprintf(of, " rect.bg { fill: rgb(255,255,255); }\n");
+ fprintf(of, " rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
+ fprintf(of, " rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
+ fprintf(of, " rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
+ fprintf(of, " rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
+ fprintf(of, " rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
+ fprintf(of, " rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
+ fprintf(of, " rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
+ fprintf(of, " rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
+ fprintf(of, " line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
+ fprintf(of, "// line.sec1 { }\n");
+ fprintf(of, " line.sec5 { stroke-width: 2; }\n");
+ fprintf(of, " line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
+ fprintf(of, " line.dot { stroke-dasharray: 2 4; }\n");
+ fprintf(of, " line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
+
+ fprintf(of, " .run { font-size: 8; font-style: italic; }\n");
+ fprintf(of, " text { font-family: Verdana, Helvetica; font-size: 10; }\n");
+ fprintf(of, " text.sec { font-size: 8; }\n");
+ fprintf(of, " text.t1 { font-size: 24; }\n");
+ fprintf(of, " text.t2 { font-size: 12; }\n");
+ fprintf(of, " text.idle { font-size: 18; }\n");
+
+ fprintf(of, " ]]>\n </style>\n</defs>\n\n");
}
-static void svg_title(const char *build) {
- char cmdline[256] = "";
- char filename[PATH_MAX];
- char buf[256];
- char rootbdev[16] = "Unknown";
- char model[256] = "Unknown";
+static int svg_title(FILE *of, const char *build, int pscount, double log_start, int overrun) {
+ _cleanup_free_ char *cmdline = NULL;
+ _cleanup_free_ char *model = NULL;
+ _cleanup_free_ char *buf = NULL;
char date[256] = "Unknown";
- char cpu[256] = "Unknown";
+ char *cpu;
char *c;
- FILE *f;
time_t t;
- int fd, r;
+ int r;
struct utsname uts;
- /* grab /proc/cmdline */
- fd = openat(procfd, "cmdline", O_RDONLY);
- f = fdopen(fd, "r");
- if (f) {
- if (!fgets(cmdline, 255, f))
- sprintf(cmdline, "Unknown");
- fclose(f);
+ r = read_one_line_file("/proc/cmdline", &cmdline);
+ if (r < 0) {
+ log_error_errno(r, "Unable to read cmdline: %m");
+ return r;
}
/* extract root fs so we can find disk model name in sysfs */
/* FIXME: this works only in the simple case */
c = strstr(cmdline, "root=/dev/");
if (c) {
- strncpy(rootbdev, &c[10], 3);
+ char rootbdev[4];
+ char filename[32];
+
+ strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1);
rootbdev[3] = '\0';
- sprintf(filename, "block/%s/device/model", rootbdev);
- fd = openat(sysfd, filename, O_RDONLY);
- f = fdopen(fd, "r");
- if (f) {
- if (!fgets(model, 255, f))
- fprintf(stderr, "Error reading disk model for %s\n", rootbdev);
- fclose(f);
- }
+ snprintf(filename, sizeof(filename), "/sys/block/%s/device/model", rootbdev);
+
+ r = read_one_line_file(filename, &model);
+ if (r < 0)
+ log_warning("Error reading disk model for %s: %m\n", rootbdev);
}
/* various utsname parameters */
- if (uname(&uts))
- fprintf(stderr, "Error getting uname info\n");
+ r = uname(&uts);
+ if (r < 0) {
+ log_error("Error getting uname info\n");
+ return -errno;
+ }
/* date */
t = time(NULL);
@@ -201,43 +190,45 @@ static void svg_title(const char *build) {
assert_se(r > 0);
/* CPU type */
- fd = openat(procfd, "cpuinfo", O_RDONLY);
- f = fdopen(fd, "r");
- if (f) {
- while (fgets(buf, 255, f)) {
- if (strstr(buf, "model name")) {
- strncpy(cpu, &buf[13], 255);
- break;
- }
- }
- fclose(f);
+ r = read_full_file("/proc/cpuinfo", &buf, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Unable to read cpuinfo: %m");
+
+ cpu = strstr(buf, "model name");
+ if (!cpu) {
+ log_error("Unable to read module name from cpuinfo.\n");
+ return -ENOENT;
}
- svg("<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
- uts.nodename, date);
- svg("<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
- uts.sysname, uts.release, uts.version, uts.machine);
- svg("<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n",
- cpu);
- svg("<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n",
- model);
- svg("<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n",
- cmdline);
- svg("<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n",
- build);
- svg("<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
- svg("<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
+ cpu += 13;
+ c = strchr(cpu, '\n');
+ if (c)
+ *c = '\0';
+
+ fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
+ uts.nodename, date);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
+ uts.sysname, uts.release, uts.version, uts.machine);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n", cpu);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n", model);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n", cmdline);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n", build);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
if (idletime >= 0.0)
- svg("%.03fs", idletime);
+ fprintf(of, "%.03fs", idletime);
else
- svg("Not detected");
- svg("</text>\n");
- svg("<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n",
- arg_hz, arg_samples_len, overrun, pscount, pfiltered);
+ fprintf(of, "Not detected");
+
+ fprintf(of, "</text>\n");
+ fprintf(of, "<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n",
+ arg_hz, arg_samples_len, overrun, pscount, pfiltered);
+
+ return 0;
}
-static void svg_graph_box(int height) {
+static void svg_graph_box(FILE *of, struct list_sample_data *head, int height, double graph_start) {
double d = 0.0;
int i = 0;
double finalsample = 0.0;
@@ -251,36 +242,35 @@ static void svg_graph_box(int height) {
finalsample = sampledata_last->sampletime;
/* outside box, fill */
- svg("<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(0.0),
- time_to_graph(finalsample - graph_start),
- ps_to_graph(height));
+ fprintf(of, "<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(0.0),
+ time_to_graph(finalsample - graph_start),
+ ps_to_graph(height));
for (d = graph_start; d <= finalsample;
d += (arg_scale_x < 2.0 ? 60.0 : arg_scale_x < 10.0 ? 1.0 : 0.1)) {
/* lines for each second */
if (i % 50 == 0)
- svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(d - graph_start),
- time_to_graph(d - graph_start),
- ps_to_graph(height));
+ fprintf(of, " <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ time_to_graph(d - graph_start),
+ time_to_graph(d - graph_start),
+ ps_to_graph(height));
else if (i % 10 == 0)
- svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(d - graph_start),
- time_to_graph(d - graph_start),
- ps_to_graph(height));
+ fprintf(of, " <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ time_to_graph(d - graph_start),
+ time_to_graph(d - graph_start),
+ ps_to_graph(height));
else
- svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(d - graph_start),
- time_to_graph(d - graph_start),
- ps_to_graph(height));
+ fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ time_to_graph(d - graph_start),
+ time_to_graph(d - graph_start),
+ ps_to_graph(height));
/* time label */
if (i % 10 == 0)
- svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
- time_to_graph(d - graph_start),
- -5.0,
- d - graph_start);
+ fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
+ time_to_graph(d - graph_start),
+ -5.0, d - graph_start);
i++;
}
@@ -301,7 +291,10 @@ static char* xml_comment_encode(const char* name) {
return enc_name;
}
-static void svg_pss_graph(void) {
+static void svg_pss_graph(FILE *of,
+ struct list_sample_data *head,
+ struct ps_struct *ps_first,
+ double graph_start) {
struct ps_struct *ps;
int i;
struct list_sample_data *sampledata_last;
@@ -312,24 +305,24 @@ static void svg_pss_graph(void) {
}
- svg("\n\n<!-- Pss memory size graph -->\n");
+ fprintf(of, "\n\n<!-- Pss memory size graph -->\n");
- svg("\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
+ fprintf(of, "\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
/* vsize 1000 == 1000mb */
- svg_graph_box(100);
+ svg_graph_box(of, head, 100, graph_start);
/* draw some hlines for usable memory sizes */
for (i = 100000; i < 1000000; i += 100000) {
- svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
+ fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
time_to_graph(.0),
kb_to_graph(i),
time_to_graph(sampledata_last->sampletime - graph_start),
kb_to_graph(i));
- svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
- time_to_graph(sampledata_last->sampletime - graph_start) + 5,
- kb_to_graph(i), (1000000 - i) / 1000);
+ fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
+ time_to_graph(sampledata_last->sampletime - graph_start) + 5,
+ kb_to_graph(i), (1000000 - i) / 1000);
}
- svg("\n");
+ fprintf(of, "\n");
/* now plot the graph itself */
i = 1;
@@ -368,12 +361,12 @@ static void svg_pss_graph(void) {
top += ps->sample->pss;
}
- svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- "rgb(64,64,64)",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - top),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- kb_to_graph(top - bottom));
+ fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ "rgb(64,64,64)",
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ kb_to_graph(1000000.0 - top),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ kb_to_graph(top - bottom));
bottom = top;
/* now plot the ones that are of significant size */
@@ -389,34 +382,36 @@ static void svg_pss_graph(void) {
break;
}
/* don't draw anything smaller than 2mb */
- if (ps->sample->sampledata == sampledata) {
- if (ps->sample->pss > (100 * arg_scale_y)) {
+ if (ps->sample->sampledata != sampledata)
+ continue;
+ if (ps->sample->pss > (100 * arg_scale_y)) {
top = bottom + ps->sample->pss;
- svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- colorwheel[ps->pid % 12],
- time_to_graph(prev_sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - top),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- kb_to_graph(top - bottom));
+ fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ colorwheel[ps->pid % 12],
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ kb_to_graph(1000000.0 - top),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ kb_to_graph(top - bottom));
bottom = top;
- }
- break;
}
+ break;
}
+
while ((cross_place = ps->sample->cross)) {
ps = ps->sample->cross->ps_new;
ps->sample = cross_place;
if (ps->sample->pss > (100 * arg_scale_y)) {
top = bottom + ps->sample->pss;
- svg(" <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- colorwheel[ps->pid % 12],
- time_to_graph(prev_sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - top),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- kb_to_graph(top - bottom));
+ fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ colorwheel[ps->pid % 12],
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ kb_to_graph(1000000.0 - top),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ kb_to_graph(top - bottom));
bottom = top;
}
}
+
prev_sampledata = sampledata;
i++;
}
@@ -435,18 +430,22 @@ static void svg_pss_graph(void) {
ps = ps->next_ps;
if (!ps)
continue;
+
ps->sample = ps->first;
while (ps->sample->next) {
ps->sample = ps->sample->next;
if (ps->sample->sampledata == sampledata)
break;
}
+
if (ps->sample->sampledata == sampledata) {
if (ps->sample->pss <= (100 * arg_scale_y))
top += ps->sample->pss;
+
break;
}
}
+
while ((cross_place = ps->sample->cross)) {
ps = ps->sample->cross->ps_new;
ps->sample = cross_place;
@@ -475,11 +474,10 @@ static void svg_pss_graph(void) {
top = bottom + ps->sample->pss;
/* draw a label with the process / PID */
if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y)))
- svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
- time_to_graph(sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
- ps->name,
- ps->pid);
+ fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
+ time_to_graph(sampledata->sampletime - graph_start),
+ kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
+ ps->name, ps->pid);
bottom = top;
}
break;
@@ -493,19 +491,19 @@ static void svg_pss_graph(void) {
top = bottom + ps->sample->pss;
/* draw a label with the process / PID */
if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y)))
- svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
- time_to_graph(sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
- ps->name,
- ps->pid);
+ fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
+ time_to_graph(sampledata->sampletime - graph_start),
+ kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
+ ps->name, ps->pid);
bottom = top;
}
}
+
i++;
}
/* debug output - full data dump */
- svg("\n\n<!-- PSS map - csv format -->\n");
+ fprintf(of, "\n\n<!-- PSS map - csv format -->\n");
ps = ps_first;
while (ps->next_ps) {
_cleanup_free_ char *enc_name = NULL;
@@ -517,19 +515,25 @@ static void svg_pss_graph(void) {
if (!enc_name)
continue;
- svg("<!-- %s [%d] pss=", enc_name, ps->pid);
+ fprintf(of, "<!-- %s [%d] pss=", enc_name, ps->pid);
ps->sample = ps->first;
while (ps->sample->next) {
ps->sample = ps->sample->next;
- svg("%d," , ps->sample->pss);
+ fprintf(of, "%d," , ps->sample->pss);
}
- svg(" -->\n");
+
+ fprintf(of, " -->\n");
}
}
-static void svg_io_bi_bar(void) {
+static void svg_io_bi_bar(FILE *of,
+ struct list_sample_data *head,
+ int n_samples,
+ double graph_start,
+ double interval) {
+
double max = 0.0;
double range;
int max_here = 0;
@@ -538,9 +542,8 @@ static void svg_io_bi_bar(void) {
struct list_sample_data *start_sampledata;
struct list_sample_data *stop_sampledata;
- svg("<!-- IO utilization graph - In -->\n");
-
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n");
+ fprintf(of, "<!-- IO utilization graph - In -->\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n");
/*
* calculate rounding range
@@ -554,7 +557,7 @@ static void svg_io_bi_bar(void) {
range = 2.0; /* no smoothing */
/* surrounding box */
- svg_graph_box(5);
+ svg_graph_box(of, head, 5, graph_start);
/* find the max IO first */
i = 1;
@@ -565,27 +568,26 @@ static void svg_io_bi_bar(void) {
double tot;
start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), samples - 1);
+ stop = MIN(i + (range / 2), n_samples - 1);
diff = (stop - start);
start_sampledata = sampledata;
stop_sampledata = sampledata;
- for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++)
+ for (k = 0; k < ((range/2) - 1) && start_sampledata->link_next; k++)
start_sampledata = start_sampledata->link_next;
- for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++)
+
+ for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
stop_sampledata = stop_sampledata->link_prev;
- tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi)
- / diff;
+ tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
if (tot > max) {
max = tot;
max_here = i;
}
- tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo)
- / diff;
+ tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff;
if (tot > max)
max = tot;
@@ -604,43 +606,48 @@ static void svg_io_bi_bar(void) {
double pbi = 0;
start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), samples);
+ stop = MIN(i + (range / 2), n_samples);
diff = (stop - start);
start_sampledata = sampledata;
stop_sampledata = sampledata;
- for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++)
+ for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++)
start_sampledata = start_sampledata->link_next;
- for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++)
+
+ for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
stop_sampledata = stop_sampledata->link_prev;
- tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi)
- / diff;
+ tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
if (max > 0)
pbi = tot / max;
if (pbi > 0.001)
- svg("<rect class=\"bi\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- pbi * (arg_scale_y * 5));
+ fprintf(of, "<rect class=\"bi\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ pbi * (arg_scale_y * 5));
/* labels around highest value */
if (i == max_here) {
- svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
- time_to_graph(sampledata->sampletime - graph_start) + 5,
- ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15,
- max / 1024.0 / (interval / 1000000000.0));
+ fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
+ time_to_graph(sampledata->sampletime - graph_start) + 5,
+ ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15,
+ max / 1024.0 / (interval / 1000000000.0));
}
+
i++;
prev_sampledata = sampledata;
}
}
-static void svg_io_bo_bar(void) {
+static void svg_io_bo_bar(FILE *of,
+ struct list_sample_data *head,
+ int n_samples,
+ double graph_start,
+ double interval) {
double max = 0.0;
double range;
int max_here = 0;
@@ -649,9 +656,8 @@ static void svg_io_bo_bar(void) {
struct list_sample_data *start_sampledata;
struct list_sample_data *stop_sampledata;
- svg("<!-- IO utilization graph - out -->\n");
-
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - write</text>\n");
+ fprintf(of, "<!-- IO utilization graph - out -->\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - write</text>\n");
/*
* calculate rounding range
@@ -665,7 +671,7 @@ static void svg_io_bo_bar(void) {
range = 2.0; /* no smoothing */
/* surrounding box */
- svg_graph_box(5);
+ svg_graph_box(of, head, 5, graph_start);
/* find the max IO first */
i = 0;
@@ -676,52 +682,52 @@ static void svg_io_bo_bar(void) {
double tot;
start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), samples - 1);
+ stop = MIN(i + (range / 2), n_samples - 1);
diff = (stop - start);
start_sampledata = sampledata;
stop_sampledata = sampledata;
- for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++)
+ for (k = 0; k < (range/2) - 1 && start_sampledata->link_next; k++)
start_sampledata = start_sampledata->link_next;
- for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++)
+
+ for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
stop_sampledata = stop_sampledata->link_prev;
- tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi)
- / diff;
+ tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
if (tot > max)
max = tot;
- tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo)
- / diff;
+
+ tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff;
if (tot > max) {
max = tot;
max_here = i;
}
+
i++;
}
/* plot bo */
prev_sampledata = head;
- i=1;
+ i = 1;
+
LIST_FOREACH_BEFORE(link, sampledata, head) {
- int start;
- int stop;
- int diff;
- double tot;
- double pbo;
+ int start, stop, diff;
+ double tot, pbo;
pbo = 0;
start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), samples);
+ stop = MIN(i + (range / 2), n_samples);
diff = (stop - start);
start_sampledata = sampledata;
stop_sampledata = sampledata;
- for (k=0;(k<((range/2)-1))&&(start_sampledata->link_next);k++)
+ for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++)
start_sampledata = start_sampledata->link_next;
- for (k=0;(k<(range/2))&&(stop_sampledata->link_prev);k++)
+
+ for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
stop_sampledata = stop_sampledata->link_prev;
tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo)
@@ -731,34 +737,36 @@ static void svg_io_bo_bar(void) {
pbo = tot / max;
if (pbo > 0.001)
- svg("<rect class=\"bo\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- pbo * (arg_scale_y * 5));
+ fprintf(of, "<rect class=\"bo\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ pbo * (arg_scale_y * 5));
/* labels around highest bo value */
if (i == max_here) {
- svg(" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
- time_to_graph(sampledata->sampletime - graph_start) + 5,
- ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))),
- max / 1024.0 / (interval / 1000000000.0));
+ fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
+ time_to_graph(sampledata->sampletime - graph_start) + 5,
+ ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))),
+ max / 1024.0 / (interval / 1000000000.0));
}
+
i++;
prev_sampledata = sampledata;
}
}
-static void svg_cpu_bar(int cpu_num) {
+static void svg_cpu_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) {
- svg("<!-- CPU utilization graph -->\n");
+ fprintf(of, "<!-- CPU utilization graph -->\n");
if (cpu_num < 0)
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] utilization</text>\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] utilization</text>\n");
else
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] utilization</text>\n", cpu_num);
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] utilization</text>\n", cpu_num);
+
/* surrounding box */
- svg_graph_box(5);
+ svg_graph_box(of, head, 5, graph_start);
/* bars for each sample, proportional to the CPU util. */
prev_sampledata = head;
@@ -770,7 +778,7 @@ static void svg_cpu_bar(int cpu_num) {
ptrt = trt = 0.0;
if (cpu_num < 0)
- for (c = 0; c < cpus; c++)
+ for (c = 0; c < n_cpus; c++)
trt += sampledata->runtime[c] - prev_sampledata->runtime[c];
else
trt = sampledata->runtime[cpu_num] - prev_sampledata->runtime[cpu_num];
@@ -778,7 +786,7 @@ static void svg_cpu_bar(int cpu_num) {
trt = trt / 1000000000.0;
if (cpu_num < 0)
- trt = trt / (double)cpus;
+ trt = trt / (double)n_cpus;
if (trt > 0.0)
ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime);
@@ -786,28 +794,28 @@ static void svg_cpu_bar(int cpu_num) {
if (ptrt > 1.0)
ptrt = 1.0;
- if (ptrt > 0.001) {
- svg("<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- ptrt * (arg_scale_y * 5));
- }
+ if (ptrt > 0.001)
+ fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ ptrt * (arg_scale_y * 5));
+
prev_sampledata = sampledata;
}
}
-static void svg_wait_bar(int cpu_num) {
+static void svg_wait_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) {
- svg("<!-- Wait time aggregation box -->\n");
+ fprintf(of, "<!-- Wait time aggregation box -->\n");
if (cpu_num < 0)
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] wait</text>\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] wait</text>\n");
else
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] wait</text>\n", cpu_num);
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] wait</text>\n", cpu_num);
/* surrounding box */
- svg_graph_box(5);
+ svg_graph_box(of, head, 5, graph_start);
/* bars for each sample, proportional to the CPU util. */
prev_sampledata = head;
@@ -819,7 +827,7 @@ static void svg_wait_bar(int cpu_num) {
ptwt = twt = 0.0;
if (cpu_num < 0)
- for (c = 0; c < cpus; c++)
+ for (c = 0; c < n_cpus; c++)
twt += sampledata->waittime[c] - prev_sampledata->waittime[c];
else
twt = sampledata->waittime[cpu_num] - prev_sampledata->waittime[cpu_num];
@@ -827,7 +835,7 @@ static void svg_wait_bar(int cpu_num) {
twt = twt / 1000000000.0;
if (cpu_num < 0)
- twt = twt / (double)cpus;
+ twt = twt / (double)n_cpus;
if (twt > 0.0)
ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime);
@@ -835,39 +843,38 @@ static void svg_wait_bar(int cpu_num) {
if (ptwt > 1.0)
ptwt = 1.0;
- if (ptwt > 0.001) {
- svg("<rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- ptwt * (arg_scale_y * 5));
- }
+ if (ptwt > 0.001)
+ fprintf(of, "<rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ ptwt * (arg_scale_y * 5));
+
prev_sampledata = sampledata;
}
}
-static void svg_entropy_bar(void) {
+static void svg_entropy_bar(FILE *of, struct list_sample_data *head, double graph_start) {
- svg("<!-- entropy pool graph -->\n");
+ fprintf(of, "<!-- entropy pool graph -->\n");
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">Entropy pool size</text>\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Entropy pool size</text>\n");
/* surrounding box */
- svg_graph_box(5);
+ svg_graph_box(of, head, 5, graph_start);
/* bars for each sample, scale 0-4096 */
prev_sampledata = head;
LIST_FOREACH_BEFORE(link, sampledata, head) {
- /* svg("<!-- entropy %.03f %i -->\n", sampletime[i], entropy_avail[i]); */
- svg("<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- ((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- (sampledata->entropy_avail / 4096.) * (arg_scale_y * 5));
+ fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev_sampledata->sampletime - graph_start),
+ ((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))),
+ time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
+ (sampledata->entropy_avail / 4096.) * (arg_scale_y * 5));
prev_sampledata = sampledata;
}
}
-static struct ps_struct *get_next_ps(struct ps_struct *ps) {
+static struct ps_struct *get_next_ps(struct ps_struct *ps, struct ps_struct *ps_first) {
/*
* walk the list of processes and return the next one to be
* painted
@@ -885,9 +892,9 @@ static struct ps_struct *get_next_ps(struct ps_struct *ps) {
/* go back for parent siblings */
while (1) {
- if (ps->parent)
- if (ps->parent->next)
- return ps->parent->next;
+ if (ps->parent && ps->parent->next)
+ return ps->parent->next;
+
ps = ps->parent;
if (!ps)
return ps;
@@ -915,7 +922,7 @@ static bool ps_filter(struct ps_struct *ps) {
return 0;
}
-static void svg_do_initcall(int count_only) {
+static void svg_do_initcall(FILE *of, struct list_sample_data *head, int count_only, double graph_start) {
_cleanup_pclose_ FILE *f = NULL;
double t;
char func[256];
@@ -923,17 +930,16 @@ static void svg_do_initcall(int count_only) {
int usecs;
/* can't plot initcall when disabled or in relative mode */
- if (!initcall || arg_relative) {
+ if (!arg_initcall || arg_relative) {
kcount = 0;
return;
}
if (!count_only) {
- svg("<!-- initcall -->\n");
-
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">Kernel init threads</text>\n");
+ fprintf(of, "<!-- initcall -->\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Kernel init threads</text>\n");
/* surrounding box */
- svg_graph_box(kcount);
+ svg_graph_box(of, head, kcount, graph_start);
}
kcount = 0;
@@ -979,47 +985,52 @@ static void svg_do_initcall(int count_only) {
continue;
}
- svg("<!-- thread=\"%s\" time=\"%.3f\" elapsed=\"%d\" result=\"%d\" -->\n",
- func, t, usecs, ret);
+ fprintf(of, "<!-- thread=\"%s\" time=\"%.3f\" elapsed=\"%d\" result=\"%d\" -->\n",
+ func, t, usecs, ret);
if (usecs < 1000)
continue;
/* rect */
- svg(" <rect class=\"krnl\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(t - (usecs / 1000000.0)),
- ps_to_graph(kcount),
- time_to_graph(usecs / 1000000.0),
- ps_to_graph(1));
+ fprintf(of, " <rect class=\"krnl\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(t - (usecs / 1000000.0)),
+ ps_to_graph(kcount),
+ time_to_graph(usecs / 1000000.0),
+ ps_to_graph(1));
/* label */
- svg(" <text x=\"%.03f\" y=\"%.03f\">%s <tspan class=\"run\">%.03fs</tspan></text>\n",
- time_to_graph(t - (usecs / 1000000.0)) + 5,
- ps_to_graph(kcount) + 15,
- func,
- usecs / 1000000.0);
+ fprintf(of, " <text x=\"%.03f\" y=\"%.03f\">%s <tspan class=\"run\">%.03fs</tspan></text>\n",
+ time_to_graph(t - (usecs / 1000000.0)) + 5,
+ ps_to_graph(kcount) + 15,
+ func, usecs / 1000000.0);
kcount++;
}
}
-static void svg_ps_bars(void) {
+static void svg_ps_bars(FILE *of,
+ struct list_sample_data *head,
+ int n_samples,
+ int n_cpus,
+ struct ps_struct *ps_first,
+ double graph_start,
+ double interval) {
+
struct ps_struct *ps;
int i = 0;
int j = 0;
int pid;
double w = 0.0;
- svg("<!-- Process graph -->\n");
-
- svg("<text class=\"t2\" x=\"5\" y=\"-15\">Processes</text>\n");
+ fprintf(of, "<!-- Process graph -->\n");
+ fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Processes</text>\n");
/* surrounding box */
- svg_graph_box(pcount);
+ svg_graph_box(of, head, pcount, graph_start);
/* pass 2 - ps boxes */
ps = ps_first;
- while ((ps = get_next_ps(ps))) {
+ while ((ps = get_next_ps(ps, ps_first))) {
_cleanup_free_ char *enc_name = NULL, *escaped = NULL;
double endtime;
double starttime;
@@ -1033,8 +1044,8 @@ static void svg_ps_bars(void) {
continue;
/* leave some trace of what we actually filtered etc. */
- svg("<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid,
- ps->ppid, ps->total);
+ fprintf(of, "<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid,
+ ps->ppid, ps->total);
starttime = ps->first->sampledata->sampletime;
@@ -1049,20 +1060,20 @@ static void svg_ps_bars(void) {
/* if this is the last child, we might still need to draw a connecting line */
if ((!ps->next) && (ps->parent))
- svg(" <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- ps->parent->pos_x,
- ps_to_graph(j-1) + 10.0, /* whee, use the last value here */
- ps->parent->pos_x,
- ps->parent->pos_y);
+ fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ ps->parent->pos_x,
+ ps_to_graph(j-1) + 10.0, /* whee, use the last value here */
+ ps->parent->pos_x,
+ ps->parent->pos_y);
continue;
}
endtime = ps->last->sampledata->sampletime;
- svg(" <rect class=\"ps\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(starttime - graph_start),
- ps_to_graph(j),
- time_to_graph(ps->last->sampledata->sampletime - starttime),
- ps_to_graph(1));
+ fprintf(of, " <rect class=\"ps\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(starttime - graph_start),
+ ps_to_graph(j),
+ time_to_graph(ps->last->sampledata->sampletime - starttime),
+ ps_to_graph(1));
/* paint cpu load over these */
ps->sample = ps->first;
@@ -1091,18 +1102,18 @@ static void svg_ps_bars(void) {
if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */
continue;
- svg(" <rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev->sampledata->sampletime - graph_start),
- ps_to_graph(j),
- time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
- ps_to_graph(wrt));
+ fprintf(of, " <rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev->sampledata->sampletime - graph_start),
+ ps_to_graph(j),
+ time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
+ ps_to_graph(wrt));
/* draw cpu over wait - TODO figure out how/why run + wait > interval */
- svg(" <rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev->sampledata->sampletime - graph_start),
- ps_to_graph(j + (1.0 - prt)),
- time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
- ps_to_graph(prt));
+ fprintf(of, " <rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
+ time_to_graph(prev->sampledata->sampletime - graph_start),
+ ps_to_graph(j + (1.0 - prt)),
+ time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
+ ps_to_graph(prt));
t++;
}
@@ -1114,34 +1125,34 @@ static void svg_ps_bars(void) {
w = starttime;
/* text label of process name */
- svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan> %s</text>\n",
- time_to_graph(w - graph_start) + 5.0,
- ps_to_graph(j) + 14.0,
- escaped ? escaped : ps->name,
- ps->pid,
- (ps->last->runtime - ps->first->runtime) / 1000000000.0,
- arg_show_cgroup ? ps->cgroup : "");
+ fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan> %s</text>\n",
+ time_to_graph(w - graph_start) + 5.0,
+ ps_to_graph(j) + 14.0,
+ escaped ? escaped : ps->name,
+ ps->pid,
+ (ps->last->runtime - ps->first->runtime) / 1000000000.0,
+ arg_show_cgroup ? ps->cgroup : "");
/* paint lines to the parent process */
if (ps->parent) {
/* horizontal part */
- svg(" <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(starttime - graph_start),
- ps_to_graph(j) + 10.0,
- ps->parent->pos_x,
- ps_to_graph(j) + 10.0);
+ fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ time_to_graph(starttime - graph_start),
+ ps_to_graph(j) + 10.0,
+ ps->parent->pos_x,
+ ps_to_graph(j) + 10.0);
/* one vertical line connecting all the horizontal ones up */
if (!ps->next)
- svg(" <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- ps->parent->pos_x,
- ps_to_graph(j) + 10.0,
- ps->parent->pos_x,
- ps->parent->pos_y);
+ fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ ps->parent->pos_x,
+ ps_to_graph(j) + 10.0,
+ ps->parent->pos_x,
+ ps->parent->pos_y);
}
j++; /* count boxes */
- svg("\n");
+ fprintf(of, "\n");
}
/* last pass - determine when idle */
@@ -1161,7 +1172,7 @@ static void svg_ps_bars(void) {
ps->sample = ps->first;
i = ps->sample->next->sampledata->counter;
- while (ps->sample->next && i<(samples-(arg_hz/2))) {
+ while (ps->sample->next && i<(n_samples-(arg_hz/2))) {
double crt;
double brt;
int c;
@@ -1170,13 +1181,14 @@ static void svg_ps_bars(void) {
ps->sample = ps->sample->next;
sample_hz = ps->sample;
- for (ii=0;((ii<(int)arg_hz/2)&&(ps->sample->next));ii++)
+ for (ii = 0; (ii < (int)arg_hz/2) && sample_hz->next; ii++)
sample_hz = sample_hz->next;
/* subtract bootchart cpu utilization from total */
crt = 0.0;
- for (c = 0; c < cpus; c++)
+ for (c = 0; c < n_cpus; c++)
crt += sample_hz->sampledata->runtime[c] - ps->sample->sampledata->runtime[c];
+
brt = sample_hz->runtime - ps->sample->runtime;
/*
* our definition of "idle":
@@ -1186,24 +1198,24 @@ static void svg_ps_bars(void) {
*/
if ((crt - brt) < (interval / 2.0)) {
idletime = ps->sample->sampledata->sampletime - graph_start;
- svg("\n<!-- idle detected at %.03f seconds -->\n",
- idletime);
- svg("<line class=\"idle\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(idletime),
- -arg_scale_y,
- time_to_graph(idletime),
- ps_to_graph(pcount) + arg_scale_y);
- svg("<text class=\"idle\" x=\"%.03f\" y=\"%.03f\">%.01fs</text>\n",
- time_to_graph(idletime) + 5.0,
- ps_to_graph(pcount) + arg_scale_y,
- idletime);
+ fprintf(of, "\n<!-- idle detected at %.03f seconds -->\n", idletime);
+ fprintf(of, "<line class=\"idle\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
+ time_to_graph(idletime),
+ -arg_scale_y,
+ time_to_graph(idletime),
+ ps_to_graph(pcount) + arg_scale_y);
+ fprintf(of, "<text class=\"idle\" x=\"%.03f\" y=\"%.03f\">%.01fs</text>\n",
+ time_to_graph(idletime) + 5.0,
+ ps_to_graph(pcount) + arg_scale_y,
+ idletime);
break;
}
+
i++;
}
}
-static void svg_top_ten_cpu(void) {
+static void svg_top_ten_cpu(FILE *of, struct ps_struct *ps_first) {
struct ps_struct *top[10];
struct ps_struct emptyps = {};
struct ps_struct *ps;
@@ -1214,7 +1226,7 @@ static void svg_top_ten_cpu(void) {
/* walk all ps's and setup ptrs */
ps = ps_first;
- while ((ps = get_next_ps(ps))) {
+ while ((ps = get_next_ps(ps, ps_first))) {
for (n = 0; n < 10; n++) {
if (ps->total <= top[n]->total)
continue;
@@ -1226,16 +1238,16 @@ static void svg_top_ten_cpu(void) {
}
}
- svg("<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n");
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n");
for (n = 0; n < 10; n++)
- svg("<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - <![CDATA[%s]]> [%d]</text>\n",
- 20 + (n * 13),
- top[n]->total,
- top[n]->name,
- top[n]->pid);
+ fprintf(of, "<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - <![CDATA[%s]]> [%d]</text>\n",
+ 20 + (n * 13),
+ top[n]->total,
+ top[n]->name,
+ top[n]->pid);
}
-static void svg_top_ten_pss(void) {
+static void svg_top_ten_pss(FILE *of, struct ps_struct *ps_first) {
struct ps_struct *top[10];
struct ps_struct emptyps = {};
struct ps_struct *ps;
@@ -1246,10 +1258,11 @@ static void svg_top_ten_pss(void) {
/* walk all ps's and setup ptrs */
ps = ps_first;
- while ((ps = get_next_ps(ps))) {
+ while ((ps = get_next_ps(ps, ps_first))) {
for (n = 0; n < 10; n++) {
if (ps->pss_max <= top[n]->pss_max)
continue;
+
/* cascade insert */
for (m = 9; m > n; m--)
top[m] = top[m-1];
@@ -1258,30 +1271,39 @@ static void svg_top_ten_pss(void) {
}
}
- svg("<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n");
+ fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n");
for (n = 0; n < 10; n++)
- svg("<text class=\"t3\" x=\"20\" y=\"%d\">%dK - <![CDATA[%s]]> [%d]</text>\n",
- 20 + (n * 13),
- top[n]->pss_max,
- top[n]->name,
- top[n]->pid);
+ fprintf(of, "<text class=\"t3\" x=\"20\" y=\"%d\">%dK - <![CDATA[%s]]> [%d]</text>\n",
+ 20 + (n * 13),
+ top[n]->pss_max,
+ top[n]->name,
+ top[n]->pid);
}
-void svg_do(const char *build) {
+int svg_do(FILE *of,
+ const char *build,
+ struct list_sample_data *head,
+ struct ps_struct *ps_first,
+ int n_samples,
+ int pscount,
+ int n_cpus,
+ double graph_start,
+ double log_start,
+ double interval,
+ int overrun) {
+
struct ps_struct *ps;
double offset = 7;
- int c;
-
- memzero(&str, sizeof(str));
+ int r, c;
ps = ps_first;
/* count initcall thread count first */
- svg_do_initcall(1);
- ksize = (kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0);
+ svg_do_initcall(of, head, 1, graph_start);
+ ksize = kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0;
/* then count processes */
- while ((ps = get_next_ps(ps))) {
+ while ((ps = get_next_ps(ps, ps_first))) {
if (!ps_filter(ps))
pcount++;
else
@@ -1292,65 +1314,70 @@ void svg_do(const char *build) {
esize = (arg_entropy ? arg_scale_y * 7 : 0);
/* after this, we can draw the header with proper sizing */
- svg_header();
- svg("<rect class=\"bg\" width=\"100%%\" height=\"100%%\" />\n\n");
+ svg_header(of, head, graph_start);
+ fprintf(of, "<rect class=\"bg\" width=\"100%%\" height=\"100%%\" />\n\n");
- svg("<g transform=\"translate(10,400)\">\n");
- svg_io_bi_bar();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,400)\">\n");
+ svg_io_bi_bar(of, head, n_samples, graph_start, interval);
+ fprintf(of, "</g>\n\n");
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_io_bo_bar();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
+ svg_io_bo_bar(of, head, n_samples, graph_start, interval);
+ fprintf(of, "</g>\n\n");
- for (c = -1; c < (arg_percpu ? cpus : 0); c++) {
+ for (c = -1; c < (arg_percpu ? n_cpus : 0); c++) {
offset += 7;
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_cpu_bar(c);
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
+ svg_cpu_bar(of, head, n_cpus, c, graph_start);
+ fprintf(of, "</g>\n\n");
offset += 7;
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_wait_bar(c);
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
+ svg_wait_bar(of, head, n_cpus, c, graph_start);
+ fprintf(of, "</g>\n\n");
}
if (kcount) {
offset += 7;
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_do_initcall(0);
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
+ svg_do_initcall(of, head, 0, graph_start);
+ fprintf(of, "</g>\n\n");
}
offset += 7;
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize);
- svg_ps_bars();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize);
+ svg_ps_bars(of, head, n_samples, n_cpus, ps_first, graph_start, interval);
+ fprintf(of, "</g>\n\n");
+
+ fprintf(of, "<g transform=\"translate(10, 0)\">\n");
+ r = svg_title(of, build, pscount, log_start, overrun);
+ fprintf(of, "</g>\n\n");
- svg("<g transform=\"translate(10, 0)\">\n");
- svg_title(build);
- svg("</g>\n\n");
+ if (r < 0)
+ return r;
- svg("<g transform=\"translate(10,200)\">\n");
- svg_top_ten_cpu();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,200)\">\n");
+ svg_top_ten_cpu(of, ps_first);
+ fprintf(of, "</g>\n\n");
if (arg_entropy) {
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize);
- svg_entropy_bar();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize);
+ svg_entropy_bar(of, head, graph_start);
+ fprintf(of, "</g>\n\n");
}
if (arg_pss) {
- svg("<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize);
- svg_pss_graph();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize);
+ svg_pss_graph(of, head, ps_first, graph_start);
+ fprintf(of, "</g>\n\n");
- svg("<g transform=\"translate(410,200)\">\n");
- svg_top_ten_pss();
- svg("</g>\n\n");
+ fprintf(of, "<g transform=\"translate(410,200)\">\n");
+ svg_top_ten_pss(of, ps_first);
+ fprintf(of, "</g>\n\n");
}
- /* svg footer */
- svg("\n</svg>\n");
+ /* fprintf footer */
+ fprintf(of, "\n</svg>\n");
+
+ return 0;
}
diff --git a/src/bootchart/svg.h b/src/bootchart/svg.h
index df3a7bf8ef..75efa22614 100644
--- a/src/bootchart/svg.h
+++ b/src/bootchart/svg.h
@@ -24,4 +24,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-void svg_do(const char *build);
+int svg_do(FILE *of,
+ const char *build,
+ struct list_sample_data *head,
+ struct ps_struct *ps_first,
+ int n_samples,
+ int pscount,
+ int n_cpus,
+ double graph_start,
+ double log_start,
+ double interval,
+ int overrun);
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index b6b0056362..3e398b53e9 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -23,13 +23,9 @@
***/
#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/types.h>
-#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <poll.h>
#include <sys/prctl.h>
#include <stddef.h>
#include <getopt.h>
@@ -37,24 +33,15 @@
#include "log.h"
#include "util.h"
-#include "hashmap.h"
-#include "socket-util.h"
#include "sd-daemon.h"
-#include "sd-bus.h"
#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.h"
#include "build.h"
#include "strv.h"
#include "def.h"
#include "capability.h"
-#include "bus-control.h"
-#include "smack-util.h"
-#include "set.h"
#include "bus-xml-policy.h"
-#include "driver.h"
#include "proxy.h"
-#include "synthesize.h"
+#include "formats-util.h"
static char *arg_address = NULL;
static char **arg_configuration = NULL;
@@ -82,7 +69,7 @@ static int client_context_new(ClientContext **out) {
c = new0(ClientContext, 1);
if (!c)
- return log_oom();
+ return -ENOMEM;
c->fd = -1;
diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c
index f6ac0c0093..675d24485e 100644
--- a/src/bus-proxyd/bus-xml-policy.c
+++ b/src/bus-proxyd/bus-xml-policy.c
@@ -25,9 +25,9 @@
#include "set.h"
#include "conf-files.h"
#include "bus-internal.h"
-#include "bus-message.h"
#include "bus-xml-policy.h"
#include "sd-login.h"
+#include "formats-util.h"
static void policy_item_free(PolicyItem *i) {
assert(i);
diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h
index f2ec1bbea4..8f0ab8f17f 100644
--- a/src/bus-proxyd/bus-xml-policy.h
+++ b/src/bus-proxyd/bus-xml-policy.h
@@ -21,12 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <pthread.h>
#include "list.h"
#include "hashmap.h"
-#include "set.h"
typedef enum PolicyItemType {
_POLICY_ITEM_TYPE_UNSET = 0,
diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c
index bc2c0c86f3..4ac955da41 100644
--- a/src/bus-proxyd/driver.c
+++ b/src/bus-proxyd/driver.c
@@ -21,23 +21,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stddef.h>
-#include "log.h"
#include "util.h"
#include "sd-bus.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "build.h"
#include "strv.h"
-#include "def.h"
-#include "capability.h"
-#include "bus-control.h"
#include "set.h"
#include "driver.h"
#include "synthesize.h"
@@ -56,9 +49,6 @@ static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bu
if (r < 0)
return r;
- if ((c->mask & mask) != mask)
- return -ENOTSUP;
-
*_creds = c;
c = NULL;
@@ -116,6 +106,10 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
" <method name=\"RemoveMatch\">\n"
" <arg type=\"s\" direction=\"in\"/>\n"
" </method>\n"
+ " <method name=\"GetConnectionCredentials\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"a{sv}\" direction=\"out\"/>\n"
+ " </method>\n"
" <method name=\"GetConnectionSELinuxSecurityContext\">\n"
" <arg type=\"s\" direction=\"in\"/>\n"
" <arg type=\"ay\" direction=\"out\"/>\n"
@@ -219,7 +213,74 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
return synthetic_reply_method_return(m, NULL);
+ } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionCredentials")) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
+ r = get_creds_by_message(a, m, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, &error);
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_open_container(reply, 'a', "{sv}");
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ /* Due to i.e. namespace translations some data might be missing */
+
+ if (creds->mask & SD_BUS_CREDS_PID) {
+ r = sd_bus_message_append(reply, "{sv}", "ProcessID", "u", (uint32_t) creds->pid);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+ }
+
+ if (creds->mask & SD_BUS_CREDS_EUID) {
+ r = sd_bus_message_append(reply, "{sv}", "UnixUserID", "u", (uint32_t) creds->euid);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+ }
+
+ if (creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+ r = sd_bus_message_open_container(reply, 'e', "sv");
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_append(reply, "s", "LinuxSecurityLabel");
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_open_container(reply, 'v', "ay");
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ return synthetic_driver_send(m->bus, reply);
+
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -230,7 +291,18 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
- return synthetic_reply_method_return(m, "y", creds->label, strlen(creds->label));
+ if (!(creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
+ return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
+ return synthetic_driver_send(m->bus, reply);
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
@@ -243,6 +315,9 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
+ if (!(creds->mask & SD_BUS_CREDS_PID))
+ return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
+
return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
@@ -256,6 +331,9 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
+ if (!(creds->mask & SD_BUS_CREDS_EUID))
+ return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
+
return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
@@ -290,6 +368,9 @@ int bus_proxy_process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPoli
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
+ if (!(creds->mask & SD_BUS_CREDS_UNIQUE_NAME))
+ return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
+
return synthetic_reply_method_return(m, "s", creds->unique_name);
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c
index 3dea908f5b..aa5010c1ac 100644
--- a/src/bus-proxyd/proxy.c
+++ b/src/bus-proxyd/proxy.c
@@ -23,35 +23,26 @@
***/
#include <sys/socket.h>
-#include <sys/un.h>
#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <poll.h>
-#include <stddef.h>
-#include <getopt.h>
#include "log.h"
#include "util.h"
-#include "socket-util.h"
#include "sd-daemon.h"
#include "sd-bus.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "build.h"
#include "strv.h"
-#include "def.h"
-#include "capability.h"
#include "bus-control.h"
-#include "smack-util.h"
#include "set.h"
#include "bus-xml-policy.h"
#include "driver.h"
#include "proxy.h"
#include "synthesize.h"
+#include "formats-util.h"
static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
_cleanup_bus_close_unref_ sd_bus *b = NULL;
@@ -729,13 +720,21 @@ static int proxy_process_destination_to_local(Proxy *p) {
/* Return the error to the client, if we can */
synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
- log_error_errno(r,
- "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
- p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
- strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
+ if (r == -ENOBUFS) {
+ /* if local dbus1 peer does not dispatch its queue, warn only once */
+ if (!p->queue_overflow)
+ log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid);
+ p->queue_overflow = true;
+ } else
+ log_error_errno(r,
+ "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
+ p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
+ strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
+
return 1;
}
+ p->queue_overflow = false;
return 1;
}
diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h
index 913d47071b..ff278a2465 100644
--- a/src/bus-proxyd/proxy.h
+++ b/src/bus-proxyd/proxy.h
@@ -21,10 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include "sd-bus.h"
#include "bus-xml-policy.h"
-#include "util.h"
typedef struct Proxy Proxy;
@@ -40,6 +38,7 @@ struct Proxy {
SharedPolicy *policy;
bool got_hello : 1;
+ bool queue_overflow : 1;
};
int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest);
diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c
index 9fb3e9fc49..61bc08ae33 100644
--- a/src/bus-proxyd/stdio-bridge.c
+++ b/src/bus-proxyd/stdio-bridge.c
@@ -21,36 +21,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/types.h>
-#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <poll.h>
#include <stddef.h>
#include <getopt.h>
#include "log.h"
#include "util.h"
-#include "socket-util.h"
#include "sd-daemon.h"
#include "sd-bus.h"
#include "bus-internal.h"
-#include "bus-message.h"
#include "bus-util.h"
#include "build.h"
#include "strv.h"
#include "def.h"
-#include "capability.h"
-#include "bus-control.h"
-#include "smack-util.h"
-#include "set.h"
-#include "bus-xml-policy.h"
-#include "driver.h"
#include "proxy.h"
-#include "synthesize.h"
+#include "formats-util.h"
static char *arg_address = NULL;
static char *arg_command_line_buffer = NULL;
diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c
index e1b0fd3535..67bcc7a242 100644
--- a/src/bus-proxyd/synthesize.c
+++ b/src/bus-proxyd/synthesize.c
@@ -21,24 +21,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
#include <stddef.h>
-#include "log.h"
#include "util.h"
#include "sd-bus.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "strv.h"
-#include "def.h"
-#include "bus-control.h"
#include "synthesize.h"
-static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
+int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
int r;
assert(b);
diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h
index a55f171cb2..e850350bc5 100644
--- a/src/bus-proxyd/synthesize.h
+++ b/src/bus-proxyd/synthesize.h
@@ -23,6 +23,8 @@
#include "sd-bus.h"
+int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
+
int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...);
int synthetic_reply_method_return_strv(sd_bus_message *call, char **l);
diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c
index 421487e038..d19d0e1b60 100644
--- a/src/bus-proxyd/test-bus-xml-policy.c
+++ b/src/bus-proxyd/test-bus-xml-policy.c
@@ -19,27 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/types.h>
-#include <fcntl.h>
#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <poll.h>
#include <stddef.h>
-#include <getopt.h>
#include "log.h"
#include "util.h"
#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "build.h"
#include "strv.h"
-#include "def.h"
-#include "capability.h"
#include "bus-xml-policy.h"
static int test_policy_load(Policy *p, const char *name) {
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 579e06de5b..c6f5485716 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 3c7ad40605..a390cf3256 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -29,6 +29,7 @@
#include <getopt.h>
#include "path-util.h"
+#include "terminal-util.h"
#include "util.h"
#include "hashmap.h"
#include "cgroup-util.h"
@@ -447,7 +448,7 @@ static int display(Hashmap *a) {
Group *g;
Group **array;
signed path_columns;
- unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 0;
+ unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 3; /* 3 for ellipsize() to work properly */
char buffer[MAX3(21, FORMAT_BYTES_MAX, FORMAT_TIMESPAN_MAX)];
assert(a);
diff --git a/src/console/consoled-display.c b/src/console/consoled-display.c
index a30a2f1022..569c011dc0 100644
--- a/src/console/consoled-display.c
+++ b/src/console/consoled-display.c
@@ -20,7 +20,6 @@
***/
#include <errno.h>
-#include <inttypes.h>
#include <stdlib.h>
#include "consoled.h"
#include "grdev.h"
diff --git a/src/console/consoled-manager.c b/src/console/consoled-manager.c
index 9dd62f04a0..e560dcf524 100644
--- a/src/console/consoled-manager.c
+++ b/src/console/consoled-manager.c
@@ -20,20 +20,18 @@
***/
#include <errno.h>
-#include <libudev.h>
#include <stdlib.h>
-#include <string.h>
-#include "consoled.h"
-#include "grdev.h"
-#include "idev.h"
-#include "log.h"
#include "sd-bus.h"
-#include "sd-daemon.h"
#include "sd-event.h"
#include "sd-login.h"
+#include "log.h"
+#include "signal-util.h"
+#include "util.h"
+#include "consoled.h"
+#include "idev.h"
+#include "grdev.h"
#include "sysview.h"
#include "unifont.h"
-#include "util.h"
int manager_new(Manager **out) {
_cleanup_(manager_freep) Manager *m = NULL;
@@ -228,7 +226,7 @@ static int manager_sysview_session_control(Manager *m, sysview_event *event) {
sysview_session_get_name(session));
session_free(s);
sysview_session_set_userdata(session, NULL);
- return -error;
+ return error;
}
return 0;
diff --git a/src/console/consoled-session.c b/src/console/consoled-session.c
index 927965e02c..264a4d009a 100644
--- a/src/console/consoled-session.c
+++ b/src/console/consoled-session.c
@@ -20,16 +20,12 @@
***/
#include <errno.h>
-#include <inttypes.h>
-#include <libudev.h>
#include <stdlib.h>
#include "consoled.h"
#include "grdev.h"
-#include "hashmap.h"
#include "idev.h"
#include "list.h"
#include "macro.h"
-#include "sd-bus.h"
#include "sd-event.h"
#include "sysview.h"
#include "util.h"
diff --git a/src/console/consoled-terminal.c b/src/console/consoled-terminal.c
index 19d14016ad..03447d1b92 100644
--- a/src/console/consoled-terminal.c
+++ b/src/console/consoled-terminal.c
@@ -20,7 +20,6 @@
***/
#include <errno.h>
-#include <inttypes.h>
#include <stdlib.h>
#include "consoled.h"
#include "list.h"
@@ -99,7 +98,7 @@ Terminal *terminal_free(Terminal *t) {
assert(t->workspace);
if (t->pty) {
- (void)pty_signal(t->pty, SIGHUP);
+ (void) pty_signal(t->pty, SIGHUP);
pty_close(t->pty);
pty_unref(t->pty);
}
diff --git a/src/console/consoled-workspace.c b/src/console/consoled-workspace.c
index 56344ef2cf..5e9e5c7c49 100644
--- a/src/console/consoled-workspace.c
+++ b/src/console/consoled-workspace.c
@@ -20,7 +20,6 @@
***/
#include <errno.h>
-#include <inttypes.h>
#include <stdlib.h>
#include "consoled.h"
#include "grdev.h"
diff --git a/src/console/consoled.c b/src/console/consoled.c
index 6f65dcdcb9..9f69e8983f 100644
--- a/src/console/consoled.c
+++ b/src/console/consoled.c
@@ -21,11 +21,10 @@
#include <errno.h>
#include <stdlib.h>
-#include <string.h>
-#include "consoled.h"
-#include "log.h"
#include "sd-daemon.h"
-#include "util.h"
+#include "log.h"
+#include "signal-util.h"
+#include "consoled.h"
int main(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
diff --git a/src/console/consoled.h b/src/console/consoled.h
index b0db610400..f85c1a0791 100644
--- a/src/console/consoled.h
+++ b/src/console/consoled.h
@@ -21,10 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <inttypes.h>
-#include <libudev.h>
-#include <stdlib.h>
#include "grdev.h"
#include "idev.h"
#include "list.h"
diff --git a/src/core/automount.c b/src/core/automount.c
index 9f6bd84b21..d847dc1629 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -32,8 +32,6 @@
#include "unit.h"
#include "automount.h"
#include "mount.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
#include "unit-name.h"
#include "special.h"
#include "label.h"
@@ -42,6 +40,9 @@
#include "dbus-automount.h"
#include "bus-util.h"
#include "bus-error.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "async.h"
static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
[AUTOMOUNT_DEAD] = UNIT_INACTIVE,
@@ -50,6 +51,22 @@ static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
[AUTOMOUNT_FAILED] = UNIT_FAILED
};
+struct expire_data {
+ int dev_autofs_fd;
+ int ioctl_fd;
+};
+
+static inline void expire_data_free(struct expire_data *data) {
+ if (!data)
+ return;
+
+ safe_close(data->dev_autofs_fd);
+ safe_close(data->ioctl_fd);
+ free(data);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
+
static int open_dev_autofs(Manager *m);
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
@@ -81,13 +98,16 @@ static void repeat_unmount(const char *path) {
}
}
+static int automount_send_ready(Automount *a, Set *tokens, int status);
+
static void unmount_autofs(Automount *a) {
assert(a);
if (a->pipe_fd < 0)
return;
- automount_send_ready(a, -EHOSTDOWN);
+ automount_send_ready(a, a->tokens, -EHOSTDOWN);
+ automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
a->pipe_fd = safe_close(a->pipe_fd);
@@ -112,6 +132,10 @@ static void automount_done(Unit *u) {
set_free(a->tokens);
a->tokens = NULL;
+ set_free(a->expire_tokens);
+ a->expire_tokens = NULL;
+
+ a->expire_event_source = sd_event_source_unref(a->expire_event_source);
}
static int automount_add_mount_links(Automount *a) {
@@ -132,7 +156,7 @@ static int automount_add_default_dependencies(Automount *a) {
assert(a);
- if (UNIT(a)->manager->running_as != SYSTEMD_SYSTEM)
+ if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
return 0;
r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
@@ -143,26 +167,25 @@ static int automount_add_default_dependencies(Automount *a) {
}
static int automount_verify(Automount *a) {
- bool b;
_cleanup_free_ char *e = NULL;
+ int r;
+
assert(a);
if (UNIT(a)->load_state != UNIT_LOADED)
return 0;
if (path_equal(a->where, "/")) {
- log_unit_error(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing.");
+ log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing.");
return -EINVAL;
}
- e = unit_name_from_path(a->where, ".automount");
- if (!e)
- return -ENOMEM;
-
- b = unit_has_name(UNIT(a), e);
+ r = unit_name_from_path(a->where, ".automount", &e);
+ if (r < 0)
+ return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m");
- if (!b) {
- log_unit_error(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
+ if (!unit_has_name(UNIT(a), e)) {
+ log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");
return -EINVAL;
}
@@ -185,9 +208,9 @@ static int automount_load(Unit *u) {
Unit *x;
if (!a->where) {
- a->where = unit_name_to_path(u->id);
- if (!a->where)
- return -ENOMEM;
+ r = unit_name_to_path(u->id, &a->where);
+ if (r < 0)
+ return r;
}
path_kill_slashes(a->where);
@@ -226,11 +249,7 @@ static void automount_set_state(Automount *a, AutomountState state) {
unmount_autofs(a);
if (state != old_state)
- log_unit_debug(UNIT(a)->id,
- "%s changed %s -> %s",
- UNIT(a)->id,
- automount_state_to_string(old_state),
- automount_state_to_string(state));
+ log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));
unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -250,12 +269,13 @@ static int automount_coldplug(Unit *u) {
if (a->deserialized_state == AUTOMOUNT_WAITING ||
a->deserialized_state == AUTOMOUNT_RUNNING) {
-
assert(a->pipe_fd >= 0);
r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u);
if (r < 0)
return r;
+
+ (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
}
automount_set_state(a, a->deserialized_state);
@@ -265,6 +285,7 @@ static int automount_coldplug(Unit *u) {
}
static void automount_dump(Unit *u, FILE *f, const char *prefix) {
+ char time_string[FORMAT_TIMESPAN_MAX];
Automount *a = AUTOMOUNT(u);
assert(a);
@@ -273,11 +294,13 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
"%sAutomount State: %s\n"
"%sResult: %s\n"
"%sWhere: %s\n"
- "%sDirectoryMode: %04o\n",
+ "%sDirectoryMode: %04o\n"
+ "%sTimeoutIdleUSec: %s\n",
prefix, automount_state_to_string(a->state),
prefix, automount_result_to_string(a->result),
prefix, a->where,
- prefix, a->directory_mode);
+ prefix, a->directory_mode,
+ prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
}
static void automount_enter_dead(Automount *a, AutomountResult f) {
@@ -336,7 +359,7 @@ static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
if (param->ioctlfd < 0)
return -EIO;
- fd_cloexec(param->ioctlfd, true);
+ (void) fd_cloexec(param->ioctlfd, true);
return param->ioctlfd;
}
@@ -367,7 +390,7 @@ static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
return 0;
}
-static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
+static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) {
struct autofs_dev_ioctl param;
assert(dev_autofs_fd >= 0);
@@ -375,7 +398,9 @@ static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
init_autofs_dev_ioctl(&param);
param.ioctlfd = ioctl_fd;
- param.timeout.timeout = sec;
+
+ /* Convert to seconds, rounding up. */
+ param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC;
if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
return -errno;
@@ -404,7 +429,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in
return 0;
}
-int automount_send_ready(Automount *a, int status) {
+static int automount_send_ready(Automount *a, Set *tokens, int status) {
_cleanup_close_ int ioctl_fd = -1;
unsigned token;
int r;
@@ -412,7 +437,7 @@ int automount_send_ready(Automount *a, int status) {
assert(a);
assert(status <= 0);
- if (set_isempty(a->tokens))
+ if (set_isempty(tokens))
return 0;
ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
@@ -420,14 +445,14 @@ int automount_send_ready(Automount *a, int status) {
return ioctl_fd;
if (status)
- log_unit_debug_errno(UNIT(a)->id, status, "Sending failure: %m");
+ log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
else
- log_unit_debug(UNIT(a)->id, "Sending success.");
+ log_unit_debug(UNIT(a), "Sending success.");
r = 0;
/* Autofs thankfully does not hand out 0 as a token */
- while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
+ while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
int k;
/* Autofs fun fact II:
@@ -446,6 +471,53 @@ int automount_send_ready(Automount *a, int status) {
return r;
}
+int automount_update_mount(Automount *a, MountState old_state, MountState state) {
+ assert(a);
+
+ switch (state) {
+ case MOUNT_MOUNTED:
+ case MOUNT_REMOUNTING:
+ automount_send_ready(a, a->tokens, 0);
+ break;
+ case MOUNT_DEAD:
+ case MOUNT_UNMOUNTING:
+ case MOUNT_MOUNTING_SIGTERM:
+ case MOUNT_MOUNTING_SIGKILL:
+ case MOUNT_REMOUNTING_SIGTERM:
+ case MOUNT_REMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ case MOUNT_UNMOUNTING_SIGKILL:
+ case MOUNT_FAILED:
+ if (old_state != state)
+ automount_send_ready(a, a->tokens, -ENODEV);
+ break;
+ default:
+ break;
+ }
+
+ switch (state) {
+ case MOUNT_DEAD:
+ automount_send_ready(a, a->expire_tokens, 0);
+ break;
+ case MOUNT_MOUNTING:
+ case MOUNT_MOUNTING_DONE:
+ case MOUNT_MOUNTING_SIGTERM:
+ case MOUNT_MOUNTING_SIGKILL:
+ case MOUNT_REMOUNTING_SIGTERM:
+ case MOUNT_REMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ case MOUNT_UNMOUNTING_SIGKILL:
+ case MOUNT_FAILED:
+ if (old_state != state)
+ automount_send_ready(a, a->expire_tokens, -ENODEV);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static void automount_enter_waiting(Automount *a) {
_cleanup_close_ int ioctl_fd = -1;
int p[2] = { -1, -1 };
@@ -460,8 +532,15 @@ static void automount_enter_waiting(Automount *a) {
assert(a->pipe_fd < 0);
assert(a->where);
- if (a->tokens)
- set_clear(a->tokens);
+ set_clear(a->tokens);
+
+ r = unit_fail_if_symlink(UNIT(a), a->where);
+ if (r < 0)
+ goto fail;
+
+ (void) mkdir_p_label(a->where, 0555);
+
+ unit_warn_if_dir_nonempty(UNIT(a), a->where);
dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
if (dev_autofs_fd < 0) {
@@ -469,11 +548,6 @@ static void automount_enter_waiting(Automount *a) {
goto fail;
}
- /* We knowingly ignore the results of this call */
- mkdir_p_label(a->where, 0555);
-
- warn_if_dir_nonempty(a->meta.id, a->where);
-
if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
r = -errno;
goto fail;
@@ -505,7 +579,7 @@ static void automount_enter_waiting(Automount *a) {
if (r < 0)
goto fail;
- r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300);
+ r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec);
if (r < 0)
goto fail;
@@ -519,6 +593,8 @@ static void automount_enter_waiting(Automount *a) {
if (r < 0)
goto fail;
+ (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
+
a->pipe_fd = p[0];
a->dev_id = st.st_dev;
@@ -532,11 +608,93 @@ fail:
if (mounted)
repeat_unmount(a->where);
- log_unit_error(UNIT(a)->id,
- "Failed to initialize automounter: %s", strerror(-r));
+ log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
+static void *expire_thread(void *p) {
+ struct autofs_dev_ioctl param;
+ _cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p;
+ int r;
+
+ assert(data->dev_autofs_fd >= 0);
+ assert(data->ioctl_fd >= 0);
+
+ init_autofs_dev_ioctl(&param);
+ param.ioctlfd = data->ioctl_fd;
+
+ do {
+ r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, &param);
+ } while (r >= 0);
+
+ if (errno != EAGAIN)
+ log_warning_errno(errno, "Failed to expire automount, ignoring: %m");
+
+ return NULL;
+}
+
+static int automount_start_expire(Automount *a);
+
+static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
+ Automount *a = AUTOMOUNT(userdata);
+ _cleanup_(expire_data_freep) struct expire_data *data = NULL;
+ int r;
+
+ assert(a);
+ assert(source == a->expire_event_source);
+
+ data = new0(struct expire_data, 1);
+ if (!data)
+ return log_oom();
+
+ data->ioctl_fd = -1;
+
+ data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3);
+ if (data->dev_autofs_fd < 0)
+ return log_unit_error_errno(UNIT(a), errno, "Failed to duplicate autofs fd: %m");
+
+ data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
+ if (data->ioctl_fd < 0)
+ return log_unit_error_errno(UNIT(a), data->ioctl_fd, "Couldn't open autofs ioctl fd: %m");
+
+ r = asynchronous_job(expire_thread, data);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(a), r, "Failed to start expire job: %m");
+
+ data = NULL;
+
+ return automount_start_expire(a);
+}
+
+static int automount_start_expire(Automount *a) {
+ int r;
+ usec_t timeout;
+
+ assert(a);
+
+ timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/10, USEC_PER_SEC);
+
+ if (a->expire_event_source) {
+ r = sd_event_source_set_time(a->expire_event_source, timeout);
+ if (r < 0)
+ return r;
+
+ return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
+ }
+
+ r = sd_event_add_time(
+ UNIT(a)->manager->event,
+ &a->expire_event_source,
+ CLOCK_MONOTONIC, timeout, 0,
+ automount_dispatch_expire, a);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(a->expire_event_source, "automount-expire");
+
+ return 0;
+}
+
static void automount_enter_runnning(Automount *a) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
struct stat st;
@@ -547,9 +705,9 @@ static void automount_enter_runnning(Automount *a) {
/* We don't take mount requests anymore if we are supposed to
* shut down anyway */
if (unit_stop_pending(UNIT(a))) {
- log_unit_debug(UNIT(a)->id,
- "Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
- automount_send_ready(a, -EHOSTDOWN);
+ log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
+ automount_send_ready(a, a->tokens, -EHOSTDOWN);
+ automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
return;
}
@@ -557,25 +715,25 @@ static void automount_enter_runnning(Automount *a) {
/* Before we do anything, let's see if somebody is playing games with us? */
if (lstat(a->where, &st) < 0) {
- log_unit_warning(UNIT(a)->id,
- "%s failed to stat automount point: %m", UNIT(a)->id);
+ log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
goto fail;
}
if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
- log_unit_info(UNIT(a)->id,
- "%s's automount point already active?", UNIT(a)->id);
+ log_unit_info(UNIT(a), "Automount point already active?");
else {
r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
JOB_REPLACE, true, &error, NULL);
if (r < 0) {
- log_unit_warning(UNIT(a)->id,
- "%s failed to queue mount startup job: %s",
- UNIT(a)->id, bus_error_message(&error, r));
+ log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
goto fail;
}
}
+ r = automount_start_expire(a);
+ if (r < 0)
+ log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
+
automount_set_state(a, AUTOMOUNT_RUNNING);
return;
@@ -589,10 +747,8 @@ static int automount_start(Unit *u) {
assert(a);
assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
- if (path_is_mount_point(a->where, false)) {
- log_unit_error(u->id,
- "Path %s is already a mount point, refusing start for %s",
- a->where, u->id);
+ if (path_is_mount_point(a->where, 0) > 0) {
+ log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
return -EEXIST;
}
@@ -629,6 +785,8 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
SET_FOREACH(p, a->tokens, i)
unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
+ SET_FOREACH(p, a->expire_tokens, i)
+ unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
if (a->pipe_fd >= 0) {
int copy;
@@ -655,7 +813,7 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
state = automount_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
a->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -663,7 +821,7 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
f = automount_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != AUTOMOUNT_SUCCESS)
a->result = f;
@@ -671,34 +829,52 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
unsigned d;
if (safe_atou(value, &d) < 0)
- log_unit_debug(u->id, "Failed to parse dev-id value %s", value);
+ log_unit_debug(u, "Failed to parse dev-id value: %s", value);
else
a->dev_id = (unsigned) d;
} else if (streq(key, "token")) {
unsigned token;
if (safe_atou(value, &token) < 0)
- log_unit_debug(u->id, "Failed to parse token value %s", value);
+ log_unit_debug(u, "Failed to parse token value: %s", value);
else {
- if (!a->tokens)
- if (!(a->tokens = set_new(NULL)))
- return -ENOMEM;
+ r = set_ensure_allocated(&a->tokens, NULL);
+ if (r < 0) {
+ log_oom();
+ return 0;
+ }
r = set_put(a->tokens, UINT_TO_PTR(token));
if (r < 0)
- return r;
+ log_unit_error_errno(u, r, "Failed to add token to set: %m");
+ }
+ } else if (streq(key, "expire-token")) {
+ unsigned token;
+
+ if (safe_atou(value, &token) < 0)
+ log_unit_debug(u, "Failed to parse token value: %s", value);
+ else {
+ r = set_ensure_allocated(&a->expire_tokens, NULL);
+ if (r < 0) {
+ log_oom();
+ return 0;
+ }
+
+ r = set_put(a->expire_tokens, UINT_TO_PTR(token));
+ if (r < 0)
+ log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
}
} else if (streq(key, "pipe-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse pipe-fd value %s", value);
+ log_unit_debug(u, "Failed to parse pipe-fd value: %s", value);
else {
safe_close(a->pipe_fd);
a->pipe_fd = fdset_remove(fds, fd);
}
} else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -725,25 +901,22 @@ static bool automount_check_gc(Unit *u) {
}
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
union autofs_v5_packet_union packet;
Automount *a = AUTOMOUNT(userdata);
- ssize_t l;
int r;
assert(a);
assert(fd == a->pipe_fd);
if (events != EPOLLIN) {
- log_unit_error(UNIT(a)->id, "Got invalid poll event on pipe.");
+ log_unit_error(UNIT(a), "Got invalid poll event %"PRIu32" on pipe (fd=%d)", events, fd);
goto fail;
}
- l = loop_read(a->pipe_fd, &packet, sizeof(packet), true);
- if (l != sizeof(packet)) {
- if (l < 0)
- log_unit_error_errno(UNIT(a)->id, l, "Invalid read from pipe: %m");
- else
- log_unit_error(UNIT(a)->id, "Invalid read from pipe: short read");
+ r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(a), r, "Invalid read from pipe: %m");
goto fail;
}
@@ -755,29 +928,50 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
_cleanup_free_ char *p = NULL;
get_process_comm(packet.v5_packet.pid, &p);
- log_unit_info(UNIT(a)->id,
- "Got automount request for %s, triggered by %"PRIu32" (%s)",
- a->where, packet.v5_packet.pid, strna(p));
+ log_unit_info(UNIT(a), "Got automount request for %s, triggered by %"PRIu32" (%s)", a->where, packet.v5_packet.pid, strna(p));
} else
- log_unit_debug(UNIT(a)->id, "Got direct mount request on %s", a->where);
+ log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);
r = set_ensure_allocated(&a->tokens, NULL);
if (r < 0) {
- log_unit_error(UNIT(a)->id, "Failed to allocate token set.");
+ log_unit_error(UNIT(a), "Failed to allocate token set.");
goto fail;
}
r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
if (r < 0) {
- log_unit_error_errno(UNIT(a)->id, r, "Failed to remember token: %m");
+ log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
goto fail;
}
automount_enter_runnning(a);
break;
+ case autofs_ptype_expire_direct:
+ log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
+
+ (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
+
+ r = set_ensure_allocated(&a->expire_tokens, NULL);
+ if (r < 0) {
+ log_unit_error(UNIT(a), "Failed to allocate token set.");
+ goto fail;
+ }
+
+ r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
+ if (r < 0) {
+ log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
+ goto fail;
+ }
+ r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
+ if (r < 0) {
+ log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
+ goto fail;
+ }
+ break;
+
default:
- log_unit_error(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type);
+ log_unit_error(UNIT(a), "Received unknown automount request %i", packet.hdr.type);
break;
}
@@ -805,11 +999,9 @@ static void automount_reset_failed(Unit *u) {
a->result = AUTOMOUNT_SUCCESS;
}
-static bool automount_supported(Manager *m) {
+static bool automount_supported(void) {
static int supported = -1;
- assert(m);
-
if (supported < 0)
supported = access("/dev/autofs", F_OK) >= 0;
diff --git a/src/core/automount.h b/src/core/automount.h
index 60f5522389..2a50fef68d 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -47,6 +47,7 @@ struct Automount {
AutomountState state, deserialized_state;
char *where;
+ usec_t timeout_idle_usec;
int pipe_fd;
sd_event_source *pipe_event_source;
@@ -54,13 +55,16 @@ struct Automount {
dev_t dev_id;
Set *tokens;
+ Set *expire_tokens;
+
+ sd_event_source *expire_event_source;
AutomountResult result;
};
extern const UnitVTable automount_vtable;
-int automount_send_ready(Automount *a, int status);
+int automount_update_mount(Automount *a, MountState old_state, MountState state);
const char* automount_state_to_string(AutomountState i) _const_;
AutomountState automount_state_from_string(const char *s) _pure_;
diff --git a/src/core/bus-policy.c b/src/core/bus-policy.c
index 710283dcd1..a6a8fcd4d3 100644
--- a/src/core/bus-policy.c
+++ b/src/core/bus-policy.c
@@ -150,8 +150,11 @@ int bus_kernel_make_starter(
hello->attach_flags_send = _KDBUS_ATTACH_ANY;
hello->attach_flags_recv = _KDBUS_ATTACH_ANY;
- if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0)
+ if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
+ if (errno == ENOTTY) /* Major API change */
+ return -ESOCKTNOSUPPORT;
return -errno;
+ }
/* not interested in any output values */
cmd_free.offset = hello->offset;
@@ -160,7 +163,7 @@ int bus_kernel_make_starter(
/* The higher 32bit of the bus_flags fields are considered
* 'incompatible flags'. Refuse them all for now. */
if (hello->bus_flags > 0xFFFFFFFFULL)
- return -ENOTSUP;
+ return -ESOCKTNOSUPPORT;
return fd;
}
diff --git a/src/core/busname.c b/src/core/busname.c
index 1d77292f9b..11f3b98009 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -22,12 +22,14 @@
#include <sys/mman.h>
#include "special.h"
+#include "formats-util.h"
+#include "signal-util.h"
#include "bus-kernel.h"
#include "bus-internal.h"
#include "bus-util.h"
-#include "service.h"
#include "kdbus.h"
#include "bus-policy.h"
+#include "service.h"
#include "dbus-busname.h"
#include "busname.h"
@@ -123,12 +125,18 @@ static int busname_arm_timer(BusName *n) {
return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
}
- return sd_event_add_time(
+ r = sd_event_add_time(
UNIT(n)->manager->event,
&n->timer_event_source,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + n->timeout_usec, 0,
busname_dispatch_timer, n);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(n->timer_event_source, "busname-timer");
+
+ return 0;
}
static int busname_add_default_default_dependencies(BusName *n) {
@@ -140,7 +148,7 @@ static int busname_add_default_default_dependencies(BusName *n) {
if (r < 0)
return r;
- if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) {
+ if (UNIT(n)->manager->running_as == MANAGER_SYSTEM) {
r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -156,9 +164,9 @@ static int busname_add_extras(BusName *n) {
assert(n);
if (!n->name) {
- n->name = unit_name_to_prefix(u->id);
- if (!n->name)
- return -ENOMEM;
+ r = unit_name_to_prefix(u->id, &n->name);
+ if (r < 0)
+ return r;
}
if (!u->description) {
@@ -201,13 +209,13 @@ static int busname_verify(BusName *n) {
return 0;
if (!service_name_is_valid(n->name)) {
- log_unit_error(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
+ log_unit_error(UNIT(n), "Name= setting is not a valid service name Refusing.");
return -EINVAL;
}
e = strjoina(n->name, ".busname");
if (!unit_has_name(UNIT(n), e)) {
- log_unit_error(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
+ log_unit_error(UNIT(n), "Name= setting doesn't match unit name. Refusing.");
return -EINVAL;
}
@@ -269,7 +277,7 @@ static void busname_unwatch_fd(BusName *n) {
r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_OFF);
if (r < 0)
- log_unit_debug(UNIT(n)->id, "Failed to disable event source.");
+ log_unit_debug_errno(UNIT(n), r, "Failed to disable event source: %m");
}
static int busname_watch_fd(BusName *n) {
@@ -280,17 +288,24 @@ static int busname_watch_fd(BusName *n) {
if (n->starter_fd < 0)
return 0;
- if (n->starter_event_source)
+ if (n->starter_event_source) {
r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_ON);
- else
+ if (r < 0)
+ goto fail;
+ } else {
r = sd_event_add_io(UNIT(n)->manager->event, &n->starter_event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "Failed to watch starter fd: %m");
- busname_unwatch_fd(n);
- return r;
+ if (r < 0)
+ goto fail;
+
+ (void) sd_event_source_set_description(n->starter_event_source, "busname-starter");
}
return 0;
+
+fail:
+ log_unit_warning_errno(UNIT(n), r, "Failed to watch starter fd: %m");
+ busname_unwatch_fd(n);
+ return r;
}
static int busname_open_fd(BusName *n) {
@@ -302,10 +317,10 @@ static int busname_open_fd(BusName *n) {
if (n->starter_fd >= 0)
return 0;
- mode = UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user";
+ mode = UNIT(n)->manager->running_as == MANAGER_SYSTEM ? "system" : "user";
n->starter_fd = bus_kernel_open_bus_fd(mode, &path);
if (n->starter_fd < 0)
- return log_unit_warning_errno(UNIT(n)->id, n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");
+ return log_unit_warning_errno(UNIT(n), n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");
return 0;
}
@@ -329,8 +344,7 @@ static void busname_set_state(BusName *n, BusNameState state) {
busname_close_fd(n);
if (state != old_state)
- log_unit_debug(UNIT(n)->id, "%s changed %s -> %s",
- UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
+ log_unit_debug(UNIT(n), "Changed %s -> %s", busname_state_to_string(old_state), busname_state_to_string(state));
unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -452,14 +466,14 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
n->control_pid,
false);
if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to kill control process: %m", UNIT(n)->id);
+ log_unit_warning_errno(UNIT(n), r, "Failed to kill control process: %m");
goto fail;
}
if (r > 0) {
r = busname_arm_timer(n);
if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to arm timer: %m", UNIT(n)->id);
+ log_unit_warning_errno(UNIT(n), r, "Failed to arm timer: %m");
goto fail;
}
@@ -483,7 +497,7 @@ static void busname_enter_listening(BusName *n) {
if (n->activating) {
r = busname_watch_fd(n);
if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to watch names: %m", UNIT(n)->id);
+ log_unit_warning_errno(UNIT(n), r, "Failed to watch names: %m");
goto fail;
}
@@ -514,7 +528,7 @@ static void busname_enter_making(BusName *n) {
r = busname_make_starter(n, &n->control_pid);
if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to fork 'making' task: %m", UNIT(n)->id);
+ log_unit_warning_errno(UNIT(n), r, "Failed to fork 'making' task: %m");
goto fail;
}
@@ -525,7 +539,7 @@ static void busname_enter_making(BusName *n) {
r = bus_kernel_make_starter(n->starter_fd, n->name, n->activating, n->accept_fd, NULL, n->policy_world);
if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to make starter: %m", UNIT(n)->id);
+ log_unit_warning_errno(UNIT(n), r, "Failed to make starter: %m");
goto fail;
}
@@ -550,11 +564,11 @@ static void busname_enter_running(BusName *n) {
if (!n->activating)
return;
- /* We don't take conenctions anymore if we are supposed to
+ /* We don't take connections anymore if we are supposed to
* shut down anyway */
if (unit_stop_pending(UNIT(n))) {
- log_unit_debug(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
+ log_unit_debug(UNIT(n), "Suppressing activation request since unit stop is scheduled.");
/* Flush all queued activation reqeuest by closing and reopening the connection */
bus_kernel_drop_one(n->starter_fd);
@@ -581,7 +595,7 @@ static void busname_enter_running(BusName *n) {
return;
fail:
- log_unit_warning(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
+ log_unit_warning(UNIT(n), "Failed to queue service startup job: %s", bus_error_message(&error, r));
busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
}
@@ -605,7 +619,7 @@ static int busname_start(Unit *u) {
service = SERVICE(UNIT_DEREF(n->service));
if (UNIT(service)->load_state != UNIT_LOADED) {
- log_unit_error(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
+ log_unit_error(u, "Bus service %s not loaded, refusing.", UNIT(service)->id);
return -ENOENT;
}
}
@@ -679,7 +693,7 @@ static int busname_deserialize_item(Unit *u, const char *key, const char *value,
state = busname_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
n->deserialized_state = state;
@@ -688,7 +702,7 @@ static int busname_deserialize_item(Unit *u, const char *key, const char *value,
f = busname_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != BUSNAME_SUCCESS)
n->result = f;
@@ -696,20 +710,20 @@ static int busname_deserialize_item(Unit *u, const char *key, const char *value,
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u, "Failed to parse control-pid value: %s", value);
else
n->control_pid = pid;
} else if (streq(key, "starter-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse starter fd value %s", value);
+ log_unit_debug(u, "Failed to parse starter fd value: %s", value);
else {
safe_close(n->starter_fd);
n->starter_fd = fdset_remove(fds, fd);
}
} else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -759,8 +773,7 @@ static int busname_peek_message(BusName *n) {
if (errno == EINTR || errno == EAGAIN)
return 0;
- log_unit_error(UNIT(n)->id, "%s: Failed to query activation message: %m", UNIT(n)->id);
- return -errno;
+ return log_unit_error_errno(UNIT(n), errno, "Failed to query activation message: %m");
}
/* We map as late as possible, and unmap imemdiately after
@@ -776,8 +789,7 @@ static int busname_peek_message(BusName *n) {
p = mmap(NULL, sz, PROT_READ, MAP_SHARED, n->starter_fd, start);
if (p == MAP_FAILED) {
- log_unit_error(UNIT(n)->id, "%s: Failed to map activation message: %m", UNIT(n)->id);
- r = -errno;
+ r = log_unit_error_errno(UNIT(n), errno, "Failed to map activation message: %m");
goto finish;
}
@@ -796,7 +808,7 @@ static int busname_peek_message(BusName *n) {
}
if (pid > 0)
- log_unit_debug(UNIT(n)->id, "%s: Activation triggered by process " PID_FMT " (%s)", UNIT(n)->id, pid, strna(comm));
+ log_unit_debug(UNIT(n), "Activation triggered by process " PID_FMT " (%s)", pid, strna(comm));
r = 0;
@@ -806,7 +818,7 @@ finish:
cmd_free.offset = cmd_recv.msg.offset;
if (ioctl(n->starter_fd, KDBUS_CMD_FREE, &cmd_free) < 0)
- log_unit_warning(UNIT(n)->id, "Failed to free peeked message, ignoring: %m");
+ log_unit_warning(UNIT(n), "Failed to free peeked message, ignoring: %m");
return r;
}
@@ -820,11 +832,10 @@ static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents
if (n->state != BUSNAME_LISTENING)
return 0;
- log_unit_debug(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
+ log_unit_debug(UNIT(n), "Activation request");
if (revents != EPOLLIN) {
- log_unit_error(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
- UNIT(n)->id, revents);
+ log_unit_error(UNIT(n), "Got unexpected poll event (0x%x) on starter fd.", revents);
goto fail;
}
@@ -860,10 +871,8 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
assert_not_reached("Unknown sigchld code");
- log_unit_full(u->id,
- f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s control process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
+ log_unit_full(u, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
+ "Control process exited, code=%s status=%i", sigchld_code_to_string(code), status);
if (f != BUSNAME_SUCCESS)
n->result = f;
@@ -899,17 +908,17 @@ static int busname_dispatch_timer(sd_event_source *source, usec_t usec, void *us
switch (n->state) {
case BUSNAME_MAKING:
- log_unit_warning(UNIT(n)->id, "%s making timed out. Terminating.", UNIT(n)->id);
+ log_unit_warning(UNIT(n), "Making timed out. Terminating.");
busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_TIMEOUT);
break;
case BUSNAME_SIGTERM:
- log_unit_warning(UNIT(n)->id, "%s stopping timed out. Killing.", UNIT(n)->id);
+ log_unit_warning(UNIT(n), "Stopping timed out. Killing.");
busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_FAILURE_TIMEOUT);
break;
case BUSNAME_SIGKILL:
- log_unit_warning(UNIT(n)->id, "%s still around after SIGKILL. Ignoring.", UNIT(n)->id);
+ log_unit_warning(UNIT(n), "Processes still around after SIGKILL. Ignoring.");
busname_enter_dead(n, BUSNAME_FAILURE_TIMEOUT);
break;
@@ -974,12 +983,11 @@ static int busname_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
-static bool busname_supported(Manager *m) {
+static bool busname_supported(void) {
static int supported = -1;
- assert(m);
if (supported < 0)
- supported = access("/sys/fs/kdbus", F_OK) >= 0;
+ supported = is_kdbus_available();
return supported;
}
@@ -1018,6 +1026,9 @@ const UnitVTable busname_vtable = {
"Install\0",
.private_section = "BusName",
+ .no_alias = true,
+ .no_instances = true,
+
.init = busname_init,
.done = busname_done,
.load = busname_load,
diff --git a/src/core/busname.h b/src/core/busname.h
index 775822d8de..69528a2aef 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -24,7 +24,6 @@
typedef struct BusName BusName;
typedef struct BusNamePolicy BusNamePolicy;
-#include "unit.h"
typedef enum BusNameState {
BUSNAME_DEAD,
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 10fdcc9984..6474e08bd2 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <fnmatch.h>
+#include "process-util.h"
#include "path-util.h"
#include "special.h"
#include "cgroup-util.h"
@@ -907,7 +908,7 @@ int manager_setup_cgroup(Manager *m) {
/* LEGACY: Already in /system.slice? If so, let's cut this
* off. This is to support live upgrades from older systemd
* versions where PID 1 was moved there. */
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
char *e;
e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
@@ -932,7 +933,7 @@ int manager_setup_cgroup(Manager *m) {
if (!m->test_run) {
/* 3. Install agent */
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
if (r < 0)
log_warning_errno(r, "Failed to install release agent, ignoring: %m");
@@ -1029,16 +1030,100 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
assert(cgroup);
u = manager_get_unit_by_cgroup(m, cgroup);
- if (u) {
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
- if (r > 0) {
- if (UNIT_VTABLE(u)->notify_cgroup_empty)
- UNIT_VTABLE(u)->notify_cgroup_empty(u);
+ if (!u)
+ return 0;
- unit_add_to_gc_queue(u);
- }
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
+ if (r <= 0)
+ return r;
+
+ if (UNIT_VTABLE(u)->notify_cgroup_empty)
+ UNIT_VTABLE(u)->notify_cgroup_empty(u);
+
+ unit_add_to_gc_queue(u);
+ return 0;
+}
+
+int unit_get_memory_current(Unit *u, uint64_t *ret) {
+ _cleanup_free_ char *v = NULL;
+ int r;
+
+ assert(u);
+ assert(ret);
+
+ if (!u->cgroup_path)
+ return -ENODATA;
+
+ if ((u->cgroup_realized_mask & CGROUP_MEMORY) == 0)
+ return -ENODATA;
+
+ r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+
+ return safe_atou64(v, ret);
+}
+
+static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
+ _cleanup_free_ char *v = NULL;
+ uint64_t ns;
+ int r;
+
+ assert(u);
+ assert(ret);
+
+ if (!u->cgroup_path)
+ return -ENODATA;
+
+ if ((u->cgroup_realized_mask & CGROUP_CPUACCT) == 0)
+ return -ENODATA;
+
+ r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+
+ r = safe_atou64(v, &ns);
+ if (r < 0)
+ return r;
+
+ *ret = ns;
+ return 0;
+}
+
+int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
+ nsec_t ns;
+ int r;
+
+ r = unit_get_cpu_usage_raw(u, &ns);
+ if (r < 0)
+ return r;
+
+ if (ns > u->cpuacct_usage_base)
+ ns -= u->cpuacct_usage_base;
+ else
+ ns = 0;
+
+ *ret = ns;
+ return 0;
+}
+
+int unit_reset_cpu_usage(Unit *u) {
+ nsec_t ns;
+ int r;
+
+ assert(u);
+
+ r = unit_get_cpu_usage_raw(u, &ns);
+ if (r < 0) {
+ u->cpuacct_usage_base = 0;
+ return r;
}
+ u->cpuacct_usage_base = ns;
return 0;
}
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 8fa851de32..869ddae8c4 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -91,7 +91,6 @@ struct CGroupContext {
};
#include "unit.h"
-#include "manager.h"
#include "cgroup-util.h"
void cgroup_context_init(CGroupContext *c);
@@ -127,5 +126,9 @@ pid_t unit_search_main_pid(Unit *u);
int manager_notify_cgroup_empty(Manager *m, const char *group);
+int unit_get_memory_current(Unit *u, uint64_t *ret);
+int unit_get_cpu_usage(Unit *u, nsec_t *ret);
+int unit_reset_cpu_usage(Unit *u);
+
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
index b2a510ad09..5162ce34cb 100644
--- a/src/core/dbus-automount.c
+++ b/src/core/dbus-automount.c
@@ -19,9 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
#include "automount.h"
-#include "dbus-unit.h"
#include "dbus-automount.h"
#include "bus-util.h"
@@ -32,5 +30,6 @@ const sd_bus_vtable bus_automount_vtable[] = {
SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
index 1bec953788..a2b124d756 100644
--- a/src/core/dbus-automount.h
+++ b/src/core/dbus-automount.h
@@ -21,6 +21,5 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
extern const sd_bus_vtable bus_automount_vtable[];
diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c
index 28f192403b..b1ceb05b1a 100644
--- a/src/core/dbus-busname.c
+++ b/src/core/dbus-busname.c
@@ -21,7 +21,6 @@
#include "unit.h"
#include "busname.h"
-#include "dbus-unit.h"
#include "dbus-busname.h"
#include "bus-util.h"
diff --git a/src/core/dbus-busname.h b/src/core/dbus-busname.h
index b5eed37d58..ea55b6c8c9 100644
--- a/src/core/dbus-busname.h
+++ b/src/core/dbus-busname.h
@@ -21,7 +21,5 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
-#include "unit.h"
extern const sd_bus_vtable bus_busname_vtable[];
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
index f556536f33..cb156fd37c 100644
--- a/src/core/dbus-device.c
+++ b/src/core/dbus-device.c
@@ -21,7 +21,6 @@
#include "unit.h"
#include "device.h"
-#include "dbus-unit.h"
#include "dbus-device.h"
const sd_bus_vtable bus_device_vtable[] = {
diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h
index 4aff226ab2..10e945e402 100644
--- a/src/core/dbus-device.h
+++ b/src/core/dbus-device.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
#include "unit.h"
extern const sd_bus_vtable bus_device_vtable[];
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 8b5ea2566d..cd6b909426 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -29,22 +29,6 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
-static int verify_sys_admin_or_owner_sync(sd_bus_message *message, Job *j, sd_bus_error *error) {
- int r;
-
- if (sd_bus_track_contains(j->clients, sd_bus_message_get_sender(message)))
- return 0; /* One of the job owners is calling us */
-
- r = sd_bus_query_sender_privilege(message, CAP_SYS_ADMIN);
- if (r < 0)
- return r;
- if (r == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Access denied to perform action");
-
- /* Root has called us */
- return 0;
-}
-
static int property_get_unit(
sd_bus *bus,
const char *path,
@@ -68,22 +52,28 @@ static int property_get_unit(
return sd_bus_message_append(reply, "(so)", j->unit->id, p);
}
-int bus_job_method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Job *j = userdata;
int r;
- assert(bus);
assert(message);
assert(j);
- r = verify_sys_admin_or_owner_sync(message, j, error);
- if (r < 0)
- return r;
-
r = mac_selinux_unit_access_check(j->unit, message, "stop", error);
if (r < 0)
return r;
+ /* Access is granted to the job owner */
+ if (!sd_bus_track_contains(j->clients, sd_bus_message_get_sender(message))) {
+
+ /* And for everybody else consult PolicyKit */
+ r = bus_verify_manage_units_async(j->unit->manager, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+ }
+
job_finish_and_invalidate(j, JOB_CANCELED, true);
return sd_bus_reply_method_return(message, NULL);
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
index 6c2fc0789c..fb5f1b513e 100644
--- a/src/core/dbus-job.h
+++ b/src/core/dbus-job.h
@@ -26,7 +26,7 @@
extern const sd_bus_vtable bus_job_vtable[];
-int bus_job_method_cancel(sd_bus *bus, sd_bus_message *message, void *job, sd_bus_error *error);
+int bus_job_method_cancel(sd_bus_message *message, void *job, sd_bus_error *error);
void bus_job_send_change_signal(Job *j);
void bus_job_send_removed_signal(Job *j);
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index fb29e147cb..3b8116281c 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -19,9 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "signal-util.h"
+#include "bus-util.h"
+
#include "kill.h"
#include "dbus-kill.h"
-#include "bus-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 8ba665dc3d..d8b39bdf5f 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -40,6 +40,7 @@
#include "dbus-snapshot.h"
#include "dbus-execute.h"
#include "bus-common-errors.h"
+#include "formats-util.h"
static int property_get_version(
sd_bus *bus,
@@ -342,14 +343,13 @@ static int property_set_runtime_watchdog(
return watchdog_set_timeout(t);
}
-static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -359,9 +359,26 @@ static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
+ if (isempty(name)) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ pid_t pid;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_pid(creds, &pid);
+ if (r < 0)
+ return r;
+
+ u = manager_get_unit_by_pid(m, pid);
+ if (!u)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
+ } else {
+ u = manager_get_unit(m, name);
+ if (!u)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
+ }
r = mac_selinux_unit_access_check(u, message, "status", error);
if (r < 0)
@@ -374,14 +391,13 @@ static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata,
return sd_bus_reply_method_return(message, "o", path);
}
-static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
pid_t pid;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -392,6 +408,8 @@ static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *us
r = sd_bus_message_read(message, "u", &pid);
if (r < 0)
return r;
+ if (pid < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pid);
if (pid == 0) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
@@ -420,14 +438,13 @@ static int method_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *us
return sd_bus_reply_method_return(message, "o", path);
}
-static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -437,9 +454,26 @@ static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata
if (r < 0)
return r;
- r = manager_load_unit(m, name, NULL, error, &u);
- if (r < 0)
- return r;
+ if (isempty(name)) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ pid_t pid;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_pid(creds, &pid);
+ if (r < 0)
+ return r;
+
+ u = manager_get_unit_by_pid(m, pid);
+ if (!u)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
+ } else {
+ r = manager_load_unit(m, name, NULL, error, &u);
+ if (r < 0)
+ return r;
+ }
r = mac_selinux_unit_access_check(u, message, "status", error);
if (r < 0)
@@ -452,21 +486,14 @@ static int method_load_unit(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, "o", path);
}
-static int method_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
+static int method_start_unit_generic(sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -475,53 +502,46 @@ static int method_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manag
if (r < 0)
return r;
- return bus_unit_method_start_generic(bus, message, u, job_type, reload_if_possible, error);
+ return bus_unit_method_start_generic(message, u, job_type, reload_if_possible, error);
}
-static int method_start_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_START, false, error);
+static int method_start_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_START, false, error);
}
-static int method_stop_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_STOP, false, error);
+static int method_stop_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_STOP, false, error);
}
-static int method_reload_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_RELOAD, false, error);
+static int method_reload_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_RELOAD, false, error);
}
-static int method_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_RESTART, false, error);
+static int method_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_RESTART, false, error);
}
-static int method_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
+static int method_try_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, false, error);
}
-static int method_reload_or_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_RESTART, true, error);
+static int method_reload_or_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_RESTART, true, error);
}
-static int method_reload_or_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
+static int method_reload_or_try_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
}
-static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *old_name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read(message, "s", &old_name);
if (r < 0)
return r;
@@ -530,26 +550,18 @@ static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void
if (!u || !u->job || u->job->type != JOB_START)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
- return method_start_unit_generic(bus, message, m, JOB_START, false, error);
+ return method_start_unit_generic(message, m, JOB_START, false, error);
}
-static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- /* Like bus_verify_manage_unit_async(), but uses CAP_SYS_KILL */
- r = bus_verify_manage_unit_async_for_kill(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -558,25 +570,18 @@ static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_unit_method_kill(bus, message, u, error);
+ return bus_unit_method_kill(message, u, error);
}
-static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -585,25 +590,18 @@ static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_unit_method_reset_failed(bus, message, u, error);
+ return bus_unit_method_reset_failed(message, u, error);
}
-static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_unit_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -612,7 +610,7 @@ static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void
if (!u)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_unit_method_set_properties(bus, message, u, error);
+ return bus_unit_method_set_properties(message, u, error);
}
static int transient_unit_from_message(
@@ -670,9 +668,6 @@ static int transient_aux_units_from_message(
return r;
while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) {
- if (r <= 0)
- return r;
-
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -701,7 +696,7 @@ static int transient_aux_units_from_message(
return 0;
}
-static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_start_transient_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name, *smode;
Manager *m = userdata;
JobMode mode;
@@ -709,15 +704,12 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_async(m, message, error);
+ r = mac_selinux_access_check(message, "start", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = sd_bus_message_read(message, "ss", &name, &smode);
if (r < 0)
@@ -734,9 +726,11 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi
if (mode < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
- r = mac_selinux_access_check(message, "start", error);
+ r = bus_verify_manage_units_async(m, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = transient_unit_from_message(m, message, name, &u, error);
if (r < 0)
@@ -754,17 +748,16 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi
manager_dispatch_load_queue(m);
/* Finally, start it */
- return bus_unit_queue_job(bus, message, u, JOB_START, mode, false, error);
+ return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
}
-static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
uint32_t id;
Job *j;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -789,13 +782,12 @@ static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata,
return sd_bus_reply_method_return(message, "o", path);
}
-static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_cancel_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
uint32_t id;
Job *j;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -807,31 +799,35 @@ static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdat
if (!j)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
- return bus_job_method_cancel(bus, message, j, error);
+ return bus_job_method_cancel(message, j, error);
}
-static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_clear_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
- r = mac_selinux_access_check(message, "reboot", error);
+ r = mac_selinux_access_check(message, "reload", error);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_manage_units_async(m, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
manager_clear_jobs(m);
return sd_bus_reply_method_return(message, NULL);
}
-static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -839,12 +835,18 @@ static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userd
if (r < 0)
return r;
+ r = bus_verify_manage_units_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
manager_reset_failed(m);
return sd_bus_reply_method_return(message, NULL);
}
-static int list_units_filtered(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) {
+static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
const char *k;
@@ -852,7 +854,6 @@ static int list_units_filtered(sd_bus *bus, sd_bus_message *message, void *userd
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -915,14 +916,14 @@ static int list_units_filtered(sd_bus *bus, sd_bus_message *message, void *userd
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return list_units_filtered(bus, message, userdata, error, NULL);
+static int method_list_units(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return list_units_filtered(message, userdata, error, NULL);
}
-static int method_list_units_filtered(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **states = NULL;
int r;
@@ -930,17 +931,16 @@ static int method_list_units_filtered(sd_bus *bus, sd_bus_message *message, void
if (r < 0)
return r;
- return list_units_filtered(bus, message, userdata, error, states);
+ return list_units_filtered(message, userdata, error, states);
}
-static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
Iterator i;
Job *j;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -985,14 +985,13 @@ static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_subscribe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1002,13 +1001,13 @@ static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata
if (r < 0)
return r;
- if (bus == m->api_bus) {
+ if (sd_bus_message_get_bus(message) == m->api_bus) {
/* Note that direct bus connection subscribe by
* default, we only track peers on the API bus here */
if (!m->subscribed) {
- r = sd_bus_track_new(bus, &m->subscribed, NULL, NULL);
+ r = sd_bus_track_new(sd_bus_message_get_bus(message), &m->subscribed, NULL, NULL);
if (r < 0)
return r;
}
@@ -1023,11 +1022,10 @@ static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, NULL);
}
-static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_unsubscribe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1037,7 +1035,7 @@ static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userda
if (r < 0)
return r;
- if (bus == m->api_bus) {
+ if (sd_bus_message_get_bus(message) == m->api_bus) {
r = sd_bus_track_remove_sender(m->subscribed, message);
if (r < 0)
return r;
@@ -1048,14 +1046,13 @@ static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userda
return sd_bus_reply_method_return(message, NULL);
}
-static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *dump = NULL;
_cleanup_fclose_ FILE *f = NULL;
Manager *m = userdata;
size_t size;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1080,7 +1077,7 @@ static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
return sd_bus_reply_method_return(message, "s", dump);
}
-static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_create_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
const char *name;
@@ -1088,7 +1085,6 @@ static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *us
Snapshot *s = NULL;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1103,6 +1099,12 @@ static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *us
if (isempty(name))
name = NULL;
+ r = bus_verify_manage_units_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
r = snapshot_create(m, name, cleanup, error, &s);
if (r < 0)
return r;
@@ -1114,20 +1116,15 @@ static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *us
return sd_bus_reply_method_return(message, "o", path);
}
-static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_remove_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
- r = mac_selinux_access_check(message, "stop", error);
- if (r < 0)
- return r;
-
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -1139,26 +1136,25 @@ static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *us
if (u->type != UNIT_SNAPSHOT)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
- return bus_snapshot_method_remove(bus, message, u, error);
+ return bus_snapshot_method_remove(message, u, error);
}
-static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_reload_daemon_async(m, message, error);
+ r = mac_selinux_access_check(message, "reload", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = mac_selinux_access_check(message, "reload", error);
+ r = bus_verify_reload_daemon_async(m, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
/* Instead of sending the reply back right away, we just
* remember that we need to and then send it after the reload
@@ -1170,29 +1166,27 @@ static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- m->queued_message_bus = sd_bus_ref(bus);
m->exit_code = MANAGER_RELOAD;
return 1;
}
-static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_reload_daemon_async(m, message, error);
+ r = mac_selinux_access_check(message, "reload", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = mac_selinux_access_check(message, "reload", error);
+ r = bus_verify_reload_daemon_async(m, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
/* We don't send a reply back here, the client should
* just wait for us disconnecting. */
@@ -1201,11 +1195,10 @@ static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata
return 1;
}
-static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_exit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1213,7 +1206,7 @@ static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
if (r < 0)
return r;
- if (m->running_as == SYSTEMD_SYSTEM)
+ if (m->running_as == MANAGER_SYSTEM)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
m->exit_code = MANAGER_EXIT;
@@ -1221,11 +1214,10 @@ static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
return sd_bus_reply_method_return(message, NULL);
}
-static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1233,7 +1225,7 @@ static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
m->exit_code = MANAGER_REBOOT;
@@ -1241,12 +1233,10 @@ static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, s
return sd_bus_reply_method_return(message, NULL);
}
-
-static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1254,7 +1244,7 @@ static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
m->exit_code = MANAGER_POWEROFF;
@@ -1262,11 +1252,10 @@ static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata,
return sd_bus_reply_method_return(message, NULL);
}
-static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1274,7 +1263,7 @@ static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
if (r < 0)
return r;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
m->exit_code = MANAGER_HALT;
@@ -1282,11 +1271,10 @@ static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
return sd_bus_reply_method_return(message, NULL);
}
-static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1294,7 +1282,7 @@ static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
m->exit_code = MANAGER_KEXEC;
@@ -1302,13 +1290,12 @@ static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata, sd
return sd_bus_reply_method_return(message, NULL);
}
-static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_error *error) {
char *ri = NULL, *rt = NULL;
const char *root, *init;
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1316,7 +1303,7 @@ static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userda
if (r < 0)
return r;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
r = sd_bus_message_read(message, "ss", &root, &init);
@@ -1367,12 +1354,11 @@ static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userda
return sd_bus_reply_method_return(message, NULL);
}
-static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_environment(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **plus = NULL;
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1386,6 +1372,12 @@ static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *us
if (!strv_env_is_valid(plus))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
+ r = bus_verify_set_environment_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
r = manager_environment_add(m, NULL, plus);
if (r < 0)
return r;
@@ -1393,12 +1385,11 @@ static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *us
return sd_bus_reply_method_return(message, NULL);
}
-static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_unset_environment(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **minus = NULL;
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1413,6 +1404,12 @@ static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *
if (!strv_env_name_or_assignment_is_valid(minus))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
+ r = bus_verify_set_environment_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
r = manager_environment_add(m, minus, NULL);
if (r < 0)
return r;
@@ -1420,12 +1417,11 @@ static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *
return sd_bus_reply_method_return(message, NULL);
}
-static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_unset_and_set_environment(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **minus = NULL, **plus = NULL;
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1446,6 +1442,12 @@ static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message
if (!strv_env_is_valid(plus))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
+ r = bus_verify_set_environment_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
r = manager_environment_add(m, minus, plus);
if (r < 0)
return r;
@@ -1453,7 +1455,7 @@ static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message
return sd_bus_reply_method_return(message, NULL);
}
-static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
UnitFileList *item;
@@ -1461,7 +1463,6 @@ static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *us
Iterator i;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1479,7 +1480,7 @@ static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *us
if (!h)
return -ENOMEM;
- r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
+ r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
if (r < 0)
goto fail;
@@ -1500,21 +1501,20 @@ static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *us
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
fail:
unit_file_list_free(h);
return r;
}
-static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_unit_file_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
UnitFileState state;
UnitFileScope scope;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1528,7 +1528,7 @@ static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void
if (r < 0)
return r;
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
state = unit_file_get_state(scope, NULL, name);
if (state < 0)
@@ -1537,13 +1537,12 @@ static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void
return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state));
}
-static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *default_target = NULL;
Manager *m = userdata;
UnitFileScope scope;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1553,7 +1552,7 @@ static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void
if (r < 0)
return r;
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_get_default(scope, NULL, &default_target);
if (r < 0)
@@ -1577,7 +1576,6 @@ static int send_unit_files_changed(sd_bus *bus, void *userdata) {
static int reply_unit_file_changes_and_free(
Manager *m,
- sd_bus *bus,
sd_bus_message *message,
int carries_install_info,
UnitFileChange *changes,
@@ -1621,7 +1619,7 @@ static int reply_unit_file_changes_and_free(
if (r < 0)
goto fail;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
fail:
unit_file_changes_free(changes, n_changes);
@@ -1629,7 +1627,6 @@ fail:
}
static int method_enable_unit_files_generic(
- sd_bus *bus,
sd_bus_message *message,
Manager *m,
const char *verb,
@@ -1643,16 +1640,9 @@ static int method_enable_unit_files_generic(
UnitFileScope scope;
int runtime, force, r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read_strv(message, &l);
if (r < 0)
return r;
@@ -1665,40 +1655,46 @@ static int method_enable_unit_files_generic(
if (r < 0)
return r;
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ r = bus_verify_manage_unit_files_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
if (r < 0)
return r;
- return reply_unit_file_changes_and_free(m, bus, message, carries_install_info ? r : -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
}
-static int method_enable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_enable, true, error);
+static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_enable_unit_files_generic(message, userdata, "enable", unit_file_enable, true, error);
}
-static int method_reenable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_reenable, true, error);
+static int method_reenable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_enable_unit_files_generic(message, userdata, "enable", unit_file_reenable, true, error);
}
-static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false, error);
+static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_enable_unit_files_generic(message, userdata, "enable", unit_file_link, false, error);
}
static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) {
return unit_file_preset(scope, runtime, root_dir, files, UNIT_FILE_PRESET_FULL, force, changes, n_changes);
}
-static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_preset_without_mode, true, error);
+static int method_preset_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_enable_unit_files_generic(message, userdata, "enable", unit_file_preset_without_mode, true, error);
}
-static int method_mask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "disable", unit_file_mask, false, error);
+static int method_mask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_enable_unit_files_generic(message, userdata, "disable", unit_file_mask, false, error);
}
-static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
@@ -1709,16 +1705,9 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa
int runtime, force, r;
const char *mode;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = sd_bus_message_read_strv(message, &l);
if (r < 0)
return r;
@@ -1739,17 +1728,22 @@ static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *messa
if (r < 0)
return r;
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ r = bus_verify_manage_unit_files_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
if (r < 0)
return r;
- return reply_unit_file_changes_and_free(m, bus, message, r, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
}
static int method_disable_unit_files_generic(
- sd_bus *bus,
sd_bus_message *message,
Manager *m, const
char *verb,
@@ -1762,46 +1756,45 @@ static int method_disable_unit_files_generic(
UnitFileScope scope;
int r, runtime;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_files_async(m, message, error);
+ r = sd_bus_message_read_strv(message, &l);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = mac_selinux_access_check(message, verb, error);
+ r = sd_bus_message_read(message, "b", &runtime);
if (r < 0)
return r;
- r = sd_bus_message_read_strv(message, &l);
+ r = mac_selinux_unit_access_check_strv(l, message, m, verb, error);
if (r < 0)
return r;
- r = sd_bus_message_read(message, "b", &runtime);
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+
+ r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
return r;
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = call(scope, runtime, NULL, l, &changes, &n_changes);
if (r < 0)
return r;
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
-static int method_disable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(bus, message, userdata, "disable", unit_file_disable, error);
+static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_disable_unit_files_generic(message, userdata, "disable", unit_file_disable, error);
}
-static int method_unmask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(bus, message, userdata, "enable", unit_file_unmask, error);
+static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error);
}
-static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
Manager *m = userdata;
@@ -1809,34 +1802,33 @@ static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void
const char *name;
int force, r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_files_async(m, message, error);
+ r = mac_selinux_access_check(message, "enable", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = mac_selinux_access_check(message, "enable", error);
+ r = sd_bus_message_read(message, "sb", &name, &force);
if (r < 0)
return r;
- r = sd_bus_message_read(message, "sb", &name, &force);
+ r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
if (r < 0)
return r;
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
-static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
Manager *m = userdata;
@@ -1845,16 +1837,9 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo
const char *mode;
int force, runtime, r;
- assert(bus);
assert(message);
assert(m);
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
r = mac_selinux_access_check(message, "enable", error);
if (r < 0)
return r;
@@ -1871,16 +1856,22 @@ static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, vo
return -EINVAL;
}
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ r = bus_verify_manage_unit_files_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
if (r < 0)
return r;
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
-static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_add_dependency_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
Manager *m = userdata;
UnitFileChange *changes = NULL;
@@ -1891,7 +1882,6 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message
char *type;
UnitDependency dep;
- assert(bus);
assert(message);
assert(m);
@@ -1917,13 +1907,13 @@ static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message
if (r < 0)
return r;
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
+ scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
if (r < 0)
return r;
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
const sd_bus_vtable bus_manager_vtable[] = {
@@ -1949,7 +1939,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0),
- SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, 0),
+ SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0),
SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
@@ -1982,16 +1972,16 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, 0),
- SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, 0),
+ SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnitsFiltered", "as", "a(ssssssouso)", method_list_units_filtered, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0),
- SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),
+ SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
@@ -2000,9 +1990,9 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("Halt", NULL, NULL, method_halt, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
- SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, 0),
- SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, 0),
- SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, 0),
+ SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2102,5 +2092,23 @@ void bus_manager_send_reloading(Manager *m, bool active) {
r = bus_foreach_bus(m, NULL, send_reloading, INT_TO_PTR(active));
if (r < 0)
log_debug_errno(r, "Failed to send reloading signal: %m");
+}
+
+static int send_changed_signal(sd_bus *bus, void *userdata) {
+ assert(bus);
+ return sd_bus_emit_properties_changed_strv(bus,
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ NULL);
+}
+
+void bus_manager_send_change_signal(Manager *m) {
+ int r;
+
+ assert(m);
+
+ r = bus_foreach_bus(m, NULL, send_changed_signal, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to send manager change signal: %m");
}
diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h
index e1903fa16a..5bdf6e17ab 100644
--- a/src/core/dbus-manager.h
+++ b/src/core/dbus-manager.h
@@ -21,10 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
#include "manager.h"
extern const sd_bus_vtable bus_manager_vtable[];
void bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec);
void bus_manager_send_reloading(Manager *m, bool active);
+void bus_manager_send_change_signal(Manager *m);
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 53fe4edc34..24813c6d20 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -21,7 +21,6 @@
#include "unit.h"
#include "mount.h"
-#include "dbus-unit.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
#include "dbus-cgroup.h"
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index b5e894101d..683561999b 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -21,7 +21,6 @@
#include "unit.h"
#include "path.h"
-#include "dbus-unit.h"
#include "dbus-path.h"
#include "bus-util.h"
diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h
index 667da05223..389b0d7f9b 100644
--- a/src/core/dbus-path.h
+++ b/src/core/dbus-path.h
@@ -22,6 +22,5 @@
***/
-#include "sd-bus.h"
extern const sd_bus_vtable bus_path_vtable[];
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index 60215a1935..f8fb373bf0 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -19,37 +19,40 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "selinux-access.h"
#include "unit.h"
#include "scope.h"
-#include "dbus-unit.h"
-#include "dbus-cgroup.h"
-#include "dbus-kill.h"
-#include "dbus-scope.h"
#include "dbus.h"
#include "bus-util.h"
#include "bus-internal.h"
#include "bus-common-errors.h"
+#include "dbus-unit.h"
+#include "dbus-cgroup.h"
+#include "dbus-kill.h"
+#include "dbus-scope.h"
-static int bus_scope_abandon(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Scope *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
- r = bus_verify_manage_unit_async(UNIT(s)->manager, message, error);
+ r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = scope_abandon(s);
- if (sd_bus_error_is_set(error))
- return r;
-
if (r == -ESTALE)
return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
+ if (r < 0)
+ return r;
return sd_bus_reply_method_return(message, NULL);
}
@@ -62,7 +65,7 @@ const sd_bus_vtable bus_scope_vtable[] = {
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_SIGNAL("RequestStop", NULL, 0),
- SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, 0),
+ SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6d4713babc..e1f3d56495 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -23,7 +23,6 @@
#include "path-util.h"
#include "unit.h"
#include "service.h"
-#include "dbus-unit.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
#include "dbus-cgroup.h"
diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c
index 8bc90b1dad..09e78d1f33 100644
--- a/src/core/dbus-slice.c
+++ b/src/core/dbus-slice.c
@@ -21,7 +21,6 @@
#include "unit.h"
#include "slice.h"
-#include "dbus-unit.h"
#include "dbus-cgroup.h"
#include "dbus-slice.h"
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
index 06a58e429e..cfe44c9c15 100644
--- a/src/core/dbus-snapshot.c
+++ b/src/core/dbus-snapshot.c
@@ -21,15 +21,14 @@
#include "selinux-access.h"
#include "unit.h"
+#include "dbus.h"
#include "snapshot.h"
-#include "dbus-unit.h"
#include "dbus-snapshot.h"
-int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Snapshot *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -37,6 +36,12 @@ int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userd
if (r < 0)
return r;
+ r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
snapshot_remove(s);
return sd_bus_reply_method_return(message, NULL);
@@ -44,7 +49,7 @@ int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userd
const sd_bus_vtable bus_snapshot_vtable[] = {
SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, 0),
SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
diff --git a/src/core/dbus-snapshot.h b/src/core/dbus-snapshot.h
index d7551cbcdc..9288f44e15 100644
--- a/src/core/dbus-snapshot.h
+++ b/src/core/dbus-snapshot.h
@@ -25,4 +25,4 @@
extern const sd_bus_vtable bus_snapshot_vtable[];
-int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 50b1674427..02599a9e55 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -21,9 +21,7 @@
#include "unit.h"
#include "socket.h"
-#include "dbus-unit.h"
#include "dbus-execute.h"
-#include "dbus-kill.h"
#include "dbus-cgroup.h"
#include "dbus-socket.h"
#include "bus-util.h"
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
index 1e7f66d053..0093371306 100644
--- a/src/core/dbus-swap.c
+++ b/src/core/dbus-swap.c
@@ -22,9 +22,7 @@
#include "unit.h"
#include "swap.h"
-#include "dbus-unit.h"
#include "dbus-execute.h"
-#include "dbus-kill.h"
#include "dbus-cgroup.h"
#include "dbus-swap.h"
#include "bus-util.h"
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
index 205d1c4a88..350f5c3ed2 100644
--- a/src/core/dbus-target.c
+++ b/src/core/dbus-target.c
@@ -20,8 +20,6 @@
***/
#include "unit.h"
-#include "target.h"
-#include "dbus-unit.h"
#include "dbus-target.h"
const sd_bus_vtable bus_target_vtable[] = {
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
index 6be9c9f708..4c4297bc9e 100644
--- a/src/core/dbus-target.h
+++ b/src/core/dbus-target.h
@@ -21,6 +21,5 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
extern const sd_bus_vtable bus_target_vtable[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index 43e785246c..74a9914358 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -21,10 +21,8 @@
#include "unit.h"
#include "timer.h"
-#include "dbus-unit.h"
#include "dbus-timer.h"
#include "bus-util.h"
-#include "errno-list.h"
#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 625d21ab8b..1892725f91 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -24,11 +24,8 @@
#include "selinux-access.h"
#include "cgroup-util.h"
#include "strv.h"
-#include "path-util.h"
-#include "fileio.h"
#include "bus-common-errors.h"
#include "dbus.h"
-#include "dbus-manager.h"
#include "dbus-unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
@@ -393,16 +390,25 @@ static int property_get_load_error(
return sd_bus_message_append(reply, "(ss)", e.name, e.message);
}
-int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
+int bus_unit_method_start_generic(
+ sd_bus_message *message,
+ Unit *u,
+ JobType job_type,
+ bool reload_if_possible,
+ sd_bus_error *error) {
+
const char *smode;
JobMode mode;
int r;
- assert(bus);
assert(message);
assert(u);
assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
+ r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_read(message, "s", &smode);
if (r < 0)
return r;
@@ -411,53 +417,56 @@ int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u,
if (mode < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
- return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
+ r = bus_verify_manage_units_async(u->manager, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
}
-static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
+static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_START, false, error);
}
-static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
+static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error);
}
-static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
+static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error);
}
-static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
+static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error);
}
-static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
+static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error);
}
-static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
+static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error);
}
-static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
+static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
}
-int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Unit *u = userdata;
const char *swho;
int32_t signo;
KillWho who;
int r;
- assert(bus);
assert(message);
assert(u);
- r = bus_verify_manage_unit_async_for_kill(u->manager, message, error);
+ r = mac_selinux_unit_access_check(u, message, "stop", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = sd_bus_message_read(message, "si", &swho, &signo);
if (r < 0)
@@ -474,9 +483,11 @@ int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, s
if (signo <= 0 || signo >= _NSIG)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
- r = mac_selinux_unit_access_check(u, message, "stop", error);
+ r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = unit_kill(u, who, signo, error);
if (r < 0)
@@ -485,50 +496,48 @@ int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, s
return sd_bus_reply_method_return(message, NULL);
}
-int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Unit *u = userdata;
int r;
- assert(bus);
assert(message);
assert(u);
- r = bus_verify_manage_unit_async(u->manager, message, error);
+ r = mac_selinux_unit_access_check(u, message, "reload", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = mac_selinux_unit_access_check(u, message, "reload", error);
+ r = bus_verify_manage_units_async(u->manager, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
unit_reset_failed(u);
return sd_bus_reply_method_return(message, NULL);
}
-int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Unit *u = userdata;
int runtime, r;
- assert(bus);
assert(message);
assert(u);
- r = bus_verify_manage_unit_async(u->manager, message, error);
+ r = mac_selinux_unit_access_check(u, message, "start", error);
if (r < 0)
return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = sd_bus_message_read(message, "b", &runtime);
if (r < 0)
return r;
- r = mac_selinux_unit_access_check(u, message, "start", error);
+ r = bus_verify_manage_units_async(u->manager, message, error);
if (r < 0)
return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
if (r < 0)
@@ -552,6 +561,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -606,16 +617,16 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_METHOD("Start", "s", "o", method_start, 0),
- SD_BUS_METHOD("Stop", "s", "o", method_stop, 0),
- SD_BUS_METHOD("Reload", "s", "o", method_reload, 0),
- SD_BUS_METHOD("Restart", "s", "o", method_restart, 0),
- SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, 0),
- SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, 0),
- SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, 0),
- SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, 0),
- SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, 0),
- SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, 0),
+ SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
@@ -647,30 +658,43 @@ static int property_get_current_memory(
void *userdata,
sd_bus_error *error) {
- Unit *u = userdata;
uint64_t sz = (uint64_t) -1;
+ Unit *u = userdata;
int r;
assert(bus);
assert(reply);
assert(u);
- if (u->cgroup_path &&
- (u->cgroup_realized_mask & CGROUP_MEMORY)) {
- _cleanup_free_ char *v = NULL;
+ r = unit_get_memory_current(u, &sz);
+ if (r < 0 && r != -ENODATA)
+ log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m");
- r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
- if (r < 0 && r != -ENOENT)
- log_unit_warning_errno(u->id, r, "Couldn't read memory.usage_in_bytes attribute: %m");
+ return sd_bus_message_append(reply, "t", sz);
+}
- if (v) {
- r = safe_atou64(v, &sz);
- if (r < 0)
- log_unit_warning_errno(u->id, r, "Failed to parse memory.usage_in_bytes attribute: %m");
- }
- }
+static int property_get_cpu_usage(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
- return sd_bus_message_append(reply, "t", sz);
+ nsec_t ns = (nsec_t) -1;
+ Unit *u = userdata;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(u);
+
+ r = unit_get_cpu_usage(u, &ns);
+ if (r < 0 && r != -ENODATA)
+ log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m");
+
+ return sd_bus_message_append(reply, "t", ns);
}
const sd_bus_vtable bus_unit_cgroup_vtable[] = {
@@ -678,6 +702,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
+ SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
SD_BUS_VTABLE_END
};
@@ -691,7 +716,7 @@ static int send_new_signal(sd_bus *bus, void *userdata) {
assert(u);
p = unit_dbus_path(u);
- if (!u)
+ if (!p)
return -ENOMEM;
r = sd_bus_message_new_signal(
@@ -753,7 +778,7 @@ void bus_unit_send_change_signal(Unit *u) {
r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
if (r < 0)
- log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
+ log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id);
u->sent_dbus_new_signal = true;
}
@@ -768,7 +793,7 @@ static int send_removed_signal(sd_bus *bus, void *userdata) {
assert(u);
p = unit_dbus_path(u);
- if (!u)
+ if (!p)
return -ENOMEM;
r = sd_bus_message_new_signal(
@@ -799,11 +824,10 @@ void bus_unit_send_removed_signal(Unit *u) {
r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
if (r < 0)
- log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
+ log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
}
int bus_unit_queue_job(
- sd_bus *bus,
sd_bus_message *message,
Unit *u,
JobType type,
@@ -815,7 +839,6 @@ int bus_unit_queue_job(
Job *j;
int r;
- assert(bus);
assert(message);
assert(u);
assert(type >= 0 && type < _JOB_TYPE_MAX);
@@ -849,9 +872,9 @@ int bus_unit_queue_job(
if (r < 0)
return r;
- if (bus == u->manager->api_bus) {
+ if (sd_bus_message_get_bus(message) == u->manager->api_bus) {
if (!j->clients) {
- r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
+ r = sd_bus_track_new(sd_bus_message_get_bus(message), &j->clients, NULL, NULL);
if (r < 0)
return r;
}
@@ -919,7 +942,7 @@ static int bus_unit_set_transient_property(
if (r < 0)
return r;
- if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
+ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice"))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
if (isempty(s)) {
@@ -967,7 +990,7 @@ static int bus_unit_set_transient_property(
return r;
while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
- if (!unit_name_is_valid(other, TEMPLATE_INVALID))
+ if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
if (mode != UNIT_CHECK) {
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index 57a5e19744..b622e0ae8d 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -30,10 +30,10 @@ extern const sd_bus_vtable bus_unit_cgroup_vtable[];
void bus_unit_send_change_signal(Unit *u);
void bus_unit_send_removed_signal(Unit *u);
-int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
-int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
+int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_unit_queue_job(sd_bus *bus, sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
+int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
-int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 260775cd85..86886e6d2c 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -20,7 +20,6 @@
***/
#include <sys/epoll.h>
-#include <sys/timerfd.h>
#include <errno.h>
#include <unistd.h>
@@ -44,7 +43,7 @@
#include "bus-internal.h"
#include "selinux-access.h"
-#define CONNECTIONS_MAX 512
+#define CONNECTIONS_MAX 4096
static void destroy_bus(Manager *m, sd_bus **bus);
@@ -56,28 +55,24 @@ int bus_send_queued_message(Manager *m) {
if (!m->queued_message)
return 0;
- assert(m->queued_message_bus);
-
/* If we cannot get rid of this message we won't dispatch any
* D-Bus messages, so that we won't end up wanting to queue
* another message. */
- r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
+ r = sd_bus_send(NULL, m->queued_message, NULL);
if (r < 0)
log_warning_errno(r, "Failed to send queued message: %m");
m->queued_message = sd_bus_message_unref(m->queued_message);
- m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
return 0;
}
-static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *cgroup;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -89,24 +84,29 @@ static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *use
manager_notify_cgroup_empty(m, cgroup);
- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) {
- /* If we are running as system manager, forward the
- * message to the system bus */
+ /* only forward to system bus if running as system instance */
+ if (m->running_as != MANAGER_SYSTEM || !m->system_bus)
+ return 0;
- r = sd_bus_send(m->system_bus, message, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to forward Released message: %m");
- }
+ r = sd_bus_message_rewind(message, 1);
+ if (r < 0)
+ goto exit;
+ r = sd_bus_send(m->system_bus, message, NULL);
+
+exit:
+ if (r < 0)
+ log_warning_errno(r, "Failed to forward Released message: %m");
return 0;
}
-static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
+ sd_bus *bus;
- assert(bus);
assert(message);
assert(m);
+ assert_se(bus = sd_bus_message_get_bus(message));
if (bus == m->api_bus)
destroy_bus(m, &m->api_bus);
@@ -120,12 +120,11 @@ static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userd
return 0;
}
-static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name, *old_owner, *new_owner;
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -143,7 +142,7 @@ static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void
return 0;
}
-static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
+static int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
@@ -151,7 +150,6 @@ static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void
Unit *u;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -189,7 +187,7 @@ failed:
log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
- r = sd_bus_message_new_signal(bus, &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
+ r = sd_bus_message_new_signal(sd_bus_message_get_bus(message), &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
if (r < 0) {
bus_log_create_error(r);
return 0;
@@ -201,7 +199,7 @@ failed:
return 0;
}
- r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
+ r = sd_bus_send_to(NULL, reply, "org.freedesktop.DBus", NULL);
if (r < 0)
return log_error_errno(r, "Failed to respond with to bus activation request: %m");
@@ -209,14 +207,13 @@ failed:
}
#ifdef HAVE_SELINUX
-static int mac_selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *verb, *path;
Unit *u = NULL;
Job *j;
int r;
- assert(bus);
assert(message);
/* Our own method calls are all protected individually with
@@ -667,6 +664,15 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
+ r = sd_bus_negotiate_creds(bus, 1,
+ SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
+ SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to enable credentials for new connection: %m");
+ return 0;
+ }
+
r = sd_bus_start(bus);
if (r < 0) {
log_warning_errno(r, "Failed to start new connection bus: %m");
@@ -679,7 +685,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
/* When we run as system instance we get the Released
* signal via a direct connection */
@@ -710,7 +716,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
r = set_put(m->private_buses, bus);
if (r < 0) {
- log_warning_errno(r, "Failed to add new conenction bus to set: %m");
+ log_warning_errno(r, "Failed to add new connection bus to set: %m");
return 0;
}
@@ -807,10 +813,10 @@ static int bus_init_api(Manager *m) {
return 0;
/* The API and system bus is the same if we are running in system mode */
- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus)
+ if (m->running_as == MANAGER_SYSTEM && m->system_bus)
bus = sd_bus_ref(m->system_bus);
else {
- if (m->running_as == SYSTEMD_SYSTEM)
+ if (m->running_as == MANAGER_SYSTEM)
r = sd_bus_open_system(&bus);
else
r = sd_bus_open_user(&bus);
@@ -849,22 +855,19 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
- if (m->running_as == SYSTEMD_SYSTEM)
- return 0;
-
- /* If we are a user instance we get the Released message via
- * the system bus */
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
-
- if (r < 0)
- log_warning_errno(r, "Failed to register Released match on system bus: %m");
+ /* On kdbus or if we are a user instance we get the Released message via the system bus */
+ if (m->running_as == MANAGER_USER || m->kdbus_fd >= 0) {
+ r = sd_bus_add_match(
+ bus,
+ NULL,
+ "type='signal',"
+ "interface='org.freedesktop.systemd1.Agent',"
+ "member='Released',"
+ "path='/org/freedesktop/systemd1/agent'",
+ signal_agent_released, m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to register Released match on system bus: %m");
+ }
log_debug("Successfully connected to system bus.");
return 0;
@@ -878,7 +881,7 @@ static int bus_init_system(Manager *m) {
return 0;
/* The API and system bus is the same if we are running in system mode */
- if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) {
+ if (m->running_as == MANAGER_SYSTEM && m->api_bus) {
m->system_bus = sd_bus_ref(m->api_bus);
return 0;
}
@@ -929,7 +932,7 @@ static int bus_init_private(Manager *m) {
if (m->kdbus_fd >= 0)
return 0;
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
/* We want the private bus only when running as init */
if (getpid() != 1)
@@ -973,6 +976,8 @@ static int bus_init_private(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to allocate event source: %m");
+ (void) sd_event_source_set_description(s, "bus-connection");
+
m->private_listen_fd = fd;
m->private_listen_event_source = s;
fd = -1;
@@ -1021,16 +1026,12 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
j->clients = sd_bus_track_unref(j->clients);
/* Get rid of queued message on this bus */
- if (m->queued_message_bus == *bus) {
- m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
-
- if (m->queued_message)
- m->queued_message = sd_bus_message_unref(m->queued_message);
- }
+ if (m->queued_message && sd_bus_message_get_bus(m->queued_message) == *bus)
+ m->queued_message = sd_bus_message_unref(m->queued_message);
/* Possibly flush unwritten data, but only if we are
* unprivileged, since we don't want to sync here */
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
sd_bus_flush(*bus);
/* And destroy the object */
@@ -1115,7 +1116,7 @@ int bus_foreach_bus(
sd_bus *b;
int r, ret = 0;
- /* Send to all direct busses, unconditionally */
+ /* Send to all direct buses, unconditionally */
SET_FOREACH(b, m->private_buses, i) {
r = send_message(b, userdata);
if (r < 0)
@@ -1192,19 +1193,23 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
return r;
}
-int bus_verify_manage_unit_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", false, &m->polkit_registry, error);
+int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
+ return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
}
/* Same as bus_verify_manage_unit_async(), but checks for CAP_KILL instead of CAP_SYS_ADMIN */
-int bus_verify_manage_unit_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_KILL, "org.freedesktop.systemd1.manage-units", false, &m->polkit_registry, error);
+int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error) {
+ return bus_verify_polkit_async(call, CAP_KILL, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
}
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", false, &m->polkit_registry, error);
+ return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", false, UID_INVALID, &m->polkit_registry, error);
}
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", false, &m->polkit_registry, error);
+ return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", false, UID_INVALID, &m->polkit_registry, error);
+}
+
+int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
+ return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", false, UID_INVALID, &m->polkit_registry, error);
}
diff --git a/src/core/dbus.h b/src/core/dbus.h
index d04f5326c6..4832722069 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -36,7 +36,8 @@ int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l);
int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
-int bus_verify_manage_unit_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
-int bus_verify_manage_unit_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error);
+int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
+int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
+int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
diff --git a/src/core/device.c b/src/core/device.c
index d3deac3936..e7efcf0f0a 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -23,11 +23,9 @@
#include <sys/epoll.h>
#include <libudev.h>
-#include "strv.h"
#include "log.h"
#include "unit-name.h"
#include "dbus-device.h"
-#include "def.h"
#include "path-util.h"
#include "udev-util.h"
#include "unit.h"
@@ -36,7 +34,8 @@
static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = UNIT_INACTIVE,
- [DEVICE_PLUGGED] = UNIT_ACTIVE
+ [DEVICE_TENTATIVE] = UNIT_ACTIVATING,
+ [DEVICE_PLUGGED] = UNIT_ACTIVE,
};
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
@@ -65,6 +64,41 @@ static void device_unset_sysfs(Device *d) {
d->sysfs = NULL;
}
+static int device_set_sysfs(Device *d, const char *sysfs) {
+ Device *first;
+ char *copy;
+ int r;
+
+ assert(d);
+
+ if (streq_ptr(d->sysfs, sysfs))
+ return 0;
+
+ r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ copy = strdup(sysfs);
+ if (!copy)
+ return -ENOMEM;
+
+ device_unset_sysfs(d);
+
+ first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs);
+ LIST_PREPEND(same_sysfs, first, d);
+
+ r = hashmap_replace(UNIT(d)->manager->devices_by_sysfs, copy, first);
+ if (r < 0) {
+ LIST_REMOVE(same_sysfs, first, d);
+ free(copy);
+ return r;
+ }
+
+ d->sysfs = copy;
+
+ return 0;
+}
+
static void device_init(Unit *u) {
Device *d = DEVICE(u);
@@ -98,10 +132,7 @@ static void device_set_state(Device *d, DeviceState state) {
d->state = state;
if (state != old_state)
- log_unit_debug(UNIT(d)->id,
- "%s changed %s -> %s", UNIT(d)->id,
- device_state_to_string(old_state),
- device_state_to_string(state));
+ log_unit_debug(UNIT(d), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));
unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -112,8 +143,48 @@ static int device_coldplug(Unit *u) {
assert(d);
assert(d->state == DEVICE_DEAD);
- if (d->sysfs)
+ if (d->found & DEVICE_FOUND_UDEV)
+ /* If udev says the device is around, it's around */
device_set_state(d, DEVICE_PLUGGED);
+ else if (d->found != DEVICE_NOT_FOUND && d->deserialized_state != DEVICE_PLUGGED)
+ /* If a device is found in /proc/self/mountinfo or
+ * /proc/swaps, and was not yet announced via udev,
+ * it's "tentatively" around. */
+ device_set_state(d, DEVICE_TENTATIVE);
+
+ return 0;
+}
+
+static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
+ Device *d = DEVICE(u);
+
+ assert(u);
+ assert(f);
+ assert(fds);
+
+ unit_serialize_item(u, f, "state", device_state_to_string(d->state));
+
+ return 0;
+}
+
+static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+ Device *d = DEVICE(u);
+
+ assert(u);
+ assert(key);
+ assert(value);
+ assert(fds);
+
+ if (streq(key, "state")) {
+ DeviceState state;
+
+ state = device_state_from_string(value);
+ if (state < 0)
+ log_unit_debug(u, "Failed to parse state value: %s", value);
+ else
+ d->deserialized_state = state;
+ } else
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -142,49 +213,9 @@ _pure_ static const char *device_sub_state_to_string(Unit *u) {
return device_state_to_string(DEVICE(u)->state);
}
-static int device_add_escaped_name(Unit *u, const char *dn) {
- _cleanup_free_ char *e = NULL;
- int r;
-
- assert(u);
- assert(dn);
- assert(dn[0] == '/');
-
- e = unit_name_from_path(dn, ".device");
- if (!e)
- return -ENOMEM;
-
- r = unit_add_name(u, e);
- if (r < 0 && r != -EEXIST)
- return r;
-
- return 0;
-}
-
-static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
- _cleanup_free_ char *e = NULL;
- Unit *u;
-
- assert(m);
- assert(dn);
- assert(dn[0] == '/');
- assert(_u);
-
- e = unit_name_from_path(dn, ".device");
- if (!e)
- return -ENOMEM;
-
- u = manager_get_unit(m, e);
- if (u) {
- *_u = u;
- return 1;
- }
-
- return 0;
-}
-
-static int device_make_description(Unit *u, struct udev_device *dev, const char *path) {
+static int device_update_description(Unit *u, struct udev_device *dev, const char *path) {
const char *model;
+ int r;
assert(u);
assert(dev);
@@ -209,13 +240,18 @@ static int device_make_description(Unit *u, struct udev_device *dev, const char
j = strjoin(model, " ", label, NULL);
if (j)
- return unit_set_description(u, j);
- }
+ r = unit_set_description(u, j);
+ else
+ r = -ENOMEM;
+ } else
+ r = unit_set_description(u, model);
+ } else
+ r = unit_set_description(u, path);
- return unit_set_description(u, model);
- }
+ if (r < 0)
+ log_unit_error_errno(u, r, "Failed to set device description: %m");
- return unit_set_description(u, path);
+ return r;
}
static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
@@ -228,7 +264,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
assert(u);
assert(dev);
- property = u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
+ property = u->manager->running_as == MANAGER_USER ? "MANAGER_USER_WANTS" : "SYSTEMD_WANTS";
wants = udev_device_get_property_value(dev, property);
if (!wants)
return 0;
@@ -240,41 +276,49 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
memcpy(e, word, l);
e[l] = 0;
- n = unit_name_mangle(e, MANGLE_NOGLOB);
- if (!n)
- return -ENOMEM;
+ r = unit_name_mangle(e, UNIT_NAME_NOGLOB, &n);
+ if (r < 0)
+ return log_unit_error_errno(u, r, "Failed to mangle unit name: %m");
r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
if (r < 0)
- return r;
+ return log_unit_error_errno(u, r, "Failed to add wants dependency: %m");
}
if (!isempty(state))
- log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.",
- property, strna(udev_device_get_syspath(dev)));
+ log_unit_warning(u, "Property %s on %s has trailing garbage, ignoring.", property, strna(udev_device_get_syspath(dev)));
return 0;
}
-static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
- const char *sysfs;
+static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
+ _cleanup_free_ char *e = NULL;
+ const char *sysfs = NULL;
Unit *u = NULL;
bool delete;
int r;
assert(m);
- assert(dev);
assert(path);
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
- return 0;
+ if (dev) {
+ sysfs = udev_device_get_syspath(dev);
+ if (!sysfs)
+ return 0;
+ }
- r = device_find_escape_name(m, path, &u);
+ r = unit_name_from_path(path, ".device", &e);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to generate unit name from device path: %m");
+
+ u = manager_get_unit(m, e);
- if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
+ if (u &&
+ sysfs &&
+ DEVICE(u)->sysfs &&
+ !path_equal(DEVICE(u)->sysfs, sysfs)) {
+ log_unit_debug(u, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
+ }
if (!u) {
delete = true;
@@ -283,7 +327,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
if (!u)
return log_oom();
- r = device_add_escaped_name(u, path);
+ r = unit_add_name(u, e);
if (r < 0)
goto fail;
@@ -294,38 +338,19 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
/* 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 (!DEVICE(u)->sysfs) {
- Device *first;
-
- DEVICE(u)->sysfs = strdup(sysfs);
- if (!DEVICE(u)->sysfs) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = hashmap_ensure_allocated(&m->devices_by_sysfs, &string_hash_ops);
+ if (sysfs) {
+ r = device_set_sysfs(DEVICE(u), sysfs);
if (r < 0)
goto fail;
- first = hashmap_get(m->devices_by_sysfs, sysfs);
- LIST_PREPEND(same_sysfs, first, DEVICE(u));
+ (void) device_update_description(u, dev, path);
- r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first);
- if (r < 0)
- goto fail;
+ /* The additional systemd udev properties we only interpret
+ * for the main object */
+ if (main)
+ (void) device_add_udev_wants(u, dev);
}
- device_make_description(u, dev, path);
-
- if (main) {
- /* The additional systemd udev properties we only
- * interpret for the main object */
-
- r = device_add_udev_wants(u, dev);
- if (r < 0)
- goto fail;
- }
/* Note that this won't dispatch the load queue, the caller
* has to do that if needed and appropriate */
@@ -334,15 +359,15 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
return 0;
fail:
- log_warning_errno(r, "Failed to load device unit: %m");
+ log_unit_warning_errno(u, r, "Failed to set up device unit: %m");
- if (delete && u)
+ if (delete)
unit_free(u);
return r;
}
-static int device_process_new_device(Manager *m, struct udev_device *dev) {
+static int device_process_new(Manager *m, struct udev_device *dev) {
const char *sysfs, *dn, *alias;
struct udev_list_entry *item = NULL, *first = NULL;
int r;
@@ -354,14 +379,14 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
return 0;
/* Add the main unit named after the sysfs path */
- r = device_update_unit(m, dev, sysfs, true);
+ r = device_setup_unit(m, dev, sysfs, true);
if (r < 0)
return r;
/* Add an additional unit for the device node */
dn = udev_device_get_devnode(dev);
if (dn)
- device_update_unit(m, dev, dn, false);
+ (void) device_setup_unit(m, dev, dn, false);
/* Add additional units for all symlinks */
first = udev_device_get_devlinks_list_entry(dev);
@@ -388,7 +413,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
st.st_rdev != udev_device_get_devnum(dev))
continue;
- device_update_unit(m, dev, p, false);
+ (void) device_setup_unit(m, dev, p, false);
}
/* Add additional units for all explicitly configured
@@ -405,7 +430,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
e[l] = 0;
if (path_is_absolute(e))
- device_update_unit(m, dev, e, false);
+ (void) device_setup_unit(m, dev, e, false);
else
log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
}
@@ -416,39 +441,74 @@ static int device_process_new_device(Manager *m, struct udev_device *dev) {
return 0;
}
-static void device_set_path_plugged(Manager *m, struct udev_device *dev) {
- const char *sysfs;
+static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
+ DeviceFound n, previous;
+
+ assert(d);
+
+ n = add ? (d->found | found) : (d->found & ~found);
+ if (n == d->found)
+ return;
+
+ previous = d->found;
+ d->found = n;
+
+ if (!now)
+ return;
+
+ if (d->found & DEVICE_FOUND_UDEV)
+ /* When the device is known to udev we consider it
+ * plugged. */
+ device_set_state(d, DEVICE_PLUGGED);
+ else if (d->found != DEVICE_NOT_FOUND && (previous & DEVICE_FOUND_UDEV) == 0)
+ /* If the device has not been seen by udev yet, but is
+ * now referenced by the kernel, then we assume the
+ * kernel knows it now, and udev might soon too. */
+ device_set_state(d, DEVICE_TENTATIVE);
+ else
+ /* If nobody sees the device, or if the device was
+ * previously seen by udev and now is only referenced
+ * from the kernel, then we consider the device is
+ * gone, the kernel just hasn't noticed it yet. */
+ device_set_state(d, DEVICE_DEAD);
+}
+
+static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
Device *d, *l;
assert(m);
- assert(dev);
+ assert(sysfs);
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
- return;
+ if (found == DEVICE_NOT_FOUND)
+ return 0;
l = hashmap_get(m->devices_by_sysfs, sysfs);
LIST_FOREACH(same_sysfs, d, l)
- device_set_state(d, DEVICE_PLUGGED);
+ device_update_found_one(d, add, found, now);
+
+ return 0;
}
-static int device_process_removed_device(Manager *m, struct udev_device *dev) {
- const char *sysfs;
- Device *d;
+static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
+ _cleanup_free_ char *e = NULL;
+ Unit *u;
+ int r;
assert(m);
- assert(dev);
+ assert(path);
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
- return -ENOMEM;
+ if (found == DEVICE_NOT_FOUND)
+ return 0;
- /* Remove all units of this sysfs path */
- while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
- device_unset_sysfs(d);
- device_set_state(d, DEVICE_DEAD);
- }
+ r = unit_name_from_path(path, ".device", &e);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name from device path: %m");
+
+ u = manager_get_unit(m, e);
+ if (!u)
+ return 0;
+ device_update_found_one(DEVICE(u), add, found, now);
return 0;
}
@@ -464,22 +524,6 @@ static bool device_is_ready(struct udev_device *dev) {
return parse_boolean(ready) != 0;
}
-static int device_process_new_path(Manager *m, const char *path) {
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
-
- assert(m);
- assert(path);
-
- dev = udev_device_new_from_syspath(m->udev, path);
- if (!dev)
- return log_oom();
-
- if (!device_is_ready(dev))
- return 0;
-
- return device_process_new_device(m, dev);
-}
-
static Unit *device_following(Unit *u) {
Device *d = DEVICE(u);
Device *other, *first = NULL;
@@ -572,7 +616,7 @@ static int device_enumerate(Manager *m) {
/* This will fail if we are unprivileged, but that
* should not matter much, as user instances won't run
* during boot. */
- udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
+ (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
if (r < 0)
@@ -585,6 +629,8 @@ static int device_enumerate(Manager *m) {
r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
if (r < 0)
goto fail;
+
+ (void) sd_event_source_set_description(m->udev_event_source, "device");
}
e = udev_enumerate_new(m->udev);
@@ -606,12 +652,31 @@ static int device_enumerate(Manager *m) {
goto fail;
first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first)
- device_process_new_path(m, udev_list_entry_get_name(item));
+ udev_list_entry_foreach(item, first) {
+ _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+ const char *sysfs;
+
+ sysfs = udev_list_entry_get_name(item);
+
+ dev = udev_device_new_from_syspath(m->udev, sysfs);
+ if (!dev) {
+ log_oom();
+ continue;
+ }
+
+ if (!device_is_ready(dev))
+ continue;
+
+ (void) device_process_new(m, dev);
+
+ device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
+ }
return 0;
fail:
+ log_error_errno(r, "Failed to enumerate devices: %m");
+
device_shutdown(m);
return r;
}
@@ -619,7 +684,7 @@ fail:
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
_cleanup_udev_device_unref_ struct udev_device *dev = NULL;
Manager *m = userdata;
- const char *action;
+ const char *action, *sysfs;
int r;
assert(m);
@@ -641,41 +706,54 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (!dev)
return 0;
+ sysfs = udev_device_get_syspath(dev);
+ if (!sysfs) {
+ log_error("Failed to get udev sys path.");
+ return 0;
+ }
+
action = udev_device_get_action(dev);
if (!action) {
log_error("Failed to get udev action string.");
return 0;
}
- if (streq(action, "remove") || !device_is_ready(dev)) {
- r = device_process_removed_device(m, dev);
- if (r < 0)
- log_error_errno(r, "Failed to process device remove event: %m");
-
- r = swap_process_removed_device(m, dev);
+ if (streq(action, "remove")) {
+ r = swap_process_device_remove(m, dev);
if (r < 0)
log_error_errno(r, "Failed to process swap device remove event: %m");
- } else {
- r = device_process_new_device(m, dev);
- if (r < 0)
- log_error_errno(r, "Failed to process device new event: %m");
+ /* If we get notified that a device was removed by
+ * udev, then it's completely gone, hence unset all
+ * found bits */
+ device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV|DEVICE_FOUND_MOUNT|DEVICE_FOUND_SWAP, true);
+
+ } else if (device_is_ready(dev)) {
- r = swap_process_new_device(m, dev);
+ (void) device_process_new(m, dev);
+
+ r = swap_process_device_new(m, dev);
if (r < 0)
log_error_errno(r, "Failed to process swap device new event: %m");
manager_dispatch_load_queue(m);
- device_set_path_plugged(m, dev);
+ /* The device is found now, set the udev found bit */
+ device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, true);
+
+ } else {
+ /* The device is nominally around, but not ready for
+ * us. Hence unset the udev bit, but leave the rest
+ * around. */
+
+ device_update_found_by_sysfs(m, sysfs, false, DEVICE_FOUND_UDEV, true);
}
return 0;
}
-static bool device_supported(Manager *m) {
+static bool device_supported(void) {
static int read_only = -1;
- assert(m);
/* If /sys is read-only we don't support device units, and any
* attempts to start one should fail immediately. */
@@ -686,9 +764,64 @@ static bool device_supported(Manager *m) {
return read_only <= 0;
}
+int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now) {
+ _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
+ struct stat st;
+
+ assert(m);
+ assert(node);
+
+ if (!device_supported())
+ return 0;
+
+ /* This is called whenever we find a device referenced in
+ * /proc/swaps or /proc/self/mounts. Such a device might be
+ * mounted/enabled at a time where udev has not finished
+ * probing it yet, and we thus haven't learned about it
+ * yet. In this case we will set the device unit to
+ * "tentative" state. */
+
+ if (add) {
+ if (!path_startswith(node, "/dev"))
+ return 0;
+
+ /* We make an extra check here, if the device node
+ * actually exists. If it's missing, then this is an
+ * indication that device was unplugged but is still
+ * referenced in /proc/swaps or
+ * /proc/self/mountinfo. Note that this check doesn't
+ * really cover all cases where a device might be gone
+ * away, since drives that can have a medium inserted
+ * will still have a device node even when the medium
+ * is not there... */
+
+ if (stat(node, &st) >= 0) {
+ if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
+ return 0;
+
+ dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
+ if (!dev && errno != ENOENT)
+ return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
+
+ } else if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
+
+ /* If the device is known in the kernel and newly
+ * appeared, then we'll create a device unit for it,
+ * under the name referenced in /proc/swaps or
+ * /proc/self/mountinfo. */
+
+ (void) device_setup_unit(m, dev, node, false);
+ }
+
+ /* Update the device unit's state, should it exist */
+ return device_update_found_by_name(m, node, add, found, now);
+}
+
static const char* const device_state_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = "dead",
- [DEVICE_PLUGGED] = "plugged"
+ [DEVICE_TENTATIVE] = "tentative",
+ [DEVICE_PLUGGED] = "plugged",
};
DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
@@ -708,6 +841,9 @@ const UnitVTable device_vtable = {
.coldplug = device_coldplug,
+ .serialize = device_serialize,
+ .deserialize_item = device_deserialize_item,
+
.dump = device_dump,
.active_state = device_active_state,
diff --git a/src/core/device.h b/src/core/device.h
index bb7ae07834..10ab113176 100644
--- a/src/core/device.h
+++ b/src/core/device.h
@@ -23,32 +23,40 @@
typedef struct Device Device;
-#include "unit.h"
-
/* We simply watch devices, we cannot plug/unplug them. That
* simplifies the state engine greatly */
typedef enum DeviceState {
DEVICE_DEAD,
- DEVICE_PLUGGED,
+ DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
+ DEVICE_PLUGGED, /* announced by udev */
_DEVICE_STATE_MAX,
_DEVICE_STATE_INVALID = -1
} DeviceState;
+typedef enum DeviceFound {
+ DEVICE_NOT_FOUND = 0,
+ DEVICE_FOUND_UDEV = 1,
+ DEVICE_FOUND_MOUNT = 2,
+ DEVICE_FOUND_SWAP = 4,
+} DeviceFound;
+
struct Device {
Unit meta;
char *sysfs;
+ DeviceFound found;
/* In order to be able to distinguish dependencies on
different device nodes we might end up creating multiple
devices for the same sysfs path. We chain them up here. */
-
LIST_FIELDS(struct Device, same_sysfs);
- DeviceState state;
+ DeviceState state, deserialized_state;
};
extern const UnitVTable device_vtable;
const char* device_state_to_string(DeviceState i) _const_;
DeviceState device_state_from_string(const char *s) _pure_;
+
+int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
diff --git a/src/core/execute.c b/src/core/execute.c
index 1815e3de2d..4120493bda 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
@@ -29,14 +27,8 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/prctl.h>
-#include <linux/sched.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <grp.h>
-#include <pwd.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-#include <linux/oom.h>
#include <poll.h>
#include <glob.h>
#include <sys/personality.h>
@@ -57,13 +49,13 @@
#include <sys/apparmor.h>
#endif
-#include "execute.h"
+#include "sd-messages.h"
+#include "rm-rf.h"
#include "strv.h"
#include "macro.h"
#include "capability.h"
#include "util.h"
#include "log.h"
-#include "sd-messages.h"
#include "ioprio.h"
#include "securebits.h"
#include "namespace.h"
@@ -80,16 +72,24 @@
#include "errno-list.h"
#include "af-list.h"
#include "mkdir.h"
-#include "apparmor-util.h"
#include "smack-util.h"
#include "bus-endpoint.h"
-#include "label.h"
#include "cap-list.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
+
+#ifdef HAVE_APPARMOR
+#include "apparmor-util.h"
+#endif
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "execute.h"
+
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
@@ -394,11 +394,12 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty
}
}
-static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin, uid_t uid, gid_t gid) {
+static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
ExecOutput o;
ExecInput i;
int r;
+ assert(unit);
assert(context);
assert(ident);
@@ -461,15 +462,9 @@ static int setup_output(const ExecContext *context, int fileno, int socket_fd, c
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- r = connect_logger_as(context, o, ident, unit_id, fileno, uid, gid);
+ r = connect_logger_as(context, o, ident, unit->id, fileno, uid, gid);
if (r < 0) {
- log_unit_struct(unit_id,
- LOG_ERR,
- LOG_MESSAGE("Failed to connect %s of %s to the journal socket: %s",
- fileno == STDOUT_FILENO ? "stdout" : "stderr",
- unit_id, strerror(-r)),
- LOG_ERRNO(-r),
- NULL);
+ log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
r = open_null_as(O_WRONLY, fileno);
}
return r;
@@ -1165,10 +1160,10 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
/* Signal systemd that we are bored and want to continue. */
- write(idle_pipe[3], "x", 1);
-
- /* Wait for systemd to react to the signal above. */
- fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
+ r = write(idle_pipe[3], "x", 1);
+ if (r > 0)
+ /* Wait for systemd to react to the signal above. */
+ fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
}
safe_close(idle_pipe[0]);
@@ -1264,7 +1259,38 @@ static int build_environment(
return 0;
}
+static bool exec_needs_mount_namespace(
+ const ExecContext *context,
+ const ExecParameters *params,
+ ExecRuntime *runtime) {
+
+ assert(context);
+ assert(params);
+
+ if (!strv_isempty(context->read_write_dirs) ||
+ !strv_isempty(context->read_only_dirs) ||
+ !strv_isempty(context->inaccessible_dirs))
+ return true;
+
+ if (context->mount_flags != 0)
+ return true;
+
+ if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
+ return true;
+
+ if (params->bus_endpoint_path)
+ return true;
+
+ if (context->private_devices ||
+ context->protect_system != PROTECT_SYSTEM_NO ||
+ context->protect_home != PROTECT_HOME_NO)
+ return true;
+
+ return false;
+}
+
static int exec_child(
+ Unit *unit,
ExecCommand *command,
const ExecContext *context,
const ExecParameters *params,
@@ -1283,7 +1309,9 @@ static int exec_child(
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r;
+ bool needs_mount_namespace;
+ assert(unit);
assert(command);
assert(context);
assert(params);
@@ -1385,13 +1413,13 @@ static int exec_child(
return r;
}
- r = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
- r = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;
@@ -1417,7 +1445,7 @@ static int exec_child(
r = write_string_file("/proc/self/oom_score_adj", t);
if (r == -EPERM || r == -EACCES) {
log_open();
- log_unit_debug_errno(params->unit_id, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
+ log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
log_close();
} else if (r < 0) {
*exit_status = EXIT_OOM_ADJUST;
@@ -1465,7 +1493,7 @@ static int exec_child(
return -errno;
}
- if (context->personality != 0xffffffffUL)
+ if (context->personality != PERSONALITY_INVALID)
if (personality(context->personality) < 0) {
*exit_status = EXIT_PERSONALITY;
return -errno;
@@ -1560,16 +1588,9 @@ static int exec_child(
}
}
- if (!strv_isempty(context->read_write_dirs) ||
- !strv_isempty(context->read_only_dirs) ||
- !strv_isempty(context->inaccessible_dirs) ||
- context->mount_flags != 0 ||
- (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) ||
- params->bus_endpoint_path ||
- context->private_devices ||
- context->protect_system != PROTECT_SYSTEM_NO ||
- context->protect_home != PROTECT_HOME_NO) {
+ needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
+ if (needs_mount_namespace) {
char *tmp = NULL, *var = NULL;
/* The runtime struct only contains the parent
@@ -1586,6 +1607,7 @@ static int exec_child(
}
r = setup_namespace(
+ params->apply_chroot ? context->root_directory : NULL,
context->read_write_dirs,
context->read_only_dirs,
context->inaccessible_dirs,
@@ -1602,7 +1624,7 @@ static int exec_child(
* silently proceeed. */
if (r == -EPERM || r == -EACCES) {
log_open();
- log_unit_debug_errno(params->unit_id, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
+ log_unit_debug_errno(unit, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
log_close();
} else if (r < 0) {
*exit_status = EXIT_NAMESPACE;
@@ -1611,7 +1633,7 @@ static int exec_child(
}
if (params->apply_chroot) {
- if (context->root_directory)
+ if (!needs_mount_namespace && context->root_directory)
if (chroot(context->root_directory) < 0) {
*exit_status = EXIT_CHROOT;
return -errno;
@@ -1803,20 +1825,22 @@ static int exec_child(
line = exec_command_line(final_argv);
if (line) {
log_open();
- log_unit_struct(params->unit_id,
- LOG_DEBUG,
- "EXECUTABLE=%s", command->path,
- LOG_MESSAGE("Executing: %s", line),
- NULL);
+ log_struct(LOG_DEBUG,
+ LOG_UNIT_ID(unit),
+ "EXECUTABLE=%s", command->path,
+ LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
+ NULL);
log_close();
}
}
+
execve(command->path, final_argv, final_env);
*exit_status = EXIT_EXEC;
return -errno;
}
-int exec_spawn(ExecCommand *command,
+int exec_spawn(Unit *unit,
+ ExecCommand *command,
const ExecContext *context,
const ExecParameters *params,
ExecRuntime *runtime,
@@ -1829,6 +1853,7 @@ int exec_spawn(ExecCommand *command,
char **argv;
pid_t pid;
+ assert(unit);
assert(command);
assert(context);
assert(ret);
@@ -1840,7 +1865,7 @@ int exec_spawn(ExecCommand *command,
context->std_error == EXEC_OUTPUT_SOCKET) {
if (params->n_fds != 1) {
- log_unit_error(params->unit_id, "Got more than one socket.");
+ log_unit_error(unit, "Got more than one socket.");
return -EINVAL;
}
@@ -1851,28 +1876,29 @@ int exec_spawn(ExecCommand *command,
n_fds = params->n_fds;
}
- r = exec_context_load_environment(context, params->unit_id, &files_env);
+ r = exec_context_load_environment(unit, context, &files_env);
if (r < 0)
- return log_unit_error_errno(params->unit_id, r, "Failed to load environment files: %m");
+ return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
argv = params->argv ?: command->argv;
line = exec_command_line(argv);
if (!line)
return log_oom();
- log_unit_struct(params->unit_id,
- LOG_DEBUG,
- "EXECUTABLE=%s", command->path,
- LOG_MESSAGE("About to execute: %s", line),
- NULL);
+ log_struct(LOG_DEBUG,
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
+ "EXECUTABLE=%s", command->path,
+ NULL);
pid = fork();
if (pid < 0)
- return log_unit_error_errno(params->unit_id, r, "Failed to fork: %m");
+ return log_unit_error_errno(unit, r, "Failed to fork: %m");
if (pid == 0) {
int exit_status;
- r = exec_child(command,
+ r = exec_child(unit,
+ command,
context,
params,
runtime,
@@ -1883,21 +1909,20 @@ int exec_spawn(ExecCommand *command,
&exit_status);
if (r < 0) {
log_open();
- log_unit_struct(params->unit_id,
- LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
- "EXECUTABLE=%s", command->path,
- LOG_MESSAGE("Failed at step %s spawning %s: %s",
- exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
- command->path, strerror(-r)),
- LOG_ERRNO(r),
- NULL);
+ log_struct_errno(LOG_ERR, r,
+ LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
+ exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
+ command->path),
+ "EXECUTABLE=%s", command->path,
+ NULL);
}
_exit(exit_status);
}
- log_unit_debug(params->unit_id, "Forked %s as "PID_FMT, command->path, pid);
+ log_unit_debug(unit, "Forked %s as "PID_FMT, command->path, pid);
/* We add the new process to the cgroup both in the child (so
* that we can be sure that no user code is ever executed
@@ -1905,7 +1930,7 @@ int exec_spawn(ExecCommand *command,
* sure that when we kill the cgroup the process will be
* killed too). */
if (params->cgroup_path)
- cg_attach(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, pid);
+ (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, pid);
exec_status_start(&command->exec_status, pid);
@@ -1923,7 +1948,7 @@ void exec_context_init(ExecContext *c) {
c->syslog_level_prefix = true;
c->ignore_sigpipe = true;
c->timer_slack_nsec = NSEC_INFINITY;
- c->personality = 0xffffffffUL;
+ c->personality = PERSONALITY_INVALID;
c->runtime_directory_mode = 0755;
}
@@ -2026,7 +2051,7 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_p
/* We execute this synchronously, since we need to be
* sure this is gone when we start the service
* next. */
- rm_rf(p, false, true, false);
+ (void) rm_rf(p, REMOVE_ROOT);
}
return 0;
@@ -2069,17 +2094,17 @@ void exec_command_free_array(ExecCommand **c, unsigned n) {
}
typedef struct InvalidEnvInfo {
- const char *unit_id;
+ Unit *unit;
const char *path;
} InvalidEnvInfo;
static void invalid_env(const char *p, void *userdata) {
InvalidEnvInfo *info = userdata;
- log_unit_error(info->unit_id, "Ignoring invalid environment assignment '%s': %s", p, info->path);
+ log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
}
-int exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l) {
+int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) {
char **i, **r = NULL;
assert(c);
@@ -2137,7 +2162,7 @@ int exec_context_load_environment(const ExecContext *c, const char *unit_id, cha
/* Log invalid environment variables with filename */
if (p) {
InvalidEnvInfo info = {
- .unit_id = unit_id,
+ .unit = unit,
.path = pglob.gl_pathv[n]
};
@@ -2404,7 +2429,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sSELinuxContext: %s%s\n",
prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
- if (c->personality != 0xffffffffUL)
+ if (c->personality != PERSONALITY_INVALID)
fprintf(f,
"%sPersonality: %s\n",
prefix, strna(personality_to_string(c->personality)));
@@ -2735,17 +2760,18 @@ ExecRuntime *exec_runtime_unref(ExecRuntime *r) {
assert(r->n_ref > 0);
r->n_ref--;
- if (r->n_ref <= 0) {
- free(r->tmp_dir);
- free(r->var_tmp_dir);
- safe_close_pair(r->netns_storage_socket);
- free(r);
- }
+ if (r->n_ref > 0)
+ return NULL;
+
+ free(r->tmp_dir);
+ free(r->var_tmp_dir);
+ safe_close_pair(r->netns_storage_socket);
+ free(r);
return NULL;
}
-int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds) {
+int exec_runtime_serialize(Unit *u, ExecRuntime *rt, FILE *f, FDSet *fds) {
assert(u);
assert(f);
assert(fds);
@@ -2782,7 +2808,7 @@ int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds) {
return 0;
}
-int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds) {
+int exec_runtime_deserialize_item(Unit *u, ExecRuntime **rt, const char *key, const char *value, FDSet *fds) {
int r;
assert(rt);
@@ -2794,7 +2820,7 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
r = exec_runtime_allocate(rt);
if (r < 0)
- return r;
+ return log_oom();
copy = strdup(value);
if (!copy)
@@ -2808,7 +2834,7 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
r = exec_runtime_allocate(rt);
if (r < 0)
- return r;
+ return log_oom();
copy = strdup(value);
if (!copy)
@@ -2822,10 +2848,10 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
r = exec_runtime_allocate(rt);
if (r < 0)
- return r;
+ return log_oom();
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse netns socket value %s", value);
+ log_unit_debug(u, "Failed to parse netns socket value: %s", value);
else {
safe_close((*rt)->netns_storage_socket[0]);
(*rt)->netns_storage_socket[0] = fdset_remove(fds, fd);
@@ -2835,10 +2861,10 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
r = exec_runtime_allocate(rt);
if (r < 0)
- return r;
+ return log_oom();
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse netns socket value %s", value);
+ log_unit_debug(u, "Failed to parse netns socket value: %s", value);
else {
safe_close((*rt)->netns_storage_socket[1]);
(*rt)->netns_storage_socket[1] = fdset_remove(fds, fd);
@@ -2852,7 +2878,7 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
static void *remove_tmpdir_thread(void *p) {
_cleanup_free_ char *path = p;
- rm_rf_dangerous(path, false, true, false);
+ (void) rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL);
return NULL;
}
diff --git a/src/core/execute.h b/src/core/execute.h
index 6e0c9faa75..f5d5c1dee7 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -27,17 +27,12 @@ typedef struct ExecContext ExecContext;
typedef struct ExecRuntime ExecRuntime;
typedef struct ExecParameters ExecParameters;
-#include <linux/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
#include <sys/capability.h>
#include <stdbool.h>
#include <stdio.h>
#include <sched.h>
#include "list.h"
-#include "util.h"
-#include "set.h"
#include "fdset.h"
#include "missing.h"
#include "namespace.h"
@@ -170,7 +165,7 @@ struct ExecContext {
/* This is not exposed to the user but available
* internally. We need it to make sure that whenever we spawn
- * /bin/mount it is run in the same process group as us so
+ * /usr/bin/mount it is run in the same process group as us so
* that the autofs logic detects that it belongs to us and we
* don't enter a trigger loop. */
bool same_pgrp;
@@ -214,14 +209,14 @@ struct ExecParameters {
const char *cgroup_path;
bool cgroup_delegate;
const char *runtime_prefix;
- const char *unit_id;
usec_t watchdog_usec;
int *idle_pipe;
char *bus_endpoint_path;
int bus_endpoint_fd;
};
-int exec_spawn(ExecCommand *command,
+int exec_spawn(Unit *unit,
+ ExecCommand *command,
const ExecContext *context,
const ExecParameters *exec_params,
ExecRuntime *runtime,
@@ -247,7 +242,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_root);
-int exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l);
+int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l);
bool exec_context_may_touch_console(ExecContext *c);
bool exec_context_maintains_privileges(ExecContext *c);
@@ -260,8 +255,8 @@ int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id);
ExecRuntime *exec_runtime_ref(ExecRuntime *r);
ExecRuntime *exec_runtime_unref(ExecRuntime *r);
-int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds);
-int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds);
+int exec_runtime_serialize(Unit *unit, ExecRuntime *rt, FILE *f, FDSet *fds);
+int exec_runtime_deserialize_item(Unit *unit, ExecRuntime **rt, const char *key, const char *value, FDSet *fds);
void exec_runtime_destroy(ExecRuntime *rt);
diff --git a/src/core/failure-action.c b/src/core/failure-action.c
index ce522a4e4f..b06a7d2ae5 100644
--- a/src/core/failure-action.c
+++ b/src/core/failure-action.c
@@ -22,12 +22,12 @@
#include <sys/reboot.h>
#include <linux/reboot.h>
-#include <sys/syscall.h>
#include "bus-util.h"
#include "bus-error.h"
#include "special.h"
#include "failure-action.h"
+#include "terminal-util.h"
static void log_and_status(Manager *m, const char *message) {
log_warning("%s", message);
@@ -50,7 +50,7 @@ int failure_action(
if (action == FAILURE_ACTION_NONE)
return -ECANCELED;
- if (m->running_as == SYSTEMD_USER) {
+ if (m->running_as == MANAGER_USER) {
/* Downgrade all options to simply exiting if we run
* in user mode */
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 6664e8952c..932ddbf95a 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -19,39 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <stdlib.h>
-#include "hostname-setup.h"
#include "macro.h"
#include "util.h"
#include "log.h"
#include "fileio.h"
-
-static int read_and_strip_hostname(const char *path, char **hn) {
- char *s;
- int r;
-
- assert(path);
- assert(hn);
-
- r = read_one_line_file(path, &s);
- if (r < 0)
- return r;
-
- hostname_cleanup(s, false);
-
- if (isempty(s)) {
- free(s);
- return -ENOENT;
- }
-
- *hn = s;
- return 0;
-}
+#include "hostname-util.h"
+#include "hostname-setup.h"
int hostname_setup(void) {
int r;
@@ -59,7 +36,7 @@ int hostname_setup(void) {
const char *hn;
bool enoent = false;
- r = read_and_strip_hostname("/etc/hostname", &b);
+ r = read_hostname_config("/etc/hostname", &b);
if (r < 0) {
if (r == -ENOENT)
enoent = true;
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 0e0d16a7c9..4d8b638115 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -22,14 +22,12 @@
***/
#include <unistd.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
#include "ima-setup.h"
-#include "copy.h"
#include "util.h"
#include "log.h"
@@ -42,6 +40,8 @@ int ima_setup(void) {
#ifdef HAVE_IMA
_cleanup_close_ int policyfd = -1, imafd = -1;
+ struct stat st;
+ char *policy;
if (access(IMA_SECFS_DIR, F_OK) < 0) {
log_debug("IMA support is disabled in the kernel, ignoring.");
@@ -66,12 +66,20 @@ int ima_setup(void) {
return 0;
}
- r = copy_bytes(policyfd, imafd, (off_t) -1, false);
+ if (fstat(policyfd, &st) < 0)
+ return log_error_errno(errno, "Failed to fstat "IMA_POLICY_PATH": %m");
+
+ policy = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
+ if (policy == MAP_FAILED)
+ return log_error_errno(errno, "Failed to mmap "IMA_POLICY_PATH": %m");
+
+ r = loop_write(imafd, policy, (size_t) st.st_size, false);
if (r < 0)
log_error_errno(r, "Failed to load the IMA custom policy file "IMA_POLICY_PATH": %m");
else
log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH".");
+ munmap(policy, st.st_size);
#endif /* HAVE_IMA */
return r;
}
diff --git a/src/core/job.c b/src/core/job.c
index 4740ff18cb..8a047df0c3 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -19,10 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
-#include <sys/timerfd.h>
-#include <sys/epoll.h>
#include "sd-id128.h"
#include "sd-messages.h"
@@ -30,14 +27,13 @@
#include "unit.h"
#include "macro.h"
#include "strv.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
#include "log.h"
#include "dbus-job.h"
#include "special.h"
#include "async.h"
#include "virt.h"
#include "dbus.h"
+#include "terminal-util.h"
Job* job_new_raw(Unit *unit) {
Job *j;
@@ -197,7 +193,7 @@ Job* job_install(Job *j) {
if (uj->state == JOB_WAITING ||
(job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
job_merge_into_installed(uj, j);
- log_unit_debug(uj->unit->id,
+ log_unit_debug(uj->unit,
"Merged into installed job %s/%s as %u",
uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
return uj;
@@ -207,7 +203,7 @@ Job* job_install(Job *j) {
/* XXX It should be safer to queue j to run after uj finishes, but it is
* not currently possible to have more than one installed job per unit. */
job_merge_into_installed(uj, j);
- log_unit_debug(uj->unit->id,
+ log_unit_debug(uj->unit,
"Merged into running job, re-running: %s/%s as %u",
uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
@@ -222,7 +218,7 @@ Job* job_install(Job *j) {
j->installed = true;
j->manager->n_installed_jobs ++;
- log_unit_debug(j->unit->id,
+ log_unit_debug(j->unit,
"Installed new job %s/%s as %u",
j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
return j;
@@ -240,7 +236,7 @@ int job_install_deserialized(Job *j) {
pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
if (*pj) {
- log_unit_debug(j->unit->id, "Unit %s already has a job installed. Not installing deserialized job.", j->unit->id);
+ log_unit_debug(j->unit, "Unit already has a job installed. Not installing deserialized job.");
return -EEXIST;
}
@@ -250,7 +246,7 @@ int job_install_deserialized(Job *j) {
if (j->state == JOB_RUNNING)
j->unit->manager->n_running_jobs++;
- log_unit_debug(j->unit->id,
+ log_unit_debug(j->unit,
"Reinstalled deserialized job %s/%s as %u",
j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
return 0;
@@ -322,8 +318,8 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
* the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
* the following properties hold:
*
- * Merging is associative! A merged with B merged with C is the same as
- * A merged with C merged with B.
+ * Merging is associative! A merged with B, and then merged with C is the same
+ * as A merged with the result of B merged with C.
*
* Mergeability is transitive! If A can be merged with B and B with C then
* A also with C.
@@ -392,38 +388,38 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
}
}
-void job_type_collapse(JobType *t, Unit *u) {
+JobType job_type_collapse(JobType t, Unit *u) {
UnitActiveState s;
- switch (*t) {
+ switch (t) {
case JOB_TRY_RESTART:
s = unit_active_state(u);
if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- *t = JOB_NOP;
- else
- *t = JOB_RESTART;
- break;
+ return JOB_NOP;
+
+ return JOB_RESTART;
case JOB_RELOAD_OR_START:
s = unit_active_state(u);
if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- *t = JOB_START;
- else
- *t = JOB_RELOAD;
- break;
+ return JOB_START;
+
+ return JOB_RELOAD;
default:
- ;
+ return t;
}
}
int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
- JobType t = job_type_lookup_merge(*a, b);
+ JobType t;
+
+ t = job_type_lookup_merge(*a, b);
if (t < 0)
return -EEXIST;
- *a = t;
- job_type_collapse(a, u);
+
+ *a = job_type_collapse(t, u);
return 0;
}
@@ -489,7 +485,9 @@ static bool job_is_runnable(Job *j) {
}
static void job_change_type(Job *j, JobType newtype) {
- log_unit_debug(j->unit->id,
+ assert(j);
+
+ log_unit_debug(j->unit,
"Converting job %s/%s -> %s/%s",
j->unit->id, job_type_to_string(j->type),
j->unit->id, job_type_to_string(newtype));
@@ -578,7 +576,7 @@ int job_run_and_invalidate(Job *j) {
r = job_finish_and_invalidate(j, JOB_INVALID, true);
else if (r == -EPROTO)
r = job_finish_and_invalidate(j, JOB_ASSERT, true);
- else if (r == -ENOTSUP)
+ else if (r == -EOPNOTSUPP)
r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
else if (r == -EAGAIN)
job_set_state(j, JOB_WAITING);
@@ -679,15 +677,13 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
break;
case JOB_FAILED: {
- bool quotes;
+ _cleanup_free_ char *quoted = NULL;
- quotes = chars_intersect(u->id, SHELL_NEED_QUOTES);
+ quoted = shell_maybe_quote(u->id);
manager_flip_auto_status(u->manager, true);
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
- "See \"systemctl status %s%s%s\" for details.",
- quotes ? "'" : "", u->id, quotes ? "'" : "");
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
break;
}
@@ -770,28 +766,46 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
sd_id128_t mid;
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- log_unit_struct(u->id,
- result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(mid),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
+ log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ LOG_MESSAGE_ID(mid),
+ LOG_UNIT_ID(u),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
} else if (t == JOB_STOP)
- log_unit_struct(u->id,
- result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
+ log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
+ LOG_UNIT_ID(u),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
else if (t == JOB_RELOAD)
- log_unit_struct(u->id,
- result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
+ log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
+ LOG_UNIT_ID(u),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
+}
+
+static void job_fail_dependencies(Unit *u, UnitDependency d) {
+ Unit *other;
+ Iterator i;
+
+ assert(u);
+
+ SET_FOREACH(other, u->dependencies[d], i) {
+ Job *j = other->job;
+
+ if (!j)
+ continue;
+ if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
+ continue;
+
+ job_finish_and_invalidate(j, JOB_DEPENDENCY, true);
+ }
}
int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
@@ -809,8 +823,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
j->result = result;
- log_unit_debug(u->id, "Job %s/%s finished, result=%s",
- u->id, job_type_to_string(t), job_result_to_string(result));
+ log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
job_print_status_message(u, t, result);
job_log_status_message(u, t, result);
@@ -836,37 +849,14 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
/* Fail depending jobs on failure */
if (result != JOB_DONE && recursive) {
-
- if (t == JOB_START ||
- t == JOB_VERIFY_ACTIVE) {
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
- if (other->job &&
- !other->job->override &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- } else if (t == JOB_STOP) {
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
- }
+ if (IN_SET(t, JOB_START, JOB_VERIFY_ACTIVE)) {
+ job_fail_dependencies(u, UNIT_REQUIRED_BY);
+ job_fail_dependencies(u, UNIT_REQUISITE_OF);
+ job_fail_dependencies(u, UNIT_BOUND_BY);
+ job_fail_dependencies(u, UNIT_REQUIRED_BY_OVERRIDABLE);
+ job_fail_dependencies(u, UNIT_REQUISITE_OF_OVERRIDABLE);
+ } else if (t == JOB_STOP)
+ job_fail_dependencies(u, UNIT_CONFLICTED_BY);
}
/* Trigger OnFailure dependencies that are not generated by
@@ -874,15 +864,15 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
* this context. And JOB_FAILURE is already handled by the
* unit itself. */
if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
- log_unit_struct(u->id,
- LOG_NOTICE,
- "JOB_TYPE=%s", job_type_to_string(t),
- "JOB_RESULT=%s", job_result_to_string(result),
- LOG_MESSAGE("Job %s/%s failed with result '%s'.",
+ log_struct(LOG_NOTICE,
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_MESSAGE(u, "Job %s/%s failed with result '%s'.",
u->id,
job_type_to_string(t),
job_result_to_string(result)),
- NULL);
+ NULL);
unit_start_on_failure(u);
}
@@ -910,7 +900,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
assert(j);
assert(s == j->timer_event_source);
- log_unit_warning(j->unit->id, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
+ log_unit_warning(j->unit, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
u = j->unit;
job_finish_and_invalidate(j, JOB_TIMEOUT, true);
@@ -940,6 +930,8 @@ int job_start_timer(Job *j) {
if (r < 0)
return r;
+ (void) sd_event_source_set_description(j->timer_event_source, "job-start");
+
return 0;
}
@@ -1136,6 +1128,8 @@ int job_coldplug(Job *j) {
if (r < 0)
log_debug_errno(r, "Failed to restart timeout for job: %m");
+ (void) sd_event_source_set_description(j->timer_event_source, "job-timeout");
+
return r;
}
@@ -1153,7 +1147,7 @@ void job_shutdown_magic(Job *j) {
if (j->type != JOB_START)
return;
- if (j->unit->manager->running_as != SYSTEMD_SYSTEM)
+ if (j->unit->manager->running_as != MANAGER_SYSTEM)
return;
if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
diff --git a/src/core/job.h b/src/core/job.h
index d967b68a3f..1d1b10f1d3 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -22,8 +22,6 @@
***/
#include <stdbool.h>
-#include <inttypes.h>
-#include <errno.h>
typedef struct Job Job;
typedef struct JobDependency JobDependency;
@@ -108,9 +106,7 @@ enum JobResult {
};
#include "sd-event.h"
-#include "manager.h"
#include "unit.h"
-#include "hashmap.h"
#include "list.h"
struct JobDependency {
@@ -210,7 +206,7 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
/* Collapses a state-dependent job type into a simpler type by observing
* the state of the unit which it is going to be applied to. */
-void job_type_collapse(JobType *t, Unit *u);
+JobType job_type_collapse(JobType t, Unit *u);
int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u);
diff --git a/src/core/kill.c b/src/core/kill.c
index 4271346511..2de71c6bf9 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -19,10 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-
-#include "kill.h"
#include "util.h"
+#include "signal-util.h"
+#include "kill.h"
void kill_context_init(KillContext *c) {
assert(c);
diff --git a/src/core/killall.c b/src/core/killall.c
index 5a50ae6f04..6e85923581 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -25,9 +25,11 @@
#include <unistd.h>
#include "util.h"
-#include "def.h"
#include "killall.h"
#include "set.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
#define TIMEOUT_USEC (10 * USEC_PER_SEC)
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index c0a05b97aa..6cc5951719 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -19,18 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
-#include <errno.h>
#ifdef HAVE_KMOD
#include <libkmod.h>
#endif
#include "macro.h"
-#include "execute.h"
#include "capability.h"
+#include "bus-util.h"
#include "kmod-setup.h"
#ifdef HAVE_KMOD
@@ -47,10 +45,6 @@ static void systemd_kmod_log(
log_internalv(LOG_DEBUG, 0, file, line, fn, format, args);
REENABLE_WARNING;
}
-
-static bool cmdline_check_kdbus(void) {
- return get_proc_cmdline_key("kdbus", NULL) > 0;
-}
#endif
int kmod_setup(void) {
@@ -63,16 +57,23 @@ int kmod_setup(void) {
bool (*condition_fn)(void);
} kmod_table[] = {
/* auto-loading on use doesn't work before udev is up */
- { "autofs4", "/sys/class/misc/autofs", true, NULL },
+ { "autofs4", "/sys/class/misc/autofs", true, NULL },
/* early configure of ::1 on the loopback device */
- { "ipv6", "/sys/module/ipv6", true, NULL },
+ { "ipv6", "/sys/module/ipv6", true, NULL },
/* this should never be a module */
- { "unix", "/proc/net/unix", true, NULL },
+ { "unix", "/proc/net/unix", true, NULL },
+#ifdef ENABLE_KDBUS
/* IPC is needed before we bring up any other services */
- { "kdbus", "/sys/fs/kdbus", false, cmdline_check_kdbus },
+ { "kdbus", "/sys/fs/kdbus", false, is_kdbus_wanted },
+#endif
+
+#ifdef HAVE_LIBIPTC
+ /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */
+ { "ip_tables", "/proc/net/ip_tables_names", false, NULL },
+#endif
};
struct kmod_ctx *ctx = NULL;
unsigned int i;
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 8be190040e..11566af51b 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
-#include <errno.h>
#include "unit.h"
#include "load-dropin.h"
@@ -29,7 +27,6 @@
#include "unit-name.h"
#include "conf-parser.h"
#include "load-fragment.h"
-#include "conf-files.h"
static int add_dependency_consumer(
UnitDependency dependency,
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 53059845e3..66c9145aa6 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -318,6 +318,7 @@ KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
m4_dnl
Automount.Where, config_parse_path, 0, offsetof(Automount, where)
Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode)
+Automount.TimeoutIdleSec, config_parse_sec, 0, offsetof(Automount, timeout_idle_usec)
m4_dnl
Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what)
Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 90bf5634c8..df5fe6fb32 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -21,26 +21,18 @@
***/
#include <linux/oom.h>
-#include <assert.h>
#include <errno.h>
#include <string.h>
-#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
-#include <sys/prctl.h>
-#include <sys/mount.h>
#include <linux/fs.h>
#include <sys/stat.h>
-#include <sys/time.h>
#include <sys/resource.h>
-#include <sys/types.h>
-#include <grp.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
-#include "sd-messages.h"
#include "unit.h"
#include "strv.h"
#include "conf-parser.h"
@@ -60,6 +52,7 @@
#include "errno-list.h"
#include "af-list.h"
#include "cap-list.h"
+#include "signal-util.h"
#include "bus-internal.h"
#ifdef HAVE_SECCOMP
@@ -364,7 +357,7 @@ int config_parse_socket_listen(const char *unit,
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
- r = socket_address_parse(&p->address, k ? k : rvalue);
+ r = socket_address_parse_and_warn(&p->address, k ? k : rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, -r,
"Failed to parse address value, ignoring: %s", rvalue);
@@ -381,7 +374,7 @@ int config_parse_socket_listen(const char *unit,
}
if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
- log_syntax(unit, LOG_ERR, filename, line, ENOTSUP,
+ log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
"Address family not supported, ignoring: %s", rvalue);
return 0;
}
@@ -515,16 +508,17 @@ int config_parse_exec_oom_score_adjust(const char* unit,
return 0;
}
-int config_parse_exec(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_exec(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
ExecCommand **e = data, *nce;
char *path, **n;
@@ -576,15 +570,13 @@ int config_parse_exec(const char *unit,
word ++;
}
}
- } else
- if (strneq(word, ";", MAX(l, 1U)))
- goto found;
+ } else if (strneq(word, ";", MAX(l, 1U)))
+ goto found;
k++;
}
if (!isempty(state)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
return 0;
}
@@ -604,7 +596,12 @@ int config_parse_exec(const char *unit,
skip = separate_argv0 + ignore;
/* skip special chars in the beginning */
- assert(skip < l);
+ if (l <= skip) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Empty path in command line, ignoring: \"%s\"", rvalue);
+ r = 0;
+ goto fail;
+ }
} else if (strneq(word, ";", MAX(l, 1U)))
/* new commandline */
@@ -613,9 +610,10 @@ int config_parse_exec(const char *unit,
else
skip = strneq(word, "\\;", MAX(l, 1U));
- c = cunescape_length(word + skip, l - skip);
- if (!c) {
- r = log_oom();
+ r = cunescape_length(word + skip, l - skip, UNESCAPE_RELAX, &c);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to unescape command line, ignoring: %s", rvalue);
+ r = 0;
goto fail;
}
@@ -634,8 +632,6 @@ int config_parse_exec(const char *unit,
n[k] = NULL;
- log_debug("path: %s", path ?: n[0]);
-
if (!n[0])
reason = "Empty executable name or zeroeth argument";
else if (!string_is_safe(path ?: n[0]))
@@ -647,8 +643,7 @@ int config_parse_exec(const char *unit,
else
goto ok;
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "%s, ignoring: %s", reason, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "%s, ignoring: %s", reason, rvalue);
r = 0;
goto fail;
@@ -1213,17 +1208,15 @@ int config_parse_exec_mount_flags(const char *unit,
flags = MS_SHARED;
else if (streq(t, "slave"))
flags = MS_SLAVE;
- else if (streq(word, "private"))
+ else if (streq(t, "private"))
flags = MS_PRIVATE;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
return 0;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
c->mount_flags = flags;
return 0;
@@ -1986,8 +1979,7 @@ int config_parse_environ(const char *unit,
if (u) {
r = unit_full_printf(u, rvalue, &k);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
}
if (!k)
@@ -1999,13 +1991,14 @@ int config_parse_environ(const char *unit,
_cleanup_free_ char *n;
char **x;
- n = cunescape_length(word, l);
- if (!n)
- return log_oom();
+ r = cunescape_length(word, l, 0, &n);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
+ continue;
+ }
if (!env_assignment_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid environment assignment, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
continue;
}
@@ -2380,7 +2373,7 @@ int config_parse_syscall_filter(
continue;
r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == -EEXIST)
+ if (r == 0)
continue;
if (r < 0)
return log_oom();
@@ -2408,7 +2401,7 @@ int config_parse_syscall_filter(
*/
if (!invert == c->syscall_whitelist) {
r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == -EEXIST)
+ if (r == 0)
continue;
if (r < 0)
return log_oom();
@@ -2421,7 +2414,7 @@ int config_parse_syscall_filter(
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
- if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
+ if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
c->no_new_privileges = true;
return 0;
@@ -2470,7 +2463,7 @@ int config_parse_syscall_archs(
}
r = set_put(*archs, UINT32_TO_PTR(a + 1));
- if (r == -EEXIST)
+ if (r == 0)
continue;
if (r < 0)
return log_oom();
@@ -2581,7 +2574,7 @@ int config_parse_address_families(
*/
if (!invert == c->address_families_whitelist) {
r = set_put(c->address_families, INT_TO_PTR(af));
- if (r == -EEXIST)
+ if (r == 0)
continue;
if (r < 0)
return log_oom();
@@ -3054,7 +3047,7 @@ int config_parse_personality(
assert(personality);
p = personality_from_string(rvalue);
- if (p == 0xffffffffUL) {
+ if (p == PERSONALITY_INVALID) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Failed to parse personality, ignoring: %s", rvalue);
return 0;
@@ -3407,7 +3400,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
* unit name. */
name = basename(*filename);
- if (unit_name_is_valid(name, TEMPLATE_VALID)) {
+ if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
id = set_get(names, name);
if (!id) {
@@ -3440,9 +3433,8 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
f = fdopen(fd, "re");
if (!f) {
- r = -errno;
safe_close(fd);
- return r;
+ return -errno;
}
*_f = f;
@@ -3656,11 +3648,11 @@ int unit_load_fragment(Unit *u) {
/* Look for a template */
if (u->load_state == UNIT_STUB && u->instance) {
- _cleanup_free_ char *k;
+ _cleanup_free_ char *k = NULL;
- k = unit_name_template(u->id);
- if (!k)
- return -ENOMEM;
+ r = unit_name_template(u->id, &k);
+ if (r < 0)
+ return r;
r = load_from_path(u, k);
if (r < 0)
@@ -3673,9 +3665,9 @@ int unit_load_fragment(Unit *u) {
if (t == u->id)
continue;
- z = unit_name_template(t);
- if (!z)
- return -ENOMEM;
+ r = unit_name_template(t, &z);
+ if (r < 0)
+ return r;
r = load_from_path(u, z);
if (r < 0)
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
index e993c57321..108072ca9f 100644
--- a/src/core/locale-setup.c
+++ b/src/core/locale-setup.c
@@ -19,13 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "locale-setup.h"
#include "util.h"
-#include "macro.h"
#include "virt.h"
#include "fileio.h"
#include "strv.h"
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
index 67ce160c19..63b15c1200 100644
--- a/src/core/loopback-setup.c
+++ b/src/core/loopback-setup.c
@@ -19,18 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <net/if.h>
-#include <asm/types.h>
-#include <netinet/in.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
#include "sd-rtnl.h"
-#include "util.h"
-#include "macro.h"
-#include "socket-util.h"
#include "rtnl-util.h"
#include "missing.h"
#include "loopback-setup.h"
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index d00a53246f..b3d22840cf 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -23,7 +23,6 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
-#include <stdlib.h>
#include <fcntl.h>
#include <sys/mount.h>
@@ -37,10 +36,17 @@
#include "virt.h"
#include "fileio.h"
#include "path-util.h"
+#include "process-util.h"
static int shorten_uuid(char destination[34], const char source[36]) {
unsigned i, j;
+ assert(destination);
+ assert(source);
+
+ /* Converts a UUID into a machine ID, by lowercasing it and
+ * removing dashes. Validates everything. */
+
for (i = 0, j = 0; i < 36 && j < 32; i++) {
int t;
@@ -51,21 +57,57 @@ static int shorten_uuid(char destination[34], const char source[36]) {
destination[j++] = hexchar(t);
}
- if (i == 36 && j == 32) {
- destination[32] = '\n';
- destination[33] = 0;
- return 0;
- }
+ if (i != 36 || j != 32)
+ return -EINVAL;
+
+ destination[32] = '\n';
+ destination[33] = 0;
+ return 0;
+}
+
+static int read_machine_id(int fd, char id[34]) {
+ char id_to_validate[34];
+ int r;
+
+ assert(fd >= 0);
+ assert(id);
- return -EINVAL;
+ /* Reads a machine ID from a file, validates it, and returns
+ * it. The returned ID ends in a newline. */
+
+ r = loop_read_exact(fd, id_to_validate, 33, false);
+ if (r < 0)
+ return r;
+
+ if (id_to_validate[32] != '\n')
+ return -EINVAL;
+
+ id_to_validate[32] = 0;
+
+ if (!id128_is_valid(id_to_validate))
+ return -EINVAL;
+
+ memcpy(id, id_to_validate, 32);
+ id[32] = '\n';
+ id[33] = 0;
+ return 0;
}
-static int generate(char id[34], const char *root) {
+static int write_machine_id(int fd, char id[34]) {
+ assert(fd >= 0);
+ assert(id);
+
+ if (lseek(fd, 0, SEEK_SET) < 0)
+ return -errno;
+
+ return loop_write(fd, id, 33, false);
+}
+
+static int generate_machine_id(char id[34], const char *root) {
int fd, r;
unsigned char *p;
sd_id128_t buf;
char *q;
- ssize_t k;
const char *vm_id, *dbus_machine_id;
assert(id);
@@ -78,19 +120,12 @@ static int generate(char id[34], const char *root) {
/* First, try reading the D-Bus machine id, unless it is a symlink */
fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd >= 0) {
- k = loop_read(fd, id, 33, false);
+ r = read_machine_id(fd, id);
safe_close(fd);
- if (k == 33 && id[32] == '\n') {
-
- id[32] = 0;
- if (id128_is_valid(id)) {
- id[32] = '\n';
- id[33] = 0;
-
- log_info("Initializing machine ID from D-Bus machine ID.");
- return 0;
- }
+ if (r >= 0) {
+ log_info("Initializing machine ID from D-Bus machine ID.");
+ return 0;
}
}
@@ -104,12 +139,10 @@ static int generate(char id[34], const char *root) {
r = getenv_for_pid(1, "container_uuid", &e);
if (r > 0) {
- if (strlen(e) >= 36) {
- r = shorten_uuid(id, e);
- if (r >= 0) {
- log_info("Initializing machine ID from container UUID.");
- return 0;
- }
+ r = shorten_uuid(id, e);
+ if (r >= 0) {
+ log_info("Initializing machine ID from container UUID.");
+ return 0;
}
}
@@ -120,14 +153,14 @@ static int generate(char id[34], const char *root) {
r = detect_vm(&vm_id);
if (r > 0 && streq(vm_id, "kvm")) {
- char uuid[37];
+ char uuid[36];
fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd >= 0) {
- k = loop_read(fd, uuid, 36, false);
+ r = loop_read_exact(fd, uuid, 36, false);
safe_close(fd);
- if (k >= 36) {
+ if (r >= 0) {
r = shorten_uuid(id, uuid);
if (r >= 0) {
log_info("Initializing machine ID from KVM UUID.");
@@ -157,35 +190,96 @@ static int generate(char id[34], const char *root) {
return 0;
}
-static int get_valid_machine_id(int fd, char id[34]) {
- char id_to_validate[34];
+int machine_id_setup(const char *root) {
+ const char *etc_machine_id, *run_machine_id;
+ _cleanup_close_ int fd = -1;
+ bool writable = true;
+ char id[34]; /* 32 + \n + \0 */
+ int r;
- assert(fd >= 0);
- assert(id);
+ if (isempty(root)) {
+ etc_machine_id = "/etc/machine-id";
+ run_machine_id = "/run/machine-id";
+ } else {
+ char *x;
- if (loop_read(fd, id_to_validate, 33, false) == 33 && id_to_validate[32] == '\n') {
- id_to_validate[32] = 0;
+ x = strjoina(root, "/etc/machine-id");
+ etc_machine_id = path_kill_slashes(x);
- if (id128_is_valid(id_to_validate)) {
- memcpy(id, id_to_validate, 32);
- id[32] = '\n';
- id[33] = 0;
- return 0;
- }
+ x = strjoina(root, "/run/machine-id");
+ run_machine_id = path_kill_slashes(x);
}
- return -EINVAL;
-}
+ RUN_WITH_UMASK(0000) {
+ /* We create this 0444, to indicate that this isn't really
+ * something you should ever modify. Of course, since the file
+ * will be owned by root it doesn't matter much, but maybe
+ * people look. */
-static int write_machine_id(int fd, char id[34]) {
- assert(fd >= 0);
- assert(id);
- lseek(fd, 0, SEEK_SET);
+ mkdir_parents(etc_machine_id, 0755);
+ fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
+ if (fd < 0) {
+ int old_errno = errno;
+
+ fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0) {
+ if (old_errno == EROFS && errno == ENOENT)
+ log_error_errno(errno,
+ "System cannot boot: Missing /etc/machine-id and /etc is mounted read-only.\n"
+ "Booting up is supported only when:\n"
+ "1) /etc/machine-id exists and is populated.\n"
+ "2) /etc/machine-id exists and is empty.\n"
+ "3) /etc/machine-id is missing and /etc is writable.\n");
+ else
+ log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
- if (loop_write(fd, id, 33, false) == 0)
+ return -errno;
+ }
+
+ writable = false;
+ }
+ }
+
+ if (read_machine_id(fd, id) >= 0)
return 0;
- return -errno;
+ /* Hmm, so, the id currently stored is not useful, then let's
+ * generate one */
+
+ r = generate_machine_id(id, root);
+ if (r < 0)
+ return r;
+
+ if (writable)
+ if (write_machine_id(fd, id) >= 0)
+ return 0;
+
+ fd = safe_close(fd);
+
+ /* Hmm, we couldn't write it? So let's write it to
+ * /run/machine-id as a replacement */
+
+ RUN_WITH_UMASK(0022) {
+ r = write_string_file(run_machine_id, id);
+ }
+ if (r < 0) {
+ (void) unlink(run_machine_id);
+ return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
+ }
+
+ /* And now, let's mount it over */
+ if (mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL) < 0) {
+ (void) unlink_noerrno(run_machine_id);
+ return log_error_errno(errno, "Failed to mount %s: %m", etc_machine_id);
+ }
+
+ log_info("Installed transient %s file.", etc_machine_id);
+
+ /* Mark the mount read-only */
+ if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
+ log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id);
+
+ return 0;
}
int machine_id_commit(const char *root) {
@@ -203,7 +297,7 @@ int machine_id_commit(const char *root) {
etc_machine_id = path_kill_slashes(x);
}
- r = path_is_mount_point(etc_machine_id, false);
+ r = path_is_mount_point(etc_machine_id, 0);
if (r < 0)
return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id);
if (r == 0) {
@@ -216,11 +310,11 @@ int machine_id_commit(const char *root) {
if (fd < 0)
return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
- r = get_valid_machine_id(fd, id);
+ r = read_machine_id(fd, id);
if (r < 0)
return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
- r = is_fd_on_temporary_fs(fd);
+ r = fd_is_temporary_fs(fd);
if (r < 0)
return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
if (r == 0) {
@@ -266,100 +360,3 @@ int machine_id_commit(const char *root) {
return 0;
}
-
-int machine_id_setup(const char *root) {
- const char *etc_machine_id, *run_machine_id;
- _cleanup_close_ int fd = -1;
- bool writable = true;
- struct stat st;
- char id[34]; /* 32 + \n + \0 */
- int r;
-
- if (isempty(root)) {
- etc_machine_id = "/etc/machine-id";
- run_machine_id = "/run/machine-id";
- } else {
- char *x;
-
- x = strjoina(root, "/etc/machine-id");
- etc_machine_id = path_kill_slashes(x);
-
- x = strjoina(root, "/run/machine-id");
- run_machine_id = path_kill_slashes(x);
- }
-
- RUN_WITH_UMASK(0000) {
- /* We create this 0444, to indicate that this isn't really
- * something you should ever modify. Of course, since the file
- * will be owned by root it doesn't matter much, but maybe
- * people look. */
-
- mkdir_parents(etc_machine_id, 0755);
- fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
- if (fd < 0) {
- int old_errno = errno;
-
- fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- if (old_errno == EROFS && errno == ENOENT)
- log_error("System cannot boot: Missing /etc/machine-id and /etc is mounted read-only.\n"
- "Booting up is supported only when:\n"
- "1) /etc/machine-id exists and is populated.\n"
- "2) /etc/machine-id exists and is empty.\n"
- "3) /etc/machine-id is missing and /etc is writable.\n");
- else
- log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
- return -errno;
- }
-
- writable = false;
- }
- }
-
- if (fstat(fd, &st) < 0)
- return log_error_errno(errno, "fstat() failed: %m");
-
- if (S_ISREG(st.st_mode) && get_valid_machine_id(fd, id) == 0)
- return 0;
-
- /* Hmm, so, the id currently stored is not useful, then let's
- * generate one */
-
- r = generate(id, root);
- if (r < 0)
- return r;
-
- if (S_ISREG(st.st_mode) && writable)
- if (write_machine_id(fd, id) == 0)
- return 0;
-
- fd = safe_close(fd);
-
- /* Hmm, we couldn't write it? So let's write it to
- * /run/machine-id as a replacement */
-
- RUN_WITH_UMASK(0022) {
- r = write_string_file(run_machine_id, id);
- }
- if (r < 0) {
- log_error_errno(r, "Cannot write %s: %m", run_machine_id);
- unlink(run_machine_id);
- return r;
- }
-
- /* And now, let's mount it over */
- r = mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL);
- if (r < 0) {
- log_error_errno(errno, "Failed to mount %s: %m", etc_machine_id);
- unlink_noerrno(run_machine_id);
- return -errno;
- }
-
- log_info("Installed transient %s file.", etc_machine_id);
-
- /* Mark the mount read-only */
- if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
- log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id);
-
- return 0;
-}
diff --git a/src/core/main.c b/src/core/main.c
index ba2de85bd3..674e47e788 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -23,11 +23,9 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <signal.h>
-#include <sys/wait.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/mount.h>
@@ -40,14 +38,12 @@
#endif
#include "sd-daemon.h"
-#include "sd-messages.h"
#include "sd-bus.h"
#include "log.h"
#include "fdset.h"
#include "special.h"
#include "conf-parser.h"
#include "missing.h"
-#include "label.h"
#include "pager.h"
#include "build.h"
#include "strv.h"
@@ -55,7 +51,6 @@
#include "virt.h"
#include "architecture.h"
#include "watchdog.h"
-#include "path-util.h"
#include "switch-root.h"
#include "capability.h"
#include "killall.h"
@@ -65,6 +60,10 @@
#include "bus-error.h"
#include "bus-util.h"
#include "selinux-util.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
#include "manager.h"
#include "dbus-manager.h"
#include "load-fragment.h"
@@ -87,7 +86,7 @@ static enum {
ACTION_DONE
} arg_action = ACTION_RUN;
static char *arg_default_unit = NULL;
-static SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
+static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
static bool arg_dump_core = true;
static bool arg_crash_shell = false;
static int arg_crash_chvt = -1;
@@ -161,7 +160,7 @@ noreturn static void crash(int sig) {
setrlimit(RLIMIT_CORE, &rl);
/* Just to be sure... */
- chdir("/");
+ (void) chdir("/");
/* Raise the signal again */
pid = raw_getpid();
@@ -280,10 +279,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
"s", SPECIAL_RESCUE_TARGET,
"S", SPECIAL_RESCUE_TARGET,
"1", SPECIAL_RESCUE_TARGET,
- "2", SPECIAL_RUNLEVEL2_TARGET,
- "3", SPECIAL_RUNLEVEL3_TARGET,
- "4", SPECIAL_RUNLEVEL4_TARGET,
- "5", SPECIAL_RUNLEVEL5_TARGET,
+ "2", SPECIAL_MULTI_USER_TARGET,
+ "3", SPECIAL_MULTI_USER_TARGET,
+ "4", SPECIAL_MULTI_USER_TARGET,
+ "5", SPECIAL_GRAPHICAL_TARGET,
};
int r;
@@ -473,7 +472,7 @@ static int config_parse_cpu_affinity2(
if (c) {
if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
- log_unit_warning(unit, "Failed to set CPU affinity: %m");
+ log_warning("Failed to set CPU affinity: %m");
CPU_FREE(c);
}
@@ -678,8 +677,8 @@ static int parse_config_file(void) {
const char *fn, *conf_dirs_nulstr;
- fn = arg_running_as == SYSTEMD_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
- conf_dirs_nulstr = arg_running_as == SYSTEMD_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
+ fn = arg_running_as == MANAGER_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
+ conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
config_item_table_lookup, items, false, NULL);
@@ -816,11 +815,11 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_SYSTEM:
- arg_running_as = SYSTEMD_SYSTEM;
+ arg_running_as = MANAGER_SYSTEM;
break;
case ARG_USER:
- arg_running_as = SYSTEMD_USER;
+ arg_running_as = MANAGER_USER;
break;
case ARG_TEST:
@@ -1277,7 +1276,7 @@ int main(int argc, char *argv[]) {
if (getpid() == 1 && detect_container(NULL) <= 0) {
/* Running outside of a container as PID 1 */
- arg_running_as = SYSTEMD_SYSTEM;
+ arg_running_as = MANAGER_SYSTEM;
make_null_stdio();
log_set_target(LOG_TARGET_KMSG);
log_open();
@@ -1351,7 +1350,7 @@ int main(int argc, char *argv[]) {
} else if (getpid() == 1) {
/* Running inside a container, as PID 1 */
- arg_running_as = SYSTEMD_SYSTEM;
+ arg_running_as = MANAGER_SYSTEM;
log_set_target(LOG_TARGET_CONSOLE);
log_close_console(); /* force reopen of /dev/console */
log_open();
@@ -1366,7 +1365,7 @@ int main(int argc, char *argv[]) {
} else {
/* Running as user instance */
- arg_running_as = SYSTEMD_USER;
+ arg_running_as = MANAGER_USER;
log_set_target(LOG_TARGET_AUTO);
log_open();
@@ -1386,7 +1385,7 @@ int main(int argc, char *argv[]) {
r = initialize_join_controllers();
if (r < 0) {
- error_message = "Failed to initalize cgroup controllers";
+ error_message = "Failed to initialize cgroup controllers";
goto finish;
}
@@ -1415,7 +1414,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == SYSTEMD_SYSTEM) {
+ if (arg_running_as == MANAGER_SYSTEM) {
r = parse_proc_cmdline(parse_proc_cmdline_item);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
@@ -1436,14 +1435,14 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == SYSTEMD_USER &&
+ if (arg_running_as == MANAGER_USER &&
arg_action == ACTION_RUN &&
sd_booted() <= 0) {
log_error("Trying to run as user instance, but the system has not been booted with systemd.");
goto finish;
}
- if (arg_running_as == SYSTEMD_SYSTEM &&
+ if (arg_running_as == MANAGER_SYSTEM &&
arg_action == ACTION_RUN &&
running_in_chroot() > 0) {
log_error("Cannot be run in a chroot() environment.");
@@ -1470,7 +1469,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == SYSTEMD_USER &&
+ if (arg_running_as == MANAGER_USER &&
!getenv("XDG_RUNTIME_DIR")) {
log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
goto finish;
@@ -1493,16 +1492,16 @@ int main(int argc, char *argv[]) {
if (arg_serialization)
assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
- if (arg_running_as == SYSTEMD_SYSTEM)
+ if (arg_running_as == MANAGER_SYSTEM)
/* Become a session leader if we aren't one yet. */
setsid();
/* Move out of the way, so that we won't block unmounts */
- assert_se(chdir("/") == 0);
+ assert_se(chdir("/") == 0);
/* Reset the console, but only if this is really init and we
* are freshly booted */
- if (arg_running_as == SYSTEMD_SYSTEM && arg_action == ACTION_RUN) {
+ if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) {
/* If we are init, we connect stdin/stdout/stderr to
* /dev/null and make sure we don't have a controlling
@@ -1529,7 +1528,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == SYSTEMD_SYSTEM) {
+ if (arg_running_as == MANAGER_SYSTEM) {
const char *virtualization = NULL;
log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
@@ -1537,11 +1536,11 @@ int main(int argc, char *argv[]) {
detect_virtualization(&virtualization);
if (virtualization)
- log_info("Detected virtualization '%s'.", virtualization);
+ log_info("Detected virtualization %s.", virtualization);
write_container_id();
- log_info("Detected architecture '%s'.", architecture_to_string(uname_architecture()));
+ log_info("Detected architecture %s.", architecture_to_string(uname_architecture()));
if (in_initrd())
log_info("Running in initial RAM disk.");
@@ -1565,8 +1564,8 @@ int main(int argc, char *argv[]) {
arg_action == ACTION_TEST ? " test" : "", getuid(), t);
}
- if (arg_running_as == SYSTEMD_SYSTEM && !skip_setup) {
- if (arg_show_status > 0 || plymouth_running())
+ if (arg_running_as == MANAGER_SYSTEM && !skip_setup) {
+ if (arg_show_status > 0)
status_welcome();
hostname_setup();
@@ -1577,7 +1576,7 @@ int main(int argc, char *argv[]) {
test_usr();
}
- if (arg_running_as == SYSTEMD_SYSTEM && arg_runtime_watchdog > 0)
+ if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0)
watchdog_set_timeout(&arg_runtime_watchdog);
if (arg_timer_slack_nsec != NSEC_INFINITY)
@@ -1607,7 +1606,7 @@ int main(int argc, char *argv[]) {
}
}
- if (arg_running_as == SYSTEMD_USER) {
+ if (arg_running_as == MANAGER_USER) {
/* Become reaper of our children */
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
log_warning_errno(errno, "Failed to make us a subreaper: %m");
@@ -1616,11 +1615,11 @@ int main(int argc, char *argv[]) {
}
}
- if (arg_running_as == SYSTEMD_SYSTEM) {
+ if (arg_running_as == MANAGER_SYSTEM) {
bump_rlimit_nofile(&saved_rlimit_nofile);
if (empty_etc) {
- r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_FULL, false, NULL, 0);
+ r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, false, NULL, 0);
if (r < 0)
log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m");
else
@@ -1897,7 +1896,7 @@ finish:
args[i++] = SYSTEMD_BINARY_PATH;
if (switch_root_dir)
args[i++] = "--switched-root";
- args[i++] = arg_running_as == SYSTEMD_SYSTEM ? "--system" : "--user";
+ args[i++] = arg_running_as == MANAGER_SYSTEM ? "--system" : "--user";
args[i++] = "--deserialize";
args[i++] = sfd;
args[i++] = NULL;
diff --git a/src/core/manager.c b/src/core/manager.c
index 4775219e4a..a1c54339ea 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
@@ -27,14 +26,10 @@
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/epoll.h>
-#include <poll.h>
#include <sys/reboot.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
-#include <termios.h>
#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <sys/timerfd.h>
@@ -43,11 +38,8 @@
#endif
#include "sd-daemon.h"
-#include "sd-id128.h"
#include "sd-messages.h"
-#include "manager.h"
-#include "transaction.h"
#include "hashmap.h"
#include "macro.h"
#include "strv.h"
@@ -56,15 +48,14 @@
#include "mkdir.h"
#include "ratelimit.h"
#include "locale-setup.h"
-#include "mount-setup.h"
#include "unit-name.h"
#include "missing.h"
+#include "rm-rf.h"
#include "path-lookup.h"
#include "special.h"
#include "exit-status.h"
#include "virt.h"
#include "watchdog.h"
-#include "cgroup-util.h"
#include "path-util.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
@@ -72,12 +63,17 @@
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "bus-kernel.h"
+#include "time-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
#include "dbus.h"
#include "dbus-unit.h"
#include "dbus-job.h"
#include "dbus-manager.h"
-#include "bus-kernel.h"
-#include "time-util.h"
+#include "manager.h"
+#include "transaction.h"
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -93,21 +89,26 @@ static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
static int manager_run_generators(Manager *m);
static void manager_undo_generators(Manager *m);
-static int manager_watch_jobs_in_progress(Manager *m) {
+static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
+ int r;
assert(m);
if (m->jobs_in_progress_event_source)
- return 0;
+ return;
next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
- return sd_event_add_time(
+ r = sd_event_add_time(
m->event,
&m->jobs_in_progress_event_source,
CLOCK_MONOTONIC,
next, 0,
manager_dispatch_jobs_in_progress, m);
+ if (r < 0)
+ return;
+
+ (void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
}
#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
@@ -186,8 +187,10 @@ static void manager_print_jobs_in_progress(Manager *m) {
m->jobs_in_progress_iteration++;
- if (m->n_running_jobs > 1)
- asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs);
+ if (m->n_running_jobs > 1) {
+ if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
+ job_of_n = NULL;
+ }
format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
if (job_get_timeout(j, &x) > 0)
@@ -281,6 +284,8 @@ static int manager_check_ask_password(Manager *m) {
return -errno;
}
+ (void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
+
/* Queries might have been added meanwhile... */
manager_dispatch_ask_password_fd(m->ask_password_event_source,
m->ask_password_inotify_fd, EPOLLIN, m);
@@ -304,6 +309,8 @@ static int manager_watch_idle_pipe(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to watch idle pipe: %m");
+ (void) sd_event_source_set_description(m->idle_pipe_event_source, "manager-idle-pipe");
+
return 0;
}
@@ -346,6 +353,8 @@ static int manager_setup_time_change(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to create time change event source: %m");
+ (void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
+
log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
return 0;
@@ -456,6 +465,8 @@ static int manager_setup_signals(Manager *m) {
if (r < 0)
return r;
+ (void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
+
/* Process signals a bit earlier than the rest of things, but
* later than notify_fd processing, so that the notify
* processing can still figure out to which process/service a
@@ -464,7 +475,7 @@ static int manager_setup_signals(Manager *m) {
if (r < 0)
return r;
- if (m->running_as == SYSTEMD_SYSTEM)
+ if (m->running_as == MANAGER_SYSTEM)
return enable_special_signals(m);
return 0;
@@ -490,7 +501,7 @@ static void manager_clean_environment(Manager *m) {
static int manager_default_environment(Manager *m) {
assert(m);
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
/* The system manager always starts with a clean
* environment for its children. It does not import
* the kernel or the parents exported variables.
@@ -518,20 +529,32 @@ static int manager_default_environment(Manager *m) {
return 0;
}
-int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
+
+int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
+
+ static const char * const unit_log_fields[_MANAGER_RUNNING_AS_MAX] = {
+ [MANAGER_SYSTEM] = "UNIT=",
+ [MANAGER_USER] = "USER_UNIT=",
+ };
+
+ static const char * const unit_log_format_strings[_MANAGER_RUNNING_AS_MAX] = {
+ [MANAGER_SYSTEM] = "UNIT=%s",
+ [MANAGER_USER] = "USER_UNIT=%s",
+ };
+
Manager *m;
int r;
assert(_m);
assert(running_as >= 0);
- assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
+ assert(running_as < _MANAGER_RUNNING_AS_MAX);
m = new0(Manager, 1);
if (!m)
return -ENOMEM;
#ifdef ENABLE_EFI
- if (running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
+ if (running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0)
boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
#endif
@@ -539,6 +562,10 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
+ /* Prepare log fields we can use for structured logging */
+ m->unit_log_field = unit_log_fields[running_as];
+ m->unit_log_format_string = unit_log_format_strings[running_as];
+
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
@@ -596,6 +623,8 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
if (r < 0)
goto fail;
+ (void) sd_event_source_set_description(m->run_queue_event_source, "manager-run-queue");
+
r = manager_setup_signals(m);
if (r < 0)
goto fail;
@@ -650,7 +679,7 @@ static int manager_setup_notify(Manager *m) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate notification socket: %m");
- if (m->running_as == SYSTEMD_SYSTEM)
+ if (m->running_as == MANAGER_SYSTEM)
m->notify_socket = strdup("/run/systemd/notify");
else {
const char *e;
@@ -694,6 +723,8 @@ static int manager_setup_notify(Manager *m) {
r = sd_event_source_set_priority(m->notify_event_source, -7);
if (r < 0)
return log_error_errno(r, "Failed to set priority of notify event source: %m");
+
+ (void) sd_event_source_set_description(m->notify_event_source, "manager-notify");
}
return 0;
@@ -707,13 +738,12 @@ static int manager_setup_kdbus(Manager *m) {
if (m->test_run || m->kdbus_fd >= 0)
return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
- bus_kernel_fix_attach_mask();
+ if (!is_kdbus_available())
+ return -ESOCKTNOSUPPORT;
m->kdbus_fd = bus_kernel_create_bus(
- m->running_as == SYSTEMD_SYSTEM ? "system" : "user",
- m->running_as == SYSTEMD_SYSTEM, &p);
+ m->running_as == MANAGER_SYSTEM ? "system" : "user",
+ m->running_as == MANAGER_SYSTEM, &p);
if (m->kdbus_fd < 0)
return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
@@ -735,9 +765,9 @@ static int manager_connect_bus(Manager *m, bool reexecuting) {
try_bus_connect =
m->kdbus_fd >= 0 ||
reexecuting ||
- (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
+ (m->running_as == MANAGER_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
- /* Try to connect to the busses, if possible. */
+ /* Try to connect to the buses, if possible. */
return bus_init(m, try_bus_connect);
}
@@ -844,7 +874,8 @@ static unsigned manager_dispatch_gc_queue(Manager *m) {
if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
- log_unit_debug(u->id, "Collecting %s", u->id);
+ if (u->id)
+ log_unit_debug(u, "Collecting.");
u->gc_marker = gc_marker + GC_OFFSET_BAD;
unit_add_to_cleanup_queue(u);
}
@@ -960,8 +991,8 @@ int manager_enumerate(Manager *m) {
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
int q;
- if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
- log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c));
+ if (!unit_type_supported(c)) {
+ log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
}
@@ -977,28 +1008,25 @@ int manager_enumerate(Manager *m) {
return r;
}
-static int manager_coldplug(Manager *m) {
- int r = 0;
+static void manager_coldplug(Manager *m) {
Iterator i;
Unit *u;
char *k;
+ int r;
assert(m);
/* Then, let's set up their initial state. */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- int q;
/* ignore aliases */
if (u->id != k)
continue;
- q = unit_coldplug(u);
- if (q < 0)
- r = q;
+ r = unit_coldplug(u);
+ if (r < 0)
+ log_warning_errno(r, "We couldn't coldplug %s, proceeding anyway: %m", u->id);
}
-
- return r;
}
static void manager_build_unit_path_cache(Manager *m) {
@@ -1142,9 +1170,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed);
/* Third, fire things up! */
- q = manager_coldplug(m);
- if (q < 0 && r == 0)
- r = q;
+ manager_coldplug(m);
if (serialization) {
assert(m->n_reloading > 0);
@@ -1174,11 +1200,9 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
if (mode == JOB_ISOLATE && !unit->allow_isolate)
return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
- log_unit_debug(unit->id,
- "Trying to enqueue job %s/%s/%s", unit->id,
- job_type_to_string(type), job_mode_to_string(mode));
+ log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
- job_type_collapse(&type, unit);
+ type = job_type_collapse(type, unit);
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
if (!tr)
@@ -1200,7 +1224,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
if (r < 0)
goto tr_abort;
- log_unit_debug(unit->id,
+ log_unit_debug(unit,
"Enqueued job %s/%s as %u", unit->id,
job_type_to_string(type), (unsigned) tr->anchor_job->id);
@@ -1296,7 +1320,7 @@ int manager_load_unit_prepare(
t = unit_name_to_type(name);
- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID))
+ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
ret = manager_get_unit(m, name);
@@ -1470,10 +1494,10 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *
return;
}
- log_unit_debug(u->id, "Got notification message for unit %s", u->id);
-
if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, pid, tags, fds);
+ else
+ log_unit_debug(u, "Got notification message for unit. Ignoring.");
}
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
@@ -1593,7 +1617,7 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
assert(u);
assert(si);
- log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
+ log_unit_debug(u, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
unit_unwatch_pid(u, si->si_pid);
UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
@@ -1665,11 +1689,11 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
- log_unit_debug(name, "Activating special unit %s", name);
+ log_debug("Activating special unit %s", name);
r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
if (r < 0)
- log_unit_error(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
+ log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
return r;
}
@@ -1702,7 +1726,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
}
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
- (sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER)
+ (sfsi.ssi_signo == SIGTERM && m->running_as == MANAGER_USER)
? LOG_DEBUG : LOG_INFO,
&sfsi);
@@ -1713,7 +1737,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGTERM:
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
/* This is for compatibility with the
* original sysvinit */
m->exit_code = MANAGER_REEXECUTE;
@@ -1723,7 +1747,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
/* Fall through */
case SIGINT:
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
/* If the user presses C-A-D more than
* 7 times within 2s, we reboot
@@ -1749,14 +1773,14 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGWINCH:
- if (m->running_as == SYSTEMD_SYSTEM)
+ if (m->running_as == MANAGER_SYSTEM)
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
break;
case SIGPWR:
- if (m->running_as == SYSTEMD_SYSTEM)
+ if (m->running_as == MANAGER_SYSTEM)
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
@@ -1870,7 +1894,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case 24:
- if (m->running_as == SYSTEMD_USER) {
+ if (m->running_as == MANAGER_USER) {
m->exit_code = MANAGER_EXIT;
return 0;
}
@@ -1988,7 +2012,7 @@ int manager_loop(Manager *m) {
while (m->exit_code == MANAGER_OK) {
usec_t wait_usec;
- if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
+ if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)
watchdog_ping();
if (!ratelimit_test(&rl)) {
@@ -2014,7 +2038,7 @@ int manager_loop(Manager *m) {
continue;
/* Sleep for half the watchdog time */
- if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) {
+ if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) {
wait_usec = m->runtime_watchdog / 2;
if (wait_usec <= 0)
wait_usec = 1;
@@ -2083,7 +2107,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
#ifdef HAVE_AUDIT
_cleanup_free_ char *p = NULL;
const char *msg;
- int audit_fd;
+ int audit_fd, r;
audit_fd = get_audit_fd();
if (audit_fd < 0)
@@ -2094,15 +2118,15 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
if (m->n_reloading > 0)
return;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return;
if (u->type != UNIT_SERVICE)
return;
- p = unit_name_to_prefix_and_instance(u->id);
- if (!p) {
- log_oom();
+ r = unit_name_to_prefix_and_instance(u->id, &p);
+ if (r < 0) {
+ log_error_errno(r, "Failed to extract prefix and instance of unit name: %m");
return;
}
@@ -2131,7 +2155,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
if (m->n_reloading > 0)
return;
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return;
if (detect_container(NULL) > 0)
@@ -2193,7 +2217,7 @@ int manager_open_serialization(Manager *m, FILE **_f) {
assert(_f);
- path = m->running_as == SYSTEMD_SYSTEM ? "/run/systemd" : "/tmp";
+ path = m->running_as == MANAGER_SYSTEM ? "/run/systemd" : "/tmp";
fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
@@ -2399,11 +2423,9 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
_cleanup_free_ char *uce = NULL;
char **e;
- uce = cunescape(l+4);
- if (!uce) {
- r = -ENOMEM;
+ r = cunescape(l + 4, UNESCAPE_RELAX, &uce);
+ if (r < 0)
goto finish;
- }
e = strv_env_set(m->environment, uce);
if (!e) {
@@ -2564,9 +2586,7 @@ int manager_reload(Manager *m) {
r = q;
/* Third, fire things up! */
- q = manager_coldplug(m);
- if (q < 0 && r >= 0)
- r = q;
+ manager_coldplug(m);
assert(m->n_reloading > 0);
m->n_reloading--;
@@ -2613,7 +2633,7 @@ static void manager_notify_finished(Manager *m) {
if (m->test_run)
return;
- if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
+ if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
* and m->firmware_usec.monotonic and
@@ -2681,10 +2701,21 @@ void manager_check_finished(Manager *m) {
assert(m);
+ if (m->n_reloading > 0)
+ return;
+
+ /* Verify that we are actually running currently. Initially
+ * the exit code is set to invalid, and during operation it is
+ * then set to MANAGER_OK */
+ if (m->exit_code != MANAGER_OK)
+ return;
+
if (hashmap_size(m->jobs) > 0) {
if (m->jobs_in_progress_event_source)
- sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
+ /* Ignore any failure, this is only for feedback */
+ (void) sd_event_source_set_time(m->jobs_in_progress_event_source,
+ now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
return;
}
@@ -2727,7 +2758,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
if (*generator)
return 0;
- if (m->running_as == SYSTEMD_SYSTEM && getpid() == 1) {
+ if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
/* systemd --system, not running --test */
p = strappend("/run/systemd/", name);
@@ -2740,7 +2771,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
free(p);
return r;
}
- } else if (m->running_as == SYSTEMD_USER) {
+ } else if (m->running_as == MANAGER_USER) {
const char *s = NULL;
s = getenv("XDG_RUNTIME_DIR");
@@ -2791,7 +2822,7 @@ static void trim_generator_dir(Manager *m, char **generator) {
}
static int manager_run_generators(Manager *m) {
- _cleanup_free_ char **paths = NULL;
+ _cleanup_strv_free_ char **paths = NULL;
const char *argv[5];
char **path;
int r;
@@ -2853,7 +2884,7 @@ static void remove_generator_dir(Manager *m, char **generator) {
return;
strv_remove(m->lookup_paths.unit_path, *generator);
- rm_rf(*generator, false, true, false);
+ (void) rm_rf(*generator, REMOVE_ROOT);
free(*generator);
*generator = NULL;
@@ -2927,7 +2958,7 @@ void manager_recheck_journal(Manager *m) {
assert(m);
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return;
u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
@@ -2951,7 +2982,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
assert(m);
assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return;
m->show_status = mode;
@@ -2965,7 +2996,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
static bool manager_get_show_status(Manager *m, StatusType type) {
assert(m);
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return false;
if (m->no_console_output)
@@ -2981,15 +3012,13 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
if (m->show_status > 0)
return true;
- /* If Plymouth is running make sure we show the status, so
- * that there's something nice to see when people press Esc */
- return plymouth_running();
+ return false;
}
void manager_set_first_boot(Manager *m, bool b) {
assert(m);
- if (m->running_as != SYSTEMD_SYSTEM)
+ if (m->running_as != MANAGER_SYSTEM)
return;
m->first_boot = b;
@@ -3021,15 +3050,16 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
_cleanup_free_ char *p = NULL;
Unit *found;
+ int r;
assert(m);
assert(path);
assert(suffix);
assert(_found);
- p = unit_name_from_path(path, suffix);
- if (!p)
- return -ENOMEM;
+ r = unit_name_from_path(path, suffix, &p);
+ if (r < 0)
+ return r;
found = manager_get_unit(m, p);
if (!found) {
@@ -3056,11 +3086,29 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
const char *manager_get_runtime_prefix(Manager *m) {
assert(m);
- return m->running_as == SYSTEMD_SYSTEM ?
+ return m->running_as == MANAGER_SYSTEM ?
"/run" :
getenv("XDG_RUNTIME_DIR");
}
+void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
+ unsigned size;
+
+ assert(m);
+ assert(u->manager == m);
+
+ size = set_size(m->failed_units);
+
+ if (failed) {
+ if (set_put(m->failed_units, u) < 0)
+ log_oom();
+ } else
+ set_remove(m->failed_units, u);
+
+ if (set_size(m->failed_units) != size)
+ bus_manager_send_change_signal(m);
+}
+
ManagerState manager_state(Manager *m) {
Unit *u;
diff --git a/src/core/manager.h b/src/core/manager.h
index d3971f1684..4ef869d14a 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -22,7 +22,6 @@
***/
#include <stdbool.h>
-#include <inttypes.h>
#include <stdio.h>
#include "sd-bus.h"
@@ -31,7 +30,6 @@
#include "cgroup-util.h"
#include "hashmap.h"
#include "list.h"
-#include "set.h"
#include "ratelimit.h"
/* Enforce upper limit how many names we allow */
@@ -70,14 +68,11 @@ typedef enum StatusType {
STATUS_TYPE_EMERGENCY,
} StatusType;
-#include "unit.h"
#include "job.h"
#include "path-lookup.h"
#include "execute.h"
#include "unit-name.h"
-#include "exit-status.h"
#include "show-status.h"
-#include "failure-action.h"
struct Manager {
/* Note that the set of units we know of is allowed to be
@@ -204,11 +199,9 @@ struct Manager {
sd_bus_track *subscribed;
char **deserialized_subscribed;
- sd_bus_message *queued_message; /* This is used during reloading:
- * before the reload we queue the
- * reply message here, and
- * afterwards we send it */
- sd_bus *queued_message_bus; /* The connection to send the queued message on */
+ /* This is used during reloading: before the reload we queue
+ * the reply message here, and afterwards we send it */
+ sd_bus_message *queued_message;
Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */
@@ -233,7 +226,7 @@ struct Manager {
int pin_cgroupfs_fd;
/* Flags */
- SystemdRunningAs running_as;
+ ManagerRunningAs running_as;
ManagerExitCode exit_code:5;
bool dispatching_load_queue:1;
@@ -299,9 +292,12 @@ struct Manager {
/* When the user hits C-A-D more than 7 times per 2s, reboot immediately... */
RateLimit ctrl_alt_del_ratelimit;
+
+ const char *unit_log_field;
+ const char *unit_log_format_string;
};
-int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);
+int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
Manager* manager_free(Manager *m);
int manager_enumerate(Manager *m);
@@ -367,5 +363,7 @@ const char *manager_get_runtime_prefix(Manager *m);
ManagerState manager_state(Manager *m);
+void manager_update_failed_units(Manager *m, Unit *u, bool failed);
+
const char *manager_state_to_string(ManagerState m) _const_;
ManagerState manager_state_from_string(const char *s) _pure_;
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 521545e5ce..c35248eeae 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -21,10 +21,7 @@
#include <sys/mount.h>
#include <errno.h>
-#include <sys/stat.h>
#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
#include <unistd.h>
#include <ftw.h>
@@ -42,7 +39,6 @@
#include "virt.h"
#include "efivars.h"
#include "smack-util.h"
-#include "def.h"
#include "cgroup-util.h"
typedef enum MountMode {
@@ -160,10 +156,9 @@ static int mount_one(const MountPoint *p, bool relabel) {
if (relabel)
label_fix(p->where, true, true);
- r = path_is_mount_point(p->where, true);
- if (r < 0)
+ r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW);
+ if (r < 0 && r != -ENOENT)
return r;
-
if (r > 0)
return 0;
@@ -378,7 +373,7 @@ int mount_setup(bool loaded_policy) {
/* Create a few default symlinks, which are normally created
* by udevd, but some scripts might need them before we start
* udevd. */
- dev_setup(NULL);
+ dev_setup(NULL, UID_INVALID, GID_INVALID);
/* Mark the root directory as shared in regards to mount
* propagation. The kernel defaults to "private", but we think
diff --git a/src/core/mount.c b/src/core/mount.c
index f3977e62de..ba1dcf1e85 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -21,7 +21,6 @@
#include <errno.h>
#include <stdio.h>
-#include <mntent.h>
#include <sys/epoll.h>
#include <signal.h>
#include <libmount.h>
@@ -30,8 +29,6 @@
#include "manager.h"
#include "unit.h"
#include "mount.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
#include "log.h"
#include "sd-messages.h"
#include "strv.h"
@@ -41,10 +38,9 @@
#include "unit-name.h"
#include "dbus-mount.h"
#include "special.h"
-#include "bus-common-errors.h"
#include "exit-status.h"
-#include "def.h"
#include "fstab-util.h"
+#include "formats-util.h"
#define RETRY_UMOUNT_MAX 32
@@ -107,7 +103,9 @@ static bool mount_is_auto(const MountParameters *p) {
static bool needs_quota(const MountParameters *p) {
assert(p);
- if (mount_is_network(p))
+ /* Quotas are not enabled on network filesystems,
+ * but we want them, for example, on storage connected via iscsi */
+ if (p->fstype && fstype_is_network(p->fstype))
return false;
if (mount_is_bind(p))
@@ -137,8 +135,8 @@ static void mount_init(Unit *u) {
m->exec_context.std_error = u->manager->default_std_error;
}
- /* We need to make sure that /bin/mount is always called in
- * the same process group as us, so that the autofs kernel
+ /* We need to make sure that /usr/bin/mount is always called
+ * in the same process group as us, so that the autofs kernel
* side doesn't send us another mount request while we are
* already trying to comply its last one. */
m->exec_context.same_pgrp = true;
@@ -166,12 +164,18 @@ static int mount_arm_timer(Mount *m) {
return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT);
}
- return sd_event_add_time(
+ r = sd_event_add_time(
UNIT(m)->manager->event,
&m->timer_event_source,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + m->timeout_usec, 0,
mount_dispatch_timer, m);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(m->timer_event_source, "mount-timer");
+
+ return 0;
}
static void mount_unwatch_control_pid(Mount *m) {
@@ -313,10 +317,16 @@ static int mount_add_device_links(Mount *m) {
if (!is_device_path(p->what))
return 0;
+ /* /dev/root is a really weird thing, it's not a real device,
+ * but just a path the kernel exports for the root file system
+ * specified on the kernel command line. Ignore it here. */
+ if (path_equal(p->what, "/dev/root"))
+ return 0;
+
if (path_equal(m->where, "/"))
return 0;
- if (mount_is_auto(p) && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
+ if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
device_wants_mount = true;
r = unit_add_node_link(UNIT(m), p->what, device_wants_mount);
@@ -332,7 +342,7 @@ static int mount_add_quota_links(Mount *m) {
assert(m);
- if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
+ if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
return 0;
p = get_mount_parameters_fragment(m);
@@ -375,7 +385,7 @@ static int mount_add_default_dependencies(Mount *m) {
assert(m);
- if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
+ if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
return 0;
/* We do not add any default dependencies to / and /usr, since
@@ -431,7 +441,7 @@ static int mount_add_default_dependencies(Mount *m) {
static int mount_verify(Mount *m) {
_cleanup_free_ char *e = NULL;
- bool b;
+ int r;
assert(m);
@@ -441,28 +451,27 @@ static int mount_verify(Mount *m) {
if (!m->from_fragment && !m->from_proc_self_mountinfo)
return -ENOENT;
- e = unit_name_from_path(m->where, ".mount");
- if (!e)
- return -ENOMEM;
+ r = unit_name_from_path(m->where, ".mount", &e);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(m), r, "Failed to generate unit name from mount path: %m");
- b = unit_has_name(UNIT(m), e);
- if (!b) {
- log_unit_error(UNIT(m)->id, "%s's Where= setting doesn't match unit name. Refusing.", UNIT(m)->id);
+ if (!unit_has_name(UNIT(m), e)) {
+ log_unit_error(UNIT(m), "Where= setting doesn't match unit name. Refusing.");
return -EINVAL;
}
if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
- log_unit_error(UNIT(m)->id, "Cannot create mount unit for API file system %s. Refusing.", m->where);
+ log_unit_error(UNIT(m), "Cannot create mount unit for API file system %s. Refusing.", m->where);
return -EINVAL;
}
if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
- log_unit_error(UNIT(m)->id, "%s's What setting is missing. Refusing.", UNIT(m)->id);
+ log_unit_error(UNIT(m), "What= setting is missing. Refusing.");
return -EBADMSG;
}
if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(m)->id, "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.",UNIT(m)->id);
+ log_unit_error(UNIT(m), "Unit has PAM enabled. Kill mode must be set to control-group'. Refusing.");
return -EINVAL;
}
@@ -479,9 +488,9 @@ static int mount_add_extras(Mount *m) {
m->from_fragment = true;
if (!m->where) {
- m->where = unit_name_to_path(u->id);
- if (!m->where)
- return -ENOMEM;
+ r = unit_name_to_path(u->id, &m->where);
+ if (r < 0)
+ return r;
}
path_kill_slashes(m->where);
@@ -550,7 +559,7 @@ static int mount_load(Unit *u) {
return mount_verify(m);
}
-static int mount_notify_automount(Mount *m, int status) {
+static int mount_notify_automount(Mount *m, MountState old_state, MountState state) {
Unit *p;
int r;
Iterator i;
@@ -559,7 +568,7 @@ static int mount_notify_automount(Mount *m, int status) {
SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
if (p->type == UNIT_AUTOMOUNT) {
- r = automount_send_ready(AUTOMOUNT(p), status);
+ r = automount_update_mount(AUTOMOUNT(p), old_state, state);
if (r < 0)
return r;
}
@@ -590,28 +599,10 @@ static void mount_set_state(Mount *m, MountState state) {
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
}
- if (state == MOUNT_MOUNTED ||
- state == MOUNT_REMOUNTING)
- mount_notify_automount(m, 0);
- else if (state == MOUNT_DEAD ||
- state == MOUNT_UNMOUNTING ||
- state == MOUNT_MOUNTING_SIGTERM ||
- state == MOUNT_MOUNTING_SIGKILL ||
- state == MOUNT_REMOUNTING_SIGTERM ||
- state == MOUNT_REMOUNTING_SIGKILL ||
- state == MOUNT_UNMOUNTING_SIGTERM ||
- state == MOUNT_UNMOUNTING_SIGKILL ||
- state == MOUNT_FAILED) {
- if (state != old_state)
- mount_notify_automount(m, -ENODEV);
- }
+ mount_notify_automount(m, old_state, state);
if (state != old_state)
- log_unit_debug(UNIT(m)->id,
- "%s changed %s -> %s",
- UNIT(m)->id,
- mount_state_to_string(old_state),
- mount_state_to_string(state));
+ log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
m->reload_result = MOUNT_SUCCESS;
@@ -705,13 +696,18 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
+ .bus_endpoint_fd = -1,
};
assert(m);
assert(c);
assert(_pid);
- unit_realize_cgroup(UNIT(m));
+ (void) unit_realize_cgroup(UNIT(m));
+ if (m->reset_cpu_usage) {
+ (void) unit_reset_cpu_usage(UNIT(m));
+ m->reset_cpu_usage = false;
+ }
r = unit_setup_exec_runtime(UNIT(m));
if (r < 0)
@@ -727,9 +723,9 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
exec_params.cgroup_path = UNIT(m)->cgroup_path;
exec_params.cgroup_delegate = m->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager);
- exec_params.unit_id = UNIT(m)->id;
- r = exec_spawn(c,
+ r = exec_spawn(UNIT(m),
+ c,
&m->exec_context,
&exec_params,
m->exec_runtime,
@@ -814,8 +810,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
return;
fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(m), r, "Failed to kill processes: %m");
if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
@@ -823,46 +818,6 @@ fail:
mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
}
-void warn_if_dir_nonempty(const char *unit, const char* where) {
- int r;
-
- assert(unit);
- assert(where);
-
- r = dir_is_empty(where);
- if (r > 0)
- return;
- else if (r == 0)
- log_unit_struct(unit,
- LOG_NOTICE,
- LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- LOG_MESSAGE("%s: Directory %s to mount over is not empty, mounting anyway.",
- unit, where),
- "WHERE=%s", where,
- NULL);
- else
- log_unit_warning(unit,
- "MESSAGE=Failed to check directory %s: %s",
- where, strerror(-r));
-}
-
-static int fail_if_symlink(const char *unit, const char* where) {
- assert(where);
-
- if (is_symlink(where) > 0) {
- log_unit_struct(unit,
- LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- LOG_MESSAGE("%s: Mount on symlink %s not allowed.",
- unit, where),
- "WHERE=%s", where,
- NULL);
-
- return -ELOOP;
- }
- return 0;
-}
-
static void mount_enter_unmounting(Mount *m) {
int r;
@@ -878,8 +833,8 @@ static void mount_enter_unmounting(Mount *m) {
m->control_command_id = MOUNT_EXEC_UNMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
- r = exec_command_set(m->control_command, "/bin/umount", m->where, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
+ r = exec_command_set(m->control_command, UMOUNT_PATH, m->where, NULL);
+ if (r >= 0 && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
r = exec_command_append(m->control_command, "-n", NULL);
if (r < 0)
goto fail;
@@ -895,9 +850,7 @@ static void mount_enter_unmounting(Mount *m) {
return;
fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to run 'umount' task: %s",
- UNIT(m)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(m), r, "Failed to run 'umount' task: %m");
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
}
@@ -910,18 +863,18 @@ static void mount_enter_mounting(Mount *m) {
m->control_command_id = MOUNT_EXEC_MOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
- mkdir_p_label(m->where, m->directory_mode);
+ r = unit_fail_if_symlink(UNIT(m), m->where);
+ if (r < 0)
+ goto fail;
- warn_if_dir_nonempty(m->meta.id, m->where);
+ (void) mkdir_p_label(m->where, m->directory_mode);
+
+ unit_warn_if_dir_nonempty(UNIT(m), m->where);
/* Create the source directory for bind-mounts if needed */
p = get_mount_parameters_fragment(m);
if (p && mount_is_bind(p))
- mkdir_p_label(p->what, m->directory_mode);
-
- r = fail_if_symlink(m->meta.id, m->where);
- if (r < 0)
- goto fail;
+ (void) mkdir_p_label(p->what, m->directory_mode);
if (m->from_fragment) {
_cleanup_free_ char *opts = NULL;
@@ -931,9 +884,9 @@ static void mount_enter_mounting(Mount *m) {
if (r < 0)
goto fail;
- r = exec_command_set(m->control_command, "/bin/mount",
+ r = exec_command_set(m->control_command, MOUNT_PATH,
m->parameters_fragment.what, m->where, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
+ if (r >= 0 && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
r = exec_command_append(m->control_command, "-n", NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
@@ -958,9 +911,7 @@ static void mount_enter_mounting(Mount *m) {
return;
fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to run 'mount' task: %s",
- UNIT(m)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(m), r, "Failed to run 'mount' task: %m");
mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
}
@@ -980,10 +931,10 @@ static void mount_enter_remounting(Mount *m) {
else
o = "remount";
- r = exec_command_set(m->control_command, "/bin/mount",
+ r = exec_command_set(m->control_command, MOUNT_PATH,
m->parameters_fragment.what, m->where,
"-o", o, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
+ if (r >= 0 && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
r = exec_command_append(m->control_command, "-n", NULL);
if (r >= 0 && m->sloppy_options)
r = exec_command_append(m->control_command, "-s", NULL);
@@ -1006,9 +957,7 @@ static void mount_enter_remounting(Mount *m) {
return;
fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to run 'remount' task: %s",
- UNIT(m)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(m), r, "Failed to run 'remount' task: %m");
m->reload_result = MOUNT_FAILURE_RESOURCES;
mount_enter_mounted(m, MOUNT_SUCCESS);
}
@@ -1035,6 +984,7 @@ static int mount_start(Unit *u) {
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
+ m->reset_cpu_usage = true;
mount_enter_mounting(m);
return 1;
@@ -1110,7 +1060,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
MountState state;
if ((state = mount_state_from_string(value)) < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
m->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -1118,8 +1068,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
f = mount_result_from_string(value);
if (f < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != MOUNT_SUCCESS)
m->result = f;
@@ -1128,8 +1077,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
f = mount_result_from_string(value);
if (f < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse reload result value %s", value);
+ log_unit_debug(u, "Failed to parse reload result value: %s", value);
else if (f != MOUNT_SUCCESS)
m->reload_result = f;
@@ -1137,23 +1085,21 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse control-pid value %s", value);
+ log_unit_debug(u, "Failed to parse control-pid value: %s", value);
else
m->control_pid = pid;
} else if (streq(key, "control-command")) {
MountExecCommand id;
- if ((id = mount_exec_command_from_string(value)) < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse exec-command value %s", value);
+ id = mount_exec_command_from_string(value);
+ if (id < 0)
+ log_unit_debug(u, "Failed to parse exec-command value: %s", value);
else {
m->control_command_id = id;
m->control_command = m->exec_command + id;
}
} else
- log_unit_debug(UNIT(m)->id,
- "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -1211,10 +1157,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
}
- log_unit_full(u->id,
- f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s mount process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
+ log_unit_full(u, f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
+ "Mount process exited, code=%s status=%i", sigchld_code_to_string(code), status);
/* Note that mount(8) returning and the kernel sending us a
* mount table change event might happen out-of-order. If an
@@ -1268,11 +1212,11 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
* the mount command. */
if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
- log_unit_debug(u->id, "%s: mount still present, trying again.", u->id);
+ log_unit_debug(u, "Mount still present, trying again.");
m->n_retry_umount++;
mount_enter_unmounting(m);
} else {
- log_unit_debug(u->id, "%s: mount still present after %u attempts to unmount, giving up.", u->id, m->n_retry_umount);
+ log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
mount_enter_mounted(m, f);
}
} else
@@ -1302,33 +1246,27 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
- log_unit_warning(UNIT(m)->id,
- "%s mounting timed out. Stopping.", UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Mounting timed out. Stopping.");
mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_REMOUNTING:
- log_unit_warning(UNIT(m)->id,
- "%s remounting timed out. Stopping.", UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Remounting timed out. Stopping.");
m->reload_result = MOUNT_FAILURE_TIMEOUT;
mount_enter_mounted(m, MOUNT_SUCCESS);
break;
case MOUNT_UNMOUNTING:
- log_unit_warning(UNIT(m)->id,
- "%s unmounting timed out. Stopping.", UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Unmounting timed out. Stopping.");
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_MOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m)->id,
- "%s mounting timed out. Killing.", UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Mounting timed out. Killing.");
mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(m)->id,
- "%s mounting timed out. Skipping SIGKILL. Ignoring.",
- UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Mounting timed out. Skipping SIGKILL. Ignoring.");
if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1339,13 +1277,10 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_REMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m)->id,
- "%s remounting timed out. Killing.", UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Remounting timed out. Killing.");
mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(m)->id,
- "%s remounting timed out. Skipping SIGKILL. Ignoring.",
- UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring.");
if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1356,13 +1291,10 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_UNMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m)->id,
- "%s unmounting timed out. Killing.", UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Unmounting timed out. Killing.");
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(m)->id,
- "%s unmounting timed out. Skipping SIGKILL. Ignoring.",
- UNIT(m)->id);
+ log_unit_warning(UNIT(m), "Unmounting timed out. Skipping SIGKILL. Ignoring.");
if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1374,9 +1306,7 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGKILL:
- log_unit_warning(UNIT(m)->id,
- "%s mount process still around after SIGKILL. Ignoring.",
- UNIT(m)->id);
+ log_unit_warning(UNIT(m),"Mount process still around after SIGKILL. Ignoring.");
if (m->from_proc_self_mountinfo)
mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
@@ -1391,7 +1321,7 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
return 0;
}
-static int mount_add_one(
+static int mount_setup_unit(
Manager *m,
const char *what,
const char *where,
@@ -1424,9 +1354,9 @@ static int mount_add_one(
if (!is_path(where))
return 0;
- e = unit_name_from_path(where, ".mount");
- if (!e)
- return -ENOMEM;
+ r = unit_name_from_path(where, ".mount", &e);
+ if (r < 0)
+ return r;
u = manager_get_unit(m, e);
if (!u) {
@@ -1434,7 +1364,7 @@ static int mount_add_one(
u = unit_new(m, sizeof(Mount));
if (!u)
- return -ENOMEM;
+ return log_oom();
r = unit_add_name(u, e);
if (r < 0)
@@ -1452,7 +1382,7 @@ static int mount_add_one(
goto fail;
}
- if (m->running_as == SYSTEMD_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM) {
const char* target;
target = mount_needs_network(options, fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
@@ -1480,7 +1410,7 @@ static int mount_add_one(
}
}
- if (m->running_as == SYSTEMD_SYSTEM &&
+ if (m->running_as == MANAGER_SYSTEM &&
mount_needs_network(options, fstype)) {
/* _netdev option may have shown up late, or on a
* remount. Add remote-fs dependencies, even though
@@ -1547,6 +1477,8 @@ static int mount_add_one(
return 0;
fail:
+ log_warning_errno(r, "Failed to set up mount unit: %m");
+
if (delete && u)
unit_free(u);
@@ -1554,45 +1486,51 @@ fail:
}
static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
- _cleanup_(mnt_free_tablep) struct libmnt_table *tb = NULL;
- _cleanup_(mnt_free_iterp) struct libmnt_iter *itr = NULL;
- struct libmnt_fs *fs;
+ _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
+ _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
int r = 0;
assert(m);
- tb = mnt_new_table();
- itr = mnt_new_iter(MNT_ITER_FORWARD);
- if (!tb || !itr)
+ t = mnt_new_table();
+ if (!t)
return log_oom();
- r = mnt_table_parse_mtab(tb, NULL);
+ i = mnt_new_iter(MNT_ITER_FORWARD);
+ if (!i)
+ return log_oom();
+
+ r = mnt_table_parse_mtab(t, NULL);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
r = 0;
for (;;) {
const char *device, *path, *options, *fstype;
- _cleanup_free_ const char *d = NULL, *p = NULL;
+ _cleanup_free_ char *d = NULL, *p = NULL;
+ struct libmnt_fs *fs;
int k;
- k = mnt_table_next_fs(tb, itr, &fs);
+ k = mnt_table_next_fs(t, i, &fs);
if (k == 1)
break;
- else if (k < 0)
- return log_error_errno(k, "Failed to get next entry from /etc/fstab: %m");
+ if (k < 0)
+ return log_error_errno(k, "Failed to get next entry from /proc/self/mountinfo: %m");
device = mnt_fs_get_source(fs);
path = mnt_fs_get_target(fs);
options = mnt_fs_get_options(fs);
fstype = mnt_fs_get_fstype(fs);
- d = cunescape(device);
- p = cunescape(path);
- if (!d || !p)
+ if (cunescape(device, UNESCAPE_RELAX, &d) < 0)
return log_oom();
- k = mount_add_one(m, d, p, options, fstype, set_flags);
+ if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
+ return log_oom();
+
+ (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags);
+
+ k = mount_setup_unit(m, d, p, options, fstype, set_flags);
if (r == 0 && k < 0)
r = k;
}
@@ -1644,10 +1582,12 @@ static int mount_enumerate(Manager *m) {
/* Dispatch this before we dispatch SIGCHLD, so that
* we always get the events from /proc/self/mountinfo
- * before the SIGCHLD of /bin/mount. */
+ * before the SIGCHLD of /usr/bin/mount. */
r = sd_event_source_set_priority(m->mount_event_source, -10);
if (r < 0)
goto fail;
+
+ (void) sd_event_source_set_description(m->mount_event_source, "mount-mountinfo-dispatch");
}
if (m->utab_inotify_fd < 0) {
@@ -1672,6 +1612,8 @@ static int mount_enumerate(Manager *m) {
r = sd_event_source_set_priority(m->mount_utab_event_source, -10);
if (r < 0)
goto fail;
+
+ (void) sd_event_source_set_description(m->mount_utab_event_source, "mount-utab-dispatch");
}
r = mount_load_proc_self_mountinfo(m, false);
@@ -1686,7 +1628,10 @@ fail:
}
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ _cleanup_set_free_ Set *around = NULL, *gone = NULL;
Manager *m = userdata;
+ const char *what;
+ Iterator i;
Unit *u;
int r;
@@ -1736,8 +1681,6 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
r = mount_load_proc_self_mountinfo(m, true);
if (r < 0) {
- log_error_errno(r, "Failed to reread /proc/self/mountinfo: %m");
-
/* Reset flags, just in case, for later calls */
LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
Mount *mount = MOUNT(u);
@@ -1755,6 +1698,19 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (!mount->is_mounted) {
+ /* A mount point is not around right now. It
+ * might be gone, or might never have
+ * existed. */
+
+ if (mount->from_proc_self_mountinfo &&
+ mount->parameters_proc_self_mountinfo.what) {
+
+ /* Remember that this device might just have disappeared */
+ if (set_ensure_allocated(&gone, &string_hash_ops) < 0 ||
+ set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0)
+ log_oom(); /* we don't care too much about OOM here... */
+ }
+
mount->from_proc_self_mountinfo = false;
switch (mount->state) {
@@ -1772,7 +1728,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
} else if (mount->just_mounted || mount->just_changed) {
- /* New or changed mount entry */
+ /* A mount point was added or changed */
switch (mount->state) {
@@ -1799,10 +1755,27 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
}
}
+ if (mount->is_mounted &&
+ mount->from_proc_self_mountinfo &&
+ mount->parameters_proc_self_mountinfo.what) {
+
+ if (set_ensure_allocated(&around, &string_hash_ops) < 0 ||
+ set_put(around, mount->parameters_proc_self_mountinfo.what) < 0)
+ log_oom();
+ }
+
/* Reset the flags for later calls */
mount->is_mounted = mount->just_mounted = mount->just_changed = false;
}
+ SET_FOREACH(what, gone, i) {
+ if (set_contains(around, what))
+ continue;
+
+ /* Let the device units know that the device is no longer mounted */
+ (void) device_found_node(m, what, false, DEVICE_FOUND_MOUNT, true);
+ }
+
return 0;
}
diff --git a/src/core/mount.h b/src/core/mount.h
index d6987e6fa1..280ea0d638 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -23,15 +23,13 @@
typedef struct Mount Mount;
-#include "unit.h"
#include "kill.h"
#include "execute.h"
-#include "cgroup.h"
typedef enum MountState {
MOUNT_DEAD,
- MOUNT_MOUNTING, /* /bin/mount is running, but the mount is not done yet. */
- MOUNT_MOUNTING_DONE, /* /bin/mount is running, and the mount is done. */
+ MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */
+ MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */
MOUNT_MOUNTED,
MOUNT_REMOUNTING,
MOUNT_UNMOUNTING,
@@ -88,6 +86,8 @@ struct Mount {
bool just_mounted:1;
bool just_changed:1;
+ bool reset_cpu_usage:1;
+
bool sloppy_options;
MountResult result;
@@ -128,5 +128,3 @@ MountExecCommand mount_exec_command_from_string(const char *s) _pure_;
const char* mount_result_to_string(MountResult i) _const_;
MountResult mount_result_from_string(const char *s) _pure_;
-
-void warn_if_dir_nonempty(const char *unit, const char* where);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 4fecd32363..01a817bf23 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -25,25 +25,18 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <sched.h>
-#include <sys/syscall.h>
-#include <limits.h>
#include <linux/fs.h>
-#include <sys/file.h>
#include "strv.h"
#include "util.h"
#include "path-util.h"
#include "missing.h"
-#include "execute.h"
#include "loopback-setup.h"
-#include "mkdir.h"
#include "dev-setup.h"
-#include "def.h"
-#include "label.h"
#include "selinux-util.h"
#include "namespace.h"
+#include "mkdir.h"
typedef enum MountMode {
/* This is ordered by priority! */
@@ -91,9 +84,11 @@ static int append_mounts(BindMount **p, char **strv, MountMode mode) {
static int mount_path_compare(const void *a, const void *b) {
const BindMount *p = a, *q = b;
+ int d;
- if (path_equal(p->path, q->path)) {
+ d = path_compare(p->path, q->path);
+ if (d == 0) {
/* If the paths are equal, check the mode */
if (p->mode < q->mode)
return -1;
@@ -105,13 +100,7 @@ static int mount_path_compare(const void *a, const void *b) {
}
/* If the paths are not equal, then order prefixes first */
- if (path_startswith(p->path, q->path))
- return 1;
-
- if (path_startswith(q->path, p->path))
- return -1;
-
- return 0;
+ return d;
}
static void drop_duplicates(BindMount *m, unsigned *n) {
@@ -158,24 +147,27 @@ static int mount_dev(BindMount *m) {
return -errno;
dev = strjoina(temporary_mount, "/dev");
- (void)mkdir(dev, 0755);
+ (void) mkdir(dev, 0755);
if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
r = -errno;
goto fail;
}
devpts = strjoina(temporary_mount, "/dev/pts");
- (void)mkdir(devpts, 0755);
+ (void) mkdir(devpts, 0755);
if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
r = -errno;
goto fail;
}
devptmx = strjoina(temporary_mount, "/dev/ptmx");
- symlink("pts/ptmx", devptmx);
+ if (symlink("pts/ptmx", devptmx) < 0) {
+ r = -errno;
+ goto fail;
+ }
devshm = strjoina(temporary_mount, "/dev/shm");
- (void)mkdir(devshm, 01777);
+ (void) mkdir(devshm, 01777);
r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
if (r < 0) {
r = -errno;
@@ -183,15 +175,15 @@ static int mount_dev(BindMount *m) {
}
devmqueue = strjoina(temporary_mount, "/dev/mqueue");
- (void)mkdir(devmqueue, 0755);
- mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
+ (void) mkdir(devmqueue, 0755);
+ (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
devhugepages = strjoina(temporary_mount, "/dev/hugepages");
- (void)mkdir(devhugepages, 0755);
- mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
+ (void) mkdir(devhugepages, 0755);
+ (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
devlog = strjoina(temporary_mount, "/dev/log");
- symlink("/run/systemd/journal/dev-log", devlog);
+ (void) symlink("/run/systemd/journal/dev-log", devlog);
NULSTR_FOREACH(d, devnodes) {
_cleanup_free_ char *dn = NULL;
@@ -232,9 +224,15 @@ static int mount_dev(BindMount *m) {
}
}
- dev_setup(temporary_mount);
+ dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
+
+ /* Create the /dev directory if missing. It is more likely to be
+ * missing when the service is started with RootDirectory. This is
+ * consistent with mount units creating the mount points when missing.
+ */
+ (void) mkdir_p_label(m->path, 0755);
- if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) {
+ if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
}
@@ -281,7 +279,7 @@ static int mount_kdbus(BindMount *m) {
return log_error_errno(errno, "Failed create temp dir: %m");
root = strjoina(temporary_mount, "/kdbus");
- (void)mkdir(root, 0755);
+ (void) mkdir(root, 0755);
if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
r = -errno;
goto fail;
@@ -302,7 +300,7 @@ static int mount_kdbus(BindMount *m) {
goto fail;
}
- r = mount(m->path, busnode, "bind", MS_BIND, NULL);
+ r = mount(m->path, busnode, NULL, MS_BIND, NULL);
if (r < 0) {
log_error_errno(errno, "bind mount of %s failed: %m", m->path);
r = -errno;
@@ -413,6 +411,7 @@ static int make_read_only(BindMount *m) {
}
int setup_namespace(
+ const char* root_directory,
char** read_write_dirs,
char** read_only_dirs,
char** inaccessible_dirs,
@@ -458,37 +457,56 @@ int setup_namespace(
return r;
if (tmp_dir) {
- m->path = "/tmp";
+ m->path = prefix_roota(root_directory, "/tmp");
m->mode = PRIVATE_TMP;
m++;
}
if (var_tmp_dir) {
- m->path = "/var/tmp";
+ m->path = prefix_roota(root_directory, "/var/tmp");
m->mode = PRIVATE_VAR_TMP;
m++;
}
if (private_dev) {
- m->path = "/dev";
+ m->path = prefix_roota(root_directory, "/dev");
m->mode = PRIVATE_DEV;
m++;
}
if (bus_endpoint_path) {
- m->path = bus_endpoint_path;
+ m->path = prefix_roota(root_directory, bus_endpoint_path);
m->mode = PRIVATE_BUS_ENDPOINT;
m++;
}
if (protect_home != PROTECT_HOME_NO) {
- r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
+ const char *home_dir, *run_user_dir, *root_dir;
+
+ home_dir = prefix_roota(root_directory, "/home");
+ home_dir = strjoina("-", home_dir);
+ run_user_dir = prefix_roota(root_directory, "/run/user");
+ run_user_dir = strjoina("-", run_user_dir);
+ root_dir = prefix_roota(root_directory, "/root");
+ root_dir = strjoina("-", root_dir);
+
+ r = append_mounts(&m, STRV_MAKE(home_dir, run_user_dir, root_dir),
+ protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
if (r < 0)
return r;
}
if (protect_system != PROTECT_SYSTEM_NO) {
- r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "-/boot", "/etc") : STRV_MAKE("/usr", "-/boot"), READONLY);
+ const char *usr_dir, *boot_dir, *etc_dir;
+
+ usr_dir = prefix_roota(root_directory, "/usr");
+ boot_dir = prefix_roota(root_directory, "/boot");
+ boot_dir = strjoina("-", boot_dir);
+ etc_dir = prefix_roota(root_directory, "/etc");
+
+ r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL
+ ? STRV_MAKE(usr_dir, boot_dir, etc_dir)
+ : STRV_MAKE(usr_dir, boot_dir), READONLY);
if (r < 0)
return r;
}
@@ -499,12 +517,20 @@ int setup_namespace(
drop_duplicates(mounts, &n);
}
- if (n > 0) {
+ if (n > 0 || root_directory) {
/* Remount / as SLAVE so that nothing now mounted in the namespace
shows up in the parent */
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
return -errno;
+ }
+
+ if (root_directory) {
+ /* Turn directory into bind mount */
+ if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0)
+ return -errno;
+ }
+ if (n > 0) {
for (m = mounts; m < mounts + n; ++m) {
r = apply_mount(m, tmp_dir, var_tmp_dir);
if (r < 0)
@@ -518,12 +544,21 @@ int setup_namespace(
}
}
+ if (root_directory) {
+ /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
+ r = mount_move_root(root_directory);
+
+ /* at this point, we cannot rollback */
+ if (r < 0)
+ return r;
+ }
+
/* Remount / as the desired mode. Not that this will not
* reestablish propagation from our side to the host, since
* what's disconnected is disconnected. */
if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
- r = -errno;
- goto fail;
+ /* at this point, we cannot rollback */
+ return -errno;
}
return 0;
@@ -532,7 +567,7 @@ fail:
if (n > 0) {
for (m = mounts; m < mounts + n; ++m)
if (m->done)
- umount2(m->path, MNT_DETACH);
+ (void) umount2(m->path, MNT_DETACH);
}
return r;
diff --git a/src/core/namespace.h b/src/core/namespace.h
index 42b92e7803..00ab22bf2e 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -41,7 +41,8 @@ typedef enum ProtectSystem {
_PROTECT_SYSTEM_INVALID = -1
} ProtectSystem;
-int setup_namespace(char **read_write_dirs,
+int setup_namespace(const char *chroot,
+ char **read_write_dirs,
char **read_only_dirs,
char **inaccessible_dirs,
const char *tmp_dir,
diff --git a/src/core/org.freedesktop.systemd1.policy.in.in b/src/core/org.freedesktop.systemd1.policy.in.in
index fd771b4b26..cc39a9e1c3 100644
--- a/src/core/org.freedesktop.systemd1.policy.in.in
+++ b/src/core/org.freedesktop.systemd1.policy.in.in
@@ -28,8 +28,8 @@
</action>
<action id="org.freedesktop.systemd1.manage-units">
- <_description>Manage system services or units</_description>
- <_message>Authentication is required to manage system services or units.</_message>
+ <_description>Manage system services or other units</_description>
+ <_message>Authentication is required to manage system services or other units.</_message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
@@ -47,6 +47,16 @@
</defaults>
</action>
+ <action id="org.freedesktop.systemd1.set-environment">
+ <_description>Set or unset system and service manager environment variables</_description>
+ <_message>Authentication is required to set or unset system and service manager environment variables.</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
<action id="org.freedesktop.systemd1.reload-daemon">
<_description>Reload the systemd state</_description>
<_message>Authentication is required to reload the systemd state.</_message>
diff --git a/src/core/path.c b/src/core/path.c
index e5ea79fec7..6d26d89e82 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -21,7 +21,6 @@
#include <sys/inotify.h>
#include <sys/epoll.h>
-#include <sys/ioctl.h>
#include <errno.h>
#include <unistd.h>
@@ -31,7 +30,6 @@
#include "mkdir.h"
#include "dbus-path.h"
#include "special.h"
-#include "path-util.h"
#include "macro.h"
#include "bus-util.h"
#include "bus-error.h"
@@ -75,6 +73,8 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
if (r < 0)
goto fail;
+ (void) sd_event_source_set_description(s->event_source, "path");
+
/* This assumes the path was passed through path_kill_slashes()! */
for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
@@ -99,9 +99,7 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
break;
}
- log_warning("Failed to add watch on %s: %s", s->path,
- errno == ENOSPC ? "too many watches" : strerror(-r));
- r = -errno;
+ r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror(-r));
if (cut)
*cut = tmp;
goto fail;
@@ -136,9 +134,8 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
}
if (!exists) {
- log_error_errno(errno, "Failed to add watch on any of the components of %s: %m",
- s->path);
- r = -errno; /* either EACCESS or ENOENT */
+ r = log_error_errno(errno, "Failed to add watch on any of the components of %s: %m", s->path);
+ /* either EACCESS or ENOENT */
goto fail;
}
@@ -300,8 +297,7 @@ static int path_verify(Path *p) {
return 0;
if (!p->specs) {
- log_unit_error(UNIT(p)->id,
- "%s lacks path setting. Refusing.", UNIT(p)->id);
+ log_unit_error(UNIT(p), "Path unit lacks path setting. Refusing.");
return -EINVAL;
}
@@ -318,7 +314,7 @@ static int path_add_default_dependencies(Path *p) {
if (r < 0)
return r;
- if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
+ if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
@@ -430,10 +426,7 @@ static void path_set_state(Path *p, PathState state) {
path_unwatch(p);
if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(p)->id,
- path_state_to_string(old_state),
- path_state_to_string(state));
+ log_debug("Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -492,8 +485,7 @@ static void path_enter_running(Path *p) {
return;
fail:
- log_warning("%s failed to queue unit startup job: %s",
- UNIT(p)->id, bus_error_message(&error, r));
+ log_unit_warning(UNIT(p), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
path_enter_dead(p, PATH_FAILURE_RESOURCES);
}
@@ -518,7 +510,7 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
if (recheck)
if (path_check_good(p, initial)) {
- log_debug("%s got triggered.", UNIT(p)->id);
+ log_unit_debug(UNIT(p), "Got triggered.");
path_enter_running(p);
return;
}
@@ -533,7 +525,7 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
if (recheck)
if (path_check_good(p, false)) {
- log_debug("%s got triggered.", UNIT(p)->id);
+ log_unit_debug(UNIT(p), "Got triggered.");
path_enter_running(p);
return;
}
@@ -542,7 +534,7 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
return;
fail:
- log_warning_errno(r, "%s failed to enter waiting state: %m", UNIT(p)->id);
+ log_unit_warning_errno(UNIT(p), r, "Failed to enter waiting state: %m");
path_enter_dead(p, PATH_FAILURE_RESOURCES);
}
@@ -611,7 +603,7 @@ static int path_deserialize_item(Unit *u, const char *key, const char *value, FD
state = path_state_from_string(value);
if (state < 0)
- log_debug("Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
p->deserialized_state = state;
@@ -620,12 +612,12 @@ static int path_deserialize_item(Unit *u, const char *key, const char *value, FD
f = path_result_from_string(value);
if (f < 0)
- log_debug("Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != PATH_SUCCESS)
p->result = f;
} else
- log_debug("Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -703,9 +695,7 @@ static void path_trigger_notify(Unit *u, Unit *other) {
if (p->state == PATH_RUNNING &&
UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- log_unit_debug(UNIT(p)->id,
- "%s got notified about unit deactivation.",
- UNIT(p)->id);
+ log_unit_debug(UNIT(p), "Got notified about unit deactivation.");
/* Hmm, so inotify was triggered since the
* last activation, so I guess we need to
diff --git a/src/core/path.h b/src/core/path.h
index 0d36aab960..dec39333e4 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -25,7 +25,6 @@ typedef struct Path Path;
typedef struct PathSpec PathSpec;
#include "unit.h"
-#include "mount.h"
typedef enum PathState {
PATH_DEAD,
diff --git a/src/core/scope.c b/src/core/scope.c
index b41db7872c..ab1769b46b 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -20,12 +20,10 @@
***/
#include <errno.h>
-#include <signal.h>
#include <unistd.h>
#include "unit.h"
#include "scope.h"
-#include "load-fragment.h"
#include "log.h"
#include "dbus-scope.h"
#include "special.h"
@@ -83,12 +81,18 @@ static int scope_arm_timer(Scope *s) {
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
- return sd_event_add_time(
+ r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
scope_dispatch_timer, s);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");
+
+ return 0;
}
static void scope_set_state(Scope *s, ScopeState state) {
@@ -133,7 +137,7 @@ static int scope_verify(Scope *s) {
return 0;
if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
- log_unit_error(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
return -EINVAL;
}
@@ -264,8 +268,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
return;
fail:
- log_unit_warning(UNIT(s)->id,
- "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
}
@@ -279,6 +282,7 @@ static int scope_start(Unit *u) {
if (s->state == SCOPE_FAILED)
return -EPERM;
+ /* We can't fulfill this right now, please try again later */
if (s->state == SCOPE_STOP_SIGTERM ||
s->state == SCOPE_STOP_SIGKILL)
return -EAGAIN;
@@ -288,9 +292,15 @@ static int scope_start(Unit *u) {
if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
return -ENOENT;
+ (void) unit_realize_cgroup(u);
+ (void) unit_reset_cpu_usage(u);
+
r = unit_attach_pids_to_cgroup(u);
- if (r < 0)
+ if (r < 0) {
+ log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m");
+ scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
return r;
+ }
s->result = SCOPE_SUCCESS;
@@ -367,12 +377,12 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F
state = scope_state_from_string(value);
if (state < 0)
- log_debug("Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %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;
}
@@ -398,7 +408,7 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
Scope *s = SCOPE(u);
assert(u);
- log_unit_debug(u->id, "%s: cgroup is empty", u->id);
+ log_unit_debug(u, "cgroup is empty");
if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
scope_enter_dead(s, SCOPE_SUCCESS);
@@ -430,17 +440,17 @@ static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case SCOPE_STOP_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
}
break;
case SCOPE_STOP_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
break;
diff --git a/src/core/scope.h b/src/core/scope.h
index 6c59126422..4452fe2c94 100644
--- a/src/core/scope.h
+++ b/src/core/scope.h
@@ -23,7 +23,6 @@
typedef struct Scope Scope;
-#include "unit.h"
#include "kill.h"
typedef enum ScopeState {
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 18888747f2..5e9a4a5e02 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -24,12 +24,9 @@
#ifdef HAVE_SELINUX
#include <stdio.h>
-#include <string.h>
#include <errno.h>
-#include <limits.h>
#include <selinux/selinux.h>
#include <selinux/avc.h>
-#include <sys/socket.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
#endif
@@ -38,7 +35,6 @@
#include "bus-util.h"
#include "util.h"
#include "log.h"
-#include "audit.h"
#include "selinux-util.h"
#include "audit-fd.h"
#include "strv.h"
@@ -84,17 +80,33 @@ static int audit_callback(
return 0;
}
+static int callback_type_to_priority(int type) {
+ switch(type) {
+ case SELINUX_ERROR: return LOG_ERR;
+ case SELINUX_WARNING: return LOG_WARNING;
+ case SELINUX_INFO: return LOG_INFO;
+ case SELINUX_AVC:
+ default: return LOG_NOTICE;
+ }
+}
+
/*
- Any time an access gets denied this callback will be called
- code copied from dbus. If audit is turned on the messages will go as
- user_avc's into the /var/log/audit/audit.log, otherwise they will be
- sent to syslog.
+ libselinux uses this callback when access gets denied or other
+ events happen. If audit is turned on, messages will be reported
+ using audit netlink, otherwise they will be logged using the usual
+ channels.
+
+ Code copied from dbus and modified.
*/
_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
va_list ap;
#ifdef HAVE_AUDIT
- if (get_audit_fd() >= 0) {
+ int fd;
+
+ fd = get_audit_fd();
+
+ if (fd >= 0) {
_cleanup_free_ char *buf = NULL;
int r;
@@ -103,14 +115,15 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
va_end(ap);
if (r >= 0) {
- audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
+ audit_log_user_avc_message(fd, AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
return 0;
}
}
#endif
va_start(ap, fmt);
- log_internalv(LOG_AUTH | LOG_INFO, 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
+ log_internalv(LOG_AUTH | callback_type_to_priority(type),
+ 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
va_end(ap);
return 0;
@@ -209,6 +222,14 @@ int mac_selinux_generic_access_check(
if (r < 0)
goto finish;
+ /* The SELinux context is something we really should have
+ * gotten directly from the message or sender, and not be an
+ * augmented field. If it was augmented we cannot use it for
+ * authorization, since this is racy and vulnerable. Let's add
+ * an extra check, just in case, even though this really
+ * shouldn't be possible. */
+ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_SELINUX_CONTEXT) == 0, -EPERM);
+
r = sd_bus_creds_get_selinux_context(creds, &scon);
if (r < 0)
goto finish;
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index dd1e8bb9d0..b5758e2e42 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -22,7 +22,6 @@
***/
#include "sd-bus.h"
-#include "bus-error.h"
#include "bus-util.h"
#include "manager.h"
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index fba915d7da..a4678500e6 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -22,8 +22,6 @@
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
@@ -31,8 +29,6 @@
#include "selinux-setup.h"
#include "selinux-util.h"
-#include "label.h"
-#include "mount-setup.h"
#include "macro.h"
#include "util.h"
#include "log.h"
diff --git a/src/core/service.c b/src/core/service.c
index 15e29be149..c7e65772ea 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -21,7 +21,6 @@
#include <errno.h>
#include <signal.h>
-#include <dirent.h>
#include <unistd.h>
#include "async.h"
@@ -46,6 +45,9 @@
#include "bus-error.h"
#include "bus-util.h"
#include "bus-kernel.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "signal-util.h"
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
@@ -137,7 +139,7 @@ static void service_unwatch_pid_file(Service *s) {
if (!s->pid_file_pathspec)
return;
- log_unit_debug(UNIT(s)->id, "Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
+ log_unit_debug(UNIT(s), "Stopping watch for PID file %s", s->pid_file_pathspec->path);
path_spec_unwatch(s->pid_file_pathspec);
path_spec_done(s->pid_file_pathspec);
free(s->pid_file_pathspec);
@@ -167,7 +169,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
s->main_pid_known = true;
if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
- log_unit_warning(UNIT(s)->id, "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", UNIT(s)->id, pid);
+ log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
s->main_pid_alien = true;
} else
s->main_pid_alien = false;
@@ -209,7 +211,7 @@ static void service_start_watchdog(Service *s) {
if (s->watchdog_event_source) {
r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to reset watchdog timer: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m");
return;
}
@@ -222,17 +224,19 @@ static void service_start_watchdog(Service *s) {
s->watchdog_timestamp.monotonic + s->watchdog_usec, 0,
service_dispatch_watchdog, s);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to add watchdog timer: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m");
return;
}
+ (void) sd_event_source_set_description(s->watchdog_event_source, "service-watchdog");
+
/* Let's process everything else which might be a sign
* of living before we consider a service died. */
r = sd_event_source_set_priority(s->watchdog_event_source, SD_EVENT_PRIORITY_IDLE);
}
if (r < 0)
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to install watchdog timer: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to install watchdog timer: %m");
}
static void service_reset_watchdog(Service *s) {
@@ -270,7 +274,7 @@ static void service_release_resources(Unit *u) {
if (!s->fd_store)
return;
- log_debug("Releasing all resources for %s", u->id);
+ log_unit_debug(u, "Releasing all resources.");
while (s->fd_store)
service_fd_store_unlink(s->fd_store);
@@ -371,6 +375,8 @@ static int service_add_fd_store(Service *s, int fd) {
return r;
}
+ (void) sd_event_source_set_description(fs->event_source, "service-fd-store");
+
LIST_PREPEND(fd_store, s->fd_store, fs);
s->n_fd_store++;
@@ -394,16 +400,16 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
r = service_add_fd_store(s, fd);
if (r < 0)
- return log_unit_error_errno(UNIT(s)->id, r, "%s: Couldn't add fd to fd store: %m", UNIT(s)->id);
+ return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
if (r > 0) {
- log_unit_debug(UNIT(s)->id, "%s: added fd to fd store.", UNIT(s)->id);
+ log_unit_debug(UNIT(s), "Added fd to fd store.");
fd = -1;
}
}
if (fdset_size(fds) > 0)
- log_unit_warning(UNIT(s)->id, "%s: tried to store more fds than FDStoreMax=%u allows, closing remaining.", UNIT(s)->id, s->n_fd_store_max);
+ log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
return 0;
}
@@ -421,12 +427,18 @@ static int service_arm_timer(Service *s, usec_t usec) {
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
- return sd_event_add_time(
+ r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + usec, 0,
service_dispatch_timer, s);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s->timer_event_source, "service-timer");
+
+ return 0;
}
static int service_verify(Service *s) {
@@ -436,45 +448,45 @@ static int service_verify(Service *s) {
return 0;
if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) {
- log_unit_error(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service lacks both ExecStart= and ExecStop= setting. Refusing.");
return -EINVAL;
}
if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
- log_unit_error(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
return -EINVAL;
}
if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
- log_unit_error(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.");
return -EINVAL;
}
if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_unit_error(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
return -EINVAL;
}
if (s->type == SERVICE_ONESHOT && s->restart != SERVICE_RESTART_NO) {
- log_unit_error(UNIT(s)->id, "%s has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.");
return -EINVAL;
}
if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) {
- log_unit_error(UNIT(s)->id, "%s has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.");
return -EINVAL;
}
if (s->type == SERVICE_DBUS && !s->bus_name) {
- log_unit_error(UNIT(s)->id, "%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service is of type D-Bus but no D-Bus service name has been specified. Refusing.");
return -EINVAL;
}
if (s->bus_name && s->type != SERVICE_DBUS)
- log_unit_warning(UNIT(s)->id, "%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Service has a D-Bus service name specified, but is not of type dbus. Ignoring.");
if (s->exec_context.pam_name && !(s->kill_context.kill_mode == KILL_CONTROL_GROUP || s->kill_context.kill_mode == KILL_MIXED)) {
- log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.");
return -EINVAL;
}
@@ -556,14 +568,16 @@ static int service_add_extras(Service *s) {
s->notify_access = NOTIFY_MAIN;
if (s->bus_name) {
+#ifdef ENABLE_KDBUS
const char *n;
- r = unit_watch_bus_name(UNIT(s), s->bus_name);
+ n = strjoina(s->bus_name, ".busname");
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
if (r < 0)
return r;
+#endif
- n = strjoina(s->bus_name, ".busname");
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
+ r = unit_watch_bus_name(UNIT(s), s->bus_name);
if (r < 0)
return r;
}
@@ -711,20 +725,20 @@ static int service_load_pid_file(Service *s, bool may_warn) {
r = read_one_line_file(s->pid_file, &k);
if (r < 0) {
if (may_warn)
- log_unit_info(UNIT(s)->id, "PID file %s not readable (yet?) after %s.", s->pid_file, service_state_to_string(s->state));
+ log_unit_info_errno(UNIT(s), r, "PID file %s not readable (yet?) after %s: %m", s->pid_file, service_state_to_string(s->state));
return r;
}
r = parse_pid(k, &pid);
if (r < 0) {
if (may_warn)
- log_unit_info_errno(UNIT(s)->id, r, "Failed to read PID from file %s: %m", s->pid_file);
+ log_unit_info_errno(UNIT(s), r, "Failed to read PID from file %s: %m", s->pid_file);
return r;
}
if (!pid_is_alive(pid)) {
if (may_warn)
- log_unit_info(UNIT(s)->id, "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file);
+ log_unit_info(UNIT(s), "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file);
return -ESRCH;
}
@@ -732,12 +746,12 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (pid == s->main_pid)
return 0;
- log_unit_debug(UNIT(s)->id, "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
+ log_unit_debug(UNIT(s), "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
service_unwatch_main_pid(s);
s->main_pid_known = false;
} else
- log_unit_debug(UNIT(s)->id, "Main PID loaded: "PID_FMT, pid);
+ log_unit_debug(UNIT(s), "Main PID loaded: "PID_FMT, pid);
r = service_set_main_pid(s, pid);
if (r < 0)
@@ -746,7 +760,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
r = unit_watch_pid(UNIT(s), pid);
if (r < 0) {
/* FIXME: we need to do something here */
- log_unit_warning(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid);
return r;
}
@@ -773,7 +787,7 @@ static int service_search_main_pid(Service *s) {
if (pid <= 0)
return -ENOENT;
- log_unit_debug(UNIT(s)->id, "Main PID guessed: "PID_FMT, pid);
+ log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
r = service_set_main_pid(s, pid);
if (r < 0)
return r;
@@ -781,7 +795,7 @@ static int service_search_main_pid(Service *s) {
r = unit_watch_pid(UNIT(s), pid);
if (r < 0) {
/* FIXME: we need to do something here */
- log_unit_warning(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
return r;
}
@@ -804,8 +818,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART))
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
@@ -813,8 +826,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_main_pid(s);
s->main_command = NULL;
@@ -823,8 +835,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
service_unwatch_control_pid(s);
s->control_command = NULL;
@@ -837,8 +848,8 @@ static void service_set_state(Service *s, ServiceState state) {
if (!IN_SET(state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_STOP_SIGABRT, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
!(state == SERVICE_DEAD && UNIT(s)->job)) {
service_close_socket_fd(s);
service_connection_unref(s);
@@ -873,7 +884,7 @@ static void service_set_state(Service *s, ServiceState state) {
}
if (old_state != state)
- log_unit_debug(UNIT(s)->id, "%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state));
+ log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
s->reload_result = SERVICE_SUCCESS;
@@ -891,8 +902,7 @@ static int service_coldplug(Unit *u) {
if (IN_SET(s->deserialized_state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
usec_t k;
@@ -920,8 +930,7 @@ static int service_coldplug(Unit *u) {
IN_SET(s->deserialized_state,
SERVICE_START, SERVICE_START_POST,
SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
r = unit_watch_pid(UNIT(s), s->main_pid);
if (r < 0)
@@ -932,8 +941,7 @@ static int service_coldplug(Unit *u) {
IN_SET(s->deserialized_state,
SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
@@ -1047,10 +1055,10 @@ static int service_spawn(
**argv = NULL, **final_env = NULL, **our_env = NULL;
const char *path;
ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .bus_endpoint_fd = -1,
+ .apply_permissions = apply_permissions,
+ .apply_chroot = apply_chroot,
+ .apply_tty_stdin = apply_tty_stdin,
+ .bus_endpoint_fd = -1,
.selinux_context_net = s->socket_fd_selinux_context_net
};
@@ -1058,7 +1066,11 @@ static int service_spawn(
assert(c);
assert(_pid);
- unit_realize_cgroup(UNIT(s));
+ (void) unit_realize_cgroup(UNIT(s));
+ if (s->reset_cpu_usage) {
+ (void) unit_reset_cpu_usage(UNIT(s));
+ s->reset_cpu_usage = false;
+ }
r = unit_setup_exec_runtime(UNIT(s));
if (r < 0)
@@ -1092,7 +1104,7 @@ static int service_spawn(
if (r < 0)
goto fail;
- our_env = new0(char*, 4);
+ our_env = new0(char*, 6);
if (!our_env) {
r = -ENOMEM;
goto fail;
@@ -1110,12 +1122,52 @@ static int service_spawn(
goto fail;
}
- if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
+ if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) {
r = -ENOMEM;
goto fail;
}
+ if (UNIT_DEREF(s->accept_socket)) {
+ union sockaddr_union sa;
+ socklen_t salen = sizeof(sa);
+
+ r = getpeername(s->socket_fd, &sa.sa, &salen);
+ if (r < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) {
+ _cleanup_free_ char *addr = NULL;
+ char *t;
+ int port;
+
+ r = sockaddr_pretty(&sa.sa, salen, true, false, &addr);
+ if (r < 0)
+ goto fail;
+
+ t = strappend("REMOTE_ADDR=", addr);
+ if (!t) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ our_env[n_env++] = t;
+
+ port = sockaddr_port(&sa.sa);
+ if (port < 0) {
+ r = port;
+ goto fail;
+ }
+
+ if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ our_env[n_env++] = t;
+ }
+ }
+
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
if (!final_env) {
r = -ENOMEM;
@@ -1130,7 +1182,7 @@ static int service_spawn(
#ifdef ENABLE_KDBUS
if (s->exec_context.bus_endpoint) {
- r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
+ r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user",
UNIT(s)->id, &bus_endpoint_path);
if (r < 0)
goto fail;
@@ -1151,13 +1203,13 @@ static int service_spawn(
exec_params.cgroup_path = path;
exec_params.cgroup_delegate = s->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
- exec_params.unit_id = UNIT(s)->id;
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.bus_endpoint_path = bus_endpoint_path;
if (s->type == SERVICE_IDLE)
exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
- r = exec_spawn(c,
+ r = exec_spawn(UNIT(s),
+ c,
&s->exec_context,
&exec_params,
s->exec_runtime,
@@ -1227,6 +1279,49 @@ static int cgroup_good(Service *s) {
return !r;
}
+static bool service_shall_restart(Service *s) {
+ assert(s);
+
+ /* Don't restart after manual stops */
+ if (s->forbid_restart)
+ return false;
+
+ /* Never restart if this is configured as special exception */
+ if (exit_status_set_test(&s->restart_prevent_status, s->main_exec_status.code, s->main_exec_status.status))
+ return false;
+
+ /* Restart if the exit code/status are configured as restart triggers */
+ if (exit_status_set_test(&s->restart_force_status, s->main_exec_status.code, s->main_exec_status.status))
+ return true;
+
+ switch (s->restart) {
+
+ case SERVICE_RESTART_NO:
+ return false;
+
+ case SERVICE_RESTART_ALWAYS:
+ return true;
+
+ case SERVICE_RESTART_ON_SUCCESS:
+ return s->result == SERVICE_SUCCESS;
+
+ case SERVICE_RESTART_ON_FAILURE:
+ return s->result != SERVICE_SUCCESS;
+
+ case SERVICE_RESTART_ON_ABNORMAL:
+ return !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE);
+
+ case SERVICE_RESTART_ON_WATCHDOG:
+ return s->result == SERVICE_FAILURE_WATCHDOG;
+
+ case SERVICE_RESTART_ON_ABORT:
+ return IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP);
+
+ default:
+ assert_not_reached("unknown restart setting");
+ }
+}
+
static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
int r;
assert(s);
@@ -1237,22 +1332,11 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
if (s->result != SERVICE_SUCCESS) {
- log_unit_warning(UNIT(s)->id, "%s failed.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg);
}
- if (allow_restart &&
- !s->forbid_restart &&
- (s->restart == SERVICE_RESTART_ALWAYS ||
- (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
- (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
- (s->restart == SERVICE_RESTART_ON_ABNORMAL && !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE)) ||
- (s->restart == SERVICE_RESTART_ON_WATCHDOG && s->result == SERVICE_FAILURE_WATCHDOG) ||
- (s->restart == SERVICE_RESTART_ON_ABORT && IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP)) ||
- (s->main_exec_status.code == CLD_EXITED && set_contains(s->restart_force_status.status, INT_TO_PTR(s->main_exec_status.status))) ||
- (IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) && set_contains(s->restart_force_status.signal, INT_TO_PTR(s->main_exec_status.status)))) &&
- (s->main_exec_status.code != CLD_EXITED || !set_contains(s->restart_prevent_status.status, INT_TO_PTR(s->main_exec_status.status))) &&
- (!IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) || !set_contains(s->restart_prevent_status.signal, INT_TO_PTR(s->main_exec_status.status)))) {
+ if (allow_restart && service_shall_restart(s)) {
r = service_arm_timer(s, s->restart_usec);
if (r < 0)
@@ -1261,6 +1345,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
service_set_state(s, SERVICE_AUTO_RESTART);
}
+ /* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
s->forbid_restart = false;
/* We want fresh tmpdirs in case service is started again immediately */
@@ -1279,7 +1364,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run install restart timer: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run install restart timer: %m");
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
}
@@ -1316,10 +1401,29 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop-post' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-post' task: %m");
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
+static int state_to_kill_operation(ServiceState state) {
+ switch (state) {
+
+ case SERVICE_STOP_SIGABRT:
+ return KILL_ABORT;
+
+ case SERVICE_STOP_SIGTERM:
+ case SERVICE_FINAL_SIGTERM:
+ return KILL_TERMINATE;
+
+ case SERVICE_STOP_SIGKILL:
+ case SERVICE_FINAL_SIGKILL:
+ return KILL_KILL;
+
+ default:
+ return _KILL_OPERATION_INVALID;
+ }
+}
+
static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
int r;
@@ -1333,8 +1437,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
r = unit_kill_context(
UNIT(s),
&s->kill_context,
- (state != SERVICE_STOP_SIGTERM && state != SERVICE_FINAL_SIGTERM && state != SERVICE_STOP_SIGABRT) ?
- KILL_KILL : (state == SERVICE_STOP_SIGABRT ? KILL_ABORT : KILL_TERMINATE),
+ state_to_kill_operation(state),
s->main_pid,
s->control_pid,
s->main_pid_alien);
@@ -1350,11 +1453,11 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
}
service_set_state(s, state);
- } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGABRT)
+ } else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
- else if (state == SERVICE_STOP_SIGKILL)
+ else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_SUCCESS);
- else if (state == SERVICE_FINAL_SIGTERM)
+ else if (state == SERVICE_FINAL_SIGTERM && s->kill_context.send_sigkill)
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
else
service_enter_dead(s, SERVICE_SUCCESS, true);
@@ -1362,10 +1465,9 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
- if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL ||
- state == SERVICE_STOP_SIGABRT)
+ if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
else
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
@@ -1417,7 +1519,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop' task: %m");
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
@@ -1479,7 +1581,7 @@ static void service_enter_start_post(Service *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-post' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-post' task: %m");
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
@@ -1572,7 +1674,7 @@ static void service_enter_start(Service *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'start' task: %m");
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
@@ -1610,7 +1712,7 @@ static void service_enter_start_pre(Service *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-pre' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-pre' task: %m");
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
}
@@ -1622,7 +1724,7 @@ static void service_enter_restart(Service *s) {
if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
/* Don't restart things if we are going down anyway */
- log_unit_info(UNIT(s)->id, "Stop job pending for unit, delaying automatic restart.");
+ log_unit_info(UNIT(s), "Stop job pending for unit, delaying automatic restart.");
r = service_arm_timer(s, s->restart_usec);
if (r < 0)
@@ -1643,11 +1745,11 @@ static void service_enter_restart(Service *s) {
* it will be canceled as part of the service_stop() call that
* is executed as part of JOB_RESTART. */
- log_unit_debug(UNIT(s)->id, "%s scheduled restart job.", UNIT(s)->id);
+ log_unit_debug(UNIT(s), "Scheduled restart job.");
return;
fail:
- log_unit_warning(UNIT(s)->id, "%s failed to schedule restart job: %s", UNIT(s)->id, bus_error_message(&error, -r));
+ log_unit_warning(UNIT(s), "Failed to schedule restart job: %s", bus_error_message(&error, -r));
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
}
@@ -1690,7 +1792,7 @@ static void service_enter_reload(Service *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'reload' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
}
@@ -1723,7 +1825,7 @@ static void service_run_next_control(Service *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next control task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m");
if (s->state == SERVICE_START_PRE)
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
@@ -1767,7 +1869,7 @@ static void service_run_next_main(Service *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next main task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run next main task: %m");
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
@@ -1777,7 +1879,7 @@ static int service_start_limit_test(Service *s) {
if (ratelimit_test(&s->start_limit))
return 0;
- log_unit_warning(UNIT(s)->id, "start request repeated too quickly for %s", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Start request repeated too quickly.");
return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg);
}
@@ -1790,19 +1892,13 @@ static int service_start(Unit *u) {
/* We cannot fulfill this request right now, try again later
* please! */
- if (s->state == SERVICE_STOP ||
- s->state == SERVICE_STOP_SIGABRT ||
- s->state == SERVICE_STOP_SIGTERM ||
- s->state == SERVICE_STOP_SIGKILL ||
- s->state == SERVICE_STOP_POST ||
- s->state == SERVICE_FINAL_SIGTERM ||
- s->state == SERVICE_FINAL_SIGKILL)
+ if (IN_SET(s->state,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
return -EAGAIN;
/* Already on it! */
- if (s->state == SERVICE_START_PRE ||
- s->state == SERVICE_START ||
- s->state == SERVICE_START_POST)
+ if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST))
return 0;
/* A service that will be restarted must be stopped first to
@@ -1815,7 +1911,7 @@ static int service_start(Unit *u) {
if (s->state == SERVICE_AUTO_RESTART)
return -EAGAIN;
- assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED);
+ assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
/* Make sure we don't enter a busy loop of some kind. */
r = service_start_limit_test(s);
@@ -1829,6 +1925,7 @@ static int service_start(Unit *u) {
s->main_pid_known = false;
s->main_pid_alien = false;
s->forbid_restart = false;
+ s->reset_cpu_usage = true;
free(s->status_text);
s->status_text = NULL;
@@ -1845,17 +1942,13 @@ static int service_stop(Unit *u) {
assert(s);
- /* Don't create restart jobs from here. */
+ /* Don't create restart jobs from manual stops. */
s->forbid_restart = true;
/* Already on it */
- if (s->state == SERVICE_STOP ||
- s->state == SERVICE_STOP_SIGABRT ||
- s->state == SERVICE_STOP_SIGTERM ||
- s->state == SERVICE_STOP_SIGKILL ||
- s->state == SERVICE_STOP_POST ||
- s->state == SERVICE_FINAL_SIGTERM ||
- s->state == SERVICE_FINAL_SIGKILL)
+ if (IN_SET(s->state,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
return 0;
/* A restart will be scheduled or is in progress. */
@@ -1866,16 +1959,12 @@ static int service_stop(Unit *u) {
/* If there's already something running we go directly into
* kill mode. */
- if (s->state == SERVICE_START_PRE ||
- s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RELOAD) {
+ if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD)) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
return 0;
}
- assert(s->state == SERVICE_RUNNING ||
- s->state == SERVICE_EXITED);
+ assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
service_enter_stop(s, SERVICE_SUCCESS);
return 1;
@@ -1913,23 +2002,25 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "reload-result", service_result_to_string(s->reload_result));
if (s->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", PID_FMT,
- s->control_pid);
+ unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
if (s->main_pid_known && s->main_pid > 0)
unit_serialize_item_format(u, f, "main-pid", PID_FMT, s->main_pid);
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
- if (s->status_text)
- unit_serialize_item(u, f, "status-text", s->status_text);
+ if (s->status_text) {
+ _cleanup_free_ char *c = NULL;
+
+ c = cescape(s->status_text);
+ unit_serialize_item(u, f, "status-text", strempty(c));
+ }
/* FIXME: There's a minor uncleanliness here: if there are
* multiple commands attached here, we will start from the
* first one again */
if (s->control_command_id >= 0)
- unit_serialize_item(u, f, "control-command",
- service_exec_command_to_string(s->control_command_id));
+ unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
if (s->socket_fd >= 0) {
int copy;
@@ -1962,20 +2053,16 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
}
if (s->main_exec_status.pid > 0) {
- unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT,
- s->main_exec_status.pid);
- dual_timestamp_serialize(f, "main-exec-status-start",
- &s->main_exec_status.start_timestamp);
- dual_timestamp_serialize(f, "main-exec-status-exit",
- &s->main_exec_status.exit_timestamp);
+ unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT, s->main_exec_status.pid);
+ dual_timestamp_serialize(f, "main-exec-status-start", &s->main_exec_status.start_timestamp);
+ dual_timestamp_serialize(f, "main-exec-status-exit", &s->main_exec_status.exit_timestamp);
if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
- unit_serialize_item_format(u, f, "main-exec-status-code", "%i",
- s->main_exec_status.code);
- unit_serialize_item_format(u, f, "main-exec-status-status", "%i",
- s->main_exec_status.status);
+ unit_serialize_item_format(u, f, "main-exec-status-code", "%i", s->main_exec_status.code);
+ unit_serialize_item_format(u, f, "main-exec-status-status", "%i", s->main_exec_status.status);
}
}
+
if (dual_timestamp_is_set(&s->watchdog_timestamp))
dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
@@ -1999,7 +2086,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
state = service_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
s->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -2007,7 +2094,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
f = service_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != SERVICE_SUCCESS)
s->result = f;
@@ -2016,7 +2103,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
f = service_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse reload result value %s", value);
+ log_unit_debug(u, "Failed to parse reload result value: %s", value);
else if (f != SERVICE_SUCCESS)
s->reload_result = f;
@@ -2024,14 +2111,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u, "Failed to parse control-pid value: %s", value);
else
s->control_pid = pid;
} else if (streq(key, "main-pid")) {
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse main-pid value %s", value);
+ log_unit_debug(u, "Failed to parse main-pid value: %s", value);
else {
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
@@ -2041,15 +2128,15 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
b = parse_boolean(value);
if (b < 0)
- log_unit_debug(u->id, "Failed to parse main-pid-known value %s", value);
+ log_unit_debug(u, "Failed to parse main-pid-known value: %s", value);
else
s->main_pid_known = b;
} else if (streq(key, "status-text")) {
char *t;
- t = strdup(value);
- if (!t)
- log_oom();
+ r = cunescape(value, 0, &t);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to unescape status text: %s", value);
else {
free(s->status_text);
s->status_text = t;
@@ -2060,7 +2147,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
id = service_exec_command_from_string(value);
if (id < 0)
- log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
+ log_unit_debug(u, "Failed to parse exec-command value: %s", value);
else {
s->control_command_id = id;
s->control_command = s->exec_command[id];
@@ -2069,7 +2156,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse socket-fd value %s", value);
+ log_unit_debug(u, "Failed to parse socket-fd value: %s", value);
else {
asynchronous_close(s->socket_fd);
s->socket_fd = fdset_remove(fds, fd);
@@ -2078,7 +2165,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse endpoint-fd value %s", value);
+ log_unit_debug(u, "Failed to parse endpoint-fd value: %s", value);
else {
safe_close(s->bus_endpoint_fd);
s->bus_endpoint_fd = fdset_remove(fds, fd);
@@ -2087,11 +2174,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse fd-store-fd value %s", value);
+ log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
else {
r = service_add_fd_store(s, fd);
if (r < 0)
- log_unit_error_errno(u->id, r, "Failed to add fd to store: %m");
+ log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else if (r > 0)
fdset_remove(fds, fd);
}
@@ -2100,21 +2187,21 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse main-exec-status-pid value %s", value);
+ log_unit_debug(u, "Failed to parse main-exec-status-pid value: %s", value);
else
s->main_exec_status.pid = pid;
} else if (streq(key, "main-exec-status-code")) {
int i;
if (safe_atoi(value, &i) < 0)
- log_unit_debug(u->id, "Failed to parse main-exec-status-code value %s", value);
+ log_unit_debug(u, "Failed to parse main-exec-status-code value: %s", value);
else
s->main_exec_status.code = i;
} else if (streq(key, "main-exec-status-status")) {
int i;
if (safe_atoi(value, &i) < 0)
- log_unit_debug(u->id, "Failed to parse main-exec-status-status value %s", value);
+ log_unit_debug(u, "Failed to parse main-exec-status-status value: %s", value);
else
s->main_exec_status.status = i;
} else if (streq(key, "main-exec-status-start"))
@@ -2128,11 +2215,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
b = parse_boolean(value);
if (b < 0)
- log_unit_debug(u->id, "Failed to parse forbid-restart value %s", value);
+ log_unit_debug(u, "Failed to parse forbid-restart value: %s", value);
else
s->forbid_restart = b;
} else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -2195,19 +2282,19 @@ static int service_retry_pid_file(Service *s) {
static int service_watch_pid_file(Service *s) {
int r;
- log_unit_debug(UNIT(s)->id, "Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
+ 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_io);
if (r < 0)
goto fail;
/* the pidfile might have appeared just before we set the watch */
- log_unit_debug(UNIT(s)->id, "Trying to read %s's PID file %s in case it changed", UNIT(s)->id, s->pid_file_pathspec->path);
+ log_unit_debug(UNIT(s), "Trying to read PID file %s in case it changed", s->pid_file_pathspec->path);
service_retry_pid_file(s);
return 0;
fail:
- log_unit_error_errno(UNIT(s)->id, r, "Failed to set a watch for %s's PID file %s: %m", UNIT(s)->id, s->pid_file_pathspec->path);
+ log_unit_error_errno(UNIT(s), r, "Failed to set a watch for PID file %s: %m", s->pid_file_pathspec->path);
service_unwatch_pid_file(s);
return r;
}
@@ -2255,7 +2342,7 @@ static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events,
assert(s->pid_file_pathspec);
assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
- log_unit_debug(UNIT(s)->id, "inotify event for %s", UNIT(s)->id);
+ log_unit_debug(UNIT(s), "inotify event");
if (path_spec_fd_event(p, events) < 0)
goto fail;
@@ -2279,7 +2366,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
assert(u);
- log_unit_debug(u->id, "%s: cgroup is empty", u->id);
+ log_unit_debug(u, "cgroup is empty");
switch (s->state) {
@@ -2294,7 +2381,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
/* If we were hoping for the daemon to write its PID file,
* we can give up now. */
if (s->pid_file_pathspec) {
- log_unit_warning(u->id, "%s never wrote its PID file. Failing.", UNIT(s)->id);
+ log_unit_warning(u, "Daemon never wrote its PID file. Failing.");
service_unwatch_pid_file(s);
if (s->state == SERVICE_START)
@@ -2381,16 +2468,16 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
f = SERVICE_SUCCESS;
}
- log_unit_struct(u->id,
- f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- LOG_MESSAGE("%s: main process exited, code=%s, status=%i/%s",
- u->id, sigchld_code_to_string(code), status,
+ log_struct(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+ LOG_UNIT_ID(u),
+ LOG_UNIT_MESSAGE(u, "Main process exited, code=%s, status=%i/%s",
+ sigchld_code_to_string(code), status,
strna(code == CLD_EXITED
? exit_status_to_string(status, EXIT_STATUS_FULL)
: signal_to_string(status))),
- "EXIT_CODE=%s", sigchld_code_to_string(code),
- "EXIT_STATUS=%i", status,
- NULL);
+ "EXIT_CODE=%s", sigchld_code_to_string(code),
+ "EXIT_STATUS=%i", status,
+ NULL);
if (f != SERVICE_SUCCESS)
s->result = f;
@@ -2402,7 +2489,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* There is another command to *
* execute, so let's do that. */
- log_unit_debug(u->id, "%s running next main command for state %s", u->id, service_state_to_string(s->state));
+ log_unit_debug(u, "Running next main command for state %s.", service_state_to_string(s->state));
service_run_next_main(s);
} else {
@@ -2469,10 +2556,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
f = SERVICE_SUCCESS;
}
- log_unit_full(u->id,
- f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s: control process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
+ log_unit_full(u, f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
+ "Control process exited, code=%s status=%i",
+ sigchld_code_to_string(code), status);
if (f != SERVICE_SUCCESS)
s->result = f;
@@ -2489,7 +2575,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* There is another command to *
* execute, so let's do that. */
- log_unit_debug(u->id, "%s running next control command for state %s", u->id, service_state_to_string(s->state));
+ log_unit_debug(u, "Running next control command for state %s.", service_state_to_string(s->state));
service_run_next_control(s);
} else {
@@ -2499,7 +2585,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- log_unit_debug(u->id, "%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state));
+ log_unit_debug(u, "Got final SIGCHLD for state %s.", service_state_to_string(s->state));
switch (s->state) {
@@ -2628,38 +2714,37 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
case SERVICE_START_PRE:
case SERVICE_START:
- log_unit_warning(UNIT(s)->id, "%s %s operation timed out. Terminating.", UNIT(s)->id, s->state == SERVICE_START ? "start" : "start-pre");
+ log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", s->state == SERVICE_START ? "Start" : "Start-pre");
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_START_POST:
- log_unit_warning(UNIT(s)->id, "%s start-post operation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping.");
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_RELOAD:
- log_unit_warning(UNIT(s)->id, "%s reload operation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Reload operation timed out. Stopping.");
s->reload_result = SERVICE_FAILURE_TIMEOUT;
service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_STOP:
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_STOP_SIGABRT:
- log_unit_warning(UNIT(s)->id,
- "%s stop-sigabrt timed out. Terminating.", UNIT(s)->id);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, s->result);
+ log_unit_warning(UNIT(s), "State 'stop-sigabrt' timed out. Terminating.");
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_STOP_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stop-sigterm timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Killing.");
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Skipping SIGKILL.");
service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
}
@@ -2670,37 +2755,36 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
* Must be something we cannot kill, so let's just be
* weirded out and continue */
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Processes still around after SIGKILL. Ignoring.");
service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_STOP_POST:
- log_unit_warning(UNIT(s)->id, "%s stop-post timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_FINAL_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Killing.");
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
}
break;
case SERVICE_FINAL_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Processes still around after final SIGKILL. Entering failed mode.");
service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
break;
case SERVICE_AUTO_RESTART:
- log_unit_info(UNIT(s)->id,
+ log_unit_info(UNIT(s),
s->restart_usec > 0 ?
- "%s holdoff time over, scheduling restart." :
- "%s has no holdoff time, scheduling restart.",
- UNIT(s)->id);
+ "Service hold-off time over, scheduling restart." :
+ "Service has no hold-off time, scheduling restart.");
service_enter_restart(s);
break;
@@ -2718,7 +2802,7 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void
assert(s);
assert(source == s->watchdog_event_source);
- log_unit_error(UNIT(s)->id, "%s watchdog timeout (limit %s)!", UNIT(s)->id,
+ log_unit_error(UNIT(s), "Watchdog timeout (limit %s)!",
format_timespan(t, sizeof(t), s->watchdog_usec, 1));
service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG);
@@ -2735,30 +2819,25 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
assert(u);
cc = strv_join(tags, ", ");
- log_unit_debug(u->id, "%s: Got notification message from PID "PID_FMT" (%s)",
- u->id, pid, isempty(cc) ? "n/a" : cc);
if (s->notify_access == NOTIFY_NONE) {
- log_unit_warning(u->id, "%s: Got notification message from PID "PID_FMT", but reception is disabled.", u->id, pid);
+ log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception is disabled.", pid);
return;
- }
-
- if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
+ } else if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
if (s->main_pid != 0)
- log_unit_warning(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, u->id, pid, s->main_pid);
+ log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
else
- log_unit_debug(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", u->id, pid);
+ log_unit_debug(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid);
return;
- }
+ } else
+ log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", pid, isempty(cc) ? "n/a" : cc);
/* Interpret MAINPID= */
e = strv_find_startswith(tags, "MAINPID=");
if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
if (parse_pid(e, &pid) < 0)
- log_unit_warning(u->id, "Failed to parse MAINPID= field in notification message: %s", e);
+ log_unit_warning(u, "Failed to parse MAINPID= field in notification message: %s", e);
else {
- log_unit_debug(u->id, "%s: got MAINPID=%s", u->id, e);
-
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
notify_dbus = true;
@@ -2768,7 +2847,6 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
/* Interpret RELOADING= */
if (strv_find(tags, "RELOADING=1")) {
- log_unit_debug(u->id, "%s: got RELOADING=1", u->id);
s->notify_state = NOTIFY_RELOADING;
if (s->state == SERVICE_RUNNING)
@@ -2780,7 +2858,6 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
/* Interpret READY= */
if (strv_find(tags, "READY=1")) {
- log_unit_debug(u->id, "%s: got READY=1", u->id);
s->notify_state = NOTIFY_READY;
/* Type=notify services inform us about completed
@@ -2799,7 +2876,6 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
/* Interpret STOPPING= */
if (strv_find(tags, "STOPPING=1")) {
- log_unit_debug(u->id, "%s: got STOPPING=1", u->id);
s->notify_state = NOTIFY_STOPPING;
if (s->state == SERVICE_RUNNING)
@@ -2815,10 +2891,8 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
if (!isempty(e)) {
if (!utf8_is_valid(e))
- log_unit_warning(u->id, "Status message in notification is not UTF-8 clean.");
+ log_unit_warning(u, "Status message in notification message is not UTF-8 clean.");
else {
- log_unit_debug(u->id, "%s: got STATUS=%s", u->id, e);
-
t = strdup(e);
if (!t)
log_oom();
@@ -2841,10 +2915,8 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
int status_errno;
if (safe_atoi(e, &status_errno) < 0 || status_errno < 0)
- log_unit_warning(u->id, "Failed to parse ERRNO= field in notification message: %s", e);
+ log_unit_warning(u, "Failed to parse ERRNO= field in notification message: %s", e);
else {
- log_unit_debug(u->id, "%s: got ERRNO=%s", u->id, e);
-
if (s->status_errno != status_errno) {
s->status_errno = status_errno;
notify_dbus = true;
@@ -2854,13 +2926,11 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
/* Interpret WATCHDOG= */
if (strv_find(tags, "WATCHDOG=1")) {
- log_unit_debug(u->id, "%s: got WATCHDOG=1", u->id);
service_reset_watchdog(s);
}
/* Add the passed fds to the fd store */
if (strv_find(tags, "FDSTORE=1")) {
- log_unit_debug(u->id, "%s: got FDSTORE=1", u->id);
service_add_fd_store_set(s, fds);
}
@@ -2899,11 +2969,11 @@ static void service_bus_name_owner_change(
assert(old_owner || new_owner);
if (old_owner && new_owner)
- log_unit_debug(u->id, "%s's D-Bus name %s changed owner from %s to %s", u->id, name, old_owner, new_owner);
+ log_unit_debug(u, "D-Bus name %s changed owner from %s to %s", name, old_owner, new_owner);
else if (old_owner)
- log_unit_debug(u->id, "%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
+ log_unit_debug(u, "D-Bus name %s no longer registered by %s", name, old_owner);
else
- log_unit_debug(u->id, "%s's D-Bus name %s now registered by %s", u->id, name, new_owner);
+ log_unit_debug(u, "D-Bus name %s now registered by %s", name, new_owner);
s->bus_name_good = !!new_owner;
@@ -2932,7 +3002,7 @@ static void service_bus_name_owner_change(
if (r >= 0)
r = sd_bus_creds_get_pid(creds, &pid);
if (r >= 0) {
- log_unit_debug(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
+ log_unit_debug(u, "D-Bus name %s is now owned by process %u", name, (unsigned) pid);
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
diff --git a/src/core/service.h b/src/core/service.h
index dfeee6a68c..7da0a93961 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -24,12 +24,10 @@
typedef struct Service Service;
typedef struct ServiceFDStore ServiceFDStore;
-#include "unit.h"
#include "path.h"
#include "ratelimit.h"
#include "kill.h"
#include "exit-status.h"
-#include "failure-action.h"
typedef enum ServiceState {
SERVICE_DEAD,
@@ -191,6 +189,8 @@ struct Service {
bool forbid_restart:1;
bool start_timeout_defined:1;
+ bool reset_cpu_usage:1;
+
char *bus_name;
char *status_text;
@@ -216,8 +216,6 @@ struct Service {
extern const UnitVTable service_vtable;
-struct Socket;
-
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
const char* service_state_to_string(ServiceState i) _const_;
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 71f001ac13..aba16b4689 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -20,21 +20,15 @@
***/
#include <sys/mman.h>
-#include <sys/types.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
-#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mount.h>
-#include <sys/syscall.h>
-#include <fcntl.h>
-#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <string.h>
#include <getopt.h>
#include "missing.h"
@@ -42,14 +36,14 @@
#include "fileio.h"
#include "umount.h"
#include "util.h"
-#include "mkdir.h"
#include "virt.h"
#include "watchdog.h"
#include "killall.h"
#include "cgroup-util.h"
#include "def.h"
#include "switch-root.h"
-#include "strv.h"
+#include "process-util.h"
+#include "terminal-util.h"
#define FINALIZE_ATTEMPTS 50
diff --git a/src/core/slice.c b/src/core/slice.c
index ae9819d015..e52bf71515 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -20,12 +20,9 @@
***/
#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
#include "unit.h"
#include "slice.h"
-#include "load-fragment.h"
#include "log.h"
#include "dbus-slice.h"
#include "special.h"
@@ -96,27 +93,28 @@ static int slice_add_default_dependencies(Slice *s) {
return 0;
}
+
static int slice_verify(Slice *s) {
+ _cleanup_free_ char *parent = NULL;
+ int r;
+
assert(s);
if (UNIT(s)->load_state != UNIT_LOADED)
return 0;
- if (UNIT_DEREF(UNIT(s)->slice)) {
- char *a, *dash;
+ if (!slice_name_is_valid(UNIT(s)->id)) {
+ log_unit_error(UNIT(s), "Slice name %s is not valid. Refusing.", UNIT(s)->id);
+ return -EINVAL;
+ }
- a = strdupa(UNIT(s)->id);
- dash = strrchr(a, '-');
- if (dash)
- strcpy(dash, ".slice");
- else
- a = (char*) SPECIAL_ROOT_SLICE;
+ r = slice_build_parent_slice(UNIT(s)->id, &parent);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m");
- if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
- log_unit_error(UNIT(s)->id,
- "%s located outside its parent slice. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
+ if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) {
+ log_unit_error(UNIT(s), "Located outside of parent slice. Refusing.");
+ return -EINVAL;
}
return 0;
@@ -184,7 +182,8 @@ static int slice_start(Unit *u) {
assert(t);
assert(t->state == SLICE_DEAD);
- unit_realize_cgroup(u);
+ (void) unit_realize_cgroup(u);
+ (void) unit_reset_cpu_usage(u);
slice_set_state(t, SLICE_ACTIVE);
return 1;
diff --git a/src/core/slice.h b/src/core/slice.h
index ad0c63902b..ac648e56f8 100644
--- a/src/core/slice.h
+++ b/src/core/slice.h
@@ -23,7 +23,6 @@
typedef struct Slice Slice;
-#include "unit.h"
typedef enum SliceState {
SLICE_DEAD,
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index 59f6832bc2..ff2a02004d 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -24,21 +24,15 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <sys/vfs.h>
#include <fcntl.h>
-#include <sys/types.h>
#include <dirent.h>
-#include <sys/mount.h>
-#include <stdint.h>
#include "macro.h"
#include "smack-setup.h"
#include "util.h"
#include "fileio.h"
#include "log.h"
-#include "label.h"
#define SMACK_CONFIG "/etc/smack/accesses.d/"
#define CIPSO_CONFIG "/etc/smack/cipso.d/"
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
index b70c3beb60..1e634b9bc1 100644
--- a/src/core/snapshot.c
+++ b/src/core/snapshot.c
@@ -51,11 +51,7 @@ static void snapshot_set_state(Snapshot *s, SnapshotState state) {
s->state = state;
if (state != old_state)
- log_unit_debug(UNIT(s)->id,
- "%s changed %s -> %s",
- UNIT(s)->id,
- snapshot_state_to_string(old_state),
- snapshot_state_to_string(state));
+ log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -155,7 +151,7 @@ static int snapshot_deserialize_item(Unit *u, const char *key, const char *value
state = snapshot_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
s->deserialized_state = state;
@@ -163,7 +159,7 @@ static int snapshot_deserialize_item(Unit *u, const char *key, const char *value
r = parse_boolean(value);
if (r < 0)
- log_unit_debug(u->id, "Failed to parse cleanup value %s", value);
+ log_unit_debug(u, "Failed to parse cleanup value: %s", value);
else
s->cleanup = r;
@@ -173,7 +169,7 @@ static int snapshot_deserialize_item(Unit *u, const char *key, const char *value
if (r < 0)
return r;
} else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -201,10 +197,10 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e,
assert(_s);
if (name) {
- if (!unit_name_is_valid(name, TEMPLATE_INVALID))
+ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
- if (unit_name_to_type(name) != UNIT_SNAPSHOT)
+ if (!endswith(name, ".snapshot"))
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
if (manager_get_unit(m, name))
@@ -258,7 +254,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e,
SNAPSHOT(u)->cleanup = cleanup;
*_s = SNAPSHOT(u);
- log_unit_info(u->id, "Created snapshot %s.", u->id);
+ log_unit_info(u, "Created snapshot.");
return 0;
@@ -272,7 +268,7 @@ fail:
void snapshot_remove(Snapshot *s) {
assert(s);
- log_unit_info(UNIT(s)->id, "Removing snapshot %s.", UNIT(s)->id);
+ log_unit_info(UNIT(s), "Removing snapshot.");
unit_add_to_cleanup_queue(UNIT(s));
}
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
index e6dc661060..f2451b1193 100644
--- a/src/core/snapshot.h
+++ b/src/core/snapshot.h
@@ -23,7 +23,6 @@
typedef struct Snapshot Snapshot;
-#include "unit.h"
typedef enum SnapshotState {
SNAPSHOT_DEAD,
diff --git a/src/core/socket.c b/src/core/socket.c
index 48c43a2880..fc5eb1464a 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
@@ -29,12 +28,9 @@
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <mqueue.h>
-#include <sys/xattr.h>
#include "sd-event.h"
#include "log.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
#include "strv.h"
#include "mkdir.h"
#include "path-util.h"
@@ -51,6 +47,8 @@
#include "selinux-util.h"
#include "dbus-socket.h"
#include "unit.h"
+#include "formats-util.h"
+#include "signal-util.h"
#include "socket.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
@@ -173,12 +171,18 @@ static int socket_arm_timer(Socket *s) {
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
- return sd_event_add_time(
+ r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
socket_dispatch_timer, s);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s->timer_event_source, "socket-timer");
+
+ return 0;
}
int socket_instantiate_service(Socket *s) {
@@ -193,12 +197,15 @@ int socket_instantiate_service(Socket *s) {
* here. For Accept=no this is mostly a NOP since the service
* is figured out at load time anyway. */
- if (UNIT_DEREF(s->service) || !s->accept)
+ if (UNIT_DEREF(s->service))
return 0;
- prefix = unit_name_to_prefix(UNIT(s)->id);
- if (!prefix)
- return -ENOMEM;
+ if (!s->accept)
+ return 0;
+
+ r = unit_name_to_prefix(UNIT(s)->id, &prefix);
+ if (r < 0)
+ return r;
if (asprintf(&name, "%s@%u.service", prefix, s->n_accepted) < 0)
return -ENOMEM;
@@ -278,7 +285,7 @@ static int socket_add_default_dependencies(Socket *s) {
if (r < 0)
return r;
- if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) {
+ if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -392,33 +399,32 @@ static int socket_verify(Socket *s) {
return 0;
if (!s->ports) {
- log_unit_error(UNIT(s)->id, "%s lacks Listen setting. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Unit lacks Listen setting. Refusing.");
return -EINVAL;
}
if (s->accept && have_non_accept_socket(s)) {
- log_unit_error(UNIT(s)->id, "%s configured for accepting sockets, but sockets are non-accepting. Refusing.",
- UNIT(s)->id);
+ log_unit_error(UNIT(s), "Unit configured for accepting sockets, but sockets are non-accepting. Refusing.");
return -EINVAL;
}
if (s->accept && s->max_connections <= 0) {
- log_unit_error(UNIT(s)->id, "%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "MaxConnection= setting too small. Refusing.");
return -EINVAL;
}
if (s->accept && UNIT_DEREF(s->service)) {
- log_unit_error(UNIT(s)->id, "Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Explicit service configuration for accepting socket units not supported. Refusing.");
return -EINVAL;
}
if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing.");
return -EINVAL;
}
if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) {
- log_unit_error(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Unit has symlinks set but none or more than one node in the file system. Refusing.");
return -EINVAL;
}
@@ -816,60 +822,60 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (s->keep_alive) {
int b = s->keep_alive;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_KEEPALIVE failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_KEEPALIVE failed: %m");
}
if (s->keep_alive_time) {
int value = s->keep_alive_time / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_KEEPIDLE failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPIDLE failed: %m");
}
if (s->keep_alive_interval) {
int value = s->keep_alive_interval / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_KEEPINTVL failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPINTVL failed: %m");
}
if (s->keep_alive_cnt) {
int value = s->keep_alive_cnt;
if (setsockopt(fd, SOL_SOCKET, TCP_KEEPCNT, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_KEEPCNT failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPCNT failed: %m");
}
if (s->defer_accept) {
int value = s->defer_accept / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_DEFER_ACCEPT failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "TCP_DEFER_ACCEPT failed: %m");
}
if (s->no_delay) {
int b = s->no_delay;
if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_NODELAY failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m");
}
if (s->broadcast) {
int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_BROADCAST failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_BROADCAST failed: %m");
}
if (s->pass_cred) {
int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_PASSCRED failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_PASSCRED failed: %m");
}
if (s->pass_sec) {
int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_PASSSEC failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_PASSSEC failed: %m");
}
if (s->priority >= 0)
if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_PRIORITY failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_PRIORITY failed: %m");
if (s->receive_buffer > 0) {
int value = (int) s->receive_buffer;
@@ -878,23 +884,23 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_RCVBUF failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_RCVBUF failed: %m");
}
if (s->send_buffer > 0) {
int value = (int) s->send_buffer;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_SNDBUF failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_SNDBUF failed: %m");
}
if (s->mark >= 0)
if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_MARK failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_MARK failed: %m");
if (s->ip_tos >= 0)
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
- log_unit_warning(UNIT(s)->id, "IP_TOS failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "IP_TOS failed: %m");
if (s->ip_ttl >= 0) {
int x;
@@ -909,30 +915,29 @@ static void socket_apply_socket_options(Socket *s, int fd) {
}
if (r < 0 && x < 0)
- log_unit_warning(UNIT(s)->id,
- "IP_TTL/IPV6_UNICAST_HOPS failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "IP_TTL/IPV6_UNICAST_HOPS failed: %m");
}
if (s->tcp_congestion)
if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_CONGESTION failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "TCP_CONGESTION failed: %m");
if (s->reuse_port) {
int b = s->reuse_port;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &b, sizeof(b)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_REUSEPORT failed: %m");
+ log_unit_warning_errno(UNIT(s), errno, "SO_REUSEPORT failed: %m");
}
if (s->smack_ip_in) {
r = mac_smack_apply_ip_in_fd(fd, s->smack_ip_in);
if (r < 0)
- log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_ip_in_fd: %m");
+ log_unit_error_errno(UNIT(s), r, "mac_smack_apply_ip_in_fd: %m");
}
if (s->smack_ip_out) {
r = mac_smack_apply_ip_out_fd(fd, s->smack_ip_out);
if (r < 0)
- log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_ip_out_fd: %m");
+ log_unit_error_errno(UNIT(s), r, "mac_smack_apply_ip_out_fd: %m");
}
}
@@ -944,12 +949,12 @@ static void socket_apply_fifo_options(Socket *s, int fd) {
if (s->pipe_size > 0)
if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
- log_unit_warning(UNIT(s)->id, "F_SETPIPE_SZ: %m");
+ log_unit_warning_errno(UNIT(s), errno, "F_SETPIPE_SZ: %m");
if (s->smack) {
r = mac_smack_apply_fd(fd, s->smack);
if (r < 0)
- log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_fd: %m");
+ log_unit_error_errno(UNIT(s), r, "mac_smack_apply_fd: %m");
}
}
@@ -1250,7 +1255,7 @@ static void socket_unwatch_fds(Socket *s) {
r = sd_event_source_set_enabled(p->event_source, SD_EVENT_OFF);
if (r < 0)
- log_unit_debug(UNIT(s)->id, "Failed to disable event source.");
+ log_unit_debug_errno(UNIT(s), r, "Failed to disable event source: %m");
}
}
@@ -1264,20 +1269,23 @@ static int socket_watch_fds(Socket *s) {
if (p->fd < 0)
continue;
- if (p->event_source)
+ if (p->event_source) {
r = sd_event_source_set_enabled(p->event_source, SD_EVENT_ON);
- else
+ if (r < 0)
+ goto fail;
+ } else {
r = sd_event_add_io(UNIT(s)->manager->event, &p->event_source, p->fd, EPOLLIN, socket_dispatch_io, p);
+ if (r < 0)
+ goto fail;
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "Failed to watch listening fds: %m");
- goto fail;
+ (void) sd_event_source_set_description(p->event_source, "socket-port-io");
}
}
return 0;
fail:
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch listening fds: %m");
socket_unwatch_fds(s);
return r;
}
@@ -1320,8 +1328,7 @@ static void socket_set_state(Socket *s, SocketState state) {
socket_close_fds(s);
if (state != old_state)
- log_unit_debug(UNIT(s)->id, "%s changed %s -> %s",
- UNIT(s)->id, socket_state_to_string(old_state), socket_state_to_string(state));
+ log_unit_debug(UNIT(s), "Changed %s -> %s", socket_state_to_string(old_state), socket_state_to_string(state));
unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -1390,13 +1397,18 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
+ .bus_endpoint_fd = -1,
};
assert(s);
assert(c);
assert(_pid);
- unit_realize_cgroup(UNIT(s));
+ (void) unit_realize_cgroup(UNIT(s));
+ if (s->reset_cpu_usage) {
+ (void) unit_reset_cpu_usage(UNIT(s));
+ s->reset_cpu_usage = false;
+ }
r = unit_setup_exec_runtime(UNIT(s));
if (r < 0)
@@ -1417,9 +1429,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
exec_params.cgroup_path = UNIT(s)->cgroup_path;
exec_params.cgroup_delegate = s->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
- exec_params.unit_id = UNIT(s)->id;
- r = exec_spawn(c,
+ r = exec_spawn(UNIT(s),
+ c,
&s->exec_context,
&exec_params,
s->exec_runtime,
@@ -1563,9 +1575,7 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
return;
fail:
- log_unit_warning(UNIT(s)->id,
- "%s failed to run 'stop-post' task: %s",
- UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-post' task: %m");
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
}
@@ -1606,7 +1616,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
@@ -1637,7 +1647,7 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop-pre' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-pre' task: %m");
socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
}
@@ -1647,7 +1657,7 @@ static void socket_enter_listening(Socket *s) {
r = socket_watch_fds(s);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to watch sockets: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
goto fail;
}
@@ -1669,7 +1679,7 @@ static void socket_enter_start_post(Socket *s) {
if (s->control_command) {
r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-post' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-post' task: %m");
goto fail;
}
@@ -1690,7 +1700,7 @@ static void socket_enter_start_chown(Socket *s) {
r = socket_open_fds(s);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to listen on sockets: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to listen on sockets: %m");
goto fail;
}
@@ -1702,7 +1712,7 @@ static void socket_enter_start_chown(Socket *s) {
r = socket_chown(s, &s->control_pid);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to fork 'start-chown' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to fork 'start-chown' task: %m");
goto fail;
}
@@ -1727,7 +1737,7 @@ static void socket_enter_start_pre(Socket *s) {
if (s->control_command) {
r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-pre' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-pre' task: %m");
goto fail;
}
@@ -1751,7 +1761,7 @@ static void socket_enter_running(Socket *s, int cfd) {
* shut down anyway */
if (unit_stop_pending(UNIT(s))) {
- log_unit_debug(UNIT(s)->id, "Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
+ log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
if (cfd >= 0)
safe_close(cfd);
@@ -1761,14 +1771,14 @@ static void socket_enter_running(Socket *s, int cfd) {
r = socket_open_fds(s);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to listen on sockets: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to listen on sockets: %m");
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
return;
}
r = socket_watch_fds(s);
if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to watch sockets: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
}
}
@@ -1791,7 +1801,7 @@ static void socket_enter_running(Socket *s, int cfd) {
if (!pending) {
if (!UNIT_ISSET(s->service)) {
- log_unit_error(UNIT(s)->id, "%s: service to activate vanished, refusing activation.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Service to activate vanished, refusing activation.");
r = -ENOENT;
goto fail;
}
@@ -1807,7 +1817,7 @@ static void socket_enter_running(Socket *s, int cfd) {
Service *service;
if (s->n_connections >= s->max_connections) {
- log_unit_warning(UNIT(s)->id, "%s: Too many incoming connections (%u)", UNIT(s)->id, s->n_connections);
+ log_unit_warning(UNIT(s), "Too many incoming connections (%u)", s->n_connections);
safe_close(cfd);
return;
}
@@ -1827,17 +1837,13 @@ static void socket_enter_running(Socket *s, int cfd) {
return;
}
- prefix = unit_name_to_prefix(UNIT(s)->id);
- if (!prefix) {
- r = -ENOMEM;
+ r = unit_name_to_prefix(UNIT(s)->id, &prefix);
+ if (r < 0)
goto fail;
- }
- name = unit_name_build(prefix, instance, ".service");
- if (!name) {
- r = -ENOMEM;
+ r = unit_name_build(prefix, instance, ".service", &name);
+ if (r < 0)
goto fail;
- }
r = unit_add_name(UNIT_DEREF(s->service), name);
if (r < 0)
@@ -1869,8 +1875,8 @@ static void socket_enter_running(Socket *s, int cfd) {
return;
fail:
- log_unit_warning(UNIT(s)->id, "%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
- UNIT(s)->id, cfd >= 0 ? "template" : "non-template",
+ 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));
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
@@ -1895,7 +1901,7 @@ static void socket_run_next(Socket *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run next task: %m");
if (s->state == SOCKET_START_POST)
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
@@ -1935,7 +1941,7 @@ static int socket_start(Unit *u) {
service = SERVICE(UNIT_DEREF(s->service));
if (UNIT(service)->load_state != UNIT_LOADED) {
- log_unit_error(u->id, "Socket service %s not loaded, refusing.", UNIT(service)->id);
+ log_unit_error(u, "Socket service %s not loaded, refusing.", UNIT(service)->id);
return -ENOENT;
}
@@ -1944,7 +1950,7 @@ static int socket_start(Unit *u) {
if (service->state != SERVICE_DEAD &&
service->state != SERVICE_FAILED &&
service->state != SERVICE_AUTO_RESTART) {
- log_unit_error(u->id, "Socket service %s already active, refusing.", UNIT(service)->id);
+ log_unit_error(u, "Socket service %s already active, refusing.", UNIT(service)->id);
return -EBUSY;
}
}
@@ -1952,6 +1958,8 @@ static int socket_start(Unit *u) {
assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
s->result = SOCKET_SUCCESS;
+ s->reset_cpu_usage = true;
+
socket_enter_start_pre(s);
return 1;
@@ -2054,7 +2062,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
state = socket_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
s->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -2062,7 +2070,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
f = socket_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != SOCKET_SUCCESS)
s->result = f;
@@ -2070,14 +2078,14 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
unsigned k;
if (safe_atou(value, &k) < 0)
- log_unit_debug(u->id, "Failed to parse n-accepted value %s", value);
+ log_unit_debug(u, "Failed to parse n-accepted value: %s", value);
else
s->n_accepted += k;
} else if (streq(key, "control-pid")) {
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u, "Failed to parse control-pid value: %s", value);
else
s->control_pid = pid;
} else if (streq(key, "control-command")) {
@@ -2085,7 +2093,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
id = socket_exec_command_from_string(value);
if (id < 0)
- log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
+ log_unit_debug(u, "Failed to parse exec-command value: %s", value);
else {
s->control_command_id = id;
s->control_command = s->exec_command[id];
@@ -2095,12 +2103,12 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse fifo value %s", value);
+ log_unit_debug(u, "Failed to parse fifo value: %s", value);
else {
LIST_FOREACH(port, p, s->ports)
if (p->type == SOCKET_FIFO &&
- streq_ptr(p->path, value+skip))
+ path_equal_or_files_same(p->path, value+skip))
break;
if (p) {
@@ -2114,12 +2122,12 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse special value %s", value);
+ log_unit_debug(u, "Failed to parse special value: %s", value);
else {
LIST_FOREACH(port, p, s->ports)
if (p->type == SOCKET_SPECIAL &&
- streq_ptr(p->path, value+skip))
+ path_equal_or_files_same(p->path, value+skip))
break;
if (p) {
@@ -2133,12 +2141,12 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse mqueue value %s", value);
+ log_unit_debug(u, "Failed to parse mqueue value: %s", value);
else {
LIST_FOREACH(port, p, s->ports)
if (p->type == SOCKET_MQUEUE &&
- streq_ptr(p->path, value+skip))
+ streq(p->path, value+skip))
break;
if (p) {
@@ -2152,7 +2160,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse socket value %s", value);
+ log_unit_debug(u, "Failed to parse socket value: %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2170,7 +2178,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse socket value %s", value);
+ log_unit_debug(u, "Failed to parse socket value: %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2183,7 +2191,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
}
}
} else
- log_unit_debug(UNIT(s)->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(UNIT(s), "Unknown serialization key: %s", key);
return 0;
}
@@ -2287,16 +2295,14 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (p->socket->state != SOCKET_LISTENING)
return 0;
- log_unit_debug(UNIT(p->socket)->id, "Incoming traffic on %s", UNIT(p->socket)->id);
+ log_unit_debug(UNIT(p->socket), "Incoming traffic");
if (revents != EPOLLIN) {
if (revents & EPOLLHUP)
- log_unit_error(UNIT(p->socket)->id, "%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.",
- UNIT(p->socket)->id);
+ log_unit_error(UNIT(p->socket), "Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.");
else
- log_unit_error(UNIT(p->socket)->id, "%s: Got unexpected poll event (0x%x) on socket.",
- UNIT(p->socket)->id, revents);
+ log_unit_error(UNIT(p->socket), "Got unexpected poll event (0x%x) on socket.", revents);
goto fail;
}
@@ -2313,8 +2319,7 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (errno == EINTR)
continue;
- log_unit_error(UNIT(p->socket)->id,
- "Failed to accept socket: %m");
+ log_unit_error_errno(UNIT(p->socket), errno, "Failed to accept socket: %m");
goto fail;
}
@@ -2362,10 +2367,9 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
f = SOCKET_SUCCESS;
}
- log_unit_full(u->id,
- f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s control process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
+ log_unit_full(u, f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
+ "Control process exited, code=%s status=%i",
+ sigchld_code_to_string(code), status);
if (f != SOCKET_SUCCESS)
s->result = f;
@@ -2374,9 +2378,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command->command_next &&
f == SOCKET_SUCCESS) {
- log_unit_debug(u->id,
- "%s running next command for state %s",
- u->id, socket_state_to_string(s->state));
+ log_unit_debug(u, "Running next command for state %s", socket_state_to_string(s->state));
socket_run_next(s);
} else {
s->control_command = NULL;
@@ -2385,9 +2387,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* No further commands for this step, so let's figure
* out what to do next */
- log_unit_debug(u->id,
- "%s got final SIGCHLD for state %s",
- u->id, socket_state_to_string(s->state));
+ log_unit_debug(u, "Got final SIGCHLD for state %s", socket_state_to_string(s->state));
switch (s->state) {
@@ -2442,53 +2442,53 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
switch (s->state) {
case SOCKET_START_PRE:
- log_unit_warning(UNIT(s)->id, "%s starting timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Starting timed out. Terminating.");
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_START_CHOWN:
case SOCKET_START_POST:
- log_unit_warning(UNIT(s)->id, "%s starting timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Starting timed out. Stopping.");
socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_STOP_PRE:
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_STOP_PRE_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out. Killing.");
socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL. Ignoring.");
socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
}
break;
case SOCKET_STOP_PRE_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Processes still around after SIGKILL. Ignoring.");
socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_STOP_POST:
- log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out (2). Terminating.");
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_FINAL_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out (2). Killing.");
socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Stopping timed out (2). Skipping SIGKILL. Ignoring.");
socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
}
break;
case SOCKET_FINAL_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL (2). Entering failed mode.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Still around after SIGKILL (2). Entering failed mode.");
socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
break;
@@ -2521,7 +2521,8 @@ int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
return 0;
}
- if (!(rfds = new(int, rn_fds)))
+ rfds = new(int, rn_fds);
+ if (!rfds)
return -ENOMEM;
k = 0;
@@ -2557,7 +2558,7 @@ static void socket_notify_service_dead(Socket *s, bool failed_permanent) {
* services. */
if (s->state == SOCKET_RUNNING) {
- log_unit_debug(UNIT(s)->id, "%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
+ log_unit_debug(UNIT(s), "Got notified about service death (failed permanently: %s)", yes_no(failed_permanent));
if (failed_permanent)
socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
else
@@ -2576,7 +2577,7 @@ void socket_connection_unref(Socket *s) {
assert(s->n_connections > 0);
s->n_connections--;
- log_unit_debug(UNIT(s)->id, "%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
+ log_unit_debug(UNIT(s), "One connection closed, %u left.", s->n_connections);
}
static void socket_trigger_notify(Unit *u, Unit *other) {
diff --git a/src/core/socket.h b/src/core/socket.h
index a2e08998c0..fa3ebdafa0 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -23,8 +23,6 @@
typedef struct Socket Socket;
-#include "manager.h"
-#include "unit.h"
#include "socket-util.h"
#include "mount.h"
#include "service.h"
@@ -168,6 +166,8 @@ struct Socket {
bool selinux_context_from_net;
char *user, *group;
+
+ bool reset_cpu_usage:1;
};
/* Called from the service code when collecting fds */
diff --git a/src/core/swap.c b/src/core/swap.c
index 6997921fde..193c8c3767 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -20,28 +20,22 @@
***/
#include <errno.h>
-#include <limits.h>
#include <unistd.h>
-#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/stat.h>
-#include <sys/swap.h>
#include <libudev.h>
#include "unit.h"
#include "swap.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
#include "unit-name.h"
#include "dbus-swap.h"
#include "special.h"
-#include "bus-common-errors.h"
#include "exit-status.h"
-#include "def.h"
#include "path-util.h"
#include "virt.h"
#include "udev-util.h"
#include "fstab-util.h"
+#include "formats-util.h"
static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
[SWAP_DEAD] = UNIT_INACTIVE,
@@ -183,12 +177,18 @@ static int swap_arm_timer(Swap *s) {
return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
}
- return sd_event_add_time(
+ r = sd_event_add_time(
UNIT(s)->manager->event,
&s->timer_event_source,
CLOCK_MONOTONIC,
now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
swap_dispatch_timer, s);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s->timer_event_source, "swap-timer");
+
+ return 0;
}
static int swap_add_device_links(Swap *s) {
@@ -201,7 +201,7 @@ static int swap_add_device_links(Swap *s) {
return 0;
if (is_device_path(s->what))
- return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
+ return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM);
else
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
@@ -212,7 +212,7 @@ static int swap_add_device_links(Swap *s) {
static int swap_add_default_dependencies(Swap *s) {
assert(s);
- if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
+ if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
return 0;
if (detect_container(NULL) > 0)
@@ -222,24 +222,23 @@ static int swap_add_default_dependencies(Swap *s) {
}
static int swap_verify(Swap *s) {
- bool b;
_cleanup_free_ char *e = NULL;
+ int r;
if (UNIT(s)->load_state != UNIT_LOADED)
return 0;
- e = unit_name_from_path(s->what, ".swap");
- if (!e)
- return log_oom();
+ r = unit_name_from_path(s->what, ".swap", &e);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to generate unit name from path: %m");
- b = unit_has_name(UNIT(s), e);
- if (!b) {
- log_unit_error(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
+ if (!unit_has_name(UNIT(s), e)) {
+ log_unit_error(UNIT(s), "Value of What= and unit name do not match, not loading.");
return -EINVAL;
}
if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id);
+ log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.");
return -EINVAL;
}
@@ -289,8 +288,11 @@ static int swap_load(Unit *u) {
s->what = strdup(s->parameters_fragment.what);
else if (s->parameters_proc_swaps.what)
s->what = strdup(s->parameters_proc_swaps.what);
- else
- s->what = unit_name_to_path(u->id);
+ else {
+ r = unit_name_to_path(u->id, &s->what);
+ if (r < 0)
+ return r;
+ }
if (!s->what)
return -ENOMEM;
@@ -338,7 +340,7 @@ static int swap_load(Unit *u) {
return swap_verify(s);
}
-static int swap_add_one(
+static int swap_setup_unit(
Manager *m,
const char *what,
const char *what_proc_swaps,
@@ -355,16 +357,18 @@ static int swap_add_one(
assert(what);
assert(what_proc_swaps);
- e = unit_name_from_path(what, ".swap");
- if (!e)
- return log_oom();
+ 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");
u = manager_get_unit(m, e);
if (u &&
SWAP(u)->from_proc_swaps &&
- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
+ !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) {
+ log_error("Swap %s appeared twice with different device paths %s and %s", e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
return -EEXIST;
+ }
if (!u) {
delete = true;
@@ -379,7 +383,7 @@ static int swap_add_one(
SWAP(u)->what = strdup(what);
if (!SWAP(u)->what) {
- r = log_oom();
+ r = -ENOMEM;
goto fail;
}
@@ -407,11 +411,10 @@ static int swap_add_one(
p->priority = priority;
unit_add_to_dbus_queue(u);
-
return 0;
fail:
- log_unit_warning_errno(e, r, "Failed to load swap unit: %m");
+ log_unit_warning_errno(u, r, "Failed to load swap unit: %m");
if (delete && u)
unit_free(u);
@@ -419,7 +422,7 @@ fail:
return r;
}
-static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) {
+static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
const char *dn;
@@ -428,7 +431,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
assert(m);
- r = swap_add_one(m, device, device, prio, set_flags);
+ r = swap_setup_unit(m, device, device, prio, set_flags);
if (r < 0)
return r;
@@ -444,7 +447,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
/* Add the main device node */
dn = udev_device_get_devnode(d);
if (dn && !streq(dn, device))
- swap_add_one(m, dn, device, prio, set_flags);
+ swap_setup_unit(m, dn, device, prio, set_flags);
/* Add additional units for all symlinks */
first = udev_device_get_devlinks_list_entry(d);
@@ -465,7 +468,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
st.st_rdev != udev_device_get_devnum(d))
continue;
- swap_add_one(m, p, device, prio, set_flags);
+ swap_setup_unit(m, p, device, prio, set_flags);
}
return r;
@@ -494,11 +497,7 @@ static void swap_set_state(Swap *s, SwapState state) {
}
if (state != old_state)
- log_unit_debug(UNIT(s)->id,
- "%s changed %s -> %s",
- UNIT(s)->id,
- swap_state_to_string(old_state),
- swap_state_to_string(state));
+ log_unit_debug(UNIT(s), "Changed %s -> %s", swap_state_to_string(old_state), swap_state_to_string(state));
unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
@@ -604,13 +603,18 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
+ .bus_endpoint_fd = -1,
};
assert(s);
assert(c);
assert(_pid);
- unit_realize_cgroup(UNIT(s));
+ (void) unit_realize_cgroup(UNIT(s));
+ if (s->reset_cpu_usage) {
+ (void) unit_reset_cpu_usage(UNIT(s));
+ s->reset_cpu_usage = false;
+ }
r = unit_setup_exec_runtime(UNIT(s));
if (r < 0)
@@ -626,9 +630,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
exec_params.cgroup_path = UNIT(s)->cgroup_path;
exec_params.cgroup_delegate = s->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
- exec_params.unit_id = UNIT(s)->id;
- r = exec_spawn(c,
+ r = exec_spawn(UNIT(s),
+ c,
&s->exec_context,
&exec_params,
s->exec_runtime,
@@ -708,13 +712,13 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
}
static void swap_enter_activating(Swap *s) {
- _cleanup_free_ char *discard = NULL;
- int r, priority = -1;
+ _cleanup_free_ char *opts = NULL;
+ int r;
assert(s);
@@ -722,36 +726,31 @@ static void swap_enter_activating(Swap *s) {
s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
if (s->from_fragment) {
- fstab_filter_options(s->parameters_fragment.options, "discard\0",
- NULL, &discard, NULL);
+ int priority = -1;
+
+ r = fstab_find_pri(s->parameters_fragment.options, &priority);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse swap priority \"%s\", ignoring: %m", s->parameters_fragment.options);
+ else if (r == 1 && s->parameters_fragment.priority >= 0)
+ log_warning("Duplicate swap priority configuration by Priority and Options fields.");
- priority = s->parameters_fragment.priority;
- if (priority < 0)
- fstab_find_pri(s->parameters_fragment.options, &priority);
+ if (r <= 0 && s->parameters_fragment.priority >= 0) {
+ if (s->parameters_fragment.options)
+ r = asprintf(&opts, "%s,pri=%i", s->parameters_fragment.options, s->parameters_fragment.priority);
+ else
+ r = asprintf(&opts, "pri=%i", s->parameters_fragment.priority);
+ if (r < 0)
+ goto fail;
+ }
}
r = exec_command_set(s->control_command, "/sbin/swapon", NULL);
if (r < 0)
goto fail;
- if (priority >= 0) {
- char p[DECIMAL_STR_MAX(int)];
-
- sprintf(p, "%i", priority);
- r = exec_command_append(s->control_command, "-p", p, NULL);
- if (r < 0)
- goto fail;
- }
-
- if (discard && !streq(discard, "none")) {
- const char *discard_arg;
-
- if (streq(discard, "all"))
- discard_arg = "--discard";
- else
- discard_arg = strjoina("--discard=", discard);
-
- r = exec_command_append(s->control_command, discard_arg, NULL);
+ if (s->parameters_fragment.options || opts) {
+ r = exec_command_append(s->control_command, "-o",
+ opts ? : s->parameters_fragment.options, NULL);
if (r < 0)
goto fail;
}
@@ -771,7 +770,7 @@ static void swap_enter_activating(Swap *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'swapon' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapon' task: %m");
swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
}
@@ -801,7 +800,7 @@ static void swap_enter_deactivating(Swap *s) {
return;
fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'swapoff' task: %m", UNIT(s)->id);
+ log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapoff' task: %m");
swap_enter_active(s, SWAP_FAILURE_RESOURCES);
}
@@ -836,6 +835,8 @@ static int swap_start(Unit *u) {
return -EAGAIN;
s->result = SWAP_SUCCESS;
+ s->reset_cpu_usage = true;
+
swap_enter_activating(s);
return 1;
}
@@ -893,7 +894,7 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
state = swap_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
s->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -901,14 +902,14 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
f = swap_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != SWAP_SUCCESS)
s->result = f;
} else if (streq(key, "control-pid")) {
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u, "Failed to parse control-pid value: %s", value);
else
s->control_pid = pid;
@@ -917,13 +918,13 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
id = swap_exec_command_from_string(value);
if (id < 0)
- log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
+ log_unit_debug(u, "Failed to parse exec-command value: %s", value);
else {
s->control_command_id = id;
s->control_command = s->exec_command + id;
}
} else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -981,10 +982,8 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
}
- log_unit_full(u->id,
- f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s swap process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
+ log_unit_full(u, f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
+ "Swap process exited, code=%s status=%i", sigchld_code_to_string(code), status);
switch (s->state) {
@@ -1024,38 +1023,38 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
case SWAP_ACTIVATING:
case SWAP_ACTIVATING_DONE:
- log_unit_warning(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Activation timed out. Stopping.");
swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
break;
case SWAP_DEACTIVATING:
- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Deactivation timed out. Stopping.");
swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
break;
case SWAP_ACTIVATING_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Activation timed out. Killing.");
swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Activation timed out. Skipping SIGKILL. Ignoring.");
swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
}
break;
case SWAP_DEACTIVATING_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Deactivation timed out. Killing.");
swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Deactivation timed out. Skipping SIGKILL. Ignoring.");
swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
}
break;
case SWAP_ACTIVATING_SIGKILL:
case SWAP_DEACTIVATING_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s), "Swap process still around after SIGKILL. Ignoring.");
swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
break;
@@ -1091,15 +1090,16 @@ static int swap_load_proc_swaps(Manager *m, bool set_flags) {
if (k == EOF)
break;
- log_warning("Failed to parse /proc/swaps:%u", i);
+ log_warning("Failed to parse /proc/swaps:%u.", i);
continue;
}
- d = cunescape(dev);
- if (!d)
- return -ENOMEM;
+ if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
+ return log_oom();
- k = swap_process_new_swap(m, d, prio, set_flags);
+ device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
+
+ k = swap_process_new(m, d, prio, set_flags);
if (k < 0)
r = k;
}
@@ -1151,6 +1151,9 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
break;
}
+ if (swap->what)
+ device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
+
} else if (swap->just_activated) {
/* New swap entry */
@@ -1285,6 +1288,8 @@ static int swap_enumerate(Manager *m) {
r = sd_event_source_set_priority(m->swap_event_source, -10);
if (r < 0)
goto fail;
+
+ (void) sd_event_source_set_description(m->swap_event_source, "swap-proc");
}
r = swap_load_proc_swaps(m, false);
@@ -1298,7 +1303,7 @@ fail:
return r;
}
-int swap_process_new_device(Manager *m, struct udev_device *dev) {
+int swap_process_device_new(Manager *m, struct udev_device *dev) {
struct udev_list_entry *item = NULL, *first = NULL;
_cleanup_free_ char *e = NULL;
const char *dn;
@@ -1312,9 +1317,9 @@ int swap_process_new_device(Manager *m, struct udev_device *dev) {
if (!dn)
return 0;
- e = unit_name_from_path(dn, ".swap");
- if (!e)
- return -ENOMEM;
+ r = unit_name_from_path(dn, ".swap", &e);
+ if (r < 0)
+ return r;
s = hashmap_get(m->units, e);
if (s)
@@ -1323,15 +1328,14 @@ int swap_process_new_device(Manager *m, struct udev_device *dev) {
first = udev_device_get_devlinks_list_entry(dev);
udev_list_entry_foreach(item, first) {
_cleanup_free_ char *n = NULL;
+ int q;
- n = unit_name_from_path(udev_list_entry_get_name(item), ".swap");
- if (!n)
- return -ENOMEM;
+ q = unit_name_from_path(udev_list_entry_get_name(item), ".swap", &n);
+ if (q < 0)
+ return q;
s = hashmap_get(m->units, n);
if (s) {
- int q;
-
q = swap_set_devnode(s, dn);
if (q < 0)
r = q;
@@ -1341,7 +1345,7 @@ int swap_process_new_device(Manager *m, struct udev_device *dev) {
return r;
}
-int swap_process_removed_device(Manager *m, struct udev_device *dev) {
+int swap_process_device_remove(Manager *m, struct udev_device *dev) {
const char *dn;
int r = 0;
Swap *s;
@@ -1390,7 +1394,7 @@ static int swap_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
-static bool swap_supported(Manager *m) {
+static bool swap_supported(void) {
static int supported = -1;
/* If swap support is not available in the kernel, or we are
diff --git a/src/core/swap.h b/src/core/swap.h
index 73e64d87a4..9136b9abab 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -26,7 +26,6 @@
typedef struct Swap Swap;
-#include "unit.h"
typedef enum SwapState {
SWAP_DEAD,
@@ -88,6 +87,8 @@ struct Swap {
bool is_active:1;
bool just_activated:1;
+ bool reset_cpu_usage:1;
+
SwapResult result;
usec_t timeout_usec;
@@ -116,8 +117,8 @@ struct Swap {
extern const UnitVTable swap_vtable;
-int swap_process_new_device(Manager *m, struct udev_device *dev);
-int swap_process_removed_device(Manager *m, struct udev_device *dev);
+int swap_process_device_new(Manager *m, struct udev_device *dev);
+int swap_process_device_remove(Manager *m, struct udev_device *dev);
const char* swap_state_to_string(SwapState i) _const_;
SwapState swap_state_from_string(const char *s) _pure_;
diff --git a/src/core/system.conf b/src/core/system.conf
index a3727200df..231609033b 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -5,10 +5,11 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/system.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
-# See systemd-system.conf(5) for details
+# See systemd-system.conf(5) for details.
[Manager]
#LogLevel=info
diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in
index d5b86bf65c..ac52b30dd3 100644
--- a/src/core/systemd.pc.in
+++ b/src/core/systemd.pc.in
@@ -6,7 +6,6 @@
# (at your option) any later version.
prefix=@prefix@
-libdir=@libdir@
systemdutildir=@rootlibexecdir@
systemdsystemunitdir=@systemunitdir@
systemdsystempresetdir=@systempresetdir@
diff --git a/src/core/target.c b/src/core/target.c
index 33fb66bc3f..8817ef21c4 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -19,13 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
#include "unit.h"
#include "target.h"
-#include "load-fragment.h"
#include "log.h"
#include "dbus-target.h"
#include "special.h"
diff --git a/src/core/target.h b/src/core/target.h
index a5398d9e98..0a25ef469a 100644
--- a/src/core/target.h
+++ b/src/core/target.h
@@ -23,7 +23,6 @@
typedef struct Target Target;
-#include "unit.h"
typedef enum TargetState {
TARGET_DEAD,
diff --git a/src/core/timer.c b/src/core/timer.c
index 45744c7de5..7f4a2eb716 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -28,7 +28,6 @@
#include "special.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "mkdir.h"
static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
[TIMER_DEAD] = UNIT_INACTIVE,
@@ -86,7 +85,7 @@ static int timer_verify(Timer *t) {
return 0;
if (!t->values) {
- log_unit_error(UNIT(t)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
+ log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
return -EINVAL;
}
@@ -103,7 +102,7 @@ static int timer_add_default_dependencies(Timer *t) {
if (r < 0)
return r;
- if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
+ if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -129,7 +128,7 @@ static int timer_setup_persistent(Timer *t) {
if (!t->persistent)
return 0;
- if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
+ if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
if (r < 0)
@@ -148,7 +147,7 @@ static int timer_setup_persistent(Timer *t) {
r = get_home_dir(&h);
if (r < 0)
- return log_error_errno(r, "Failed to determine home directory: %m");
+ return log_unit_error_errno(UNIT(t), r, "Failed to determine home directory: %m");
t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
}
@@ -258,10 +257,7 @@ static void timer_set_state(Timer *t, TimerState state) {
}
if (state != old_state)
- log_unit_debug(UNIT(t)->id,
- "%s changed %s -> %s", UNIT(t)->id,
- timer_state_to_string(old_state),
- timer_state_to_string(state));
+ log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
}
@@ -417,7 +413,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
}
if (!found_monotonic && !found_realtime) {
- log_unit_debug(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
+ log_unit_debug(UNIT(t), "Timer is elapsed.");
timer_set_state(t, TIMER_ELAPSED);
return;
}
@@ -425,9 +421,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (found_monotonic) {
char buf[FORMAT_TIMESPAN_MAX];
- log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
- UNIT(t)->id,
- format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
+ log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
if (t->monotonic_event_source) {
r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
@@ -435,15 +429,21 @@ static void timer_enter_waiting(Timer *t, bool initial) {
goto fail;
r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
- } else
+ if (r < 0)
+ goto fail;
+ } else {
+
r = sd_event_add_time(
UNIT(t)->manager->event,
&t->monotonic_event_source,
t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
timer_dispatch, t);
- if (r < 0)
- goto fail;
+ if (r < 0)
+ goto fail;
+
+ (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
+ }
} else if (t->monotonic_event_source) {
@@ -454,7 +454,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (found_realtime) {
char buf[FORMAT_TIMESTAMP_MAX];
- log_unit_debug(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
+ log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
if (t->realtime_event_source) {
r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
@@ -462,15 +462,20 @@ static void timer_enter_waiting(Timer *t, bool initial) {
goto fail;
r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
- } else
+ if (r < 0)
+ goto fail;
+ } else {
r = sd_event_add_time(
UNIT(t)->manager->event,
&t->realtime_event_source,
t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
t->next_elapse_realtime, t->accuracy_usec,
timer_dispatch, t);
- if (r < 0)
- goto fail;
+ if (r < 0)
+ goto fail;
+
+ (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
+ }
} else if (t->realtime_event_source) {
@@ -483,7 +488,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
return;
fail:
- log_unit_warning_errno(UNIT(t)->id, r, "%s failed to enter waiting state: %m", UNIT(t)->id);
+ log_unit_warning_errno(UNIT(t), r, "Failed to enter waiting state: %m");
timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
}
@@ -511,9 +516,7 @@ static void timer_enter_running(Timer *t) {
return;
fail:
- log_unit_warning(UNIT(t)->id,
- "%s failed to queue unit startup job: %s",
- UNIT(t)->id, bus_error_message(&error, r));
+ log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
}
@@ -594,7 +597,7 @@ static int timer_deserialize_item(Unit *u, const char *key, const char *value, F
state = timer_state_from_string(value);
if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u, "Failed to parse state value: %s", value);
else
t->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -602,23 +605,23 @@ static int timer_deserialize_item(Unit *u, const char *key, const char *value, F
f = timer_result_from_string(value);
if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u, "Failed to parse result value: %s", value);
else if (f != TIMER_SUCCESS)
t->result = f;
} else if (streq(key, "last-trigger-realtime")) {
r = safe_atou64(value, &t->last_trigger.realtime);
if (r < 0)
- log_unit_debug(u->id, "Failed to parse last-trigger-realtime value %s", value);
+ log_unit_debug(u, "Failed to parse last-trigger-realtime value: %s", value);
} else if (streq(key, "last-trigger-monotonic")) {
r = safe_atou64(value, &t->last_trigger.monotonic);
if (r < 0)
- log_unit_debug(u->id, "Failed to parse last-trigger-monotonic value %s", value);
+ log_unit_debug(u, "Failed to parse last-trigger-monotonic value: %s", value);
} else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u, "Unknown serialization key: %s", key);
return 0;
}
@@ -643,7 +646,7 @@ static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
if (t->state != TIMER_WAITING)
return 0;
- log_unit_debug(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
+ log_unit_debug(UNIT(t), "Timer elapsed.");
timer_enter_running(t);
return 0;
}
@@ -676,7 +679,7 @@ static void timer_trigger_notify(Unit *u, Unit *other) {
case TIMER_RUNNING:
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- log_unit_debug(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
+ log_unit_debug(UNIT(t), "Got notified about unit deactivation.");
timer_enter_waiting(t, false);
}
break;
@@ -709,7 +712,7 @@ static void timer_time_change(Unit *u) {
if (t->state != TIMER_WAITING)
return;
- log_unit_debug(u->id, "%s: time change, recalculating next elapse.", u->id);
+ log_unit_debug(u, "Time change, recalculating next elapse.");
timer_enter_waiting(t, false);
}
diff --git a/src/core/timer.h b/src/core/timer.h
index de412a043e..9d919e4d3e 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -23,7 +23,6 @@
typedef struct Timer Timer;
-#include "unit.h"
#include "calendarspec.h"
typedef enum TimerState {
diff --git a/src/core/transaction.c b/src/core/transaction.c
index b0b3d6bd60..090103fbda 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -23,9 +23,9 @@
#include <fcntl.h>
#include "bus-common-errors.h"
-#include "bus-util.h"
#include "bus-error.h"
#include "transaction.h"
+#include "terminal-util.h"
static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
@@ -189,11 +189,11 @@ static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
* another unit in which case we
* rather remove the start. */
- log_unit_debug(j->unit->id,
+ log_unit_debug(j->unit,
"Looking at job %s/%s conflicted_by=%s",
j->unit->id, job_type_to_string(j->type),
yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
- log_unit_debug(k->unit->id,
+ log_unit_debug(k->unit,
"Looking at job %s/%s conflicted_by=%s",
k->unit->id, job_type_to_string(k->type),
yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
@@ -222,7 +222,7 @@ static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
return -ENOEXEC;
/* Ok, we can drop one, so let's do so. */
- log_unit_debug(d->unit->id,
+ log_unit_debug(d->unit,
"Fixing conflicting jobs %s/%s,%s/%s by deleting job %s/%s",
j->unit->id, job_type_to_string(j->type),
k->unit->id, job_type_to_string(k->type),
@@ -368,7 +368,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
* job to remove. We use the marker to find our way
* back, since smart how we are we stored our way back
* in there. */
- log_unit_warning(j->unit->id,
+ log_unit_warning(j->unit,
"Found ordering cycle on %s/%s",
j->unit->id, job_type_to_string(j->type));
@@ -376,7 +376,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
/* logging for j not k here here to provide consistent narrative */
- log_unit_warning(j->unit->id,
+ log_unit_warning(j->unit,
"Found dependency on %s/%s",
k->unit->id, job_type_to_string(k->type));
@@ -396,10 +396,10 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
if (delete) {
/* logging for j not k here here to provide consistent narrative */
- log_unit_warning(j->unit->id,
+ log_unit_warning(j->unit,
"Breaking ordering cycle by deleting job %s/%s",
delete->unit->id, job_type_to_string(delete->type));
- log_unit_error(delete->unit->id,
+ log_unit_error(delete->unit,
"Job %s/%s deleted to break ordering cycle starting with %s/%s",
delete->unit->id, job_type_to_string(delete->type),
j->unit->id, job_type_to_string(j->type));
@@ -552,17 +552,17 @@ rescan:
continue;
if (stops_running_service)
- log_unit_debug(j->unit->id,
+ log_unit_debug(j->unit,
"%s/%s would stop a running service.",
j->unit->id, job_type_to_string(j->type));
if (changes_existing_job)
- log_unit_debug(j->unit->id,
+ log_unit_debug(j->unit,
"%s/%s would change existing job.",
j->unit->id, job_type_to_string(j->type));
/* Ok, let's get rid of this */
- log_unit_debug(j->unit->id,
+ log_unit_debug(j->unit,
"Deleting %s/%s to minimize impact.",
j->unit->id, job_type_to_string(j->type));
@@ -817,7 +817,7 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen
job_dependency_free(j->object_list);
if (other && delete_dependencies) {
- log_unit_debug(other->unit->id,
+ log_unit_debug(other->unit,
"Deleting job %s/%s as dependency of job %s/%s",
other->unit->id, job_type_to_string(other->type),
j->unit->id, job_type_to_string(j->type));
@@ -848,14 +848,20 @@ int transaction_add_job_and_dependencies(
assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
assert(unit);
+ /* Before adding jobs for this unit, let's ensure that its state has been loaded
+ * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
+ * This way, we "recursively" coldplug units, ensuring that we do not look at state of
+ * not-yet-coldplugged units. */
+ if (unit->manager->n_reloading > 0)
+ unit_coldplug(unit);
+
/* log_debug("Pulling in %s/%s from %s/%s", */
/* unit->id, job_type_to_string(type), */
/* by ? by->unit->id : "NA", */
/* by ? job_type_to_string(by->type) : "NA"); */
if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s is not loaded properly.", unit->id);
+ return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
if (unit->load_error == -ENOENT || unit->manager->test_run)
@@ -913,12 +919,8 @@ int transaction_add_job_and_dependencies(
SET_FOREACH(dep, following, i) {
r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
if (r < 0) {
- log_unit_warning(dep->id,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
+ log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r));
+ sd_bus_error_free(e);
}
}
@@ -933,8 +935,7 @@ int transaction_add_job_and_dependencies(
if (r != -EBADR)
goto fail;
- if (e)
- sd_bus_error_free(e);
+ sd_bus_error_free(e);
}
}
@@ -944,34 +945,29 @@ int transaction_add_job_and_dependencies(
if (r != -EBADR)
goto fail;
- if (e)
- sd_bus_error_free(e);
+ sd_bus_error_free(e);
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
if (r < 0) {
- log_unit_full(dep->id,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
+ log_unit_full(dep,
+ r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
+ "Cannot add dependency job, ignoring: %s",
+ bus_error_message(e, r));
+ sd_bus_error_free(e);
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
if (r < 0) {
- log_unit_full(dep->id,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
+ log_unit_full(dep,
+ r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
+ "Cannot add dependency job, ignoring: %s",
+ bus_error_message(e, r));
+ sd_bus_error_free(e);
}
}
@@ -981,21 +977,18 @@ int transaction_add_job_and_dependencies(
if (r != -EBADR)
goto fail;
- if (e)
- sd_bus_error_free(e);
+ sd_bus_error_free(e);
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
if (r < 0) {
- log_unit_full(dep->id,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
+ log_unit_full(dep,
+ r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
+ "Cannot add dependency job, ignoring: %s",
+ bus_error_message(e, r));
+ sd_bus_error_free(e);
}
}
@@ -1005,60 +998,54 @@ int transaction_add_job_and_dependencies(
if (r != -EBADR)
goto fail;
- if (e)
- sd_bus_error_free(e);
+ sd_bus_error_free(e);
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
if (r < 0) {
- log_unit_warning(dep->id,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
+ log_unit_warning(dep,
+ "Cannot add dependency job, ignoring: %s",
+ bus_error_message(e, r));
+ sd_bus_error_free(e);
}
}
}
if (type == JOB_STOP || type == JOB_RESTART) {
+ static const UnitDependency propagate_deps[] = {
+ UNIT_REQUIRED_BY,
+ UNIT_REQUISITE_OF,
+ UNIT_BOUND_BY,
+ UNIT_CONSISTS_OF,
+ };
+
+ JobType ptype;
+ unsigned j;
+
+ /* We propagate STOP as STOP, but RESTART only
+ * as TRY_RESTART, in order not to start
+ * dependencies that are not around. */
+ ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
+
+ for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
+ SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
+ JobType nt;
+
+ nt = job_type_collapse(ptype, dep);
+ if (nt == JOB_NOP)
+ continue;
+
+ r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e);
+ if (r < 0) {
+ if (r != -EBADR)
+ goto fail;
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
sd_bus_error_free(e);
+ }
}
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
}
if (type == JOB_RELOAD) {
@@ -1066,12 +1053,10 @@ int transaction_add_job_and_dependencies(
SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
if (r < 0) {
- log_unit_warning(dep->id,
- "Cannot add dependency reload job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
+ log_unit_warning(dep,
+ "Cannot add dependency reload job, ignoring: %s",
+ bus_error_message(e, r));
+ sd_bus_error_free(e);
}
}
}
@@ -1113,9 +1098,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
if (r < 0)
- log_unit_warning(u->id,
- "Cannot add isolate job for unit %s, ignoring: %s",
- u->id, strerror(-r));
+ log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
}
return 0;
diff --git a/src/core/umount.c b/src/core/umount.c
index dd7df194de..bee267a5ad 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -24,7 +24,6 @@
#include <string.h>
#include <sys/mount.h>
#include <sys/swap.h>
-#include <unistd.h>
#include <linux/loop.h>
#include <linux/dm-ioctl.h>
@@ -63,6 +62,7 @@ static void mount_points_list_free(MountPoint **head) {
static int mount_points_list_get(MountPoint **head) {
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
unsigned int i;
+ int r;
assert(head);
@@ -98,9 +98,9 @@ static int mount_points_list_get(MountPoint **head) {
continue;
}
- p = cunescape(path);
- if (!p)
- return -ENOMEM;
+ r = cunescape(path, UNESCAPE_RELAX, &p);
+ if (r < 0)
+ return r;
/* Ignore mount points we can't unmount because they
* are API or because we are keeping them open (like
@@ -134,10 +134,12 @@ static int mount_points_list_get(MountPoint **head) {
static int swap_list_get(MountPoint **head) {
_cleanup_fclose_ FILE *proc_swaps = NULL;
unsigned int i;
+ int r;
assert(head);
- if (!(proc_swaps = fopen("/proc/swaps", "re")))
+ proc_swaps = fopen("/proc/swaps", "re");
+ if (!proc_swaps)
return (errno == ENOENT) ? 0 : -errno;
(void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
@@ -147,19 +149,19 @@ static int swap_list_get(MountPoint **head) {
char *dev = NULL, *d;
int k;
- if ((k = fscanf(proc_swaps,
- "%ms " /* device/file */
- "%*s " /* type of swap */
- "%*s " /* swap size */
- "%*s " /* used */
- "%*s\n", /* priority */
- &dev)) != 1) {
+ k = fscanf(proc_swaps,
+ "%ms " /* device/file */
+ "%*s " /* type of swap */
+ "%*s " /* swap size */
+ "%*s " /* used */
+ "%*s\n", /* priority */
+ &dev);
+ if (k != 1) {
if (k == EOF)
break;
log_warning("Failed to parse /proc/swaps:%u.", i);
-
free(dev);
continue;
}
@@ -169,14 +171,13 @@ static int swap_list_get(MountPoint **head) {
continue;
}
- d = cunescape(dev);
+ r = cunescape(dev, UNESCAPE_RELAX, &d);
free(dev);
+ if (r < 0)
+ return r;
- if (!d) {
- return -ENOMEM;
- }
-
- if (!(swap = new0(MountPoint, 1))) {
+ swap = new0(MountPoint, 1);
+ if (!swap) {
free(d);
return -ENOMEM;
}
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index 97135db551..0889769d03 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -19,96 +19,65 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-id128.h"
#include "unit.h"
#include "specifier.h"
-#include "path-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "macro.h"
#include "cgroup-util.h"
-#include "special.h"
+#include "formats-util.h"
static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
- char *n;
assert(u);
- n = unit_name_to_prefix_and_instance(u->id);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return unit_name_to_prefix_and_instance(u->id, ret);
}
static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
- char *n;
assert(u);
- n = unit_name_to_prefix(u->id);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return unit_name_to_prefix(u->id, ret);
}
static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
_cleanup_free_ char *p = NULL;
- char *n;
+ Unit *u = userdata;
+ int r;
assert(u);
- p = unit_name_to_prefix(u->id);
- if (!p)
- return -ENOMEM;
+ r = unit_name_to_prefix(u->id, &p);
+ if (r < 0)
+ return r;
- n = unit_name_unescape(p);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return unit_name_unescape(p, ret);
}
static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
- char *n;
assert(u);
if (!u->instance)
- return -ENOTSUP;
-
- n = unit_name_unescape(u->instance);
- if (!n)
- return -ENOMEM;
+ return -EINVAL;
- *ret = n;
- return 0;
+ return unit_name_unescape(u->instance, ret);
}
static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
- char *n;
assert(u);
if (u->instance)
- n = unit_name_path_unescape(u->instance);
+ return unit_name_path_unescape(u->instance, ret);
else
- n = unit_name_to_path(u->id);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return unit_name_to_path(u->id, ret);
}
static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
@@ -130,26 +99,35 @@ static int specifier_cgroup(char specifier, void *data, void *userdata, char **r
static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
- const char *slice;
char *n;
- int r;
assert(u);
- slice = unit_slice_name(u);
- if (specifier == 'R' || !slice)
- n = strdup(u->manager->cgroup_root);
- else {
- _cleanup_free_ char *p = NULL;
+ n = strdup(u->manager->cgroup_root);
+ if (!n)
+ return -ENOMEM;
- r = cg_slice_to_path(slice, &p);
- if (r < 0)
- return r;
+ *ret = n;
+ return 0;
+}
- n = strjoin(u->manager->cgroup_root, "/", p, NULL);
- if (!n)
- return -ENOMEM;
- }
+static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) {
+ Unit *u = userdata;
+ char *n;
+
+ assert(u);
+
+ if (UNIT_ISSET(u->slice)) {
+ Unit *slice;
+
+ slice = UNIT_DEREF(u->slice);
+
+ if (slice->cgroup_path)
+ n = strdup(slice->cgroup_path);
+ else
+ n = unit_default_cgroup_path(slice);
+ } else
+ n = strdup(u->manager->cgroup_root);
*ret = n;
return 0;
@@ -162,12 +140,12 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char **
assert(u);
- if (u->manager->running_as == SYSTEMD_SYSTEM)
+ if (u->manager->running_as == MANAGER_SYSTEM)
e = "/run";
else {
e = getenv("XDG_RUNTIME_DIR");
if (!e)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
n = strdup(e);
@@ -188,9 +166,9 @@ static int specifier_user_name(char specifier, void *data, void *userdata, char
c = unit_get_exec_context(u);
if (!c)
- return -ENOTSUP;
+ return -EINVAL;
- if (u->manager->running_as == SYSTEMD_SYSTEM) {
+ if (u->manager->running_as == MANAGER_SYSTEM) {
/* We cannot use NSS from PID 1, hence try to make the
* best of it in that case, and fail if we can't help
@@ -251,9 +229,9 @@ static int specifier_user_home(char specifier, void *data, void *userdata, char
c = unit_get_exec_context(u);
if (!c)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
- if (u->manager->running_as == SYSTEMD_SYSTEM) {
+ if (u->manager->running_as == MANAGER_SYSTEM) {
/* We cannot use NSS from PID 1, hence try to make the
* best of it if we can, but fail if we can't */
@@ -261,7 +239,7 @@ static int specifier_user_home(char specifier, void *data, void *userdata, char
if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
n = strdup("/root");
else
- return -ENOTSUP;
+ return -EOPNOTSUPP;
} else {
@@ -299,9 +277,9 @@ static int specifier_user_shell(char specifier, void *data, void *userdata, char
c = unit_get_exec_context(u);
if (!c)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
- if (u->manager->running_as == SYSTEMD_SYSTEM) {
+ if (u->manager->running_as == MANAGER_SYSTEM) {
/* We cannot use NSS from PID 1, hence try to make the
* best of it if we can, but fail if we can't */
@@ -309,7 +287,7 @@ static int specifier_user_shell(char specifier, void *data, void *userdata, char
if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
n = strdup("/bin/sh");
else
- return -ENOTSUP;
+ return -EOPNOTSUPP;
} else {
@@ -394,7 +372,7 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
{ 'f', specifier_filename, NULL },
{ 'c', specifier_cgroup, NULL },
- { 'r', specifier_cgroup_root, NULL },
+ { 'r', specifier_cgroup_slice, NULL },
{ 'R', specifier_cgroup_root, NULL },
{ 't', specifier_runtime, NULL },
{ 'U', specifier_user_name, NULL },
diff --git a/src/core/unit.c b/src/core/unit.c
index ee8e607c27..e380276d49 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -19,12 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <string.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <poll.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
@@ -45,13 +41,13 @@
#include "cgroup-util.h"
#include "missing.h"
#include "mkdir.h"
-#include "label.h"
#include "fileio-label.h"
#include "bus-common-errors.h"
#include "dbus.h"
#include "execute.h"
-#include "virt.h"
#include "dropin.h"
+#include "formats-util.h"
+#include "process-util.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
@@ -69,7 +65,7 @@ const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SCOPE] = &scope_vtable
};
-static int maybe_warn_about_dependency(const char *id, const char *other, UnitDependency dependency);
+static void maybe_warn_about_dependency(Unit *u, const char *other, UnitDependency dependency);
Unit *unit_new(Manager *m, size_t size) {
Unit *u;
@@ -89,12 +85,13 @@ Unit *unit_new(Manager *m, size_t size) {
u->manager = m;
u->type = _UNIT_TYPE_INVALID;
- u->deserialized_job = _JOB_TYPE_INVALID;
u->default_dependencies = true;
u->unit_file_state = _UNIT_FILE_STATE_INVALID;
u->unit_file_preset = -1;
u->on_failure_job_mode = JOB_REPLACE;
+ RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
+
return u;
}
@@ -147,21 +144,31 @@ int unit_add_name(Unit *u, const char *text) {
assert(u);
assert(text);
- if (unit_name_is_template(text)) {
+ if (unit_name_is_valid(text, UNIT_NAME_TEMPLATE)) {
if (!u->instance)
return -EINVAL;
- s = unit_name_replace_instance(text, u->instance);
- } else
+ r = unit_name_replace_instance(text, u->instance, &s);
+ if (r < 0)
+ return r;
+ } else {
s = strdup(text);
- if (!s)
- return -ENOMEM;
+ if (!s)
+ return -ENOMEM;
+ }
+
+ if (set_contains(u->names, s))
+ return 0;
+ if (hashmap_contains(u->manager->units, s))
+ return -EEXIST;
- if (!unit_name_is_valid(s, TEMPLATE_INVALID))
+ if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
return -EINVAL;
- assert_se((t = unit_name_to_type(s)) >= 0);
+ t = unit_name_to_type(s);
+ if (t < 0)
+ return -EINVAL;
if (u->type != _UNIT_TYPE_INVALID && t != u->type)
return -EINVAL;
@@ -174,29 +181,25 @@ int unit_add_name(Unit *u, const char *text) {
return -EINVAL;
/* Ensure that this unit is either instanced or not instanced,
- * but not both. */
+ * but not both. Note that we do allow names with different
+ * instance names however! */
if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
return -EINVAL;
- if (unit_vtable[t]->no_alias &&
- !set_isempty(u->names) &&
- !set_get(u->names, s))
+ if (unit_vtable[t]->no_alias && !set_isempty(u->names))
return -EEXIST;
if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
return -E2BIG;
r = set_put(u->names, s);
- if (r < 0) {
- if (r == -EEXIST)
- return 0;
-
+ if (r < 0)
return r;
- }
+ assert(r > 0);
r = hashmap_put(u->manager->units, s, u);
if (r < 0) {
- set_remove(u->names, s);
+ (void) set_remove(u->names, s);
return r;
}
@@ -226,14 +229,14 @@ int unit_choose_id(Unit *u, const char *name) {
assert(u);
assert(name);
- if (unit_name_is_template(name)) {
+ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
if (!u->instance)
return -EINVAL;
- t = unit_name_replace_instance(name, u->instance);
- if (!t)
- return -ENOMEM;
+ r = unit_name_replace_instance(name, u->instance, &t);
+ if (r < 0)
+ return r;
name = t;
}
@@ -243,6 +246,7 @@ int unit_choose_id(Unit *u, const char *name) {
if (!s)
return -ENOENT;
+ /* Determine the new instance from the new id */
r = unit_name_to_instance(s, &i);
if (r < 0)
return r;
@@ -522,7 +526,7 @@ void unit_free(Unit *u) {
free(u->cgroup_path);
}
- set_remove(u->manager->failed_units, u);
+ manager_update_failed_units(u->manager, u, false);
set_remove(u->manager->startup_units, u);
free(u->description);
@@ -649,7 +653,7 @@ static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitD
/* Do not add dependencies between u and itself */
if (back == u) {
if (set_remove(back->dependencies[k], other))
- maybe_warn_about_dependency(u->id, other_id, k);
+ maybe_warn_about_dependency(u, other_id, k);
} else {
r = set_remove_and_put(back->dependencies[k], other, u);
if (r == -EEXIST)
@@ -663,7 +667,7 @@ static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitD
/* Also do not move dependencies on u to itself */
back = set_remove(other->dependencies[d], u);
if (back)
- maybe_warn_about_dependency(u->id, other_id, d);
+ maybe_warn_about_dependency(u, other_id, d);
/* The move cannot fail. The caller must have performed a reservation. */
assert_se(complete_move(&u->dependencies[d], &other->dependencies[d]) == 0);
@@ -756,24 +760,22 @@ int unit_merge_by_name(Unit *u, const char *name) {
assert(u);
assert(name);
- if (unit_name_is_template(name)) {
+ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
if (!u->instance)
return -EINVAL;
- s = unit_name_replace_instance(name, u->instance);
- if (!s)
- return -ENOMEM;
+ r = unit_name_replace_instance(name, u->instance, &s);
+ if (r < 0)
+ return r;
name = s;
}
other = manager_get_unit(u->manager, name);
- if (!other)
- r = unit_add_name(u, name);
- else
- r = unit_merge(u, other);
+ if (other)
+ return unit_merge(u, other);
- return r;
+ return unit_add_name(u, name);
}
Unit* unit_follow_merge(Unit *u) {
@@ -803,7 +805,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
return r;
}
- if (u->manager->running_as != SYSTEMD_SYSTEM)
+ if (u->manager->running_as != MANAGER_SYSTEM)
return 0;
if (c->private_tmp) {
@@ -1091,6 +1093,8 @@ static int unit_add_target_dependencies(Unit *u) {
static const UnitDependency deps[] = {
UNIT_REQUIRED_BY,
UNIT_REQUIRED_BY_OVERRIDABLE,
+ UNIT_REQUISITE_OF,
+ UNIT_REQUISITE_OF_OVERRIDABLE,
UNIT_WANTED_BY,
UNIT_BOUND_BY
};
@@ -1167,7 +1171,6 @@ static int unit_add_mount_dependencies(Unit *u) {
static int unit_add_startup_units(Unit *u) {
CGroupContext *c;
- int r = 0;
c = unit_get_cgroup_context(u);
if (!c)
@@ -1177,11 +1180,7 @@ static int unit_add_startup_units(Unit *u) {
c->startup_blockio_weight == (unsigned long) -1)
return 0;
- r = set_put(u->manager->startup_units, u);
- if (r == -EEXIST)
- return 0;
-
- return r;
+ return set_put(u->manager->startup_units, u);
}
int unit_load(Unit *u) {
@@ -1230,7 +1229,7 @@ int unit_load(Unit *u) {
goto fail;
if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
- log_unit_error(u->id, "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id);
+ log_unit_error(u, "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing.");
r = -EINVAL;
goto fail;
}
@@ -1251,8 +1250,7 @@ fail:
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
- log_unit_debug(u->id, "Failed to load configuration for %s: %s",
- u->id, strerror(-r));
+ log_unit_debug_errno(u, r, "Failed to load configuration: %m");
return r;
}
@@ -1276,23 +1274,20 @@ static bool unit_condition_test_list(Unit *u, Condition *first, const char *(*to
r = condition_test(c);
if (r < 0)
- log_unit_warning(u->id,
- "Couldn't determine result for %s=%s%s%s for %s, assuming failed: %s",
+ log_unit_warning(u,
+ "Couldn't determine result for %s=%s%s%s, assuming failed: %m",
to_string(c->type),
c->trigger ? "|" : "",
c->negate ? "!" : "",
- c->parameter,
- u->id,
- strerror(-r));
+ c->parameter);
else
- log_unit_debug(u->id,
- "%s=%s%s%s %s for %s.",
+ log_unit_debug(u,
+ "%s=%s%s%s %s.",
to_string(c->type),
c->trigger ? "|" : "",
c->negate ? "!" : "",
c->parameter,
- condition_result_to_string(c->result),
- u->id);
+ condition_result_to_string(c->result));
if (!c->trigger && r <= 0)
return false;
@@ -1405,11 +1400,17 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING :
SD_MESSAGE_UNIT_RELOADING;
- log_unit_struct(u->id,
- LOG_INFO,
- LOG_MESSAGE_ID(mid),
- LOG_MESSAGE("%s", buf),
- NULL);
+ /* Note that we deliberately use LOG_MESSAGE() instead of
+ * LOG_UNIT_MESSAGE() here, since this is supposed to mimic
+ * closely what is written to screen using the status output,
+ * which is supposed the highest level, friendliest output
+ * possible, which means we should avoid the low-level unit
+ * name. */
+ log_struct(LOG_INFO,
+ LOG_MESSAGE_ID(mid),
+ LOG_UNIT_ID(u),
+ LOG_MESSAGE("%s", buf),
+ NULL);
}
/* Errors:
@@ -1443,26 +1444,26 @@ int unit_start(Unit *u) {
* but we don't want to recheck the condition in that case. */
if (state != UNIT_ACTIVATING &&
!unit_condition_test(u)) {
- log_unit_debug(u->id, "Starting of %s requested but condition failed. Not starting unit.", u->id);
+ log_unit_debug(u, "Starting requested but condition failed. Not starting unit.");
return -EALREADY;
}
/* If the asserts failed, fail the entire job */
if (state != UNIT_ACTIVATING &&
!unit_assert_test(u)) {
- log_unit_debug(u->id, "Starting of %s requested but asserts failed.", u->id);
+ log_unit_notice(u, "Starting requested but asserts failed.");
return -EPROTO;
}
/* Forward to the main object, if we aren't it. */
following = unit_following(u);
if (following) {
- log_unit_debug(u->id, "Redirecting start request from %s to %s.", u->id, following->id);
+ log_unit_debug(u, "Redirecting start request from %s to %s.", u->id, following->id);
return unit_start(following);
}
- if (UNIT_VTABLE(u)->supported && !UNIT_VTABLE(u)->supported(u->manager))
- return -ENOTSUP;
+ if (!unit_supported(u))
+ return -EOPNOTSUPP;
/* If it is stopped, but we cannot start it, then fail */
if (!UNIT_VTABLE(u)->start)
@@ -1517,7 +1518,7 @@ int unit_stop(Unit *u) {
following = unit_following(u);
if (following) {
- log_unit_debug(u->id, "Redirecting stop request from %s to %s.", u->id, following->id);
+ log_unit_debug(u, "Redirecting stop request from %s to %s.", u->id, following->id);
return unit_stop(following);
}
@@ -1558,13 +1559,13 @@ int unit_reload(Unit *u) {
return -EALREADY;
if (state != UNIT_ACTIVE) {
- log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.", u->id);
+ log_unit_warning(u, "Unit cannot be reloaded because it is inactive.");
return -ENOEXEC;
}
following = unit_following(u);
if (following) {
- log_unit_debug(u->id, "Redirecting reload request from %s to %s.", u->id, following->id);
+ log_unit_debug(u, "Redirecting reload request from %s to %s.", u->id, following->id);
return unit_reload(following);
}
@@ -1591,8 +1592,20 @@ bool unit_can_reload(Unit *u) {
}
static void unit_check_unneeded(Unit *u) {
- Iterator i;
+
+ static const UnitDependency needed_dependencies[] = {
+ UNIT_REQUIRED_BY,
+ UNIT_REQUIRED_BY_OVERRIDABLE,
+ UNIT_REQUISITE,
+ UNIT_REQUISITE_OF_OVERRIDABLE,
+ UNIT_WANTED_BY,
+ UNIT_BOUND_BY,
+ };
+
Unit *other;
+ Iterator i;
+ unsigned j;
+ int r;
assert(u);
@@ -1605,32 +1618,32 @@ static void unit_check_unneeded(Unit *u) {
if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
return;
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
- if (unit_active_or_pending(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
- if (unit_active_or_pending(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
- if (unit_active_or_pending(other))
- return;
+ for (j = 0; j < ELEMENTSOF(needed_dependencies); j++)
+ SET_FOREACH(other, u->dependencies[needed_dependencies[j]], i)
+ if (unit_active_or_pending(other))
+ return;
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (unit_active_or_pending(other))
- return;
+ /* If stopping a unit fails continously we might enter a stop
+ * loop here, hence stop acting on the service being
+ * unnecessary after a while. */
+ if (!ratelimit_test(&u->auto_stop_ratelimit)) {
+ log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
+ return;
+ }
- log_unit_info(u->id, "Unit %s is not needed anymore. Stopping.", u->id);
+ log_unit_info(u, "Unit not needed anymore. Stopping.");
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m");
}
static void unit_check_binds_to(Unit *u) {
bool stop = false;
Unit *other;
Iterator i;
+ int r;
assert(u);
@@ -1648,15 +1661,27 @@ static void unit_check_binds_to(Unit *u) {
continue;
stop = true;
+ break;
}
if (!stop)
return;
- log_unit_info(u->id, "Unit %s is bound to inactive unit. Stopping, too.", u->id);
+ /* If stopping a unit fails continously we might enter a stop
+ * loop here, hence stop acting on the service being
+ * unnecessary after a while. */
+ if (!ratelimit_test(&u->auto_stop_ratelimit)) {
+ log_unit_warning(u, "Unit is bound to inactive unit %s, but not stopping since we tried this too often recently.", other->id);
+ return;
+ }
+
+ assert(other);
+ log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
/* A unit we need to run is gone. Sniff. Let's stop this. */
- manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m");
}
static void retroactively_start_dependencies(Unit *u) {
@@ -1745,14 +1770,14 @@ void unit_start_on_failure(Unit *u) {
if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
return;
- log_unit_info(u->id, "Triggering OnFailure= dependencies of %s.", u->id);
+ log_unit_info(u, "Triggering OnFailure= dependencies.");
SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
int r;
r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL);
if (r < 0)
- log_unit_error_errno(u->id, r, "Failed to enqueue OnFailure= job: %m");
+ log_unit_error_errno(u, r, "Failed to enqueue OnFailure= job: %m");
}
}
@@ -1801,10 +1826,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
}
/* Keep track of failed units */
- if (ns == UNIT_FAILED)
- set_put(u->manager->failed_units, u);
- else
- set_remove(u->manager->failed_units, u);
+ manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
/* Make sure the cgroup is always removed when we become inactive */
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
@@ -1916,7 +1938,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
check_unneeded_dependencies(u);
if (ns != os && ns == UNIT_FAILED) {
- log_unit_notice(u->id, "Unit %s entered failed state.", u->id);
+ log_unit_notice(u, "Unit entered failed state.");
unit_start_on_failure(u);
}
}
@@ -2147,51 +2169,17 @@ bool unit_job_is_applicable(Unit *u, JobType j) {
}
}
-static int maybe_warn_about_dependency(const char *id, const char *other, UnitDependency dependency) {
- assert(id);
-
- switch (dependency) {
- case UNIT_REQUIRES:
- case UNIT_REQUIRES_OVERRIDABLE:
- case UNIT_WANTS:
- case UNIT_REQUISITE:
- case UNIT_REQUISITE_OVERRIDABLE:
- case UNIT_BINDS_TO:
- case UNIT_PART_OF:
- case UNIT_REQUIRED_BY:
- case UNIT_REQUIRED_BY_OVERRIDABLE:
- case UNIT_WANTED_BY:
- case UNIT_BOUND_BY:
- case UNIT_CONSISTS_OF:
- case UNIT_REFERENCES:
- case UNIT_REFERENCED_BY:
- case UNIT_PROPAGATES_RELOAD_TO:
- case UNIT_RELOAD_PROPAGATED_FROM:
- case UNIT_JOINS_NAMESPACE_OF:
- return 0;
-
- case UNIT_CONFLICTS:
- case UNIT_CONFLICTED_BY:
- case UNIT_BEFORE:
- case UNIT_AFTER:
- case UNIT_ON_FAILURE:
- case UNIT_TRIGGERS:
- case UNIT_TRIGGERED_BY:
- if (streq_ptr(id, other))
- log_unit_warning(id, "Dependency %s=%s dropped from unit %s",
- unit_dependency_to_string(dependency), id, other);
- else
- log_unit_warning(id, "Dependency %s=%s dropped from unit %s merged into %s",
- unit_dependency_to_string(dependency), id,
- strna(other), id);
- return -EINVAL;
+static void maybe_warn_about_dependency(Unit *u, const char *other, UnitDependency dependency) {
+ assert(u);
- case _UNIT_DEPENDENCY_MAX:
- case _UNIT_DEPENDENCY_INVALID:
- break;
- }
+ /* Only warn about some unit types */
+ if (!IN_SET(dependency, UNIT_CONFLICTS, UNIT_CONFLICTED_BY, UNIT_BEFORE, UNIT_AFTER, UNIT_ON_FAILURE, UNIT_TRIGGERS, UNIT_TRIGGERED_BY))
+ return;
- assert_not_reached("Invalid dependency type");
+ if (streq_ptr(u->id, other))
+ log_unit_warning(u, "Dependency %s=%s dropped", unit_dependency_to_string(dependency), u->id);
+ else
+ log_unit_warning(u, "Dependency %s=%s dropped, merged into %s", unit_dependency_to_string(dependency), strna(other), u->id);
}
int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
@@ -2200,13 +2188,15 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen
[UNIT_REQUIRES] = UNIT_REQUIRED_BY,
[UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
[UNIT_WANTS] = UNIT_WANTED_BY,
- [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
- [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
+ [UNIT_REQUISITE] = UNIT_REQUISITE_OF,
+ [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUISITE_OF_OVERRIDABLE,
[UNIT_BINDS_TO] = UNIT_BOUND_BY,
[UNIT_PART_OF] = UNIT_CONSISTS_OF,
- [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
+ [UNIT_REQUIRED_BY] = UNIT_REQUIRES,
+ [UNIT_REQUIRED_BY_OVERRIDABLE] = UNIT_REQUIRES_OVERRIDABLE,
+ [UNIT_REQUISITE_OF] = UNIT_REQUISITE,
+ [UNIT_REQUISITE_OF_OVERRIDABLE] = UNIT_REQUISITE_OVERRIDABLE,
+ [UNIT_WANTED_BY] = UNIT_WANTS,
[UNIT_BOUND_BY] = UNIT_BINDS_TO,
[UNIT_CONSISTS_OF] = UNIT_PART_OF,
[UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
@@ -2235,7 +2225,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen
/* We won't allow dependencies on ourselves. We will not
* consider them an error however. */
if (u == other) {
- maybe_warn_about_dependency(orig_u->id, orig_other->id, d);
+ maybe_warn_about_dependency(orig_u, orig_other->id, d);
return 0;
}
@@ -2308,58 +2298,55 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit
if (r < 0)
return r;
- r = unit_add_dependency(u, e, other, add_reference);
- if (r < 0)
- return r;
-
- return 0;
+ return unit_add_dependency(u, e, other, add_reference);
}
-static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
- char *s;
+static int resolve_template(Unit *u, const char *name, const char*path, char **buf, const char **ret) {
+ int r;
assert(u);
assert(name || path);
- assert(p);
+ assert(buf);
+ assert(ret);
if (!name)
name = basename(path);
- if (!unit_name_is_template(name)) {
- *p = NULL;
- return name;
+ if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
+ *buf = NULL;
+ *ret = name;
+ return 0;
}
if (u->instance)
- s = unit_name_replace_instance(name, u->instance);
+ r = unit_name_replace_instance(name, u->instance, buf);
else {
_cleanup_free_ char *i = NULL;
- i = unit_name_to_prefix(u->id);
- if (!i)
- return NULL;
+ r = unit_name_to_prefix(u->id, &i);
+ if (r < 0)
+ return r;
- s = unit_name_replace_instance(name, i);
+ r = unit_name_replace_instance(name, i, buf);
}
+ if (r < 0)
+ return r;
- if (!s)
- return NULL;
-
- *p = s;
- return s;
+ *ret = *buf;
+ return 0;
}
int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+ _cleanup_free_ char *buf = NULL;
Unit *other;
int r;
- _cleanup_free_ char *s = NULL;
assert(u);
assert(name || path);
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
+ r = resolve_template(u, name, path, &buf, &name);
+ if (r < 0)
+ return r;
r = manager_load_unit(u->manager, name, path, NULL, &other);
if (r < 0)
@@ -2369,16 +2356,16 @@ int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, con
}
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *s = NULL;
+ _cleanup_free_ char *buf = NULL;
Unit *other;
int r;
assert(u);
assert(name || path);
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
+ r = resolve_template(u, name, path, &buf, &name);
+ if (r < 0)
+ return r;
r = manager_load_unit(u->manager, name, path, NULL, &other);
if (r < 0)
@@ -2388,16 +2375,16 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
}
int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
+ _cleanup_free_ char *buf = NULL;
Unit *other;
int r;
- _cleanup_free_ char *s = NULL;
assert(u);
assert(name || path);
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
+ r = resolve_template(u, name, path, &buf, &name);
+ if (r < 0)
+ return r;
r = manager_load_unit(u->manager, name, path, NULL, &other);
if (r < 0)
@@ -2407,26 +2394,22 @@ int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *n
}
int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
+ _cleanup_free_ char *buf = NULL;
Unit *other;
int r;
- _cleanup_free_ char *s = NULL;
assert(u);
assert(name || path);
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
+ r = resolve_template(u, name, path, &buf, &name);
if (r < 0)
return r;
- r = unit_add_two_dependencies(other, d, e, u, add_reference);
+ r = manager_load_unit(u->manager, name, path, NULL, &other);
if (r < 0)
return r;
- return r;
+ return unit_add_two_dependencies(other, d, e, u, add_reference);
}
int set_unit_path(const char *p) {
@@ -2489,18 +2472,18 @@ int unit_add_default_slice(Unit *u, CGroupContext *c) {
/* Implicitly place all instantiated units in their
* own per-template slice */
- prefix = unit_name_to_prefix(u->id);
- if (!prefix)
- return -ENOMEM;
+ r = unit_name_to_prefix(u->id, &prefix);
+ if (r < 0)
+ return r;
/* The prefix is already escaped, but it might include
* "-" which has a special meaning for slice units,
* hence escape it here extra. */
- escaped = strreplace(prefix, "-", "\\x2d");
+ escaped = unit_name_escape(prefix);
if (!escaped)
return -ENOMEM;
- if (u->manager->running_as == SYSTEMD_SYSTEM)
+ if (u->manager->running_as == MANAGER_SYSTEM)
b = strjoin("system-", escaped, ".slice", NULL);
else
b = strappend(escaped, ".slice");
@@ -2510,7 +2493,7 @@ int unit_add_default_slice(Unit *u, CGroupContext *c) {
slice_name = b;
} else
slice_name =
- u->manager->running_as == SYSTEMD_SYSTEM
+ u->manager->running_as == MANAGER_SYSTEM
? SPECIAL_SYSTEM_SLICE
: SPECIAL_ROOT_SLICE;
@@ -2539,11 +2522,11 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
assert(type);
assert(_found);
- t = unit_name_change_suffix(u->id, type);
- if (!t)
- return -ENOMEM;
-
- assert(!unit_has_name(u, t));
+ r = unit_name_change_suffix(u->id, type, &t);
+ if (r < 0)
+ return r;
+ if (unit_has_name(u, t))
+ return -EINVAL;
r = manager_load_unit(u->manager, t, NULL, NULL, _found);
assert(r < 0 || *_found != u);
@@ -2589,7 +2572,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
rt = unit_get_exec_runtime(u);
if (rt) {
- r = exec_runtime_serialize(rt, u, f, fds);
+ r = exec_runtime_serialize(u, rt, f, fds);
if (r < 0)
return r;
}
@@ -2609,6 +2592,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result));
unit_serialize_item(u, f, "transient", yes_no(u->transient));
+ unit_serialize_item_format(u, f, "cpuacct-usage-base", "%" PRIu64, u->cpuacct_usage_base);
if (u->cgroup_path)
unit_serialize_item(u, f, "cgroup", u->cgroup_path);
@@ -2657,6 +2641,40 @@ void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
fprintf(f, "%s=%s\n", key, value);
}
+static int unit_set_cgroup_path(Unit *u, const char *path) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ assert(u);
+
+ if (path) {
+ p = strdup(path);
+ if (!p)
+ return -ENOMEM;
+ } else
+ p = NULL;
+
+ if (streq_ptr(u->cgroup_path, p))
+ return 0;
+
+ if (p) {
+ r = hashmap_put(u->manager->cgroup_unit, p, u);
+ if (r < 0)
+ return r;
+ }
+
+ if (u->cgroup_path) {
+ log_unit_debug(u, "Changing cgroup path from %s to %s.", u->cgroup_path, strna(p));
+ hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
+ free(u->cgroup_path);
+ }
+
+ u->cgroup_path = p;
+ p = NULL;
+
+ return 0;
+}
+
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
ExecRuntime **rt = NULL;
size_t offset;
@@ -2684,7 +2702,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
l = strstrip(line);
/* End marker */
- if (l[0] == 0)
+ if (isempty(l))
return 0;
k = strcspn(l, "=");
@@ -2702,7 +2720,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
j = job_new_raw(u);
if (!j)
- return -ENOMEM;
+ return log_oom();
r = job_deserialize(j, f, fds);
if (r < 0) {
@@ -2722,16 +2740,8 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
job_free(j);
return r;
}
- } else {
- /* legacy */
- JobType type;
-
- type = job_type_from_string(v);
- if (type < 0)
- log_debug("Failed to parse job type value %s", v);
- else
- u->deserialized_job = type;
- }
+ } else /* legacy for pre-44 */
+ log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
continue;
} else if (streq(l, "inactive-exit-timestamp")) {
dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
@@ -2752,71 +2762,68 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
dual_timestamp_deserialize(v, &u->assert_timestamp);
continue;
} else if (streq(l, "condition-result")) {
- int b;
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse condition result value %s", v);
+ r = parse_boolean(v);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v);
else
- u->condition_result = b;
+ u->condition_result = r;
continue;
} else if (streq(l, "assert-result")) {
- int b;
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse assert result value %s", v);
+ r = parse_boolean(v);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v);
else
- u->assert_result = b;
+ u->assert_result = r;
continue;
} else if (streq(l, "transient")) {
- int b;
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse transient bool %s", v);
+ r = parse_boolean(v);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v);
else
- u->transient = b;
+ u->transient = r;
continue;
- } else if (streq(l, "cgroup")) {
- char *s;
- s = strdup(v);
- if (!s)
- return -ENOMEM;
+ } else if (streq(l, "cpuacct-usage-base")) {
- if (u->cgroup_path) {
- void *p;
+ r = safe_atou64(v, &u->cpuacct_usage_base);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse CPU usage %s, ignoring.", v);
- p = hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
- log_info("Removing cgroup_path %s from hashmap (%p)",
- u->cgroup_path, p);
- free(u->cgroup_path);
- }
+ continue;
- u->cgroup_path = s;
- assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1);
+ } else if (streq(l, "cgroup")) {
+
+ r = unit_set_cgroup_path(u, v);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
continue;
}
if (unit_can_serialize(u)) {
if (rt) {
- r = exec_runtime_deserialize_item(rt, u, l, v, fds);
- if (r < 0)
- return r;
+ r = exec_runtime_deserialize_item(u, rt, l, v, fds);
+ if (r < 0) {
+ log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
+ continue;
+ }
+
+ /* Returns positive if key was handled by the call */
if (r > 0)
continue;
}
r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
if (r < 0)
- return r;
+ log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
}
}
}
@@ -2828,24 +2835,27 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
assert(u);
- if (!what)
- return 0;
-
/* Adds in links to the device node that this unit is based on */
+ if (isempty(what))
+ return 0;
if (!is_device_path(what))
return 0;
- e = unit_name_from_path(what, ".device");
- if (!e)
- return -ENOMEM;
+ /* When device units aren't supported (such as in a
+ * container), don't create dependencies on them. */
+ if (!unit_type_supported(UNIT_DEVICE))
+ return 0;
- r = manager_load_unit(u->manager, e, NULL, NULL, &device);
+ r = unit_name_from_path(what, ".device", &e);
+ if (r < 0)
+ return r;
+ r = manager_load_unit(u->manager, e, NULL, NULL, &device);
if (r < 0)
return r;
- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, device, true);
+ r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == MANAGER_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true);
if (r < 0)
return r;
@@ -2863,21 +2873,23 @@ int unit_coldplug(Unit *u) {
assert(u);
- if (UNIT_VTABLE(u)->coldplug)
- if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
+ /* Make sure we don't enter a loop, when coldplugging
+ * recursively. */
+ if (u->coldplugged)
+ return 0;
+
+ u->coldplugged = true;
+
+ if (UNIT_VTABLE(u)->coldplug) {
+ r = UNIT_VTABLE(u)->coldplug(u);
+ if (r < 0)
return r;
+ }
if (u->job) {
r = job_coldplug(u->job);
if (r < 0)
return r;
- } else if (u->deserialized_job >= 0) {
- /* legacy */
- r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL);
- if (r < 0)
- return r;
-
- u->deserialized_job = _JOB_TYPE_INVALID;
}
return 0;
@@ -3011,7 +3023,7 @@ int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
assert(signo < _NSIG);
if (!UNIT_VTABLE(u)->kill)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
return UNIT_VTABLE(u)->kill(u, w, signo, error);
}
@@ -3111,7 +3123,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
if (u->unit_file_state < 0 && u->fragment_path)
u->unit_file_state = unit_file_get_state(
- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
NULL, basename(u->fragment_path));
return u->unit_file_state;
@@ -3122,7 +3134,7 @@ int unit_get_unit_file_preset(Unit *u) {
if (u->unit_file_preset < 0 && u->fragment_path)
u->unit_file_preset = unit_file_query_preset(
- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
NULL, basename(u->fragment_path));
return u->unit_file_preset;
@@ -3172,7 +3184,7 @@ int unit_patch_contexts(Unit *u) {
return -ENOMEM;
}
- if (u->manager->running_as == SYSTEMD_USER &&
+ if (u->manager->running_as == MANAGER_USER &&
!ec->working_directory) {
r = get_home_dir(&ec->working_directory);
@@ -3184,7 +3196,7 @@ int unit_patch_contexts(Unit *u) {
ec->working_directory_missing_ok = true;
}
- if (u->manager->running_as == SYSTEMD_USER &&
+ if (u->manager->running_as == MANAGER_USER &&
(ec->syscall_whitelist ||
!set_isempty(ec->syscall_filter) ||
!set_isempty(ec->syscall_archs) ||
@@ -3263,7 +3275,7 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
}
static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) {
- if (u->manager->running_as == SYSTEMD_USER) {
+ if (u->manager->running_as == MANAGER_USER) {
int r;
if (mode == UNIT_PERSISTENT && !transient)
@@ -3432,7 +3444,7 @@ int unit_make_transient(Unit *u) {
free(u->fragment_path);
u->fragment_path = NULL;
- if (u->manager->running_as == SYSTEMD_USER) {
+ if (u->manager->running_as == MANAGER_USER) {
_cleanup_free_ char *c = NULL;
r = user_runtime_dir(&c);
@@ -3494,7 +3506,7 @@ int unit_kill_context(
_cleanup_free_ char *comm = NULL;
get_process_comm(main_pid, &comm);
- log_unit_warning_errno(u->id, r, "Failed to kill main process " PID_FMT " (%s): %m", main_pid, strna(comm));
+ log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s): %m", main_pid, strna(comm));
} else {
if (!main_pid_alien)
wait_for_exit = true;
@@ -3511,7 +3523,7 @@ int unit_kill_context(
_cleanup_free_ char *comm = NULL;
get_process_comm(control_pid, &comm);
- log_unit_warning_errno(u->id, r, "Failed to kill control process " PID_FMT " (%s): %m", control_pid, strna(comm));
+ log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s): %m", control_pid, strna(comm));
} else {
wait_for_exit = true;
@@ -3531,7 +3543,7 @@ int unit_kill_context(
r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_unit_warning_errno(u->id, r, "Failed to kill control group: %m");
+ log_unit_warning_errno(u, r, "Failed to kill control group: %m");
} else if (r > 0) {
/* FIXME: For now, we will not wait for the
@@ -3603,11 +3615,9 @@ int unit_require_mounts_for(Unit *u, const char *path) {
if (!x) {
char *q;
- if (!u->manager->units_requiring_mounts_for) {
- u->manager->units_requiring_mounts_for = hashmap_new(&string_hash_ops);
- if (!u->manager->units_requiring_mounts_for)
- return -ENOMEM;
- }
+ r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &string_hash_ops);
+ if (r < 0)
+ return r;
q = strdup(prefix);
if (!q)
@@ -3662,6 +3672,64 @@ int unit_setup_exec_runtime(Unit *u) {
return exec_runtime_make(rt, unit_get_exec_context(u), u->id);
}
+bool unit_type_supported(UnitType t) {
+ if (_unlikely_(t < 0))
+ return false;
+ if (_unlikely_(t >= _UNIT_TYPE_MAX))
+ return false;
+
+ if (!unit_vtable[t]->supported)
+ return true;
+
+ return unit_vtable[t]->supported();
+}
+
+void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
+ int r;
+
+ assert(u);
+ assert(where);
+
+ r = dir_is_empty(where);
+ if (r > 0)
+ return;
+ if (r < 0) {
+ log_unit_warning_errno(u, r, "Failed to check directory %s: %m", where);
+ return;
+ }
+
+ log_struct(LOG_NOTICE,
+ LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
+ "WHERE=%s", where,
+ NULL);
+}
+
+int unit_fail_if_symlink(Unit *u, const char* where) {
+ int r;
+
+ assert(u);
+ assert(where);
+
+ r = is_symlink(where);
+ if (r < 0) {
+ log_unit_debug_errno(u, r, "Failed to check symlink %s, ignoring: %m", where);
+ return 0;
+ }
+ if (r == 0)
+ return 0;
+
+ log_struct(LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
+ LOG_UNIT_ID(u),
+ LOG_UNIT_MESSAGE(u, "Mount on symlink %s not allowed.", where),
+ "WHERE=%s", where,
+ NULL);
+
+ return -ELOOP;
+}
+
static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
[UNIT_ACTIVE] = "active",
[UNIT_RELOADING] = "reloading",
diff --git a/src/core/unit.h b/src/core/unit.h
index 291bc77a76..9491ef64f9 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -31,13 +31,7 @@ typedef enum UnitActiveState UnitActiveState;
typedef struct UnitRef UnitRef;
typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-#include "sd-event.h"
-#include "set.h"
-#include "util.h"
#include "list.h"
-#include "socket-util.h"
-#include "execute.h"
-#include "cgroup.h"
#include "condition.h"
#include "install.h"
#include "unit-name.h"
@@ -58,6 +52,8 @@ typedef enum KillOperation {
KILL_TERMINATE,
KILL_KILL,
KILL_ABORT,
+ _KILL_OPERATION_MAX,
+ _KILL_OPERATION_INVALID = -1
} KillOperation;
static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) {
@@ -76,7 +72,6 @@ static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
return t == UNIT_INACTIVE || t == UNIT_FAILED;
}
-#include "manager.h"
#include "job.h"
struct UnitRef {
@@ -109,6 +104,7 @@ struct Unit {
char *fragment_path; /* if loaded from a config file this is the primary path to it */
char *source_path; /* if converted, the source file */
char **dropin_paths;
+
usec_t fragment_mtime;
usec_t source_mtime;
usec_t dropin_mtime;
@@ -170,19 +166,19 @@ struct Unit {
/* Used during GC sweeps */
unsigned gc_marker;
- /* When deserializing, temporarily store the job type for this
- * unit here, if there was a job scheduled.
- * Only for deserializing from a legacy version. New style uses full
- * serialized jobs. */
- int deserialized_job; /* This is actually of type JobType */
-
/* Error code when we didn't manage to load the unit (negative) */
int load_error;
+ /* Make sure we never enter endless loops with the check unneeded logic, or the BindsTo= logic */
+ RateLimit auto_stop_ratelimit;
+
/* Cached unit file state and preset */
UnitFileState unit_file_state;
int unit_file_preset;
+ /* Where the cpuacct.usage cgroup counter was at the time the unit was started */
+ nsec_t cpuacct_usage_base;
+
/* Counterparts in the cgroup filesystem */
char *cgroup_path;
CGroupControllerMask cgroup_realized_mask;
@@ -235,6 +231,9 @@ struct Unit {
bool cgroup_realized:1;
bool cgroup_members_mask_valid:1;
bool cgroup_subtree_mask_valid:1;
+
+ /* Did we already invoke unit_coldplug() for this unit? */
+ bool coldplugged:1;
};
struct UnitStatusMessageFormats {
@@ -249,13 +248,11 @@ typedef enum UnitSetPropertiesMode {
UNIT_PERSISTENT = 2,
} UnitSetPropertiesMode;
-#include "service.h"
#include "socket.h"
#include "busname.h"
#include "target.h"
#include "snapshot.h"
#include "device.h"
-#include "mount.h"
#include "automount.h"
#include "swap.h"
#include "timer.h"
@@ -402,7 +399,7 @@ struct UnitVTable {
/* If this function is set and return false all jobs for units
* of this type will immediately fail. */
- bool (*supported)(Manager *m);
+ bool (*supported)(void);
/* The interface name */
const char *bus_interface;
@@ -601,25 +598,38 @@ int unit_make_transient(Unit *u);
int unit_require_mounts_for(Unit *u, const char *path);
-const char *unit_active_state_to_string(UnitActiveState i) _const_;
-UnitActiveState unit_active_state_from_string(const char *s) _pure_;
+bool unit_type_supported(UnitType t);
-/* Macros which append UNIT= or USER_UNIT= to the message */
+static inline bool unit_supported(Unit *u) {
+ return unit_type_supported(u->type);
+}
-#define log_unit_full_errno(unit, level, error, ...) log_object_internal(level, error, __FILE__, __LINE__, __func__, getpid() == 1 ? "UNIT=" : "USER_UNIT=", unit, __VA_ARGS__)
-#define log_unit_full(unit, level, ...) log_unit_full_errno(unit, level, 0, __VA_ARGS__)
+void unit_warn_if_dir_nonempty(Unit *u, const char* where);
+int unit_fail_if_symlink(Unit *u, const char* where);
-#define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, __VA_ARGS__)
-#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, __VA_ARGS__)
-#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, __VA_ARGS__)
-#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, __VA_ARGS__)
-#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, __VA_ARGS__)
+const char *unit_active_state_to_string(UnitActiveState i) _const_;
+UnitActiveState unit_active_state_from_string(const char *s) _pure_;
-#define log_unit_debug_errno(unit, error, ...) log_unit_full_errno(unit, LOG_DEBUG, error, __VA_ARGS__)
-#define log_unit_info_errno(unit, error, ...) log_unit_full_errno(unit, LOG_INFO, error, __VA_ARGS__)
-#define log_unit_notice_errno(unit, error, ...) log_unit_full_errno(unit, LOG_NOTICE, error, __VA_ARGS__)
-#define log_unit_warning_errno(unit, error, ...) log_unit_full_errno(unit, LOG_WARNING, error, __VA_ARGS__)
-#define log_unit_error_errno(unit, error, ...) log_unit_full_errno(unit, LOG_ERR, error, __VA_ARGS__)
+/* Macros which append UNIT= or USER_UNIT= to the message */
-#define log_unit_struct(unit, level, ...) log_struct(level, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
-#define log_unit_struct_errno(unit, level, error, ...) log_struct_errno(level, error, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
+#define log_unit_full(unit, level, error, ...) \
+ ({ \
+ Unit *_u = (unit); \
+ _u ? log_object_internal(level, error, __FILE__, __LINE__, __func__, _u->manager->unit_log_field, _u->id, ##__VA_ARGS__) : \
+ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
+ })
+
+#define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_unit_debug_errno(unit, error, ...) log_unit_full(unit, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_unit_info_errno(unit, error, ...) log_unit_full(unit, LOG_INFO, error, ##__VA_ARGS__)
+#define log_unit_notice_errno(unit, error, ...) log_unit_full(unit, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_unit_warning_errno(unit, error, ...) log_unit_full(unit, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_unit_error_errno(unit, error, ...) log_unit_full(unit, LOG_ERR, error, ##__VA_ARGS__)
+
+#define LOG_UNIT_MESSAGE(unit, fmt, ...) "MESSAGE=%s: " fmt, (unit)->id, ##__VA_ARGS__
+#define LOG_UNIT_ID(unit) (unit)->manager->unit_log_format_string, (unit)->id
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 05061c0704..6fad8ad80c 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -20,11 +20,8 @@
***/
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
#include "dropin.h"
-#include "fileio.h"
#include "generator.h"
#include "hashmap.h"
#include "log.h"
@@ -81,9 +78,9 @@ static int create_disk(
if (!e)
return log_oom();
- n = unit_name_build("systemd-cryptsetup", e, ".service");
- if (!n)
- return log_oom();
+ r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
p = strjoin(arg_dest, "/", n, NULL);
if (!p)
@@ -93,9 +90,9 @@ static int create_disk(
if (!u)
return log_oom();
- d = unit_name_from_path(u, ".device");
- if (!d)
- return log_oom();
+ r = unit_name_from_path(u, ".device", &d);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
f = fopen(p, "wxe");
if (!f)
@@ -131,11 +128,11 @@ static int create_disk(
if (!path_equal(uu, "/dev/null")) {
if (is_device_path(uu)) {
- _cleanup_free_ char *dd;
+ _cleanup_free_ char *dd = NULL;
- dd = unit_name_from_path(uu, ".device");
- if (!dd)
- return log_oom();
+ r = unit_name_from_path(uu, ".device", &dd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
} else
@@ -179,9 +176,9 @@ static int create_disk(
"ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
name);
- fflush(f);
- if (ferror(f))
- return log_error_errno(errno, "Failed to write file %s: %m", p);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write file %s: %m", p);
from = strjoina("../", n);
@@ -377,13 +374,6 @@ static int add_crypttab_devices(void) {
return 0;
}
- /* If we readd support for specifying passphrases
- * directly in crypttab we should upgrade the warning
- * below, though possibly only if a passphrase is
- * specified directly. */
- if (st.st_mode & 0005)
- log_debug("/etc/crypttab is world-readable. This is usually not a good idea.");
-
for (;;) {
int r, k;
char line[LINE_MAX], *l, *uuid;
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 3f613d9b65..a5018f13ed 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -32,9 +32,8 @@
#include "path-util.h"
#include "strv.h"
#include "ask-password-api.h"
-#include "def.h"
-#include "libudev.h"
-#include "udev-util.h"
+#include "sd-device.h"
+#include "device-util.h"
static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
static char *arg_cipher = NULL;
@@ -51,12 +50,12 @@ static bool arg_discards = false;
static bool arg_tcrypt_hidden = false;
static bool arg_tcrypt_system = false;
static char **arg_tcrypt_keyfiles = NULL;
+static uint64_t arg_offset = 0;
+static uint64_t arg_skip = 0;
static usec_t arg_timeout = 0;
/* Options Debian's crypttab knows we don't:
- offset=
- skip=
precheck=
check=
checkargs=
@@ -186,6 +185,20 @@ static int parse_one_option(const char *option) {
return 0;
}
+ } else if (startswith(option, "offset=")) {
+
+ if (safe_atou64(option+7, &arg_offset) < 0) {
+ log_error("offset= parse failure, refusing.");
+ return -EINVAL;
+ }
+
+ } else if (startswith(option, "skip=")) {
+
+ if (safe_atou64(option+5, &arg_skip) < 0) {
+ log_error("skip= parse failure, refusing.");
+ return -EINVAL;
+ }
+
} else if (!streq(option, "none"))
log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
@@ -210,6 +223,14 @@ static int parse_options(const char *options) {
return r;
}
+ /* sanity-check options */
+ if (arg_type != NULL && !streq(arg_type, CRYPT_PLAIN)) {
+ if (arg_offset)
+ log_warning("offset= ignored with type %s", arg_type);
+ if (arg_skip)
+ log_warning("skip= ignored with type %s", arg_type);
+ }
+
return 0;
}
@@ -225,10 +246,10 @@ static char* disk_description(const char *path) {
"ID_MODEL_FROM_DATABASE\0"
"ID_MODEL\0";
- _cleanup_udev_unref_ struct udev *udev = NULL;
- _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ _cleanup_device_unref_ sd_device *device = NULL;
struct stat st;
const char *i;
+ int r;
assert(path);
@@ -238,19 +259,15 @@ static char* disk_description(const char *path) {
if (!S_ISBLK(st.st_mode))
return NULL;
- udev = udev_new();
- if (!udev)
- return NULL;
-
- device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
- if (!device)
+ r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
+ if (r < 0)
return NULL;
NULSTR_FOREACH(i, name_fields) {
const char *name;
- name = udev_device_get_property_value(device, i);
- if (!isempty(name))
+ r = sd_device_get_property_value(device, i, &name);
+ if (r >= 0 && !isempty(name))
return strdup(name);
}
@@ -415,7 +432,10 @@ static int attach_luks_or_plain(struct crypt_device *cd,
}
if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
- struct crypt_params_plain params = {};
+ struct crypt_params_plain params = {
+ .offset = arg_offset,
+ .skip = arg_skip,
+ };
const char *cipher, *cipher_mode;
_cleanup_free_ char *truncated_cipher = NULL;
diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c
index 2e08af2df2..4980fccc31 100644
--- a/src/dbus1-generator/dbus1-generator.c
+++ b/src/dbus1-generator/dbus1-generator.c
@@ -188,7 +188,7 @@ static int add_dbus(const char *path, const char *fname, const char *type) {
}
if (service) {
- if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
+ if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
log_warning("Unit name %s is not valid, ignoring.", service);
return 0;
}
@@ -302,7 +302,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (access("/sys/fs/kdbus/control", F_OK) < 0)
+ if (!is_kdbus_available())
return 0;
r = cg_pid_get_owner_uid(0, NULL);
@@ -310,7 +310,7 @@ int main(int argc, char *argv[]) {
path = "/usr/share/dbus-1/services";
type = "session";
units = USER_DATA_UNIT_PATH;
- } else if (r == -ENOENT) {
+ } else if (r == -ENXIO) {
path = "/usr/share/dbus-1/system-services";
type = "system";
units = SYSTEM_DATA_UNIT_PATH;
diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c
index 1b9019325c..9d0ab06e2f 100644
--- a/src/debug-generator/debug-generator.c
+++ b/src/debug-generator/debug-generator.c
@@ -41,9 +41,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
else {
char *n;
- n = unit_name_mangle(value, MANGLE_NOGLOB);
- if (!n)
- return log_oom();
+ r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to glob unit name: %m");
r = strv_consume(&arg_mask, n);
if (r < 0)
@@ -57,9 +57,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
else {
char *n;
- n = unit_name_mangle(value, MANGLE_NOGLOB);
- if (!n)
- return log_oom();
+ r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to glob unit name: %m");
r = strv_consume(&arg_wants, n);
if (r < 0)
diff --git a/src/delta/delta.c b/src/delta/delta.c
index de963f7009..c764bb4b46 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -21,7 +21,6 @@
***/
#include <errno.h>
-#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
@@ -33,6 +32,8 @@
#include "pager.h"
#include "build.h"
#include "strv.h"
+#include "process-util.h"
+#include "terminal-util.h"
static const char prefixes[] =
"/etc\0"
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index 9a924117db..606d073cbc 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -22,7 +22,6 @@
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
-#include <string.h>
#include <getopt.h>
#include "util.h"
diff --git a/src/efi-boot-generator/efi-boot-generator.c b/src/efi-boot-generator/efi-boot-generator.c
index b3ff3a8b78..e6b15c9bb0 100644
--- a/src/efi-boot-generator/efi-boot-generator.c
+++ b/src/efi-boot-generator/efi-boot-generator.c
@@ -26,7 +26,6 @@
#include "path-util.h"
#include "util.h"
#include "mkdir.h"
-#include "unit-name.h"
#include "virt.h"
#include "generator.h"
#include "special.h"
@@ -69,8 +68,14 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
- if (path_is_mount_point("/boot", true) <= 0 &&
- dir_is_empty("/boot") <= 0) {
+ r = path_is_mount_point("/boot", AT_SYMLINK_FOLLOW);
+ if (r > 0) {
+ log_debug("/boot is already a mount point, exiting.");
+ return EXIT_SUCCESS;
+ }
+ if (r == -ENOENT)
+ log_debug("/boot does not exist, continuing.");
+ else if (dir_is_empty("/boot") <= 0) {
log_debug("/boot already populated, exiting.");
return EXIT_SUCCESS;
}
@@ -118,9 +123,9 @@ int main(int argc, char *argv[]) {
"Options=umask=0077,noauto\n",
what);
- fflush(f);
- if (ferror(f)) {
- log_error_errno(errno, "Failed to write mount unit file: %m");
+ r = fflush_and_check(f);
+ if (r < 0) {
+ log_error_errno(r, "Failed to write mount unit file: %m");
return EXIT_FAILURE;
}
@@ -136,11 +141,12 @@ int main(int argc, char *argv[]) {
"[Unit]\n"
"Description=EFI System Partition Automount\n\n"
"[Automount]\n"
- "Where=/boot\n", f);
+ "Where=/boot\n"
+ "TimeoutIdleSec=120\n", f);
- fflush(f);
- if (ferror(f)) {
- log_error_errno(errno, "Failed to write automount unit file: %m");
+ r = fflush_and_check(f);
+ if (r < 0) {
+ log_error_errno(r, "Failed to write automount unit file: %m");
return EXIT_FAILURE;
}
diff --git a/src/escape/escape.c b/src/escape/escape.c
index f2a0721861..9ccb015538 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -99,7 +99,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_TEMPLATE:
- if (!unit_name_is_valid(optarg, true) || !unit_name_is_template(optarg)) {
+ if (!unit_name_is_valid(optarg, UNIT_NAME_TEMPLATE)) {
log_error("Template name %s is not valid.", optarg);
return -EINVAL;
}
@@ -166,22 +166,26 @@ int main(int argc, char *argv[]) {
switch (arg_action) {
case ACTION_ESCAPE:
- if (arg_path)
- e = unit_name_path_escape(*i);
- else
+ if (arg_path) {
+ r = unit_name_path_escape(*i, &e);
+ if (r < 0) {
+ log_error_errno(r, "Failed to escape string: %m");
+ goto finish;
+ }
+ } else {
e = unit_name_escape(*i);
-
- if (!e) {
- r = log_oom();
- goto finish;
+ if (!e) {
+ r = log_oom();
+ goto finish;
+ }
}
if (arg_template) {
char *x;
- x = unit_name_replace_instance(arg_template, e);
- if (!x) {
- r = log_oom();
+ r = unit_name_replace_instance(arg_template, e, &x);
+ if (r < 0) {
+ log_error_errno(r, "Failed to replace instance: %m");
goto finish;
}
@@ -204,20 +208,20 @@ int main(int argc, char *argv[]) {
case ACTION_UNESCAPE:
if (arg_path)
- e = unit_name_path_unescape(*i);
+ r = unit_name_path_unescape(*i, &e);
else
- e = unit_name_unescape(*i);
+ r = unit_name_unescape(*i, &e);
- if (!e) {
- r = log_oom();
+ if (r < 0) {
+ log_error_errno(r, "Failed to unescape string: %m");
goto finish;
}
break;
case ACTION_MANGLE:
- e = unit_name_mangle(*i, MANGLE_NOGLOB);
- if (!e) {
- r = log_oom();
+ r = unit_name_mangle(*i, UNIT_NAME_NOGLOB, &e);
+ if (r < 0) {
+ log_error_errno(r, "Failed to mangle name: %m");
goto finish;
}
break;
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index a765d6d219..cda96d484a 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -32,8 +32,11 @@
#include "mkdir.h"
#include "time-util.h"
#include "path-util.h"
+#include "random-util.h"
#include "locale-util.h"
#include "ask-password-api.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
static char *arg_root = NULL;
static char *arg_locale = NULL; /* $LANG */
@@ -50,8 +53,6 @@ static bool arg_copy_locale = false;
static bool arg_copy_timezone = false;
static bool arg_copy_root_password = false;
-#define prefix_roota(p) (arg_root ? (const char*) strjoina(arg_root, p) : (const char*) p)
-
static void clear_string(char *x) {
if (!x)
@@ -85,13 +86,13 @@ static void print_welcome(void) {
if (done)
return;
- os_release = prefix_roota("/etc/os-release");
+ os_release = prefix_roota(arg_root, "/etc/os-release");
r = parse_env_file(os_release, NEWLINE,
"PRETTY_NAME", &pretty_name,
NULL);
if (r == -ENOENT) {
- os_release = prefix_roota("/usr/lib/os-release");
+ os_release = prefix_roota(arg_root, "/usr/lib/os-release");
r = parse_env_file(os_release, NEWLINE,
"PRETTY_NAME", &pretty_name,
NULL);
@@ -249,7 +250,7 @@ static int process_locale(void) {
unsigned i = 0;
int r;
- etc_localeconf = prefix_roota("/etc/locale.conf");
+ etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf");
if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return 0;
@@ -323,7 +324,7 @@ static int process_timezone(void) {
const char *etc_localtime, *e;
int r;
- etc_localtime = prefix_roota("/etc/localtime");
+ etc_localtime = prefix_roota(arg_root, "/etc/localtime");
if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return 0;
@@ -402,7 +403,7 @@ static int process_hostname(void) {
const char *etc_hostname;
int r;
- etc_hostname = prefix_roota("/etc/hostname");
+ etc_hostname = prefix_roota(arg_root, "/etc/hostname");
if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return 0;
@@ -427,7 +428,7 @@ static int process_machine_id(void) {
char id[SD_ID128_STRING_MAX];
int r;
- etc_machine_id = prefix_roota("/etc/machine-id");
+ etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return 0;
@@ -453,7 +454,7 @@ static int prompt_root_password(void) {
if (!arg_prompt_root_password)
return 0;
- etc_shadow = prefix_roota("/etc/shadow");
+ etc_shadow = prefix_roota(arg_root, "/etc/shadow");
if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return 0;
@@ -525,9 +526,9 @@ static int process_root_password(void) {
struct spwd item = {
.sp_namp = (char*) "root",
- .sp_min = 0,
- .sp_max = 99999,
- .sp_warn = 7,
+ .sp_min = -1,
+ .sp_max = -1,
+ .sp_warn = -1,
.sp_inact = -1,
.sp_expire = -1,
.sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
@@ -542,7 +543,7 @@ static int process_root_password(void) {
const char *etc_shadow;
int r;
- etc_shadow = prefix_roota("/etc/shadow");
+ etc_shadow = prefix_roota(arg_root, "/etc/shadow");
if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return 0;
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 78ceeb6fab..f0e5c5f239 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -22,23 +22,38 @@
#include <stdio.h>
#include <stdbool.h>
-#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
#include "sd-bus.h"
-#include "libudev.h"
+#include "sd-device.h"
#include "util.h"
+#include "process-util.h"
+#include "signal-util.h"
#include "special.h"
#include "bus-util.h"
#include "bus-error.h"
#include "bus-common-errors.h"
-#include "fileio.h"
-#include "udev-util.h"
+#include "device-util.h"
#include "path-util.h"
+#include "socket-util.h"
+
+/* exit codes as defined in fsck(8) */
+enum {
+ FSCK_SUCCESS = 0,
+ FSCK_ERROR_CORRECTED = 1,
+ FSCK_SYSTEM_SHOULD_REBOOT = 2,
+ FSCK_ERRORS_LEFT_UNCORRECTED = 4,
+ FSCK_OPERATIONAL_ERROR = 8,
+ FSCK_USAGE_OR_SYNTAX_ERROR = 16,
+ FSCK_USER_CANCELLED = 32,
+ FSCK_SHARED_LIB_ERROR = 128,
+};
static bool arg_skip = false;
static bool arg_force = false;
@@ -72,10 +87,13 @@ static void start_target(const char *target) {
/* Don't print a warning if we aren't called during startup */
if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB))
- log_error("Failed to start unit: %s", bus_error_message(&error, -r));
+ log_error("Failed to start unit: %s", bus_error_message(&error, r));
}
static int parse_proc_cmdline_item(const char *key, const char *value) {
+ int r;
+
+ assert(key);
if (streq(key, "fsck.mode") && value) {
@@ -92,12 +110,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
if (streq(value, "preen"))
arg_repair = "-a";
- else if (streq(value, "yes"))
- arg_repair = "-y";
- else if (streq(value, "no"))
- arg_repair = "-n";
- else
- log_warning("Invalid fsck.repair= parameter '%s'. Ignoring.", value);
+ else {
+ r = parse_boolean(value);
+ if (r > 0)
+ arg_repair = "-y";
+ else if (r == 0)
+ arg_repair = "-n";
+ else
+ log_warning("Invalid fsck.repair= parameter '%s'. Ignoring.", value);
+ }
}
#ifdef HAVE_SYSV_COMPAT
@@ -128,8 +149,7 @@ static void test_files(void) {
}
#endif
- if (access("/run/systemd/show-status", F_OK) >= 0 || plymouth_running())
- arg_show_progress = true;
+ arg_show_progress = access("/run/systemd/show-status", F_OK) >= 0;
}
static double percent(int pass, unsigned long cur, unsigned long max) {
@@ -154,9 +174,13 @@ static int process_progress(int fd) {
_cleanup_fclose_ FILE *console = NULL, *f = NULL;
usec_t last = 0;
bool locked = false;
- int clear = 0;
+ int clear = 0, r;
+
+ /* No progress pipe to process? Then we are a NOP. */
+ if (fd < 0)
+ return 0;
- f = fdopen(fd, "r");
+ f = fdopen(fd, "re");
if (!f) {
safe_close(fd);
return -errno;
@@ -166,15 +190,25 @@ static int process_progress(int fd) {
if (!console)
return -ENOMEM;
- while (!feof(f)) {
+ for (;;) {
int pass, m;
unsigned long cur, max;
_cleanup_free_ char *device = NULL;
double p;
usec_t t;
- if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4)
+ if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4) {
+
+ if (ferror(f))
+ r = log_warning_errno(errno, "Failed to read from progress pipe: %m");
+ else if (feof(f))
+ r = 0;
+ else {
+ log_warning("Failed to parse progress pipe data");
+ r = -EBADMSG;
+ }
break;
+ }
/* Only show one progress counter at max */
if (!locked) {
@@ -209,21 +243,40 @@ static int process_progress(int fd) {
fflush(console);
}
- return 0;
+ return r;
+}
+
+static int fsck_progress_socket(void) {
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/fsck.progress",
+ };
+
+ int fd, r;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ return log_warning_errno(errno, "socket(): %m");
+
+ if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+ errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path);
+ safe_close(fd);
+ return r;
+ }
+
+ return fd;
}
int main(int argc, char *argv[]) {
- const char *cmdline[9];
- int i = 0, r = EXIT_FAILURE, q;
- pid_t pid;
- siginfo_t status;
- _cleanup_udev_unref_ struct udev *udev = NULL;
- _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
+ _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 };
+ _cleanup_device_unref_ sd_device *dev = NULL;
const char *device, *type;
bool root_directory;
- int progress_pipe[2] = { -1, -1 };
- char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1];
+ siginfo_t status;
struct stat st;
+ int r;
+ pid_t pid;
if (argc > 2) {
log_error("This program expects one or no arguments.");
@@ -236,135 +289,164 @@ int main(int argc, char *argv[]) {
umask(0022);
- q = parse_proc_cmdline(parse_proc_cmdline_item);
- if (q < 0)
- log_warning_errno(q, "Failed to parse kernel command line, ignoring: %m");
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
test_files();
- if (!arg_force && arg_skip)
- return 0;
-
- udev = udev_new();
- if (!udev) {
- log_oom();
- return EXIT_FAILURE;
+ if (!arg_force && arg_skip) {
+ r = 0;
+ goto finish;
}
if (argc > 1) {
device = argv[1];
- root_directory = false;
if (stat(device, &st) < 0) {
- log_error_errno(errno, "Failed to stat '%s': %m", device);
- return EXIT_FAILURE;
+ r = log_error_errno(errno, "Failed to stat %s: %m", device);
+ goto finish;
+ }
+
+ if (!S_ISBLK(st.st_mode)) {
+ log_error("%s is not a block device.", device);
+ r = -EINVAL;
+ goto finish;
}
- udev_device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
- if (!udev_device) {
- log_error("Failed to detect device %s", device);
- return EXIT_FAILURE;
+ r = sd_device_new_from_devnum(&dev, 'b', st.st_rdev);
+ if (r < 0) {
+ log_error_errno(r, "Failed to detect device %s: %m", device);
+ goto finish;
}
+
+ root_directory = false;
} else {
struct timespec times[2];
/* Find root device */
if (stat("/", &st) < 0) {
- log_error_errno(errno, "Failed to stat() the root directory: %m");
- return EXIT_FAILURE;
+ r = log_error_errno(errno, "Failed to stat() the root directory: %m");
+ goto finish;
}
/* Virtual root devices don't need an fsck */
- if (major(st.st_dev) == 0)
- return EXIT_SUCCESS;
+ if (major(st.st_dev) == 0) {
+ log_debug("Root directory is virtual or btrfs, skipping check.");
+ r = 0;
+ goto finish;
+ }
/* check if we are already writable */
times[0] = st.st_atim;
times[1] = st.st_mtim;
+
if (utimensat(AT_FDCWD, "/", times, 0) == 0) {
log_info("Root directory is writable, skipping check.");
- return EXIT_SUCCESS;
+ r = 0;
+ goto finish;
}
- udev_device = udev_device_new_from_devnum(udev, 'b', st.st_dev);
- if (!udev_device) {
- log_error("Failed to detect root device.");
- return EXIT_FAILURE;
+ r = sd_device_new_from_devnum(&dev, 'b', st.st_dev);
+ if (r < 0) {
+ log_error_errno(r, "Failed to detect root device: %m");
+ goto finish;
}
- device = udev_device_get_devnode(udev_device);
- if (!device) {
- log_error("Failed to detect device node of root directory.");
- return EXIT_FAILURE;
+ r = sd_device_get_devname(dev, &device);
+ if (r < 0) {
+ log_error_errno(r, "Failed to detect device node of root directory: %m");
+ goto finish;
}
root_directory = true;
}
- type = udev_device_get_property_value(udev_device, "ID_FS_TYPE");
- if (type) {
+ r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type);
+ if (r >= 0) {
r = fsck_exists(type);
if (r == -ENOENT) {
log_info("fsck.%s doesn't exist, not checking file system on %s", type, device);
- return EXIT_SUCCESS;
+ r = 0;
+ goto finish;
} else if (r < 0)
- log_warning_errno(r, "fsck.%s cannot be used for %s: %m", type, device);
+ log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s: %m", type, device);
}
- if (arg_show_progress)
+ if (arg_show_progress) {
if (pipe(progress_pipe) < 0) {
- log_error_errno(errno, "pipe(): %m");
- return EXIT_FAILURE;
+ r = log_error_errno(errno, "pipe(): %m");
+ goto finish;
}
+ }
- cmdline[i++] = "/sbin/fsck";
- cmdline[i++] = arg_repair;
- cmdline[i++] = "-T";
+ pid = fork();
+ if (pid < 0) {
+ r = log_error_errno(errno, "fork(): %m");
+ goto finish;
+ }
+ if (pid == 0) {
+ char dash_c[sizeof("-C")-1 + DECIMAL_STR_MAX(int) + 1];
+ int progress_socket = -1;
+ const char *cmdline[9];
+ int i = 0;
- /*
- * Since util-linux v2.25 fsck uses /run/fsck/<diskname>.lock files.
- * The previous versions use flock for the device and conflict with
- * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5
- */
- cmdline[i++] = "-l";
+ /* Child */
- if (!root_directory)
- cmdline[i++] = "-M";
+ reset_all_signal_handlers();
+ reset_signal_mask();
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
- if (arg_force)
- cmdline[i++] = "-f";
+ /* Close the reading side of the progress pipe */
+ progress_pipe[0] = safe_close(progress_pipe[0]);
- if (progress_pipe[1] >= 0) {
- xsprintf(dash_c, "-C%i", progress_pipe[1]);
- cmdline[i++] = dash_c;
- }
+ /* Try to connect to a progress management daemon, if there is one */
+ progress_socket = fsck_progress_socket();
+ if (progress_socket >= 0) {
+ /* If this worked we close the progress pipe early, and just use the socket */
+ progress_pipe[1] = safe_close(progress_pipe[1]);
+ xsprintf(dash_c, "-C%i", progress_socket);
+ } else if (progress_pipe[1] >= 0) {
+ /* Otherwise if we have the progress pipe to our own local handle, we use it */
+ xsprintf(dash_c, "-C%i", progress_pipe[1]);
+ } else
+ dash_c[0] = 0;
- cmdline[i++] = device;
- cmdline[i++] = NULL;
+ cmdline[i++] = "/sbin/fsck";
+ cmdline[i++] = arg_repair;
+ cmdline[i++] = "-T";
+
+ /*
+ * Since util-linux v2.25 fsck uses /run/fsck/<diskname>.lock files.
+ * The previous versions use flock for the device and conflict with
+ * udevd, see https://bugs.freedesktop.org/show_bug.cgi?id=79576#c5
+ */
+ cmdline[i++] = "-l";
+
+ if (!root_directory)
+ cmdline[i++] = "-M";
+
+ if (arg_force)
+ cmdline[i++] = "-f";
+
+ if (!isempty(dash_c))
+ cmdline[i++] = dash_c;
+
+ cmdline[i++] = device;
+ cmdline[i++] = NULL;
- pid = fork();
- if (pid < 0) {
- log_error_errno(errno, "fork(): %m");
- goto finish;
- } else if (pid == 0) {
- /* Child */
- if (progress_pipe[0] >= 0)
- safe_close(progress_pipe[0]);
execv(cmdline[0], (char**) cmdline);
- _exit(8); /* Operational error */
+ _exit(FSCK_OPERATIONAL_ERROR);
}
progress_pipe[1] = safe_close(progress_pipe[1]);
+ (void) process_progress(progress_pipe[0]);
+ progress_pipe[0] = -1;
- if (progress_pipe[0] >= 0) {
- process_progress(progress_pipe[0]);
- progress_pipe[0] = -1;
- }
-
- q = wait_for_terminate(pid, &status);
- if (q < 0) {
- log_error_errno(q, "waitid(): %m");
+ r = wait_for_terminate(pid, &status);
+ if (r < 0) {
+ log_error_errno(r, "waitid(): %m");
goto finish;
}
@@ -377,25 +459,25 @@ int main(int argc, char *argv[]) {
else
log_error("fsck failed due to unknown reason.");
- if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory)
+ r = -EINVAL;
+
+ if (status.si_code == CLD_EXITED && (status.si_status & FSCK_SYSTEM_SHOULD_REBOOT) && root_directory)
/* System should be rebooted. */
start_target(SPECIAL_REBOOT_TARGET);
- else if (status.si_code == CLD_EXITED && (status.si_status & 6))
+ else if (status.si_code == CLD_EXITED && (status.si_status & (FSCK_SYSTEM_SHOULD_REBOOT | FSCK_ERRORS_LEFT_UNCORRECTED)))
/* Some other problem */
start_target(SPECIAL_EMERGENCY_TARGET);
else {
- r = EXIT_SUCCESS;
log_warning("Ignoring error.");
+ r = 0;
}
} else
- r = EXIT_SUCCESS;
+ r = 0;
- if (status.si_code == CLD_EXITED && (status.si_status & 1))
- touch("/run/systemd/quotacheck");
+ if (status.si_code == CLD_EXITED && (status.si_status & FSCK_ERROR_CORRECTED))
+ (void) touch("/run/systemd/quotacheck");
finish:
- safe_close_pair(progress_pipe);
-
- return r;
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 5662b5fde1..a88b68e2c0 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -33,7 +33,6 @@
#include "mount-setup.h"
#include "special.h"
#include "mkdir.h"
-#include "fileio.h"
#include "generator.h"
#include "strv.h"
#include "virt.h"
@@ -56,7 +55,7 @@ static int add_swap(
_cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
_cleanup_fclose_ FILE *f = NULL;
- int r, pri = -1;
+ int r;
assert(what);
assert(me);
@@ -71,13 +70,9 @@ static int add_swap(
return 0;
}
- r = fstab_find_pri(me->mnt_opts, &pri);
+ r = unit_name_from_path(what, ".swap", &name);
if (r < 0)
- return log_error_errno(r, "Failed to parse priority: %m");
-
- name = unit_name_from_path(what, ".swap");
- if (!name)
- return log_oom();
+ return log_error_errno(r, "Failed to generate unit name: %m");
unit = strjoin(arg_dest, "/", name, NULL);
if (!unit)
@@ -101,11 +96,6 @@ static int add_swap(
"What=%s\n",
what);
- /* Note that we currently pass the priority field twice, once
- * in Priority=, and once in Options= */
- if (pri >= 0)
- fprintf(f, "Priority=%i\n", pri);
-
if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
fprintf(f, "Options=%s\n", me->mnt_opts);
@@ -146,6 +136,88 @@ static bool mount_in_initrd(struct mntent *me) {
streq(me->mnt_dir, "/usr");
}
+static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
+ _cleanup_free_ char *timeout = NULL;
+ char timespan[FORMAT_TIMESPAN_MAX];
+ usec_t u;
+ int r;
+
+ r = fstab_filter_options(opts, "x-systemd.idle-timeout\0", NULL, &timeout, NULL);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to parse options: %m");
+ if (r == 0)
+ return 0;
+
+ r = parse_sec(timeout, &u);
+ if (r < 0) {
+ log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
+ return 0;
+ }
+
+ fprintf(f, "TimeoutIdleSec=%s\n", format_timespan(timespan, sizeof(timespan), u, 0));
+
+ return 0;
+}
+
+static int write_requires_after(FILE *f, const char *opts) {
+ _cleanup_strv_free_ char **names = NULL, **units = NULL;
+ _cleanup_free_ char *res = NULL;
+ char **s;
+ int r;
+
+ assert(f);
+ assert(opts);
+
+ r = fstab_extract_values(opts, "x-systemd.requires", &names);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to parse options: %m");
+ if (r == 0)
+ return 0;
+
+ STRV_FOREACH(s, names) {
+ char *x;
+
+ r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
+ r = strv_consume(&units, x);
+ if (r < 0)
+ return log_oom();
+ }
+
+ if (units) {
+ res = strv_join(units, " ");
+ if (!res)
+ return log_oom();
+ fprintf(f, "After=%1$s\nRequires=%1$s\n", res);
+ }
+
+ return 0;
+}
+
+static int write_requires_mounts_for(FILE *f, const char *opts) {
+ _cleanup_strv_free_ char **paths = NULL;
+ _cleanup_free_ char *res = NULL;
+ int r;
+
+ assert(f);
+ assert(opts);
+
+ r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to parse options: %m");
+ if (r == 0)
+ return 0;
+
+ res = strv_join(paths, " ");
+ if (!res)
+ return log_oom();
+
+ fprintf(f, "RequiresMountsFor=%s\n", res);
+
+ return 0;
+}
+
static int add_mount(
const char *what,
const char *where,
@@ -183,15 +255,19 @@ static int add_mount(
return 0;
if (path_equal(where, "/")) {
- /* The root disk is not an option */
- automount = false;
- noauto = false;
- nofail = false;
+ if (noauto)
+ log_warning("Ignoring \"noauto\" for root device");
+ if (nofail)
+ log_warning("Ignoring \"nofail\" for root device");
+ if (automount)
+ log_warning("Ignoring automount option for root device");
+
+ noauto = nofail = automount = false;
}
- name = unit_name_from_path(where, ".mount");
- if (!name)
- return log_oom();
+ r = unit_name_from_path(where, ".mount", &name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
unit = strjoin(arg_dest, "/", name, NULL);
if (!unit)
@@ -216,6 +292,15 @@ static int add_mount(
if (post && !noauto && !nofail && !automount)
fprintf(f, "Before=%s\n", post);
+ if (!automount && opts) {
+ r = write_requires_after(f, opts);
+ if (r < 0)
+ return r;
+ r = write_requires_mounts_for(f, opts);
+ if (r < 0)
+ return r;
+ }
+
if (passno != 0) {
r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
if (r < 0)
@@ -240,9 +325,9 @@ static int add_mount(
if (!isempty(filtered) && !streq(filtered, "defaults"))
fprintf(f, "Options=%s\n", filtered);
- fflush(f);
- if (ferror(f))
- return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit);
if (!noauto && post) {
lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
@@ -255,9 +340,9 @@ static int add_mount(
}
if (automount) {
- automount_name = unit_name_from_path(where, ".automount");
- if (!automount_name)
- return log_oom();
+ r = unit_name_from_path(where, ".automount", &automount_name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
if (!automount_unit)
@@ -280,14 +365,27 @@ static int add_mount(
"Before=%s\n",
post);
+ if (opts) {
+ r = write_requires_after(f, opts);
+ if (r < 0)
+ return r;
+ r = write_requires_mounts_for(f, opts);
+ if (r < 0)
+ return r;
+ }
+
fprintf(f,
"[Automount]\n"
"Where=%s\n",
where);
- fflush(f);
- if (ferror(f))
- return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
+ r = write_idle_timeout(f, where, opts);
+ if (r < 0)
+ return r;
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
free(lnk);
lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
@@ -385,7 +483,7 @@ static int parse_fstab(bool initrd) {
return r;
}
-static int add_root_mount(void) {
+static int add_sysroot_mount(void) {
_cleanup_free_ char *what = NULL;
const char *opts;
@@ -395,10 +493,8 @@ static int add_root_mount(void) {
}
what = fstab_node_to_udev_node(arg_root_what);
- if (!path_is_absolute(what)) {
- log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
- return 0;
- }
+ if (!what)
+ return log_oom();
if (!arg_root_options)
opts = arg_root_rw > 0 ? "rw" : "ro";
@@ -413,7 +509,7 @@ static int add_root_mount(void) {
"/sysroot",
arg_root_fstype,
opts,
- 1,
+ is_device_path(what) ? 1 : 0,
false,
false,
false,
@@ -421,7 +517,7 @@ static int add_root_mount(void) {
"/proc/cmdline");
}
-static int add_usr_mount(void) {
+static int add_sysroot_usr_mount(void) {
_cleanup_free_ char *what = NULL;
const char *opts;
@@ -568,9 +664,9 @@ int main(int argc, char *argv[]) {
/* Always honour root= and usr= in the kernel command line if we are in an initrd */
if (in_initrd()) {
- r = add_root_mount();
+ r = add_sysroot_mount();
if (r == 0)
- r = add_usr_mount();
+ r = add_sysroot_usr_mount();
}
/* Honour /etc/fstab only when that's enabled */
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index f8f5fb30c2..d23caab44a 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -31,6 +31,8 @@
#include "virt.h"
#include "fileio.h"
#include "path-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
static const char *arg_dest = "/tmp";
@@ -48,13 +50,11 @@ static int add_symlink(const char *fservice, const char *tservice) {
r = symlink(from, to);
if (r < 0) {
+ /* In case console=hvc0 is passed this will very likely result in EEXIST */
if (errno == EEXIST)
- /* In case console=hvc0 is passed this will very likely result in EEXIST */
return 0;
- else {
- log_error_errno(errno, "Failed to create symlink %s: %m", to);
- return -errno;
- }
+
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
}
return 0;
@@ -62,28 +62,30 @@ static int add_symlink(const char *fservice, const char *tservice) {
static int add_serial_getty(const char *tty) {
_cleanup_free_ char *n = NULL;
+ int r;
assert(tty);
log_debug("Automatically adding serial getty for /dev/%s.", tty);
- n = unit_name_from_path_instance("serial-getty", tty, ".service");
- if (!n)
- return log_oom();
+ r = unit_name_from_path_instance("serial-getty", tty, ".service", &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate service name: %m");
return add_symlink("serial-getty@.service", n);
}
static int add_container_getty(const char *tty) {
_cleanup_free_ char *n = NULL;
+ int r;
assert(tty);
log_debug("Automatically adding container getty for /dev/pts/%s.", tty);
- n = unit_name_from_path_instance("container-getty", tty, ".service");
- if (!n)
- return log_oom();
+ r = unit_name_from_path_instance("container-getty", tty, ".service", &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate service name: %m");
return add_symlink("container-getty@.service", n);
}
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 5c58b58f8a..b46e160888 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -21,8 +21,6 @@
#include <unistd.h>
#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
#include <sys/statfs.h>
#include <blkid/blkid.h>
@@ -51,14 +49,15 @@ static bool arg_root_rw = false;
static int add_swap(const char *path) {
_cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
_cleanup_fclose_ FILE *f = NULL;
+ int r;
assert(path);
log_debug("Adding swap: %s", path);
- name = unit_name_from_path(path, ".swap");
- if (!name)
- return log_oom();
+ r = unit_name_from_path(path, ".swap", &name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
unit = strjoin(arg_dest, "/", name, NULL);
if (!unit)
@@ -102,17 +101,17 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
assert(what);
assert(device);
- d = unit_name_from_path(what, ".device");
- if (!d)
- return log_oom();
+ r = unit_name_from_path(what, ".device", &d);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
e = unit_name_escape(id);
if (!e)
return log_oom();
- n = unit_name_build("systemd-cryptsetup", e, ".service");
- if (!n)
- return log_oom();
+ r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
p = strjoin(arg_dest, "/", n, NULL);
if (!p)
@@ -226,9 +225,9 @@ static int add_mount(
fstype = NULL;
}
- unit = unit_name_from_path(where, ".mount");
- if (!unit)
- return log_oom();
+ r = unit_name_from_path(where, ".mount", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
p = strjoin(arg_dest, "/", unit, NULL);
if (!p)
@@ -290,7 +289,7 @@ static int probe_and_add_mount(
const char *post) {
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
- const char *fstype;
+ const char *fstype = NULL;
int r;
assert(id);
@@ -298,7 +297,7 @@ static int probe_and_add_mount(
assert(where);
assert(description);
- if (path_is_mount_point(where, true) <= 0 &&
+ if (path_is_mount_point(where, AT_SYMLINK_FOLLOW) <= 0 &&
dir_is_empty(where) <= 0) {
log_debug("%s already populated, ignoring.", where);
return 0;
@@ -323,14 +322,11 @@ static int probe_and_add_mount(
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) /* no result or uncertain */
return 0;
- else if (r != 0) {
- if (errno == 0)
- errno = EIO;
- log_error_errno(errno, "Failed to probe %s: %m", what);
- return -errno;
- }
+ else if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
- blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
+ /* add_mount is OK with fstype being NULL. */
+ (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
return add_mount(
id,
@@ -351,7 +347,7 @@ static int enumerate_partitions(dev_t devnum) {
_cleanup_free_ char *home = NULL, *srv = NULL;
struct udev_list_entry *first, *item;
struct udev_device *parent = NULL;
- const char *node, *pttype, *devtype;
+ const char *name, *node, *pttype, *devtype;
int home_nr = -1, srv_nr = -1;
bool home_rw = true, srv_rw = true;
blkid_partlist pl;
@@ -366,33 +362,42 @@ static int enumerate_partitions(dev_t devnum) {
if (!d)
return log_oom();
+ name = udev_device_get_devnode(d);
+ if (!name)
+ name = udev_device_get_syspath(d);
+ if (!name) {
+ log_debug("Device %u:%u does not have a name, ignoring.",
+ major(devnum), minor(devnum));
+ return 0;
+ }
+
parent = udev_device_get_parent(d);
if (!parent) {
- log_debug("Not a partitioned device, ignoring.");
+ log_debug("%s: not a partitioned device, ignoring.", name);
return 0;
}
/* Does it have a devtype? */
devtype = udev_device_get_devtype(parent);
if (!devtype) {
- log_debug("Parent doesn't have a device type, ignoring.");
+ log_debug("%s: parent doesn't have a device type, ignoring.", name);
return 0;
}
/* Is this a disk or a partition? We only care for disks... */
if (!streq(devtype, "disk")) {
- log_debug("Parent isn't a raw disk, ignoring.");
+ log_debug("%s: parent isn't a raw disk, ignoring.", name);
return 0;
}
/* Does it have a device node? */
node = udev_device_get_devnode(parent);
if (!node) {
- log_debug("Parent device does not have device node, ignoring.");
+ log_debug("%s: parent device does not have device node, ignoring.", name);
return 0;
}
- log_debug("Root device %s.", node);
+ log_debug("%s: root device %s.", name, node);
pn = udev_device_get_devnum(parent);
if (major(pn) == 0)
@@ -404,8 +409,7 @@ static int enumerate_partitions(dev_t devnum) {
if (errno == 0)
return log_oom();
- log_error_errno(errno, "Failed allocate prober: %m");
- return -errno;
+ return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
}
blkid_probe_enable_partitions(b, 1);
@@ -415,25 +419,18 @@ static int enumerate_partitions(dev_t devnum) {
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) /* no result or uncertain */
return 0;
- else if (r != 0) {
- if (errno == 0)
- errno = EIO;
- log_error_errno(errno, "Failed to probe %s: %m", node);
- return -errno;
- }
+ else if (r != 0)
+ return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
errno = 0;
r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
- if (r != 0) {
- if (errno == 0)
- errno = EIO;
- log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
- return -errno;
- }
+ if (r != 0)
+ return log_error_errno(errno ?: EIO,
+ "%s: failed to determine partition table type: %m", node);
/* We only do this all for GPT... */
if (!streq_ptr(pttype, "gpt")) {
- log_debug("Not a GPT partition table, ignoring.");
+ log_debug("%s: not a GPT partition table, ignoring.", node);
return 0;
}
@@ -443,8 +440,7 @@ static int enumerate_partitions(dev_t devnum) {
if (errno == 0)
return log_oom();
- log_error_errno(errno, "Failed to list partitions of %s: %m", node);
- return -errno;
+ return log_error_errno(errno, "%s: failed to list partitions: %m", node);
}
e = udev_enumerate_new(udev);
@@ -461,7 +457,7 @@ static int enumerate_partitions(dev_t devnum) {
r = udev_enumerate_scan_devices(e);
if (r < 0)
- return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
+ return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
@@ -516,7 +512,7 @@ static int enumerate_partitions(dev_t devnum) {
if (sd_id128_equal(type_id, GPT_SWAP)) {
if (flags & GPT_FLAG_READ_ONLY) {
- log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
+ log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
continue;
}
@@ -548,7 +544,7 @@ static int enumerate_partitions(dev_t devnum) {
srv_rw = !(flags & GPT_FLAG_READ_ONLY),
free(srv);
- srv = strdup(node);
+ srv = strdup(subnode);
if (!srv)
return log_oom();
}
@@ -602,7 +598,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
r = parse_boolean(value);
if (r < 0)
- log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
+ log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
else
arg_enabled = r;
@@ -663,8 +659,13 @@ static int add_mounts(void) {
if (r < 0)
return log_error_errno(r, "Failed to determine block device of root file system: %m");
else if (r == 0) {
- log_debug("Root file system not on a (single) block device.");
- return 0;
+ r = get_block_device("/usr", &devno);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
+ else if (r == 0) {
+ log_debug("Neither root nor /usr file system are on a (single) block device.");
+ return 0;
+ }
}
return enumerate_partitions(devno);
diff --git a/src/gudev/.gitignore b/src/gudev/.gitignore
deleted file mode 100644
index 4577903c40..0000000000
--- a/src/gudev/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-gudev-1.0.pc
-gudevenumtypes.c
-gudevenumtypes.h
-gudevmarshal.c
-gudevmarshal.h
-GUdev-1.0.gir
-GUdev-1.0.typelib
diff --git a/src/gudev/gjs-example.js b/src/gudev/gjs-example.js
deleted file mode 100755
index 5586fd6a61..0000000000
--- a/src/gudev/gjs-example.js
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env gjs-console
-
-// This currently depends on the following patches to gjs
-//
-// http://bugzilla.gnome.org/show_bug.cgi?id=584558
-// http://bugzilla.gnome.org/show_bug.cgi?id=584560
-// http://bugzilla.gnome.org/show_bug.cgi?id=584568
-
-const GUdev = imports.gi.GUdev;
-const Mainloop = imports.mainloop;
-
-function print_device (device) {
- print (" subsystem: " + device.get_subsystem ());
- print (" devtype: " + device.get_devtype ());
- print (" name: " + device.get_name ());
- print (" number: " + device.get_number ());
- print (" sysfs_path: " + device.get_sysfs_path ());
- print (" driver: " + device.get_driver ());
- print (" action: " + device.get_action ());
- print (" seqnum: " + device.get_seqnum ());
- print (" device type: " + device.get_device_type ());
- print (" device number: " + device.get_device_number ());
- print (" device file: " + device.get_device_file ());
- print (" device file symlinks: " + device.get_device_file_symlinks ());
- print (" foo: " + device.get_sysfs_attr_as_strv ("stat"));
- var keys = device.get_property_keys ();
- for (var n = 0; n < keys.length; n++) {
- print (" " + keys[n] + "=" + device.get_property (keys[n]));
- }
-}
-
-function on_uevent (client, action, device) {
- print ("action " + action + " on device " + device.get_sysfs_path());
- print_device (device);
- print ("");
-}
-
-var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]});
-client.connect ("uevent", on_uevent);
-
-var block_devices = client.query_by_subsystem ("block");
-for (var n = 0; n < block_devices.length; n++) {
- print ("block device: " + block_devices[n].get_device_file ());
-}
-
-var d;
-
-d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810);
-if (d == null) {
- print ("query_by_device_number 0x810 -> null");
-} else {
- print ("query_by_device_number 0x810 -> " + d.get_device_file ());
- var dd = d.get_parent_with_subsystem ("usb", null);
- print_device (dd);
- print ("--------------------------------------------------------------------------");
- while (d != null) {
- print_device (d);
- print ("");
- d = d.get_parent ();
- }
-}
-
-d = client.query_by_sysfs_path ("/sys/block/sda/sda1");
-print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ());
-
-d = client.query_by_subsystem_and_name ("block", "sda2");
-print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ());
-
-d = client.query_by_device_file ("/dev/sda");
-print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ());
-
-d = client.query_by_device_file ("/dev/block/8:0");
-print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ());
-
-Mainloop.run('udev-example');
diff --git a/src/gudev/gudev-1.0.pc.in b/src/gudev/gudev-1.0.pc.in
deleted file mode 100644
index 058262d767..0000000000
--- a/src/gudev/gudev-1.0.pc.in
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: gudev-1.0
-Description: GObject bindings for libudev
-Version: @VERSION@
-Requires: glib-2.0, gobject-2.0
-Libs: -L${libdir} -lgudev-1.0
-Cflags: -I${includedir}/gudev-1.0
diff --git a/src/gudev/gudev.h b/src/gudev/gudev.h
deleted file mode 100644
index 1dc42b11b7..0000000000
--- a/src/gudev/gudev.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef __G_UDEV_H__
-#define __G_UDEV_H__
-
-#define _GUDEV_INSIDE_GUDEV_H
-#include <gudev/gudevenums.h>
-#include <gudev/gudevenumtypes.h>
-#include <gudev/gudevtypes.h>
-#include <gudev/gudevclient.h>
-#include <gudev/gudevdevice.h>
-#include <gudev/gudevenumerator.h>
-#undef _GUDEV_INSIDE_GUDEV_H
-
-#endif /* __G_UDEV_H__ */
diff --git a/src/gudev/gudevclient.c b/src/gudev/gudevclient.c
deleted file mode 100644
index 1eec758935..0000000000
--- a/src/gudev/gudevclient.c
+++ /dev/null
@@ -1,532 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gudevclient.h"
-#include "gudevdevice.h"
-#include "gudevmarshal.h"
-#include "gudevprivate.h"
-
-/**
- * SECTION:gudevclient
- * @short_description: Query devices and listen to uevents
- *
- * #GUdevClient is used to query information about devices on a Linux
- * system from the Linux kernel and the udev device
- * manager.
- *
- * Device information is retrieved from the kernel (through the
- * <literal>sysfs</literal> filesystem) and the udev daemon (through a
- * <literal>tmpfs</literal> filesystem) and presented through
- * #GUdevDevice objects. This means that no blocking IO ever happens
- * (in both cases, we are essentially just reading data from kernel
- * memory) and as such there are no asynchronous versions of the
- * provided methods.
- *
- * To get #GUdevDevice objects, use
- * g_udev_client_query_by_subsystem(),
- * g_udev_client_query_by_device_number(),
- * g_udev_client_query_by_device_file(),
- * g_udev_client_query_by_sysfs_path(),
- * g_udev_client_query_by_subsystem_and_name()
- * or the #GUdevEnumerator type.
- *
- * To listen to uevents, connect to the #GUdevClient::uevent signal.
- */
-
-struct _GUdevClientPrivate
-{
- GSource *watch_source;
- struct udev *udev;
- struct udev_monitor *monitor;
-
- gchar **subsystems;
-};
-
-enum
-{
- PROP_0,
- PROP_SUBSYSTEMS,
-};
-
-enum
-{
- UEVENT_SIGNAL,
- LAST_SIGNAL,
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT)
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-monitor_event (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
- GUdevClient *client = (GUdevClient *) data;
- GUdevDevice *device;
- struct udev_device *udevice;
-
- if (client->priv->monitor == NULL)
- goto out;
- udevice = udev_monitor_receive_device (client->priv->monitor);
- if (udevice == NULL)
- goto out;
-
- device = _g_udev_device_new (udevice);
- udev_device_unref (udevice);
- g_signal_emit (client,
- signals[UEVENT_SIGNAL],
- 0,
- g_udev_device_get_action (device),
- device);
- g_object_unref (device);
-
- out:
- return TRUE;
-}
-
-static void
-g_udev_client_finalize (GObject *object)
-{
- GUdevClient *client = G_UDEV_CLIENT (object);
-
- if (client->priv->watch_source != NULL)
- {
- g_source_destroy (client->priv->watch_source);
- client->priv->watch_source = NULL;
- }
-
- if (client->priv->monitor != NULL)
- {
- udev_monitor_unref (client->priv->monitor);
- client->priv->monitor = NULL;
- }
-
- if (client->priv->udev != NULL)
- {
- udev_unref (client->priv->udev);
- client->priv->udev = NULL;
- }
-
- g_strfreev (client->priv->subsystems);
-
- if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL)
- G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object);
-}
-
-static void
-g_udev_client_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GUdevClient *client = G_UDEV_CLIENT (object);
-
- switch (prop_id)
- {
- case PROP_SUBSYSTEMS:
- if (client->priv->subsystems != NULL)
- g_strfreev (client->priv->subsystems);
- client->priv->subsystems = g_strdupv (g_value_get_boxed (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-g_udev_client_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GUdevClient *client = G_UDEV_CLIENT (object);
-
- switch (prop_id)
- {
- case PROP_SUBSYSTEMS:
- g_value_set_boxed (value, client->priv->subsystems);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-g_udev_client_constructed (GObject *object)
-{
- GUdevClient *client = G_UDEV_CLIENT (object);
- GIOChannel *channel;
- guint n;
-
- client->priv->udev = udev_new ();
-
- /* connect to event source */
- client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev");
-
- //g_debug ("ss = %p", client->priv->subsystems);
-
- if (client->priv->subsystems != NULL)
- {
- /* install subsystem filters to only wake up for certain events */
- for (n = 0; client->priv->subsystems[n] != NULL; n++)
- {
- gchar *subsystem;
- gchar *devtype;
- gchar *s;
-
- subsystem = g_strdup (client->priv->subsystems[n]);
- devtype = NULL;
-
- //g_debug ("s = '%s'", subsystem);
-
- s = strstr (subsystem, "/");
- if (s != NULL)
- {
- devtype = s + 1;
- *s = '\0';
- }
-
- if (client->priv->monitor != NULL)
- udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype);
-
- g_free (subsystem);
- }
-
- /* listen to events, and buffer them */
- if (client->priv->monitor != NULL)
- {
- udev_monitor_enable_receiving (client->priv->monitor);
- channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor));
- client->priv->watch_source = g_io_create_watch (channel, G_IO_IN);
- g_io_channel_unref (channel);
- g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL);
- g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ());
- g_source_unref (client->priv->watch_source);
- }
- else
- {
- client->priv->watch_source = NULL;
- }
- }
-
- if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL)
- G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object);
-}
-
-
-static void
-g_udev_client_class_init (GUdevClientClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- gobject_class->constructed = g_udev_client_constructed;
- gobject_class->set_property = g_udev_client_set_property;
- gobject_class->get_property = g_udev_client_get_property;
- gobject_class->finalize = g_udev_client_finalize;
-
- /**
- * GUdevClient:subsystems:
- *
- * The subsystems to listen for uevents on.
- *
- * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use
- * "subsystem/devtype". For example, to only listen for uevents
- * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use
- * "usb/usb_interface".
- *
- * If this property is %NULL, then no events will be reported. If
- * it's the empty array, events from all subsystems will be
- * reported.
- */
- g_object_class_install_property (gobject_class,
- PROP_SUBSYSTEMS,
- g_param_spec_boxed ("subsystems",
- "The subsystems to listen for changes on",
- "The subsystems to listen for changes on",
- G_TYPE_STRV,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE));
-
- /**
- * GUdevClient::uevent:
- * @client: The #GUdevClient receiving the event.
- * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc.
- * @device: Details about the #GUdevDevice the event is for.
- *
- * Emitted when @client receives an uevent.
- *
- * This signal is emitted in the
- * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
- * of the thread that @client was created in.
- */
- signals[UEVENT_SIGNAL] = g_signal_new ("uevent",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GUdevClientClass, uevent),
- NULL,
- NULL,
- g_udev_marshal_VOID__STRING_OBJECT,
- G_TYPE_NONE,
- 2,
- G_TYPE_STRING,
- G_UDEV_TYPE_DEVICE);
-
- g_type_class_add_private (klass, sizeof (GUdevClientPrivate));
-}
-
-static void
-g_udev_client_init (GUdevClient *client)
-{
- client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client,
- G_UDEV_TYPE_CLIENT,
- GUdevClientPrivate);
-}
-
-/**
- * g_udev_client_new:
- * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter.
- *
- * Constructs a #GUdevClient object that can be used to query
- * information about devices. Connect to the #GUdevClient::uevent
- * signal to listen for uevents. Note that signals are emitted in the
- * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
- * of the thread that you call this constructor from.
- *
- * Returns: A new #GUdevClient object. Free with g_object_unref().
- */
-GUdevClient *
-g_udev_client_new (const gchar * const *subsystems)
-{
- return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL));
-}
-
-/**
- * g_udev_client_query_by_subsystem:
- * @client: A #GUdevClient.
- * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices.
- *
- * Gets all devices belonging to @subsystem.
- *
- * Returns: (nullable) (element-type GUdevDevice) (transfer full): A
- * list of #GUdevDevice objects. The caller should free the result by
- * using g_object_unref() on each element in the list and then
- * g_list_free() on the list.
- */
-GList *
-g_udev_client_query_by_subsystem (GUdevClient *client,
- const gchar *subsystem)
-{
- struct udev_enumerate *enumerate;
- struct udev_list_entry *l, *devices;
- GList *ret;
-
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
-
- ret = NULL;
-
- /* prepare a device scan */
- enumerate = udev_enumerate_new (client->priv->udev);
-
- /* filter for subsystem */
- if (subsystem != NULL)
- udev_enumerate_add_match_subsystem (enumerate, subsystem);
- /* retrieve the list */
- udev_enumerate_scan_devices (enumerate);
-
- /* add devices to the list */
- devices = udev_enumerate_get_list_entry (enumerate);
- for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
- {
- struct udev_device *udevice;
- GUdevDevice *device;
-
- udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate),
- udev_list_entry_get_name (l));
- if (udevice == NULL)
- continue;
- device = _g_udev_device_new (udevice);
- udev_device_unref (udevice);
- ret = g_list_prepend (ret, device);
- }
- udev_enumerate_unref (enumerate);
-
- ret = g_list_reverse (ret);
-
- return ret;
-}
-
-/**
- * g_udev_client_query_by_device_number:
- * @client: A #GUdevClient.
- * @type: A value from the #GUdevDeviceType enumeration.
- * @number: A device number.
- *
- * Looks up a device for a type and device number.
- *
- * Returns: (nullable) (transfer full): A #GUdevDevice object or %NULL
- * if the device was not found. Free with g_object_unref().
- */
-GUdevDevice *
-g_udev_client_query_by_device_number (GUdevClient *client,
- GUdevDeviceType type,
- GUdevDeviceNumber number)
-{
- struct udev_device *udevice;
- GUdevDevice *device;
-
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
-
- device = NULL;
- udevice = udev_device_new_from_devnum (client->priv->udev, type, number);
-
- if (udevice == NULL)
- goto out;
-
- device = _g_udev_device_new (udevice);
- udev_device_unref (udevice);
-
- out:
- return device;
-}
-
-/**
- * g_udev_client_query_by_device_file:
- * @client: A #GUdevClient.
- * @device_file: A device file.
- *
- * Looks up a device for a device file.
- *
- * Returns: (nullable) (transfer full): A #GUdevDevice object or %NULL
- * if the device was not found. Free with g_object_unref().
- */
-GUdevDevice *
-g_udev_client_query_by_device_file (GUdevClient *client,
- const gchar *device_file)
-{
- struct stat stat_buf;
- GUdevDevice *device;
-
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
- g_return_val_if_fail (device_file != NULL, NULL);
-
- device = NULL;
-
- if (stat (device_file, &stat_buf) != 0)
- goto out;
-
- if (stat_buf.st_rdev == 0)
- goto out;
-
- if (S_ISBLK (stat_buf.st_mode))
- device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev);
- else if (S_ISCHR (stat_buf.st_mode))
- device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev);
-
- out:
- return device;
-}
-
-/**
- * g_udev_client_query_by_sysfs_path:
- * @client: A #GUdevClient.
- * @sysfs_path: A sysfs path.
- *
- * Looks up a device for a sysfs path.
- *
- * Returns: (nullable) (transfer full): A #GUdevDevice object or %NULL
- * if the device was not found. Free with g_object_unref().
- */
-GUdevDevice *
-g_udev_client_query_by_sysfs_path (GUdevClient *client,
- const gchar *sysfs_path)
-{
- struct udev_device *udevice;
- GUdevDevice *device;
-
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
- g_return_val_if_fail (sysfs_path != NULL, NULL);
-
- device = NULL;
- udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path);
- if (udevice == NULL)
- goto out;
-
- device = _g_udev_device_new (udevice);
- udev_device_unref (udevice);
-
- out:
- return device;
-}
-
-/**
- * g_udev_client_query_by_subsystem_and_name:
- * @client: A #GUdevClient.
- * @subsystem: A subsystem name.
- * @name: The name of the device.
- *
- * Looks up a device for a subsystem and name.
- *
- * Returns: (nullable) (transfer full): A #GUdevDevice object or %NULL
- * if the device was not found. Free with g_object_unref().
- */
-GUdevDevice *
-g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
- const gchar *subsystem,
- const gchar *name)
-{
- struct udev_device *udevice;
- GUdevDevice *device;
-
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
- g_return_val_if_fail (subsystem != NULL, NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- device = NULL;
- udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name);
- if (udevice == NULL)
- goto out;
-
- device = _g_udev_device_new (udevice);
- udev_device_unref (udevice);
-
- out:
- return device;
-}
-
-struct udev *
-_g_udev_client_get_udev (GUdevClient *client)
-{
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
- return client->priv->udev;
-}
diff --git a/src/gudev/gudevclient.h b/src/gudev/gudevclient.h
deleted file mode 100644
index 23bfce615f..0000000000
--- a/src/gudev/gudevclient.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_CLIENT_H__
-#define __G_UDEV_CLIENT_H__
-
-#include <gudev/gudevtypes.h>
-
-G_BEGIN_DECLS
-
-#define G_UDEV_TYPE_CLIENT (g_udev_client_get_type ())
-#define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_CLIENT, GUdevClient))
-#define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass))
-#define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_CLIENT))
-#define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_CLIENT))
-#define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_CLIENT, GUdevClientClass))
-
-typedef struct _GUdevClientClass GUdevClientClass;
-typedef struct _GUdevClientPrivate GUdevClientPrivate;
-
-/**
- * GUdevClient:
- *
- * The #GUdevClient struct is opaque and should not be accessed directly.
- */
-struct _GUdevClient
-{
- GObject parent;
-
- /*< private >*/
- GUdevClientPrivate *priv;
-};
-
-/**
- * GUdevClientClass:
- * @parent_class: Parent class.
- * @uevent: Signal class handler for the #GUdevClient::uevent signal.
- *
- * Class structure for #GUdevClient.
- */
-struct _GUdevClientClass
-{
- GObjectClass parent_class;
-
- /* signals */
- void (*uevent) (GUdevClient *client,
- const gchar *action,
- GUdevDevice *device);
-
- /*< private >*/
- /* Padding for future expansion */
- void (*reserved1) (void);
- void (*reserved2) (void);
- void (*reserved3) (void);
- void (*reserved4) (void);
- void (*reserved5) (void);
- void (*reserved6) (void);
- void (*reserved7) (void);
- void (*reserved8) (void);
-};
-
-GType g_udev_client_get_type (void) G_GNUC_CONST;
-GUdevClient *g_udev_client_new (const gchar* const *subsystems);
-GList *g_udev_client_query_by_subsystem (GUdevClient *client,
- const gchar *subsystem);
-GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client,
- GUdevDeviceType type,
- GUdevDeviceNumber number);
-GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client,
- const gchar *device_file);
-GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client,
- const gchar *sysfs_path);
-GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
- const gchar *subsystem,
- const gchar *name);
-
-G_END_DECLS
-
-#endif /* __G_UDEV_CLIENT_H__ */
diff --git a/src/gudev/gudevdevice.c b/src/gudev/gudevdevice.c
deleted file mode 100644
index 7106719111..0000000000
--- a/src/gudev/gudevdevice.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gudevdevice.h"
-#include "gudevprivate.h"
-
-/**
- * SECTION:gudevdevice
- * @short_description: Get information about a device
- *
- * The #GUdevDevice class is used to get information about a specific
- * device. Note that you cannot instantiate a #GUdevDevice object
- * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice
- * objects.
- *
- * To get basic information about a device, use
- * g_udev_device_get_subsystem(), g_udev_device_get_devtype(),
- * g_udev_device_get_name(), g_udev_device_get_number(),
- * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(),
- * g_udev_device_get_action(), g_udev_device_get_seqnum(),
- * g_udev_device_get_device_type(), g_udev_device_get_device_number(),
- * g_udev_device_get_device_file(),
- * g_udev_device_get_device_file_symlinks().
- *
- * To navigate the device tree, use g_udev_device_get_parent() and
- * g_udev_device_get_parent_with_subsystem().
- *
- * To access udev properties for the device, use
- * g_udev_device_get_property_keys(),
- * g_udev_device_has_property(),
- * g_udev_device_get_property(),
- * g_udev_device_get_property_as_int(),
- * g_udev_device_get_property_as_uint64(),
- * g_udev_device_get_property_as_double(),
- * g_udev_device_get_property_as_boolean() and
- * g_udev_device_get_property_as_strv().
- *
- * To access sysfs attributes for the device, use
- * g_udev_device_get_sysfs_attr_keys(),
- * g_udev_device_has_sysfs_attr(),
- * g_udev_device_get_sysfs_attr(),
- * g_udev_device_get_sysfs_attr_as_int(),
- * g_udev_device_get_sysfs_attr_as_uint64(),
- * g_udev_device_get_sysfs_attr_as_double(),
- * g_udev_device_get_sysfs_attr_as_boolean() and
- * g_udev_device_get_sysfs_attr_as_strv().
- *
- * Note that all getters on #GUdevDevice are non-reffing – returned
- * values are owned by the object, should not be freed and are only
- * valid as long as the object is alive.
- *
- * By design, #GUdevDevice will not react to changes for a device – it
- * only contains a snapshot of information when the #GUdevDevice
- * object was created. To work with changes, you typically connect to
- * the #GUdevClient::uevent signal on a #GUdevClient and get a new
- * #GUdevDevice whenever an event happens.
- */
-
-struct _GUdevDevicePrivate
-{
- struct udev_device *udevice;
-
- /* computed ondemand and cached */
- gchar **device_file_symlinks;
- gchar **property_keys;
- gchar **sysfs_attr_keys;
- gchar **tags;
- GHashTable *prop_strvs;
- GHashTable *sysfs_attr_strvs;
-};
-
-G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT)
-
-static void
-g_udev_device_finalize (GObject *object)
-{
- GUdevDevice *device = G_UDEV_DEVICE (object);
-
- g_strfreev (device->priv->device_file_symlinks);
- g_strfreev (device->priv->property_keys);
- g_strfreev (device->priv->sysfs_attr_keys);
- g_strfreev (device->priv->tags);
-
- if (device->priv->udevice != NULL)
- udev_device_unref (device->priv->udevice);
-
- if (device->priv->prop_strvs != NULL)
- g_hash_table_unref (device->priv->prop_strvs);
-
- if (device->priv->sysfs_attr_strvs != NULL)
- g_hash_table_unref (device->priv->sysfs_attr_strvs);
-
- if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL)
- (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object);
-}
-
-static void
-g_udev_device_class_init (GUdevDeviceClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- gobject_class->finalize = g_udev_device_finalize;
-
- g_type_class_add_private (klass, sizeof (GUdevDevicePrivate));
-}
-
-static void
-g_udev_device_init (GUdevDevice *device)
-{
- device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
- G_UDEV_TYPE_DEVICE,
- GUdevDevicePrivate);
-}
-
-
-GUdevDevice *
-_g_udev_device_new (struct udev_device *udevice)
-{
- GUdevDevice *device;
-
- device = G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL));
- device->priv->udevice = udev_device_ref (udevice);
-
- return device;
-}
-
-/**
- * g_udev_device_get_subsystem:
- * @device: A #GUdevDevice.
- *
- * Gets the subsystem for @device.
- *
- * Returns: The subsystem for @device.
- */
-const gchar *
-g_udev_device_get_subsystem (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_subsystem (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_devtype:
- * @device: A #GUdevDevice.
- *
- * Gets the device type for @device.
- *
- * Returns: The devtype for @device.
- */
-const gchar *
-g_udev_device_get_devtype (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_devtype (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_name:
- * @device: A #GUdevDevice.
- *
- * Gets the name of @device, e.g. "sda3".
- *
- * Returns: The name of @device.
- */
-const gchar *
-g_udev_device_get_name (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_sysname (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_number:
- * @device: A #GUdevDevice.
- *
- * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3".
- *
- * Returns: The number of @device.
- */
-const gchar *
-g_udev_device_get_number (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_sysnum (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_sysfs_path:
- * @device: A #GUdevDevice.
- *
- * Gets the sysfs path for @device.
- *
- * Returns: The sysfs path for @device.
- */
-const gchar *
-g_udev_device_get_sysfs_path (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_syspath (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_driver:
- * @device: A #GUdevDevice.
- *
- * Gets the name of the driver used for @device.
- *
- * Returns: (nullable): The name of the driver for @device or %NULL if
- * unknown.
- */
-const gchar *
-g_udev_device_get_driver (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_driver (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_action:
- * @device: A #GUdevDevice.
- *
- * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device.
- *
- * Returns: An action string.
- */
-const gchar *
-g_udev_device_get_action (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_action (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_seqnum:
- * @device: A #GUdevDevice.
- *
- * Gets the most recent sequence number for @device.
- *
- * Returns: A sequence number.
- */
-guint64
-g_udev_device_get_seqnum (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- return udev_device_get_seqnum (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_device_type:
- * @device: A #GUdevDevice.
- *
- * Gets the type of the device file, if any, for @device.
- *
- * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file.
- */
-GUdevDeviceType
-g_udev_device_get_device_type (GUdevDevice *device)
-{
- struct stat stat_buf;
- const gchar *device_file;
- GUdevDeviceType type;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE);
-
- type = G_UDEV_DEVICE_TYPE_NONE;
-
- /* TODO: would be better to have support for this in libudev... */
-
- device_file = g_udev_device_get_device_file (device);
- if (device_file == NULL)
- goto out;
-
- if (stat (device_file, &stat_buf) != 0)
- goto out;
-
- if (S_ISBLK (stat_buf.st_mode))
- type = G_UDEV_DEVICE_TYPE_BLOCK;
- else if (S_ISCHR (stat_buf.st_mode))
- type = G_UDEV_DEVICE_TYPE_CHAR;
-
- out:
- return type;
-}
-
-/**
- * g_udev_device_get_device_number:
- * @device: A #GUdevDevice.
- *
- * Gets the device number, if any, for @device.
- *
- * Returns: The device number for @device or 0 if unknown.
- */
-GUdevDeviceNumber
-g_udev_device_get_device_number (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- return udev_device_get_devnum (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_device_file:
- * @device: A #GUdevDevice.
- *
- * Gets the device file for @device.
- *
- * Returns: (nullable): The device file for @device or %NULL if no
- * device file exists.
- */
-const gchar *
-g_udev_device_get_device_file (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- return udev_device_get_devnode (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_device_file_symlinks:
- * @device: A #GUdevDevice.
- *
- * Gets a list of symlinks (in <literal>/dev</literal>) that points to
- * the device file for @device.
- *
- * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller.
- */
-const gchar * const *
-g_udev_device_get_device_file_symlinks (GUdevDevice *device)
-{
- struct udev_list_entry *l;
- GPtrArray *p;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
-
- if (device->priv->device_file_symlinks != NULL)
- goto out;
-
- p = g_ptr_array_new ();
- for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
- {
- g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
- }
- g_ptr_array_add (p, NULL);
- device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE);
-
- out:
- return (const gchar * const *) device->priv->device_file_symlinks;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
- * g_udev_device_get_parent:
- * @device: A #GUdevDevice.
- *
- * Gets the immediate parent of @device, if any.
- *
- * Returns: (nullable) (transfer full): A #GUdevDevice or %NULL if
- * @device has no parent. Free with g_object_unref().
- */
-GUdevDevice *
-g_udev_device_get_parent (GUdevDevice *device)
-{
- GUdevDevice *ret;
- struct udev_device *udevice;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
-
- ret = NULL;
-
- udevice = udev_device_get_parent (device->priv->udevice);
- if (udevice == NULL)
- goto out;
-
- ret = _g_udev_device_new (udevice);
-
- out:
- return ret;
-}
-
-/**
- * g_udev_device_get_parent_with_subsystem:
- * @device: A #GUdevDevice.
- * @subsystem: The subsystem of the parent to get.
- * @devtype: (allow-none): The devtype of the parent to get or %NULL.
- *
- * Walks up the chain of parents of @device and returns the first
- * device encountered where @subsystem and @devtype matches, if any.
- *
- * Returns: (nullable) (transfer full): A #GUdevDevice or %NULL if
- * @device has no parent with @subsystem and @devtype. Free with
- * g_object_unref().
- */
-GUdevDevice *
-g_udev_device_get_parent_with_subsystem (GUdevDevice *device,
- const gchar *subsystem,
- const gchar *devtype)
-{
- GUdevDevice *ret;
- struct udev_device *udevice;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- g_return_val_if_fail (subsystem != NULL, NULL);
-
- ret = NULL;
-
- udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice,
- subsystem,
- devtype);
- if (udevice == NULL)
- goto out;
-
- ret = _g_udev_device_new (udevice);
-
- out:
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
- * g_udev_device_get_property_keys:
- * @device: A #GUdevDevice.
- *
- * Gets all keys for properties on @device.
- *
- * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller.
- */
-const gchar* const *
-g_udev_device_get_property_keys (GUdevDevice *device)
-{
- struct udev_list_entry *l;
- GPtrArray *p;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
-
- if (device->priv->property_keys != NULL)
- goto out;
-
- p = g_ptr_array_new ();
- for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
- {
- g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
- }
- g_ptr_array_add (p, NULL);
- device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE);
-
- out:
- return (const gchar * const *) device->priv->property_keys;
-}
-
-
-/**
- * g_udev_device_has_property:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Check if a the property with the given key exists.
- *
- * Returns: %TRUE only if the value for @key exist.
- */
-gboolean
-g_udev_device_has_property (GUdevDevice *device,
- const gchar *key)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (key != NULL, FALSE);
- return udev_device_get_property_value (device->priv->udevice, key) != NULL;
-}
-
-/**
- * g_udev_device_get_property:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Look up the value for @key on @device.
- *
- * Returns: (nullable): The value for @key or %NULL if @key doesn't
- * exist on @device. Do not free this string, it is owned by @device.
- */
-const gchar *
-g_udev_device_get_property (GUdevDevice *device,
- const gchar *key)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- g_return_val_if_fail (key != NULL, NULL);
- return udev_device_get_property_value (device->priv->udevice, key);
-}
-
-/**
- * g_udev_device_get_property_as_int:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Look up the value for @key on @device and convert it to an integer
- * using strtol().
- *
- * Returns: The value for @key or 0 if @key doesn't exist or
- * isn't an integer.
- */
-gint
-g_udev_device_get_property_as_int (GUdevDevice *device,
- const gchar *key)
-{
- gint result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- g_return_val_if_fail (key != NULL, 0);
-
- result = 0;
- s = g_udev_device_get_property (device, key);
- if (s == NULL)
- goto out;
-
- result = strtol (s, NULL, 0);
-out:
- return result;
-}
-
-/**
- * g_udev_device_get_property_as_uint64:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Look up the value for @key on @device and convert it to an unsigned
- * 64-bit integer using g_ascii_strtoull().
- *
- * Returns: The value for @key or 0 if @key doesn't exist or isn't a
- * #guint64.
- */
-guint64
-g_udev_device_get_property_as_uint64 (GUdevDevice *device,
- const gchar *key)
-{
- guint64 result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- g_return_val_if_fail (key != NULL, 0);
-
- result = 0;
- s = g_udev_device_get_property (device, key);
- if (s == NULL)
- goto out;
-
- result = g_ascii_strtoull (s, NULL, 0);
-out:
- return result;
-}
-
-/**
- * g_udev_device_get_property_as_double:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Look up the value for @key on @device and convert it to a double
- * precision floating point number using strtod().
- *
- * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a
- * #gdouble.
- */
-gdouble
-g_udev_device_get_property_as_double (GUdevDevice *device,
- const gchar *key)
-{
- gdouble result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
- g_return_val_if_fail (key != NULL, 0.0);
-
- result = 0.0;
- s = g_udev_device_get_property (device, key);
- if (s == NULL)
- goto out;
-
- result = strtod (s, NULL);
-out:
- return result;
-}
-
-/**
- * g_udev_device_get_property_as_boolean:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Look up the value for @key on @device and convert it to an
- * boolean. This is done by doing a case-insensitive string comparison
- * on the string value against "1" and "true".
- *
- * Returns: The value for @key or %FALSE if @key doesn't exist or
- * isn't a #gboolean.
- */
-gboolean
-g_udev_device_get_property_as_boolean (GUdevDevice *device,
- const gchar *key)
-{
- gboolean result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (key != NULL, FALSE);
-
- result = FALSE;
- s = g_udev_device_get_property (device, key);
- if (s == NULL)
- goto out;
-
- if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
- result = TRUE;
- out:
- return result;
-}
-
-static gchar **
-split_at_whitespace (const gchar *s)
-{
- gchar **result;
- guint n;
- guint m;
-
- result = g_strsplit_set (s, " \v\t\r\n", 0);
-
- /* remove empty strings, thanks GLib */
- for (n = 0; result[n] != NULL; n++)
- {
- if (strlen (result[n]) == 0)
- {
- g_free (result[n]);
- for (m = n; result[m] != NULL; m++)
- result[m] = result[m + 1];
- n--;
- }
- }
-
- return result;
-}
-
-/**
- * g_udev_device_get_property_as_strv:
- * @device: A #GUdevDevice.
- * @key: Name of property.
- *
- * Look up the value for @key on @device and return the result of
- * splitting it into non-empty tokens split at white space (only space
- * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'),
- * horizontal tab ('\t'), and vertical tab ('\v') are considered; the
- * locale is not taken into account).
- *
- * Returns: (nullable) (transfer none) (array zero-terminated=1) (element-type utf8):
- * The value of @key on @device split into tokens or %NULL if @key
- * doesn't exist. This array is owned by @device and should not be
- * freed by the caller.
- */
-const gchar* const *
-g_udev_device_get_property_as_strv (GUdevDevice *device,
- const gchar *key)
-{
- gchar **result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- g_return_val_if_fail (key != NULL, NULL);
-
- if (device->priv->prop_strvs != NULL)
- {
- result = g_hash_table_lookup (device->priv->prop_strvs, key);
- if (result != NULL)
- goto out;
- }
-
- result = NULL;
- s = g_udev_device_get_property (device, key);
- if (s == NULL)
- goto out;
-
- result = split_at_whitespace (s);
- if (result == NULL)
- goto out;
-
- if (device->priv->prop_strvs == NULL)
- device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
- g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result);
-
-out:
- return (const gchar* const *) result;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
- * g_udev_device_get_sysfs_attr_keys:
- * @device: A #GUdevDevice.
- *
- * Gets all keys for sysfs attributes on @device.
- *
- * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of sysfs attribute keys. This array is owned by @device and should not be freed by the caller.
- */
-const gchar * const *
-g_udev_device_get_sysfs_attr_keys (GUdevDevice *device)
-{
- struct udev_list_entry *l;
- GPtrArray *p;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
-
- if (device->priv->sysfs_attr_keys != NULL)
- goto out;
-
- p = g_ptr_array_new ();
- for (l = udev_device_get_sysattr_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
- {
- g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
- }
- g_ptr_array_add (p, NULL);
- device->priv->sysfs_attr_keys = (gchar **) g_ptr_array_free (p, FALSE);
-
- out:
- return (const gchar * const *) device->priv->sysfs_attr_keys;
-}
-
-/**
- * g_udev_device_has_sysfs_attr:
- * @device: A #GUdevDevice.
- * @key: Name of sysfs attribute.
- *
- * Check if a the sysfs attribute with the given key exists.
- *
- * Returns: %TRUE only if the value for @key exist.
- */
-gboolean
-g_udev_device_has_sysfs_attr (GUdevDevice *device,
- const gchar *key)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (key != NULL, FALSE);
- return udev_device_get_sysattr_value (device->priv->udevice, key) != NULL;
-}
-
-/**
- * g_udev_device_get_sysfs_attr:
- * @device: A #GUdevDevice.
- * @name: Name of the sysfs attribute.
- *
- * Look up the sysfs attribute with @name on @device.
- *
- * Returns: (nullable): The value of the sysfs attribute or %NULL if
- * there is no such attribute. Do not free this string, it is owned by
- * @device.
- */
-const gchar *
-g_udev_device_get_sysfs_attr (GUdevDevice *device,
- const gchar *name)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- return udev_device_get_sysattr_value (device->priv->udevice, name);
-}
-
-/**
- * g_udev_device_get_sysfs_attr_as_int:
- * @device: A #GUdevDevice.
- * @name: Name of the sysfs attribute.
- *
- * Look up the sysfs attribute with @name on @device and convert it to an integer
- * using strtol().
- *
- * Returns: The value of the sysfs attribute or 0 if there is no such
- * attribute.
- */
-gint
-g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device,
- const gchar *name)
-{
- gint result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- g_return_val_if_fail (name != NULL, 0);
-
- result = 0;
- s = g_udev_device_get_sysfs_attr (device, name);
- if (s == NULL)
- goto out;
-
- result = strtol (s, NULL, 0);
-out:
- return result;
-}
-
-/**
- * g_udev_device_get_sysfs_attr_as_uint64:
- * @device: A #GUdevDevice.
- * @name: Name of the sysfs attribute.
- *
- * Look up the sysfs attribute with @name on @device and convert it to an unsigned
- * 64-bit integer using g_ascii_strtoull().
- *
- * Returns: The value of the sysfs attribute or 0 if there is no such
- * attribute.
- */
-guint64
-g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device,
- const gchar *name)
-{
- guint64 result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- g_return_val_if_fail (name != NULL, 0);
-
- result = 0;
- s = g_udev_device_get_sysfs_attr (device, name);
- if (s == NULL)
- goto out;
-
- result = g_ascii_strtoull (s, NULL, 0);
-out:
- return result;
-}
-
-/**
- * g_udev_device_get_sysfs_attr_as_double:
- * @device: A #GUdevDevice.
- * @name: Name of the sysfs attribute.
- *
- * Look up the sysfs attribute with @name on @device and convert it to a double
- * precision floating point number using strtod().
- *
- * Returns: The value of the sysfs attribute or 0.0 if there is no such
- * attribute.
- */
-gdouble
-g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device,
- const gchar *name)
-{
- gdouble result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
- g_return_val_if_fail (name != NULL, 0.0);
-
- result = 0.0;
- s = g_udev_device_get_sysfs_attr (device, name);
- if (s == NULL)
- goto out;
-
- result = strtod (s, NULL);
-out:
- return result;
-}
-
-/**
- * g_udev_device_get_sysfs_attr_as_boolean:
- * @device: A #GUdevDevice.
- * @name: Name of the sysfs attribute.
- *
- * Look up the sysfs attribute with @name on @device and convert it to an
- * boolean. This is done by doing a case-insensitive string comparison
- * on the string value against "1" and "true".
- *
- * Returns: The value of the sysfs attribute or %FALSE if there is no such
- * attribute.
- */
-gboolean
-g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device,
- const gchar *name)
-{
- gboolean result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
- g_return_val_if_fail (name != NULL, FALSE);
-
- result = FALSE;
- s = g_udev_device_get_sysfs_attr (device, name);
- if (s == NULL)
- goto out;
-
- if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
- result = TRUE;
- out:
- return result;
-}
-
-/**
- * g_udev_device_get_sysfs_attr_as_strv:
- * @device: A #GUdevDevice.
- * @name: Name of the sysfs attribute.
- *
- * Look up the sysfs attribute with @name on @device and return the result of
- * splitting it into non-empty tokens split at white space (only space (' '),
- * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
- * tab ('\t'), and vertical tab ('\v') are considered; the locale is
- * not taken into account).
- *
- * Returns: (nullable) (transfer none) (array zero-terminated=1) (element-type utf8):
- * The value of the sysfs attribute split into tokens or %NULL if
- * there is no such attribute. This array is owned by @device and
- * should not be freed by the caller.
- */
-const gchar * const *
-g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device,
- const gchar *name)
-{
- gchar **result;
- const gchar *s;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
- g_return_val_if_fail (name != NULL, NULL);
-
- if (device->priv->sysfs_attr_strvs != NULL)
- {
- result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name);
- if (result != NULL)
- goto out;
- }
-
- result = NULL;
- s = g_udev_device_get_sysfs_attr (device, name);
- if (s == NULL)
- goto out;
-
- result = split_at_whitespace (s);
- if (result == NULL)
- goto out;
-
- if (device->priv->sysfs_attr_strvs == NULL)
- device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
- g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result);
-
-out:
- return (const gchar* const *) result;
-}
-
-/**
- * g_udev_device_get_tags:
- * @device: A #GUdevDevice.
- *
- * Gets all tags for @device.
- *
- * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of tags. This array is owned by @device and should not be freed by the caller.
- *
- * Since: 165
- */
-const gchar* const *
-g_udev_device_get_tags (GUdevDevice *device)
-{
- struct udev_list_entry *l;
- GPtrArray *p;
-
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
-
- if (device->priv->tags != NULL)
- goto out;
-
- p = g_ptr_array_new ();
- for (l = udev_device_get_tags_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
- {
- g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
- }
- g_ptr_array_add (p, NULL);
- device->priv->tags = (gchar **) g_ptr_array_free (p, FALSE);
-
- out:
- return (const gchar * const *) device->priv->tags;
-}
-
-/**
- * g_udev_device_get_is_initialized:
- * @device: A #GUdevDevice.
- *
- * Gets whether @device has been initalized.
- *
- * Returns: Whether @device has been initialized.
- *
- * Since: 165
- */
-gboolean
-g_udev_device_get_is_initialized (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
- return udev_device_get_is_initialized (device->priv->udevice);
-}
-
-/**
- * g_udev_device_get_usec_since_initialized:
- * @device: A #GUdevDevice.
- *
- * Gets number of micro-seconds since @device was initialized.
- *
- * This only works for devices with properties in the udev
- * database. All other devices return 0.
- *
- * Returns: Number of micro-seconds since @device was initialized or 0 if unknown.
- *
- * Since: 165
- */
-guint64
-g_udev_device_get_usec_since_initialized (GUdevDevice *device)
-{
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
- return udev_device_get_usec_since_initialized (device->priv->udevice);
-}
diff --git a/src/gudev/gudevdevice.h b/src/gudev/gudevdevice.h
deleted file mode 100644
index 72ec180f55..0000000000
--- a/src/gudev/gudevdevice.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_DEVICE_H__
-#define __G_UDEV_DEVICE_H__
-
-#include <gudev/gudevtypes.h>
-
-G_BEGIN_DECLS
-
-#define G_UDEV_TYPE_DEVICE (g_udev_device_get_type ())
-#define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_DEVICE, GUdevDevice))
-#define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
-#define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE))
-#define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_DEVICE))
-#define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass))
-
-typedef struct _GUdevDeviceClass GUdevDeviceClass;
-typedef struct _GUdevDevicePrivate GUdevDevicePrivate;
-
-/**
- * GUdevDevice:
- *
- * The #GUdevDevice struct is opaque and should not be accessed directly.
- */
-struct _GUdevDevice
-{
- GObject parent;
-
- /*< private >*/
- GUdevDevicePrivate *priv;
-};
-
-/**
- * GUdevDeviceClass:
- * @parent_class: Parent class.
- *
- * Class structure for #GUdevDevice.
- */
-struct _GUdevDeviceClass
-{
- GObjectClass parent_class;
-
- /*< private >*/
- /* Padding for future expansion */
- void (*reserved1) (void);
- void (*reserved2) (void);
- void (*reserved3) (void);
- void (*reserved4) (void);
- void (*reserved5) (void);
- void (*reserved6) (void);
- void (*reserved7) (void);
- void (*reserved8) (void);
-};
-
-GType g_udev_device_get_type (void) G_GNUC_CONST;
-gboolean g_udev_device_get_is_initialized (GUdevDevice *device);
-guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device);
-const gchar *g_udev_device_get_subsystem (GUdevDevice *device);
-const gchar *g_udev_device_get_devtype (GUdevDevice *device);
-const gchar *g_udev_device_get_name (GUdevDevice *device);
-const gchar *g_udev_device_get_number (GUdevDevice *device);
-const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device);
-const gchar *g_udev_device_get_driver (GUdevDevice *device);
-const gchar *g_udev_device_get_action (GUdevDevice *device);
-guint64 g_udev_device_get_seqnum (GUdevDevice *device);
-GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device);
-GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device);
-const gchar *g_udev_device_get_device_file (GUdevDevice *device);
-const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device);
-GUdevDevice *g_udev_device_get_parent (GUdevDevice *device);
-GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device,
- const gchar *subsystem,
- const gchar *devtype);
-const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device);
-gboolean g_udev_device_has_property (GUdevDevice *device,
- const gchar *key);
-const gchar *g_udev_device_get_property (GUdevDevice *device,
- const gchar *key);
-gint g_udev_device_get_property_as_int (GUdevDevice *device,
- const gchar *key);
-guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device,
- const gchar *key);
-gdouble g_udev_device_get_property_as_double (GUdevDevice *device,
- const gchar *key);
-gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device,
- const gchar *key);
-const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device,
- const gchar *key);
-
-const gchar* const *g_udev_device_get_sysfs_attr_keys (GUdevDevice *device);
-gboolean g_udev_device_has_sysfs_attr (GUdevDevice *device,
- const gchar *key);
-const gchar *g_udev_device_get_sysfs_attr (GUdevDevice *device,
- const gchar *name);
-gint g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device,
- const gchar *name);
-guint64 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device,
- const gchar *name);
-gdouble g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device,
- const gchar *name);
-gboolean g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device,
- const gchar *name);
-const gchar* const *g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device,
- const gchar *name);
-const gchar* const *g_udev_device_get_tags (GUdevDevice *device);
-
-G_END_DECLS
-
-#endif /* __G_UDEV_DEVICE_H__ */
diff --git a/src/gudev/gudevenumerator.c b/src/gudev/gudevenumerator.c
deleted file mode 100644
index 1fb3098709..0000000000
--- a/src/gudev/gudevenumerator.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gudevclient.h"
-#include "gudevenumerator.h"
-#include "gudevdevice.h"
-#include "gudevmarshal.h"
-#include "gudevprivate.h"
-
-/**
- * SECTION:gudevenumerator
- * @short_description: Lookup and sort devices
- *
- * #GUdevEnumerator is used to lookup and sort devices.
- *
- * Since: 165
- */
-
-struct _GUdevEnumeratorPrivate
-{
- GUdevClient *client;
- struct udev_enumerate *e;
-};
-
-enum
-{
- PROP_0,
- PROP_CLIENT,
-};
-
-G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT)
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-g_udev_enumerator_finalize (GObject *object)
-{
- GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
-
- if (enumerator->priv->client != NULL)
- {
- g_object_unref (enumerator->priv->client);
- enumerator->priv->client = NULL;
- }
-
- if (enumerator->priv->e != NULL)
- {
- udev_enumerate_unref (enumerator->priv->e);
- enumerator->priv->e = NULL;
- }
-
- if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL)
- G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object);
-}
-
-static void
-g_udev_enumerator_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
-
- switch (prop_id)
- {
- case PROP_CLIENT:
- if (enumerator->priv->client != NULL)
- g_object_unref (enumerator->priv->client);
- enumerator->priv->client = g_value_dup_object (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-g_udev_enumerator_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
-
- switch (prop_id)
- {
- case PROP_CLIENT:
- g_value_set_object (value, enumerator->priv->client);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-g_udev_enumerator_constructed (GObject *object)
-{
- GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object);
-
- g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client));
-
- enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client));
-
- if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL)
- G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object);
-}
-
-static void
-g_udev_enumerator_class_init (GUdevEnumeratorClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- gobject_class->finalize = g_udev_enumerator_finalize;
- gobject_class->set_property = g_udev_enumerator_set_property;
- gobject_class->get_property = g_udev_enumerator_get_property;
- gobject_class->constructed = g_udev_enumerator_constructed;
-
- /**
- * GUdevEnumerator:client:
- *
- * The #GUdevClient to enumerate devices from.
- *
- * Since: 165
- */
- g_object_class_install_property (gobject_class,
- PROP_CLIENT,
- g_param_spec_object ("client",
- "The client to enumerate devices from",
- "The client to enumerate devices from",
- G_UDEV_TYPE_CLIENT,
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE));
-
- g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate));
-}
-
-static void
-g_udev_enumerator_init (GUdevEnumerator *enumerator)
-{
- enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator,
- G_UDEV_TYPE_ENUMERATOR,
- GUdevEnumeratorPrivate);
-}
-
-/**
- * g_udev_enumerator_new:
- * @client: A #GUdevClient to enumerate devices from.
- *
- * Constructs a #GUdevEnumerator object that can be used to enumerate
- * and sort devices. Use the add_match_*() and add_nomatch_*() methods
- * and execute the query to get a list of devices with
- * g_udev_enumerator_execute().
- *
- * Returns: A new #GUdevEnumerator object. Free with g_object_unref().
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_new (GUdevClient *client)
-{
- g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL);
- return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL));
-}
-
-
-/**
- * g_udev_enumerator_add_match_subsystem:
- * @enumerator: A #GUdevEnumerator.
- * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'.
- *
- * All returned devices will match the given @subsystem.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator,
- const gchar *subsystem)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (subsystem != NULL, NULL);
- udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_nomatch_subsystem:
- * @enumerator: A #GUdevEnumerator.
- * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'.
- *
- * All returned devices will not match the given @subsystem.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator,
- const gchar *subsystem)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (subsystem != NULL, NULL);
- udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_match_sysfs_attr:
- * @enumerator: A #GUdevEnumerator.
- * @name: Wildcard filter for sysfs attribute key.
- * @value: Wildcard filter for sysfs attribute value.
- *
- * All returned devices will have a sysfs attribute matching the given @name and @value.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator,
- const gchar *name,
- const gchar *value)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- g_return_val_if_fail (value != NULL, NULL);
- udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_nomatch_sysfs_attr:
- * @enumerator: A #GUdevEnumerator.
- * @name: Wildcard filter for sysfs attribute key.
- * @value: Wildcard filter for sysfs attribute value.
- *
- * All returned devices will not have a sysfs attribute matching the given @name and @value.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator,
- const gchar *name,
- const gchar *value)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- g_return_val_if_fail (value != NULL, NULL);
- udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_match_property:
- * @enumerator: A #GUdevEnumerator.
- * @name: Wildcard filter for property name.
- * @value: Wildcard filter for property value.
- *
- * All returned devices will have a property matching the given @name and @value.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator,
- const gchar *name,
- const gchar *value)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- g_return_val_if_fail (value != NULL, NULL);
- udev_enumerate_add_match_property (enumerator->priv->e, name, value);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_match_name:
- * @enumerator: A #GUdevEnumerator.
- * @name: Wildcard filter for kernel name e.g. "sda*".
- *
- * All returned devices will match the given @name.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator,
- const gchar *name)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (name != NULL, NULL);
- udev_enumerate_add_match_sysname (enumerator->priv->e, name);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_sysfs_path:
- * @enumerator: A #GUdevEnumerator.
- * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda"
- *
- * Add a device to the list of devices, to retrieve it back sorted in dependency order.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator,
- const gchar *sysfs_path)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (sysfs_path != NULL, NULL);
- udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_match_tag:
- * @enumerator: A #GUdevEnumerator.
- * @tag: A udev tag e.g. "udev-acl".
- *
- * All returned devices will match the given @tag.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator,
- const gchar *tag)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- g_return_val_if_fail (tag != NULL, NULL);
- udev_enumerate_add_match_tag (enumerator->priv->e, tag);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_add_match_is_initialized:
- * @enumerator: A #GUdevEnumerator.
- *
- * All returned devices will be initialized.
- *
- * Returns: (transfer none): The passed in @enumerator.
- *
- * Since: 165
- */
-GUdevEnumerator *
-g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator)
-{
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
- udev_enumerate_add_match_is_initialized (enumerator->priv->e);
- return enumerator;
-}
-
-/**
- * g_udev_enumerator_execute:
- * @enumerator: A #GUdevEnumerator.
- *
- * Executes the query in @enumerator.
- *
- * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list.
- *
- * Since: 165
- */
-GList *
-g_udev_enumerator_execute (GUdevEnumerator *enumerator)
-{
- GList *ret;
- struct udev_list_entry *l, *devices;
-
- g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL);
-
- ret = NULL;
-
- /* retrieve the list */
- udev_enumerate_scan_devices (enumerator->priv->e);
-
- devices = udev_enumerate_get_list_entry (enumerator->priv->e);
- for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
- {
- struct udev_device *udevice;
- GUdevDevice *device;
-
- udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e),
- udev_list_entry_get_name (l));
- if (udevice == NULL)
- continue;
-
- device = _g_udev_device_new (udevice);
- udev_device_unref (udevice);
- ret = g_list_prepend (ret, device);
- }
-
- ret = g_list_reverse (ret);
-
- return ret;
-}
diff --git a/src/gudev/gudevenumerator.h b/src/gudev/gudevenumerator.h
deleted file mode 100644
index e1dbcf1441..0000000000
--- a/src/gudev/gudevenumerator.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_ENUMERATOR_H__
-#define __G_UDEV_ENUMERATOR_H__
-
-#include <gudev/gudevtypes.h>
-
-G_BEGIN_DECLS
-
-#define G_UDEV_TYPE_ENUMERATOR (g_udev_enumerator_get_type ())
-#define G_UDEV_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumerator))
-#define G_UDEV_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass))
-#define G_UDEV_IS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_ENUMERATOR))
-#define G_UDEV_IS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_ENUMERATOR))
-#define G_UDEV_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass))
-
-typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass;
-typedef struct _GUdevEnumeratorPrivate GUdevEnumeratorPrivate;
-
-/**
- * GUdevEnumerator:
- *
- * The #GUdevEnumerator struct is opaque and should not be accessed directly.
- *
- * Since: 165
- */
-struct _GUdevEnumerator
-{
- GObject parent;
-
- /*< private >*/
- GUdevEnumeratorPrivate *priv;
-};
-
-/**
- * GUdevEnumeratorClass:
- * @parent_class: Parent class.
- *
- * Class structure for #GUdevEnumerator.
- *
- * Since: 165
- */
-struct _GUdevEnumeratorClass
-{
- GObjectClass parent_class;
-
- /*< private >*/
- /* Padding for future expansion */
- void (*reserved1) (void);
- void (*reserved2) (void);
- void (*reserved3) (void);
- void (*reserved4) (void);
- void (*reserved5) (void);
- void (*reserved6) (void);
- void (*reserved7) (void);
- void (*reserved8) (void);
-};
-
-GType g_udev_enumerator_get_type (void) G_GNUC_CONST;
-GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client);
-GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator,
- const gchar *subsystem);
-GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator,
- const gchar *subsystem);
-GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator,
- const gchar *name,
- const gchar *value);
-GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator,
- const gchar *name,
- const gchar *value);
-GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator,
- const gchar *name,
- const gchar *value);
-GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator,
- const gchar *name);
-GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator,
- const gchar *tag);
-GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator);
-GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator,
- const gchar *sysfs_path);
-GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator);
-
-G_END_DECLS
-
-#endif /* __G_UDEV_ENUMERATOR_H__ */
diff --git a/src/gudev/gudevenums.h b/src/gudev/gudevenums.h
deleted file mode 100644
index 467e93bd60..0000000000
--- a/src/gudev/gudevenums.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_ENUMS_H__
-#define __G_UDEV_ENUMS_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-/**
- * GUdevDeviceType:
- * @G_UDEV_DEVICE_TYPE_NONE: Device does not have a device file.
- * @G_UDEV_DEVICE_TYPE_BLOCK: Device is a block device.
- * @G_UDEV_DEVICE_TYPE_CHAR: Device is a character device.
- *
- * Enumeration used to specify a the type of a device.
- */
-typedef enum
-{
- G_UDEV_DEVICE_TYPE_NONE = 0,
- G_UDEV_DEVICE_TYPE_BLOCK = 'b',
- G_UDEV_DEVICE_TYPE_CHAR = 'c',
-} GUdevDeviceType;
-
-G_END_DECLS
-
-#endif /* __G_UDEV_ENUMS_H__ */
diff --git a/src/gudev/gudevenumtypes.c.template b/src/gudev/gudevenumtypes.c.template
deleted file mode 100644
index fc30b39e2e..0000000000
--- a/src/gudev/gudevenumtypes.c.template
+++ /dev/null
@@ -1,39 +0,0 @@
-/*** BEGIN file-header ***/
-#include <gudev.h>
-
-/*** END file-header ***/
-
-/*** BEGIN file-production ***/
-/* enumerations from "@filename@" */
-/*** END file-production ***/
-
-/*** BEGIN value-header ***/
-GType
-@enum_name@_get_type (void)
-{
- static volatile gsize g_define_type_id__volatile = 0;
-
- if (g_once_init_enter (&g_define_type_id__volatile))
- {
- static const G@Type@Value values[] = {
-/*** END value-header ***/
-
-/*** BEGIN value-production ***/
- { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
-/*** END value-production ***/
-
-/*** BEGIN value-tail ***/
- { 0, NULL, NULL }
- };
- GType g_define_type_id =
- g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
- g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
- }
-
- return g_define_type_id__volatile;
-}
-
-/*** END value-tail ***/
-
-/*** BEGIN file-tail ***/
-/*** END file-tail ***/
diff --git a/src/gudev/gudevenumtypes.h.template b/src/gudev/gudevenumtypes.h.template
deleted file mode 100644
index d0ab3393e6..0000000000
--- a/src/gudev/gudevenumtypes.h.template
+++ /dev/null
@@ -1,24 +0,0 @@
-/*** BEGIN file-header ***/
-#ifndef __GUDEV_ENUM_TYPES_H__
-#define __GUDEV_ENUM_TYPES_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-/*** END file-header ***/
-
-/*** BEGIN file-production ***/
-
-/* enumerations from "@filename@" */
-/*** END file-production ***/
-
-/*** BEGIN value-header ***/
-GType @enum_name@_get_type (void) G_GNUC_CONST;
-#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
-/*** END value-header ***/
-
-/*** BEGIN file-tail ***/
-G_END_DECLS
-
-#endif /* __GUDEV_ENUM_TYPES_H__ */
-/*** END file-tail ***/
diff --git a/src/gudev/gudevmarshal.list b/src/gudev/gudevmarshal.list
deleted file mode 100644
index 7e665999e8..0000000000
--- a/src/gudev/gudevmarshal.list
+++ /dev/null
@@ -1 +0,0 @@
-VOID:STRING,OBJECT
diff --git a/src/gudev/gudevprivate.h b/src/gudev/gudevprivate.h
deleted file mode 100644
index 52e272be3d..0000000000
--- a/src/gudev/gudevprivate.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_PRIVATE_H__
-#define __G_UDEV_PRIVATE_H__
-
-#include <gudev/gudevtypes.h>
-
-#include <libudev.h>
-
-G_BEGIN_DECLS
-
-GUdevDevice *
-_g_udev_device_new (struct udev_device *udevice);
-
-struct udev *_g_udev_client_get_udev (GUdevClient *client);
-
-G_END_DECLS
-
-#endif /* __G_UDEV_PRIVATE_H__ */
diff --git a/src/gudev/gudevtypes.h b/src/gudev/gudevtypes.h
deleted file mode 100644
index e2f688ff2d..0000000000
--- a/src/gudev/gudevtypes.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H)
-#error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef __G_UDEV_TYPES_H__
-#define __G_UDEV_TYPES_H__
-
-#include <gudev/gudevenums.h>
-#include <sys/types.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GUdevClient GUdevClient;
-typedef struct _GUdevDevice GUdevDevice;
-typedef struct _GUdevEnumerator GUdevEnumerator;
-
-/**
- * GUdevDeviceNumber:
- *
- * Corresponds to the standard #dev_t type as defined by POSIX (Until
- * bug 584517 is resolved this work-around is needed).
- */
-#ifdef _GUDEV_WORK_AROUND_DEV_T_BUG
-typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */
-#else
-typedef dev_t GUdevDeviceNumber;
-#endif
-
-G_END_DECLS
-
-#endif /* __G_UDEV_TYPES_H__ */
diff --git a/src/gudev/libgudev-1.0.sym b/src/gudev/libgudev-1.0.sym
deleted file mode 100644
index 0600486e9c..0000000000
--- a/src/gudev/libgudev-1.0.sym
+++ /dev/null
@@ -1,68 +0,0 @@
-/***
- This file is part of systemd.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-***/
-
-{
-global:
- g_udev_client_get_type;
- g_udev_client_new;
- g_udev_client_query_by_device_file;
- g_udev_client_query_by_device_number;
- g_udev_client_query_by_subsystem;
- g_udev_client_query_by_subsystem_and_name;
- g_udev_client_query_by_sysfs_path;
- g_udev_device_get_action;
- g_udev_device_get_device_file;
- g_udev_device_get_device_file_symlinks;
- g_udev_device_get_device_number;
- g_udev_device_get_device_type;
- g_udev_device_get_devtype;
- g_udev_device_get_driver;
- g_udev_device_get_is_initialized;
- g_udev_device_get_name;
- g_udev_device_get_number;
- g_udev_device_get_parent;
- g_udev_device_get_parent_with_subsystem;
- g_udev_device_get_property;
- g_udev_device_get_property_as_boolean;
- g_udev_device_get_property_as_double;
- g_udev_device_get_property_as_int;
- g_udev_device_get_property_as_strv;
- g_udev_device_get_property_as_uint64;
- g_udev_device_get_property_keys;
- g_udev_device_get_seqnum;
- g_udev_device_get_subsystem;
- g_udev_device_get_sysfs_attr;
- g_udev_device_get_sysfs_attr_as_boolean;
- g_udev_device_get_sysfs_attr_as_double;
- g_udev_device_get_sysfs_attr_as_int;
- g_udev_device_get_sysfs_attr_as_strv;
- g_udev_device_get_sysfs_attr_as_uint64;
- g_udev_device_get_sysfs_attr_keys;
- g_udev_device_get_sysfs_path;
- g_udev_device_get_tags;
- g_udev_device_get_type;
- g_udev_device_get_usec_since_initialized;
- g_udev_device_has_property;
- g_udev_device_has_sysfs_attr;
- g_udev_device_type_get_type;
- g_udev_enumerator_add_match_is_initialized;
- g_udev_enumerator_add_match_name;
- g_udev_enumerator_add_match_property;
- g_udev_enumerator_add_match_subsystem;
- g_udev_enumerator_add_match_sysfs_attr;
- g_udev_enumerator_add_match_tag;
- g_udev_enumerator_add_nomatch_subsystem;
- g_udev_enumerator_add_nomatch_sysfs_attr;
- g_udev_enumerator_add_sysfs_path;
- g_udev_enumerator_execute;
- g_udev_enumerator_get_type;
- g_udev_enumerator_new;
-local:
- *;
-};
diff --git a/src/gudev/seed-example-enum.js b/src/gudev/seed-example-enum.js
deleted file mode 100755
index 66206ad806..0000000000
--- a/src/gudev/seed-example-enum.js
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env seed
-
-const GLib = imports.gi.GLib;
-const GUdev = imports.gi.GUdev;
-
-function print_device(device) {
- print(" initialized: " + device.get_is_initialized());
- print(" usec since initialized: " + device.get_usec_since_initialized());
- print(" subsystem: " + device.get_subsystem());
- print(" devtype: " + device.get_devtype());
- print(" name: " + device.get_name());
- print(" number: " + device.get_number());
- print(" sysfs_path: " + device.get_sysfs_path());
- print(" driver: " + device.get_driver());
- print(" action: " + device.get_action());
- print(" seqnum: " + device.get_seqnum());
- print(" device type: " + device.get_device_type());
- print(" device number: " + device.get_device_number());
- print(" device file: " + device.get_device_file());
- print(" device file symlinks: " + device.get_device_file_symlinks());
- print(" tags: " + device.get_tags());
- var keys = device.get_property_keys();
- for (var n = 0; n < keys.length; n++) {
- print(" " + keys[n] + "=" + device.get_property(keys[n]));
- }
-}
-
-var client = new GUdev.Client({subsystems: []});
-var enumerator = new GUdev.Enumerator({client: client});
-enumerator.add_match_subsystem('b*')
-
-var devices = enumerator.execute();
-
-for (var n=0; n < devices.length; n++) {
- var device = devices[n];
- print_device(device);
- print("");
-}
diff --git a/src/gudev/seed-example.js b/src/gudev/seed-example.js
deleted file mode 100755
index e2ac324d23..0000000000
--- a/src/gudev/seed-example.js
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env seed
-
-// seed example
-
-const GLib = imports.gi.GLib;
-const GUdev = imports.gi.GUdev;
-
-function print_device (device) {
- print (" subsystem: " + device.get_subsystem ());
- print (" devtype: " + device.get_devtype ());
- print (" name: " + device.get_name ());
- print (" number: " + device.get_number ());
- print (" sysfs_path: " + device.get_sysfs_path ());
- print (" driver: " + device.get_driver ());
- print (" action: " + device.get_action ());
- print (" seqnum: " + device.get_seqnum ());
- print (" device type: " + device.get_device_type ());
- print (" device number: " + device.get_device_number ());
- print (" device file: " + device.get_device_file ());
- print (" device file symlinks: " + device.get_device_file_symlinks ());
- print (" foo: " + device.get_sysfs_attr_as_strv ("stat"));
- var keys = device.get_property_keys ();
- for (var n = 0; n < keys.length; n++) {
- print (" " + keys[n] + "=" + device.get_property (keys[n]));
- }
-}
-
-function on_uevent (client, action, device) {
- print ("action " + action + " on device " + device.get_sysfs_path());
- print_device (device);
- print ("");
-}
-
-var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]});
-client.signal.connect ("uevent", on_uevent);
-
-var block_devices = client.query_by_subsystem ("block");
-for (var n = 0; n < block_devices.length; n++) {
- print ("block device: " + block_devices[n].get_device_file ());
-}
-
-var d;
-
-d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810);
-if (d == null) {
- print ("query_by_device_number 0x810 -> null");
-} else {
- print ("query_by_device_number 0x810 -> " + d.get_device_file ());
- dd = d.get_parent_with_subsystem ("usb", null);
- print_device (dd);
- print ("--------------------------------------------------------------------------");
- while (d != null) {
- print_device (d);
- print ("");
- d = d.get_parent ();
- }
-}
-
-d = client.query_by_sysfs_path ("/sys/block/sda/sda1");
-print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ());
-
-d = client.query_by_subsystem_and_name ("block", "sda2");
-print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ());
-
-d = client.query_by_device_file ("/dev/sda");
-print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ());
-
-d = client.query_by_device_file ("/dev/block/8:0");
-print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ());
-
-var mainloop = GLib.main_loop_new ();
-GLib.main_loop_run (mainloop);
diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c
index 0207346b28..9fb6233336 100644
--- a/src/hibernate-resume/hibernate-resume-generator.c
+++ b/src/hibernate-resume/hibernate-resume-generator.c
@@ -32,6 +32,7 @@ static const char *arg_dest = "/tmp";
static char *arg_resume_dev = NULL;
static int parse_proc_cmdline_item(const char *key, const char *value) {
+
if (streq(key, "resume") && value) {
free(arg_resume_dev);
arg_resume_dev = fstab_node_to_udev_node(value);
@@ -44,13 +45,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
static int process_resume(void) {
_cleanup_free_ char *name = NULL, *lnk = NULL;
+ int r;
if (!arg_resume_dev)
return 0;
- name = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service");
- if (!name)
- return log_oom();
+ r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service", &name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", name, NULL);
if (!lnk)
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
index f28eabbe37..43aac616b6 100644
--- a/src/hibernate-resume/hibernate-resume.c
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -21,9 +21,7 @@
#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
#include "log.h"
#include "util.h"
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index de4ce7ede6..69ecd61f60 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -21,26 +21,19 @@
#include <stdlib.h>
#include <stdbool.h>
-#include <unistd.h>
#include <getopt.h>
#include <locale.h>
#include <string.h>
-#include <sys/timex.h>
-#include <sys/utsname.h>
#include "sd-bus.h"
-
+#include "sd-id128.h"
+#include "hostname-util.h"
#include "bus-util.h"
#include "bus-error.h"
#include "util.h"
#include "spawn-polkit-agent.h"
#include "build.h"
-#include "clock-util.h"
-#include "strv.h"
-#include "sd-id128.h"
-#include "virt.h"
#include "architecture.h"
-#include "fileio.h"
static bool arg_ask_password = true;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 7cd4a1d001..7ff3a4e224 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -30,10 +30,10 @@
#include "virt.h"
#include "env-util.h"
#include "fileio-label.h"
-#include "label.h"
#include "bus-util.h"
#include "event-util.h"
#include "selinux-util.h"
+#include "hostname-util.h"
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
@@ -96,7 +96,7 @@ static int context_read_data(Context *c) {
if (!c->data[PROP_HOSTNAME])
return -ENOMEM;
- r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
+ r = read_hostname_config("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
if (r < 0 && r != -ENOENT)
return r;
@@ -404,13 +404,16 @@ static int property_get_chassis(
return sd_bus_message_append(reply, "s", name);
}
-static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *name;
int interactive;
char *h;
int r;
+ assert(m);
+ assert(c);
+
r = sd_bus_message_read(m, "sb", &name, &interactive);
if (r < 0)
return r;
@@ -427,7 +430,14 @@ static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, s
if (streq_ptr(name, c->data[PROP_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-hostname", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.hostname1.set-hostname",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -448,17 +458,20 @@ static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, s
log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
- sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
+ (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
return sd_bus_reply_method_return(m, NULL);
}
-static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *name;
int interactive;
int r;
+ assert(m);
+ assert(c);
+
r = sd_bus_message_read(m, "sb", &name, &interactive);
if (r < 0)
return r;
@@ -469,7 +482,14 @@ static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *user
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-static-hostname", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.hostname1.set-static-hostname",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -506,18 +526,17 @@ static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *user
log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
- sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
+ (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
return sd_bus_reply_method_return(m, NULL);
}
-static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
+static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
int interactive;
const char *name;
int r;
assert(c);
- assert(bus);
assert(m);
r = sd_bus_message_read(m, "sb", &name, &interactive);
@@ -534,10 +553,14 @@ static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop
* same time as the static one, use the same policy action for
* both... */
- r = bus_verify_polkit_async(m, CAP_SYS_ADMIN,
- prop == PROP_PRETTY_HOSTNAME ?
- "org.freedesktop.hostname1.set-static-hostname" :
- "org.freedesktop.hostname1.set-machine-info", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -583,33 +606,36 @@ static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop
prop == PROP_LOCATION ? "location" :
prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
- sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
- prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
- prop == PROP_DEPLOYMENT ? "Deployment" :
- prop == PROP_LOCATION ? "Location" :
- prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
+ (void) sd_bus_emit_properties_changed(
+ sd_bus_message_get_bus(m),
+ "/org/freedesktop/hostname1",
+ "org.freedesktop.hostname1",
+ prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
+ prop == PROP_DEPLOYMENT ? "Deployment" :
+ prop == PROP_LOCATION ? "Location" :
+ prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
return sd_bus_reply_method_return(m, NULL);
}
-static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
+static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
}
-static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
+static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
}
-static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
+static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
}
-static int method_set_deployment(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return set_machine_info(userdata, bus, m, PROP_DEPLOYMENT, method_set_deployment, error);
+static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
}
-static int method_set_location(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return set_machine_info(userdata, bus, m, PROP_LOCATION, method_set_location, error);
+static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
}
static const sd_bus_vtable hostname_vtable[] = {
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 4539673ead..446de3a2fc 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -18,7 +18,6 @@
***/
#include <stdlib.h>
-#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <ctype.h>
@@ -28,7 +27,6 @@
#include "conf-files.h"
#include "strv.h"
#include "mkdir.h"
-#include "fileio.h"
#include "verbs.h"
#include "build.h"
diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c
index c1301cdb4a..18c42b8b6d 100644
--- a/src/import/aufs-util.c
+++ b/src/import/aufs-util.c
@@ -22,6 +22,7 @@
#include <ftw.h>
#include "util.h"
+#include "rm-rf.h"
#include "aufs-util.h"
static int nftw_cb(
@@ -43,7 +44,7 @@ static int nftw_cb(
return FTW_CONTINUE;
log_debug("Removing whiteout indicator %s.", fpath);
- r = rm_rf_dangerous(fpath, false, true, false);
+ r = rm_rf(fpath, REMOVE_ROOT|REMOVE_PHYSICAL);
if (r < 0)
return FTW_STOP;
@@ -53,7 +54,7 @@ static int nftw_cb(
strcpy(mempcpy(p, fpath, ftwbuf->base), original);
log_debug("Removing deleted file %s.", p);
- r = rm_rf_dangerous(p, false, true, false);
+ r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
if (r < 0)
return FTW_STOP;
}
diff --git a/src/import/export-raw.c b/src/import/export-raw.c
new file mode 100644
index 0000000000..4b6d8dac32
--- /dev/null
+++ b/src/import/export-raw.c
@@ -0,0 +1,345 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/sendfile.h>
+#include <libgen.h>
+#undef basename
+
+#include "sd-daemon.h"
+#include "util.h"
+#include "ratelimit.h"
+#include "btrfs-util.h"
+#include "copy.h"
+#include "import-common.h"
+#include "export-raw.h"
+
+#define COPY_BUFFER_SIZE (16*1024)
+
+struct RawExport {
+ sd_event *event;
+
+ RawExportFinished on_finished;
+ void *userdata;
+
+ char *path;
+
+ int input_fd;
+ int output_fd;
+
+ ImportCompress compress;
+
+ sd_event_source *output_event_source;
+
+ void *buffer;
+ size_t buffer_size;
+ size_t buffer_allocated;
+
+ uint64_t written_compressed;
+ uint64_t written_uncompressed;
+
+ unsigned last_percent;
+ RateLimit progress_rate_limit;
+
+ struct stat st;
+
+ bool eof;
+ bool tried_reflink;
+ bool tried_sendfile;
+};
+
+RawExport *raw_export_unref(RawExport *e) {
+ if (!e)
+ return NULL;
+
+ sd_event_source_unref(e->output_event_source);
+
+ import_compress_free(&e->compress);
+
+ sd_event_unref(e->event);
+
+ safe_close(e->input_fd);
+
+ free(e->buffer);
+ free(e->path);
+ free(e);
+
+ return NULL;
+}
+
+int raw_export_new(
+ RawExport **ret,
+ sd_event *event,
+ RawExportFinished on_finished,
+ void *userdata) {
+
+ _cleanup_(raw_export_unrefp) RawExport *e = NULL;
+ int r;
+
+ assert(ret);
+
+ e = new0(RawExport, 1);
+ if (!e)
+ return -ENOMEM;
+
+ e->output_fd = e->input_fd = -1;
+ e->on_finished = on_finished;
+ e->userdata = userdata;
+
+ RATELIMIT_INIT(e->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
+ e->last_percent = (unsigned) -1;
+
+ if (event)
+ e->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&e->event);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = e;
+ e = NULL;
+
+ return 0;
+}
+
+static void raw_export_report_progress(RawExport *e) {
+ unsigned percent;
+ assert(e);
+
+ if (e->written_uncompressed >= (uint64_t) e->st.st_size)
+ percent = 100;
+ else
+ percent = (unsigned) ((e->written_uncompressed * UINT64_C(100)) / (uint64_t) e->st.st_size);
+
+ if (percent == e->last_percent)
+ return;
+
+ if (!ratelimit_test(&e->progress_rate_limit))
+ return;
+
+ sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
+ log_info("Exported %u%%.", percent);
+
+ e->last_percent = percent;
+}
+
+static int raw_export_process(RawExport *e) {
+ ssize_t l;
+ int r;
+
+ assert(e);
+
+ if (!e->tried_reflink && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
+
+ /* If we shall take an uncompressed snapshot we can
+ * reflink source to destination directly. Let's see
+ * if this works. */
+
+ r = btrfs_reflink(e->input_fd, e->output_fd);
+ if (r >= 0) {
+ r = 0;
+ goto finish;
+ }
+
+ e->tried_reflink = true;
+ }
+
+ if (!e->tried_sendfile && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
+
+ l = sendfile(e->output_fd, e->input_fd, NULL, COPY_BUFFER_SIZE);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ e->tried_sendfile = true;
+ } else if (l == 0) {
+ r = 0;
+ goto finish;
+ } else {
+ e->written_uncompressed += l;
+ e->written_compressed += l;
+
+ raw_export_report_progress(e);
+
+ return 0;
+ }
+ }
+
+ while (e->buffer_size <= 0) {
+ uint8_t input[COPY_BUFFER_SIZE];
+
+ if (e->eof) {
+ r = 0;
+ goto finish;
+ }
+
+ l = read(e->input_fd, input, sizeof(input));
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read raw file: %m");
+ goto finish;
+ }
+
+ if (l == 0) {
+ e->eof = true;
+ r = import_compress_finish(&e->compress, &e->buffer, &e->buffer_size, &e->buffer_allocated);
+ } else {
+ e->written_uncompressed += l;
+ r = import_compress(&e->compress, input, l, &e->buffer, &e->buffer_size, &e->buffer_allocated);
+ }
+ if (r < 0) {
+ r = log_error_errno(r, "Failed to encode: %m");
+ goto finish;
+ }
+ }
+
+ l = write(e->output_fd, e->buffer, e->buffer_size);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ r = log_error_errno(errno, "Failed to write output file: %m");
+ goto finish;
+ }
+
+ assert((size_t) l <= e->buffer_size);
+ memmove(e->buffer, (uint8_t*) e->buffer + l, e->buffer_size - l);
+ e->buffer_size -= l;
+ e->written_compressed += l;
+
+ raw_export_report_progress(e);
+
+ return 0;
+
+finish:
+ if (r >= 0) {
+ (void) copy_times(e->input_fd, e->output_fd);
+ (void) copy_xattr(e->input_fd, e->output_fd);
+ }
+
+ if (e->on_finished)
+ e->on_finished(e, r, e->userdata);
+ else
+ sd_event_exit(e->event, r);
+
+ return 0;
+}
+
+static int raw_export_on_output(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ RawExport *i = userdata;
+
+ return raw_export_process(i);
+}
+
+static int raw_export_on_defer(sd_event_source *s, void *userdata) {
+ RawExport *i = userdata;
+
+ return raw_export_process(i);
+}
+
+static int reflink_snapshot(int fd, const char *path) {
+ char *p, *d;
+ int new_fd, r;
+
+ p = strdupa(path);
+ d = dirname(p);
+
+ new_fd = open(d, O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0600);
+ if (new_fd < 0) {
+ _cleanup_free_ char *t = NULL;
+
+ r = tempfn_random(path, &t);
+ if (r < 0)
+ return r;
+
+ new_fd = open(t, O_CLOEXEC|O_CREAT|O_NOCTTY|O_RDWR, 0600);
+ if (new_fd < 0)
+ return -errno;
+
+ (void) unlink(t);
+ }
+
+ r = btrfs_reflink(fd, new_fd);
+ if (r < 0) {
+ safe_close(new_fd);
+ return r;
+ }
+
+ return new_fd;
+}
+
+int raw_export_start(RawExport *e, const char *path, int fd, ImportCompressType compress) {
+ _cleanup_close_ int sfd = -1, tfd = -1;
+ int r;
+
+ assert(e);
+ assert(path);
+ assert(fd >= 0);
+ assert(compress < _IMPORT_COMPRESS_TYPE_MAX);
+ assert(compress != IMPORT_COMPRESS_UNKNOWN);
+
+ if (e->output_fd >= 0)
+ return -EBUSY;
+
+ r = fd_nonblock(fd, true);
+ if (r < 0)
+ return r;
+
+ r = free_and_strdup(&e->path, path);
+ if (r < 0)
+ return r;
+
+ sfd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (sfd < 0)
+ return -errno;
+
+ if (fstat(sfd, &e->st) < 0)
+ return -errno;
+ if (!S_ISREG(e->st.st_mode))
+ return -ENOTTY;
+
+ /* Try to take a reflink snapshot of the file, if we can t make the export atomic */
+ tfd = reflink_snapshot(sfd, path);
+ if (tfd >= 0) {
+ e->input_fd = tfd;
+ tfd = -1;
+ } else {
+ e->input_fd = sfd;
+ sfd = -1;
+ }
+
+ r = import_compress_init(&e->compress, compress);
+ if (r < 0)
+ return r;
+
+ r = sd_event_add_io(e->event, &e->output_event_source, fd, EPOLLOUT, raw_export_on_output, e);
+ if (r == -EPERM) {
+ r = sd_event_add_defer(e->event, &e->output_event_source, raw_export_on_defer, e);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_enabled(e->output_event_source, SD_EVENT_ON);
+ }
+ if (r < 0)
+ return r;
+
+ e->output_fd = fd;
+ return r;
+}
diff --git a/src/import/export-raw.h b/src/import/export-raw.h
new file mode 100644
index 0000000000..b71de6cb82
--- /dev/null
+++ b/src/import/export-raw.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-event.h"
+#include "macro.h"
+#include "import-compress.h"
+
+typedef struct RawExport RawExport;
+
+typedef void (*RawExportFinished)(RawExport *export, int error, void *userdata);
+
+int raw_export_new(RawExport **export, sd_event *event, RawExportFinished on_finished, void *userdata);
+RawExport* raw_export_unref(RawExport *export);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(RawExport*, raw_export_unref);
+
+int raw_export_start(RawExport *export, const char *path, int fd, ImportCompressType compress);
diff --git a/src/import/export-tar.c b/src/import/export-tar.c
new file mode 100644
index 0000000000..d31295745f
--- /dev/null
+++ b/src/import/export-tar.c
@@ -0,0 +1,329 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/sendfile.h>
+
+#include "sd-daemon.h"
+#include "util.h"
+#include "ratelimit.h"
+#include "btrfs-util.h"
+#include "import-common.h"
+#include "export-tar.h"
+#include "process-util.h"
+
+#define COPY_BUFFER_SIZE (16*1024)
+
+struct TarExport {
+ sd_event *event;
+
+ TarExportFinished on_finished;
+ void *userdata;
+
+ char *path;
+ char *temp_path;
+
+ int output_fd;
+ int tar_fd;
+
+ ImportCompress compress;
+
+ sd_event_source *output_event_source;
+
+ void *buffer;
+ size_t buffer_size;
+ size_t buffer_allocated;
+
+ uint64_t written_compressed;
+ uint64_t written_uncompressed;
+
+ pid_t tar_pid;
+
+ struct stat st;
+ uint64_t quota_referenced;
+
+ unsigned last_percent;
+ RateLimit progress_rate_limit;
+
+ bool eof;
+ bool tried_splice;
+};
+
+TarExport *tar_export_unref(TarExport *e) {
+ if (!e)
+ return NULL;
+
+ sd_event_source_unref(e->output_event_source);
+
+ if (e->tar_pid > 1) {
+ (void) kill_and_sigcont(e->tar_pid, SIGKILL);
+ (void) wait_for_terminate(e->tar_pid, NULL);
+ }
+
+ if (e->temp_path) {
+ (void) btrfs_subvol_remove(e->temp_path, false);
+ free(e->temp_path);
+ }
+
+ import_compress_free(&e->compress);
+
+ sd_event_unref(e->event);
+
+ safe_close(e->tar_fd);
+
+ free(e->buffer);
+ free(e->path);
+ free(e);
+
+ return NULL;
+}
+
+int tar_export_new(
+ TarExport **ret,
+ sd_event *event,
+ TarExportFinished on_finished,
+ void *userdata) {
+
+ _cleanup_(tar_export_unrefp) TarExport *e = NULL;
+ int r;
+
+ assert(ret);
+
+ e = new0(TarExport, 1);
+ if (!e)
+ return -ENOMEM;
+
+ e->output_fd = e->tar_fd = -1;
+ e->on_finished = on_finished;
+ e->userdata = userdata;
+ e->quota_referenced = (uint64_t) -1;
+
+ RATELIMIT_INIT(e->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
+ e->last_percent = (unsigned) -1;
+
+ if (event)
+ e->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&e->event);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = e;
+ e = NULL;
+
+ return 0;
+}
+
+static void tar_export_report_progress(TarExport *e) {
+ unsigned percent;
+ assert(e);
+
+ /* Do we have any quota info? If not, we don't know anything about the progress */
+ if (e->quota_referenced == (uint64_t) -1)
+ return;
+
+ if (e->written_uncompressed >= e->quota_referenced)
+ percent = 100;
+ else
+ percent = (unsigned) ((e->written_uncompressed * UINT64_C(100)) / e->quota_referenced);
+
+ if (percent == e->last_percent)
+ return;
+
+ if (!ratelimit_test(&e->progress_rate_limit))
+ return;
+
+ sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
+ log_info("Exported %u%%.", percent);
+
+ e->last_percent = percent;
+}
+
+static int tar_export_process(TarExport *e) {
+ ssize_t l;
+ int r;
+
+ assert(e);
+
+ if (!e->tried_splice && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
+
+ l = splice(e->tar_fd, NULL, e->output_fd, NULL, COPY_BUFFER_SIZE, 0);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ e->tried_splice = true;
+ } else if (l == 0) {
+ r = 0;
+ goto finish;
+ } else {
+ e->written_uncompressed += l;
+ e->written_compressed += l;
+
+ tar_export_report_progress(e);
+
+ return 0;
+ }
+ }
+
+ while (e->buffer_size <= 0) {
+ uint8_t input[COPY_BUFFER_SIZE];
+
+ if (e->eof) {
+ r = 0;
+ goto finish;
+ }
+
+ l = read(e->tar_fd, input, sizeof(input));
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read tar file: %m");
+ goto finish;
+ }
+
+ if (l == 0) {
+ e->eof = true;
+ r = import_compress_finish(&e->compress, &e->buffer, &e->buffer_size, &e->buffer_allocated);
+ } else {
+ e->written_uncompressed += l;
+ r = import_compress(&e->compress, input, l, &e->buffer, &e->buffer_size, &e->buffer_allocated);
+ }
+ if (r < 0) {
+ r = log_error_errno(r, "Failed to encode: %m");
+ goto finish;
+ }
+ }
+
+ l = write(e->output_fd, e->buffer, e->buffer_size);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ r = log_error_errno(errno, "Failed to write output file: %m");
+ goto finish;
+ }
+
+ assert((size_t) l <= e->buffer_size);
+ memmove(e->buffer, (uint8_t*) e->buffer + l, e->buffer_size - l);
+ e->buffer_size -= l;
+ e->written_compressed += l;
+
+ tar_export_report_progress(e);
+
+ return 0;
+
+finish:
+ if (e->on_finished)
+ e->on_finished(e, r, e->userdata);
+ else
+ sd_event_exit(e->event, r);
+
+ return 0;
+}
+
+static int tar_export_on_output(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ TarExport *i = userdata;
+
+ return tar_export_process(i);
+}
+
+static int tar_export_on_defer(sd_event_source *s, void *userdata) {
+ TarExport *i = userdata;
+
+ return tar_export_process(i);
+}
+
+int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType compress) {
+ _cleanup_close_ int sfd = -1;
+ int r;
+
+ assert(e);
+ assert(path);
+ assert(fd >= 0);
+ assert(compress < _IMPORT_COMPRESS_TYPE_MAX);
+ assert(compress != IMPORT_COMPRESS_UNKNOWN);
+
+ if (e->output_fd >= 0)
+ return -EBUSY;
+
+ sfd = open(path, O_DIRECTORY|O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (sfd < 0)
+ return -errno;
+
+ if (fstat(sfd, &e->st) < 0)
+ return -errno;
+
+ r = fd_nonblock(fd, true);
+ if (r < 0)
+ return r;
+
+ r = free_and_strdup(&e->path, path);
+ if (r < 0)
+ return r;
+
+ e->quota_referenced = (uint64_t) -1;
+
+ if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */
+ BtrfsQuotaInfo q;
+
+ r = btrfs_subvol_get_quota_fd(sfd, &q);
+ if (r >= 0)
+ e->quota_referenced = q.referenced;
+
+ free(e->temp_path);
+ e->temp_path = NULL;
+
+ r = tempfn_random(path, &e->temp_path);
+ if (r < 0)
+ return r;
+
+ /* Let's try to make a snapshot, if we can, so that the export is atomic */
+ r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE);
+ if (r < 0) {
+ log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path);
+ free(e->temp_path);
+ e->temp_path = NULL;
+ }
+ }
+
+ r = import_compress_init(&e->compress, compress);
+ if (r < 0)
+ return r;
+
+ r = sd_event_add_io(e->event, &e->output_event_source, fd, EPOLLOUT, tar_export_on_output, e);
+ if (r == -EPERM) {
+ r = sd_event_add_defer(e->event, &e->output_event_source, tar_export_on_defer, e);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_enabled(e->output_event_source, SD_EVENT_ON);
+ }
+ if (r < 0)
+ return r;
+
+ e->tar_fd = import_fork_tar_c(e->temp_path ?: e->path, &e->tar_pid);
+ if (e->tar_fd < 0) {
+ e->output_event_source = sd_event_source_unref(e->output_event_source);
+ return e->tar_fd;
+ }
+
+ e->output_fd = fd;
+ return r;
+}
diff --git a/src/import/export-tar.h b/src/import/export-tar.h
new file mode 100644
index 0000000000..ce27a9fc1e
--- /dev/null
+++ b/src/import/export-tar.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-event.h"
+#include "macro.h"
+#include "import-compress.h"
+
+typedef struct TarExport TarExport;
+
+typedef void (*TarExportFinished)(TarExport *export, int error, void *userdata);
+
+int tar_export_new(TarExport **export, sd_event *event, TarExportFinished on_finished, void *userdata);
+TarExport* tar_export_unref(TarExport *export);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(TarExport*, tar_export_unref);
+
+int tar_export_start(TarExport *export, const char *path, int fd, ImportCompressType compress);
diff --git a/src/import/export.c b/src/import/export.c
new file mode 100644
index 0000000000..d4bc88e010
--- /dev/null
+++ b/src/import/export.c
@@ -0,0 +1,320 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <getopt.h>
+
+#include "sd-event.h"
+#include "event-util.h"
+#include "signal-util.h"
+#include "verbs.h"
+#include "build.h"
+#include "machine-image.h"
+#include "import-util.h"
+#include "export-tar.h"
+#include "export-raw.h"
+
+static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
+
+static void determine_compression_from_filename(const char *p) {
+
+ if (arg_compress != IMPORT_COMPRESS_UNKNOWN)
+ return;
+
+ if (!p) {
+ arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
+ return;
+ }
+
+ if (endswith(p, ".xz"))
+ arg_compress = IMPORT_COMPRESS_XZ;
+ else if (endswith(p, ".gz"))
+ arg_compress = IMPORT_COMPRESS_GZIP;
+ else if (endswith(p, ".bz2"))
+ arg_compress = IMPORT_COMPRESS_BZIP2;
+ else
+ arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
+}
+
+static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ log_notice("Transfer aborted.");
+ sd_event_exit(sd_event_source_get_event(s), EINTR);
+ return 0;
+}
+
+static void on_tar_finished(TarExport *export, int error, void *userdata) {
+ sd_event *event = userdata;
+ assert(export);
+
+ if (error == 0)
+ log_info("Operation completed successfully.");
+
+ sd_event_exit(event, abs(error));
+}
+
+static int export_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_(tar_export_unrefp) TarExport *export = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ _cleanup_(image_unrefp) Image *image = NULL;
+ const char *path = NULL, *local = NULL;
+ _cleanup_close_ int open_fd = -1;
+ int r, fd;
+
+ if (machine_name_is_valid(argv[1])) {
+ r = image_find(argv[1], &image);
+ if (r < 0)
+ return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
+ if (r == 0) {
+ log_error("Machine image %s not found.", argv[1]);
+ return -ENOENT;
+ }
+
+ local = image->path;
+ } else
+ local = argv[1];
+
+ if (argc >= 3)
+ path = argv[2];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ determine_compression_from_filename(path);
+
+ if (path) {
+ open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
+ if (open_fd < 0)
+ return log_error_errno(errno, "Failed to open tar image for export: %m");
+
+ fd = open_fd;
+
+ log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
+ } else {
+ _cleanup_free_ char *pretty = NULL;
+
+ fd = STDOUT_FILENO;
+
+ (void) readlink_malloc("/proc/self/fd/1", &pretty);
+ log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
+ }
+
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event loop: %m");
+
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
+ sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
+ sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+
+ r = tar_export_new(&export, event, on_tar_finished, event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate exporter: %m");
+
+ r = tar_export_start(export, local, fd, arg_compress);
+ if (r < 0)
+ return log_error_errno(r, "Failed to export image: %m");
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ log_info("Exiting.");
+ return -r;
+}
+
+static void on_raw_finished(RawExport *export, int error, void *userdata) {
+ sd_event *event = userdata;
+ assert(export);
+
+ if (error == 0)
+ log_info("Operation completed successfully.");
+
+ sd_event_exit(event, abs(error));
+}
+
+static int export_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_(raw_export_unrefp) RawExport *export = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ _cleanup_(image_unrefp) Image *image = NULL;
+ const char *path = NULL, *local = NULL;
+ _cleanup_close_ int open_fd = -1;
+ int r, fd;
+
+ if (machine_name_is_valid(argv[1])) {
+ r = image_find(argv[1], &image);
+ if (r < 0)
+ return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
+ if (r == 0) {
+ log_error("Machine image %s not found.", argv[1]);
+ return -ENOENT;
+ }
+
+ local = image->path;
+ } else
+ local = argv[1];
+
+ if (argc >= 3)
+ path = argv[2];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ determine_compression_from_filename(path);
+
+ if (path) {
+ open_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
+ if (open_fd < 0)
+ return log_error_errno(errno, "Failed to open raw image for export: %m");
+
+ fd = open_fd;
+
+ log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, path, import_compress_type_to_string(arg_compress));
+ } else {
+ _cleanup_free_ char *pretty = NULL;
+
+ fd = STDOUT_FILENO;
+
+ (void) readlink_malloc("/proc/self/fd/1", &pretty);
+ log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
+ }
+
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event loop: %m");
+
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
+ sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
+ sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+
+ r = raw_export_new(&export, event, on_raw_finished, event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate exporter: %m");
+
+ r = raw_export_start(export, local, fd, arg_compress);
+ if (r < 0)
+ return log_error_errno(r, "Failed to export image: %m");
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ log_info("Exiting.");
+ return -r;
+}
+
+static int help(int argc, char *argv[], void *userdata) {
+
+ printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+ "Export container or virtual machine images.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --format=FORMAT Select format\n\n"
+ "Commands:\n"
+ " tar NAME [FILE] Export a TAR image\n"
+ " raw NAME [FILE] Export a RAW image\n",
+ program_invocation_short_name);
+
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_FORMAT,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "format", required_argument, NULL, ARG_FORMAT },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+
+ switch (c) {
+
+ case 'h':
+ return help(0, NULL, NULL);
+
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0;
+
+ case ARG_FORMAT:
+ if (streq(optarg, "uncompressed"))
+ arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
+ else if (streq(optarg, "xz"))
+ arg_compress = IMPORT_COMPRESS_XZ;
+ else if (streq(optarg, "gzip"))
+ arg_compress = IMPORT_COMPRESS_GZIP;
+ else if (streq(optarg, "bzip2"))
+ arg_compress = IMPORT_COMPRESS_BZIP2;
+ else {
+ log_error("Unknown format: %s", optarg);
+ return -EINVAL;
+ }
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+
+ return 1;
+}
+
+static int export_main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "help", VERB_ANY, VERB_ANY, 0, help },
+ { "tar", 2, 3, 0, export_tar },
+ { "raw", 2, 3, 0, export_raw },
+ {}
+ };
+
+ return dispatch_verb(argc, argv, verbs, NULL);
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ setlocale(LC_ALL, "");
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ goto finish;
+
+ ignore_signals(SIGPIPE, -1);
+
+ r = export_main(argc, argv);
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/import/import-common.c b/src/import/import-common.c
index 2acf380f99..9711614000 100644
--- a/src/import/import-common.c
+++ b/src/import/import-common.c
@@ -20,127 +20,15 @@
***/
#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "util.h"
-#include "strv.h"
-#include "copy.h"
#include "btrfs-util.h"
#include "capability.h"
-#include "import-job.h"
+#include "signal-util.h"
#include "import-common.h"
-#define FILENAME_ESCAPE "/.#\"\'"
-
-int import_find_old_etags(const char *url, const char *image_root, int dt, const char *prefix, const char *suffix, char ***etags) {
- _cleanup_free_ char *escaped_url = NULL;
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_strv_free_ char **l = NULL;
- struct dirent *de;
- int r;
-
- assert(url);
- assert(etags);
-
- if (!image_root)
- image_root = "/var/lib/machines";
-
- escaped_url = xescape(url, FILENAME_ESCAPE);
- if (!escaped_url)
- return -ENOMEM;
-
- d = opendir(image_root);
- if (!d) {
- if (errno == ENOENT) {
- *etags = NULL;
- return 0;
- }
-
- return -errno;
- }
-
- FOREACH_DIRENT_ALL(de, d, return -errno) {
- const char *a, *b;
- char *u;
-
- if (de->d_type != DT_UNKNOWN &&
- de->d_type != dt)
- continue;
-
- if (prefix) {
- a = startswith(de->d_name, prefix);
- if (!a)
- continue;
- } else
- a = de->d_name;
-
- a = startswith(a, escaped_url);
- if (!a)
- continue;
-
- a = startswith(a, ".");
- if (!a)
- continue;
-
- if (suffix) {
- b = endswith(de->d_name, suffix);
- if (!b)
- continue;
- } else
- b = strchr(de->d_name, 0);
-
- if (a >= b)
- continue;
-
- u = cunescape_length(a, b - a);
- if (!u)
- return -ENOMEM;
-
- if (!http_etag_is_valid(u)) {
- free(u);
- continue;
- }
-
- r = strv_consume(&l, u);
- if (r < 0)
- return r;
- }
-
- *etags = l;
- l = NULL;
-
- return 0;
-}
-
-int import_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
- const char *p;
- int r;
-
- assert(final);
- assert(local);
-
- if (!image_root)
- image_root = "/var/lib/machines";
-
- p = strjoina(image_root, "/", local);
-
- if (force_local) {
- (void) btrfs_subvol_remove(p);
- (void) rm_rf_dangerous(p, false, true, false);
- }
-
- r = btrfs_subvol_snapshot(final, p, false, false);
- if (r == -ENOTTY) {
- r = copy_tree(final, p, false);
- if (r < 0)
- return log_error_errno(r, "Failed to copy image: %m");
- } else if (r < 0)
- return log_error_errno(r, "Failed to create local image: %m");
-
- log_info("Created new local image '%s'.", local);
-
- return 0;
-}
-
int import_make_read_only_fd(int fd) {
int r;
@@ -182,191 +70,30 @@ int import_make_read_only(const char *path) {
return import_make_read_only_fd(fd);
}
-int import_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
- _cleanup_free_ char *escaped_url = NULL;
- char *path;
-
- assert(url);
- assert(ret);
-
- if (!image_root)
- image_root = "/var/lib/machines";
-
- escaped_url = xescape(url, FILENAME_ESCAPE);
- if (!escaped_url)
- return -ENOMEM;
-
- if (etag) {
- _cleanup_free_ char *escaped_etag = NULL;
-
- escaped_etag = xescape(etag, FILENAME_ESCAPE);
- if (!escaped_etag)
- return -ENOMEM;
-
- path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
- } else
- path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
- if (!path)
- return -ENOMEM;
-
- *ret = path;
- return 0;
-}
-
-int import_make_verification_jobs(
- ImportJob **ret_checksum_job,
- ImportJob **ret_signature_job,
- ImportVerify verify,
- const char *url,
- CurlGlue *glue,
- ImportJobFinished on_finished,
- void *userdata) {
-
- _cleanup_(import_job_unrefp) ImportJob *checksum_job = NULL, *signature_job = NULL;
- int r;
-
- assert(ret_checksum_job);
- assert(ret_signature_job);
- assert(verify >= 0);
- assert(verify < _IMPORT_VERIFY_MAX);
- assert(url);
- assert(glue);
-
- if (verify != IMPORT_VERIFY_NO) {
- _cleanup_free_ char *checksum_url = NULL;
-
- /* Queue job for the SHA256SUMS file for the image */
- r = import_url_change_last_component(url, "SHA256SUMS", &checksum_url);
- if (r < 0)
- return r;
-
- r = import_job_new(&checksum_job, checksum_url, glue, userdata);
- if (r < 0)
- return r;
-
- checksum_job->on_finished = on_finished;
- checksum_job->uncompressed_max = checksum_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
- }
-
- if (verify == IMPORT_VERIFY_SIGNATURE) {
- _cleanup_free_ char *signature_url = NULL;
-
- /* Queue job for the SHA256SUMS.gpg file for the image. */
- r = import_url_change_last_component(url, "SHA256SUMS.gpg", &signature_url);
- if (r < 0)
- return r;
-
- r = import_job_new(&signature_job, signature_url, glue, userdata);
- if (r < 0)
- return r;
-
- signature_job->on_finished = on_finished;
- signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
- }
-
- *ret_checksum_job = checksum_job;
- *ret_signature_job = signature_job;
-
- checksum_job = signature_job = NULL;
-
- return 0;
-}
-
-int import_verify(
- ImportJob *main_job,
- ImportJob *checksum_job,
- ImportJob *signature_job) {
-
- _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
- _cleanup_free_ char *fn = NULL;
- _cleanup_close_ int sig_file = -1;
- const char *p, *line;
- char sig_file_path[] = "/tmp/sigXXXXXX";
- _cleanup_sigkill_wait_ pid_t pid = 0;
+int import_fork_tar_x(const char *path, pid_t *ret) {
+ _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
+ pid_t pid;
int r;
- assert(main_job);
- assert(main_job->state == IMPORT_JOB_DONE);
-
- if (!checksum_job)
- return 0;
-
- assert(main_job->calc_checksum);
- assert(main_job->checksum);
- assert(checksum_job->state == IMPORT_JOB_DONE);
-
- if (!checksum_job->payload || checksum_job->payload_size <= 0) {
- log_error("Checksum is empty, cannot verify.");
- return -EBADMSG;
- }
-
- r = import_url_last_component(main_job->url, &fn);
- if (r < 0)
- return log_oom();
-
- if (!filename_is_valid(fn)) {
- log_error("Cannot verify checksum, could not determine valid server-side file name.");
- return -EBADMSG;
- }
-
- line = strjoina(main_job->checksum, " *", fn, "\n");
-
- p = memmem(checksum_job->payload,
- checksum_job->payload_size,
- line,
- strlen(line));
-
- if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
- log_error("Checksum did not check out, payload has been tempered with.");
- return -EBADMSG;
- }
-
- log_info("SHA256 checksum of %s is valid.", main_job->url);
-
- if (!signature_job)
- return 0;
-
- assert(signature_job->state == IMPORT_JOB_DONE);
-
- if (!signature_job->payload || signature_job->payload_size <= 0) {
- log_error("Signature is empty, cannot verify.");
- return -EBADMSG;
- }
-
- r = pipe2(gpg_pipe, O_CLOEXEC);
- if (r < 0)
- return log_error_errno(errno, "Failed to create pipe for gpg: %m");
-
- sig_file = mkostemp(sig_file_path, O_RDWR);
- if (sig_file < 0)
- return log_error_errno(errno, "Failed to create temporary file: %m");
+ assert(path);
+ assert(ret);
- r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false);
- if (r < 0) {
- log_error_errno(r, "Failed to write to temporary file: %m");
- goto finish;
- }
+ if (pipe2(pipefd, O_CLOEXEC) < 0)
+ return log_error_errno(errno, "Failed to create pipe for tar: %m");
pid = fork();
if (pid < 0)
- return log_error_errno(errno, "Failed to fork off gpg: %m");
+ return log_error_errno(errno, "Failed to fork off tar: %m");
+
if (pid == 0) {
- const char *cmd[] = {
- "gpg",
- "--no-options",
- "--no-default-keyring",
- "--no-auto-key-locate",
- "--no-auto-check-trustdb",
- "--batch",
- "--trust-model=always",
- NULL, /* keyring to use */
- NULL, /* --verify */
- NULL, /* signature file */
- NULL, /* dash */
- NULL /* trailing NULL */
- };
- unsigned k = ELEMENTSOF(cmd) - 5;
int null_fd;
+ uint64_t retain =
+ (1ULL << CAP_CHOWN) |
+ (1ULL << CAP_FOWNER) |
+ (1ULL << CAP_FSETID) |
+ (1ULL << CAP_MKNOD) |
+ (1ULL << CAP_SETFCAP) |
+ (1ULL << CAP_DAC_OVERRIDE);
/* Child */
@@ -374,15 +101,15 @@ int import_verify(
reset_signal_mask();
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
- gpg_pipe[1] = safe_close(gpg_pipe[1]);
+ pipefd[1] = safe_close(pipefd[1]);
- if (dup2(gpg_pipe[0], STDIN_FILENO) != STDIN_FILENO) {
+ if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
_exit(EXIT_FAILURE);
}
- if (gpg_pipe[0] != STDIN_FILENO)
- gpg_pipe[0] = safe_close(gpg_pipe[0]);
+ if (pipefd[0] != STDIN_FILENO)
+ pipefd[0] = safe_close(pipefd[0]);
null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
if (null_fd < 0) {
@@ -398,58 +125,32 @@ int import_verify(
if (null_fd != STDOUT_FILENO)
null_fd = safe_close(null_fd);
- /* We add the user keyring only to the command line
- * arguments, if it's around since gpg fails
- * otherwise. */
- if (access(USER_KEYRING_PATH, F_OK) >= 0)
- cmd[k++] = "--keyring=" USER_KEYRING_PATH;
- else
- cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
-
- cmd[k++] = "--verify";
- cmd[k++] = sig_file_path;
- cmd[k++] = "-";
- cmd[k++] = NULL;
-
fd_cloexec(STDIN_FILENO, false);
fd_cloexec(STDOUT_FILENO, false);
fd_cloexec(STDERR_FILENO, false);
- execvp("gpg", (char * const *) cmd);
- log_error_errno(errno, "Failed to execute gpg: %m");
- _exit(EXIT_FAILURE);
- }
+ if (unshare(CLONE_NEWNET) < 0)
+ log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m");
- gpg_pipe[0] = safe_close(gpg_pipe[0]);
+ r = capability_bounding_set_drop(~retain, true);
+ if (r < 0)
+ log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
- r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false);
- if (r < 0) {
- log_error_errno(r, "Failed to write to pipe: %m");
- goto finish;
+ execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
+ log_error_errno(errno, "Failed to execute tar: %m");
+ _exit(EXIT_FAILURE);
}
- gpg_pipe[1] = safe_close(gpg_pipe[1]);
-
- r = wait_for_terminate_and_warn("gpg", pid, true);
- pid = 0;
- if (r < 0)
- goto finish;
- if (r > 0) {
- log_error("Signature verification failed.");
- r = -EBADMSG;
- } else {
- log_info("Signature verification succeeded.");
- r = 0;
- }
+ pipefd[0] = safe_close(pipefd[0]);
+ r = pipefd[1];
+ pipefd[1] = -1;
-finish:
- if (sig_file >= 0)
- unlink(sig_file_path);
+ *ret = pid;
return r;
}
-int import_fork_tar(const char *path, pid_t *ret) {
+int import_fork_tar_c(const char *path, pid_t *ret) {
_cleanup_close_pair_ int pipefd[2] = { -1, -1 };
pid_t pid;
int r;
@@ -466,13 +167,7 @@ int import_fork_tar(const char *path, pid_t *ret) {
if (pid == 0) {
int null_fd;
- uint64_t retain =
- (1ULL << CAP_CHOWN) |
- (1ULL << CAP_FOWNER) |
- (1ULL << CAP_FSETID) |
- (1ULL << CAP_MKNOD) |
- (1ULL << CAP_SETFCAP) |
- (1ULL << CAP_DAC_OVERRIDE);
+ uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
/* Child */
@@ -480,28 +175,28 @@ int import_fork_tar(const char *path, pid_t *ret) {
reset_signal_mask();
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
- pipefd[1] = safe_close(pipefd[1]);
+ pipefd[0] = safe_close(pipefd[0]);
- if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) {
+ if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
_exit(EXIT_FAILURE);
}
- if (pipefd[0] != STDIN_FILENO)
- pipefd[0] = safe_close(pipefd[0]);
+ if (pipefd[1] != STDOUT_FILENO)
+ pipefd[1] = safe_close(pipefd[1]);
- null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
+ null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
if (null_fd < 0) {
log_error_errno(errno, "Failed to open /dev/null: %m");
_exit(EXIT_FAILURE);
}
- if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
+ if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
_exit(EXIT_FAILURE);
}
- if (null_fd != STDOUT_FILENO)
+ if (null_fd != STDIN_FILENO)
null_fd = safe_close(null_fd);
fd_cloexec(STDIN_FILENO, false);
@@ -515,14 +210,14 @@ int import_fork_tar(const char *path, pid_t *ret) {
if (r < 0)
log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
- execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
+ execlp("tar", "tar", "--sparse", "-C", path, "-c", ".", NULL);
log_error_errno(errno, "Failed to execute tar: %m");
_exit(EXIT_FAILURE);
}
- pipefd[0] = safe_close(pipefd[0]);
- r = pipefd[1];
- pipefd[1] = -1;
+ pipefd[1] = safe_close(pipefd[1]);
+ r = pipefd[0];
+ pipefd[0] = -1;
*ret = pid;
diff --git a/src/import/import-common.h b/src/import/import-common.h
index f6b4268fd7..7b60de80c2 100644
--- a/src/import/import-common.h
+++ b/src/import/import-common.h
@@ -21,21 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-
-#include "import-job.h"
-#include "import-util.h"
-
-int import_make_local_copy(const char *final, const char *root, const char *local, bool force_local);
-
-int import_find_old_etags(const char *url, const char *root, int dt, const char *prefix, const char *suffix, char ***etags);
-
int import_make_read_only_fd(int fd);
int import_make_read_only(const char *path);
-int import_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
-
-int import_make_verification_jobs(ImportJob **ret_checksum_job, ImportJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, ImportJobFinished on_finished, void *userdata);
-int import_verify(ImportJob *main_job, ImportJob *checksum_job, ImportJob *signature_job);
-
-int import_fork_tar(const char *path, pid_t *ret);
+int import_fork_tar_c(const char *path, pid_t *ret);
+int import_fork_tar_x(const char *path, pid_t *ret);
diff --git a/src/import/import-compress.c b/src/import/import-compress.c
new file mode 100644
index 0000000000..d6b8133036
--- /dev/null
+++ b/src/import/import-compress.c
@@ -0,0 +1,470 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "import-compress.h"
+
+void import_compress_free(ImportCompress *c) {
+ assert(c);
+
+ if (c->type == IMPORT_COMPRESS_XZ)
+ lzma_end(&c->xz);
+ else if (c->type == IMPORT_COMPRESS_GZIP) {
+ if (c->encoding)
+ deflateEnd(&c->gzip);
+ else
+ inflateEnd(&c->gzip);
+ } else if (c->type == IMPORT_COMPRESS_BZIP2) {
+ if (c->encoding)
+ BZ2_bzCompressEnd(&c->bzip2);
+ else
+ BZ2_bzDecompressEnd(&c->bzip2);
+ }
+
+ c->type = IMPORT_COMPRESS_UNKNOWN;
+}
+
+int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
+ static const uint8_t xz_signature[] = {
+ 0xfd, '7', 'z', 'X', 'Z', 0x00
+ };
+ static const uint8_t gzip_signature[] = {
+ 0x1f, 0x8b
+ };
+ static const uint8_t bzip2_signature[] = {
+ 'B', 'Z', 'h'
+ };
+
+ int r;
+
+ assert(c);
+
+ if (c->type != IMPORT_COMPRESS_UNKNOWN)
+ return 1;
+
+ if (size < MAX3(sizeof(xz_signature),
+ sizeof(gzip_signature),
+ sizeof(bzip2_signature)))
+ return 0;
+
+ assert(data);
+
+ if (memcmp(data, xz_signature, sizeof(xz_signature)) == 0) {
+ lzma_ret xzr;
+
+ xzr = lzma_stream_decoder(&c->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK);
+ if (xzr != LZMA_OK)
+ return -EIO;
+
+ c->type = IMPORT_COMPRESS_XZ;
+
+ } else if (memcmp(data, gzip_signature, sizeof(gzip_signature)) == 0) {
+ r = inflateInit2(&c->gzip, 15+16);
+ if (r != Z_OK)
+ return -EIO;
+
+ c->type = IMPORT_COMPRESS_GZIP;
+
+ } else if (memcmp(data, bzip2_signature, sizeof(bzip2_signature)) == 0) {
+ r = BZ2_bzDecompressInit(&c->bzip2, 0, 0);
+ if (r != BZ_OK)
+ return -EIO;
+
+ c->type = IMPORT_COMPRESS_BZIP2;
+ } else
+ c->type = IMPORT_COMPRESS_UNCOMPRESSED;
+
+ c->encoding = false;
+
+ return 1;
+}
+
+int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCompressCallback callback, void *userdata) {
+ int r;
+
+ assert(c);
+ assert(callback);
+
+ r = import_uncompress_detect(c, data, size);
+ if (r <= 0)
+ return r;
+
+ if (c->encoding)
+ return -EINVAL;
+
+ if (size <= 0)
+ return 1;
+
+ assert(data);
+
+ switch (c->type) {
+
+ case IMPORT_COMPRESS_UNCOMPRESSED:
+ r = callback(data, size, userdata);
+ if (r < 0)
+ return r;
+
+ break;
+
+ case IMPORT_COMPRESS_XZ:
+ c->xz.next_in = data;
+ c->xz.avail_in = size;
+
+ while (c->xz.avail_in > 0) {
+ uint8_t buffer[16 * 1024];
+ lzma_ret lzr;
+
+ c->xz.next_out = buffer;
+ c->xz.avail_out = sizeof(buffer);
+
+ lzr = lzma_code(&c->xz, LZMA_RUN);
+ if (lzr != LZMA_OK && lzr != LZMA_STREAM_END)
+ return -EIO;
+
+ r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata);
+ if (r < 0)
+ return r;
+ }
+
+ break;
+
+ case IMPORT_COMPRESS_GZIP:
+ c->gzip.next_in = (void*) data;
+ c->gzip.avail_in = size;
+
+ while (c->gzip.avail_in > 0) {
+ uint8_t buffer[16 * 1024];
+
+ c->gzip.next_out = buffer;
+ c->gzip.avail_out = sizeof(buffer);
+
+ r = inflate(&c->gzip, Z_NO_FLUSH);
+ if (r != Z_OK && r != Z_STREAM_END)
+ return -EIO;
+
+ r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata);
+ if (r < 0)
+ return r;
+ }
+
+ break;
+
+ case IMPORT_COMPRESS_BZIP2:
+ c->bzip2.next_in = (void*) data;
+ c->bzip2.avail_in = size;
+
+ while (c->bzip2.avail_in > 0) {
+ uint8_t buffer[16 * 1024];
+
+ c->bzip2.next_out = (char*) buffer;
+ c->bzip2.avail_out = sizeof(buffer);
+
+ r = BZ2_bzDecompress(&c->bzip2);
+ if (r != BZ_OK && r != BZ_STREAM_END)
+ return -EIO;
+
+ r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata);
+ if (r < 0)
+ return r;
+ }
+
+ break;
+
+ default:
+ assert_not_reached("Unknown compression");
+ }
+
+ return 1;
+}
+
+int import_compress_init(ImportCompress *c, ImportCompressType t) {
+ int r;
+
+ assert(c);
+
+ switch (t) {
+
+ case IMPORT_COMPRESS_XZ: {
+ lzma_ret xzr;
+
+ xzr = lzma_easy_encoder(&c->xz, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
+ if (xzr != LZMA_OK)
+ return -EIO;
+
+ c->type = IMPORT_COMPRESS_XZ;
+ break;
+ }
+
+ case IMPORT_COMPRESS_GZIP:
+ r = deflateInit2(&c->gzip, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
+ if (r != Z_OK)
+ return -EIO;
+
+ c->type = IMPORT_COMPRESS_GZIP;
+ break;
+
+ case IMPORT_COMPRESS_BZIP2:
+ r = BZ2_bzCompressInit(&c->bzip2, 9, 0, 0);
+ if (r != BZ_OK)
+ return -EIO;
+
+ c->type = IMPORT_COMPRESS_BZIP2;
+ break;
+
+ case IMPORT_COMPRESS_UNCOMPRESSED:
+ c->type = IMPORT_COMPRESS_UNCOMPRESSED;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ c->encoding = true;
+ return 0;
+}
+
+static int enlarge_buffer(void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
+ size_t l;
+ void *p;
+
+ if (*buffer_allocated > *buffer_size)
+ return 0;
+
+ l = MAX(16*1024U, (*buffer_size * 2));
+ p = realloc(*buffer, l);
+ if (!p)
+ return -ENOMEM;
+
+ *buffer = p;
+ *buffer_allocated = l;
+
+ return 1;
+}
+
+int import_compress(ImportCompress *c, const void *data, size_t size, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
+ int r;
+
+ assert(c);
+ assert(buffer);
+ assert(buffer_size);
+ assert(buffer_allocated);
+
+ if (!c->encoding)
+ return -EINVAL;
+
+ if (size <= 0)
+ return 0;
+
+ assert(data);
+
+ *buffer_size = 0;
+
+ switch (c->type) {
+
+ case IMPORT_COMPRESS_XZ:
+
+ c->xz.next_in = data;
+ c->xz.avail_in = size;
+
+ while (c->xz.avail_in > 0) {
+ lzma_ret lzr;
+
+ r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
+ if (r < 0)
+ return r;
+
+ c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
+ c->xz.avail_out = *buffer_allocated - *buffer_size;
+
+ lzr = lzma_code(&c->xz, LZMA_RUN);
+ if (lzr != LZMA_OK)
+ return -EIO;
+
+ *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
+ }
+
+ break;
+
+ case IMPORT_COMPRESS_GZIP:
+
+ c->gzip.next_in = (void*) data;
+ c->gzip.avail_in = size;
+
+ while (c->gzip.avail_in > 0) {
+ r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
+ if (r < 0)
+ return r;
+
+ c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
+ c->gzip.avail_out = *buffer_allocated - *buffer_size;
+
+ r = deflate(&c->gzip, Z_NO_FLUSH);
+ if (r != Z_OK)
+ return -EIO;
+
+ *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
+ }
+
+ break;
+
+ case IMPORT_COMPRESS_BZIP2:
+
+ c->bzip2.next_in = (void*) data;
+ c->bzip2.avail_in = size;
+
+ while (c->bzip2.avail_in > 0) {
+ r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
+ if (r < 0)
+ return r;
+
+ c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
+ c->bzip2.avail_out = *buffer_allocated - *buffer_size;
+
+ r = BZ2_bzCompress(&c->bzip2, BZ_RUN);
+ if (r != BZ_RUN_OK)
+ return -EIO;
+
+ *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
+ }
+
+ break;
+
+ case IMPORT_COMPRESS_UNCOMPRESSED:
+
+ if (*buffer_allocated < size) {
+ void *p;
+
+ p = realloc(*buffer, size);
+ if (!p)
+ return -ENOMEM;
+
+ *buffer = p;
+ *buffer_allocated = size;
+ }
+
+ memcpy(*buffer, data, size);
+ *buffer_size = size;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
+ int r;
+
+ assert(c);
+ assert(buffer);
+ assert(buffer_size);
+ assert(buffer_allocated);
+
+ if (!c->encoding)
+ return -EINVAL;
+
+ *buffer_size = 0;
+
+ switch (c->type) {
+
+ case IMPORT_COMPRESS_XZ: {
+ lzma_ret lzr;
+
+ c->xz.avail_in = 0;
+
+ do {
+ r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
+ if (r < 0)
+ return r;
+
+ c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
+ c->xz.avail_out = *buffer_allocated - *buffer_size;
+
+ lzr = lzma_code(&c->xz, LZMA_FINISH);
+ if (lzr != LZMA_OK && lzr != LZMA_STREAM_END)
+ return -EIO;
+
+ *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
+ } while (lzr != LZMA_STREAM_END);
+
+ break;
+ }
+
+ case IMPORT_COMPRESS_GZIP:
+ c->gzip.avail_in = 0;
+
+ do {
+ r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
+ if (r < 0)
+ return r;
+
+ c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
+ c->gzip.avail_out = *buffer_allocated - *buffer_size;
+
+ r = deflate(&c->gzip, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END)
+ return -EIO;
+
+ *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
+ } while (r != Z_STREAM_END);
+
+ break;
+
+ case IMPORT_COMPRESS_BZIP2:
+ c->bzip2.avail_in = 0;
+
+ do {
+ r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
+ if (r < 0)
+ return r;
+
+ c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
+ c->bzip2.avail_out = *buffer_allocated - *buffer_size;
+
+ r = BZ2_bzCompress(&c->bzip2, BZ_FINISH);
+ if (r != BZ_FINISH_OK && r != BZ_STREAM_END)
+ return -EIO;
+
+ *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
+ } while (r != BZ_STREAM_END);
+
+ break;
+
+ case IMPORT_COMPRESS_UNCOMPRESSED:
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static const char* const import_compress_type_table[_IMPORT_COMPRESS_TYPE_MAX] = {
+ [IMPORT_COMPRESS_UNKNOWN] = "unknown",
+ [IMPORT_COMPRESS_UNCOMPRESSED] = "uncompressed",
+ [IMPORT_COMPRESS_XZ] = "xz",
+ [IMPORT_COMPRESS_GZIP] = "gzip",
+ [IMPORT_COMPRESS_BZIP2] = "bzip2",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);
diff --git a/src/import/import-compress.h b/src/import/import-compress.h
new file mode 100644
index 0000000000..50d91f732c
--- /dev/null
+++ b/src/import/import-compress.h
@@ -0,0 +1,64 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+
+#include <lzma.h>
+#include <zlib.h>
+#include <bzlib.h>
+
+#include "macro.h"
+
+typedef enum ImportCompressType {
+ IMPORT_COMPRESS_UNKNOWN,
+ IMPORT_COMPRESS_UNCOMPRESSED,
+ IMPORT_COMPRESS_XZ,
+ IMPORT_COMPRESS_GZIP,
+ IMPORT_COMPRESS_BZIP2,
+ _IMPORT_COMPRESS_TYPE_MAX,
+ _IMPORT_COMPRESS_TYPE_INVALID = -1,
+} ImportCompressType;
+
+typedef struct ImportCompress {
+ ImportCompressType type;
+ bool encoding;
+ union {
+ lzma_stream xz;
+ z_stream gzip;
+ bz_stream bzip2;
+ };
+} ImportCompress;
+
+typedef int (*ImportCompressCallback)(const void *data, size_t size, void *userdata);
+
+void import_compress_free(ImportCompress *c);
+
+int import_uncompress_detect(ImportCompress *c, const void *data, size_t size);
+int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCompressCallback callback, void *userdata);
+
+int import_compress_init(ImportCompress *c, ImportCompressType t);
+int import_compress(ImportCompress *c, const void *data, size_t size, void **buffer, size_t *buffer_size, size_t *buffer_allocated);
+int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size, size_t *buffer_allocated);
+
+const char* import_compress_type_to_string(ImportCompressType t) _const_;
+ImportCompressType import_compress_type_from_string(const char *s) _pure_;
diff --git a/src/import/import-job.h b/src/import/import-job.h
deleted file mode 100644
index dcf89cb28c..0000000000
--- a/src/import/import-job.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2015 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <lzma.h>
-#include <zlib.h>
-#include <bzlib.h>
-#include <gcrypt.h>
-
-#include "macro.h"
-#include "curl-util.h"
-
-typedef struct ImportJob ImportJob;
-
-typedef void (*ImportJobFinished)(ImportJob *job);
-typedef int (*ImportJobOpenDisk)(ImportJob *job);
-typedef int (*ImportJobHeader)(ImportJob *job, const char *header, size_t sz);
-typedef void (*ImportJobProgress)(ImportJob *job);
-
-typedef enum ImportJobState {
- IMPORT_JOB_INIT,
- IMPORT_JOB_ANALYZING, /* Still reading into ->payload, to figure out what we have */
- IMPORT_JOB_RUNNING, /* Writing to destination */
- IMPORT_JOB_DONE,
- IMPORT_JOB_FAILED,
- _IMPORT_JOB_STATE_MAX,
- _IMPORT_JOB_STATE_INVALID = -1,
-} ImportJobState;
-
-#define IMPORT_JOB_STATE_IS_COMPLETE(j) (IN_SET((j)->state, IMPORT_JOB_DONE, IMPORT_JOB_FAILED))
-
-typedef enum ImportJobCompression {
- IMPORT_JOB_UNCOMPRESSED,
- IMPORT_JOB_XZ,
- IMPORT_JOB_GZIP,
- IMPORT_JOB_BZIP2,
- _IMPORT_JOB_COMPRESSION_MAX,
- _IMPORT_JOB_COMPRESSION_INVALID = -1,
-} ImportJobCompression;
-
-struct ImportJob {
- ImportJobState state;
- int error;
-
- char *url;
-
- void *userdata;
- ImportJobFinished on_finished;
- ImportJobOpenDisk on_open_disk;
- ImportJobHeader on_header;
- ImportJobProgress on_progress;
-
- CurlGlue *glue;
- CURL *curl;
- struct curl_slist *request_header;
-
- char *etag;
- char **old_etags;
- bool etag_exists;
-
- uint64_t content_length;
- uint64_t written_compressed;
- uint64_t written_uncompressed;
-
- uint64_t uncompressed_max;
- uint64_t compressed_max;
-
- uint8_t *payload;
- size_t payload_size;
- size_t payload_allocated;
-
- int disk_fd;
-
- usec_t mtime;
-
- ImportJobCompression compressed;
- lzma_stream xz;
- z_stream gzip;
- bz_stream bzip2;
-
- unsigned progress_percent;
- usec_t start_usec;
- usec_t last_status_usec;
-
- bool allow_sparse;
-
- bool calc_checksum;
- gcry_md_hd_t checksum_context;
-
- char *checksum;
-};
-
-int import_job_new(ImportJob **job, const char *url, CurlGlue *glue, void *userdata);
-ImportJob* import_job_unref(ImportJob *job);
-
-int import_job_begin(ImportJob *j);
-
-void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(ImportJob*, import_job_unref);
diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index 8d99f1085c..97e1254f09 100644
--- a/src/import/import-raw.c
+++ b/src/import/import-raw.c
@@ -3,7 +3,7 @@
/***
This file is part of systemd.
- Copyright 2014 Lennart Poettering
+ Copyright 2015 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -19,64 +19,64 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/xattr.h>
#include <linux/fs.h>
-#include <curl/curl.h>
#include "sd-daemon.h"
-#include "utf8.h"
-#include "strv.h"
-#include "copy.h"
-#include "btrfs-util.h"
+#include "sd-event.h"
#include "util.h"
-#include "macro.h"
+#include "path-util.h"
+#include "btrfs-util.h"
+#include "copy.h"
#include "mkdir.h"
-#include "import-util.h"
-#include "curl-util.h"
+#include "rm-rf.h"
+#include "ratelimit.h"
+#include "machine-pool.h"
#include "qcow2-util.h"
-#include "import-job.h"
+#include "import-compress.h"
#include "import-common.h"
#include "import-raw.h"
-typedef enum RawProgress {
- RAW_DOWNLOADING,
- RAW_VERIFYING,
- RAW_UNPACKING,
- RAW_FINALIZING,
- RAW_COPYING,
-} RawProgress;
-
struct RawImport {
sd_event *event;
- CurlGlue *glue;
char *image_root;
- ImportJob *raw_job;
- ImportJob *checksum_job;
- ImportJob *signature_job;
-
RawImportFinished on_finished;
void *userdata;
char *local;
bool force_local;
+ bool read_only;
+ bool grow_machine_directory;
char *temp_path;
char *final_path;
- ImportVerify verify;
+ int input_fd;
+ int output_fd;
+
+ ImportCompress compress;
+
+ uint64_t written_since_last_grow;
+
+ sd_event_source *input_event_source;
+
+ uint8_t buffer[16*1024];
+ size_t buffer_size;
+
+ uint64_t written_compressed;
+ uint64_t written_uncompressed;
+
+ struct stat st;
+
+ unsigned last_percent;
+ RateLimit progress_rate_limit;
};
RawImport* raw_import_unref(RawImport *i) {
if (!i)
return NULL;
- import_job_unref(i->raw_job);
- import_job_unref(i->checksum_job);
- import_job_unref(i->signature_job);
-
- curl_glue_unref(i->glue);
sd_event_unref(i->event);
if (i->temp_path) {
@@ -84,6 +84,12 @@ RawImport* raw_import_unref(RawImport *i) {
free(i->temp_path);
}
+ import_compress_free(&i->compress);
+
+ sd_event_source_unref(i->input_event_source);
+
+ safe_close(i->output_fd);
+
free(i->final_path);
free(i->image_root);
free(i->local);
@@ -108,13 +114,19 @@ int raw_import_new(
if (!i)
return -ENOMEM;
+ i->input_fd = i->output_fd = -1;
i->on_finished = on_finished;
i->userdata = userdata;
+ RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
+ i->last_percent = (unsigned) -1;
+
i->image_root = strdup(image_root ?: "/var/lib/machines");
if (!i->image_root)
return -ENOMEM;
+ i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
+
if (event)
i->event = sd_event_ref(event);
else {
@@ -123,68 +135,35 @@ int raw_import_new(
return r;
}
- r = curl_glue_new(&i->glue, i->event);
- if (r < 0)
- return r;
-
- i->glue->on_finished = import_job_curl_on_finished;
- i->glue->userdata = i;
-
*ret = i;
i = NULL;
return 0;
}
-static void raw_import_report_progress(RawImport *i, RawProgress p) {
+static void raw_import_report_progress(RawImport *i) {
unsigned percent;
-
assert(i);
- switch (p) {
-
- case RAW_DOWNLOADING: {
- unsigned remain = 80;
-
- percent = 0;
-
- if (i->checksum_job) {
- percent += i->checksum_job->progress_percent * 5 / 100;
- remain -= 5;
- }
-
- if (i->signature_job) {
- percent += i->signature_job->progress_percent * 5 / 100;
- remain -= 5;
- }
-
- if (i->raw_job)
- percent += i->raw_job->progress_percent * remain / 100;
- break;
- }
-
- case RAW_VERIFYING:
- percent = 80;
- break;
-
- case RAW_UNPACKING:
- percent = 85;
- break;
+ /* We have no size information, unless the source is a regular file */
+ if (!S_ISREG(i->st.st_mode))
+ return;
- case RAW_FINALIZING:
- percent = 90;
- break;
+ if (i->written_compressed >= (uint64_t) i->st.st_size)
+ percent = 100;
+ else
+ percent = (unsigned) ((i->written_compressed * UINT64_C(100)) / (uint64_t) i->st.st_size);
- case RAW_COPYING:
- percent = 95;
- break;
+ if (percent == i->last_percent)
+ return;
- default:
- assert_not_reached("Unknown progress state");
- }
+ if (!ratelimit_test(&i->progress_rate_limit))
+ return;
sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
- log_debug("Combined progress %u%%", percent);
+ log_info("Imported %u%%.", percent);
+
+ i->last_percent = percent;
}
static int raw_import_maybe_convert_qcow2(RawImport *i) {
@@ -193,9 +172,8 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) {
int r;
assert(i);
- assert(i->raw_job);
- r = qcow2_detect(i->raw_job->disk_fd);
+ r = qcow2_detect(i->output_fd);
if (r < 0)
return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m");
if (r == 0)
@@ -206,308 +184,278 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) {
if (r < 0)
return log_oom();
- converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0644);
+ converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
if (converted_fd < 0)
return log_error_errno(errno, "Failed to create %s: %m", t);
- r = chattr_fd(converted_fd, true, FS_NOCOW_FL);
+ r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);
log_info("Unpacking QCOW2 file.");
- r = qcow2_convert(i->raw_job->disk_fd, converted_fd);
+ r = qcow2_convert(i->output_fd, converted_fd);
if (r < 0) {
unlink(t);
return log_error_errno(r, "Failed to convert qcow2 image: %m");
}
- unlink(i->temp_path);
+ (void) unlink(i->temp_path);
free(i->temp_path);
-
i->temp_path = t;
t = NULL;
- safe_close(i->raw_job->disk_fd);
- i->raw_job->disk_fd = converted_fd;
+ safe_close(i->output_fd);
+ i->output_fd = converted_fd;
converted_fd = -1;
return 1;
}
-static int raw_import_make_local_copy(RawImport *i) {
- _cleanup_free_ char *tp = NULL;
- _cleanup_close_ int dfd = -1;
- const char *p;
+static int raw_import_finish(RawImport *i) {
int r;
assert(i);
- assert(i->raw_job);
+ assert(i->output_fd >= 0);
+ assert(i->temp_path);
+ assert(i->final_path);
+
+ /* In case this was a sparse file, make sure the file system is right */
+ if (i->written_uncompressed > 0) {
+ if (ftruncate(i->output_fd, i->written_uncompressed) < 0)
+ return log_error_errno(errno, "Failed to truncate file: %m");
+ }
- if (!i->local)
- return 0;
+ r = raw_import_maybe_convert_qcow2(i);
+ if (r < 0)
+ return r;
- if (i->raw_job->etag_exists) {
- /* We have downloaded this one previously, reopen it */
+ if (S_ISREG(i->st.st_mode)) {
+ (void) copy_times(i->input_fd, i->output_fd);
+ (void) copy_xattr(i->input_fd, i->output_fd);
+ }
- assert(i->raw_job->disk_fd < 0);
+ if (i->read_only) {
+ r = import_make_read_only_fd(i->output_fd);
+ if (r < 0)
+ return r;
+ }
- if (!i->final_path) {
- r = import_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", ".raw", &i->final_path);
- if (r < 0)
- return log_oom();
- }
+ if (i->force_local)
+ (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
- i->raw_job->disk_fd = open(i->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (i->raw_job->disk_fd < 0)
- return log_error_errno(errno, "Failed to open vendor image: %m");
- } else {
- /* We freshly downloaded the image, use it */
+ r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to move image into place: %m");
- assert(i->raw_job->disk_fd >= 0);
+ free(i->temp_path);
+ i->temp_path = NULL;
- if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) == (off_t) -1)
- return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
- }
+ return 0;
+}
- p = strjoina(i->image_root, "/", i->local, ".raw");
+static int raw_import_open_disk(RawImport *i) {
+ int r;
- if (i->force_local) {
- (void) btrfs_subvol_remove(p);
- (void) rm_rf_dangerous(p, false, true, false);
- }
+ assert(i);
- r = tempfn_random(p, &tp);
+ assert(!i->final_path);
+ assert(!i->temp_path);
+ assert(i->output_fd < 0);
+
+ i->final_path = strjoin(i->image_root, "/", i->local, ".raw", NULL);
+ if (!i->final_path)
+ return log_oom();
+
+ r = tempfn_random(i->final_path, &i->temp_path);
if (r < 0)
return log_oom();
- dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
- if (dfd < 0)
- return log_error_errno(errno, "Failed to create writable copy of image: %m");
+ (void) mkdir_parents_label(i->temp_path, 0700);
- /* Turn off COW writing. This should greatly improve
- * performance on COW file systems like btrfs, since it
- * reduces fragmentation caused by not allowing in-place
- * writes. */
- r = chattr_fd(dfd, true, FS_NOCOW_FL);
+ i->output_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+ if (i->output_fd < 0)
+ return log_error_errno(errno, "Failed to open destination %s: %m", i->temp_path);
+
+ r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp);
+ log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
- r = copy_bytes(i->raw_job->disk_fd, dfd, (off_t) -1, true);
- if (r < 0) {
- unlink(tp);
- return log_error_errno(r, "Failed to make writable copy of image: %m");
- }
+ return 0;
+}
- (void) copy_times(i->raw_job->disk_fd, dfd);
- (void) copy_xattr(i->raw_job->disk_fd, dfd);
+static int raw_import_try_reflink(RawImport *i) {
+ off_t p;
+ int r;
- dfd = safe_close(dfd);
+ assert(i);
+ assert(i->input_fd >= 0);
+ assert(i->output_fd >= 0);
- r = rename(tp, p);
- if (r < 0) {
- unlink(tp);
- return log_error_errno(errno, "Failed to move writable image into place: %m");
- }
+ if (i->compress.type != IMPORT_COMPRESS_UNCOMPRESSED)
+ return 0;
+
+ if (!S_ISREG(i->st.st_mode))
+ return 0;
+
+ p = lseek(i->input_fd, 0, SEEK_CUR);
+ if (p == (off_t) -1)
+ return log_error_errno(errno, "Failed to read file offset of input file: %m");
+
+ /* Let's only try a btrfs reflink, if we are reading from the beginning of the file */
+ if ((uint64_t) p != (uint64_t) i->buffer_size)
+ return 0;
+
+ r = btrfs_reflink(i->input_fd, i->output_fd);
+ if (r >= 0)
+ return 1;
- log_info("Created new local image '%s'.", i->local);
return 0;
}
-static bool raw_import_is_done(RawImport *i) {
- assert(i);
- assert(i->raw_job);
+static int raw_import_write(const void *p, size_t sz, void *userdata) {
+ RawImport *i = userdata;
+ ssize_t n;
+
+ if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) {
+ i->written_since_last_grow = 0;
+ grow_machine_directory();
+ }
- if (i->raw_job->state != IMPORT_JOB_DONE)
- return false;
- if (i->checksum_job && i->checksum_job->state != IMPORT_JOB_DONE)
- return false;
- if (i->signature_job && i->signature_job->state != IMPORT_JOB_DONE)
- return false;
+ n = sparse_write(i->output_fd, p, sz, 64);
+ if (n < 0)
+ return -errno;
+ if ((size_t) n < sz)
+ return -EIO;
- return true;
+ i->written_uncompressed += sz;
+ i->written_since_last_grow += sz;
+
+ return 0;
}
-static void raw_import_job_on_finished(ImportJob *j) {
- RawImport *i;
+static int raw_import_process(RawImport *i) {
+ ssize_t l;
int r;
- assert(j);
- assert(j->userdata);
+ assert(i);
+ assert(i->buffer_size < sizeof(i->buffer));
- i = j->userdata;
- if (j->error != 0) {
- if (j == i->checksum_job)
- log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
- else if (j == i->signature_job)
- log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
- else
- log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
+ l = read(i->input_fd, i->buffer + i->buffer_size, sizeof(i->buffer) - i->buffer_size);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
- r = j->error;
+ r = log_error_errno(errno, "Failed to read input file: %m");
goto finish;
}
+ if (l == 0) {
+ if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
+ log_error("Premature end of file: %m");
+ r = -EIO;
+ goto finish;
+ }
- /* This is invoked if either the download completed
- * successfully, or the download was skipped because we
- * already have the etag. In this case ->etag_exists is
- * true.
- *
- * We only do something when we got all three files */
-
- if (!raw_import_is_done(i))
- return;
-
- if (!i->raw_job->etag_exists) {
- /* This is a new download, verify it, and move it into place */
- assert(i->raw_job->disk_fd >= 0);
+ r = raw_import_finish(i);
+ goto finish;
+ }
- raw_import_report_progress(i, RAW_VERIFYING);
+ i->buffer_size += l;
- r = import_verify(i->raw_job, i->checksum_job, i->signature_job);
- if (r < 0)
+ if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
+ r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size);
+ if (r < 0) {
+ log_error("Failed to detect file compression: %m");
goto finish;
+ }
+ if (r == 0) /* Need more data */
+ return 0;
- raw_import_report_progress(i, RAW_UNPACKING);
-
- r = raw_import_maybe_convert_qcow2(i);
+ r = raw_import_open_disk(i);
if (r < 0)
goto finish;
- raw_import_report_progress(i, RAW_FINALIZING);
-
- r = import_make_read_only_fd(i->raw_job->disk_fd);
+ r = raw_import_try_reflink(i);
if (r < 0)
goto finish;
-
- r = rename(i->temp_path, i->final_path);
- if (r < 0) {
- r = log_error_errno(errno, "Failed to move RAW file into place: %m");
+ if (r > 0) {
+ r = raw_import_finish(i);
goto finish;
}
+ }
- free(i->temp_path);
- i->temp_path = NULL;
+ r = import_uncompress(&i->compress, i->buffer, i->buffer_size, raw_import_write, i);
+ if (r < 0) {
+ log_error_errno(r, "Failed to decode and write: %m");
+ goto finish;
}
- raw_import_report_progress(i, RAW_COPYING);
+ i->written_compressed += i->buffer_size;
+ i->buffer_size = 0;
- r = raw_import_make_local_copy(i);
- if (r < 0)
- goto finish;
+ raw_import_report_progress(i);
- r = 0;
+ return 0;
finish:
if (i->on_finished)
i->on_finished(i, r, i->userdata);
else
sd_event_exit(i->event, r);
-}
-
-static int raw_import_job_on_open_disk(ImportJob *j) {
- RawImport *i;
- int r;
-
- assert(j);
- assert(j->userdata);
-
- i = j->userdata;
- assert(i->raw_job == j);
- assert(!i->final_path);
- assert(!i->temp_path);
-
- r = import_make_path(j->url, j->etag, i->image_root, ".raw-", ".raw", &i->final_path);
- if (r < 0)
- return log_oom();
-
- r = tempfn_random(i->final_path, &i->temp_path);
- if (r <0)
- return log_oom();
-
- mkdir_parents_label(i->temp_path, 0700);
-
- j->disk_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0644);
- if (j->disk_fd < 0)
- return log_error_errno(errno, "Failed to create %s: %m", i->temp_path);
-
- r = chattr_fd(j->disk_fd, true, FS_NOCOW_FL);
- if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
return 0;
}
-static void raw_import_job_on_progress(ImportJob *j) {
- RawImport *i;
+static int raw_import_on_input(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ RawImport *i = userdata;
- assert(j);
- assert(j->userdata);
+ return raw_import_process(i);
+}
- i = j->userdata;
+static int raw_import_on_defer(sd_event_source *s, void *userdata) {
+ RawImport *i = userdata;
- raw_import_report_progress(i, RAW_DOWNLOADING);
+ return raw_import_process(i);
}
-int raw_import_pull(RawImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
+int raw_import_start(RawImport *i, int fd, const char *local, bool force_local, bool read_only) {
int r;
assert(i);
- assert(verify < _IMPORT_VERIFY_MAX);
- assert(verify >= 0);
+ assert(fd >= 0);
+ assert(local);
- if (!http_url_is_valid(url))
+ if (!machine_name_is_valid(local))
return -EINVAL;
- if (local && !machine_name_is_valid(local))
- return -EINVAL;
-
- if (i->raw_job)
+ if (i->input_fd >= 0)
return -EBUSY;
- r = free_and_strdup(&i->local, local);
+ r = fd_nonblock(fd, true);
if (r < 0)
return r;
- i->force_local = force_local;
- i->verify = verify;
- /* Queue job for the image itself */
- r = import_job_new(&i->raw_job, url, i->glue, i);
- if (r < 0)
- return r;
-
- i->raw_job->on_finished = raw_import_job_on_finished;
- i->raw_job->on_open_disk = raw_import_job_on_open_disk;
- i->raw_job->on_progress = raw_import_job_on_progress;
- i->raw_job->calc_checksum = verify != IMPORT_VERIFY_NO;
-
- r = import_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags);
- if (r < 0)
- return r;
-
- r = import_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_import_job_on_finished, i);
- if (r < 0)
- return r;
-
- r = import_job_begin(i->raw_job);
+ r = free_and_strdup(&i->local, local);
if (r < 0)
return r;
+ i->force_local = force_local;
+ i->read_only = read_only;
- if (i->checksum_job) {
- i->checksum_job->on_progress = raw_import_job_on_progress;
+ if (fstat(fd, &i->st) < 0)
+ return -errno;
- r = import_job_begin(i->checksum_job);
+ r = sd_event_add_io(i->event, &i->input_event_source, fd, EPOLLIN, raw_import_on_input, i);
+ if (r == -EPERM) {
+ /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
+ r = sd_event_add_defer(i->event, &i->input_event_source, raw_import_on_defer, i);
if (r < 0)
return r;
- }
- if (i->signature_job) {
- i->signature_job->on_progress = raw_import_job_on_progress;
-
- r = import_job_begin(i->signature_job);
- if (r < 0)
- return r;
+ r = sd_event_source_set_enabled(i->input_event_source, SD_EVENT_ON);
}
+ if (r < 0)
+ return r;
- return 0;
+ i->input_fd = fd;
+ return r;
}
diff --git a/src/import/import-raw.h b/src/import/import-raw.h
index ae2c29991f..bf7c770340 100644
--- a/src/import/import-raw.h
+++ b/src/import/import-raw.h
@@ -5,7 +5,7 @@
/***
This file is part of systemd.
- Copyright 2014 Lennart Poettering
+ Copyright 2015 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -34,4 +34,4 @@ RawImport* raw_import_unref(RawImport *import);
DEFINE_TRIVIAL_CLEANUP_FUNC(RawImport*, raw_import_unref);
-int raw_import_pull(RawImport *import, const char *url, const char *local, bool force_local, ImportVerify verify);
+int raw_import_start(RawImport *i, int fd, const char *local, bool force_local, bool read_only);
diff --git a/src/import/import-tar.c b/src/import/import-tar.c
index 999aa8ab5e..12701bfcef 100644
--- a/src/import/import-tar.c
+++ b/src/import/import-tar.c
@@ -19,76 +19,85 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/prctl.h>
-#include <curl/curl.h>
+#include <linux/fs.h>
#include "sd-daemon.h"
-#include "utf8.h"
-#include "strv.h"
-#include "copy.h"
-#include "btrfs-util.h"
+#include "sd-event.h"
#include "util.h"
-#include "macro.h"
+#include "path-util.h"
+#include "btrfs-util.h"
+#include "copy.h"
#include "mkdir.h"
-#include "import-util.h"
-#include "curl-util.h"
-#include "import-job.h"
+#include "rm-rf.h"
+#include "ratelimit.h"
+#include "machine-pool.h"
+#include "qcow2-util.h"
+#include "import-compress.h"
#include "import-common.h"
#include "import-tar.h"
-
-typedef enum TarProgress {
- TAR_DOWNLOADING,
- TAR_VERIFYING,
- TAR_FINALIZING,
- TAR_COPYING,
-} TarProgress;
+#include "process-util.h"
struct TarImport {
sd_event *event;
- CurlGlue *glue;
char *image_root;
- ImportJob *tar_job;
- ImportJob *checksum_job;
- ImportJob *signature_job;
-
TarImportFinished on_finished;
void *userdata;
char *local;
bool force_local;
-
- pid_t tar_pid;
+ bool read_only;
+ bool grow_machine_directory;
char *temp_path;
char *final_path;
- ImportVerify verify;
+ int input_fd;
+ int tar_fd;
+
+ ImportCompress compress;
+
+ uint64_t written_since_last_grow;
+
+ sd_event_source *input_event_source;
+
+ uint8_t buffer[16*1024];
+ size_t buffer_size;
+
+ uint64_t written_compressed;
+ uint64_t written_uncompressed;
+
+ struct stat st;
+
+ pid_t tar_pid;
+
+ unsigned last_percent;
+ RateLimit progress_rate_limit;
};
TarImport* tar_import_unref(TarImport *i) {
if (!i)
return NULL;
+ sd_event_source_unref(i->input_event_source);
+
if (i->tar_pid > 1) {
(void) kill_and_sigcont(i->tar_pid, SIGKILL);
(void) wait_for_terminate(i->tar_pid, NULL);
}
- import_job_unref(i->tar_job);
- import_job_unref(i->checksum_job);
- import_job_unref(i->signature_job);
-
- curl_glue_unref(i->glue);
- sd_event_unref(i->event);
-
if (i->temp_path) {
- (void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf_dangerous(i->temp_path, false, true, false);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(i->temp_path);
}
+ import_compress_free(&i->compress);
+
+ sd_event_unref(i->event);
+
+ safe_close(i->tar_fd);
+
free(i->final_path);
free(i->image_root);
free(i->local);
@@ -108,19 +117,24 @@ int tar_import_new(
int r;
assert(ret);
- assert(event);
i = new0(TarImport, 1);
if (!i)
return -ENOMEM;
+ i->input_fd = i->tar_fd = -1;
i->on_finished = on_finished;
i->userdata = userdata;
+ RATELIMIT_INIT(i->progress_rate_limit, 100 * USEC_PER_MSEC, 1);
+ i->last_percent = (unsigned) -1;
+
i->image_root = strdup(image_root ?: "/var/lib/machines");
if (!i->image_root)
return -ENOMEM;
+ i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
+
if (event)
i->event = sd_event_ref(event);
else {
@@ -129,282 +143,239 @@ int tar_import_new(
return r;
}
- r = curl_glue_new(&i->glue, i->event);
- if (r < 0)
- return r;
-
- i->glue->on_finished = import_job_curl_on_finished;
- i->glue->userdata = i;
-
*ret = i;
i = NULL;
return 0;
}
-static void tar_import_report_progress(TarImport *i, TarProgress p) {
+static void tar_import_report_progress(TarImport *i) {
unsigned percent;
-
assert(i);
- switch (p) {
+ /* We have no size information, unless the source is a regular file */
+ if (!S_ISREG(i->st.st_mode))
+ return;
- case TAR_DOWNLOADING: {
- unsigned remain = 85;
+ if (i->written_compressed >= (uint64_t) i->st.st_size)
+ percent = 100;
+ else
+ percent = (unsigned) ((i->written_compressed * UINT64_C(100)) / (uint64_t) i->st.st_size);
- percent = 0;
+ if (percent == i->last_percent)
+ return;
- if (i->checksum_job) {
- percent += i->checksum_job->progress_percent * 5 / 100;
- remain -= 5;
- }
+ if (!ratelimit_test(&i->progress_rate_limit))
+ return;
- if (i->signature_job) {
- percent += i->signature_job->progress_percent * 5 / 100;
- remain -= 5;
- }
+ sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
+ log_info("Imported %u%%.", percent);
- if (i->tar_job)
- percent += i->tar_job->progress_percent * remain / 100;
- break;
- }
+ i->last_percent = percent;
+}
- case TAR_VERIFYING:
- percent = 85;
- break;
+static int tar_import_finish(TarImport *i) {
+ int r;
- case TAR_FINALIZING:
- percent = 90;
- break;
+ assert(i);
+ assert(i->tar_fd >= 0);
+ assert(i->temp_path);
+ assert(i->final_path);
- case TAR_COPYING:
- percent = 95;
- break;
+ i->tar_fd = safe_close(i->tar_fd);
- default:
- assert_not_reached("Unknown progress state");
+ if (i->tar_pid > 0) {
+ r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
+ i->tar_pid = 0;
+ if (r < 0)
+ return r;
}
- sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
- log_debug("Combined progress %u%%", percent);
+ if (i->read_only) {
+ r = import_make_read_only(i->temp_path);
+ if (r < 0)
+ return r;
+ }
+
+ if (i->force_local)
+ (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+
+ r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to move image into place: %m");
+
+ free(i->temp_path);
+ i->temp_path = NULL;
+
+ return 0;
}
-static int tar_import_make_local_copy(TarImport *i) {
+static int tar_import_fork_tar(TarImport *i) {
int r;
assert(i);
- assert(i->tar_job);
- if (!i->local)
- return 0;
+ assert(!i->final_path);
+ assert(!i->temp_path);
+ assert(i->tar_fd < 0);
- if (!i->final_path) {
- r = import_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
- if (r < 0)
- return log_oom();
- }
+ i->final_path = strjoin(i->image_root, "/", i->local, NULL);
+ if (!i->final_path)
+ return log_oom();
- r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
+ r = tempfn_random(i->final_path, &i->temp_path);
if (r < 0)
- return r;
+ return log_oom();
- return 0;
-}
+ (void) mkdir_parents_label(i->temp_path, 0700);
-static bool tar_import_is_done(TarImport *i) {
- assert(i);
- assert(i->tar_job);
+ r = btrfs_subvol_make(i->temp_path);
+ if (r == -ENOTTY) {
+ if (mkdir(i->temp_path, 0755) < 0)
+ return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
+ } else if (r < 0)
+ return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
- if (i->tar_job->state != IMPORT_JOB_DONE)
- return false;
- if (i->checksum_job && i->checksum_job->state != IMPORT_JOB_DONE)
- return false;
- if (i->signature_job && i->signature_job->state != IMPORT_JOB_DONE)
- return false;
+ i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
+ if (i->tar_fd < 0)
+ return i->tar_fd;
- return true;
+ return 0;
}
-static void tar_import_job_on_finished(ImportJob *j) {
- TarImport *i;
+static int tar_import_write(const void *p, size_t sz, void *userdata) {
+ TarImport *i = userdata;
int r;
- assert(j);
- assert(j->userdata);
-
- i = j->userdata;
- if (j->error != 0) {
- if (j == i->checksum_job)
- log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
- else if (j == i->signature_job)
- log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
- else
- log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
-
- r = j->error;
- goto finish;
+ if (i->grow_machine_directory && i->written_since_last_grow >= GROW_INTERVAL_BYTES) {
+ i->written_since_last_grow = 0;
+ grow_machine_directory();
}
- /* This is invoked if either the download completed
- * successfully, or the download was skipped because we
- * already have the etag. */
+ r = loop_write(i->tar_fd, p, sz, false);
+ if (r < 0)
+ return r;
- if (!tar_import_is_done(i))
- return;
+ i->written_uncompressed += sz;
+ i->written_since_last_grow += sz;
- j->disk_fd = safe_close(i->tar_job->disk_fd);
+ return 0;
+}
- if (i->tar_pid > 0) {
- r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
- i->tar_pid = 0;
- if (r < 0)
- goto finish;
- }
+static int tar_import_process(TarImport *i) {
+ ssize_t l;
+ int r;
- if (!i->tar_job->etag_exists) {
- /* This is a new download, verify it, and move it into place */
+ assert(i);
+ assert(i->buffer_size < sizeof(i->buffer));
- tar_import_report_progress(i, TAR_VERIFYING);
+ l = read(i->input_fd, i->buffer + i->buffer_size, sizeof(i->buffer) - i->buffer_size);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
- r = import_verify(i->tar_job, i->checksum_job, i->signature_job);
- if (r < 0)
+ r = log_error_errno(errno, "Failed to read input file: %m");
+ goto finish;
+ }
+ if (l == 0) {
+ if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
+ log_error("Premature end of file: %m");
+ r = -EIO;
goto finish;
+ }
+
+ r = tar_import_finish(i);
+ goto finish;
+ }
- tar_import_report_progress(i, TAR_FINALIZING);
+ i->buffer_size += l;
- r = import_make_read_only(i->temp_path);
- if (r < 0)
+ if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) {
+ r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size);
+ if (r < 0) {
+ log_error("Failed to detect file compression: %m");
goto finish;
+ }
+ if (r == 0) /* Need more data */
+ return 0;
- if (rename(i->temp_path, i->final_path) < 0) {
- r = log_error_errno(errno, "Failed to rename to final image name: %m");
+ r = tar_import_fork_tar(i);
+ if (r < 0)
goto finish;
- }
+ }
- free(i->temp_path);
- i->temp_path = NULL;
+ r = import_uncompress(&i->compress, i->buffer, i->buffer_size, tar_import_write, i);
+ if (r < 0) {
+ log_error_errno(r, "Failed to decode and write: %m");
+ goto finish;
}
- tar_import_report_progress(i, TAR_COPYING);
+ i->written_compressed += i->buffer_size;
+ i->buffer_size = 0;
- r = tar_import_make_local_copy(i);
- if (r < 0)
- goto finish;
+ tar_import_report_progress(i);
- r = 0;
+ return 0;
finish:
if (i->on_finished)
i->on_finished(i, r, i->userdata);
else
sd_event_exit(i->event, r);
-}
-
-static int tar_import_job_on_open_disk(ImportJob *j) {
- _cleanup_close_pair_ int pipefd[2] = { -1 , -1 };
- TarImport *i;
- int r;
-
- assert(j);
- assert(j->userdata);
-
- i = j->userdata;
- assert(i->tar_job == j);
- assert(!i->final_path);
- assert(!i->temp_path);
- assert(i->tar_pid <= 0);
-
- r = import_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
- if (r < 0)
- return log_oom();
-
- r = tempfn_random(i->final_path, &i->temp_path);
- if (r < 0)
- return log_oom();
-
- mkdir_parents_label(i->temp_path, 0700);
-
- r = btrfs_subvol_make(i->temp_path);
- if (r == -ENOTTY) {
- if (mkdir(i->temp_path, 0755) < 0)
- return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
- } else if (r < 0)
- return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
-
- j->disk_fd = import_fork_tar(i->temp_path, &i->tar_pid);
- if (j->disk_fd < 0)
- return j->disk_fd;
return 0;
}
-static void tar_import_job_on_progress(ImportJob *j) {
- TarImport *i;
+static int tar_import_on_input(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ TarImport *i = userdata;
- assert(j);
- assert(j->userdata);
+ return tar_import_process(i);
+}
- i = j->userdata;
+static int tar_import_on_defer(sd_event_source *s, void *userdata) {
+ TarImport *i = userdata;
- tar_import_report_progress(i, TAR_DOWNLOADING);
+ return tar_import_process(i);
}
-int tar_import_pull(TarImport *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
+int tar_import_start(TarImport *i, int fd, const char *local, bool force_local, bool read_only) {
int r;
assert(i);
+ assert(fd >= 0);
+ assert(local);
- if (!http_url_is_valid(url))
- return -EINVAL;
-
- if (local && !machine_name_is_valid(local))
+ if (!machine_name_is_valid(local))
return -EINVAL;
- if (i->tar_job)
+ if (i->input_fd >= 0)
return -EBUSY;
- r = free_and_strdup(&i->local, local);
+ r = fd_nonblock(fd, true);
if (r < 0)
return r;
- i->force_local = force_local;
- i->verify = verify;
- r = import_job_new(&i->tar_job, url, i->glue, i);
- if (r < 0)
- return r;
-
- i->tar_job->on_finished = tar_import_job_on_finished;
- i->tar_job->on_open_disk = tar_import_job_on_open_disk;
- i->tar_job->on_progress = tar_import_job_on_progress;
- i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
-
- r = import_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
- if (r < 0)
- return r;
-
- r = import_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_import_job_on_finished, i);
- if (r < 0)
- return r;
-
- r = import_job_begin(i->tar_job);
+ r = free_and_strdup(&i->local, local);
if (r < 0)
return r;
+ i->force_local = force_local;
+ i->read_only = read_only;
- if (i->checksum_job) {
- i->checksum_job->on_progress = tar_import_job_on_progress;
+ if (fstat(fd, &i->st) < 0)
+ return -errno;
- r = import_job_begin(i->checksum_job);
+ r = sd_event_add_io(i->event, &i->input_event_source, fd, EPOLLIN, tar_import_on_input, i);
+ if (r == -EPERM) {
+ /* This fd does not support epoll, for example because it is a regular file. Busy read in that case */
+ r = sd_event_add_defer(i->event, &i->input_event_source, tar_import_on_defer, i);
if (r < 0)
return r;
- }
- if (i->signature_job) {
- i->signature_job->on_progress = tar_import_job_on_progress;
-
- r = import_job_begin(i->signature_job);
- if (r < 0)
- return r;
+ r = sd_event_source_set_enabled(i->input_event_source, SD_EVENT_ON);
}
+ if (r < 0)
+ return r;
- return 0;
+ i->input_fd = fd;
+ return r;
}
diff --git a/src/import/import-tar.h b/src/import/import-tar.h
index 212f804d16..aaecb51398 100644
--- a/src/import/import-tar.h
+++ b/src/import/import-tar.h
@@ -34,4 +34,4 @@ TarImport* tar_import_unref(TarImport *import);
DEFINE_TRIVIAL_CLEANUP_FUNC(TarImport*, tar_import_unref);
-int tar_import_pull(TarImport *import, const char *url, const char *local, bool force_local, ImportVerify verify);
+int tar_import_start(TarImport *import, int fd, const char *local, bool force_local, bool read_only);
diff --git a/src/import/import.c b/src/import/import.c
new file mode 100644
index 0000000000..fff5a104b1
--- /dev/null
+++ b/src/import/import.c
@@ -0,0 +1,337 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <getopt.h>
+
+#include "sd-event.h"
+#include "event-util.h"
+#include "verbs.h"
+#include "build.h"
+#include "signal-util.h"
+#include "machine-image.h"
+#include "import-util.h"
+#include "import-tar.h"
+#include "import-raw.h"
+
+static bool arg_force = false;
+static bool arg_read_only = false;
+static const char *arg_image_root = "/var/lib/machines";
+
+static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ log_notice("Transfer aborted.");
+ sd_event_exit(sd_event_source_get_event(s), EINTR);
+ return 0;
+}
+
+static void on_tar_finished(TarImport *import, int error, void *userdata) {
+ sd_event *event = userdata;
+ assert(import);
+
+ if (error == 0)
+ log_info("Operation completed successfully.");
+
+ sd_event_exit(event, abs(error));
+}
+
+static int import_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_(tar_import_unrefp) TarImport *import = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ const char *path = NULL, *local = NULL;
+ _cleanup_free_ char *ll = NULL;
+ _cleanup_close_ int open_fd = -1;
+ int r, fd;
+
+ if (argc >= 2)
+ path = argv[1];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ if (argc >= 3)
+ local = argv[2];
+ else if (path)
+ local = basename(path);
+ if (isempty(local) || streq(local, "-"))
+ local = NULL;
+
+ if (local) {
+ r = tar_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!machine_name_is_valid(local)) {
+ log_error("Local image name '%s' is not valid.", local);
+ return -EINVAL;
+ }
+
+ if (!arg_force) {
+ r = image_find(local, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
+ else if (r > 0) {
+ log_error_errno(EEXIST, "Image '%s' already exists.", local);
+ return -EEXIST;
+ }
+ }
+ } else
+ local = "imported";
+
+ if (path) {
+ open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (open_fd < 0)
+ return log_error_errno(errno, "Failed to open tar image to import: %m");
+
+ fd = open_fd;
+
+ log_info("Importing '%s', saving as '%s'.", path, local);
+ } else {
+ _cleanup_free_ char *pretty = NULL;
+
+ fd = STDIN_FILENO;
+
+ (void) readlink_malloc("/proc/self/fd/0", &pretty);
+ log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
+ }
+
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event loop: %m");
+
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
+ sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
+ sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+
+ r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate importer: %m");
+
+ r = tar_import_start(import, fd, local, arg_force, arg_read_only);
+ if (r < 0)
+ return log_error_errno(r, "Failed to import image: %m");
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ log_info("Exiting.");
+ return -r;
+}
+
+static void on_raw_finished(RawImport *import, int error, void *userdata) {
+ sd_event *event = userdata;
+ assert(import);
+
+ if (error == 0)
+ log_info("Operation completed successfully.");
+
+ sd_event_exit(event, abs(error));
+}
+
+static int import_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_(raw_import_unrefp) RawImport *import = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ const char *path = NULL, *local = NULL;
+ _cleanup_free_ char *ll = NULL;
+ _cleanup_close_ int open_fd = -1;
+ int r, fd;
+
+ if (argc >= 2)
+ path = argv[1];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ if (argc >= 3)
+ local = argv[2];
+ else if (path)
+ local = basename(path);
+ if (isempty(local) || streq(local, "-"))
+ local = NULL;
+
+ if (local) {
+ r = raw_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!machine_name_is_valid(local)) {
+ log_error("Local image name '%s' is not valid.", local);
+ return -EINVAL;
+ }
+
+ if (!arg_force) {
+ r = image_find(local, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
+ else if (r > 0) {
+ log_error_errno(EEXIST, "Image '%s' already exists.", local);
+ return -EEXIST;
+ }
+ }
+ } else
+ local = "imported";
+
+ if (path) {
+ open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (open_fd < 0)
+ return log_error_errno(errno, "Failed to open raw image to import: %m");
+
+ fd = open_fd;
+
+ log_info("Importing '%s', saving as '%s'.", path, local);
+ } else {
+ _cleanup_free_ char *pretty = NULL;
+
+ fd = STDIN_FILENO;
+
+ (void) readlink_malloc("/proc/self/fd/0", &pretty);
+ log_info("Importing '%s', saving as '%s'.", pretty, local);
+ }
+
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event loop: %m");
+
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1) == 0);
+ sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
+ sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
+
+ r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate importer: %m");
+
+ r = raw_import_start(import, fd, local, arg_force, arg_read_only);
+ if (r < 0)
+ return log_error_errno(r, "Failed to import image: %m");
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ log_info("Exiting.");
+ return -r;
+}
+
+static int help(int argc, char *argv[], void *userdata) {
+
+ printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+ "Import container or virtual machine images.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --force Force creation of image\n"
+ " --image-root=PATH Image root directory\n"
+ " --read-only Create a read-only image\n\n"
+ "Commands:\n"
+ " tar FILE [NAME] Import a TAR image\n"
+ " raw FILE [NAME] Import a RAW image\n",
+ program_invocation_short_name);
+
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_FORCE,
+ ARG_IMAGE_ROOT,
+ ARG_READ_ONLY,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "force", no_argument, NULL, ARG_FORCE },
+ { "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
+ { "read-only", no_argument, NULL, ARG_READ_ONLY },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+
+ switch (c) {
+
+ case 'h':
+ return help(0, NULL, NULL);
+
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0;
+
+ case ARG_FORCE:
+ arg_force = true;
+ break;
+
+ case ARG_IMAGE_ROOT:
+ arg_image_root = optarg;
+ break;
+
+ case ARG_READ_ONLY:
+ arg_read_only = true;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+
+ return 1;
+}
+
+static int import_main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "help", VERB_ANY, VERB_ANY, 0, help },
+ { "tar", 2, 3, 0, import_tar },
+ { "raw", 2, 3, 0, import_raw },
+ {}
+ };
+
+ return dispatch_verb(argc, argv, verbs, NULL);
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ setlocale(LC_ALL, "");
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ goto finish;
+
+ ignore_signals(SIGPIPE, -1);
+
+ r = import_main(argc, argv);
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/import/importd.c b/src/import/importd.c
index 1222bf3cd2..50566a6e5c 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -26,19 +26,27 @@
#include "strv.h"
#include "bus-util.h"
#include "bus-common-errors.h"
-#include "def.h"
#include "socket-util.h"
#include "mkdir.h"
-#include "import-util.h"
#include "def.h"
+#include "missing.h"
+#include "machine-pool.h"
+#include "path-util.h"
+#include "import-util.h"
+#include "process-util.h"
+#include "signal-util.h"
typedef struct Transfer Transfer;
typedef struct Manager Manager;
typedef enum TransferType {
- TRANSFER_TAR,
- TRANSFER_RAW,
- TRANSFER_DKR,
+ TRANSFER_IMPORT_TAR,
+ TRANSFER_IMPORT_RAW,
+ TRANSFER_EXPORT_TAR,
+ TRANSFER_EXPORT_RAW,
+ TRANSFER_PULL_TAR,
+ TRANSFER_PULL_RAW,
+ TRANSFER_PULL_DKR,
_TRANSFER_TYPE_MAX,
_TRANSFER_TYPE_INVALID = -1,
} TransferType;
@@ -55,8 +63,10 @@ struct Transfer {
char *remote;
char *local;
bool force_local;
+ bool read_only;
char *dkr_index_url;
+ char *format;
pid_t pid;
@@ -70,6 +80,9 @@ struct Transfer {
unsigned n_canceled;
unsigned progress_percent;
+
+ int stdin_fd;
+ int stdout_fd;
};
struct Manager {
@@ -89,9 +102,13 @@ struct Manager {
#define TRANSFERS_MAX 64
static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = {
- [TRANSFER_TAR] = "tar",
- [TRANSFER_RAW] = "raw",
- [TRANSFER_DKR] = "dkr",
+ [TRANSFER_IMPORT_TAR] = "import-tar",
+ [TRANSFER_IMPORT_RAW] = "import-raw",
+ [TRANSFER_EXPORT_TAR] = "export-tar",
+ [TRANSFER_EXPORT_RAW] = "export-raw",
+ [TRANSFER_PULL_TAR] = "pull-tar",
+ [TRANSFER_PULL_RAW] = "pull-raw",
+ [TRANSFER_PULL_DKR] = "pull-dkr",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType);
@@ -109,6 +126,7 @@ static Transfer *transfer_unref(Transfer *t) {
free(t->remote);
free(t->local);
free(t->dkr_index_url);
+ free(t->format);
free(t->object_path);
if (t->pid > 0) {
@@ -117,6 +135,8 @@ static Transfer *transfer_unref(Transfer *t) {
}
safe_close(t->log_fd);
+ safe_close(t->stdin_fd);
+ safe_close(t->stdout_fd);
free(t);
return NULL;
@@ -145,6 +165,8 @@ static int transfer_new(Manager *m, Transfer **ret) {
t->type = _TRANSFER_TYPE_INVALID;
t->log_fd = -1;
+ t->stdin_fd = -1;
+ t->verify = _IMPORT_VERIFY_INVALID;
id = m->current_transfer_id + 1;
@@ -225,7 +247,7 @@ static void transfer_send_logs(Transfer *t, bool flush) {
n = strndup(t->log_message, e - t->log_message);
/* Skip over NUL and newlines */
- while (e < t->log_message + t->log_message_size && (*e == 0 || *e == '\n'))
+ while ((e < t->log_message + t->log_message_size) && (*e == 0 || *e == '\n'))
e++;
memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
@@ -350,19 +372,21 @@ static int transfer_start(Transfer *t) {
return -errno;
if (t->pid == 0) {
const char *cmd[] = {
- "systemd-pull",
- transfer_type_to_string(t->type),
- "--verify",
+ NULL, /* systemd-import, systemd-export or systemd-pull */
+ NULL, /* tar, raw, dkr */
+ NULL, /* --verify= */
NULL, /* verify argument */
NULL, /* maybe --force */
+ NULL, /* maybe --read-only */
NULL, /* maybe --dkr-index-url */
- NULL, /* the actual URL */
+ NULL, /* if so: the actual URL */
+ NULL, /* maybe --format= */
+ NULL, /* if so: the actual format */
NULL, /* remote */
NULL, /* local */
NULL
};
- int null_fd;
- unsigned k = 3;
+ unsigned k = 0;
/* Child */
@@ -372,33 +396,55 @@ static int transfer_start(Transfer *t) {
pipefd[0] = safe_close(pipefd[0]);
- if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
log_error_errno(errno, "Failed to dup2() fd: %m");
_exit(EXIT_FAILURE);
}
- if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
- log_error_errno(errno, "Failed to dup2() fd: %m");
- _exit(EXIT_FAILURE);
+ if (t->stdout_fd >= 0) {
+ if (dup2(t->stdout_fd, STDOUT_FILENO) != STDOUT_FILENO) {
+ log_error_errno(errno, "Failed to dup2() fd: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (t->stdout_fd != STDOUT_FILENO)
+ safe_close(t->stdout_fd);
+ } else {
+ if (dup2(pipefd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ log_error_errno(errno, "Failed to dup2() fd: %m");
+ _exit(EXIT_FAILURE);
+ }
}
if (pipefd[1] != STDOUT_FILENO && pipefd[1] != STDERR_FILENO)
pipefd[1] = safe_close(pipefd[1]);
- null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
- if (null_fd < 0) {
- log_error_errno(errno, "Failed to open /dev/null: %m");
- _exit(EXIT_FAILURE);
+ if (t->stdin_fd >= 0) {
+ if (dup2(t->stdin_fd, STDIN_FILENO) != STDIN_FILENO) {
+ log_error_errno(errno, "Failed to dup2() fd: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (t->stdin_fd != STDIN_FILENO)
+ safe_close(t->stdin_fd);
+ } else {
+ int null_fd;
+
+ null_fd = open("/dev/null", O_RDONLY|O_NOCTTY);
+ if (null_fd < 0) {
+ log_error_errno(errno, "Failed to open /dev/null: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
+ log_error_errno(errno, "Failed to dup2() fd: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (null_fd != STDIN_FILENO)
+ safe_close(null_fd);
}
- if (dup2(null_fd, STDIN_FILENO) != STDIN_FILENO) {
- log_error_errno(errno, "Failed to dup2() fd: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (null_fd != STDIN_FILENO)
- safe_close(null_fd);
-
fd_cloexec(STDIN_FILENO, false);
fd_cloexec(STDOUT_FILENO, false);
fd_cloexec(STDERR_FILENO, false);
@@ -406,22 +452,53 @@ static int transfer_start(Transfer *t) {
setenv("SYSTEMD_LOG_TARGET", "console-prefixed", 1);
setenv("NOTIFY_SOCKET", "/run/systemd/import/notify", 1);
- cmd[k++] = import_verify_to_string(t->verify);
+ if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_IMPORT_RAW))
+ cmd[k++] = SYSTEMD_IMPORT_PATH;
+ else if (IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW))
+ cmd[k++] = SYSTEMD_EXPORT_PATH;
+ else
+ cmd[k++] = SYSTEMD_PULL_PATH;
+
+ if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_EXPORT_TAR, TRANSFER_PULL_TAR))
+ cmd[k++] = "tar";
+ else if (IN_SET(t->type, TRANSFER_IMPORT_RAW, TRANSFER_EXPORT_RAW, TRANSFER_PULL_RAW))
+ cmd[k++] = "raw";
+ else
+ cmd[k++] = "dkr";
+
+ if (t->verify != _IMPORT_VERIFY_INVALID) {
+ cmd[k++] = "--verify";
+ cmd[k++] = import_verify_to_string(t->verify);
+ }
+
if (t->force_local)
cmd[k++] = "--force";
+ if (t->read_only)
+ cmd[k++] = "--read-only";
if (t->dkr_index_url) {
cmd[k++] = "--dkr-index-url";
cmd[k++] = t->dkr_index_url;
}
- cmd[k++] = t->remote;
+ if (t->format) {
+ cmd[k++] = "--format";
+ cmd[k++] = t->format;
+ }
+
+ if (!IN_SET(t->type, TRANSFER_EXPORT_TAR, TRANSFER_EXPORT_RAW)) {
+ if (t->remote)
+ cmd[k++] = t->remote;
+ else
+ cmd[k++] = "-";
+ }
+
if (t->local)
cmd[k++] = t->local;
cmd[k] = NULL;
- execv(SYSTEMD_PULL_PATH, (char * const *) cmd);
- log_error_errno(errno, "Failed to execute import tool: %m");
+ execv(cmd[0], (char * const *) cmd);
+ log_error_errno(errno, "Failed to execute %s tool: %m", cmd[0]);
_exit(EXIT_FAILURE);
}
@@ -429,6 +506,8 @@ static int transfer_start(Transfer *t) {
t->log_fd = pipefd[0];
pipefd[0] = -1;
+ t->stdin_fd = safe_close(t->stdin_fd);
+
r = sd_event_add_child(t->manager->event, &t->pid_event_source, t->pid, WEXITED, transfer_on_pid, t);
if (r < 0)
return r;
@@ -518,12 +597,10 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
return -errno;
}
+ cmsg_close_all(&msghdr);
+
for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
- log_warning("Somebody sent us unexpected fds, ignoring.");
- return 0;
- } else if (cmsg->cmsg_level == SOL_SOCKET &&
+ if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDENTIALS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
@@ -643,7 +720,135 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_ind
return NULL;
}
-static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+ _cleanup_(transfer_unrefp) Transfer *t = NULL;
+ int fd, force, read_only, r;
+ const char *local, *object;
+ Manager *m = userdata;
+ TransferType type;
+ uint32_t id;
+
+ assert(msg);
+ assert(m);
+
+ r = bus_verify_polkit_async(
+ msg,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.import1.import",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
+ if (r < 0)
+ return r;
+
+ if (!machine_name_is_valid(local))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+
+ r = setup_machine_directory((uint64_t) -1, error);
+ if (r < 0)
+ return r;
+
+ type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ? TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
+
+ r = transfer_new(m, &t);
+ if (r < 0)
+ return r;
+
+ t->type = type;
+ t->force_local = force;
+ t->read_only = read_only;
+
+ t->local = strdup(local);
+ if (!t->local)
+ return -ENOMEM;
+
+ t->stdin_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (t->stdin_fd < 0)
+ return -errno;
+
+ r = transfer_start(t);
+ if (r < 0)
+ return r;
+
+ object = t->object_path;
+ id = t->id;
+ t = NULL;
+
+ return sd_bus_reply_method_return(msg, "uo", id, object);
+}
+
+static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+ _cleanup_(transfer_unrefp) Transfer *t = NULL;
+ int fd, r;
+ const char *local, *object, *format;
+ Manager *m = userdata;
+ TransferType type;
+ uint32_t id;
+
+ assert(msg);
+ assert(m);
+
+ r = bus_verify_polkit_async(
+ msg,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.import1.export",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ r = sd_bus_message_read(msg, "shs", &local, &fd, &format);
+ if (r < 0)
+ return r;
+
+ if (!machine_name_is_valid(local))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local);
+
+ type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ? TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
+
+ r = transfer_new(m, &t);
+ if (r < 0)
+ return r;
+
+ t->type = type;
+
+ if (!isempty(format)) {
+ t->format = strdup(format);
+ if (!t->format)
+ return -ENOMEM;
+ }
+
+ t->local = strdup(local);
+ if (!t->local)
+ return -ENOMEM;
+
+ t->stdout_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (t->stdout_fd < 0)
+ return -errno;
+
+ r = transfer_start(t);
+ if (r < 0)
+ return r;
+
+ object = t->object_path;
+ id = t->id;
+ t = NULL;
+
+ return sd_bus_reply_method_return(msg, "uo", id, object);
+}
+
+static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
_cleanup_(transfer_unrefp) Transfer *t = NULL;
const char *remote, *local, *verify, *object;
Manager *m = userdata;
@@ -652,7 +857,6 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda
int force, r;
uint32_t id;
- assert(bus);
assert(msg);
assert(m);
@@ -661,6 +865,7 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda
CAP_SYS_ADMIN,
"org.freedesktop.import1.pull",
false,
+ UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
@@ -687,7 +892,11 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda
if (v < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify);
- type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_TAR : TRANSFER_RAW;
+ r = setup_machine_directory((uint64_t) -1, error);
+ if (r < 0)
+ return r;
+
+ type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
if (manager_find(m, type, NULL, remote))
return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
@@ -704,9 +913,11 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda
if (!t->remote)
return -ENOMEM;
- t->local = strdup(local);
- if (!t->local)
- return -ENOMEM;
+ if (local) {
+ t->local = strdup(local);
+ if (!t->local)
+ return -ENOMEM;
+ }
r = transfer_start(t);
if (r < 0)
@@ -719,7 +930,7 @@ static int method_pull_tar_or_raw(sd_bus *bus, sd_bus_message *msg, void *userda
return sd_bus_reply_method_return(msg, "uo", id, object);
}
-static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+static int method_pull_dkr(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
_cleanup_(transfer_unrefp) Transfer *t = NULL;
const char *index_url, *remote, *tag, *local, *verify, *object;
Manager *m = userdata;
@@ -727,7 +938,6 @@ static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_
int force, r;
uint32_t id;
- assert(bus);
assert(msg);
assert(m);
@@ -736,6 +946,7 @@ static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_
CAP_SYS_ADMIN,
"org.freedesktop.import1.pull",
false,
+ UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
@@ -777,14 +988,18 @@ static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_
if (v != IMPORT_VERIFY_NO)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "DKR does not support verification.");
- if (manager_find(m, TRANSFER_DKR, index_url, remote))
+ r = setup_machine_directory((uint64_t) -1, error);
+ if (r < 0)
+ return r;
+
+ if (manager_find(m, TRANSFER_PULL_DKR, index_url, remote))
return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote);
r = transfer_new(m, &t);
if (r < 0)
return r;
- t->type = TRANSFER_DKR;
+ t->type = TRANSFER_PULL_DKR;
t->verify = v;
t->force_local = force;
@@ -796,9 +1011,11 @@ static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_
if (!t->remote)
return -ENOMEM;
- t->local = strdup(local);
- if (!t->local)
- return -ENOMEM;
+ if (local) {
+ t->local = strdup(local);
+ if (!t->local)
+ return -ENOMEM;
+ }
r = transfer_start(t);
if (r < 0)
@@ -811,14 +1028,13 @@ static int method_pull_dkr(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_
return sd_bus_reply_method_return(msg, "uo", id, object);
}
-static int method_list_transfers(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
Transfer *t;
Iterator i;
int r;
- assert(bus);
assert(msg);
assert(m);
@@ -849,14 +1065,13 @@ static int method_list_transfers(sd_bus *bus, sd_bus_message *msg, void *userdat
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_cancel(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+static int method_cancel(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
Transfer *t = userdata;
int r;
- assert(bus);
assert(msg);
assert(t);
@@ -865,6 +1080,7 @@ static int method_cancel(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bu
CAP_SYS_ADMIN,
"org.freedesktop.import1.pull",
false,
+ UID_INVALID,
&t->manager->polkit_registry,
error);
if (r < 0)
@@ -879,13 +1095,12 @@ static int method_cancel(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bu
return sd_bus_reply_method_return(msg, NULL);
}
-static int method_cancel_transfer(sd_bus *bus, sd_bus_message *msg, void *userdata, sd_bus_error *error) {
+static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Transfer *t;
uint32_t id;
int r;
- assert(bus);
assert(msg);
assert(m);
@@ -894,6 +1109,7 @@ static int method_cancel_transfer(sd_bus *bus, sd_bus_message *msg, void *userda
CAP_SYS_ADMIN,
"org.freedesktop.import1.pull",
false,
+ UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
@@ -954,6 +1170,10 @@ static const sd_bus_vtable transfer_vtable[] = {
static const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("ImportTar", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ImportRaw", "hsbb", "uo", method_import_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ExportTar", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PullDkr", "sssssb", "uo", method_pull_dkr, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/import/org.freedesktop.import1.policy.in b/src/import/org.freedesktop.import1.policy.in
index 1003f46447..85924ed743 100644
--- a/src/import/org.freedesktop.import1.policy.in
+++ b/src/import/org.freedesktop.import1.policy.in
@@ -16,6 +16,26 @@
<vendor>The systemd Project</vendor>
<vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+ <action id="org.freedesktop.import1.import">
+ <_description>Import a VM or container image</_description>
+ <_message>Authentication is required to import a VM or container image</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.import1.export">
+ <_description>Export a VM or container image</_description>
+ <_message>Authentication is required to export a VM or container image</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
<action id="org.freedesktop.import1.pull">
<_description>Download a VM or container image</_description>
<_message>Authentication is required to download a VM or container image</_message>
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
new file mode 100644
index 0000000000..d2588d4fa0
--- /dev/null
+++ b/src/import/pull-common.c
@@ -0,0 +1,425 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/prctl.h>
+
+#include "util.h"
+#include "strv.h"
+#include "copy.h"
+#include "rm-rf.h"
+#include "btrfs-util.h"
+#include "capability.h"
+#include "pull-job.h"
+#include "pull-common.h"
+#include "process-util.h"
+#include "signal-util.h"
+
+#define FILENAME_ESCAPE "/.#\"\'"
+
+int pull_find_old_etags(const char *url, const char *image_root, int dt, const char *prefix, const char *suffix, char ***etags) {
+ _cleanup_free_ char *escaped_url = NULL;
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_strv_free_ char **l = NULL;
+ struct dirent *de;
+ int r;
+
+ assert(url);
+ assert(etags);
+
+ if (!image_root)
+ image_root = "/var/lib/machines";
+
+ escaped_url = xescape(url, FILENAME_ESCAPE);
+ if (!escaped_url)
+ return -ENOMEM;
+
+ d = opendir(image_root);
+ if (!d) {
+ if (errno == ENOENT) {
+ *etags = NULL;
+ return 0;
+ }
+
+ return -errno;
+ }
+
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
+ const char *a, *b;
+ char *u;
+
+ if (de->d_type != DT_UNKNOWN &&
+ de->d_type != dt)
+ continue;
+
+ if (prefix) {
+ a = startswith(de->d_name, prefix);
+ if (!a)
+ continue;
+ } else
+ a = de->d_name;
+
+ a = startswith(a, escaped_url);
+ if (!a)
+ continue;
+
+ a = startswith(a, ".");
+ if (!a)
+ continue;
+
+ if (suffix) {
+ b = endswith(de->d_name, suffix);
+ if (!b)
+ continue;
+ } else
+ b = strchr(de->d_name, 0);
+
+ if (a >= b)
+ continue;
+
+ r = cunescape_length(a, b - a, 0, &u);
+ if (r < 0)
+ return r;
+
+ if (!http_etag_is_valid(u)) {
+ free(u);
+ continue;
+ }
+
+ r = strv_consume(&l, u);
+ if (r < 0)
+ return r;
+ }
+
+ *etags = l;
+ l = NULL;
+
+ return 0;
+}
+
+int pull_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
+ const char *p;
+ int r;
+
+ assert(final);
+ assert(local);
+
+ if (!image_root)
+ image_root = "/var/lib/machines";
+
+ p = strjoina(image_root, "/", local);
+
+ if (force_local)
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+
+ r = btrfs_subvol_snapshot(final, p, 0);
+ if (r == -ENOTTY) {
+ r = copy_tree(final, p, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy image: %m");
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to create local image: %m");
+
+ log_info("Created new local image '%s'.", local);
+
+ return 0;
+}
+
+int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
+ _cleanup_free_ char *escaped_url = NULL;
+ char *path;
+
+ assert(url);
+ assert(ret);
+
+ if (!image_root)
+ image_root = "/var/lib/machines";
+
+ escaped_url = xescape(url, FILENAME_ESCAPE);
+ if (!escaped_url)
+ return -ENOMEM;
+
+ if (etag) {
+ _cleanup_free_ char *escaped_etag = NULL;
+
+ escaped_etag = xescape(etag, FILENAME_ESCAPE);
+ if (!escaped_etag)
+ return -ENOMEM;
+
+ path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
+ } else
+ path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
+ if (!path)
+ return -ENOMEM;
+
+ *ret = path;
+ return 0;
+}
+
+int pull_make_verification_jobs(
+ PullJob **ret_checksum_job,
+ PullJob **ret_signature_job,
+ ImportVerify verify,
+ const char *url,
+ CurlGlue *glue,
+ PullJobFinished on_finished,
+ void *userdata) {
+
+ _cleanup_(pull_job_unrefp) PullJob *checksum_job = NULL, *signature_job = NULL;
+ int r;
+
+ assert(ret_checksum_job);
+ assert(ret_signature_job);
+ assert(verify >= 0);
+ assert(verify < _IMPORT_VERIFY_MAX);
+ assert(url);
+ assert(glue);
+
+ if (verify != IMPORT_VERIFY_NO) {
+ _cleanup_free_ char *checksum_url = NULL;
+
+ /* Queue job for the SHA256SUMS file for the image */
+ r = import_url_change_last_component(url, "SHA256SUMS", &checksum_url);
+ if (r < 0)
+ return r;
+
+ r = pull_job_new(&checksum_job, checksum_url, glue, userdata);
+ if (r < 0)
+ return r;
+
+ checksum_job->on_finished = on_finished;
+ checksum_job->uncompressed_max = checksum_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
+ }
+
+ if (verify == IMPORT_VERIFY_SIGNATURE) {
+ _cleanup_free_ char *signature_url = NULL;
+
+ /* Queue job for the SHA256SUMS.gpg file for the image. */
+ r = import_url_change_last_component(url, "SHA256SUMS.gpg", &signature_url);
+ if (r < 0)
+ return r;
+
+ r = pull_job_new(&signature_job, signature_url, glue, userdata);
+ if (r < 0)
+ return r;
+
+ signature_job->on_finished = on_finished;
+ signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
+ }
+
+ *ret_checksum_job = checksum_job;
+ *ret_signature_job = signature_job;
+
+ checksum_job = signature_job = NULL;
+
+ return 0;
+}
+
+int pull_verify(
+ PullJob *main_job,
+ PullJob *checksum_job,
+ PullJob *signature_job) {
+
+ _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
+ _cleanup_free_ char *fn = NULL;
+ _cleanup_close_ int sig_file = -1;
+ const char *p, *line;
+ char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
+ _cleanup_sigkill_wait_ pid_t pid = 0;
+ bool gpg_home_created = false;
+ int r;
+
+ assert(main_job);
+ assert(main_job->state == PULL_JOB_DONE);
+
+ if (!checksum_job)
+ return 0;
+
+ assert(main_job->calc_checksum);
+ assert(main_job->checksum);
+ assert(checksum_job->state == PULL_JOB_DONE);
+
+ if (!checksum_job->payload || checksum_job->payload_size <= 0) {
+ log_error("Checksum is empty, cannot verify.");
+ return -EBADMSG;
+ }
+
+ r = import_url_last_component(main_job->url, &fn);
+ if (r < 0)
+ return log_oom();
+
+ if (!filename_is_valid(fn)) {
+ log_error("Cannot verify checksum, could not determine valid server-side file name.");
+ return -EBADMSG;
+ }
+
+ line = strjoina(main_job->checksum, " *", fn, "\n");
+
+ p = memmem(checksum_job->payload,
+ checksum_job->payload_size,
+ line,
+ strlen(line));
+
+ if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
+ log_error("Checksum did not check out, payload has been tempered with.");
+ return -EBADMSG;
+ }
+
+ log_info("SHA256 checksum of %s is valid.", main_job->url);
+
+ if (!signature_job)
+ return 0;
+
+ assert(signature_job->state == PULL_JOB_DONE);
+
+ if (!signature_job->payload || signature_job->payload_size <= 0) {
+ log_error("Signature is empty, cannot verify.");
+ return -EBADMSG;
+ }
+
+ r = pipe2(gpg_pipe, O_CLOEXEC);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to create pipe for gpg: %m");
+
+ sig_file = mkostemp(sig_file_path, O_RDWR);
+ if (sig_file < 0)
+ return log_error_errno(errno, "Failed to create temporary file: %m");
+
+ r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false);
+ if (r < 0) {
+ log_error_errno(r, "Failed to write to temporary file: %m");
+ goto finish;
+ }
+
+ if (!mkdtemp(gpg_home)) {
+ r = log_error_errno(errno, "Failed to create tempory home for gpg: %m");
+ goto finish;
+ }
+
+ gpg_home_created = true;
+
+ pid = fork();
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork off gpg: %m");
+ if (pid == 0) {
+ const char *cmd[] = {
+ "gpg",
+ "--no-options",
+ "--no-default-keyring",
+ "--no-auto-key-locate",
+ "--no-auto-check-trustdb",
+ "--batch",
+ "--trust-model=always",
+ NULL, /* --homedir= */
+ NULL, /* --keyring= */
+ NULL, /* --verify */
+ NULL, /* signature file */
+ NULL, /* dash */
+ NULL /* trailing NULL */
+ };
+ unsigned k = ELEMENTSOF(cmd) - 6;
+ int null_fd;
+
+ /* Child */
+
+ reset_all_signal_handlers();
+ reset_signal_mask();
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+ gpg_pipe[1] = safe_close(gpg_pipe[1]);
+
+ if (dup2(gpg_pipe[0], STDIN_FILENO) != STDIN_FILENO) {
+ log_error_errno(errno, "Failed to dup2() fd: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (gpg_pipe[0] != STDIN_FILENO)
+ gpg_pipe[0] = safe_close(gpg_pipe[0]);
+
+ null_fd = open("/dev/null", O_WRONLY|O_NOCTTY);
+ if (null_fd < 0) {
+ log_error_errno(errno, "Failed to open /dev/null: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (dup2(null_fd, STDOUT_FILENO) != STDOUT_FILENO) {
+ log_error_errno(errno, "Failed to dup2() fd: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (null_fd != STDOUT_FILENO)
+ null_fd = safe_close(null_fd);
+
+ cmd[k++] = strjoina("--homedir=", gpg_home);
+
+ /* We add the user keyring only to the command line
+ * arguments, if it's around since gpg fails
+ * otherwise. */
+ if (access(USER_KEYRING_PATH, F_OK) >= 0)
+ cmd[k++] = "--keyring=" USER_KEYRING_PATH;
+ else
+ cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
+
+ cmd[k++] = "--verify";
+ cmd[k++] = sig_file_path;
+ cmd[k++] = "-";
+ cmd[k++] = NULL;
+
+ fd_cloexec(STDIN_FILENO, false);
+ fd_cloexec(STDOUT_FILENO, false);
+ fd_cloexec(STDERR_FILENO, false);
+
+ execvp("gpg2", (char * const *) cmd);
+ execvp("gpg", (char * const *) cmd);
+ log_error_errno(errno, "Failed to execute gpg: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ gpg_pipe[0] = safe_close(gpg_pipe[0]);
+
+ r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false);
+ if (r < 0) {
+ log_error_errno(r, "Failed to write to pipe: %m");
+ goto finish;
+ }
+
+ gpg_pipe[1] = safe_close(gpg_pipe[1]);
+
+ r = wait_for_terminate_and_warn("gpg", pid, true);
+ pid = 0;
+ if (r < 0)
+ goto finish;
+ if (r > 0) {
+ log_error("Signature verification failed.");
+ r = -EBADMSG;
+ } else {
+ log_info("Signature verification succeeded.");
+ r = 0;
+ }
+
+finish:
+ if (sig_file >= 0)
+ unlink(sig_file_path);
+
+ if (gpg_home_created)
+ (void) rm_rf(gpg_home, REMOVE_ROOT|REMOVE_PHYSICAL);
+
+ return r;
+}
diff --git a/src/import/pull-common.h b/src/import/pull-common.h
new file mode 100644
index 0000000000..bb9cf3efc1
--- /dev/null
+++ b/src/import/pull-common.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "pull-job.h"
+#include "import-util.h"
+
+int pull_make_local_copy(const char *final, const char *root, const char *local, bool force_local);
+
+int pull_find_old_etags(const char *url, const char *root, int dt, const char *prefix, const char *suffix, char ***etags);
+
+int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
+
+int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
+int pull_verify(PullJob *main_job, PullJob *checksum_job, PullJob *signature_job);
diff --git a/src/import/import-dkr.c b/src/import/pull-dkr.c
index fb72f6cee3..d7476dc340 100644
--- a/src/import/import-dkr.c
+++ b/src/import/pull-dkr.c
@@ -28,12 +28,17 @@
#include "btrfs-util.h"
#include "utf8.h"
#include "mkdir.h"
+#include "rm-rf.h"
+#include "path-util.h"
#include "import-util.h"
#include "curl-util.h"
#include "aufs-util.h"
-#include "import-job.h"
+#include "pull-job.h"
+#include "pull-common.h"
#include "import-common.h"
-#include "import-dkr.h"
+#include "pull-dkr.h"
+#include "process-util.h"
+#include "hostname-util.h"
typedef enum DkrProgress {
DKR_SEARCHING,
@@ -43,23 +48,27 @@ typedef enum DkrProgress {
DKR_COPYING,
} DkrProgress;
-struct DkrImport {
+struct DkrPull {
sd_event *event;
CurlGlue *glue;
+ char *index_protocol;
+ char *index_address;
+
char *index_url;
char *image_root;
- ImportJob *images_job;
- ImportJob *tags_job;
- ImportJob *ancestry_job;
- ImportJob *json_job;
- ImportJob *layer_job;
+ PullJob *images_job;
+ PullJob *tags_job;
+ PullJob *ancestry_job;
+ PullJob *json_job;
+ PullJob *layer_job;
char *name;
- char *tag;
+ char *reference;
char *id;
+ char *response_digest;
char *response_token;
char **response_registries;
@@ -67,11 +76,12 @@ struct DkrImport {
unsigned n_ancestry;
unsigned current_ancestry;
- DkrImportFinished on_finished;
+ DkrPullFinished on_finished;
void *userdata;
char *local;
bool force_local;
+ bool grow_machine_directory;
char *temp_path;
char *final_path;
@@ -82,13 +92,13 @@ struct DkrImport {
#define PROTOCOL_PREFIX "https://"
#define HEADER_TOKEN "X-Do" /* the HTTP header for the auth token */ "cker-Token:"
-#define HEADER_REGISTRY "X-Do" /*the HTTP header for the registry */ "cker-Endpoints:"
-
-#define LAYERS_MAX 2048
+#define HEADER_REGISTRY "X-Do" /* the HTTP header for the registry */ "cker-Endpoints:"
+#define HEADER_DIGEST "Do" /* the HTTP header for the manifest digest */ "cker-Content-Digest:"
+#define LAYERS_MAX 127
-static void dkr_import_job_on_finished(ImportJob *j);
+static void dkr_pull_job_on_finished(PullJob *j);
-DkrImport* dkr_import_unref(DkrImport *i) {
+DkrPull* dkr_pull_unref(DkrPull *i) {
if (!i)
return NULL;
@@ -97,28 +107,28 @@ DkrImport* dkr_import_unref(DkrImport *i) {
(void) wait_for_terminate(i->tar_pid, NULL);
}
- import_job_unref(i->images_job);
- import_job_unref(i->tags_job);
- import_job_unref(i->ancestry_job);
- import_job_unref(i->json_job);
- import_job_unref(i->layer_job);
+ pull_job_unref(i->images_job);
+ pull_job_unref(i->tags_job);
+ pull_job_unref(i->ancestry_job);
+ pull_job_unref(i->json_job);
+ pull_job_unref(i->layer_job);
curl_glue_unref(i->glue);
sd_event_unref(i->event);
if (i->temp_path) {
- (void) btrfs_subvol_remove(i->temp_path);
- (void) rm_rf_dangerous(i->temp_path, false, true, false);
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(i->temp_path);
}
free(i->name);
- free(i->tag);
+ free(i->reference);
free(i->id);
free(i->response_token);
- free(i->response_registries);
strv_free(i->ancestry);
free(i->final_path);
+ free(i->index_address);
+ free(i->index_protocol);
free(i->index_url);
free(i->image_root);
free(i->local);
@@ -127,15 +137,15 @@ DkrImport* dkr_import_unref(DkrImport *i) {
return NULL;
}
-int dkr_import_new(
- DkrImport **ret,
+int dkr_pull_new(
+ DkrPull **ret,
sd_event *event,
const char *index_url,
const char *image_root,
- DkrImportFinished on_finished,
+ DkrPullFinished on_finished,
void *userdata) {
- _cleanup_(dkr_import_unrefp) DkrImport *i = NULL;
+ _cleanup_(dkr_pull_unrefp) DkrPull *i = NULL;
char *e;
int r;
@@ -145,7 +155,7 @@ int dkr_import_new(
if (!http_url_is_valid(index_url))
return -EINVAL;
- i = new0(DkrImport, 1);
+ i = new0(DkrPull, 1);
if (!i)
return -ENOMEM;
@@ -156,6 +166,8 @@ int dkr_import_new(
if (!i->image_root)
return -ENOMEM;
+ i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
+
i->index_url = strdup(index_url);
if (!i->index_url)
return -ENOMEM;
@@ -176,7 +188,7 @@ int dkr_import_new(
if (r < 0)
return r;
- i->glue->on_finished = import_job_curl_on_finished;
+ i->glue->on_finished = pull_job_curl_on_finished;
i->glue->userdata = i;
*ret = i;
@@ -185,7 +197,7 @@ int dkr_import_new(
return 0;
}
-static void dkr_import_report_progress(DkrImport *i, DkrProgress p) {
+static void dkr_pull_report_progress(DkrPull *i, DkrProgress p) {
unsigned percent;
assert(i);
@@ -371,7 +383,7 @@ static int parse_ancestry(const void *payload, size_t size, char ***ret) {
}
}
-static const char *dkr_import_current_layer(DkrImport *i) {
+static const char *dkr_pull_current_layer(DkrPull *i) {
assert(i);
if (strv_isempty(i->ancestry))
@@ -380,7 +392,7 @@ static const char *dkr_import_current_layer(DkrImport *i) {
return i->ancestry[i->current_ancestry];
}
-static const char *dkr_import_current_base_layer(DkrImport *i) {
+static const char *dkr_pull_current_base_layer(DkrPull *i) {
assert(i);
if (strv_isempty(i->ancestry))
@@ -392,7 +404,7 @@ static const char *dkr_import_current_base_layer(DkrImport *i) {
return i->ancestry[i->current_ancestry-1];
}
-static int dkr_import_add_token(DkrImport *i, ImportJob *j) {
+static int dkr_pull_add_token(DkrPull *i, PullJob *j) {
const char *t;
assert(i);
@@ -410,33 +422,51 @@ static int dkr_import_add_token(DkrImport *i, ImportJob *j) {
return 0;
}
-static bool dkr_import_is_done(DkrImport *i) {
+static int dkr_pull_add_bearer_token(DkrPull *i, PullJob *j) {
+ const char *t = NULL;
+
assert(i);
- assert(i->images_job);
+ assert(j);
- if (i->images_job->state != IMPORT_JOB_DONE)
+ if (i->response_token)
+ t = strjoina("Authorization: Bearer ", i->response_token);
+ else
+ return -EINVAL;
+
+ j->request_header = curl_slist_new("Accept: application/json", t, NULL);
+ if (!j->request_header)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static bool dkr_pull_is_done(DkrPull *i) {
+ assert(i);
+ assert(i->images_job);
+ if (i->images_job->state != PULL_JOB_DONE)
return false;
- if (!i->tags_job || i->tags_job->state != IMPORT_JOB_DONE)
+ if (!i->tags_job || i->tags_job->state != PULL_JOB_DONE)
return false;
- if (!i->ancestry_job || i->ancestry_job->state != IMPORT_JOB_DONE)
+ if (!i->ancestry_job || i->ancestry_job->state != PULL_JOB_DONE)
return false;
- if (!i->json_job || i->json_job->state != IMPORT_JOB_DONE)
+ if (i->json_job && i->json_job->state != PULL_JOB_DONE)
return false;
- if (i->layer_job && i->layer_job->state != IMPORT_JOB_DONE)
+ if (i->layer_job && i->layer_job->state != PULL_JOB_DONE)
return false;
- if (dkr_import_current_layer(i))
+ if (dkr_pull_current_layer(i))
return false;
return true;
}
-static int dkr_import_make_local_copy(DkrImport *i) {
+static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
int r;
+ _cleanup_free_ char *p = NULL;
assert(i);
@@ -449,16 +479,36 @@ static int dkr_import_make_local_copy(DkrImport *i) {
return log_oom();
}
- r = import_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
+ if (version == DKR_PULL_V2) {
+ r = path_get_parent(i->image_root, &p);
+ if (r < 0)
+ return r;
+ }
+
+ r = pull_make_local_copy(i->final_path, p ?: i->image_root, i->local, i->force_local);
if (r < 0)
return r;
+ if (version == DKR_PULL_V2) {
+ char **k = NULL;
+ STRV_FOREACH(k, i->ancestry) {
+ _cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL);
+ r = btrfs_subvol_remove(d, false);
+ if (r < 0)
+ return r;
+ }
+
+ r = rmdir(i->image_root);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
-static int dkr_import_job_on_open_disk(ImportJob *j) {
+static int dkr_pull_job_on_open_disk(PullJob *j) {
const char *base;
- DkrImport *i;
+ DkrPull *i;
int r;
assert(j);
@@ -476,33 +526,33 @@ static int dkr_import_job_on_open_disk(ImportJob *j) {
mkdir_parents_label(i->temp_path, 0700);
- base = dkr_import_current_base_layer(i);
+ base = dkr_pull_current_base_layer(i);
if (base) {
const char *base_path;
base_path = strjoina(i->image_root, "/.dkr-", base);
- r = btrfs_subvol_snapshot(base_path, i->temp_path, false, true);
+ r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY);
} else
r = btrfs_subvol_make(i->temp_path);
if (r < 0)
return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
- j->disk_fd = import_fork_tar(i->temp_path, &i->tar_pid);
+ j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (j->disk_fd < 0)
return j->disk_fd;
return 0;
}
-static void dkr_import_job_on_progress(ImportJob *j) {
- DkrImport *i;
+static void dkr_pull_job_on_progress(PullJob *j) {
+ DkrPull *i;
assert(j);
assert(j->userdata);
i = j->userdata;
- dkr_import_report_progress(
+ dkr_pull_report_progress(
i,
j == i->images_job ? DKR_SEARCHING :
j == i->tags_job ? DKR_RESOLVING :
@@ -510,7 +560,9 @@ static void dkr_import_job_on_progress(ImportJob *j) {
DKR_DOWNLOADING);
}
-static int dkr_import_pull_layer(DkrImport *i) {
+static void dkr_pull_job_on_finished_v2(PullJob *j);
+
+static int dkr_pull_pull_layer_v2(DkrPull *i) {
_cleanup_free_ char *path = NULL;
const char *url, *layer = NULL;
int r;
@@ -521,7 +573,67 @@ static int dkr_import_pull_layer(DkrImport *i) {
assert(!i->final_path);
for (;;) {
- layer = dkr_import_current_layer(i);
+ layer = dkr_pull_current_layer(i);
+ if (!layer)
+ return 0; /* no more layers */
+
+ path = strjoin(i->image_root, "/.dkr-", layer, NULL);
+ if (!path)
+ return log_oom();
+
+ if (laccess(path, F_OK) < 0) {
+ if (errno == ENOENT)
+ break;
+
+ return log_error_errno(errno, "Failed to check for container: %m");
+ }
+
+ log_info("Layer %s already exists, skipping.", layer);
+
+ i->current_ancestry++;
+
+ free(path);
+ path = NULL;
+ }
+
+ log_info("Pulling layer %s...", layer);
+
+ i->final_path = path;
+ path = NULL;
+
+ url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v2/", i->name, "/blobs/", layer);
+ r = pull_job_new(&i->layer_job, url, i->glue, i);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate layer job: %m");
+
+ r = dkr_pull_add_bearer_token(i, i->layer_job);
+ if (r < 0)
+ return log_oom();
+
+ i->layer_job->on_finished = dkr_pull_job_on_finished_v2;
+ i->layer_job->on_open_disk = dkr_pull_job_on_open_disk;
+ i->layer_job->on_progress = dkr_pull_job_on_progress;
+ i->layer_job->grow_machine_directory = i->grow_machine_directory;
+
+ r = pull_job_begin(i->layer_job);
+ if (r < 0)
+ return log_error_errno(r, "Failed to start layer job: %m");
+
+ return 0;
+}
+
+static int dkr_pull_pull_layer(DkrPull *i) {
+ _cleanup_free_ char *path = NULL;
+ const char *url, *layer = NULL;
+ int r;
+
+ assert(i);
+ assert(!i->layer_job);
+ assert(!i->temp_path);
+ assert(!i->final_path);
+
+ for (;;) {
+ layer = dkr_pull_current_layer(i);
if (!layer)
return 0; /* no more layers */
@@ -550,27 +662,364 @@ static int dkr_import_pull_layer(DkrImport *i) {
path = NULL;
url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", layer, "/layer");
- r = import_job_new(&i->layer_job, url, i->glue, i);
+ r = pull_job_new(&i->layer_job, url, i->glue, i);
if (r < 0)
return log_error_errno(r, "Failed to allocate layer job: %m");
- r = dkr_import_add_token(i, i->layer_job);
+ r = dkr_pull_add_token(i, i->layer_job);
if (r < 0)
return log_oom();
- i->layer_job->on_finished = dkr_import_job_on_finished;
- i->layer_job->on_open_disk = dkr_import_job_on_open_disk;
- i->layer_job->on_progress = dkr_import_job_on_progress;
+ i->layer_job->on_finished = dkr_pull_job_on_finished;
+ i->layer_job->on_open_disk = dkr_pull_job_on_open_disk;
+ i->layer_job->on_progress = dkr_pull_job_on_progress;
+ i->layer_job->grow_machine_directory = i->grow_machine_directory;
- r = import_job_begin(i->layer_job);
+ r = pull_job_begin(i->layer_job);
if (r < 0)
return log_error_errno(r, "Failed to start layer job: %m");
return 0;
}
-static void dkr_import_job_on_finished(ImportJob *j) {
- DkrImport *i;
+static int dkr_pull_job_on_header(PullJob *j, const char *header, size_t sz) {
+ _cleanup_free_ char *registry = NULL;
+ char *token, *digest;
+ DkrPull *i;
+ int r;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+ r = curl_header_strdup(header, sz, HEADER_TOKEN, &token);
+ if (r < 0)
+ return log_oom();
+ if (r > 0) {
+ free(i->response_token);
+ i->response_token = token;
+ return 0;
+ }
+
+ r = curl_header_strdup(header, sz, HEADER_DIGEST, &digest);
+ if (r < 0)
+ return log_oom();
+ if (r > 0) {
+ free(i->response_digest);
+ i->response_digest = digest;
+ return 0;
+ }
+
+ r = curl_header_strdup(header, sz, HEADER_REGISTRY, &registry);
+ if (r < 0)
+ return log_oom();
+ if (r > 0) {
+ char **l, **k;
+
+ l = strv_split(registry, ",");
+ if (!l)
+ return log_oom();
+
+ STRV_FOREACH(k, l) {
+ if (!hostname_is_valid(*k)) {
+ log_error("Registry hostname is not valid.");
+ strv_free(l);
+ return -EBADMSG;
+ }
+ }
+
+ strv_free(i->response_registries);
+ i->response_registries = l;
+ }
+
+ return 0;
+}
+
+static void dkr_pull_job_on_finished_v2(PullJob *j) {
+ DkrPull *i;
+ int r;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+ if (j->error != 0) {
+ if (j == i->images_job)
+ log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)");
+ else if (j == i->ancestry_job)
+ log_error_errno(j->error, "Failed to retrieve manifest.");
+ else if (j == i->json_job)
+ log_error_errno(j->error, "Failed to retrieve json data.");
+ else
+ log_error_errno(j->error, "Failed to retrieve layer data.");
+
+ r = j->error;
+ goto finish;
+ }
+
+ if (i->images_job == j) {
+ const char *url;
+
+ assert(!i->tags_job);
+ assert(!i->ancestry_job);
+ assert(!i->json_job);
+ assert(!i->layer_job);
+
+ if (strv_isempty(i->response_registries)) {
+ r = -EBADMSG;
+ log_error("Didn't get registry information.");
+ goto finish;
+ }
+
+ log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]);
+ dkr_pull_report_progress(i, DKR_RESOLVING);
+
+ url = strjoina(i->index_protocol, "auth.", i->index_address, "/v2/token/?scope=repository:",
+ i->name, ":pull&service=registry.", i->index_address);
+ r = pull_job_new(&i->tags_job, url, i->glue, i);
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate tags job: %m");
+ goto finish;
+ }
+
+ i->tags_job->on_finished = dkr_pull_job_on_finished_v2;
+ i->tags_job->on_progress = dkr_pull_job_on_progress;
+
+ r = pull_job_begin(i->tags_job);
+ if (r < 0) {
+ log_error_errno(r, "Failed to start tags job: %m");
+ goto finish;
+ }
+
+ } else if (i->tags_job == j) {
+ const char *url;
+ _cleanup_free_ const char *buf;
+ _cleanup_json_variant_unref_ JsonVariant *doc = NULL;
+ JsonVariant *e = NULL;
+
+ assert(!i->ancestry_job);
+ assert(!i->json_job);
+ assert(!i->layer_job);
+
+ buf = strndup((const char *)j->payload, j->payload_size);
+ if (!buf) {
+ r = -ENOMEM;
+ log_oom();
+ goto finish;
+ }
+
+ r = json_parse(buf, &doc);
+ if (r < 0) {
+ log_error("Unable to parse bearer token\n%s", j->payload);
+ goto finish;
+ }
+
+ e = json_variant_value(doc, "token");
+ if (!e || e->type != JSON_VARIANT_STRING) {
+ r = -EBADMSG;
+ log_error("Invalid JSON format for Bearer token");
+ goto finish;
+ }
+
+ r = free_and_strdup(&i->response_token, json_variant_string(e));
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
+
+ url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v2/", i->name, "/manifests/", i->reference);
+ r = pull_job_new(&i->ancestry_job, url, i->glue, i);
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate ancestry job: %m");
+ goto finish;
+ }
+
+ r = dkr_pull_add_bearer_token(i, i->ancestry_job);
+ if (r < 0)
+ goto finish;
+
+ i->ancestry_job->on_finished = dkr_pull_job_on_finished_v2;
+ i->ancestry_job->on_progress = dkr_pull_job_on_progress;
+ i->ancestry_job->on_header = dkr_pull_job_on_header;
+
+
+ r = pull_job_begin(i->ancestry_job);
+ if (r < 0) {
+ log_error_errno(r, "Failed to start ancestry job: %m");
+ goto finish;
+ }
+
+ } else if (i->ancestry_job == j) {
+
+ _cleanup_json_variant_unref_ JsonVariant *doc = NULL, *compat = NULL;
+ JsonVariant *e = NULL;
+ _cleanup_strv_free_ char **ancestry = NULL;
+ size_t allocated = 0, size = 0;
+ char *path = NULL, **k = NULL;
+
+ r = json_parse((const char *)j->payload, &doc);
+ if (r < 0) {
+ log_error("Invalid JSON Manifest");
+ goto finish;
+ }
+
+ e = json_variant_value(doc, "fsLayers");
+ if (!e || e->type != JSON_VARIANT_ARRAY || e->size == 0) {
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ log_info("JSON manifest with schema v%"PRIi64" for %s parsed!",
+ json_variant_integer(json_variant_value(doc, "schemaVersion")),
+ json_variant_string(json_variant_value(doc, "name")));
+
+ for (unsigned z = 0; z < e->size; z++) {
+ JsonVariant *f = json_variant_element(e, z), *g = NULL;
+ const char *layer;
+ if (f->type != JSON_VARIANT_OBJECT) {
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ g = json_variant_value(f, "blobSum");
+
+ layer = json_variant_string(g);
+ if (!dkr_digest_is_valid(layer)) {
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ if (!GREEDY_REALLOC(ancestry, allocated, size + 2)) {
+ r = -ENOMEM;
+ log_oom();
+ goto finish;
+ }
+
+ ancestry[size] = strdup(layer);
+ if (!ancestry[size]) {
+ r = -ENOMEM;
+ log_oom();
+ goto finish;
+ }
+
+ ancestry[size+1] = NULL;
+ size += 1;
+ }
+
+ e = json_variant_value(doc, "history");
+ if (!e || e->type != JSON_VARIANT_ARRAY) {
+ r = -EBADMSG;
+ goto finish;
+ }
+
+ e = json_variant_element(e, 0);
+ e = json_variant_value(e, "v1Compatibility");
+ r = json_parse(json_variant_string(e), &compat);
+ if (r < 0) {
+ log_error("Invalid v1Compatibility JSON");
+ goto finish;
+ }
+
+ e = json_variant_value(compat, "id");
+
+ strv_free(i->ancestry);
+ i->ancestry = strv_reverse(strv_uniq(ancestry));
+ i->n_ancestry = strv_length(i->ancestry);
+ i->current_ancestry = 0;
+ i->id = strdup(i->ancestry[i->n_ancestry - 1]);
+ if (!i->id) {
+ r = -ENOMEM;
+ log_oom();
+ goto finish;
+ }
+ path = strjoin(i->image_root, "/.dkr-", json_variant_string(e), NULL);
+ if (!path) {
+ r = -ENOMEM;
+ log_oom();
+ goto finish;
+ }
+ free(i->image_root);
+ i->image_root = path;
+ ancestry = NULL;
+
+ log_info("Required layers:\n");
+ STRV_FOREACH(k, i->ancestry)
+ log_info("\t%s", *k);
+ log_info("\nProvenance:\n\tImageID: %s\n\tDigest: %s", json_variant_string(e), i->response_digest);
+
+ dkr_pull_report_progress(i, DKR_DOWNLOADING);
+
+ r = dkr_pull_pull_layer_v2(i);
+ if (r < 0)
+ goto finish;
+
+ } else if (i->layer_job == j) {
+ assert(i->temp_path);
+ assert(i->final_path);
+
+ j->disk_fd = safe_close(j->disk_fd);
+
+ if (i->tar_pid > 0) {
+ r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
+ i->tar_pid = 0;
+ if (r < 0)
+ goto finish;
+ }
+
+ r = aufs_resolve(i->temp_path);
+ if (r < 0) {
+ log_error_errno(r, "Failed to resolve aufs whiteouts: %m");
+ goto finish;
+ }
+
+ r = btrfs_subvol_set_read_only(i->temp_path, true);
+ if (r < 0) {
+ log_error_errno(r, "Failed to mark snapshot read-only: %m");
+ goto finish;
+ }
+
+ if (rename(i->temp_path, i->final_path) < 0) {
+ log_error_errno(errno, "Failed to rename snaphsot: %m");
+ goto finish;
+ }
+
+ log_info("Completed writing to layer %s.", i->final_path);
+
+ i->layer_job = pull_job_unref(i->layer_job);
+ free(i->temp_path);
+ i->temp_path = NULL;
+ free(i->final_path);
+ i->final_path = NULL;
+
+ i->current_ancestry ++;
+ r = dkr_pull_pull_layer_v2(i);
+ if (r < 0)
+ goto finish;
+
+ } else if (i->json_job != j)
+ assert_not_reached("Got finished event for unknown curl object");
+
+ if (!dkr_pull_is_done(i))
+ return;
+
+ dkr_pull_report_progress(i, DKR_COPYING);
+
+ r = dkr_pull_make_local_copy(i, DKR_PULL_V2);
+ if (r < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (i->on_finished)
+ i->on_finished(i, r, i->userdata);
+ else
+ sd_event_exit(i->event, r);
+
+}
+
+static void dkr_pull_job_on_finished(PullJob *j) {
+ DkrPull *i;
int r;
assert(j);
@@ -608,25 +1057,25 @@ static void dkr_import_job_on_finished(ImportJob *j) {
}
log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]);
- dkr_import_report_progress(i, DKR_RESOLVING);
+ dkr_pull_report_progress(i, DKR_RESOLVING);
- url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->tag);
- r = import_job_new(&i->tags_job, url, i->glue, i);
+ url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->reference);
+ r = pull_job_new(&i->tags_job, url, i->glue, i);
if (r < 0) {
log_error_errno(r, "Failed to allocate tags job: %m");
goto finish;
}
- r = dkr_import_add_token(i, i->tags_job);
+ r = dkr_pull_add_token(i, i->tags_job);
if (r < 0) {
log_oom();
goto finish;
}
- i->tags_job->on_finished = dkr_import_job_on_finished;
- i->tags_job->on_progress = dkr_import_job_on_progress;
+ i->tags_job->on_finished = dkr_pull_job_on_finished;
+ i->tags_job->on_progress = dkr_pull_job_on_progress;
- r = import_job_begin(i->tags_job);
+ r = pull_job_begin(i->tags_job);
if (r < 0) {
log_error_errno(r, "Failed to start tags job: %m");
goto finish;
@@ -650,47 +1099,47 @@ static void dkr_import_job_on_finished(ImportJob *j) {
i->id = id;
log_info("Tag lookup succeeded, resolved to layer %s.", i->id);
- dkr_import_report_progress(i, DKR_METADATA);
+ dkr_pull_report_progress(i, DKR_METADATA);
url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/ancestry");
- r = import_job_new(&i->ancestry_job, url, i->glue, i);
+ r = pull_job_new(&i->ancestry_job, url, i->glue, i);
if (r < 0) {
log_error_errno(r, "Failed to allocate ancestry job: %m");
goto finish;
}
- r = dkr_import_add_token(i, i->ancestry_job);
+ r = dkr_pull_add_token(i, i->ancestry_job);
if (r < 0) {
log_oom();
goto finish;
}
- i->ancestry_job->on_finished = dkr_import_job_on_finished;
- i->ancestry_job->on_progress = dkr_import_job_on_progress;
+ i->ancestry_job->on_finished = dkr_pull_job_on_finished;
+ i->ancestry_job->on_progress = dkr_pull_job_on_progress;
url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/json");
- r = import_job_new(&i->json_job, url, i->glue, i);
+ r = pull_job_new(&i->json_job, url, i->glue, i);
if (r < 0) {
log_error_errno(r, "Failed to allocate json job: %m");
goto finish;
}
- r = dkr_import_add_token(i, i->json_job);
+ r = dkr_pull_add_token(i, i->json_job);
if (r < 0) {
log_oom();
goto finish;
}
- i->json_job->on_finished = dkr_import_job_on_finished;
- i->json_job->on_progress = dkr_import_job_on_progress;
+ i->json_job->on_finished = dkr_pull_job_on_finished;
+ i->json_job->on_progress = dkr_pull_job_on_progress;
- r = import_job_begin(i->ancestry_job);
+ r = pull_job_begin(i->ancestry_job);
if (r < 0) {
log_error_errno(r, "Failed to start ancestry job: %m");
goto finish;
}
- r = import_job_begin(i->json_job);
+ r = pull_job_begin(i->json_job);
if (r < 0) {
log_error_errno(r, "Failed to start json job: %m");
goto finish;
@@ -725,9 +1174,9 @@ static void dkr_import_job_on_finished(ImportJob *j) {
i->n_ancestry = n;
i->current_ancestry = 0;
- dkr_import_report_progress(i, DKR_DOWNLOADING);
+ dkr_pull_report_progress(i, DKR_DOWNLOADING);
- r = dkr_import_pull_layer(i);
+ r = dkr_pull_pull_layer(i);
if (r < 0)
goto finish;
@@ -763,31 +1212,30 @@ static void dkr_import_job_on_finished(ImportJob *j) {
log_info("Completed writing to layer %s.", i->final_path);
- i->layer_job = import_job_unref(i->layer_job);
+ i->layer_job = pull_job_unref(i->layer_job);
free(i->temp_path);
i->temp_path = NULL;
free(i->final_path);
i->final_path = NULL;
i->current_ancestry ++;
- r = dkr_import_pull_layer(i);
+ r = dkr_pull_pull_layer(i);
if (r < 0)
goto finish;
} else if (i->json_job != j)
assert_not_reached("Got finished event for unknown curl object");
- if (!dkr_import_is_done(i))
+ if (!dkr_pull_is_done(i))
return;
- dkr_import_report_progress(i, DKR_COPYING);
+ dkr_pull_report_progress(i, DKR_COPYING);
- r = dkr_import_make_local_copy(i);
+ r = dkr_pull_make_local_copy(i, DKR_PULL_V1);
if (r < 0)
goto finish;
r = 0;
-
finish:
if (i->on_finished)
i->on_finished(i, r, i->userdata);
@@ -795,52 +1243,38 @@ finish:
sd_event_exit(i->event, r);
}
-static int dkr_import_job_on_header(ImportJob *j, const char *header, size_t sz) {
- _cleanup_free_ char *registry = NULL;
- char *token;
- DkrImport *i;
- int r;
+static int get_protocol_address(char **protocol, char **address, const char *url) {
+ const char *sep, *dot;
+ _cleanup_free_ char *a = NULL, *p = NULL;
- assert(j);
- assert(j->userdata);
+ sep = strstr(url, "://");
+ if (!sep)
+ return -EINVAL;
- i = j->userdata;
+ dot = strrchr(url, '.');
+ if (!dot)
+ return -EINVAL;
+ dot--;
- r = curl_header_strdup(header, sz, HEADER_TOKEN, &token);
- if (r < 0)
+ p = strndup(url, (sep - url) + 3);
+ if (!p)
return log_oom();
- if (r > 0) {
- free(i->response_token);
- i->response_token = token;
- return 0;
- }
- r = curl_header_strdup(header, sz, HEADER_REGISTRY, &registry);
- if (r < 0)
- return log_oom();
- if (r > 0) {
- char **l, **k;
-
- l = strv_split(registry, ",");
- if (!l)
- return log_oom();
+ while (dot > (sep + 3) && *dot != '.')
+ dot--;
- STRV_FOREACH(k, l) {
- if (!hostname_is_valid(*k)) {
- log_error("Registry hostname is not valid.");
- strv_free(l);
- return -EBADMSG;
- }
- }
+ a = strdup(dot + 1);
+ if (!a)
+ return log_oom();
- strv_free(i->response_registries);
- i->response_registries = l;
- }
+ *address = a;
+ *protocol = p;
+ a = p = NULL;
return 0;
}
-int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char *local, bool force_local) {
+int dkr_pull_start(DkrPull *i, const char *name, const char *reference, const char *local, bool force_local, DkrPullVersion version) {
const char *url;
int r;
@@ -849,7 +1283,7 @@ int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char
if (!dkr_name_is_valid(name))
return -EINVAL;
- if (tag && !dkr_tag_is_valid(tag))
+ if (reference && !dkr_ref_is_valid(reference))
return -EINVAL;
if (local && !machine_name_is_valid(local))
@@ -858,8 +1292,14 @@ int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char
if (i->images_job)
return -EBUSY;
- if (!tag)
- tag = "latest";
+ if (!reference)
+ reference = "latest";
+
+ free(i->index_protocol);
+ free(i->index_address);
+ r = get_protocol_address(&i->index_protocol, &i->index_address, i->index_url);
+ if (r < 0)
+ return r;
r = free_and_strdup(&i->local, local);
if (r < 0)
@@ -869,23 +1309,27 @@ int dkr_import_pull(DkrImport *i, const char *name, const char *tag, const char
r = free_and_strdup(&i->name, name);
if (r < 0)
return r;
- r = free_and_strdup(&i->tag, tag);
+ r = free_and_strdup(&i->reference, reference);
if (r < 0)
return r;
url = strjoina(i->index_url, "/v1/repositories/", name, "/images");
- r = import_job_new(&i->images_job, url, i->glue, i);
+ r = pull_job_new(&i->images_job, url, i->glue, i);
if (r < 0)
return r;
- r = dkr_import_add_token(i, i->images_job);
+ r = dkr_pull_add_token(i, i->images_job);
if (r < 0)
return r;
- i->images_job->on_finished = dkr_import_job_on_finished;
- i->images_job->on_header = dkr_import_job_on_header;
- i->images_job->on_progress = dkr_import_job_on_progress;
+ if (version == DKR_PULL_V1)
+ i->images_job->on_finished = dkr_pull_job_on_finished;
+ else
+ i->images_job->on_finished = dkr_pull_job_on_finished_v2;
+
+ i->images_job->on_header = dkr_pull_job_on_header;
+ i->images_job->on_progress = dkr_pull_job_on_progress;
- return import_job_begin(i->images_job);
+ return pull_job_begin(i->images_job);
}
diff --git a/src/import/pull-dkr.h b/src/import/pull-dkr.h
new file mode 100644
index 0000000000..33d18cb394
--- /dev/null
+++ b/src/import/pull-dkr.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "sd-event.h"
+#include "util.h"
+
+typedef enum { DKR_PULL_V1, DKR_PULL_V2 } DkrPullVersion;
+typedef struct DkrPull DkrPull;
+
+typedef void (*DkrPullFinished)(DkrPull *pull, int error, void *userdata);
+
+int dkr_pull_new(DkrPull **pull, sd_event *event, const char *index_url, const char *image_root, DkrPullFinished on_finished, void *userdata);
+DkrPull* dkr_pull_unref(DkrPull *pull);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(DkrPull*, dkr_pull_unref);
+
+int dkr_pull_start(DkrPull *pull, const char *name, const char *tag, const char *local, bool force_local, DkrPullVersion version);
diff --git a/src/import/import-job.c b/src/import/pull-job.c
index 809486500b..42939f2104 100644
--- a/src/import/import-job.c
+++ b/src/import/pull-job.c
@@ -22,9 +22,10 @@
#include <sys/xattr.h>
#include "strv.h"
-#include "import-job.h"
+#include "machine-pool.h"
+#include "pull-job.h"
-ImportJob* import_job_unref(ImportJob *j) {
+PullJob* pull_job_unref(PullJob *j) {
if (!j)
return NULL;
@@ -33,12 +34,7 @@ ImportJob* import_job_unref(ImportJob *j) {
safe_close(j->disk_fd);
- if (j->compressed == IMPORT_JOB_XZ)
- lzma_end(&j->xz);
- else if (j->compressed == IMPORT_JOB_GZIP)
- inflateEnd(&j->gzip);
- else if (j->compressed == IMPORT_JOB_BZIP2)
- BZ2_bzDecompressEnd(&j->bzip2);
+ import_compress_free(&j->compress);
if (j->checksum_context)
gcry_md_close(j->checksum_context);
@@ -54,19 +50,19 @@ ImportJob* import_job_unref(ImportJob *j) {
return NULL;
}
-static void import_job_finish(ImportJob *j, int ret) {
+static void pull_job_finish(PullJob *j, int ret) {
assert(j);
- if (j->state == IMPORT_JOB_DONE ||
- j->state == IMPORT_JOB_FAILED)
+ if (j->state == PULL_JOB_DONE ||
+ j->state == PULL_JOB_FAILED)
return;
if (ret == 0) {
- j->state = IMPORT_JOB_DONE;
+ j->state = PULL_JOB_DONE;
j->progress_percent = 100;
log_info("Download of %s complete.", j->url);
} else {
- j->state = IMPORT_JOB_FAILED;
+ j->state = PULL_JOB_FAILED;
j->error = ret;
}
@@ -74,16 +70,16 @@ static void import_job_finish(ImportJob *j, int ret) {
j->on_finished(j);
}
-void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
- ImportJob *j = NULL;
+void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
+ PullJob *j = NULL;
CURLcode code;
long status;
int r;
- if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, &j) != CURLE_OK)
+ if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK)
return;
- if (!j || j->state == IMPORT_JOB_DONE || j->state == IMPORT_JOB_FAILED)
+ if (!j || j->state == PULL_JOB_DONE || j->state == PULL_JOB_FAILED)
return;
if (result != CURLE_OK) {
@@ -112,7 +108,7 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
goto finish;
}
- if (j->state != IMPORT_JOB_RUNNING) {
+ if (j->state != PULL_JOB_RUNNING) {
log_error("Premature connection termination.");
r = -EIO;
goto finish;
@@ -149,8 +145,7 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
* sparse and we just seeked for the last part */
if (ftruncate(j->disk_fd, j->written_uncompressed) < 0) {
- log_error_errno(errno, "Failed to truncate file: %m");
- r = -errno;
+ r = log_error_errno(errno, "Failed to truncate file: %m");
goto finish;
}
@@ -173,10 +168,11 @@ void import_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
r = 0;
finish:
- import_job_finish(j, r);
+ pull_job_finish(j, r);
}
-static int import_job_write_uncompressed(ImportJob *j, void *p, size_t sz) {
+static int pull_job_write_uncompressed(const void *p, size_t sz, void *userdata) {
+ PullJob *j = userdata;
ssize_t n;
assert(j);
@@ -197,14 +193,17 @@ static int import_job_write_uncompressed(ImportJob *j, void *p, size_t sz) {
if (j->disk_fd >= 0) {
+ if (j->grow_machine_directory && j->written_since_last_grow >= GROW_INTERVAL_BYTES) {
+ j->written_since_last_grow = 0;
+ grow_machine_directory();
+ }
+
if (j->allow_sparse)
n = sparse_write(j->disk_fd, p, sz, 64);
else
n = write(j->disk_fd, p, sz);
- if (n < 0) {
- log_error_errno(errno, "Failed to write file: %m");
- return -errno;
- }
+ if (n < 0)
+ return log_error_errno(errno, "Failed to write file: %m");
if ((size_t) n < sz) {
log_error("Short write");
return -EIO;
@@ -219,11 +218,12 @@ static int import_job_write_uncompressed(ImportJob *j, void *p, size_t sz) {
}
j->written_uncompressed += sz;
+ j->written_since_last_grow += sz;
return 0;
}
-static int import_job_write_compressed(ImportJob *j, void *p, size_t sz) {
+static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) {
int r;
assert(j);
@@ -251,95 +251,16 @@ static int import_job_write_compressed(ImportJob *j, void *p, size_t sz) {
if (j->checksum_context)
gcry_md_write(j->checksum_context, p, sz);
- switch (j->compressed) {
-
- case IMPORT_JOB_UNCOMPRESSED:
- r = import_job_write_uncompressed(j, p, sz);
- if (r < 0)
- return r;
-
- break;
-
- case IMPORT_JOB_XZ:
- j->xz.next_in = p;
- j->xz.avail_in = sz;
-
- while (j->xz.avail_in > 0) {
- uint8_t buffer[16 * 1024];
- lzma_ret lzr;
-
- j->xz.next_out = buffer;
- j->xz.avail_out = sizeof(buffer);
-
- lzr = lzma_code(&j->xz, LZMA_RUN);
- if (lzr != LZMA_OK && lzr != LZMA_STREAM_END) {
- log_error("Decompression error.");
- return -EIO;
- }
-
- r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->xz.avail_out);
- if (r < 0)
- return r;
- }
-
- break;
-
- case IMPORT_JOB_GZIP:
- j->gzip.next_in = p;
- j->gzip.avail_in = sz;
-
- while (j->gzip.avail_in > 0) {
- uint8_t buffer[16 * 1024];
-
- j->gzip.next_out = buffer;
- j->gzip.avail_out = sizeof(buffer);
-
- r = inflate(&j->gzip, Z_NO_FLUSH);
- if (r != Z_OK && r != Z_STREAM_END) {
- log_error("Decompression error.");
- return -EIO;
- }
-
- r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->gzip.avail_out);
- if (r < 0)
- return r;
- }
-
- break;
-
- case IMPORT_JOB_BZIP2:
- j->bzip2.next_in = p;
- j->bzip2.avail_in = sz;
-
- while (j->bzip2.avail_in > 0) {
- uint8_t buffer[16 * 1024];
-
- j->bzip2.next_out = (char*) buffer;
- j->bzip2.avail_out = sizeof(buffer);
-
- r = BZ2_bzDecompress(&j->bzip2);
- if (r != BZ_OK && r != BZ_STREAM_END) {
- log_error("Decompression error.");
- return -EIO;
- }
-
- r = import_job_write_uncompressed(j, buffer, sizeof(buffer) - j->bzip2.avail_out);
- if (r < 0)
- return r;
- }
-
- break;
-
- default:
- assert_not_reached("Unknown compression");
- }
+ r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j);
+ if (r < 0)
+ return r;
j->written_compressed += sz;
return 0;
}
-static int import_job_open_disk(ImportJob *j) {
+static int pull_job_open_disk(PullJob *j) {
int r;
assert(j);
@@ -373,17 +294,7 @@ static int import_job_open_disk(ImportJob *j) {
return 0;
}
-static int import_job_detect_compression(ImportJob *j) {
- static const uint8_t xz_signature[] = {
- 0xfd, '7', 'z', 'X', 'Z', 0x00
- };
- static const uint8_t gzip_signature[] = {
- 0x1f, 0x8b
- };
- static const uint8_t bzip2_signature[] = {
- 'B', 'Z', 'h'
- };
-
+static int pull_job_detect_compression(PullJob *j) {
_cleanup_free_ uint8_t *stub = NULL;
size_t stub_size;
@@ -391,49 +302,15 @@ static int import_job_detect_compression(ImportJob *j) {
assert(j);
- if (j->payload_size < MAX3(sizeof(xz_signature),
- sizeof(gzip_signature),
- sizeof(bzip2_signature)))
+ r = import_uncompress_detect(&j->compress, j->payload, j->payload_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to initialize compressor: %m");
+ if (r == 0)
return 0;
- if (memcmp(j->payload, xz_signature, sizeof(xz_signature)) == 0)
- j->compressed = IMPORT_JOB_XZ;
- else if (memcmp(j->payload, gzip_signature, sizeof(gzip_signature)) == 0)
- j->compressed = IMPORT_JOB_GZIP;
- else if (memcmp(j->payload, bzip2_signature, sizeof(bzip2_signature)) == 0)
- j->compressed = IMPORT_JOB_BZIP2;
- else
- j->compressed = IMPORT_JOB_UNCOMPRESSED;
-
- log_debug("Stream is XZ compressed: %s", yes_no(j->compressed == IMPORT_JOB_XZ));
- log_debug("Stream is GZIP compressed: %s", yes_no(j->compressed == IMPORT_JOB_GZIP));
- log_debug("Stream is BZIP2 compressed: %s", yes_no(j->compressed == IMPORT_JOB_BZIP2));
-
- if (j->compressed == IMPORT_JOB_XZ) {
- lzma_ret xzr;
-
- xzr = lzma_stream_decoder(&j->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK);
- if (xzr != LZMA_OK) {
- log_error("Failed to initialize XZ decoder.");
- return -EIO;
- }
- }
- if (j->compressed == IMPORT_JOB_GZIP) {
- r = inflateInit2(&j->gzip, 15+16);
- if (r != Z_OK) {
- log_error("Failed to initialize gzip decoder.");
- return -EIO;
- }
- }
- if (j->compressed == IMPORT_JOB_BZIP2) {
- r = BZ2_bzDecompressInit(&j->bzip2, 0, 0);
- if (r != BZ_OK) {
- log_error("Failed to initialize bzip2 decoder.");
- return -EIO;
- }
- }
+ log_debug("Stream is compressed: %s", import_compress_type_to_string(j->compress.type));
- r = import_job_open_disk(j);
+ r = pull_job_open_disk(j);
if (r < 0)
return r;
@@ -445,17 +322,17 @@ static int import_job_detect_compression(ImportJob *j) {
j->payload_size = 0;
j->payload_allocated = 0;
- j->state = IMPORT_JOB_RUNNING;
+ j->state = PULL_JOB_RUNNING;
- r = import_job_write_compressed(j, stub, stub_size);
+ r = pull_job_write_compressed(j, stub, stub_size);
if (r < 0)
return r;
return 0;
}
-static size_t import_job_write_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
- ImportJob *j = userdata;
+static size_t pull_job_write_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
+ PullJob *j = userdata;
size_t sz = size * nmemb;
int r;
@@ -464,7 +341,7 @@ static size_t import_job_write_callback(void *contents, size_t size, size_t nmem
switch (j->state) {
- case IMPORT_JOB_ANALYZING:
+ case PULL_JOB_ANALYZING:
/* Let's first check what it actually is */
if (!GREEDY_REALLOC(j->payload, j->payload_allocated, j->payload_size + sz)) {
@@ -475,22 +352,22 @@ static size_t import_job_write_callback(void *contents, size_t size, size_t nmem
memcpy(j->payload + j->payload_size, contents, sz);
j->payload_size += sz;
- r = import_job_detect_compression(j);
+ r = pull_job_detect_compression(j);
if (r < 0)
goto fail;
break;
- case IMPORT_JOB_RUNNING:
+ case PULL_JOB_RUNNING:
- r = import_job_write_compressed(j, contents, sz);
+ r = pull_job_write_compressed(j, contents, sz);
if (r < 0)
goto fail;
break;
- case IMPORT_JOB_DONE:
- case IMPORT_JOB_FAILED:
+ case PULL_JOB_DONE:
+ case PULL_JOB_FAILED:
r = -ESTALE;
goto fail;
@@ -501,12 +378,12 @@ static size_t import_job_write_callback(void *contents, size_t size, size_t nmem
return sz;
fail:
- import_job_finish(j, r);
+ pull_job_finish(j, r);
return 0;
}
-static size_t import_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
- ImportJob *j = userdata;
+static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
+ PullJob *j = userdata;
size_t sz = size * nmemb;
_cleanup_free_ char *length = NULL, *last_modified = NULL;
char *etag;
@@ -515,12 +392,12 @@ static size_t import_job_header_callback(void *contents, size_t size, size_t nme
assert(contents);
assert(j);
- if (j->state == IMPORT_JOB_DONE || j->state == IMPORT_JOB_FAILED) {
+ if (j->state == PULL_JOB_DONE || j->state == PULL_JOB_FAILED) {
r = -ESTALE;
goto fail;
}
- assert(j->state == IMPORT_JOB_ANALYZING);
+ assert(j->state == PULL_JOB_ANALYZING);
r = curl_header_strdup(contents, sz, "ETag:", &etag);
if (r < 0) {
@@ -534,7 +411,7 @@ static size_t import_job_header_callback(void *contents, size_t size, size_t nme
if (strv_contains(j->old_etags, j->etag)) {
log_info("Image already downloaded. Skipping download.");
j->etag_exists = true;
- import_job_finish(j, 0);
+ pull_job_finish(j, 0);
return sz;
}
@@ -583,12 +460,12 @@ static size_t import_job_header_callback(void *contents, size_t size, size_t nme
return sz;
fail:
- import_job_finish(j, r);
+ pull_job_finish(j, r);
return 0;
}
-static int import_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
- ImportJob *j = userdata;
+static int pull_job_progress_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
+ PullJob *j = userdata;
unsigned percent;
usec_t n;
@@ -630,18 +507,18 @@ static int import_job_progress_callback(void *userdata, curl_off_t dltotal, curl
return 0;
}
-int import_job_new(ImportJob **ret, const char *url, CurlGlue *glue, void *userdata) {
- _cleanup_(import_job_unrefp) ImportJob *j = NULL;
+int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata) {
+ _cleanup_(pull_job_unrefp) PullJob *j = NULL;
assert(url);
assert(glue);
assert(ret);
- j = new0(ImportJob, 1);
+ j = new0(PullJob, 1);
if (!j)
return -ENOMEM;
- j->state = IMPORT_JOB_INIT;
+ j->state = PULL_JOB_INIT;
j->disk_fd = -1;
j->userdata = userdata;
j->glue = glue;
@@ -659,14 +536,17 @@ int import_job_new(ImportJob **ret, const char *url, CurlGlue *glue, void *userd
return 0;
}
-int import_job_begin(ImportJob *j) {
+int pull_job_begin(PullJob *j) {
int r;
assert(j);
- if (j->state != IMPORT_JOB_INIT)
+ if (j->state != PULL_JOB_INIT)
return -EBUSY;
+ if (j->grow_machine_directory)
+ grow_machine_directory();
+
r = curl_glue_make(&j->curl, j->url, j);
if (r < 0)
return r;
@@ -702,19 +582,19 @@ int import_job_begin(ImportJob *j) {
return -EIO;
}
- if (curl_easy_setopt(j->curl, CURLOPT_WRITEFUNCTION, import_job_write_callback) != CURLE_OK)
+ if (curl_easy_setopt(j->curl, CURLOPT_WRITEFUNCTION, pull_job_write_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_WRITEDATA, j) != CURLE_OK)
return -EIO;
- if (curl_easy_setopt(j->curl, CURLOPT_HEADERFUNCTION, import_job_header_callback) != CURLE_OK)
+ if (curl_easy_setopt(j->curl, CURLOPT_HEADERFUNCTION, pull_job_header_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_HEADERDATA, j) != CURLE_OK)
return -EIO;
- if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, import_job_progress_callback) != CURLE_OK)
+ if (curl_easy_setopt(j->curl, CURLOPT_XFERINFOFUNCTION, pull_job_progress_callback) != CURLE_OK)
return -EIO;
if (curl_easy_setopt(j->curl, CURLOPT_XFERINFODATA, j) != CURLE_OK)
@@ -727,7 +607,7 @@ int import_job_begin(ImportJob *j) {
if (r < 0)
return r;
- j->state = IMPORT_JOB_ANALYZING;
+ j->state = PULL_JOB_ANALYZING;
return 0;
}
diff --git a/src/import/pull-job.h b/src/import/pull-job.h
new file mode 100644
index 0000000000..3239aeac20
--- /dev/null
+++ b/src/import/pull-job.h
@@ -0,0 +1,117 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <gcrypt.h>
+
+#include "macro.h"
+#include "curl-util.h"
+#include "import-compress.h"
+
+typedef struct PullJob PullJob;
+
+typedef void (*PullJobFinished)(PullJob *job);
+typedef int (*PullJobOpenDisk)(PullJob *job);
+typedef int (*PullJobHeader)(PullJob *job, const char *header, size_t sz);
+typedef void (*PullJobProgress)(PullJob *job);
+
+typedef enum PullJobState {
+ PULL_JOB_INIT,
+ PULL_JOB_ANALYZING, /* Still reading into ->payload, to figure out what we have */
+ PULL_JOB_RUNNING, /* Writing to destination */
+ PULL_JOB_DONE,
+ PULL_JOB_FAILED,
+ _PULL_JOB_STATE_MAX,
+ _PULL_JOB_STATE_INVALID = -1,
+} PullJobState;
+
+#define PULL_JOB_STATE_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
+
+typedef enum PullJobCompression {
+ PULL_JOB_UNCOMPRESSED,
+ PULL_JOB_XZ,
+ PULL_JOB_GZIP,
+ PULL_JOB_BZIP2,
+ _PULL_JOB_COMPRESSION_MAX,
+ _PULL_JOB_COMPRESSION_INVALID = -1,
+} PullJobCompression;
+
+struct PullJob {
+ PullJobState state;
+ int error;
+
+ char *url;
+
+ void *userdata;
+ PullJobFinished on_finished;
+ PullJobOpenDisk on_open_disk;
+ PullJobHeader on_header;
+ PullJobProgress on_progress;
+
+ CurlGlue *glue;
+ CURL *curl;
+ struct curl_slist *request_header;
+
+ char *etag;
+ char **old_etags;
+ bool etag_exists;
+
+ uint64_t content_length;
+ uint64_t written_compressed;
+ uint64_t written_uncompressed;
+
+ uint64_t uncompressed_max;
+ uint64_t compressed_max;
+
+ uint8_t *payload;
+ size_t payload_size;
+ size_t payload_allocated;
+
+ int disk_fd;
+
+ usec_t mtime;
+
+ ImportCompress compress;
+
+ unsigned progress_percent;
+ usec_t start_usec;
+ usec_t last_status_usec;
+
+ bool allow_sparse;
+
+ bool calc_checksum;
+ gcry_md_hd_t checksum_context;
+
+ char *checksum;
+
+ bool grow_machine_directory;
+ uint64_t written_since_last_grow;
+};
+
+int pull_job_new(PullJob **job, const char *url, CurlGlue *glue, void *userdata);
+PullJob* pull_job_unref(PullJob *job);
+
+int pull_job_begin(PullJob *j);
+
+void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(PullJob*, pull_job_unref);
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
new file mode 100644
index 0000000000..b65bb0c034
--- /dev/null
+++ b/src/import/pull-raw.c
@@ -0,0 +1,517 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/xattr.h>
+#include <linux/fs.h>
+#include <curl/curl.h>
+
+#include "sd-daemon.h"
+#include "utf8.h"
+#include "strv.h"
+#include "copy.h"
+#include "btrfs-util.h"
+#include "util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "rm-rf.h"
+#include "path-util.h"
+#include "import-util.h"
+#include "import-common.h"
+#include "curl-util.h"
+#include "qcow2-util.h"
+#include "pull-job.h"
+#include "pull-common.h"
+#include "pull-raw.h"
+
+typedef enum RawProgress {
+ RAW_DOWNLOADING,
+ RAW_VERIFYING,
+ RAW_UNPACKING,
+ RAW_FINALIZING,
+ RAW_COPYING,
+} RawProgress;
+
+struct RawPull {
+ sd_event *event;
+ CurlGlue *glue;
+
+ char *image_root;
+
+ PullJob *raw_job;
+ PullJob *checksum_job;
+ PullJob *signature_job;
+
+ RawPullFinished on_finished;
+ void *userdata;
+
+ char *local;
+ bool force_local;
+ bool grow_machine_directory;
+
+ char *temp_path;
+ char *final_path;
+
+ ImportVerify verify;
+};
+
+RawPull* raw_pull_unref(RawPull *i) {
+ if (!i)
+ return NULL;
+
+ pull_job_unref(i->raw_job);
+ pull_job_unref(i->checksum_job);
+ pull_job_unref(i->signature_job);
+
+ curl_glue_unref(i->glue);
+ sd_event_unref(i->event);
+
+ if (i->temp_path) {
+ (void) unlink(i->temp_path);
+ free(i->temp_path);
+ }
+
+ free(i->final_path);
+ free(i->image_root);
+ free(i->local);
+ free(i);
+
+ return NULL;
+}
+
+int raw_pull_new(
+ RawPull **ret,
+ sd_event *event,
+ const char *image_root,
+ RawPullFinished on_finished,
+ void *userdata) {
+
+ _cleanup_(raw_pull_unrefp) RawPull *i = NULL;
+ int r;
+
+ assert(ret);
+
+ i = new0(RawPull, 1);
+ if (!i)
+ return -ENOMEM;
+
+ i->on_finished = on_finished;
+ i->userdata = userdata;
+
+ i->image_root = strdup(image_root ?: "/var/lib/machines");
+ if (!i->image_root)
+ return -ENOMEM;
+
+ i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
+
+ if (event)
+ i->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&i->event);
+ if (r < 0)
+ return r;
+ }
+
+ r = curl_glue_new(&i->glue, i->event);
+ if (r < 0)
+ return r;
+
+ i->glue->on_finished = pull_job_curl_on_finished;
+ i->glue->userdata = i;
+
+ *ret = i;
+ i = NULL;
+
+ return 0;
+}
+
+static void raw_pull_report_progress(RawPull *i, RawProgress p) {
+ unsigned percent;
+
+ assert(i);
+
+ switch (p) {
+
+ case RAW_DOWNLOADING: {
+ unsigned remain = 80;
+
+ percent = 0;
+
+ if (i->checksum_job) {
+ percent += i->checksum_job->progress_percent * 5 / 100;
+ remain -= 5;
+ }
+
+ if (i->signature_job) {
+ percent += i->signature_job->progress_percent * 5 / 100;
+ remain -= 5;
+ }
+
+ if (i->raw_job)
+ percent += i->raw_job->progress_percent * remain / 100;
+ break;
+ }
+
+ case RAW_VERIFYING:
+ percent = 80;
+ break;
+
+ case RAW_UNPACKING:
+ percent = 85;
+ break;
+
+ case RAW_FINALIZING:
+ percent = 90;
+ break;
+
+ case RAW_COPYING:
+ percent = 95;
+ break;
+
+ default:
+ assert_not_reached("Unknown progress state");
+ }
+
+ sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
+ log_debug("Combined progress %u%%", percent);
+}
+
+static int raw_pull_maybe_convert_qcow2(RawPull *i) {
+ _cleanup_close_ int converted_fd = -1;
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(i);
+ assert(i->raw_job);
+
+ r = qcow2_detect(i->raw_job->disk_fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to detect whether this is a QCOW2 image: %m");
+ if (r == 0)
+ return 0;
+
+ /* This is a QCOW2 image, let's convert it */
+ r = tempfn_random(i->final_path, &t);
+ if (r < 0)
+ return log_oom();
+
+ converted_fd = open(t, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+ if (converted_fd < 0)
+ return log_error_errno(errno, "Failed to create %s: %m", t);
+
+ r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ if (r < 0)
+ log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);
+
+ log_info("Unpacking QCOW2 file.");
+
+ r = qcow2_convert(i->raw_job->disk_fd, converted_fd);
+ if (r < 0) {
+ unlink(t);
+ return log_error_errno(r, "Failed to convert qcow2 image: %m");
+ }
+
+ (void) unlink(i->temp_path);
+ free(i->temp_path);
+ i->temp_path = t;
+ t = NULL;
+
+ safe_close(i->raw_job->disk_fd);
+ i->raw_job->disk_fd = converted_fd;
+ converted_fd = -1;
+
+ return 1;
+}
+
+static int raw_pull_make_local_copy(RawPull *i) {
+ _cleanup_free_ char *tp = NULL;
+ _cleanup_close_ int dfd = -1;
+ const char *p;
+ int r;
+
+ assert(i);
+ assert(i->raw_job);
+
+ if (!i->local)
+ return 0;
+
+ if (i->raw_job->etag_exists) {
+ /* We have downloaded this one previously, reopen it */
+
+ assert(i->raw_job->disk_fd < 0);
+
+ if (!i->final_path) {
+ r = pull_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", ".raw", &i->final_path);
+ if (r < 0)
+ return log_oom();
+ }
+
+ i->raw_job->disk_fd = open(i->final_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (i->raw_job->disk_fd < 0)
+ return log_error_errno(errno, "Failed to open vendor image: %m");
+ } else {
+ /* We freshly downloaded the image, use it */
+
+ assert(i->raw_job->disk_fd >= 0);
+
+ if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) == (off_t) -1)
+ return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
+ }
+
+ p = strjoina(i->image_root, "/", i->local, ".raw");
+
+ if (i->force_local)
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+
+ r = tempfn_random(p, &tp);
+ if (r < 0)
+ return log_oom();
+
+ dfd = open(tp, O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+ if (dfd < 0)
+ return log_error_errno(errno, "Failed to create writable copy of image: %m");
+
+ /* Turn off COW writing. This should greatly improve
+ * performance on COW file systems like btrfs, since it
+ * reduces fragmentation caused by not allowing in-place
+ * writes. */
+ r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL);
+ if (r < 0)
+ log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp);
+
+ r = copy_bytes(i->raw_job->disk_fd, dfd, (off_t) -1, true);
+ if (r < 0) {
+ unlink(tp);
+ return log_error_errno(r, "Failed to make writable copy of image: %m");
+ }
+
+ (void) copy_times(i->raw_job->disk_fd, dfd);
+ (void) copy_xattr(i->raw_job->disk_fd, dfd);
+
+ dfd = safe_close(dfd);
+
+ r = rename(tp, p);
+ if (r < 0) {
+ unlink(tp);
+ return log_error_errno(errno, "Failed to move writable image into place: %m");
+ }
+
+ log_info("Created new local image '%s'.", i->local);
+ return 0;
+}
+
+static bool raw_pull_is_done(RawPull *i) {
+ assert(i);
+ assert(i->raw_job);
+
+ if (i->raw_job->state != PULL_JOB_DONE)
+ return false;
+ if (i->checksum_job && i->checksum_job->state != PULL_JOB_DONE)
+ return false;
+ if (i->signature_job && i->signature_job->state != PULL_JOB_DONE)
+ return false;
+
+ return true;
+}
+
+static void raw_pull_job_on_finished(PullJob *j) {
+ RawPull *i;
+ int r;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+ if (j->error != 0) {
+ if (j == i->checksum_job)
+ log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
+ else if (j == i->signature_job)
+ log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+ else
+ log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
+
+ r = j->error;
+ goto finish;
+ }
+
+ /* This is invoked if either the download completed
+ * successfully, or the download was skipped because we
+ * already have the etag. In this case ->etag_exists is
+ * true.
+ *
+ * We only do something when we got all three files */
+
+ if (!raw_pull_is_done(i))
+ return;
+
+ if (!i->raw_job->etag_exists) {
+ /* This is a new download, verify it, and move it into place */
+ assert(i->raw_job->disk_fd >= 0);
+
+ raw_pull_report_progress(i, RAW_VERIFYING);
+
+ r = pull_verify(i->raw_job, i->checksum_job, i->signature_job);
+ if (r < 0)
+ goto finish;
+
+ raw_pull_report_progress(i, RAW_UNPACKING);
+
+ r = raw_pull_maybe_convert_qcow2(i);
+ if (r < 0)
+ goto finish;
+
+ raw_pull_report_progress(i, RAW_FINALIZING);
+
+ r = import_make_read_only_fd(i->raw_job->disk_fd);
+ if (r < 0)
+ goto finish;
+
+ r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
+ if (r < 0) {
+ log_error_errno(r, "Failed to move RAW file into place: %m");
+ goto finish;
+ }
+
+ free(i->temp_path);
+ i->temp_path = NULL;
+ }
+
+ raw_pull_report_progress(i, RAW_COPYING);
+
+ r = raw_pull_make_local_copy(i);
+ if (r < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (i->on_finished)
+ i->on_finished(i, r, i->userdata);
+ else
+ sd_event_exit(i->event, r);
+}
+
+static int raw_pull_job_on_open_disk(PullJob *j) {
+ RawPull *i;
+ int r;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+ assert(i->raw_job == j);
+ assert(!i->final_path);
+ assert(!i->temp_path);
+
+ r = pull_make_path(j->url, j->etag, i->image_root, ".raw-", ".raw", &i->final_path);
+ if (r < 0)
+ return log_oom();
+
+ r = tempfn_random(i->final_path, &i->temp_path);
+ if (r < 0)
+ return log_oom();
+
+ (void) mkdir_parents_label(i->temp_path, 0700);
+
+ j->disk_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
+ if (j->disk_fd < 0)
+ return log_error_errno(errno, "Failed to create %s: %m", i->temp_path);
+
+ r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ if (r < 0)
+ log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
+
+ return 0;
+}
+
+static void raw_pull_job_on_progress(PullJob *j) {
+ RawPull *i;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+
+ raw_pull_report_progress(i, RAW_DOWNLOADING);
+}
+
+int raw_pull_start(RawPull *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
+ int r;
+
+ assert(i);
+ assert(verify < _IMPORT_VERIFY_MAX);
+ assert(verify >= 0);
+
+ if (!http_url_is_valid(url))
+ return -EINVAL;
+
+ if (local && !machine_name_is_valid(local))
+ return -EINVAL;
+
+ if (i->raw_job)
+ return -EBUSY;
+
+ r = free_and_strdup(&i->local, local);
+ if (r < 0)
+ return r;
+ i->force_local = force_local;
+ i->verify = verify;
+
+ /* Queue job for the image itself */
+ r = pull_job_new(&i->raw_job, url, i->glue, i);
+ if (r < 0)
+ return r;
+
+ i->raw_job->on_finished = raw_pull_job_on_finished;
+ i->raw_job->on_open_disk = raw_pull_job_on_open_disk;
+ i->raw_job->on_progress = raw_pull_job_on_progress;
+ i->raw_job->calc_checksum = verify != IMPORT_VERIFY_NO;
+ i->raw_job->grow_machine_directory = i->grow_machine_directory;
+
+ r = pull_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags);
+ if (r < 0)
+ return r;
+
+ r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i);
+ if (r < 0)
+ return r;
+
+ r = pull_job_begin(i->raw_job);
+ if (r < 0)
+ return r;
+
+ if (i->checksum_job) {
+ i->checksum_job->on_progress = raw_pull_job_on_progress;
+
+ r = pull_job_begin(i->checksum_job);
+ if (r < 0)
+ return r;
+ }
+
+ if (i->signature_job) {
+ i->signature_job->on_progress = raw_pull_job_on_progress;
+
+ r = pull_job_begin(i->signature_job);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/import/import-dkr.h b/src/import/pull-raw.h
index 633c767965..808f7be818 100644
--- a/src/import/import-dkr.h
+++ b/src/import/pull-raw.h
@@ -1,5 +1,7 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+#pragma once
+
/***
This file is part of systemd.
@@ -19,18 +21,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "sd-event.h"
-#include "util.h"
+#include "macro.h"
+#include "import-util.h"
-typedef struct DkrImport DkrImport;
+typedef struct RawPull RawPull;
-typedef void (*DkrImportFinished)(DkrImport *import, int error, void *userdata);
+typedef void (*RawPullFinished)(RawPull *pull, int error, void *userdata);
-int dkr_import_new(DkrImport **import, sd_event *event, const char *index_url, const char *image_root, DkrImportFinished on_finished, void *userdata);
-DkrImport* dkr_import_unref(DkrImport *import);
+int raw_pull_new(RawPull **pull, sd_event *event, const char *image_root, RawPullFinished on_finished, void *userdata);
+RawPull* raw_pull_unref(RawPull *pull);
-DEFINE_TRIVIAL_CLEANUP_FUNC(DkrImport*, dkr_import_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(RawPull*, raw_pull_unref);
-int dkr_import_pull(DkrImport *import, const char *name, const char *tag, const char *local, bool force_local);
+int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify);
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
new file mode 100644
index 0000000000..27a9af804d
--- /dev/null
+++ b/src/import/pull-tar.c
@@ -0,0 +1,417 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/prctl.h>
+#include <curl/curl.h>
+
+#include "sd-daemon.h"
+#include "utf8.h"
+#include "strv.h"
+#include "copy.h"
+#include "btrfs-util.h"
+#include "util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "rm-rf.h"
+#include "path-util.h"
+#include "import-util.h"
+#include "import-common.h"
+#include "curl-util.h"
+#include "pull-job.h"
+#include "pull-common.h"
+#include "pull-tar.h"
+#include "process-util.h"
+
+typedef enum TarProgress {
+ TAR_DOWNLOADING,
+ TAR_VERIFYING,
+ TAR_FINALIZING,
+ TAR_COPYING,
+} TarProgress;
+
+struct TarPull {
+ sd_event *event;
+ CurlGlue *glue;
+
+ char *image_root;
+
+ PullJob *tar_job;
+ PullJob *checksum_job;
+ PullJob *signature_job;
+
+ TarPullFinished on_finished;
+ void *userdata;
+
+ char *local;
+ bool force_local;
+ bool grow_machine_directory;
+
+ pid_t tar_pid;
+
+ char *temp_path;
+ char *final_path;
+
+ ImportVerify verify;
+};
+
+TarPull* tar_pull_unref(TarPull *i) {
+ if (!i)
+ return NULL;
+
+ if (i->tar_pid > 1) {
+ (void) kill_and_sigcont(i->tar_pid, SIGKILL);
+ (void) wait_for_terminate(i->tar_pid, NULL);
+ }
+
+ pull_job_unref(i->tar_job);
+ pull_job_unref(i->checksum_job);
+ pull_job_unref(i->signature_job);
+
+ curl_glue_unref(i->glue);
+ sd_event_unref(i->event);
+
+ if (i->temp_path) {
+ (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ free(i->temp_path);
+ }
+
+ free(i->final_path);
+ free(i->image_root);
+ free(i->local);
+ free(i);
+
+ return NULL;
+}
+
+int tar_pull_new(
+ TarPull **ret,
+ sd_event *event,
+ const char *image_root,
+ TarPullFinished on_finished,
+ void *userdata) {
+
+ _cleanup_(tar_pull_unrefp) TarPull *i = NULL;
+ int r;
+
+ assert(ret);
+ assert(event);
+
+ i = new0(TarPull, 1);
+ if (!i)
+ return -ENOMEM;
+
+ i->on_finished = on_finished;
+ i->userdata = userdata;
+
+ i->image_root = strdup(image_root ?: "/var/lib/machines");
+ if (!i->image_root)
+ return -ENOMEM;
+
+ i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines");
+
+ if (event)
+ i->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&i->event);
+ if (r < 0)
+ return r;
+ }
+
+ r = curl_glue_new(&i->glue, i->event);
+ if (r < 0)
+ return r;
+
+ i->glue->on_finished = pull_job_curl_on_finished;
+ i->glue->userdata = i;
+
+ *ret = i;
+ i = NULL;
+
+ return 0;
+}
+
+static void tar_pull_report_progress(TarPull *i, TarProgress p) {
+ unsigned percent;
+
+ assert(i);
+
+ switch (p) {
+
+ case TAR_DOWNLOADING: {
+ unsigned remain = 85;
+
+ percent = 0;
+
+ if (i->checksum_job) {
+ percent += i->checksum_job->progress_percent * 5 / 100;
+ remain -= 5;
+ }
+
+ if (i->signature_job) {
+ percent += i->signature_job->progress_percent * 5 / 100;
+ remain -= 5;
+ }
+
+ if (i->tar_job)
+ percent += i->tar_job->progress_percent * remain / 100;
+ break;
+ }
+
+ case TAR_VERIFYING:
+ percent = 85;
+ break;
+
+ case TAR_FINALIZING:
+ percent = 90;
+ break;
+
+ case TAR_COPYING:
+ percent = 95;
+ break;
+
+ default:
+ assert_not_reached("Unknown progress state");
+ }
+
+ sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent);
+ log_debug("Combined progress %u%%", percent);
+}
+
+static int tar_pull_make_local_copy(TarPull *i) {
+ int r;
+
+ assert(i);
+ assert(i->tar_job);
+
+ if (!i->local)
+ return 0;
+
+ if (!i->final_path) {
+ r = pull_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
+ if (r < 0)
+ return log_oom();
+ }
+
+ r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static bool tar_pull_is_done(TarPull *i) {
+ assert(i);
+ assert(i->tar_job);
+
+ if (i->tar_job->state != PULL_JOB_DONE)
+ return false;
+ if (i->checksum_job && i->checksum_job->state != PULL_JOB_DONE)
+ return false;
+ if (i->signature_job && i->signature_job->state != PULL_JOB_DONE)
+ return false;
+
+ return true;
+}
+
+static void tar_pull_job_on_finished(PullJob *j) {
+ TarPull *i;
+ int r;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+ if (j->error != 0) {
+ if (j == i->checksum_job)
+ log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
+ else if (j == i->signature_job)
+ log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
+ else
+ log_error_errno(j->error, "Failed to retrieve image file. (Wrong URL?)");
+
+ r = j->error;
+ goto finish;
+ }
+
+ /* This is invoked if either the download completed
+ * successfully, or the download was skipped because we
+ * already have the etag. */
+
+ if (!tar_pull_is_done(i))
+ return;
+
+ j->disk_fd = safe_close(i->tar_job->disk_fd);
+
+ if (i->tar_pid > 0) {
+ r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
+ i->tar_pid = 0;
+ if (r < 0)
+ goto finish;
+ }
+
+ if (!i->tar_job->etag_exists) {
+ /* This is a new download, verify it, and move it into place */
+
+ tar_pull_report_progress(i, TAR_VERIFYING);
+
+ r = pull_verify(i->tar_job, i->checksum_job, i->signature_job);
+ if (r < 0)
+ goto finish;
+
+ tar_pull_report_progress(i, TAR_FINALIZING);
+
+ r = import_make_read_only(i->temp_path);
+ if (r < 0)
+ goto finish;
+
+ r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path);
+ if (r < 0) {
+ log_error_errno(r, "Failed to rename to final image name: %m");
+ goto finish;
+ }
+
+ free(i->temp_path);
+ i->temp_path = NULL;
+ }
+
+ tar_pull_report_progress(i, TAR_COPYING);
+
+ r = tar_pull_make_local_copy(i);
+ if (r < 0)
+ goto finish;
+
+ r = 0;
+
+finish:
+ if (i->on_finished)
+ i->on_finished(i, r, i->userdata);
+ else
+ sd_event_exit(i->event, r);
+}
+
+static int tar_pull_job_on_open_disk(PullJob *j) {
+ TarPull *i;
+ int r;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+ assert(i->tar_job == j);
+ assert(!i->final_path);
+ assert(!i->temp_path);
+ assert(i->tar_pid <= 0);
+
+ r = pull_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
+ if (r < 0)
+ return log_oom();
+
+ r = tempfn_random(i->final_path, &i->temp_path);
+ if (r < 0)
+ return log_oom();
+
+ mkdir_parents_label(i->temp_path, 0700);
+
+ r = btrfs_subvol_make(i->temp_path);
+ if (r == -ENOTTY) {
+ if (mkdir(i->temp_path, 0755) < 0)
+ return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
+ } else if (r < 0)
+ return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
+
+ j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
+ if (j->disk_fd < 0)
+ return j->disk_fd;
+
+ return 0;
+}
+
+static void tar_pull_job_on_progress(PullJob *j) {
+ TarPull *i;
+
+ assert(j);
+ assert(j->userdata);
+
+ i = j->userdata;
+
+ tar_pull_report_progress(i, TAR_DOWNLOADING);
+}
+
+int tar_pull_start(TarPull *i, const char *url, const char *local, bool force_local, ImportVerify verify) {
+ int r;
+
+ assert(i);
+
+ if (!http_url_is_valid(url))
+ return -EINVAL;
+
+ if (local && !machine_name_is_valid(local))
+ return -EINVAL;
+
+ if (i->tar_job)
+ return -EBUSY;
+
+ r = free_and_strdup(&i->local, local);
+ if (r < 0)
+ return r;
+ i->force_local = force_local;
+ i->verify = verify;
+
+ r = pull_job_new(&i->tar_job, url, i->glue, i);
+ if (r < 0)
+ return r;
+
+ i->tar_job->on_finished = tar_pull_job_on_finished;
+ i->tar_job->on_open_disk = tar_pull_job_on_open_disk;
+ i->tar_job->on_progress = tar_pull_job_on_progress;
+ i->tar_job->calc_checksum = verify != IMPORT_VERIFY_NO;
+ i->tar_job->grow_machine_directory = i->grow_machine_directory;
+
+ r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
+ if (r < 0)
+ return r;
+
+ r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_pull_job_on_finished, i);
+ if (r < 0)
+ return r;
+
+ r = pull_job_begin(i->tar_job);
+ if (r < 0)
+ return r;
+
+ if (i->checksum_job) {
+ i->checksum_job->on_progress = tar_pull_job_on_progress;
+
+ r = pull_job_begin(i->checksum_job);
+ if (r < 0)
+ return r;
+ }
+
+ if (i->signature_job) {
+ i->signature_job->on_progress = tar_pull_job_on_progress;
+
+ r = pull_job_begin(i->signature_job);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/import/pull-tar.h b/src/import/pull-tar.h
new file mode 100644
index 0000000000..0ed507748c
--- /dev/null
+++ b/src/import/pull-tar.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-event.h"
+#include "macro.h"
+#include "import-util.h"
+
+typedef struct TarPull TarPull;
+
+typedef void (*TarPullFinished)(TarPull *pull, int error, void *userdata);
+
+int tar_pull_new(TarPull **pull, sd_event *event, const char *image_root, TarPullFinished on_finished, void *userdata);
+TarPull* tar_pull_unref(TarPull *pull);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(TarPull*, tar_pull_unref);
+
+int tar_pull_start(TarPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify);
diff --git a/src/import/pull.c b/src/import/pull.c
index ee3ff68036..eec4583868 100644
--- a/src/import/pull.c
+++ b/src/import/pull.c
@@ -25,11 +25,12 @@
#include "event-util.h"
#include "verbs.h"
#include "build.h"
+#include "signal-util.h"
#include "machine-image.h"
-#include "import-tar.h"
-#include "import-raw.h"
-#include "import-dkr.h"
#include "import-util.h"
+#include "pull-tar.h"
+#include "pull-raw.h"
+#include "pull-dkr.h"
static bool arg_force = false;
static const char *arg_image_root = "/var/lib/machines";
@@ -42,9 +43,9 @@ static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_si
return 0;
}
-static void on_tar_finished(TarImport *import, int error, void *userdata) {
+static void on_tar_finished(TarPull *pull, int error, void *userdata) {
sd_event *event = userdata;
- assert(import);
+ assert(pull);
if (error == 0)
log_info("Operation completed successfully.");
@@ -53,7 +54,7 @@ static void on_tar_finished(TarImport *import, int error, void *userdata) {
}
static int pull_tar(int argc, char *argv[], void *userdata) {
- _cleanup_(tar_import_unrefp) TarImport *import = NULL;
+ _cleanup_(tar_pull_unrefp) TarPull *pull = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
const char *url, *local;
_cleanup_free_ char *l = NULL, *ll = NULL;
@@ -112,11 +113,11 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
- r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
+ r = tar_pull_new(&pull, event, arg_image_root, on_tar_finished, event);
if (r < 0)
- return log_error_errno(r, "Failed to allocate importer: %m");
+ return log_error_errno(r, "Failed to allocate puller: %m");
- r = tar_import_pull(import, url, local, arg_force, arg_verify);
+ r = tar_pull_start(pull, url, local, arg_force, arg_verify);
if (r < 0)
return log_error_errno(r, "Failed to pull image: %m");
@@ -128,9 +129,9 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
return -r;
}
-static void on_raw_finished(RawImport *import, int error, void *userdata) {
+static void on_raw_finished(RawPull *pull, int error, void *userdata) {
sd_event *event = userdata;
- assert(import);
+ assert(pull);
if (error == 0)
log_info("Operation completed successfully.");
@@ -139,7 +140,7 @@ static void on_raw_finished(RawImport *import, int error, void *userdata) {
}
static int pull_raw(int argc, char *argv[], void *userdata) {
- _cleanup_(raw_import_unrefp) RawImport *import = NULL;
+ _cleanup_(raw_pull_unrefp) RawPull *pull = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
const char *url, *local;
_cleanup_free_ char *l = NULL, *ll = NULL;
@@ -198,11 +199,11 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
- r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
+ r = raw_pull_new(&pull, event, arg_image_root, on_raw_finished, event);
if (r < 0)
- return log_error_errno(r, "Failed to allocate importer: %m");
+ return log_error_errno(r, "Failed to allocate puller: %m");
- r = raw_import_pull(import, url, local, arg_force, arg_verify);
+ r = raw_pull_start(pull, url, local, arg_force, arg_verify);
if (r < 0)
return log_error_errno(r, "Failed to pull image: %m");
@@ -214,9 +215,9 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
return -r;
}
-static void on_dkr_finished(DkrImport *import, int error, void *userdata) {
+static void on_dkr_finished(DkrPull *pull, int error, void *userdata) {
sd_event *event = userdata;
- assert(import);
+ assert(pull);
if (error == 0)
log_info("Operation completed successfully.");
@@ -225,9 +226,9 @@ static void on_dkr_finished(DkrImport *import, int error, void *userdata) {
}
static int pull_dkr(int argc, char *argv[], void *userdata) {
- _cleanup_(dkr_import_unrefp) DkrImport *import = NULL;
+ _cleanup_(dkr_pull_unrefp) DkrPull *pull = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
- const char *name, *tag, *local;
+ const char *name, *reference, *local, *digest;
int r;
if (!arg_dkr_index_url) {
@@ -236,17 +237,23 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
}
if (arg_verify != IMPORT_VERIFY_NO) {
- log_error("Imports from dkr do not support image verification, please pass --verify=no.");
+ log_error("Pulls from dkr do not support image verification, please pass --verify=no.");
return -EINVAL;
}
- tag = strchr(argv[1], ':');
- if (tag) {
- name = strndupa(argv[1], tag - argv[1]);
- tag++;
+ digest = strchr(argv[1], '@');
+ if (digest) {
+ reference = digest + 1;
+ name = strndupa(argv[1], digest - argv[1]);
+ }
+
+ reference = strchr(argv[1], ':');
+ if (reference) {
+ name = strndupa(argv[1], reference - argv[1]);
+ reference++;
} else {
name = argv[1];
- tag = "latest";
+ reference = "latest";
}
if (!dkr_name_is_valid(name)) {
@@ -254,8 +261,8 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- if (!dkr_tag_is_valid(tag)) {
- log_error("Tag name '%s' is not valid.", tag);
+ if (!dkr_ref_is_valid(reference)) {
+ log_error("Tag name '%s' is not valid.", reference);
return -EINVAL;
}
@@ -288,9 +295,9 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
}
}
- log_info("Pulling '%s' with tag '%s', saving as '%s'.", name, tag, local);
+ log_info("Pulling '%s' with reference '%s', saving as '%s'.", name, reference, local);
} else
- log_info("Pulling '%s' with tag '%s'.", name, tag);
+ log_info("Pulling '%s' with reference '%s'.", name, reference);
r = sd_event_default(&event);
if (r < 0)
@@ -300,11 +307,11 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
- r = dkr_import_new(&import, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
+ r = dkr_pull_new(&pull, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event);
if (r < 0)
- return log_error_errno(r, "Failed to allocate importer: %m");
+ return log_error_errno(r, "Failed to allocate puller: %m");
- r = dkr_import_pull(import, name, tag, local, arg_force);
+ r = dkr_pull_start(pull, name, reference, local, arg_force, DKR_PULL_V2);
if (r < 0)
return log_error_errno(r, "Failed to pull image: %m");
@@ -319,13 +326,13 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
- "Import container or virtual machine image.\n\n"
+ "Download container or virtual machine images.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --force Force creation of image\n"
" --verify= Verify downloaded image, one of: 'no',\n"
" 'checksum', 'signature'.\n"
- " --image-root= Image root directory\n"
+ " --image-root=PATH Image root directory\n"
" --dkr-index-url=URL Specify index URL to use for downloads\n\n"
"Commands:\n"
" tar URL [NAME] Download a TAR image\n"
@@ -409,7 +416,7 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
-static int import_main(int argc, char *argv[]) {
+static int pull_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, help },
@@ -433,7 +440,9 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = import_main(argc, argv);
+ ignore_signals(SIGPIPE, -1);
+
+ r = pull_main(argc, argv);
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c
index 9b0c23bb14..fd3cf1b0e3 100644
--- a/src/import/qcow2-util.c
+++ b/src/import/qcow2-util.c
@@ -177,7 +177,7 @@ static int normalize_offset(
uint64_t sz, csize_shift, csize_mask;
if (!compressed)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
csize_shift = 64 - 2 - (HEADER_CLUSTER_BITS(header) - 8);
csize_mask = (1ULL << (HEADER_CLUSTER_BITS(header) - 8)) - 1;
@@ -216,10 +216,10 @@ static int verify_header(const Header *header) {
if (HEADER_VERSION(header) != 2 &&
HEADER_VERSION(header) != 3)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (HEADER_CRYPT_METHOD(header) != 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (HEADER_CLUSTER_BITS(header) < 9) /* 512K */
return -EBADMSG;
@@ -236,7 +236,7 @@ static int verify_header(const Header *header) {
if (HEADER_VERSION(header) == 3) {
if (header->incompatible_features != 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (HEADER_HEADER_LENGTH(header) < sizeof(Header))
return -EBADMSG;
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index 7a6a383b32..19d6468fcc 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -19,18 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <time.h>
-#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
-#include <poll.h>
#include <sys/epoll.h>
-#include <sys/un.h>
-#include <fcntl.h>
#include <ctype.h>
#include "sd-daemon.h"
@@ -44,6 +36,7 @@
#include "bus-util.h"
#include "bus-error.h"
#include "def.h"
+#include "formats-util.h"
#define SERVER_FD_MAX 16
#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))
@@ -78,15 +71,15 @@ static const char *translate_runlevel(int runlevel, bool *isolate) {
const char *special;
bool isolate;
} table[] = {
- { '0', SPECIAL_POWEROFF_TARGET, false },
- { '1', SPECIAL_RESCUE_TARGET, true },
- { 's', SPECIAL_RESCUE_TARGET, true },
- { 'S', SPECIAL_RESCUE_TARGET, true },
- { '2', SPECIAL_RUNLEVEL2_TARGET, true },
- { '3', SPECIAL_RUNLEVEL3_TARGET, true },
- { '4', SPECIAL_RUNLEVEL4_TARGET, true },
- { '5', SPECIAL_RUNLEVEL5_TARGET, true },
- { '6', SPECIAL_REBOOT_TARGET, false },
+ { '0', SPECIAL_POWEROFF_TARGET, false },
+ { '1', SPECIAL_RESCUE_TARGET, true },
+ { 's', SPECIAL_RESCUE_TARGET, true },
+ { 'S', SPECIAL_RESCUE_TARGET, true },
+ { '2', SPECIAL_MULTI_USER_TARGET, true },
+ { '3', SPECIAL_MULTI_USER_TARGET, true },
+ { '4', SPECIAL_MULTI_USER_TARGET, true },
+ { '5', SPECIAL_GRAPHICAL_TARGET, true },
+ { '6', SPECIAL_REBOOT_TARGET, false },
};
unsigned i;
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 576f7cae7d..d9450ae8cd 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -42,6 +42,7 @@
#include "build.h"
#include "fileio.h"
#include "sigbus.h"
+#include "hostname-util.h"
static char *arg_key_pem = NULL;
static char *arg_cert_pem = NULL;
@@ -121,6 +122,26 @@ static int open_journal(RequestMeta *m) {
return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM);
}
+static int request_meta_ensure_tmp(RequestMeta *m) {
+ if (m->tmp)
+ rewind(m->tmp);
+ else {
+ int fd;
+
+ fd = open_tmpfile("/tmp", O_RDWR|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ m->tmp = fdopen(fd, "rw");
+ if (!m->tmp) {
+ safe_close(fd);
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
static ssize_t request_reader_entries(
void *cls,
uint64_t pos,
@@ -194,14 +215,10 @@ static ssize_t request_reader_entries(
m->n_skip = 0;
- if (m->tmp)
- rewind(m->tmp);
- else {
- m->tmp = tmpfile();
- if (!m->tmp) {
- log_error_errno(errno, "Failed to create temporary file: %m");
- return MHD_CONTENT_READER_END_WITH_ERROR;
- }
+ r = request_meta_ensure_tmp(m);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create temporary file: %m");
+ return MHD_CONTENT_READER_END_WITH_ERROR;
}
r = output_journal(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH, NULL);
@@ -555,14 +572,10 @@ static ssize_t request_reader_fields(
if (m->n_fields_set)
m->n_fields -= 1;
- if (m->tmp)
- rewind(m->tmp);
- else {
- m->tmp = tmpfile();
- if (!m->tmp) {
- log_error_errno(errno, "Failed to create temporary file: %m");
- return MHD_CONTENT_READER_END_WITH_ERROR;
- }
+ r = request_meta_ensure_tmp(m);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create temporary file: %m");
+ return MHD_CONTENT_READER_END_WITH_ERROR;
}
r = output_field(m->tmp, m->mode, d, l);
@@ -736,7 +749,7 @@ static int request_handler_machine(
RequestMeta *m = connection_cls;
int r;
_cleanup_free_ char* hostname = NULL, *os_name = NULL;
- uint64_t cutoff_from = 0, cutoff_to = 0, usage;
+ uint64_t cutoff_from = 0, cutoff_to = 0, usage = 0;
char *json;
sd_id128_t mid, bid;
_cleanup_free_ char *v = NULL;
@@ -769,7 +782,7 @@ static int request_handler_machine(
return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %s\n", strerror(-r));
if (parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL) == -ENOENT)
- parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL);
+ (void) parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL);
get_virtualization(&v);
@@ -982,10 +995,9 @@ int main(int argc, char *argv[]) {
sigbus_install();
-#ifdef HAVE_GNUTLS
- gnutls_global_set_log_function(log_func_gnutls);
- log_reset_gnutls_level();
-#endif
+ r = setup_gnutls_logger(NULL);
+ if (r < 0)
+ return EXIT_FAILURE;
n = sd_listen_fds(1);
if (n < 0) {
diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c
index d9dea8deb0..5ff05d3ad6 100644
--- a/src/journal-remote/journal-remote-parse.c
+++ b/src/journal-remote/journal-remote-parse.c
@@ -41,6 +41,7 @@ void source_free(RemoteSource *source) {
writer_unref(source->writer);
sd_event_source_unref(source->event);
+ sd_event_source_unref(source->buffer_event);
free(source);
}
@@ -111,21 +112,26 @@ static int get_line(RemoteSource *source, char **line, size_t *size) {
if (source->passive_fd)
/* we have to wait for some data to come to us */
- return -EWOULDBLOCK;
+ return -EAGAIN;
+ /* We know that source->filled is at most DATA_SIZE_MAX, so if
+ we reallocate it, we'll increase the size at least a bit. */
+ assert_cc(DATA_SIZE_MAX < ENTRY_SIZE_MAX);
if (source->size - source->filled < LINE_CHUNK &&
- !realloc_buffer(source,
- MIN(source->filled + LINE_CHUNK, ENTRY_SIZE_MAX)))
+ !realloc_buffer(source, MIN(source->filled + LINE_CHUNK, ENTRY_SIZE_MAX)))
return log_oom();
+ assert(source->buf);
assert(source->size - source->filled >= LINE_CHUNK ||
source->size == ENTRY_SIZE_MAX);
- n = read(source->fd, source->buf + source->filled,
+ n = read(source->fd,
+ source->buf + source->filled,
source->size - source->filled);
if (n < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK)
- log_error_errno(errno, "read(%d, ..., %zu): %m", source->fd,
+ if (errno != EAGAIN)
+ log_error_errno(errno, "read(%d, ..., %zu): %m",
+ source->fd,
source->size - source->filled);
return -errno;
} else if (n == 0)
@@ -177,7 +183,7 @@ static int fill_fixed_size(RemoteSource *source, void **data, size_t size) {
if (source->passive_fd)
/* we have to wait for some data to come to us */
- return -EWOULDBLOCK;
+ return -EAGAIN;
if (!realloc_buffer(source, source->offset + size))
return log_oom();
@@ -185,7 +191,7 @@ static int fill_fixed_size(RemoteSource *source, void **data, size_t size) {
n = read(source->fd, source->buf + source->filled,
source->size - source->filled);
if (n < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK)
+ if (errno != EAGAIN)
log_error_errno(errno, "read(%d, ..., %zu): %m", source->fd,
source->size - source->filled);
return -errno;
@@ -309,13 +315,13 @@ static int process_dunder(RemoteSource *source, char *line, size_t n) {
return 0;
}
-int process_data(RemoteSource *source) {
+static int process_data(RemoteSource *source) {
int r;
switch(source->state) {
case STATE_LINE: {
char *line, *sep;
- size_t n;
+ size_t n = 0;
assert(source->data_size == 0);
@@ -344,22 +350,25 @@ int process_data(RemoteSource *source) {
LLLLLLLL0011223344...\n
*/
sep = memchr(line, '=', n);
- if (sep)
+ if (sep) {
/* chomp newline */
n--;
- else
+
+ r = iovw_put(&source->iovw, line, n);
+ if (r < 0)
+ return r;
+ } else {
/* replace \n with = */
line[n-1] = '=';
- log_trace("Received: %.*s", (int) n, line);
- r = iovw_put(&source->iovw, line, n);
- if (r < 0) {
- log_error("Failed to put line in iovect");
- return r;
+ source->field_len = n;
+ source->state = STATE_DATA_START;
+
+ /* we cannot put the field in iovec until we have all data */
}
- if (!sep)
- source->state = STATE_DATA_START;
+ log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary");
+
return 0; /* continue */
}
@@ -382,6 +391,7 @@ int process_data(RemoteSource *source) {
case STATE_DATA: {
void *data;
+ char *field;
assert(source->data_size > 0);
@@ -396,11 +406,12 @@ int process_data(RemoteSource *source) {
assert(data);
- r = iovw_put(&source->iovw, data, source->data_size);
- if (r < 0) {
- log_error("failed to put binary buffer in iovect");
+ field = (char*) data - sizeof(uint64_t) - source->field_len;
+ memmove(field + sizeof(uint64_t), field, source->field_len);
+
+ r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size);
+ if (r < 0)
return r;
- }
source->state = STATE_DATA_FINISH;
@@ -438,7 +449,7 @@ int process_source(RemoteSource *source, bool compress, bool seal) {
return r;
/* We have a full event */
- log_trace("Received a full event from source@%p fd:%d (%s)",
+ log_trace("Received full event from source@%p fd:%d (%s)",
source, source->fd, source->name);
if (!source->iovw.count) {
diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h
index 8499f4eb82..14bfadc132 100644
--- a/src/journal-remote/journal-remote-parse.h
+++ b/src/journal-remote/journal-remote-parse.h
@@ -42,7 +42,9 @@ typedef struct RemoteSource {
size_t offset; /* offset to the beginning of live data in the buffer */
size_t scanned; /* number of bytes since the beginning of data without a newline */
size_t filled; /* total number of bytes in the buffer */
- size_t data_size; /* size of the binary data chunk being processed */
+
+ size_t field_len; /* used for binary fields: the field name length */
+ size_t data_size; /* and the size of the binary data chunk being processed */
struct iovec_wrapper iovw;
@@ -52,6 +54,7 @@ typedef struct RemoteSource {
Writer *writer;
sd_event_source *event;
+ sd_event_source *buffer_event;
} RemoteSource;
RemoteSource* source_new(int fd, bool passive_fd, char *name, Writer *writer);
@@ -63,6 +66,5 @@ static inline size_t source_non_empty(RemoteSource *source) {
}
void source_free(RemoteSource *source);
-int process_data(RemoteSource *source);
int push_data(RemoteSource *source, const char *data, size_t size);
int process_source(RemoteSource *source, bool compress, bool seal);
diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c
index df30049397..99820fa7b8 100644
--- a/src/journal-remote/journal-remote-write.c
+++ b/src/journal-remote/journal-remote-write.c
@@ -156,7 +156,7 @@ int writer_write(Writer *w,
if (r < 0)
return r;
else
- log_info("%s: Successfully rotated journal", w->journal->path);
+ log_debug("%s: Successfully rotated journal", w->journal->path);
log_debug("Retrying write.");
r = journal_file_append_entry(w->journal, ts, iovw->iovec, iovw->count,
diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h
index aa381c661e..7f47f8b014 100644
--- a/src/journal-remote/journal-remote-write.h
+++ b/src/journal-remote/journal-remote-write.h
@@ -21,7 +21,6 @@
#pragma once
-#include <stdlib.h>
#include "journal-file.h"
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 8f32a9a988..911e2a178b 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -26,22 +26,19 @@
#include <string.h>
#include <sys/prctl.h>
#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
#include <getopt.h>
#include "sd-daemon.h"
+#include "signal-util.h"
#include "journal-file.h"
#include "journald-native.h"
#include "socket-util.h"
-#include "mkdir.h"
#include "build.h"
#include "macro.h"
#include "strv.h"
#include "fileio.h"
#include "conf-parser.h"
-#include "siphash24.h"
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
@@ -147,7 +144,7 @@ static int spawn_getter(const char *getter, const char *url) {
_cleanup_strv_free_ char **words = NULL;
assert(getter);
- r = strv_split_quoted(&words, getter, false);
+ r = strv_split_quoted(&words, getter, 0);
if (r < 0)
return log_error_errno(r, "Failed to split getter option: %m");
@@ -207,7 +204,7 @@ static int open_output(Writer *w, const char* host) {
log_error_errno(r, "Failed to open output journal %s: %m",
output);
else
- log_info("Opened output file %s", w->journal->path);
+ log_debug("Opened output file %s", w->journal->path);
return r;
}
@@ -289,6 +286,8 @@ static int dispatch_raw_source_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata);
+static int dispatch_raw_source_until_block(sd_event_source *event,
+ void *userdata);
static int dispatch_blocking_source_event(sd_event_source *event,
void *userdata);
static int dispatch_raw_connection_event(sd_event_source *event,
@@ -351,7 +350,7 @@ static int remove_source(RemoteServer *s, int fd) {
static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
- RemoteSource *source;
+ RemoteSource *source = NULL;
int r;
/* This takes ownership of name, even on failure, if own_name is true. */
@@ -376,8 +375,15 @@ static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
r = sd_event_add_io(s->events, &source->event,
fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
- dispatch_raw_source_event, s);
- if (r == -EPERM) {
+ dispatch_raw_source_event, source);
+ if (r == 0) {
+ /* Add additional source for buffer processing. It will be
+ * enabled later. */
+ r = sd_event_add_defer(s->events, &source->buffer_event,
+ dispatch_raw_source_until_block, source);
+ if (r == 0)
+ sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF);
+ } else if (r == -EPERM) {
log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
r = sd_event_add_defer(s->events, &source->event,
dispatch_blocking_source_event, source);
@@ -511,7 +517,7 @@ static int process_http_upload(
while (true) {
r = process_source(source, arg_compress, arg_seal);
- if (r == -EAGAIN || r == -EWOULDBLOCK)
+ if (r == -EAGAIN)
break;
else if (r < 0) {
log_warning("Failed to process data for connection %p", connection);
@@ -693,7 +699,7 @@ static int setup_microhttpd_server(RemoteServer *s,
info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
if (!info) {
log_error("µhttp returned NULL daemon info");
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
goto error;
}
@@ -747,7 +753,7 @@ static int setup_microhttpd_socket(RemoteServer *s,
const char *trust) {
int fd;
- fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
+ fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM | SOCK_CLOEXEC);
if (fd < 0)
return fd;
@@ -844,7 +850,7 @@ static int remoteserver_init(RemoteServer *s,
if (n < 0)
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
else
- log_info("Received %d descriptors", n);
+ log_debug("Received %d descriptors", n);
if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
log_error("Received fewer sockets than expected");
@@ -853,7 +859,7 @@ static int remoteserver_init(RemoteServer *s,
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
- log_info("Received a listening socket (fd:%d)", fd);
+ log_debug("Received a listening socket (fd:%d)", fd);
if (fd == http_socket)
r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
@@ -868,7 +874,7 @@ static int remoteserver_init(RemoteServer *s,
if (r < 0)
return log_error_errno(r, "Failed to retrieve remote name: %m");
- log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
+ log_debug("Received a connection socket (fd:%d) from %s", fd, hostname);
r = add_source(s, fd, hostname, true);
} else {
@@ -908,7 +914,7 @@ static int remoteserver_init(RemoteServer *s,
}
if (arg_listen_raw) {
- log_info("Listening on a socket...");
+ log_debug("Listening on a socket...");
r = setup_raw_socket(s, arg_listen_raw);
if (r < 0)
return r;
@@ -930,12 +936,12 @@ static int remoteserver_init(RemoteServer *s,
const char *output_name;
if (streq(*file, "-")) {
- log_info("Using standard input as source.");
+ log_debug("Using standard input as source.");
fd = STDIN_FILENO;
output_name = "stdin";
} else {
- log_info("Reading file %s...", *file);
+ log_debug("Reading file %s...", *file);
fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
if (fd < 0)
@@ -997,15 +1003,18 @@ static void server_destroy(RemoteServer *s) {
**********************************************************************
**********************************************************************/
-static int dispatch_raw_source_event(sd_event_source *event,
- int fd,
- uint32_t revents,
- void *userdata) {
+static int handle_raw_source(sd_event_source *event,
+ int fd,
+ uint32_t revents,
+ RemoteServer *s) {
- RemoteServer *s = userdata;
RemoteSource *source;
int r;
+ /* Returns 1 if there might be more data pending,
+ * 0 if data is currently exhausted, negative on error.
+ */
+
assert(fd >= 0 && fd < (ssize_t) s->sources_size);
source = s->sources[fd];
assert(source->fd == fd);
@@ -1014,33 +1023,70 @@ static int dispatch_raw_source_event(sd_event_source *event,
if (source->state == STATE_EOF) {
size_t remaining;
- log_info("EOF reached with source fd:%d (%s)",
- source->fd, source->name);
+ log_debug("EOF reached with source fd:%d (%s)",
+ source->fd, source->name);
remaining = source_non_empty(source);
if (remaining > 0)
- log_warning("Premature EOF. %zu bytes lost.", remaining);
+ log_notice("Premature EOF. %zu bytes lost.", remaining);
remove_source(s, source->fd);
- log_info("%zu active sources remaining", s->active);
+ log_debug("%zu active sources remaining", s->active);
return 0;
} else if (r == -E2BIG) {
- log_error("Entry too big, skipped");
+ log_notice_errno(E2BIG, "Entry too big, skipped");
return 1;
} else if (r == -EAGAIN) {
return 0;
} else if (r < 0) {
- log_info_errno(r, "Closing connection: %m");
+ log_debug_errno(r, "Closing connection: %m");
remove_source(server, fd);
return 0;
} else
return 1;
}
+static int dispatch_raw_source_until_block(sd_event_source *event,
+ void *userdata) {
+ RemoteSource *source = userdata;
+ int r;
+
+ /* Make sure event stays around even if source is destroyed */
+ sd_event_source_ref(event);
+
+ r = handle_raw_source(event, source->fd, EPOLLIN, server);
+ if (r != 1)
+ /* No more data for now */
+ sd_event_source_set_enabled(event, SD_EVENT_OFF);
+
+ sd_event_source_unref(event);
+
+ return r;
+}
+
+static int dispatch_raw_source_event(sd_event_source *event,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+ RemoteSource *source = userdata;
+ int r;
+
+ assert(source->event);
+ assert(source->buffer_event);
+
+ r = handle_raw_source(event, fd, EPOLLIN, server);
+ if (r == 1)
+ /* Might have more data. We need to rerun the handler
+ * until we are sure the buffer is exhausted. */
+ sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
+
+ return r;
+}
+
static int dispatch_blocking_source_event(sd_event_source *event,
void *userdata) {
RemoteSource *source = userdata;
- return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
+ return handle_raw_source(event, source->fd, EPOLLIN, server);
}
static int accept_connection(const char* type, int fd,
@@ -1071,10 +1117,10 @@ static int accept_connection(const char* type, int fd,
return r;
}
- log_info("Accepted %s %s connection from %s",
- type,
- socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
- a);
+ log_debug("Accepted %s %s connection from %s",
+ type,
+ socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
+ a);
*hostname = b;
@@ -1099,7 +1145,7 @@ static int dispatch_raw_connection_event(sd_event_source *event,
.size = sizeof(union sockaddr_union),
.type = SOCK_STREAM,
};
- char *hostname;
+ char *hostname = NULL;
fd2 = accept_connection("raw", fd, &addr, &hostname);
if (fd2 < 0)
@@ -1458,31 +1504,6 @@ static int load_certificates(char **key, char **cert, char **trust) {
return 0;
}
-static int setup_gnutls_logger(char **categories) {
- if (!arg_listen_http && !arg_listen_https)
- return 0;
-
-#ifdef HAVE_GNUTLS
- {
- char **cat;
- int r;
-
- gnutls_global_set_log_function(log_func_gnutls);
-
- if (categories) {
- STRV_FOREACH(cat, categories) {
- r = log_enable_gnutls_category(*cat);
- if (r < 0)
- return r;
- }
- } else
- log_reset_gnutls_level();
- }
-#endif
-
- return 0;
-}
-
int main(int argc, char **argv) {
RemoteServer s = {};
int r;
@@ -1499,9 +1520,12 @@ int main(int argc, char **argv) {
if (r <= 0)
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
- r = setup_gnutls_logger(arg_gnutls_log);
- if (r < 0)
- return EXIT_FAILURE;
+
+ if (arg_listen_http || arg_listen_https) {
+ r = setup_gnutls_logger(arg_gnutls_log);
+ if (r < 0)
+ return EXIT_FAILURE;
+ }
if (arg_listen_https || https_socket >= 0)
if (load_certificates(&key, &cert, &trust) < 0)
diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h
index 1cf22f6383..6c2ccb9735 100644
--- a/src/journal-remote/journal-remote.h
+++ b/src/journal-remote/journal-remote.h
@@ -21,7 +21,6 @@
#pragma once
-#include <inttypes.h>
#include "sd-event.h"
#include "hashmap.h"
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 75bb434c08..ddb1ef0396 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -33,6 +33,8 @@
#include "mkdir.h"
#include "conf-parser.h"
#include "sigbus.h"
+#include "formats-util.h"
+#include "signal-util.h"
#include "journal-upload.h"
#define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c
index 34d93379da..8a11fba044 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/journal-remote/microhttpd-util.c
@@ -121,7 +121,7 @@ static struct {
{ {"9", "enc", "int"}, LOG_DEBUG },
};
-void log_func_gnutls(int level, const char *message) {
+static void log_func_gnutls(int level, const char *message) {
assert_se(message);
if (0 <= level && level < (int) ELEMENTSOF(gnutls_log_map)) {
@@ -133,7 +133,18 @@ void log_func_gnutls(int level, const char *message) {
}
}
-int log_enable_gnutls_category(const char *cat) {
+static void log_reset_gnutls_level(void) {
+ int i;
+
+ for (i = ELEMENTSOF(gnutls_log_map) - 1; i >= 0; i--)
+ if (gnutls_log_map[i].enabled) {
+ log_debug("Setting gnutls log level to %d", i);
+ gnutls_global_set_log_level(i);
+ break;
+ }
+}
+
+static int log_enable_gnutls_category(const char *cat) {
unsigned i;
if (streq(cat, "all")) {
@@ -152,15 +163,22 @@ int log_enable_gnutls_category(const char *cat) {
return -EINVAL;
}
-void log_reset_gnutls_level(void) {
- int i;
+int setup_gnutls_logger(char **categories) {
+ char **cat;
+ int r;
- for (i = ELEMENTSOF(gnutls_log_map) - 1; i >= 0; i--)
- if (gnutls_log_map[i].enabled) {
- log_debug("Setting gnutls log level to %d", i);
- gnutls_global_set_log_level(i);
- break;
+ gnutls_global_set_log_function(log_func_gnutls);
+
+ if (categories) {
+ STRV_FOREACH(cat, categories) {
+ r = log_enable_gnutls_category(*cat);
+ if (r < 0)
+ return r;
}
+ } else
+ log_reset_gnutls_level();
+
+ return 0;
}
static int verify_cert_authorized(gnutls_session_t session) {
@@ -178,7 +196,8 @@ static int verify_cert_authorized(gnutls_session_t session) {
if (r < 0)
return log_error_errno(r, "gnutls_certificate_verification_status_print failed: %m");
- log_info("Certificate status: %s", out.data);
+ log_debug("Certificate status: %s", out.data);
+ gnutls_free(out.data);
return status == 0 ? 0 : -EPERM;
}
@@ -238,10 +257,14 @@ static int get_auth_dn(gnutls_x509_crt_t client_cert, char **buf) {
return 0;
}
+static inline void gnutls_x509_crt_deinitp(gnutls_x509_crt_t *p) {
+ gnutls_x509_crt_deinit(*p);
+}
+
int check_permissions(struct MHD_Connection *connection, int *code, char **hostname) {
const union MHD_ConnectionInfo *ci;
gnutls_session_t session;
- gnutls_x509_crt_t client_cert;
+ _cleanup_(gnutls_x509_crt_deinitp) gnutls_x509_crt_t client_cert = NULL;
_cleanup_free_ char *buf = NULL;
int r;
@@ -275,7 +298,7 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn
return -EPERM;
}
- log_info("Connection from %s", buf);
+ log_debug("Connection from %s", buf);
if (hostname) {
*hostname = buf;
@@ -295,4 +318,10 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn
int check_permissions(struct MHD_Connection *connection, int *code, char **hostname) {
return -EPERM;
}
+
+int setup_gnutls_logger(char **categories) {
+ if (categories)
+ log_notice("Ignoring specified gnutls logging categories — gnutls not available.");
+ return 0;
+}
#endif
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index c43d7f75a3..b2feb9180a 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -43,13 +43,11 @@ int mhd_respond_oom(struct MHD_Connection *connection);
int check_permissions(struct MHD_Connection *connection, int *code, char **hostname);
-#ifdef HAVE_GNUTLS
-void log_func_gnutls(int level, const char *message);
-int log_enable_gnutls_category(const char *cat);
-void log_reset_gnutls_level(void);
-
-/* This is additionally filtered by our internal log level, so it
- * should be set fairly high to capture all potentially interesting
- * events without overwhelming detail.
+/* Set gnutls internal logging function to a callback which uses our
+ * own logging framework.
+ *
+ * gnutls categories are additionally filtered by our internal log
+ * level, so it should be set fairly high to capture all potentially
+ * interesting events without overwhelming detail.
*/
-#endif
+int setup_gnutls_logger(char **categories);
diff --git a/src/journal/.gitignore b/src/journal/.gitignore
index d6a79460cd..04d5852547 100644
--- a/src/journal/.gitignore
+++ b/src/journal/.gitignore
@@ -1,2 +1,4 @@
/journald-gperf.c
/libsystemd-journal.pc
+/audit_type-list.txt
+/audit_type-*-name.*
diff --git a/src/shared/time-dst.h b/src/journal/audit-type.c
index 536b6bbdfb..4888c7d05d 100644
--- a/src/shared/time-dst.h
+++ b/src/journal/audit-type.c
@@ -1,11 +1,9 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-#pragma once
-
/***
This file is part of systemd.
- Copyright 2012 Kay Sievers
+ Copyright 2015 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -21,6 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int time_get_dst(time_t date, const char *tzfile,
- time_t *switch_cur, char **zone_cur, bool *dst_cur,
- time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next);
+#include <stdio.h>
+#include <linux/audit.h>
+#ifdef HAVE_AUDIT
+# include <libaudit.h>
+#endif
+
+#include "audit-type.h"
+#include "macro.h"
+#include "missing.h"
+
+#include "audit_type-to-name.h"
diff --git a/src/journal/audit-type.h b/src/journal/audit-type.h
new file mode 100644
index 0000000000..fa5284e027
--- /dev/null
+++ b/src/journal/audit-type.h
@@ -0,0 +1,39 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+
+const char *audit_type_to_string(int type);
+int audit_type_from_string(const char *s);
+
+/* This is inspired by DNS TYPEnnn formatting */
+#define audit_type_name_alloca(type) \
+ ({ \
+ const char *_s_; \
+ _s_ = audit_type_to_string(type); \
+ if (!_s_) { \
+ _s_ = alloca(strlen("AUDIT") + DECIMAL_STR_MAX(int)); \
+ sprintf((char*) _s_, "AUDIT%04i", type); \
+ } \
+ _s_; \
+ })
diff --git a/src/journal/cat.c b/src/journal/cat.c
index 79706b692d..2e236f0004 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <getopt.h>
-#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
diff --git a/src/journal/catalog.c b/src/journal/catalog.c
index f170232841..0801e13599 100644
--- a/src/journal/catalog.c
+++ b/src/journal/catalog.c
@@ -34,7 +34,6 @@
#include "hashmap.h"
#include "strv.h"
#include "strbuf.h"
-#include "strxcpyx.h"
#include "conf-files.h"
#include "mkdir.h"
#include "catalog.h"
@@ -559,7 +558,7 @@ static const char *find_id(void *p, sd_id128_t id) {
int catalog_get(const char* database, sd_id128_t id, char **_text) {
_cleanup_close_ int fd = -1;
void *p = NULL;
- struct stat st;
+ struct stat st = {};
char *text = NULL;
int r;
const char *s;
diff --git a/src/journal/compress.c b/src/journal/compress.c
index 6923753f89..383f6a6e96 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -590,14 +589,12 @@ int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
return log_oom();
for (;;) {
- ssize_t n, m;
+ ssize_t m;
int r;
- n = read(fdf, &header, sizeof(header));
- if (n < 0)
- return -errno;
- if (n != sizeof(header))
- return errno ? -errno : -EIO;
+ r = loop_read_exact(fdf, &header, sizeof(header), false);
+ if (r < 0)
+ return r;
m = le32toh(header);
if (m == 0)
@@ -619,12 +616,9 @@ int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
if (!GREEDY_REALLOC(buf, buf_size, m))
return log_oom();
- errno = 0;
- n = loop_read(fdf, buf, m, false);
- if (n < 0)
- return n;
- if (n != m)
- return errno ? -errno : -EIO;
+ r = loop_read_exact(fdf, buf, m, false);
+ if (r < 0)
+ return r;
r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
if (r <= 0)
@@ -637,9 +631,9 @@ int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
return -EFBIG;
}
- n = loop_write(fdt, out, r, false);
- if (n < 0)
- return n;
+ r = loop_write(fdt, out, r, false);
+ if (r < 0)
+ return r;
}
log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
diff --git a/src/journal/compress.h b/src/journal/compress.h
index 136dda6d39..6294f16faa 100644
--- a/src/journal/compress.h
+++ b/src/journal/compress.h
@@ -21,8 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
-#include <stdbool.h>
#include <unistd.h>
#include "journal-def.h"
diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c
index 9b73795e5b..c0347ef569 100644
--- a/src/journal/coredump-vacuum.c
+++ b/src/journal/coredump-vacuum.c
@@ -103,8 +103,7 @@ static bool vacuum_necessary(int fd, off_t sum, off_t keep_free, off_t max_use)
if (max_use < DEFAULT_MAX_USE_LOWER)
max_use = DEFAULT_MAX_USE_LOWER;
- }
- else
+ } else
max_use = DEFAULT_MAX_USE_LOWER;
} else
max_use = PAGE_ALIGN(max_use);
@@ -135,7 +134,7 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) {
struct stat exclude_st;
int r;
- if (keep_free <= 0 && max_use <= 0)
+ if (keep_free == 0 && max_use == 0)
return 0;
if (exclude_fd >= 0) {
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index f7ba0191e1..1c747aa2b4 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -23,7 +23,6 @@
#include <unistd.h>
#include <stdio.h>
#include <sys/prctl.h>
-#include <sys/types.h>
#include <sys/xattr.h>
#ifdef HAVE_ELFUTILS
@@ -44,12 +43,12 @@
#include "conf-parser.h"
#include "copy.h"
#include "stacktrace.h"
-#include "path-util.h"
#include "compress.h"
#include "acl-util.h"
#include "capability.h"
#include "journald-native.h"
#include "coredump-vacuum.h"
+#include "process-util.h"
/* The maximum size up to which we process coredumps */
#define PROCESS_SIZE_MAX ((off_t) (2LLU*1024LLU*1024LLU*1024LLU))
@@ -244,7 +243,7 @@ static int maybe_remove_external_coredump(const char *filename, off_t size) {
static int make_filename(const char *info[_INFO_LEN], char **ret) {
_cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL;
- sd_id128_t boot;
+ sd_id128_t boot = {};
int r;
assert(info);
@@ -843,7 +842,7 @@ log:
/* Optionally store the entire coredump in the journal */
if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
coredump_size <= (off_t) arg_journal_size_max) {
- size_t sz;
+ size_t sz = 0;
/* Store the coredump itself in the journal */
diff --git a/src/journal/coredump.conf b/src/journal/coredump.conf
index 0fe9fe801a..c2f0643e03 100644
--- a/src/journal/coredump.conf
+++ b/src/journal/coredump.conf
@@ -5,10 +5,11 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/coredump.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
-# See coredump.conf(5) for details
+# See coredump.conf(5) for details.
[Coredump]
#Storage=external
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index afb39ad035..381bf72776 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -35,9 +35,11 @@
#include "pager.h"
#include "macro.h"
#include "journal-internal.h"
-#include "copy.h"
#include "compress.h"
#include "sigbus.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
static enum {
ACTION_NONE,
@@ -650,7 +652,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
}
#else
log_error("Cannot decompress file. Compiled without compression support.");
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
goto error;
#endif
} else {
diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c
index 5c8d6d6feb..a9f564c249 100644
--- a/src/journal/fsprg.c
+++ b/src/journal/fsprg.c
@@ -30,7 +30,6 @@
#include <gcrypt.h>
#include <string.h>
-#include <assert.h>
#include "fsprg.h"
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index b3e2601c4e..cdc80e2d26 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -106,7 +106,7 @@ static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *e
if (f->fss_start_usec == 0 ||
f->fss_interval_usec == 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (realtime < f->fss_start_usec)
return -ESTALE;
@@ -446,7 +446,7 @@ int journal_file_hmac_setup(JournalFile *f) {
e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (e != 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
return 0;
}
diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h
index 565fe8432c..118bb1367b 100644
--- a/src/journal/journal-authenticate.h
+++ b/src/journal/journal-authenticate.h
@@ -22,7 +22,6 @@
***/
#include <stdbool.h>
-#include <inttypes.h>
#include "journal-file.h"
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index ab089cb966..39c9dd0dbf 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -220,7 +220,7 @@ struct Header {
le64_t n_tags;
le64_t n_entry_arrays;
- /* Size: 224 */
+ /* Size: 240 */
} _packed_;
#define FSS_HEADER_SIGNATURE ((char[]) { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' })
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 2845e05ce0..be6a5522fa 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -34,7 +34,7 @@
#include "journal-authenticate.h"
#include "lookup3.h"
#include "compress.h"
-#include "fsprg.h"
+#include "random-util.h"
#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
#define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
@@ -150,7 +150,7 @@ void journal_file_close(JournalFile *f) {
* reenable all the good bits COW usually provides
* (such as data checksumming). */
- (void) chattr_fd(f->fd, false, FS_NOCOW_FL);
+ (void) chattr_fd(f->fd, 0, FS_NOCOW_FL);
(void) btrfs_defrag_fd(f->fd);
}
@@ -888,7 +888,7 @@ int journal_file_find_data_object_with_hash(
if (o->object.flags & OBJECT_COMPRESSION_MASK) {
#if defined(HAVE_XZ) || defined(HAVE_LZ4)
uint64_t l;
- size_t rsize;
+ size_t rsize = 0;
l = le64toh(o->object.size);
if (l <= offsetof(Object, data.payload))
@@ -1053,7 +1053,7 @@ static int journal_file_append_data(
#if defined(HAVE_XZ) || defined(HAVE_LZ4)
if (f->compress_xz &&
size >= COMPRESSION_SIZE_THRESHOLD) {
- size_t rsize;
+ size_t rsize = 0;
compression = compress_blob(data, size, o->data.payload, &rsize);
@@ -2014,8 +2014,7 @@ void journal_file_reset_location(JournalFile *f) {
f->current_xor_hash = 0;
}
-void journal_file_save_location(JournalFile *f, direction_t direction, Object *o, uint64_t offset) {
- f->last_direction = direction;
+void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset) {
f->location_type = LOCATION_SEEK;
f->current_offset = offset;
f->current_seqnum = le64toh(o->entry.seqnum);
@@ -2523,6 +2522,41 @@ void journal_file_print_header(JournalFile *f) {
printf("Disk usage: %s\n", format_bytes(bytes, sizeof(bytes), (off_t) st.st_blocks * 512ULL));
}
+static int journal_file_warn_btrfs(JournalFile *f) {
+ unsigned attrs;
+ int r;
+
+ assert(f);
+
+ /* Before we write anything, check if the COW logic is turned
+ * off on btrfs. Given our write pattern that is quite
+ * unfriendly to COW file systems this should greatly improve
+ * performance on COW file systems, such as btrfs, at the
+ * expense of data integrity features (which shouldn't be too
+ * bad, given that we do our own checksumming). */
+
+ r = btrfs_is_filesystem(f->fd);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to determine if journal is on btrfs: %m");
+ if (!r)
+ return 0;
+
+ r = read_attr_fd(f->fd, &attrs);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to read file attributes: %m");
+
+ if (attrs & FS_NOCOW_FL) {
+ log_debug("Detected btrfs file system with copy-on-write disabled, all is good.");
+ return 0;
+ }
+
+ log_notice("Creating journal file %s on a btrfs file system, and copy-on-write is enabled. "
+ "This is likely to slow down journal access substantially, please consider turning "
+ "off the copy-on-write file attribute on the journal directory, using chattr +C.", f->path);
+
+ return 1;
+}
+
int journal_file_open(
const char *fname,
int flags,
@@ -2603,16 +2637,7 @@ int journal_file_open(
if (f->last_stat.st_size == 0 && f->writable) {
- /* Before we write anything, turn off COW logic. Given
- * our write pattern that is quite unfriendly to COW
- * file systems this should greatly improve
- * performance on COW file systems, such as btrfs, at
- * the expense of data integrity features (which
- * shouldn't be too bad, given that we do our own
- * checksumming). */
- r = chattr_fd(f->fd, true, FS_NOCOW_FL);
- if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes: %m");
+ (void) journal_file_warn_btrfs(f);
/* Let's attach the creation time to the journal file,
* so that the vacuuming code knows the age of this
@@ -2653,10 +2678,8 @@ int journal_file_open(
}
r = mmap_cache_get(f->mmap, f->fd, f->prot, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h);
- if (r < 0) {
- r = -errno;
+ if (r < 0)
goto fail;
- }
f->header = h;
@@ -2797,14 +2820,15 @@ int journal_file_open_reliably(
r = journal_file_open(fname, flags, mode, compress, seal,
metrics, mmap_cache, template, ret);
- if (r != -EBADMSG && /* corrupted */
- r != -ENODATA && /* truncated */
- r != -EHOSTDOWN && /* other machine */
- r != -EPROTONOSUPPORT && /* incompatible feature */
- r != -EBUSY && /* unclean shutdown */
- r != -ESHUTDOWN && /* already archived */
- r != -EIO && /* IO error, including SIGBUS on mmap */
- r != -EIDRM /* File has been deleted */)
+ if (!IN_SET(r,
+ -EBADMSG, /* corrupted */
+ -ENODATA, /* truncated */
+ -EHOSTDOWN, /* other machine */
+ -EPROTONOSUPPORT, /* incompatible feature */
+ -EBUSY, /* unclean shutdown */
+ -ESHUTDOWN, /* already archived */
+ -EIO, /* IO error, including SIGBUS on mmap */
+ -EIDRM /* File has been deleted */))
return r;
if ((flags & O_ACCMODE) == O_RDONLY)
@@ -2819,9 +2843,9 @@ int journal_file_open_reliably(
/* The file is corrupted. Rotate it away and try it again (but only once) */
l = strlen(fname);
- if (asprintf(&p, "%.*s@%016llx-%016" PRIx64 ".journal~",
+ if (asprintf(&p, "%.*s@%016"PRIx64 "-%016"PRIx64 ".journal~",
(int) l - 8, fname,
- (unsigned long long) now(CLOCK_REALTIME),
+ now(CLOCK_REALTIME),
random_u64()) < 0)
return -ENOMEM;
@@ -2889,7 +2913,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
if (o->object.flags & OBJECT_COMPRESSION_MASK) {
#if defined(HAVE_XZ) || defined(HAVE_LZ4)
- size_t rsize;
+ size_t rsize = 0;
r = decompress_blob(o->object.flags & OBJECT_COMPRESSION_MASK,
o->data.payload, l, &from->compress_buffer, &from->compress_buffer_size, &rsize, 0);
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 2526e14d65..403c8f760c 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -199,7 +199,7 @@ int journal_file_find_field_object(JournalFile *f, const void *field, uint64_t s
int journal_file_find_field_object_with_hash(JournalFile *f, const void *field, uint64_t size, uint64_t hash, Object **ret, uint64_t *offset);
void journal_file_reset_location(JournalFile *f);
-void journal_file_save_location(JournalFile *f, direction_t direction, Object *o, uint64_t offset);
+void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset);
int journal_file_compare_locations(JournalFile *af, JournalFile *bf);
int journal_file_next_entry(JournalFile *f, uint64_t p, direction_t direction, Object **ret, uint64_t *offset);
diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h
index c527e65553..3ff6a3ad4a 100644
--- a/src/journal/journal-qrcode.h
+++ b/src/journal/journal-qrcode.h
@@ -21,8 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
-#include <sys/types.h>
#include <stdio.h>
#include "systemd/sd-id128.h"
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 832c327b31..81a577ea27 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -19,12 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <sys/statvfs.h>
#include <unistd.h>
-#include <sys/xattr.h>
#include "journal-def.h"
#include "journal-file.h"
@@ -76,7 +73,7 @@ static void patch_realtime(
unsigned long long *realtime) {
_cleanup_free_ const char *path = NULL;
- usec_t x, crtime;
+ usec_t x, crtime = 0;
/* The timestamp was determined by the file name, but let's
* see if the file might actually be older than the file name
diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h
index a7fb6f0f0d..c45cc31d0e 100644
--- a/src/journal/journal-vacuum.h
+++ b/src/journal/journal-vacuum.h
@@ -21,6 +21,5 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index b03335ef31..ce734d8df7 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -32,7 +32,7 @@
#include "journal-verify.h"
#include "lookup3.h"
#include "compress.h"
-#include "fsprg.h"
+#include "terminal-util.h"
static void draw_progress(uint64_t p, usec_t *last_usec) {
unsigned n, i, j, k;
@@ -818,7 +818,7 @@ int journal_file_verify(
return r;
}
#else
- return -ENOTSUP;
+ return -EOPNOTSUPP;
#endif
} else if (f->seal)
return -ENOKEY;
@@ -846,7 +846,7 @@ int journal_file_verify(
if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
log_error("Cannot verify file with unknown extensions.");
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
goto fail;
}
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 55c7786331..76ec0827e7 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -28,18 +28,15 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
-#include <time.h>
#include <getopt.h>
#include <signal.h>
#include <poll.h>
#include <sys/stat.h>
-#include <sys/ioctl.h>
#include <sys/inotify.h>
#include <linux/fs.h>
#include "sd-journal.h"
#include "sd-bus.h"
-
#include "log.h"
#include "logs-show.h"
#include "util.h"
@@ -54,7 +51,6 @@
#include "journal-internal.h"
#include "journal-def.h"
#include "journal-verify.h"
-#include "journal-authenticate.h"
#include "journal-qrcode.h"
#include "journal-vacuum.h"
#include "fsprg.h"
@@ -63,6 +59,8 @@
#include "mkdir.h"
#include "bus-util.h"
#include "bus-error.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
@@ -127,11 +125,12 @@ static enum {
ACTION_VACUUM,
} arg_action = ACTION_SHOW;
-typedef struct boot_id_t {
+typedef struct BootId {
sd_id128_t id;
uint64_t first;
uint64_t last;
-} boot_id_t;
+ LIST_FIELDS(struct BootId, boot_list);
+} BootId;
static void pager_open_if_enabled(void) {
@@ -452,7 +451,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_boot = true;
if (optarg) {
- r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
+ r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
if (r < 0) {
log_error("Failed to parse boot descriptor '%s'", optarg);
return -EINVAL;
@@ -579,7 +578,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_INTERVAL:
case ARG_FORCE:
log_error("Forward-secure sealing not available.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
#endif
case 'p': {
@@ -735,6 +734,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && (arg_file || arg_directory || arg_merge)) {
+ log_error("Using --boot or --list-boots with --file, --directory or --merge is not supported.");
+ return -EINVAL;
+ }
+
return 1;
}
@@ -791,7 +795,7 @@ static int add_matches(sd_journal *j, char **args) {
p = canonicalize_file_name(*i);
path = p ? p : *i;
- if (stat(path, &st) < 0)
+ if (lstat(path, &st) < 0)
return log_error_errno(errno, "Couldn't stat file: %m");
if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
@@ -814,17 +818,11 @@ static int add_matches(sd_journal *j, char **args) {
}
} else
t = strappend("_EXE=", path);
- } else if (S_ISCHR(st.st_mode)) {
- if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u",
- major(st.st_rdev),
- minor(st.st_rdev)) < 0)
- return -ENOMEM;
- } else if (S_ISBLK(st.st_mode)) {
- if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u",
- major(st.st_rdev),
- minor(st.st_rdev)) < 0)
- return -ENOMEM;
- } else {
+ } else if (S_ISCHR(st.st_mode))
+ (void) asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
+ else if (S_ISBLK(st.st_mode))
+ (void) asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
+ else {
log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
return -EINVAL;
}
@@ -854,111 +852,217 @@ static int add_matches(sd_journal *j, char **args) {
return 0;
}
-static int boot_id_cmp(const void *a, const void *b) {
- uint64_t _a, _b;
-
- _a = ((const boot_id_t *)a)->first;
- _b = ((const boot_id_t *)b)->first;
+static void boot_id_free_all(BootId *l) {
- return _a < _b ? -1 : (_a > _b ? 1 : 0);
+ while (l) {
+ BootId *i = l;
+ LIST_REMOVE(boot_list, l, i);
+ free(i);
+ }
}
-static int get_boots(sd_journal *j,
- boot_id_t **boots,
- unsigned int *count,
- boot_id_t *query_ref_boot) {
+static int discover_next_boot(
+ sd_journal *j,
+ BootId **boot,
+ bool advance_older,
+ bool read_realtime) {
+
int r;
- const void *data;
- size_t length, allocated = 0;
+ char match[9+32+1] = "_BOOT_ID=";
+ _cleanup_free_ BootId *next_boot = NULL;
assert(j);
- assert(boots);
- assert(count);
+ assert(boot);
+
+ /* We expect the journal to be on the last position of a boot
+ * (in relation to the direction we are going), so that the next
+ * invocation of sd_journal_next/previous will be from a different
+ * boot. We then collect any information we desire and then jump
+ * to the last location of the new boot by using a _BOOT_ID match
+ * coming from the other journal direction. */
+
+ /* Make sure we aren't restricted by any _BOOT_ID matches, so that
+ * we can actually advance to a *different* boot. */
+ sd_journal_flush_matches(j);
- r = sd_journal_query_unique(j, "_BOOT_ID");
+ if (advance_older)
+ r = sd_journal_previous(j);
+ else
+ r = sd_journal_next(j);
if (r < 0)
return r;
+ else if (r == 0)
+ return 0; /* End of journal, yay. */
- *count = 0;
- SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
- boot_id_t *id;
+ next_boot = new0(BootId, 1);
+ if (!next_boot)
+ return -ENOMEM;
- assert(startswith(data, "_BOOT_ID="));
+ r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id);
+ if (r < 0)
+ return r;
- if (!GREEDY_REALLOC(*boots, allocated, *count + 1))
- return log_oom();
+ if (read_realtime) {
+ r = sd_journal_get_realtime_usec(j, &next_boot->first);
+ if (r < 0)
+ return r;
+ }
+
+ /* Now seek to the last occurrence of this boot ID. */
+ sd_id128_to_string(next_boot->id, match + 9);
+ r = sd_journal_add_match(j, match, sizeof(match) - 1);
+ if (r < 0)
+ return r;
+
+ if (advance_older)
+ r = sd_journal_seek_head(j);
+ else
+ r = sd_journal_seek_tail(j);
+ if (r < 0)
+ return r;
- id = *boots + *count;
+ if (advance_older)
+ r = sd_journal_next(j);
+ else
+ r = sd_journal_previous(j);
+ if (r < 0)
+ return r;
+ else if (r == 0)
+ return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
- r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
+ if (read_realtime) {
+ r = sd_journal_get_realtime_usec(j, &next_boot->last);
if (r < 0)
- continue;
+ return r;
+ }
- r = sd_journal_add_match(j, data, length);
+ *boot = next_boot;
+ next_boot = NULL;
+
+ return 0;
+}
+
+static int get_boots(
+ sd_journal *j,
+ BootId **boots,
+ BootId *query_ref_boot,
+ int ref_boot_offset) {
+
+ bool skip_once;
+ int r, count = 0;
+ BootId *head = NULL, *tail = NULL;
+ const bool advance_older = query_ref_boot && ref_boot_offset <= 0;
+
+ assert(j);
+
+ /* Adjust for the asymmetry that offset 0 is
+ * the last (and current) boot, while 1 is considered the
+ * (chronological) first boot in the journal. */
+ skip_once = query_ref_boot && sd_id128_is_null(query_ref_boot->id) && ref_boot_offset < 0;
+
+ /* Advance to the earliest/latest occurrence of our reference
+ * boot ID (taking our lookup direction into account), so that
+ * discover_next_boot() can do its job.
+ * If no reference is given, the journal head/tail will do,
+ * they're "virtual" boots after all. */
+ if (query_ref_boot && !sd_id128_is_null(query_ref_boot->id)) {
+ char match[9+32+1] = "_BOOT_ID=";
+
+ sd_journal_flush_matches(j);
+
+ sd_id128_to_string(query_ref_boot->id, match + 9);
+ r = sd_journal_add_match(j, match, sizeof(match) - 1);
if (r < 0)
return r;
- r = sd_journal_seek_head(j);
+ if (advance_older)
+ r = sd_journal_seek_head(j);
+ else
+ r = sd_journal_seek_tail(j);
if (r < 0)
return r;
- r = sd_journal_next(j);
+ if (advance_older)
+ r = sd_journal_next(j);
+ else
+ r = sd_journal_previous(j);
if (r < 0)
return r;
else if (r == 0)
- goto flush;
-
- r = sd_journal_get_realtime_usec(j, &id->first);
+ goto finish;
+ else if (ref_boot_offset == 0) {
+ count = 1;
+ goto finish;
+ }
+ } else {
+ if (advance_older)
+ r = sd_journal_seek_tail(j);
+ else
+ r = sd_journal_seek_head(j);
if (r < 0)
return r;
- if (query_ref_boot) {
- id->last = 0;
- if (sd_id128_equal(id->id, query_ref_boot->id))
- *query_ref_boot = *id;
- } else {
- r = sd_journal_seek_tail(j);
- if (r < 0)
- return r;
+ /* No sd_journal_next/previous here. */
+ }
- r = sd_journal_previous(j);
- if (r < 0)
- return r;
- else if (r == 0)
- goto flush;
+ for (;;) {
+ _cleanup_free_ BootId *current = NULL;
- r = sd_journal_get_realtime_usec(j, &id->last);
- if (r < 0)
- return r;
+ r = discover_next_boot(j, &current, advance_older, !query_ref_boot);
+ if (r < 0) {
+ boot_id_free_all(head);
+ return r;
}
- (*count)++;
- flush:
- sd_journal_flush_matches(j);
+ if (!current)
+ break;
+
+ if (query_ref_boot) {
+ if (!skip_once)
+ ref_boot_offset += advance_older ? 1 : -1;
+ skip_once = false;
+
+ if (ref_boot_offset == 0) {
+ count = 1;
+ query_ref_boot->id = current->id;
+ break;
+ }
+ } else {
+ LIST_INSERT_AFTER(boot_list, head, tail, current);
+ tail = current;
+ current = NULL;
+ count++;
+ }
}
- qsort_safe(*boots, *count, sizeof(boot_id_t), boot_id_cmp);
- return 0;
+finish:
+ if (boots)
+ *boots = head;
+
+ sd_journal_flush_matches(j);
+
+ return count;
}
static int list_boots(sd_journal *j) {
- int r, w, i;
- unsigned int count;
- boot_id_t *id;
- _cleanup_free_ boot_id_t *all_ids = NULL;
+ int w, i, count;
+ BootId *id, *all_ids;
assert(j);
- r = get_boots(j, &all_ids, &count, NULL);
- if (r < 0)
- return r;
+ count = get_boots(j, &all_ids, NULL, 0);
+ if (count < 0)
+ return log_error_errno(count, "Failed to determine boots: %m");
+ if (count == 0)
+ return count;
pager_open_if_enabled();
/* numbers are one less, but we need an extra char for the sign */
w = DECIMAL_STR_WIDTH(count - 1) + 1;
- for (id = all_ids, i = 0; id < all_ids + count; id++, i++) {
+ i = 0;
+ LIST_FOREACH(boot_list, id, all_ids) {
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
@@ -966,40 +1070,10 @@ static int list_boots(sd_journal *j) {
SD_ID128_FORMAT_VAL(id->id),
format_timestamp_maybe_utc(a, sizeof(a), id->first),
format_timestamp_maybe_utc(b, sizeof(b), id->last));
+ i++;
}
- return 0;
-}
-
-static int get_boot_id_by_offset(sd_journal *j, sd_id128_t *boot_id, int offset) {
- int r;
- unsigned int count;
- boot_id_t ref_boot_id = {}, *id;
- _cleanup_free_ boot_id_t *all_ids = NULL;
-
- assert(j);
- assert(boot_id);
-
- ref_boot_id.id = *boot_id;
- r = get_boots(j, &all_ids, &count, &ref_boot_id);
- if (r < 0)
- return r;
-
- if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
- if (offset > (int) count || offset <= -(int)count)
- return -EADDRNOTAVAIL;
-
- *boot_id = all_ids[(offset <= 0)*count + offset - 1].id;
- } else {
- id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
-
- if (!id ||
- offset <= 0 ? (id - all_ids) + offset < 0 :
- (id - all_ids) + offset >= (int) count)
- return -EADDRNOTAVAIL;
-
- *boot_id = (id + offset)->id;
- }
+ boot_id_free_all(all_ids);
return 0;
}
@@ -1007,6 +1081,7 @@ static int get_boot_id_by_offset(sd_journal *j, sd_id128_t *boot_id, int offset)
static int add_boot(sd_journal *j) {
char match[9+32+1] = "_BOOT_ID=";
int r;
+ BootId ref_boot_id = {};
assert(j);
@@ -1016,17 +1091,22 @@ static int add_boot(sd_journal *j) {
if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
return add_match_this_boot(j, arg_machine);
- r = get_boot_id_by_offset(j, &arg_boot_id, arg_boot_offset);
- if (r < 0) {
- if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
- log_error_errno(r, "Failed to look up boot %+i: %m", arg_boot_offset);
+ ref_boot_id.id = arg_boot_id;
+ r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset);
+ assert(r <= 1);
+ if (r <= 0) {
+ const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r);
+
+ if (sd_id128_is_null(arg_boot_id))
+ log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason);
else
log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
- SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
- return r;
+ SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason);
+
+ return r == 0 ? -ENODATA : r;
}
- sd_id128_to_string(arg_boot_id, match + 9);
+ sd_id128_to_string(ref_boot_id.id, match + 9);
r = sd_journal_add_match(j, match, sizeof(match) - 1);
if (r < 0)
@@ -1034,7 +1114,7 @@ static int add_boot(sd_journal *j) {
r = sd_journal_add_conjunction(j);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add conjunction: %m");
return 0;
}
@@ -1052,22 +1132,24 @@ static int add_dmesg(sd_journal *j) {
r = sd_journal_add_conjunction(j);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add conjunction: %m");
return 0;
}
-static int get_possible_units(sd_journal *j,
- const char *fields,
- char **patterns,
- Set **units) {
+static int get_possible_units(
+ sd_journal *j,
+ const char *fields,
+ char **patterns,
+ Set **units) {
+
_cleanup_set_free_free_ Set *found;
const char *field;
int r;
found = set_new(&string_hash_ops);
if (!found)
- return log_oom();
+ return -ENOMEM;
NULSTR_FOREACH(field, fields) {
const void *data;
@@ -1090,7 +1172,7 @@ static int get_possible_units(sd_journal *j,
u = strndup((char*) data + prefix, size - prefix);
if (!u)
- return log_oom();
+ return -ENOMEM;
STRV_FOREACH(pattern, patterns)
if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
@@ -1137,9 +1219,9 @@ static int add_units(sd_journal *j) {
STRV_FOREACH(i, arg_system_units) {
_cleanup_free_ char *u = NULL;
- u = unit_name_mangle(*i, MANGLE_GLOB);
- if (!u)
- return log_oom();
+ r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
+ if (r < 0)
+ return r;
if (string_is_glob(u)) {
r = strv_push(&patterns, u);
@@ -1183,9 +1265,9 @@ static int add_units(sd_journal *j) {
STRV_FOREACH(i, arg_user_units) {
_cleanup_free_ char *u = NULL;
- u = unit_name_mangle(*i, MANGLE_GLOB);
- if (!u)
- return log_oom();
+ r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
+ if (r < 0)
+ return r;
if (string_is_glob(u)) {
r = strv_push(&patterns, u);
@@ -1254,7 +1336,7 @@ static int add_priorities(sd_journal *j) {
r = sd_journal_add_conjunction(j);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add conjunction: %m");
return 0;
}
@@ -1289,7 +1371,6 @@ static int setup_keys(void) {
#ifdef HAVE_GCRYPT
size_t mpk_size, seed_size, state_size, i;
uint8_t *mpk, *seed, *state;
- ssize_t l;
int fd = -1, r;
sd_id128_t machine, boot;
char *p = NULL, *k = NULL;
@@ -1319,19 +1400,16 @@ static int setup_keys(void) {
SD_ID128_FORMAT_VAL(machine)) < 0)
return log_oom();
- if (access(p, F_OK) >= 0) {
- if (arg_force) {
- r = unlink(p);
- if (r < 0) {
- log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
- r = -errno;
- goto finish;
- }
- } else {
- log_error("Sealing key file %s exists already. (--force to recreate)", p);
- r = -EEXIST;
+ if (arg_force) {
+ r = unlink(p);
+ if (r < 0 && errno != ENOENT) {
+ r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
goto finish;
}
+ } else if (access(p, F_OK) >= 0) {
+ log_error("Sealing key file %s exists already. Use --force to recreate.", p);
+ r = -EEXIST;
+ goto finish;
}
if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
@@ -1357,10 +1435,9 @@ static int setup_keys(void) {
}
log_info("Generating seed...");
- l = loop_read(fd, seed, seed_size, true);
- if (l < 0 || (size_t) l != seed_size) {
- log_error_errno(EIO, "Failed to read random seed: %m");
- r = -EIO;
+ r = loop_read_exact(fd, seed, seed_size, true);
+ if (r < 0) {
+ log_error_errno(r, "Failed to read random seed: %m");
goto finish;
}
@@ -1385,7 +1462,7 @@ static int setup_keys(void) {
/* Enable secure remove, exclusion from dump, synchronous
* writing and in-place updating */
- r = chattr_fd(fd, true, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
+ r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
if (r < 0)
log_warning_errno(errno, "Failed to set file attributes: %m");
@@ -1480,7 +1557,7 @@ finish:
return r;
#else
log_error("Forward-secure sealing not available.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
#endif
}
@@ -1495,7 +1572,7 @@ static int verify(sd_journal *j) {
ORDERED_HASHMAP_FOREACH(f, j->files, i) {
int k;
- usec_t first, validated, last;
+ usec_t first = 0, validated = 0, last = 0;
#ifdef HAVE_GCRYPT
if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
@@ -1531,54 +1608,76 @@ static int verify(sd_journal *j) {
return r;
}
-#ifdef HAVE_ACL
static int access_check_var_log_journal(sd_journal *j) {
+#ifdef HAVE_ACL
_cleanup_strv_free_ char **g = NULL;
- bool have_access;
+ const char* dir;
+#endif
int r;
assert(j);
- have_access = in_group("systemd-journal") > 0;
+ if (arg_quiet)
+ return 0;
- if (!have_access) {
- /* Let's enumerate all groups from the default ACL of
- * the directory, which generally should allow access
- * to most journal files too */
- r = search_acl_groups(&g, "/var/log/journal/", &have_access);
- if (r < 0)
- return r;
- }
+ /* If we are root, we should have access, don't warn. */
+ if (getuid() == 0)
+ return 0;
- if (!have_access) {
+ /* If we are in the 'systemd-journal' group, we should have
+ * access too. */
+ r = in_group("systemd-journal");
+ if (r < 0)
+ return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m");
+ if (r > 0)
+ return 0;
- if (strv_isempty(g))
- log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
- " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
- " turn off this notice.");
- else {
- _cleanup_free_ char *s = NULL;
+#ifdef HAVE_ACL
+ if (laccess("/run/log/journal", F_OK) >= 0)
+ dir = "/run/log/journal";
+ else
+ dir = "/var/log/journal";
- r = strv_extend(&g, "systemd-journal");
- if (r < 0)
- return log_oom();
+ /* If we are in any of the groups listed in the journal ACLs,
+ * then all is good, too. Let's enumerate all groups from the
+ * default ACL of the directory, which generally should allow
+ * access to most journal files too. */
+ r = acl_search_groups(dir, &g);
+ if (r < 0)
+ return log_error_errno(r, "Failed to search journal ACL: %m");
+ if (r > 0)
+ return 0;
- strv_sort(g);
- strv_uniq(g);
+ /* Print a pretty list, if there were ACLs set. */
+ if (!strv_isempty(g)) {
+ _cleanup_free_ char *s = NULL;
- s = strv_join(g, "', '");
- if (!s)
- return log_oom();
+ /* Thre are groups in the ACL, let's list them */
+ r = strv_extend(&g, "systemd-journal");
+ if (r < 0)
+ return log_oom();
- log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
- " Users in the groups '%s' can see all messages.\n"
- " Pass -q to turn off this notice.", s);
- }
+ strv_sort(g);
+ strv_uniq(g);
+
+ s = strv_join(g, "', '");
+ if (!s)
+ return log_oom();
+
+ log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
+ " Users in groups '%s' can see all messages.\n"
+ " Pass -q to turn off this notice.", s);
+ return 1;
}
+#endif
- return 0;
+ /* If no ACLs were found, print a short version of the message. */
+ log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
+ " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
+ " turn off this notice.");
+
+ return 1;
}
-#endif
static int access_check(sd_journal *j) {
Iterator it;
@@ -1590,40 +1689,15 @@ static int access_check(sd_journal *j) {
if (set_isempty(j->errors)) {
if (ordered_hashmap_isempty(j->files))
log_notice("No journal files were found.");
+
return 0;
}
if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
-#ifdef HAVE_ACL
- /* If /var/log/journal doesn't even exist,
- * unprivileged users have no access at all */
- if (access("/var/log/journal", F_OK) < 0 &&
- geteuid() != 0 &&
- in_group("systemd-journal") <= 0) {
- log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
- "enabled. Users in the 'systemd-journal' group may always access messages.");
- return -EACCES;
- }
-
- /* If /var/log/journal exists, try to pring a nice
- notice if the user lacks access to it */
- if (!arg_quiet && geteuid() != 0) {
- r = access_check_var_log_journal(j);
- if (r < 0)
- return r;
- }
-#else
- if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
- log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
- "group may access messages.");
- return -EACCES;
- }
-#endif
+ (void) access_check_var_log_journal(j);
- if (ordered_hashmap_isempty(j->files)) {
- log_error("No journal files were opened due to insufficient permissions.");
- r = -EACCES;
- }
+ if (ordered_hashmap_isempty(j->files))
+ r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
}
SET_FOREACH(code, j->errors, it) {
@@ -1632,8 +1706,12 @@ static int access_check(sd_journal *j) {
err = -PTR_TO_INT(code);
assert(err > 0);
- if (err != EACCES)
- log_warning_errno(err, "Error was encountered while opening journal files: %m");
+ if (err == EACCES)
+ continue;
+
+ log_warning_errno(err, "Error was encountered while opening journal files: %m");
+ if (r == 0)
+ r = -err;
}
return r;
@@ -1780,12 +1858,12 @@ int main(int argc, char *argv[]) {
if (r < 0) {
log_error_errno(r, "Failed to open %s: %m",
arg_directory ? arg_directory : arg_file ? "files" : "journal");
- return EXIT_FAILURE;
+ goto finish;
}
r = access_check(j);
if (r < 0)
- return EXIT_FAILURE;
+ goto finish;
if (arg_action == ACTION_VERIFY) {
r = verify(j);
@@ -1794,7 +1872,8 @@ int main(int argc, char *argv[]) {
if (arg_action == ACTION_PRINT_HEADER) {
journal_print_header(j);
- return EXIT_SUCCESS;
+ r = 0;
+ goto finish;
}
if (arg_action == ACTION_DISK_USAGE) {
@@ -1803,11 +1882,11 @@ int main(int argc, char *argv[]) {
r = sd_journal_get_usage(j, &bytes);
if (r < 0)
- return EXIT_FAILURE;
+ goto finish;
printf("Archived and active journals take up %s on disk.\n",
format_bytes(sbytes, sizeof(sbytes), bytes));
- return EXIT_SUCCESS;
+ goto finish;
}
if (arg_action == ACTION_VACUUM) {
@@ -1827,7 +1906,7 @@ int main(int argc, char *argv[]) {
}
}
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ goto finish;
}
if (arg_action == ACTION_LIST_BOOTS) {
@@ -1839,43 +1918,39 @@ int main(int argc, char *argv[]) {
* It may need to seek the journal to find parent boot IDs. */
r = add_boot(j);
if (r < 0)
- return EXIT_FAILURE;
+ goto finish;
r = add_dmesg(j);
if (r < 0)
- return EXIT_FAILURE;
+ goto finish;
r = add_units(j);
- strv_free(arg_system_units);
- strv_free(arg_user_units);
-
if (r < 0) {
log_error_errno(r, "Failed to add filter for units: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = add_syslog_identifier(j);
if (r < 0) {
log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = add_priorities(j);
- if (r < 0) {
- log_error_errno(r, "Failed to add filter for priorities: %m");
- return EXIT_FAILURE;
- }
+ if (r < 0)
+ goto finish;
r = add_matches(j, argv + optind);
- if (r < 0) {
- log_error_errno(r, "Failed to add filters: %m");
- return EXIT_FAILURE;
- }
+ if (r < 0)
+ goto finish;
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *filter;
filter = journal_make_match_string(j);
+ if (!filter)
+ return log_oom();
+
log_debug("Journal filter: %s", filter);
}
@@ -1885,14 +1960,14 @@ int main(int argc, char *argv[]) {
r = sd_journal_set_data_threshold(j, 0);
if (r < 0) {
- log_error("Failed to unset data size threshold");
- return EXIT_FAILURE;
+ log_error_errno(r, "Failed to unset data size threshold: %m");
+ goto finish;
}
r = sd_journal_query_unique(j, arg_field);
if (r < 0) {
log_error_errno(r, "Failed to query unique data objects: %m");
- return EXIT_FAILURE;
+ goto finish;
}
SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
@@ -1910,22 +1985,26 @@ int main(int argc, char *argv[]) {
n_shown ++;
}
- return EXIT_SUCCESS;
+ r = 0;
+ goto finish;
}
/* Opening the fd now means the first sd_journal_wait() will actually wait */
if (arg_follow) {
r = sd_journal_get_fd(j);
- if (r < 0)
- return EXIT_FAILURE;
+ if (r < 0) {
+ log_error_errno(r, "Failed to get journal fd: %m");
+ goto finish;
+ }
}
if (arg_cursor || arg_after_cursor) {
r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
if (r < 0) {
log_error_errno(r, "Failed to seek to cursor: %m");
- return EXIT_FAILURE;
+ goto finish;
}
+
if (!arg_reverse)
r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
else
@@ -1943,7 +2022,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_seek_realtime_usec(j, arg_since);
if (r < 0) {
log_error_errno(r, "Failed to seek to date: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = sd_journal_next(j);
@@ -1951,7 +2030,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_seek_realtime_usec(j, arg_until);
if (r < 0) {
log_error_errno(r, "Failed to seek to date: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = sd_journal_previous(j);
@@ -1959,7 +2038,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_seek_tail(j);
if (r < 0) {
log_error_errno(r, "Failed to seek to tail: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = sd_journal_previous_skip(j, arg_lines);
@@ -1968,7 +2047,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_seek_tail(j);
if (r < 0) {
log_error_errno(r, "Failed to seek to tail: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = sd_journal_previous(j);
@@ -1977,7 +2056,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_seek_head(j);
if (r < 0) {
log_error_errno(r, "Failed to seek to head: %m");
- return EXIT_FAILURE;
+ goto finish;
}
r = sd_journal_next(j);
@@ -1985,7 +2064,7 @@ int main(int argc, char *argv[]) {
if (r < 0) {
log_error_errno(r, "Failed to iterate through journal: %m");
- return EXIT_FAILURE;
+ goto finish;
}
if (!arg_follow)
@@ -2113,5 +2192,9 @@ finish:
strv_free(arg_file);
+ strv_free(arg_syslog_identifier);
+ strv_free(arg_system_units);
+ strv_free(arg_user_units);
+
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c
index c2f1545cc9..83c3332abf 100644
--- a/src/journal/journald-audit.c
+++ b/src/journal/journald-audit.c
@@ -21,6 +21,7 @@
#include "missing.h"
#include "journald-audit.h"
+#include "audit-type.h"
typedef struct MapField {
const char *audit_field;
@@ -336,7 +337,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s
size_t n_iov_allocated = 0;
unsigned n_iov = 0, k;
uint64_t seconds, msec, id;
- const char *p;
+ const char *p, *type_name;
unsigned z;
char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
@@ -373,7 +374,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s
if (isempty(p))
return;
- n_iov_allocated = N_IOVEC_META_FIELDS + 5;
+ n_iov_allocated = N_IOVEC_META_FIELDS + 7;
iov = new(struct iovec, n_iov_allocated);
if (!iov) {
log_oom();
@@ -392,8 +393,13 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s
sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
IOVEC_SET_STRING(iov[n_iov++], id_field);
- m = alloca(strlen("MESSAGE=<audit-") + DECIMAL_STR_MAX(int) + strlen("> ") + strlen(p) + 1);
- sprintf(m, "MESSAGE=<audit-%i> %s", type, p);
+ assert_cc(32 == LOG_AUTH);
+ IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32");
+ IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit");
+
+ type_name = audit_type_name_alloca(type);
+
+ m = strjoina("MESSAGE=", type_name, " ", p);
IOVEC_SET_STRING(iov[n_iov++], m);
z = n_iov;
@@ -528,9 +534,14 @@ int server_open_audit(Server *s) {
return 0;
}
- r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl));
- if (r < 0)
- return log_error_errno(errno, "Failed to join audit multicast group: %m");
+ if (bind(s->audit_fd, &sa.sa, sizeof(sa.nl)) < 0) {
+ log_warning_errno(errno,
+ "Failed to join audit multicast group. "
+ "The kernel is probably too old or multicast reading is not supported. "
+ "Ignoring: %m");
+ s->audit_fd = safe_close(s->audit_fd);
+ return 0;
+ }
} else
fd_nonblock(s->audit_fd, 1);
diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c
index 5363aaa4ff..307bdc3949 100644
--- a/src/journal/journald-console.c
+++ b/src/journal/journald-console.c
@@ -21,12 +21,14 @@
#include <time.h>
#include <fcntl.h>
-#include <unistd.h>
#include <sys/socket.h>
#include "fileio.h"
#include "journald-server.h"
#include "journald-console.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
static bool prefix_timestamp(void) {
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index c4216c4043..e5be7f7766 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -31,6 +31,8 @@
#include "journald-server.h"
#include "journald-kmsg.h"
#include "journald-syslog.h"
+#include "formats-util.h"
+#include "process-util.h"
void server_forward_kmsg(
Server *s,
@@ -201,8 +203,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
*e = 0;
- m = cunescape_length_with_prefix(k, e - k, "_KERNEL_");
- if (!m)
+ if (cunescape_length_with_prefix(k, e - k, "_KERNEL_", UNESCAPE_RELAX, &m) < 0)
break;
if (startswith(m, "_KERNEL_DEVICE="))
@@ -299,8 +300,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
}
}
- message = cunescape_length_with_prefix(p, pl, "MESSAGE=");
- if (message)
+ if (cunescape_length_with_prefix(p, pl, "MESSAGE=", UNESCAPE_RELAX, &message) >= 0)
IOVEC_SET_STRING(iovec[n++], message);
server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index 851625de04..da3faef93e 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -433,7 +433,7 @@ int server_open_native_socket(Server*s) {
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- chmod(sa.un.sun_path, 0666);
+ (void) chmod(sa.un.sun_path, 0666);
} else
fd_nonblock(s->native_fd, 1);
diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c
index 6d779d2966..6f83035a4e 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/journal/journald-rate-limit.c
@@ -26,6 +26,7 @@
#include "list.h"
#include "util.h"
#include "hashmap.h"
+#include "random-util.h"
#define POOLS_MAX 5
#define BUCKETS_MAX 127
diff --git a/src/journal/journald-rate-limit.h b/src/journal/journald-rate-limit.h
index 648ab22786..466239d3c6 100644
--- a/src/journal/journald-rate-limit.h
+++ b/src/journal/journald-rate-limit.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "macro.h"
#include "util.h"
typedef struct JournalRateLimit JournalRateLimit;
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 7ee8174ea2..3353024f4e 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -24,23 +24,30 @@
#include <linux/sockios.h>
#include <sys/statvfs.h>
#include <sys/mman.h>
-#include <sys/timerfd.h>
+
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
#include <libudev.h>
#include "sd-journal.h"
#include "sd-messages.h"
#include "sd-daemon.h"
-#include "fileio.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "hashmap.h"
#include "journal-file.h"
#include "socket-util.h"
#include "cgroup-util.h"
-#include "list.h"
#include "missing.h"
#include "conf-parser.h"
#include "selinux-util.h"
+#include "acl-util.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
#include "journal-internal.h"
#include "journal-vacuum.h"
#include "journal-authenticate.h"
@@ -48,15 +55,9 @@
#include "journald-kmsg.h"
#include "journald-syslog.h"
#include "journald-stream.h"
-#include "journald-console.h"
#include "journald-native.h"
#include "journald-audit.h"
#include "journald-server.h"
-#include "acl-util.h"
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
#define USER_JOURNALS_MAX 1024
@@ -1092,7 +1093,7 @@ finish:
s->runtime_journal = NULL;
if (r >= 0)
- rm_rf("/run/log/journal", false, true, false);
+ (void) rm_rf("/run/log/journal", REMOVE_ROOT);
sd_journal_close(j);
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index c96877c508..559d100131 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -21,16 +21,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <stdbool.h>
-#include <sys/epoll.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include "sd-event.h"
#include "journal-file.h"
#include "hashmap.h"
-#include "util.h"
#include "audit.h"
#include "journald-rate-limit.h"
#include "list.h"
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 942a857803..b572147a56 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <fcntl.h>
#include <unistd.h>
#include <stddef.h>
@@ -721,7 +720,7 @@ int server_open_stdout_socket(Server *s, FDSet *fds) {
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- chmod(sa.un.sun_path, 0666);
+ (void) chmod(sa.un.sun_path, 0666);
if (listen(s->stdout_fd, SOMAXCONN) < 0)
return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 7d545ca31d..90b7530946 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -31,6 +31,8 @@
#include "journald-kmsg.h"
#include "journald-console.h"
#include "journald-wall.h"
+#include "formats-util.h"
+#include "process-util.h"
/* Warn once every 30s if we missed syslog message */
#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
@@ -396,7 +398,7 @@ int server_open_syslog_socket(Server *s) {
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- chmod(sa.un.sun_path, 0666);
+ (void) chmod(sa.un.sun_path, 0666);
} else
fd_nonblock(s->syslog_fd, 1);
diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c
index e3201674d4..7863766ae7 100644
--- a/src/journal/journald-wall.c
+++ b/src/journal/journald-wall.c
@@ -22,6 +22,8 @@
#include "utmp-wtmp.h"
#include "journald-server.h"
#include "journald-wall.h"
+#include "formats-util.h"
+#include "process-util.h"
void server_forward_wall(
Server *s,
@@ -63,7 +65,7 @@ void server_forward_wall(
} else
l = message;
- r = utmp_wall(l, "systemd-journald", NULL);
+ r = utmp_wall(l, "systemd-journald", NULL, NULL, NULL);
if (r < 0)
log_debug_errno(r, "Failed to send wall message: %m");
}
diff --git a/src/journal/journald.c b/src/journal/journald.c
index 80f4634f67..b2624c6d28 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -19,12 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <errno.h>
#include <unistd.h>
-#include "systemd/sd-journal.h"
#include "systemd/sd-messages.h"
#include "systemd/sd-daemon.h"
@@ -34,6 +30,7 @@
#include "journald-syslog.h"
#include "sigbus.h"
+#include "formats-util.h"
int main(int argc, char *argv[]) {
Server server;
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 29bdf8f183..47eefe91c1 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -5,10 +5,11 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/journald.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
-# See journald.conf(5) for details
+# See journald.conf(5) for details.
[Journal]
#Storage=auto
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index ab21cdc288..22f75540b8 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -22,7 +22,6 @@
#include <errno.h>
#include <stdlib.h>
#include <sys/mman.h>
-#include <string.h>
#include "hashmap.h"
#include "list.h"
diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h
index a85c2b6063..37ea7b4a9c 100644
--- a/src/journal/mmap-cache.h
+++ b/src/journal/mmap-cache.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <stdbool.h>
#include <sys/stat.h>
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 94891cdf35..9f0f71aa81 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -42,6 +42,7 @@
#include "catalog.h"
#include "replace-var.h"
#include "fileio.h"
+#include "formats-util.h"
#define JOURNAL_FILES_MAX 7168
@@ -723,13 +724,17 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
assert(j);
assert(f);
- if (f->last_direction == direction && f->current_offset > 0) {
- /* If we hit EOF before, recheck if any new entries arrived. */
- n_entries = le64toh(f->header->n_entries);
- if (f->location_type == LOCATION_TAIL && n_entries == f->last_n_entries)
- return 0;
- f->last_n_entries = n_entries;
+ n_entries = le64toh(f->header->n_entries);
+
+ /* If we hit EOF before, we don't need to look into this file again
+ * unless direction changed or new entries appeared. */
+ if (f->last_direction == direction && f->location_type == LOCATION_TAIL &&
+ n_entries == f->last_n_entries)
+ return 0;
+
+ f->last_n_entries = n_entries;
+ if (f->last_direction == direction && f->current_offset > 0) {
/* LOCATION_SEEK here means we did the work in a previous
* iteration and the current location already points to a
* candidate entry. */
@@ -738,14 +743,16 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
if (r <= 0)
return r;
- journal_file_save_location(f, direction, c, cp);
+ journal_file_save_location(f, c, cp);
}
} else {
+ f->last_direction = direction;
+
r = find_location_with_matches(j, f, direction, &c, &cp);
if (r <= 0)
return r;
- journal_file_save_location(f, direction, c, cp);
+ journal_file_save_location(f, c, cp);
}
/* OK, we found the spot, now let's advance until an entry
@@ -773,7 +780,7 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc
if (r <= 0)
return r;
- journal_file_save_location(f, direction, c, cp);
+ journal_file_save_location(f, c, cp);
}
}
@@ -1242,7 +1249,7 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
r = add_any_file(j, path);
if (r == -ENOENT)
return 0;
- return 0;
+ return r;
}
static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
diff --git a/src/journal/stacktrace.c b/src/journal/stacktrace.c
index 6b9d2729f5..706c08eac7 100644
--- a/src/journal/stacktrace.c
+++ b/src/journal/stacktrace.c
@@ -25,6 +25,7 @@
#include "util.h"
#include "macro.h"
#include "stacktrace.h"
+#include "formats-util.h"
#define FRAMES_MAX 64
#define THREADS_MAX 64
diff --git a/src/journal/test-audit-type.c b/src/journal/test-audit-type.c
new file mode 100644
index 0000000000..7946cf3c41
--- /dev/null
+++ b/src/journal/test-audit-type.c
@@ -0,0 +1,44 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <linux/audit.h>
+
+#include "audit-type.h"
+
+static void print_audit_label(int i) {
+ const char *name;
+
+ name = audit_type_name_alloca(i);
+ /* This is a separate function only because of alloca */
+ printf("%i → %s → %s\n", i, audit_type_to_string(i), name);
+}
+
+static void test_audit_type(void) {
+ int i;
+
+ for (i = 0; i <= AUDIT_KERNEL; i++)
+ print_audit_label(i);
+}
+
+int main(int argc, char **argv) {
+ test_audit_type();
+}
diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c
index c605ee0e70..dbfdea609d 100644
--- a/src/journal/test-catalog.c
+++ b/src/journal/test-catalog.c
@@ -21,7 +21,6 @@
***/
#include <locale.h>
-#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index ae41c0c4c7..41a566d714 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -20,6 +20,7 @@
#include "compress.h"
#include "util.h"
#include "macro.h"
+#include "random-util.h"
#ifdef HAVE_XZ
# define XZ_OK 0
diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c
index 980244e016..cde2025ae9 100644
--- a/src/journal/test-journal-enum.c
+++ b/src/journal/test-journal-enum.c
@@ -24,7 +24,6 @@
#include "log.h"
#include "sd-journal.h"
#include "macro.h"
-#include "util.h"
#include "journal-internal.h"
int main(int argc, char *argv[]) {
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
index 914ca0b4d1..2d4f531e9b 100644
--- a/src/journal/test-journal-flush.c
+++ b/src/journal/test-journal-flush.c
@@ -27,8 +27,8 @@
#include "journal-internal.h"
int main(int argc, char *argv[]) {
-
- char dn[] = "/var/tmp/test-journal-flush.XXXXXX", *fn;
+ _cleanup_free_ char *fn = NULL;
+ char dn[] = "/var/tmp/test-journal-flush.XXXXXX";
JournalFile *new_journal = NULL;
sd_journal *j = NULL;
unsigned n = 0;
diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c
index 11fb150fe8..e6599f366d 100644
--- a/src/journal/test-journal-init.c
+++ b/src/journal/test-journal-init.c
@@ -23,6 +23,7 @@
#include "log.h"
#include "util.h"
+#include "rm-rf.h"
int main(int argc, char *argv[]) {
sd_journal *j;
@@ -58,7 +59,7 @@ int main(int argc, char *argv[]) {
assert_se(j == NULL);
}
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
return 0;
}
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index 3c706018e9..c2fc123e42 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -23,13 +23,12 @@
#include <unistd.h>
#include <fcntl.h>
-#include "systemd/sd-journal.h"
-
+#include "sd-journal.h"
#include "journal-file.h"
-#include "journal-internal.h"
#include "journal-vacuum.h"
#include "util.h"
#include "log.h"
+#include "rm-rf.h"
/* This program tests skipping around in a multi-file journal.
*/
@@ -191,7 +190,7 @@ static void test_skip(void (*setup)(void)) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
puts("------------------------------------------------------------");
@@ -276,7 +275,7 @@ static void test_sequence_numbers(void) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
}
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
index 3996e778e6..e1146c692d 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/journal/test-journal-stream.c
@@ -22,13 +22,13 @@
#include <unistd.h>
#include <fcntl.h>
-#include "systemd/sd-journal.h"
-
-#include "journal-file.h"
-#include "journal-internal.h"
+#include "sd-journal.h"
#include "util.h"
#include "log.h"
#include "macro.h"
+#include "rm-rf.h"
+#include "journal-file.h"
+#include "journal-internal.h"
#define N_ENTRIES 200
@@ -42,7 +42,7 @@ static void verify_contents(sd_journal *j, unsigned skip) {
const void *d;
char *k, *c;
size_t l;
- unsigned u;
+ unsigned u = 0;
assert_se(sd_journal_get_cursor(j, &k) >= 0);
printf("cursor: %s\n", k);
@@ -180,7 +180,7 @@ int main(int argc, char *argv[]) {
SD_JOURNAL_FOREACH_UNIQUE(j, data, l)
printf("%.*s\n", (int) l, (const char*) data);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
return 0;
}
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index 9da120c0bb..d24502d9a8 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -25,9 +25,10 @@
#include "util.h"
#include "log.h"
+#include "rm-rf.h"
#include "journal-file.h"
#include "journal-verify.h"
-#include "journal-authenticate.h"
+#include "terminal-util.h"
#define N_ENTRIES 6000
#define RANDOM_RANGE 77
@@ -145,7 +146,7 @@ int main(int argc, char *argv[]) {
log_info("Exiting...");
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
return 0;
}
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index 230d26596a..caaab258c9 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -22,9 +22,8 @@
#include <fcntl.h>
#include <unistd.h>
-#include "systemd/sd-journal.h"
-
#include "log.h"
+#include "rm-rf.h"
#include "journal-file.h"
#include "journal-authenticate.h"
#include "journal-vacuum.h"
@@ -119,7 +118,7 @@ static void test_non_empty(void) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
puts("------------------------------------------------------------");
@@ -158,7 +157,7 @@ static void test_empty(void) {
else {
journal_directory_vacuum(".", 3000000, 0, NULL, true);
- assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
+ assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
journal_file_close(f1);
diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c
index 3fcd77475d..3258b22702 100644
--- a/src/journal/test-mmap-cache.c
+++ b/src/journal/test-mmap-cache.c
@@ -24,7 +24,6 @@
#include <unistd.h>
#include <fcntl.h>
-#include "log.h"
#include "macro.h"
#include "util.h"
#include "mmap-cache.h"
diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install
index d433e00a5c..4c9b1f0327 100644
--- a/src/kernel-install/90-loaderentry.install
+++ b/src/kernel-install/90-loaderentry.install
@@ -43,14 +43,14 @@ fi
declare -a BOOT_OPTIONS
if [[ -f /etc/kernel/cmdline ]]; then
- readarray -t BOOT_OPTIONS < /etc/kernel/cmdline
+ read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline
fi
if ! [[ ${BOOT_OPTIONS[*]} ]]; then
- read -a line -r < /proc/cmdline
+ read -r -d '' -a line < /proc/cmdline
for i in "${line[@]}"; do
[[ "${i#initrd=*}" != "$i" ]] && continue
- BOOT_OPTIONS[${#BOOT_OPTIONS[@]}]="$i"
+ BOOT_OPTIONS+=("$i")
done
fi
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
index 419a450436..70c68ad131 100644
--- a/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libsystemd-network/dhcp-identifier.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/ethernet.h>
#include "sd-id128.h"
#include "libudev.h"
@@ -28,7 +27,6 @@
#include "virt.h"
#include "sparse-endian.h"
#include "siphash24.h"
-#include "util.h"
#include "dhcp6-protocol.h"
#include "dhcp-identifier.h"
@@ -48,8 +46,9 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
if (r < 0)
return r;
- duid->type = htobe16(DHCP6_DUID_EN);
- duid->en.pen = htobe32(SYSTEMD_PEN);
+ unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
+ unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
+
*len = sizeof(duid->type) + sizeof(duid->en);
/* a bit of snake-oil perhaps, but no need to expose the machine-id
@@ -60,7 +59,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
}
-int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id) {
+int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
/* name is a pointer to memory in the udev_device struct, so must
have the same scope */
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
@@ -94,7 +93,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t
siphash24((uint8_t*)&id, mac, mac_len, HASH_KEY.bytes);
/* fold into 32 bits */
- *_id = (id & 0xffffffff) ^ (id >> 32);
+ unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
return 0;
}
diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h
index 7f44d25499..95117915f4 100644
--- a/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libsystemd-network/dhcp-identifier.h
@@ -21,10 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/ethernet.h>
#include "macro.h"
#include "sparse-endian.h"
+#include "unaligned.h"
#include "sd-id128.h"
/* RFC 3315 section 9.1:
@@ -62,4 +62,4 @@ struct duid {
} _packed_;
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
-int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id);
+int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
index 5f2d2cfbfd..7f10838de1 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -18,7 +18,6 @@
***/
#include <errno.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/if_packet.h>
@@ -26,7 +25,6 @@
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <stdio.h>
-#include <unistd.h>
#include <linux/filter.h>
#include "socket-util.h"
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index 7581daeeeb..cd7f5095ca 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -18,22 +18,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <stdio.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
-#include <sys/param.h>
-#include "util.h"
-#include "list.h"
#include "dhcp-protocol.h"
-#include "dhcp-lease-internal.h"
#include "dhcp-internal.h"
-#include "sd-dhcp-lease.h"
-#include "sd-dhcp-client.h"
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c
index c6a989aac1..0f354461f7 100644
--- a/src/libsystemd-network/lldp-internal.c
+++ b/src/libsystemd-network/lldp-internal.c
@@ -54,14 +54,14 @@ int lldp_read_chassis_id(tlv_packet *tlv,
break;
default:
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
break;
}
*type = subtype;
out1:
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
out2:
return r;
@@ -106,14 +106,14 @@ int lldp_read_port_id(tlv_packet *tlv,
break;
default:
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
break;
}
*type = subtype;
out1:
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
out2:
return r;
@@ -130,7 +130,7 @@ int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
r = tlv_packet_read_u16(tlv, ttl);
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
out:
return r;
@@ -155,7 +155,7 @@ int lldp_read_system_name(tlv_packet *tlv,
*data = (char *) s;
out:
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
return r;
}
@@ -179,7 +179,7 @@ int lldp_read_system_description(tlv_packet *tlv,
*data = (char *) s;
out:
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
return r;
}
@@ -203,7 +203,7 @@ int lldp_read_port_description(tlv_packet *tlv,
*data = (char *) s;
out:
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
return r;
}
@@ -224,7 +224,7 @@ int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data) {
return 0;
out:
- (void)lldp_tlv_packet_exit_container(tlv);
+ (void) lldp_tlv_packet_exit_container(tlv);
return r;
}
diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c
index a2bc7d5518..664d2f7867 100644
--- a/src/libsystemd-network/lldp-network.c
+++ b/src/libsystemd-network/lldp-network.c
@@ -27,7 +27,6 @@
#include "lldp-tlv.h"
#include "lldp-network.h"
#include "lldp-internal.h"
-#include "sd-lldp.h"
int lldp_network_bind_raw_socket(int ifindex) {
typedef struct LLDPFrame {
diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c
index e43d70d3cf..e32783f3eb 100644
--- a/src/libsystemd-network/lldp-tlv.c
+++ b/src/libsystemd-network/lldp-tlv.c
@@ -156,7 +156,7 @@ static inline int tlv_packet_read_internal(tlv_section *m, void **data) {
}
int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) {
- void *val;
+ void *val = NULL;
int r;
assert_return(m, -EINVAL);
@@ -174,7 +174,7 @@ int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) {
int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) {
uint16_t t;
- void *val;
+ void *val = NULL;
int r;
assert_return(m, -EINVAL);
@@ -211,7 +211,7 @@ int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) {
}
int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
- void *val;
+ void *val = NULL;
int r;
assert_return(m, -EINVAL);
@@ -229,7 +229,7 @@ int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
}
int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) {
- void *val;
+ void *val = NULL;
int r;
assert_return(m, -EINVAL);
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index b8e4e21716..d579755cc8 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -25,7 +25,6 @@
#include "strv.h"
#include "siphash24.h"
-#include "libudev-private.h"
#include "dhcp-lease-internal.h"
#include "log.h"
#include "utf8.h"
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index e51717e919..06aba893ce 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -21,8 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
-#include <netinet/in.h>
#include <stdbool.h>
#include "udev.h"
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 5f90617b9e..0193e42d65 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -24,13 +24,11 @@
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <linux/if_infiniband.h>
-#include <netinet/ether.h>
-#include <sys/param.h>
#include <sys/ioctl.h>
#include "util.h"
-#include "list.h"
#include "refcnt.h"
+#include "random-util.h"
#include "async.h"
#include "dhcp-protocol.h"
@@ -40,7 +38,7 @@
#include "sd-dhcp-client.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
-#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
+#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
struct sd_dhcp_client {
RefCount n_ref;
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 34aa36c6e6..8a4220621b 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -22,22 +22,15 @@
#include <errno.h>
#include <string.h>
#include <stdio.h>
-#include <net/ethernet.h>
#include <arpa/inet.h>
-#include <sys/param.h>
-#include "util.h"
-#include "list.h"
-#include "mkdir.h"
#include "fileio.h"
#include "unaligned.h"
#include "in-addr-util.h"
-
+#include "hostname-util.h"
#include "dhcp-protocol.h"
-#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
#include "sd-dhcp-lease.h"
-#include "sd-dhcp-client.h"
#include "network-internal.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
@@ -679,7 +672,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r >= 0) {
_cleanup_free_ char *client_id_hex;
- client_id_hex = hexmem (client_id, client_id_len);
+ client_id_hex = hexmem(client_id, client_id_len);
if (!client_id_hex) {
r = -ENOMEM;
goto finish;
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 3f89f344d7..a0a2320efa 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -21,7 +21,6 @@
***/
#include <sys/ioctl.h>
-#include <netinet/if_ether.h>
#include "siphash24.h"
@@ -776,7 +775,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (pool_offset >= 0 &&
server->bound_leases[pool_offset] == existing_lease) {
DHCPLease *lease;
- usec_t time_now;
+ usec_t time_now = 0;
if (!existing_lease) {
lease = new0(DHCPLease, 1);
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index a432bbfc48..85162dc555 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -28,6 +28,7 @@
#include "udev-util.h"
#include "util.h"
#include "refcnt.h"
+#include "random-util.h"
#include "network-internal.h"
#include "sd-dhcp6-client.h"
@@ -158,6 +159,13 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
return 0;
}
+static int client_ensure_duid(sd_dhcp6_client *client)
+{
+ if (client->duid_len != 0)
+ return 0;
+ return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
+}
+
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
size_t duid_len)
{
@@ -378,6 +386,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (r < 0)
return r;
+ assert (client->duid_len);
r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
client->duid_len, &client->duid);
if (r < 0)
@@ -1108,6 +1117,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
if (r < 0)
return r;
+ r = client_ensure_duid(client);
+ if (r < 0)
+ return r;
+
r = dhcp6_network_bind_udp_socket(client->index, NULL);
if (r < 0)
return r;
@@ -1192,6 +1205,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
client_reset(client);
sd_dhcp6_client_detach_event(client);
+ sd_dhcp6_lease_unref(client->lease);
free(client->req_opts);
free(client);
@@ -1205,7 +1219,6 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
int sd_dhcp6_client_new(sd_dhcp6_client **ret)
{
_cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
- int r;
size_t t;
assert_return(ret, -EINVAL);
@@ -1222,11 +1235,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
client->fd = -1;
- /* initialize DUID */
- r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
- if (r < 0)
- return r;
-
client->req_opts_len = ELEMENTSOF(default_req_opts);
client->req_opts = new0(be16_t, client->req_opts_len);
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 02f2f9e0a9..9e04db96bb 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -27,6 +27,7 @@
#include "siphash24.h"
#include "list.h"
#include "refcnt.h"
+#include "random-util.h"
#include "ipv4ll-internal.h"
#include "sd-ipv4ll.h"
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 19ef2ccdbd..fddda97f52 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -24,16 +24,13 @@
#include "siphash24.h"
#include "hashmap.h"
-#include "event-util.h"
#include "lldp-tlv.h"
#include "lldp-port.h"
#include "sd-lldp.h"
#include "prioq.h"
-#include "strv.h"
#include "lldp-internal.h"
#include "lldp-util.h"
-#include "ether-addr-util.h"
typedef enum LLDPAgentRXState {
LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
@@ -522,7 +519,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
free(s);
s = k;
- (void)lldp_read_system_capability(p->packet, &data);
+ (void) lldp_read_system_capability(p->packet, &data);
sprintf(buf, "'_CAP=%x'", data);
diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c
index 4f49b799ec..1de8a5e8bf 100644
--- a/src/libsystemd-network/sd-pppoe.c
+++ b/src/libsystemd-network/sd-pppoe.c
@@ -33,10 +33,10 @@
#include "event-util.h"
#include "util.h"
+#include "random-util.h"
#include "socket-util.h"
#include "async.h"
#include "refcnt.h"
-#include "unaligned.h"
#include "utf8.h"
#define PPPOE_MAX_PACKET_SIZE 1484
@@ -340,7 +340,7 @@ static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata);
static int pppoe_arm_timeout(sd_pppoe *ppp) {
_cleanup_event_source_unref_ sd_event_source *timeout = NULL;
- usec_t next_timeout;
+ usec_t next_timeout = 0;
int r;
assert(ppp);
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index 8e88641430..d341210887 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -19,16 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <assert.h>
#include <errno.h>
#include <stdio.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include "util.h"
-#include "socket-util.h"
#include "sd-event.h"
#include "event-util.h"
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 46c8c27061..a63a4ea738 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -1,9 +1,9 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
-#include <assert.h>
#include "util.h"
#include "macro.h"
@@ -51,8 +51,7 @@ static struct option_desc option_tests[] = {
DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, },
};
-static const char *dhcp_type(int type)
-{
+static const char *dhcp_type(int type) {
switch(type) {
case DHCP_DISCOVER:
return "DHCPDISCOVER";
@@ -73,8 +72,7 @@ static const char *dhcp_type(int type)
}
}
-static void test_invalid_buffer_length(void)
-{
+static void test_invalid_buffer_length(void) {
DHCPMessage message;
assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL);
@@ -82,8 +80,7 @@ static void test_invalid_buffer_length(void)
== -EINVAL);
}
-static void test_message_init(void)
-{
+static void test_message_init(void) {
_cleanup_free_ DHCPMessage *message = NULL;
size_t optlen = 4, optoffset;
size_t len = sizeof(DHCPMessage) + optlen;
@@ -109,8 +106,7 @@ static void test_message_init(void)
static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
uint8_t *file, uint8_t filelen,
- uint8_t *sname, uint8_t snamelen)
-{
+ uint8_t *sname, uint8_t snamelen) {
DHCPMessage *message;
size_t len = sizeof(DHCPMessage) + optlen;
@@ -129,8 +125,9 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
return message;
}
-static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen)
-{
+static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) {
+ assert(*descpos >= 0);
+
while (*descpos < *desclen) {
switch(descoption[*descpos]) {
case DHCP_OPTION_PAD:
@@ -148,9 +145,7 @@ static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen)
}
}
-static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option,
- void *user_data)
-{
+static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option, void *user_data) {
struct option_desc *desc = user_data;
uint8_t *descoption = NULL;
int *desclen = NULL, *descpos = NULL;
@@ -237,8 +232,7 @@ static int test_options_cb(uint8_t code, uint8_t len, const uint8_t *option,
return 0;
}
-static void test_options(struct option_desc *desc)
-{
+static void test_options(struct option_desc *desc) {
uint8_t *options = NULL;
uint8_t *file = NULL;
uint8_t *sname = NULL;
@@ -299,8 +293,7 @@ static uint8_t options[64] = {
255
};
-static void test_option_set(void)
-{
+static void test_option_set(void) {
_cleanup_free_ DHCPMessage *result = NULL;
size_t offset = 0, len, pos;
unsigned i;
@@ -372,9 +365,8 @@ static void test_option_set(void)
printf ("\n");
}
-int main(int argc, char *argv[])
-{
- unsigned int i;
+int main(int argc, char *argv[]) {
+ unsigned i;
test_invalid_buffer_length();
test_message_init();
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 3e68f310f3..9f60ab761e 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -20,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/if_ether.h>
-#include <assert.h>
#include <errno.h>
#include "sd-event.h"
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index 9386f31ce4..761854714b 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -701,7 +701,5 @@ int main(int argc, char *argv[]) {
test_advertise_option(e);
test_client_solicit(e);
- assert_se(!sd_event_unref(e));
-
return 0;
}
diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c
index 459d5c324d..5677bfb2d2 100644
--- a/src/libsystemd-network/test-ipv4ll.c
+++ b/src/libsystemd-network/test-ipv4ll.c
@@ -28,6 +28,7 @@
#include "util.h"
#include "socket-util.h"
+#include "event-util.h"
#include "sd-ipv4ll.h"
#include "ipv4ll-internal.h"
@@ -212,7 +213,7 @@ static void test_basic_request(sd_event *e) {
}
int main(int argc, char *argv[]) {
- sd_event *e;
+ _cleanup_event_unref_ sd_event *e = NULL;
assert_se(sd_event_new(&e) >= 0);
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index ee74ebd418..06545aee59 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -21,13 +21,8 @@
***/
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/socket.h>
-#include <linux/if.h>
-#include <linux/if_ether.h>
#include <net/ethernet.h>
-#include <sys/types.h>
#include <arpa/inet.h>
#include "macro.h"
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
index dff83eaf6e..9c8d6f7779 100644
--- a/src/libsystemd-network/test-pppoe.c
+++ b/src/libsystemd-network/test-pppoe.c
@@ -20,23 +20,18 @@
***/
#include <stdlib.h>
-#include <assert.h>
#include <errno.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
#include <unistd.h>
#include <linux/veth.h>
#include <net/if.h>
#include "util.h"
-#include "socket-util.h"
#include "sd-event.h"
#include "event-util.h"
#include "sd-rtnl.h"
-#include "rtnl-util.h"
#include "sd-pppoe.h"
+#include "process-util.h"
static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) {
static int pppoe_state = -1;
diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c
index f4c25b5556..bfa166c489 100644
--- a/src/libsystemd-terminal/evcat.c
+++ b/src/libsystemd-terminal/evcat.c
@@ -26,33 +26,29 @@
* problems.
*/
-#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <libevdev/libevdev.h>
#include <linux/kd.h>
-#include <linux/vt.h>
-#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <systemd/sd-login.h>
#include <termios.h>
#include <unistd.h>
#include <xkbcommon/xkbcommon.h>
+#include "sd-bus.h"
+#include "sd-event.h"
+#include "sd-login.h"
#include "build.h"
-#include "bus-util.h"
#include "event-util.h"
-#include "idev.h"
#include "macro.h"
+#include "signal-util.h"
+#include "util.h"
+#include "idev.h"
#include "sysview.h"
#include "term-internal.h"
-#include "util.h"
typedef struct Evcat Evcat;
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
index bc4d4c9e76..4cee95f469 100644
--- a/src/libsystemd-terminal/grdev-drm.c
+++ b/src/libsystemd-terminal/grdev-drm.c
@@ -27,8 +27,6 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
#include <unistd.h>
/* Yuck! DRM headers need system headers included first.. but we have to
@@ -37,13 +35,14 @@
#include <drm_fourcc.h>
#include <drm_mode.h>
-#include "bus-util.h"
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
-#include "grdev.h"
-#include "grdev-internal.h"
#include "macro.h"
-#include "udev-util.h"
#include "util.h"
+#include "bus-util.h"
+#include "grdev.h"
+#include "grdev-internal.h"
#define GRDRM_MAX_TRIES (16)
@@ -2656,8 +2655,7 @@ static void managed_card_disable(grdev_card *card) {
grdrm_card_disable(&cm->card);
}
-static int managed_card_pause_device_fn(sd_bus *bus,
- sd_bus_message *signal,
+static int managed_card_pause_device_fn(sd_bus_message *signal,
void *userdata,
sd_bus_error *ret_error) {
managed_card *cm = userdata;
@@ -2745,8 +2743,7 @@ static int managed_card_pause_device_fn(sd_bus *bus,
return 0;
}
-static int managed_card_resume_device_fn(sd_bus *bus,
- sd_bus_message *signal,
+static int managed_card_resume_device_fn(sd_bus_message *signal,
void *userdata,
sd_bus_error *ret_error) {
managed_card *cm = userdata;
@@ -2848,8 +2845,7 @@ static int managed_card_setup_bus(managed_card *cm) {
return 0;
}
-static int managed_card_take_device_fn(sd_bus *bus,
- sd_bus_message *reply,
+static int managed_card_take_device_fn(sd_bus_message *reply,
void *userdata,
sd_bus_error *ret_error) {
managed_card *cm = userdata;
diff --git a/src/libsystemd-terminal/grdev-internal.h b/src/libsystemd-terminal/grdev-internal.h
index f455dd4172..46d65f0248 100644
--- a/src/libsystemd-terminal/grdev-internal.h
+++ b/src/libsystemd-terminal/grdev-internal.h
@@ -25,12 +25,12 @@
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "grdev.h"
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
#include "list.h"
#include "util.h"
+#include "grdev.h"
typedef struct grdev_tile grdev_tile;
typedef struct grdev_display_cache grdev_display_cache;
diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c
index 3b3cf2737b..c386e65982 100644
--- a/src/libsystemd-terminal/grdev.c
+++ b/src/libsystemd-terminal/grdev.c
@@ -19,20 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <systemd/sd-login.h>
-#include "grdev.h"
-#include "grdev-internal.h"
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
#include "login-shared.h"
#include "macro.h"
-#include "udev-util.h"
#include "util.h"
+#include "grdev.h"
+#include "grdev-internal.h"
static void pipe_enable(grdev_pipe *pipe);
static void pipe_disable(grdev_pipe *pipe);
diff --git a/src/libsystemd-terminal/grdev.h b/src/libsystemd-terminal/grdev.h
index 35d6eb2abf..110d24e6d5 100644
--- a/src/libsystemd-terminal/grdev.h
+++ b/src/libsystemd-terminal/grdev.h
@@ -53,13 +53,11 @@
#pragma once
-#include <drm_fourcc.h>
-#include <inttypes.h>
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
+#include "sd-bus.h"
+#include "sd-event.h"
#include "util.h"
typedef struct grdev_fb grdev_fb;
diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c
index dfbb2d197f..f1a18b91d3 100644
--- a/src/libsystemd-terminal/idev-evdev.c
+++ b/src/libsystemd-terminal/idev-evdev.c
@@ -20,21 +20,17 @@
***/
#include <fcntl.h>
-#include <inttypes.h>
#include <libevdev/libevdev.h>
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <unistd.h>
+#include "sd-bus.h"
+#include "sd-event.h"
+#include "macro.h"
+#include "util.h"
#include "bus-util.h"
-#include "hashmap.h"
#include "idev.h"
#include "idev-internal.h"
-#include "macro.h"
-#include "udev-util.h"
-#include "util.h"
typedef struct idev_evdev idev_evdev;
typedef struct unmanaged_evdev unmanaged_evdev;
@@ -531,8 +527,7 @@ static const idev_element_vtable unmanaged_evdev_vtable = {
* you run inside a user session with exclusive device access.
*/
-static int managed_evdev_take_device_fn(sd_bus *bus,
- sd_bus_message *reply,
+static int managed_evdev_take_device_fn(sd_bus_message *reply,
void *userdata,
sd_bus_error *ret_error) {
managed_evdev *em = userdata;
diff --git a/src/libsystemd-terminal/idev-internal.h b/src/libsystemd-terminal/idev-internal.h
index a159aef211..a02a16c408 100644
--- a/src/libsystemd-terminal/idev-internal.h
+++ b/src/libsystemd-terminal/idev-internal.h
@@ -26,13 +26,13 @@
#include <linux/input.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
#include <xkbcommon/xkbcommon.h>
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
-#include "idev.h"
#include "list.h"
#include "util.h"
+#include "idev.h"
typedef struct idev_link idev_link;
typedef struct idev_device_vtable idev_device_vtable;
diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c
index 6ee3d8150c..93f49e9458 100644
--- a/src/libsystemd-terminal/idev-keyboard.c
+++ b/src/libsystemd-terminal/idev-keyboard.c
@@ -19,20 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
-#include "bus-util.h"
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
+#include "macro.h"
+#include "util.h"
+#include "bus-util.h"
#include "idev.h"
#include "idev-internal.h"
-#include "macro.h"
#include "term-internal.h"
-#include "util.h"
typedef struct kbdtbl kbdtbl;
typedef struct kbdmap kbdmap;
@@ -385,10 +384,10 @@ static const struct bus_properties_map kbdctx_locale_map[] = {
{ "X11Layout", "s", NULL, offsetof(kbdctx, locale_x11_layout) },
{ "X11Variant", "s", NULL, offsetof(kbdctx, locale_x11_variant) },
{ "X11Options", "s", NULL, offsetof(kbdctx, locale_x11_options) },
+ { },
};
-static int kbdctx_locale_get_all_fn(sd_bus *bus,
- sd_bus_message *m,
+static int kbdctx_locale_get_all_fn(sd_bus_message *m,
void *userdata,
sd_bus_error *ret_err) {
kbdctx *kc = userdata;
@@ -404,7 +403,7 @@ static int kbdctx_locale_get_all_fn(sd_bus *bus,
return 0;
}
- r = bus_message_map_all_properties(bus, m, kbdctx_locale_map, kc);
+ r = bus_message_map_all_properties(m, kbdctx_locale_map, kc);
if (r < 0) {
log_debug("idev-keyboard: erroneous GetAll() reply from locale1");
return 0;
@@ -448,8 +447,7 @@ error:
return log_debug_errno(r, "idev-keyboard: cannot send GetAll to locale1: %m");
}
-static int kbdctx_locale_props_changed_fn(sd_bus *bus,
- sd_bus_message *signal,
+static int kbdctx_locale_props_changed_fn(sd_bus_message *signal,
void *userdata,
sd_bus_error *ret_err) {
kbdctx *kc = userdata;
@@ -462,7 +460,7 @@ static int kbdctx_locale_props_changed_fn(sd_bus *bus,
if (r < 0)
goto error;
- r = bus_message_map_properties_changed(bus, signal, kbdctx_locale_map, kc);
+ r = bus_message_map_properties_changed(signal, kbdctx_locale_map, kc);
if (r < 0)
goto error;
@@ -507,12 +505,9 @@ static void kbdctx_log_fn(struct xkb_context *ctx, enum xkb_log_level lvl, const
sd_lvl = LOG_INFO;
else if (lvl >= XKB_LOG_LEVEL_WARNING)
sd_lvl = LOG_INFO; /* most XKB warnings really are informational */
- else if (lvl >= XKB_LOG_LEVEL_ERROR)
- sd_lvl = LOG_ERR;
- else if (lvl >= XKB_LOG_LEVEL_CRITICAL)
- sd_lvl = LOG_CRIT;
else
- sd_lvl = LOG_CRIT;
+ /* XKB_LOG_LEVEL_ERROR and worse */
+ sd_lvl = LOG_ERR;
snprintf(buf, sizeof(buf), "idev-xkb: %s", format);
log_internalv(sd_lvl, 0, __FILE__, __LINE__, __func__, buf, args);
diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c
index 989683f39a..b187934977 100644
--- a/src/libsystemd-terminal/idev.c
+++ b/src/libsystemd-terminal/idev.c
@@ -19,22 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <libudev.h>
-#include <linux/input.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <systemd/sd-login.h>
-#include <xkbcommon/xkbcommon.h>
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
-#include "idev.h"
-#include "idev-internal.h"
#include "login-shared.h"
#include "macro.h"
-#include "udev-util.h"
#include "util.h"
+#include "idev.h"
+#include "idev-internal.h"
static void element_open(idev_element *e);
static void element_close(idev_element *e);
@@ -433,8 +428,7 @@ idev_session *idev_find_session(idev_context *c, const char *name) {
return hashmap_get(c->session_map, name);
}
-static int session_resume_device_fn(sd_bus *bus,
- sd_bus_message *signal,
+static int session_resume_device_fn(sd_bus_message *signal,
void *userdata,
sd_bus_error *ret_error) {
idev_session *s = userdata;
@@ -456,8 +450,7 @@ static int session_resume_device_fn(sd_bus *bus,
return 0;
}
-static int session_pause_device_fn(sd_bus *bus,
- sd_bus_message *signal,
+static int session_pause_device_fn(sd_bus_message *signal,
void *userdata,
sd_bus_error *ret_error) {
idev_session *s = userdata;
diff --git a/src/libsystemd-terminal/idev.h b/src/libsystemd-terminal/idev.h
index c8c03f3d41..241677cbbe 100644
--- a/src/libsystemd-terminal/idev.h
+++ b/src/libsystemd-terminal/idev.h
@@ -25,15 +25,12 @@
#pragma once
-#include <inttypes.h>
#include <libudev.h>
#include <linux/input.h>
#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
#include <xkbcommon/xkbcommon.h>
-#include "util.h"
+#include "sd-bus.h"
+#include "sd-event.h"
typedef struct idev_data idev_data;
typedef struct idev_data_evdev idev_data_evdev;
diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c
index 6e13432d68..f3a60e1fb0 100644
--- a/src/libsystemd-terminal/modeset.c
+++ b/src/libsystemd-terminal/modeset.c
@@ -30,26 +30,23 @@
#include <errno.h>
#include <getopt.h>
#include <linux/kd.h>
-#include <linux/vt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <systemd/sd-login.h>
#include <termios.h>
#include <unistd.h>
+#include "sd-bus.h"
+#include "sd-event.h"
+#include "sd-login.h"
#include "build.h"
-#include "bus-util.h"
-#include "event-util.h"
-#include "grdev.h"
-#include "grdev-internal.h"
#include "macro.h"
-#include "sysview.h"
+#include "random-util.h"
+#include "signal-util.h"
#include "util.h"
+#include "grdev.h"
+#include "sysview.h"
typedef struct Modeset Modeset;
diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c
index 63cd2a5ad6..d10e2f549f 100644
--- a/src/libsystemd-terminal/subterm.c
+++ b/src/libsystemd-terminal/subterm.c
@@ -26,7 +26,6 @@
* parent TTY. Think of this like what "GNU-screen" does.
*/
-#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -35,13 +34,14 @@
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
+#include "sd-event.h"
#include "macro.h"
#include "pty.h"
#include "ring.h"
-#include "sd-event.h"
-#include "term-internal.h"
-#include "util.h"
+#include "signal-util.h"
#include "utf8.h"
+#include "util.h"
+#include "term-internal.h"
typedef struct Output Output;
typedef struct Terminal Terminal;
diff --git a/src/libsystemd-terminal/sysview-internal.h b/src/libsystemd-terminal/sysview-internal.h
index 39ff933eaa..251c8d7300 100644
--- a/src/libsystemd-terminal/sysview-internal.h
+++ b/src/libsystemd-terminal/sysview-internal.h
@@ -25,13 +25,13 @@
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
+#include "sd-bus.h"
+#include "sd-event.h"
#include "hashmap.h"
#include "list.h"
#include "macro.h"
-#include "sysview.h"
#include "util.h"
+#include "sysview.h"
/*
* Devices
@@ -113,6 +113,7 @@ struct sysview_context {
sd_bus *sysbus;
struct udev *ud;
uint64_t custom_sid;
+ unsigned int n_probe;
Hashmap *seat_map;
Hashmap *session_map;
@@ -137,6 +138,7 @@ struct sysview_context {
bool running : 1;
bool scanned : 1;
bool rescan : 1;
+ bool settled : 1;
};
int sysview_context_rescan(sysview_context *c);
diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c
index 9ee32db1bc..2e9b15859a 100644
--- a/src/libsystemd-terminal/sysview.c
+++ b/src/libsystemd-terminal/sysview.c
@@ -23,17 +23,15 @@
#include <libudev.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include <systemd/sd-login.h>
-#include "bus-util.h"
-#include "event-util.h"
+#include "sd-bus.h"
+#include "sd-event.h"
+#include "sd-login.h"
#include "macro.h"
-#include "set.h"
-#include "sysview.h"
-#include "sysview-internal.h"
#include "udev-util.h"
#include "util.h"
+#include "bus-util.h"
+#include "sysview.h"
+#include "sysview-internal.h"
static int context_raise_session_control(sysview_context *c, sysview_session *session, int error);
@@ -198,7 +196,7 @@ int sysview_session_new(sysview_session **out, sysview_seat *seat, const char *n
if (r < 0)
return r;
- session->custom = false;;
+ session->custom = false;
} else {
/*
* No session name was given. We assume this is an unmanaged
@@ -273,8 +271,7 @@ sysview_seat *sysview_session_get_seat(sysview_session *session) {
return session->seat;
}
-static int session_take_control_fn(sd_bus *bus,
- sd_bus_message *reply,
+static int session_take_control_fn(sd_bus_message *reply,
void *userdata,
sd_bus_error *ret_error) {
sysview_session *session = userdata;
@@ -476,6 +473,14 @@ static int context_raise(sysview_context *c, sysview_event *event, int def) {
return c->running ? c->event_fn(c, c->userdata, event) : def;
}
+static int context_raise_settle(sysview_context *c) {
+ sysview_event event = {
+ .type = SYSVIEW_EVENT_SETTLE,
+ };
+
+ return context_raise(c, &event, 0);
+}
+
static int context_raise_seat_add(sysview_context *c, sysview_seat *seat) {
sysview_event event = {
.type = SYSVIEW_EVENT_SEAT_ADD,
@@ -587,6 +592,21 @@ static int context_raise_session_refresh(sysview_context *c, sysview_session *se
return context_raise(c, &event, 0);
}
+static void context_settle(sysview_context *c) {
+ int r;
+
+ if (c->n_probe <= 0 || --c->n_probe > 0)
+ return;
+
+ log_debug("sysview: settle");
+
+ c->settled = true;
+
+ r = context_raise_settle(c);
+ if (r < 0)
+ log_debug_errno(r, "sysview: callback failed on settle: %m");
+}
+
static void context_add_device(sysview_context *c, sysview_device *device) {
sysview_session *session;
Iterator i;
@@ -1195,8 +1215,7 @@ static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal
return 0;
}
-static int context_ld_manager_signal_fn(sd_bus *bus,
- sd_bus_message *signal,
+static int context_ld_manager_signal_fn(sd_bus_message *signal,
void *userdata,
sd_bus_error *ret_error) {
sysview_context *c = userdata;
@@ -1239,8 +1258,7 @@ static void context_ld_stop(sysview_context *c) {
c->ld_slot_manager_signal = sd_bus_slot_unref(c->ld_slot_manager_signal);
}
-static int context_ld_list_seats_fn(sd_bus *bus,
- sd_bus_message *reply,
+static int context_ld_list_seats_fn(sd_bus_message *reply,
void *userdata,
sd_bus_error *ret_error) {
sysview_context *c = userdata;
@@ -1253,7 +1271,8 @@ static int context_ld_list_seats_fn(sd_bus *bus,
log_debug("sysview: ListSeats on logind failed: %s: %s",
error->name, error->message);
- return -sd_bus_error_get_errno(error);
+ r = -sd_bus_error_get_errno(error);
+ goto settle;
}
r = sd_bus_message_enter_container(reply, 'a', "(so)");
@@ -1279,16 +1298,19 @@ static int context_ld_list_seats_fn(sd_bus *bus,
r = sd_bus_message_exit_container(reply);
if (r < 0)
- return r;
+ goto error;
- return 0;
+ r = 0;
+ goto settle;
error:
- return log_debug_errno(r, "sysview: erroneous ListSeats response from logind: %m");
+ log_debug_errno(r, "sysview: erroneous ListSeats response from logind: %m");
+settle:
+ context_settle(c);
+ return r;
}
-static int context_ld_list_sessions_fn(sd_bus *bus,
- sd_bus_message *reply,
+static int context_ld_list_sessions_fn(sd_bus_message *reply,
void *userdata,
sd_bus_error *ret_error) {
sysview_context *c = userdata;
@@ -1301,7 +1323,8 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
log_debug("sysview: ListSessions on logind failed: %s: %s",
error->name, error->message);
- return -sd_bus_error_get_errno(error);
+ r = -sd_bus_error_get_errno(error);
+ goto settle;
}
r = sd_bus_message_enter_container(reply, 'a', "(susso)");
@@ -1343,12 +1366,16 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
r = sd_bus_message_exit_container(reply);
if (r < 0)
- return r;
+ goto error;
- return 0;
+ r = 0;
+ goto settle;
error:
- return log_debug_errno(r, "sysview: erroneous ListSessions response from logind: %m");
+ log_debug_errno(r, "sysview: erroneous ListSessions response from logind: %m");
+settle:
+ context_settle(c);
+ return r;
}
static int context_ld_scan(sysview_context *c) {
@@ -1378,6 +1405,9 @@ static int context_ld_scan(sysview_context *c) {
if (r < 0)
return r;
+ if (!c->settled)
+ ++c->n_probe;
+
/* request session list */
m = sd_bus_message_unref(m);
@@ -1399,6 +1429,9 @@ static int context_ld_scan(sysview_context *c) {
if (r < 0)
return r;
+ if (!c->settled)
+ ++c->n_probe;
+
return 0;
}
@@ -1463,6 +1496,8 @@ void sysview_context_stop(sysview_context *c) {
c->running = false;
c->scanned = false;
+ c->settled = false;
+ c->n_probe = 0;
c->event_fn = NULL;
c->userdata = NULL;
c->scan_src = sd_event_source_unref(c->scan_src);
@@ -1476,6 +1511,8 @@ static int context_scan_fn(sd_event_source *s, void *userdata) {
Iterator i;
int r;
+ c->rescan = false;
+
if (!c->scanned) {
r = context_ld_scan(c);
if (r < 0)
@@ -1493,6 +1530,7 @@ static int context_scan_fn(sd_event_source *s, void *userdata) {
}
c->scanned = true;
+ context_settle(c);
return 0;
}
@@ -1503,6 +1541,12 @@ int sysview_context_rescan(sysview_context *c) {
if (!c->running)
return 0;
+ if (!c->rescan) {
+ c->rescan = true;
+ if (!c->settled)
+ ++c->n_probe;
+ }
+
if (c->scan_src)
return sd_event_source_set_enabled(c->scan_src, SD_EVENT_ONESHOT);
else
diff --git a/src/libsystemd-terminal/sysview.h b/src/libsystemd-terminal/sysview.h
index cad603d59f..a5e7a38df3 100644
--- a/src/libsystemd-terminal/sysview.h
+++ b/src/libsystemd-terminal/sysview.h
@@ -36,13 +36,9 @@
#pragma once
-#include <inttypes.h>
-#include <libudev.h>
#include <stdbool.h>
-#include <stdlib.h>
-#include <systemd/sd-bus.h>
-#include <systemd/sd-event.h>
-#include "util.h"
+#include "sd-bus.h"
+#include "sd-event.h"
typedef struct sysview_event sysview_event;
typedef struct sysview_device sysview_device;
@@ -55,6 +51,8 @@ typedef struct sysview_context sysview_context;
*/
enum {
+ SYSVIEW_EVENT_SETTLE,
+
SYSVIEW_EVENT_SEAT_ADD,
SYSVIEW_EVENT_SEAT_REMOVE,
diff --git a/src/libsystemd-terminal/term-charset.c b/src/libsystemd-terminal/term-charset.c
index a00a1912da..9db178861c 100644
--- a/src/libsystemd-terminal/term-charset.c
+++ b/src/libsystemd-terminal/term-charset.c
@@ -60,9 +60,6 @@
* include them. The mapper has to take care not to use them in GL.
*/
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
#include "term-internal.h"
/*
diff --git a/src/libsystemd-terminal/term-page.c b/src/libsystemd-terminal/term-page.c
index ae73cdf627..bac85200f1 100644
--- a/src/libsystemd-terminal/term-page.c
+++ b/src/libsystemd-terminal/term-page.c
@@ -75,7 +75,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
-#include <wchar.h>
#include "macro.h"
#include "term-internal.h"
#include "util.h"
@@ -799,11 +798,9 @@ static inline void line_insert(term_line *line, unsigned int from, unsigned int
age);
/* adjust fill-state */
- DISABLE_WARNING_SHADOW;
line->fill = MIN(line->width,
MAX(line->fill + num,
from + num));
- REENABLE_WARNING;
} else {
/* modify head-cell */
term_cell_set(line->cells + from,
@@ -872,11 +869,9 @@ void term_line_write(term_line *line, unsigned int pos_x, term_char_t ch, unsign
age);
/* adjust fill-state */
- DISABLE_WARNING_SHADOW;
line->fill = MIN(line->width,
MAX(line->fill,
pos_x + len));
- REENABLE_WARNING;
}
}
diff --git a/src/libsystemd-terminal/term-wcwidth.c b/src/libsystemd-terminal/term-wcwidth.c
index df20a40451..833a099bd7 100644
--- a/src/libsystemd-terminal/term-wcwidth.c
+++ b/src/libsystemd-terminal/term-wcwidth.c
@@ -62,7 +62,6 @@
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
-#include <wchar.h>
#include "term-internal.h"
struct interval {
diff --git a/src/libsystemd-terminal/test-term-page.c b/src/libsystemd-terminal/test-term-page.c
index 9e338776e8..d59139b62d 100644
--- a/src/libsystemd-terminal/test-term-page.c
+++ b/src/libsystemd-terminal/test-term-page.c
@@ -25,14 +25,10 @@
* those internals are changed. They should be fairly obvious, though.
*/
-#include <assert.h>
-#include <errno.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
#include "macro.h"
#include "term-internal.h"
-#include "util.h"
#define MY_ASSERT_VALS __FILE__, __LINE__, __PRETTY_FUNCTION__
#define MY_ASSERT_FORW _FILE, _LINE, _FUNC
diff --git a/src/libsystemd-terminal/test-term-parser.c b/src/libsystemd-terminal/test-term-parser.c
index e22614d06d..e40b267b1c 100644
--- a/src/libsystemd-terminal/test-term-parser.c
+++ b/src/libsystemd-terminal/test-term-parser.c
@@ -22,14 +22,10 @@
* Terminal Parser Tests
*/
-#include <assert.h>
-#include <errno.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
#include "macro.h"
#include "term-internal.h"
-#include "util.h"
#include "utf8.h"
static void test_term_utf8_invalid(void) {
diff --git a/src/libsystemd-terminal/test-unifont.c b/src/libsystemd-terminal/test-unifont.c
index cfeef61a47..2366d38574 100644
--- a/src/libsystemd-terminal/test-unifont.c
+++ b/src/libsystemd-terminal/test-unifont.c
@@ -24,14 +24,11 @@
* The glyphs are then compared to hard-coded glyphs.
*/
-#include <errno.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
#include "macro.h"
#include "unifont-def.h"
#include "unifont.h"
-#include "util.h"
static void render(char *w, const unifont_glyph *g) {
unsigned int i, j;
diff --git a/src/libsystemd-terminal/unifont.c b/src/libsystemd-terminal/unifont.c
index 2acfa9821a..0da81e8ff2 100644
--- a/src/libsystemd-terminal/unifont.c
+++ b/src/libsystemd-terminal/unifont.c
@@ -28,13 +28,10 @@
#include <endian.h>
#include <fcntl.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
#include "macro.h"
#include "unifont-def.h"
#include "unifont.h"
diff --git a/src/libsystemd-terminal/unifont.h b/src/libsystemd-terminal/unifont.h
index 30527cb3fa..74ee5ecb3c 100644
--- a/src/libsystemd-terminal/unifont.h
+++ b/src/libsystemd-terminal/unifont.h
@@ -21,10 +21,7 @@
#pragma once
-#include <stdbool.h>
#include <stdint.h>
-#include <stdlib.h>
-#include "util.h"
typedef struct unifont unifont;
typedef struct unifont_glyph unifont_glyph;
diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4
index 76a8c921c6..0b94a87dd6 100644
--- a/src/libsystemd/libsystemd.sym.m4
+++ b/src/libsystemd/libsystemd.sym.m4
@@ -63,7 +63,7 @@ global:
sd_journal_open_files;
sd_journal_open_container;
- /* sd-dameon */
+ /* sd-daemon */
sd_booted;
sd_is_fifo;
sd_is_mq;
@@ -163,8 +163,13 @@ global:
sd_pid_notify_with_fds;
} LIBSYSTEMD_217;
-m4_ifdef(`ENABLE_KDBUS',
-LIBSYSTEMD_FUTURE {
+LIBSYSTEMD_220 {
+global:
+ sd_pid_get_user_slice;
+ sd_peer_get_user_slice;
+} LIBSYSTEMD_219;
+
+LIBSYSTEMD_221 {
global:
/* sd-bus */
sd_bus_default;
@@ -179,25 +184,36 @@ global:
sd_bus_set_address;
sd_bus_set_fd;
sd_bus_set_exec;
+ sd_bus_get_address;
sd_bus_set_bus_client;
+ sd_bus_is_bus_client;
sd_bus_set_server;
+ sd_bus_is_server;
sd_bus_set_anonymous;
+ sd_bus_is_anonymous;
sd_bus_set_trusted;
+ sd_bus_is_trusted;
sd_bus_set_monitor;
+ sd_bus_is_monitor;
sd_bus_set_description;
- sd_bus_negotiate_fds;
- sd_bus_negotiate_timestamp;
+ sd_bus_get_description;
sd_bus_negotiate_creds;
+ sd_bus_negotiate_timestamp;
+ sd_bus_negotiate_fds;
+ sd_bus_can_send;
+ sd_bus_get_creds_mask;
+ sd_bus_set_allow_interactive_authorization;
+ sd_bus_get_allow_interactive_authorization;
sd_bus_start;
sd_bus_close;
sd_bus_try_close;
sd_bus_ref;
sd_bus_unref;
sd_bus_is_open;
- sd_bus_can_send;
sd_bus_get_bus_id;
+ sd_bus_get_scope;
+ sd_bus_get_tid;
sd_bus_get_owner_creds;
- sd_bus_get_description;
sd_bus_send;
sd_bus_send_to;
sd_bus_call;
@@ -209,9 +225,10 @@ global:
sd_bus_process_priority;
sd_bus_wait;
sd_bus_flush;
- sd_bus_get_current_message;
sd_bus_get_current_slot;
- sd_bus_get_tid;
+ sd_bus_get_current_message;
+ sd_bus_get_current_handler;
+ sd_bus_get_current_userdata;
sd_bus_attach_event;
sd_bus_detach_event;
sd_bus_get_event;
@@ -231,6 +248,8 @@ global:
sd_bus_slot_get_description;
sd_bus_slot_set_description;
sd_bus_slot_get_current_message;
+ sd_bus_slot_get_current_handler;
+ sd_bus_slot_get_current_userdata;
sd_bus_message_new_signal;
sd_bus_message_new_method_call;
sd_bus_message_new_method_return;
@@ -240,13 +259,13 @@ global:
sd_bus_message_new_method_errnof;
sd_bus_message_ref;
sd_bus_message_unref;
- sd_bus_message_get_bus;
sd_bus_message_get_type;
sd_bus_message_get_cookie;
sd_bus_message_get_reply_cookie;
+ sd_bus_message_get_priority;
sd_bus_message_get_expect_reply;
sd_bus_message_get_auto_start;
- sd_bus_message_get_priority;
+ sd_bus_message_get_allow_interactive_authorization;
sd_bus_message_get_signature;
sd_bus_message_get_path;
sd_bus_message_get_interface;
@@ -258,13 +277,16 @@ global:
sd_bus_message_get_monotonic_usec;
sd_bus_message_get_realtime_usec;
sd_bus_message_get_seqnum;
+ sd_bus_message_get_bus;
sd_bus_message_get_creds;
- sd_bus_message_is_empty;
sd_bus_message_is_signal;
sd_bus_message_is_method_call;
sd_bus_message_is_method_error;
+ sd_bus_message_is_empty;
+ sd_bus_message_has_signature;
sd_bus_message_set_expect_reply;
sd_bus_message_set_auto_start;
+ sd_bus_message_set_allow_interactive_authorization;
sd_bus_message_set_destination;
sd_bus_message_set_priority;
sd_bus_message_append;
@@ -316,22 +338,33 @@ global:
sd_bus_emit_interfaces_removed_strv;
sd_bus_emit_interfaces_removed;
sd_bus_query_sender_creds;
+ sd_bus_query_sender_privilege;
sd_bus_creds_new_from_pid;
sd_bus_creds_ref;
sd_bus_creds_unref;
sd_bus_creds_get_mask;
- sd_bus_creds_get_uid;
- sd_bus_creds_get_gid;
+ sd_bus_creds_get_augmented_mask;
sd_bus_creds_get_pid;
+ sd_bus_creds_get_ppid;
sd_bus_creds_get_tid;
+ sd_bus_creds_get_uid;
+ sd_bus_creds_get_euid;
+ sd_bus_creds_get_suid;
+ sd_bus_creds_get_fsuid;
+ sd_bus_creds_get_gid;
+ sd_bus_creds_get_egid;
+ sd_bus_creds_get_sgid;
+ sd_bus_creds_get_fsgid;
+ sd_bus_creds_get_supplementary_gids;
sd_bus_creds_get_comm;
sd_bus_creds_get_tid_comm;
sd_bus_creds_get_exe;
sd_bus_creds_get_cmdline;
sd_bus_creds_get_cgroup;
sd_bus_creds_get_unit;
- sd_bus_creds_get_user_unit;
sd_bus_creds_get_slice;
+ sd_bus_creds_get_user_unit;
+ sd_bus_creds_get_user_slice;
sd_bus_creds_get_session;
sd_bus_creds_get_owner_uid;
sd_bus_creds_has_effective_cap;
@@ -341,6 +374,7 @@ global:
sd_bus_creds_get_selinux_context;
sd_bus_creds_get_audit_session_id;
sd_bus_creds_get_audit_login_uid;
+ sd_bus_creds_get_tty;
sd_bus_creds_get_unique_name;
sd_bus_creds_get_well_known_names;
sd_bus_creds_get_description;
@@ -355,6 +389,7 @@ global:
sd_bus_error_copy;
sd_bus_error_is_set;
sd_bus_error_has_name;
+ sd_bus_error_add_map;
sd_bus_path_encode;
sd_bus_path_decode;
sd_bus_track_new;
@@ -382,9 +417,10 @@ global:
sd_event_add_signal;
sd_event_add_child;
sd_event_add_defer;
+ sd_event_add_post;
sd_event_add_exit;
- sd_event_wait;
sd_event_prepare;
+ sd_event_wait;
sd_event_dispatch;
sd_event_run;
sd_event_loop;
@@ -398,6 +434,9 @@ global:
sd_event_get_watchdog;
sd_event_source_ref;
sd_event_source_unref;
+ sd_event_source_get_event;
+ sd_event_source_get_userdata;
+ sd_event_source_set_userdata;
sd_event_source_set_description;
sd_event_source_get_description;
sd_event_source_set_prepare;
@@ -406,8 +445,6 @@ global:
sd_event_source_set_priority;
sd_event_source_get_enabled;
sd_event_source_set_enabled;
- sd_event_source_get_userdata;
- sd_event_source_set_userdata;
sd_event_source_get_io_fd;
sd_event_source_set_io_fd;
sd_event_source_get_io_events;
@@ -420,8 +457,11 @@ global:
sd_event_source_get_time_clock;
sd_event_source_get_signal;
sd_event_source_get_child_pid;
- sd_event_source_get_event;
+} LIBSYSTEMD_220;
+m4_ifdef(`ENABLE_KDBUS',
+LIBSYSTEMD_FUTURE {
+global:
/* sd-utf8 */
sd_utf8_is_valid;
sd_ascii_is_valid;
@@ -454,5 +494,5 @@ global:
/* sd-path */
sd_path_home;
sd_path_search;
-} LIBSYSTEMD_217;
+} LIBSYSTEMD_220;
)
diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h
index 96c82d7e8f..a9350d7f51 100644
--- a/src/libsystemd/sd-bus/bus-bloom.h
+++ b/src/libsystemd/sd-bus/bus-bloom.h
@@ -23,7 +23,6 @@
#include <stdbool.h>
#include <stdint.h>
-#include <sys/types.h>
/*
* Our default bloom filter has the following parameters:
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
index eb60ca3628..52f8dfd3be 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -35,9 +35,9 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_NOT_SUBSCRIBED, EINVAL),
SD_BUS_ERROR_MAP(BUS_ERROR_ALREADY_SUBSCRIBED, EINVAL),
SD_BUS_ERROR_MAP(BUS_ERROR_ONLY_BY_DEPENDENCY, EINVAL),
- SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, EDEADLOCK),
- SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLOCK),
- SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLOCK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, EDEADLK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, EBADR),
SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM),
@@ -60,7 +60,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_DEVICE_IS_TAKEN, EINVAL),
SD_BUS_ERROR_MAP(BUS_ERROR_DEVICE_NOT_TAKEN, EINVAL),
SD_BUS_ERROR_MAP(BUS_ERROR_OPERATION_IN_PROGRESS, EINPROGRESS),
- SD_BUS_ERROR_MAP(BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, ENOTSUP),
+ SD_BUS_ERROR_MAP(BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, EALREADY),
@@ -70,7 +70,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_INVALID_REPLY, EINVAL),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_RR, ENOENT),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_RESOURCES, ENOMEM),
- SD_BUS_ERROR_MAP(BUS_ERROR_CNAME_LOOP, EDEADLOCK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_CNAME_LOOP, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_ABORTED, ECANCELED),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_TRANSFER, ENXIO),
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index e935833bc3..b17b62ac93 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-bus.h"
#include "bus-error.h"
#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index d29b98a269..f157c25bba 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -23,7 +23,7 @@
#include <fcntl.h>
#include "util.h"
-#include "fileio.h"
+#include "process-util.h"
#include "bus-internal.h"
#include "bus-socket.h"
#include "bus-container.h"
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 06e5b4fd9a..43ddfc651d 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -34,7 +34,6 @@
#include "bus-bloom.h"
#include "bus-util.h"
#include "capability.h"
-#include "cgroup-util.h"
_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
int r;
@@ -43,6 +42,9 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
assert_return(unique, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ if (!bus->bus_client)
+ return -EINVAL;
+
r = bus_ensure_running(bus);
if (r < 0)
return r;
@@ -77,7 +79,7 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags
if (r < 0)
return -errno;
- if (n->flags & KDBUS_NAME_IN_QUEUE)
+ if (n->return_flags & KDBUS_NAME_IN_QUEUE)
return 0;
return 1;
@@ -131,12 +133,14 @@ static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags)
_public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags) {
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
- assert_return(bus->bus_client, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(!(flags & ~(SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_QUEUE)), -EINVAL);
assert_return(service_name_is_valid(name), -EINVAL);
assert_return(name[0] != ':', -EINVAL);
+ if (!bus->bus_client)
+ return -EINVAL;
+
/* Don't allow requesting the special driver and local names */
if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
return -EINVAL;
@@ -214,11 +218,13 @@ static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
_public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
- assert_return(bus->bus_client, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(service_name_is_valid(name), -EINVAL);
assert_return(name[0] != ':', -EINVAL);
+ if (!bus->bus_client)
+ return -EINVAL;
+
/* Don't allow releasing the special driver and local names */
if (STR_IN_SET(name, "org.freedesktop.DBus", "org.freedesktop.DBus.Local"))
return -EINVAL;
@@ -375,6 +381,9 @@ _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatabl
assert_return(acquired || activatable, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ if (!bus->bus_client)
+ return -EINVAL;
+
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
@@ -414,6 +423,26 @@ static int bus_populate_creds_from_items(
c->mask |= SD_BUS_CREDS_TID;
}
+ if (mask & SD_BUS_CREDS_PPID) {
+ if (item->pids.ppid > 0) {
+ c->ppid = (pid_t) item->pids.ppid;
+ c->mask |= SD_BUS_CREDS_PPID;
+ } else if (item->pids.pid == 1) {
+ /* The structure doesn't
+ * really distinguish the case
+ * where a process has no
+ * parent and where we don't
+ * know it because it could
+ * not be translated due to
+ * namespaces. However, we
+ * know that PID 1 has no
+ * parent process, hence let's
+ * patch that in, manually. */
+ c->ppid = 0;
+ c->mask |= SD_BUS_CREDS_PPID;
+ }
+ }
+
break;
case KDBUS_ITEM_CREDS:
@@ -551,12 +580,12 @@ static int bus_populate_creds_from_items(
break;
case KDBUS_ITEM_AUDIT:
- if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
+ if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
c->audit_session_id = (uint32_t) item->audit.sessionid;
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
}
- if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
+ if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
c->audit_login_uid = (uid_t) item->audit.loginuid;
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
@@ -584,16 +613,17 @@ static int bus_populate_creds_from_items(
case KDBUS_ITEM_AUXGROUPS:
if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
- size_t n;
+ size_t i, n;
uid_t *g;
- assert_cc(sizeof(gid_t) == sizeof(uint32_t));
-
- n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
- g = newdup(gid_t, item->data32, n);
+ n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
+ g = new(gid_t, n);
if (!g)
return -ENOMEM;
+ for (i = 0; i < n; i++)
+ g[i] = item->data64[i];
+
free(c->supplementary_gids);
c->supplementary_gids = g;
c->n_supplementary_gids = n;
@@ -622,7 +652,7 @@ int bus_get_name_creds_kdbus(
int r;
if (streq(name, "org.freedesktop.DBus"))
- return -ENOTSUP;
+ return -EOPNOTSUPP;
r = bus_kernel_parse_unique_name(name, &id);
if (r < 0)
@@ -644,7 +674,8 @@ int bus_get_name_creds_kdbus(
* the bits we want, then ask for the PID/TID so that we
* can read the rest from /proc. */
if ((mask & SD_BUS_CREDS_AUGMENT) &&
- (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ (mask & (SD_BUS_CREDS_PPID|
+ SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
@@ -654,7 +685,7 @@ int bus_get_name_creds_kdbus(
mask |= SD_BUS_CREDS_PID;
cmd->size = size;
- cmd->flags = attach_flags_to_kdbus(mask);
+ cmd->attach_flags = attach_flags_to_kdbus(mask);
r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
if (r < 0)
@@ -875,11 +906,13 @@ _public_ int sd_bus_get_name_creds(
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
- assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+ assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(mask == 0 || creds, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(service_name_is_valid(name), -EINVAL);
- assert_return(bus->bus_client, -ENODATA);
+
+ if (!bus->bus_client)
+ return -EINVAL;
if (streq(name, "org.freedesktop.DBus.Local"))
return -EINVAL;
@@ -910,7 +943,8 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **
* to get the bits we want, then ask for the PID/TID so that we
* can read the rest from /proc. */
if ((mask & SD_BUS_CREDS_AUGMENT) &&
- (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ (mask & (SD_BUS_CREDS_PPID|
+ SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
@@ -919,7 +953,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **
SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
mask |= SD_BUS_CREDS_PID;
- cmd.flags = attach_flags_to_kdbus(mask);
+ cmd.attach_flags = attach_flags_to_kdbus(mask);
r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
if (r < 0)
@@ -989,7 +1023,7 @@ static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **
_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
assert_return(bus, -EINVAL);
- assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+ assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(ret, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -1393,6 +1427,9 @@ int bus_add_match_internal(
assert(bus);
+ if (!bus->bus_client)
+ return -EINVAL;
+
if (bus->is_kernel)
return bus_add_match_internal_kernel(bus, components, n_components, cookie);
else
@@ -1452,6 +1489,9 @@ int bus_remove_match_internal(
assert(bus);
+ if (!bus->bus_client)
+ return -EINVAL;
+
if (bus->is_kernel)
return bus_remove_match_internal_kernel(bus, cookie);
else
@@ -1469,6 +1509,9 @@ _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(service_name_is_valid(name), -EINVAL);
+ if (!bus->bus_client)
+ return -EINVAL;
+
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index a6317e9785..28bc8d2818 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -462,11 +462,22 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
/* No data passed? Or not enough data passed to retrieve the missing bits? */
if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
/* We couldn't read anything from the call, let's try
- * to get it from the sender or peer */
+ * to get it from the sender or peer. */
if (call->sender)
+ /* There's a sender, but the creds are
+ * missing. This means we are talking via
+ * dbus1, or are getting a message that was
+ * sent to us via kdbus, but was converted
+ * from a dbus1 message by the bus-proxy and
+ * thus also lacks the creds. */
return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
else
+ /* There's no sender, hence we are on a dbus1
+ * direct connection. For direct connections
+ * the credentials of the AF_UNIX peer matter,
+ * which may be queried via
+ * sd_bus_get_owner_creds(). */
return sd_bus_get_owner_creds(call->bus, mask, creds);
}
@@ -488,10 +499,18 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability)
return -ENOTCONN;
if (capability >= 0) {
+
r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
if (r < 0)
return r;
+ /* We cannot use augmented caps for authorization,
+ * since then data is acquired raceful from
+ * /proc. This can never actually happen, but let's
+ * better be safe than sorry, and do an extra check
+ * here. */
+ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
+
/* Note that not even on kdbus we might have the caps
* field, due to faked identities, or namespace
* translation issues. */
@@ -512,6 +531,13 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability)
if (our_uid != 0 || !know_caps || capability < 0) {
uid_t sender_uid;
+ /* We cannot use augmented uid/euid for authorization,
+ * since then data is acquired raceful from
+ * /proc. This can never actually happen, but let's
+ * better be safe than sorry, and do an extra check
+ * here. */
+ assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
+
/* Try to use the EUID, if we have it. */
r = sd_bus_creds_get_euid(creds, &sender_uid);
if (r < 0)
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index ea8a619c5a..4d67619cf8 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -23,13 +23,15 @@
#include <linux/capability.h>
#include "util.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
#include "capability.h"
#include "cgroup-util.h"
#include "fileio.h"
#include "audit.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "time-util.h"
#include "strv.h"
#include "bus-creds.h"
#include "bus-label.h"
@@ -51,7 +53,10 @@ void bus_creds_done(sd_bus_creds *c) {
free(c->unit);
free(c->user_unit);
free(c->slice);
+ free(c->user_slice);
free(c->unescaped_description);
+ free(c->supplementary_gids);
+ free(c->tty);
free(c->well_known_names); /* note that this is an strv, but
* we only free the array, not the
@@ -101,7 +106,9 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
free(c->unique_name);
free(c->cgroup_root);
free(c->description);
+
free(c->supplementary_gids);
+ c->supplementary_gids = NULL;
strv_free(c->well_known_names);
c->well_known_names = NULL;
@@ -127,6 +134,12 @@ _public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
return c->mask;
}
+_public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
+ assert_return(c, 0);
+
+ return c->augmented;
+}
+
sd_bus_creds* bus_creds_new(void) {
sd_bus_creds *c;
@@ -144,7 +157,7 @@ _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t m
int r;
assert_return(pid >= 0, -EINVAL);
- assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(ret, -EINVAL);
if (pid == 0)
@@ -227,7 +240,6 @@ _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
return 0;
}
-
_public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
assert_return(c, -EINVAL);
assert_return(egid, -EINVAL);
@@ -284,6 +296,23 @@ _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
return 0;
}
+_public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
+ assert_return(c, -EINVAL);
+ assert_return(ppid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_PPID))
+ return -ENODATA;
+
+ /* PID 1 has no parent process. Let's distinguish the case of
+ * not knowing and not having a parent process by the returned
+ * error code. */
+ if (c->ppid == 0)
+ return -ENXIO;
+
+ *ppid = c->ppid;
+ return 0;
+}
+
_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
assert_return(c, -EINVAL);
assert_return(tid, -EINVAL);
@@ -338,7 +367,9 @@ _public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
if (!(c->mask & SD_BUS_CREDS_EXE))
return -ENODATA;
- assert(c->exe);
+ if (!c->exe)
+ return -ENXIO;
+
*ret = c->exe;
return 0;
}
@@ -436,6 +467,33 @@ _public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
return 0;
}
+_public_ int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **ret) {
+ int r;
+
+ assert_return(c, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_USER_SLICE))
+ return -ENODATA;
+
+ assert(c->cgroup);
+
+ if (!c->user_slice) {
+ const char *shifted;
+
+ r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
+ if (r < 0)
+ return r;
+
+ r = cg_path_get_user_slice(shifted, (char**) &c->user_slice);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = c->user_slice;
+ return 0;
+}
+
_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
int r;
@@ -488,8 +546,8 @@ _public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
if (!(c->mask & SD_BUS_CREDS_CMDLINE))
return -ENODATA;
- assert_return(c->cmdline, -ESRCH);
- assert(c->cmdline);
+ if (!c->cmdline)
+ return -ENXIO;
if (!c->cmdline_array) {
c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
@@ -508,6 +566,9 @@ _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessio
if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
return -ENODATA;
+ if (c->audit_session_id == AUDIT_SESSION_INVALID)
+ return -ENXIO;
+
*sessionid = c->audit_session_id;
return 0;
}
@@ -519,10 +580,27 @@ _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
return -ENODATA;
+ if (c->audit_login_uid == UID_INVALID)
+ return -ENXIO;
+
*uid = c->audit_login_uid;
return 0;
}
+_public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) {
+ assert_return(c, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_TTY))
+ return -ENODATA;
+
+ if (!c->tty)
+ return -ENXIO;
+
+ *ret = c->tty;
+ return 0;
+}
+
_public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
assert_return(c, -EINVAL);
assert_return(unique_name, -EINVAL);
@@ -593,10 +671,11 @@ static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
assert(capability >= 0);
assert(c->capability);
- sz = DIV_ROUND_UP(cap_last_cap(), 32U);
- if ((unsigned)capability > cap_last_cap())
+ if ((unsigned) capability > cap_last_cap())
return 0;
+ sz = DIV_ROUND_UP(cap_last_cap(), 32U);
+
return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
}
@@ -693,32 +772,33 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (!(mask & SD_BUS_CREDS_AUGMENT))
return 0;
- missing = mask & ~c->mask;
- if (missing == 0)
- return 0;
-
/* Try to retrieve PID from creds if it wasn't passed to us */
if (pid <= 0 && (c->mask & SD_BUS_CREDS_PID))
pid = c->pid;
- if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
- tid = c->pid;
-
/* Without pid we cannot do much... */
if (pid <= 0)
return 0;
- if (pid > 0) {
- c->pid = pid;
- c->mask |= SD_BUS_CREDS_PID;
- }
+ /* Try to retrieve TID from creds if it wasn't passed to us */
+ if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
+ tid = c->tid;
+
+ /* Calculate what we shall and can add */
+ missing = mask & ~(c->mask|SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_AUGMENT);
+ if (missing == 0)
+ return 0;
+
+ c->pid = pid;
+ c->mask |= SD_BUS_CREDS_PID;
if (tid > 0) {
c->tid = tid;
c->mask |= SD_BUS_CREDS_TID;
}
- if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
+ if (missing & (SD_BUS_CREDS_PPID |
+ SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
@@ -741,6 +821,25 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
FOREACH_LINE(line, f, return -errno) {
truncate_nl(line);
+ if (missing & SD_BUS_CREDS_PPID) {
+ p = startswith(line, "PPid:");
+ if (p) {
+ p += strspn(p, WHITESPACE);
+
+ /* Explicitly check for PPID 0 (which is the case for PID 1) */
+ if (!streq(p, "0")) {
+ r = parse_pid(p, &c->ppid);
+ if (r < 0)
+ return r;
+
+ } else
+ c->ppid = 0;
+
+ c->mask |= SD_BUS_CREDS_PPID;
+ continue;
+ }
+ }
+
if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
p = startswith(line, "Uid:");
if (p) {
@@ -750,10 +849,15 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
return -EIO;
- c->uid = (uid_t) uid;
- c->euid = (uid_t) euid;
- c->suid = (uid_t) suid;
- c->fsuid = (uid_t) fsuid;
+ if (missing & SD_BUS_CREDS_UID)
+ c->uid = (uid_t) uid;
+ if (missing & SD_BUS_CREDS_EUID)
+ c->euid = (uid_t) euid;
+ if (missing & SD_BUS_CREDS_SUID)
+ c->suid = (uid_t) suid;
+ if (missing & SD_BUS_CREDS_FSUID)
+ c->fsuid = (uid_t) fsuid;
+
c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
continue;
}
@@ -768,10 +872,15 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
return -EIO;
- c->gid = (gid_t) gid;
- c->egid = (gid_t) egid;
- c->sgid = (gid_t) sgid;
- c->fsgid = (gid_t) fsgid;
+ if (missing & SD_BUS_CREDS_GID)
+ c->gid = (gid_t) gid;
+ if (missing & SD_BUS_CREDS_EGID)
+ c->egid = (gid_t) egid;
+ if (missing & SD_BUS_CREDS_SGID)
+ c->sgid = (gid_t) sgid;
+ if (missing & SD_BUS_CREDS_FSGID)
+ c->fsgid = (gid_t) fsgid;
+
c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
continue;
}
@@ -879,7 +988,17 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_EXE) {
r = get_process_exe(pid, &c->exe);
- if (r < 0) {
+ if (r == -ESRCH) {
+ /* Unfortunately we cannot really distinguish
+ * the case here where the process does not
+ * exist, and /proc/$PID/exe being unreadable
+ * because $PID is a kernel thread. Hence,
+ * assume it is a kernel thread, and rely on
+ * that this case is caught with a later
+ * call. */
+ c->exe = NULL;
+ c->mask |= SD_BUS_CREDS_EXE;
+ } else if (r < 0) {
if (r != -EPERM && r != -EACCES)
return r;
} else
@@ -891,17 +1010,18 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
p = procfs_file_alloca(pid, "cmdline");
r = read_full_file(p, &c->cmdline, &c->cmdline_size);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0) {
- if (r == -ENOENT)
- return -ESRCH;
if (r != -EPERM && r != -EACCES)
return r;
} else {
if (c->cmdline_size == 0) {
free(c->cmdline);
c->cmdline = NULL;
- } else
- c->mask |= SD_BUS_CREDS_CMDLINE;
+ }
+
+ c->mask |= SD_BUS_CREDS_CMDLINE;
}
}
@@ -912,34 +1032,43 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm);
+ if (r == -ENOENT)
+ return -ESRCH;
if (r < 0) {
- if (r == -ENOENT)
- return -ESRCH;
if (r != -EPERM && r != -EACCES)
return r;
} else
c->mask |= SD_BUS_CREDS_TID_COMM;
}
- if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
+ if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
- r = cg_pid_get_path(NULL, pid, &c->cgroup);
- if (r < 0) {
- if (r != -EPERM && r != -EACCES)
- return r;
- } else {
+ if (!c->cgroup) {
+ r = cg_pid_get_path(NULL, pid, &c->cgroup);
+ if (r < 0) {
+ if (r != -EPERM && r != -EACCES)
+ return r;
+ }
+ }
+
+ if (!c->cgroup_root) {
r = cg_get_root_path(&c->cgroup_root);
if (r < 0)
return r;
-
- c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
}
+
+ if (c->cgroup)
+ c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
}
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
r = audit_session_from_pid(pid, &c->audit_session_id);
- if (r < 0) {
- if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+ if (r == -ENXIO) {
+ /* ENXIO means: no audit session id assigned */
+ c->audit_session_id = AUDIT_SESSION_INVALID;
+ c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+ } else if (r < 0) {
+ if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
@@ -947,13 +1076,43 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
- if (r < 0) {
- if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+ if (r == -ENXIO) {
+ /* ENXIO means: no audit login uid assigned */
+ c->audit_login_uid = UID_INVALID;
+ c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
+ } else if (r < 0) {
+ if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
+ if (missing & SD_BUS_CREDS_TTY) {
+ r = get_ctty(pid, NULL, &c->tty);
+ if (r == -ENXIO) {
+ /* ENXIO means: process has no controlling TTY */
+ c->tty = NULL;
+ c->mask |= SD_BUS_CREDS_TTY;
+ } else if (r < 0) {
+ if (r != -EPERM && r != -EACCES && r != -ENOENT)
+ return r;
+ } else
+ c->mask |= SD_BUS_CREDS_TTY;
+ }
+
+ /* In case only the exe path was to be read we cannot
+ * distinguish the case where the exe path was unreadable
+ * because the process was a kernel thread, or when the
+ * process didn't exist at all. Hence, let's do a final check,
+ * to be sure. */
+ if (!pid_is_alive(pid))
+ return -ESRCH;
+
+ if (tid > 0 && tid != pid && !pid_is_unwaited(tid))
+ return -ESRCH;
+
+ c->augmented = missing & c->mask;
+
return 0;
}
@@ -978,6 +1137,21 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
/* Copy the original data over */
+ if (c->mask & mask & SD_BUS_CREDS_PID) {
+ n->pid = c->pid;
+ n->mask |= SD_BUS_CREDS_PID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_TID) {
+ n->tid = c->tid;
+ n->mask |= SD_BUS_CREDS_TID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_PPID) {
+ n->ppid = c->ppid;
+ n->mask |= SD_BUS_CREDS_PPID;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_UID) {
n->uid = c->uid;
n->mask |= SD_BUS_CREDS_UID;
@@ -1019,24 +1193,22 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
}
if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
- n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
- if (!n->supplementary_gids)
- return -ENOMEM;
- n->n_supplementary_gids = c->n_supplementary_gids;
- n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
- }
-
- if (c->mask & mask & SD_BUS_CREDS_PID) {
- n->pid = c->pid;
- n->mask |= SD_BUS_CREDS_PID;
- }
+ if (c->supplementary_gids) {
+ n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
+ if (!n->supplementary_gids)
+ return -ENOMEM;
+ n->n_supplementary_gids = c->n_supplementary_gids;
+ } else {
+ n->supplementary_gids = NULL;
+ n->n_supplementary_gids = 0;
+ }
- if (c->mask & mask & SD_BUS_CREDS_TID) {
- n->tid = c->tid;
- n->mask |= SD_BUS_CREDS_TID;
+ n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
}
if (c->mask & mask & SD_BUS_CREDS_COMM) {
+ assert(c->comm);
+
n->comm = strdup(c->comm);
if (!n->comm)
return -ENOMEM;
@@ -1045,6 +1217,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
}
if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
+ assert(c->tid_comm);
+
n->tid_comm = strdup(c->tid_comm);
if (!n->tid_comm)
return -ENOMEM;
@@ -1053,23 +1227,34 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
}
if (c->mask & mask & SD_BUS_CREDS_EXE) {
- n->exe = strdup(c->exe);
- if (!n->exe)
- return -ENOMEM;
+ if (c->exe) {
+ n->exe = strdup(c->exe);
+ if (!n->exe)
+ return -ENOMEM;
+ } else
+ n->exe = NULL;
n->mask |= SD_BUS_CREDS_EXE;
}
if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
- n->cmdline = memdup(c->cmdline, c->cmdline_size);
- if (!n->cmdline)
- return -ENOMEM;
+ if (c->cmdline) {
+ n->cmdline = memdup(c->cmdline, c->cmdline_size);
+ if (!n->cmdline)
+ return -ENOMEM;
+
+ n->cmdline_size = c->cmdline_size;
+ } else {
+ n->cmdline = NULL;
+ n->cmdline_size = 0;
+ }
- n->cmdline_size = c->cmdline_size;
n->mask |= SD_BUS_CREDS_CMDLINE;
}
- if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID)) {
+ if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_OWNER_UID)) {
+ assert(c->cgroup);
+
n->cgroup = strdup(c->cgroup);
if (!n->cgroup)
return -ENOMEM;
@@ -1078,10 +1263,12 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
if (!n->cgroup_root)
return -ENOMEM;
- n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_OWNER_UID);
+ n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_OWNER_UID);
}
if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
+ assert(c->capability);
+
n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
if (!n->capability)
return -ENOMEM;
@@ -1090,6 +1277,8 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
}
if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+ assert(c->label);
+
n->label = strdup(c->label);
if (!n->label)
return -ENOMEM;
@@ -1105,7 +1294,19 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
+ if (c->mask & mask & SD_BUS_CREDS_TTY) {
+ if (c->tty) {
+ n->tty = strdup(c->tty);
+ if (!n->tty)
+ return -ENOMEM;
+ } else
+ n->tty = NULL;
+ n->mask |= SD_BUS_CREDS_TTY;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
+ assert(c->unique_name);
+
n->unique_name = strdup(c->unique_name);
if (!n->unique_name)
return -ENOMEM;
@@ -1113,24 +1314,31 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
}
if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
- n->well_known_names = strv_copy(c->well_known_names);
- if (!n->well_known_names)
- return -ENOMEM;
+ if (strv_isempty(c->well_known_names))
+ n->well_known_names = NULL;
+ else {
+ n->well_known_names = strv_copy(c->well_known_names);
+ if (!n->well_known_names)
+ return -ENOMEM;
+ }
+ n->well_known_names_driver = c->well_known_names_driver;
+ n->well_known_names_local = c->well_known_names_local;
n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
}
if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
+ assert(c->description);
n->description = strdup(c->description);
if (!n->description)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_DESCRIPTION;
}
+ n->augmented = c->augmented & n->mask;
+
/* Get more data */
- r = bus_creds_add_more(n, mask,
- c->mask & SD_BUS_CREDS_PID ? c->pid : 0,
- c->mask & SD_BUS_CREDS_TID ? c->tid : 0);
+ r = bus_creds_add_more(n, mask, 0, 0);
if (r < 0)
return r;
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
index 3b337efa32..209d216123 100644
--- a/src/libsystemd/sd-bus/bus-creds.h
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -24,12 +24,13 @@
#include <stdbool.h>
#include "sd-bus.h"
-#include "time-util.h"
struct sd_bus_creds {
bool allocated;
unsigned n_ref;
+
uint64_t mask;
+ uint64_t augmented;
uid_t uid;
uid_t euid;
@@ -43,6 +44,7 @@ struct sd_bus_creds {
gid_t *supplementary_gids;
unsigned n_supplementary_gids;
+ pid_t ppid;
pid_t pid;
pid_t tid;
@@ -59,6 +61,9 @@ struct sd_bus_creds {
char *unit;
char *user_unit;
char *slice;
+ char *user_slice;
+
+ char *tty;
uint32_t *capability;
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 7181639645..9db86adb7f 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -22,9 +22,10 @@
#include "util.h"
#include "capability.h"
#include "strv.h"
-#include "audit.h"
#include "macro.h"
#include "cap-list.h"
+#include "formats-util.h"
+#include "terminal-util.h"
#include "bus-message.h"
#include "bus-internal.h"
@@ -330,13 +331,11 @@ static void dump_capabilities(
}
int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
- bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
- const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
uid_t owner, audit_loginuid;
uint32_t audit_sessionid;
char **cmdline = NULL, **well_known = NULL;
- const char *prefix, *color, *suffix;
- int r;
+ const char *prefix, *color, *suffix, *s;
+ int r, q, v, w, z;
assert(c);
@@ -361,8 +360,16 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
if (c->mask & SD_BUS_CREDS_TID)
fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
+ if (c->mask & SD_BUS_CREDS_PPID) {
+ if (c->ppid == 0)
+ fprintf(f, "%sPPID=%sn/a%s", prefix, color, suffix);
+ else
+ fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix);
+ }
+ if (c->mask & SD_BUS_CREDS_TTY)
+ fprintf(f, "%sTTY=%s%s%s", prefix, color, strna(c->tty), suffix);
- if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))))
+ if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID|SD_BUS_CREDS_TTY))))
fputs("\n", f);
if (c->mask & SD_BUS_CREDS_UID)
@@ -404,12 +411,13 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
if (c->mask & SD_BUS_CREDS_TID_COMM)
fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
if (c->mask & SD_BUS_CREDS_EXE)
- fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
+ fprintf(f, "%sExe=%s%s%s", prefix, color, strna(c->exe), suffix);
if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
fputs("\n", f);
- if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
+ r = sd_bus_creds_get_cmdline(c, &cmdline);
+ if (r >= 0) {
char **i;
fprintf(f, "%sCommandLine=%s", prefix, color);
@@ -421,7 +429,8 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
}
fprintf(f, "%s", suffix);
- }
+ } else if (r != -ENODATA)
+ fprintf(f, "%sCommandLine=%sn/a%s", prefix, color, suffix);
if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
@@ -433,32 +442,42 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
if (c->mask & SD_BUS_CREDS_CGROUP)
fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
- (void) sd_bus_creds_get_unit(c, &u);
- if (u)
- fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
- (void) sd_bus_creds_get_user_unit(c, &uu);
- if (uu)
- fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
- (void) sd_bus_creds_get_slice(c, &sl);
- if (sl)
- fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
- (void) sd_bus_creds_get_session(c, &s);
- if (s)
- fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
-
- if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
+ s = NULL;
+ r = sd_bus_creds_get_unit(c, &s);
+ if (r != -ENODATA)
+ fprintf(f, "%sUnit=%s%s%s", prefix, color, strna(s), suffix);
+ s = NULL;
+ v = sd_bus_creds_get_slice(c, &s);
+ if (v != -ENODATA)
+ fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix);
+ s = NULL;
+ q = sd_bus_creds_get_user_unit(c, &s);
+ if (q != -ENODATA)
+ fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix);
+ s = NULL;
+ w = sd_bus_creds_get_user_slice(c, &s);
+ if (w != -ENODATA)
+ fprintf(f, "%sUserSlice=%s%s%s", prefix, color, strna(s), suffix);
+ s = NULL;
+ z = sd_bus_creds_get_session(c, &s);
+ if (z != -ENODATA)
+ fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix);
+
+ if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA || z != -ENODATA))
fputs("\n", f);
- if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
- audit_loginuid_is_set = true;
+ r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid);
+ if (r >= 0)
fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
- }
- if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
- audit_sessionid_is_set = true;
+ else if (r != -ENODATA)
+ fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix);
+ q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid);
+ if (q >= 0)
fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
- }
+ else if (q != -ENODATA)
+ fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix);
- if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
+ if (terse && (r != -ENODATA || q != -ENODATA))
fputs("\n", f);
if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
index 3bf0c5d3e4..dac157be16 100644
--- a/src/libsystemd/sd-bus/bus-error.c
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -40,7 +40,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoReply", ETIMEDOUT),
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.IOError", EIO),
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL),
- SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NotSupported", ENOTSUP),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NotSupported", EOPNOTSUPP),
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS),
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AccessDenied", EACCES),
SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AuthFailed", EACCES),
@@ -168,7 +168,7 @@ static sd_bus_error errno_to_bus_error_const(int error) {
case ECONNRESET:
return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_DISCONNECTED, "Disconnected");
- case ENOTSUP:
+ case EOPNOTSUPP:
return SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NOT_SUPPORTED, "Not supported");
case EADDRNOTAVAIL:
diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c
index 02b95cd136..2d18a4e6c1 100644
--- a/src/libsystemd/sd-bus/bus-gvariant.c
+++ b/src/libsystemd/sd-bus/bus-gvariant.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "bus-type.h"
#include "bus-gvariant.h"
#include "bus-signature.h"
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index e9f1a816aa..1351938c80 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -22,8 +22,6 @@
***/
#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
#include <pthread.h>
#include "hashmap.h"
@@ -211,6 +209,7 @@ struct sd_bus {
bool manual_peer_interface:1;
bool is_system:1;
bool is_user:1;
+ bool allow_interactive_authorization:1;
int use_memfd;
diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c
index d528ab2a04..e2f4550c7e 100644
--- a/src/libsystemd/sd-bus/bus-introspect.c
+++ b/src/libsystemd/sd-bus/bus-introspect.c
@@ -20,7 +20,6 @@
***/
#include "util.h"
-#include "sd-bus-protocol.h"
#include "bus-introspect.h"
#include "bus-signature.h"
#include "bus-internal.h"
diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h
index 98312d123b..1914e6cb8b 100644
--- a/src/libsystemd/sd-bus/bus-introspect.h
+++ b/src/libsystemd/sd-bus/bus-introspect.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdio.h>
#include "sd-bus.h"
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index e90ee449d9..417e4d5903 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -38,8 +38,8 @@
#include "strv.h"
#include "memfd-util.h"
#include "capability.h"
-#include "cgroup-util.h"
#include "fileio.h"
+#include "formats-util.h"
#include "bus-internal.h"
#include "bus-message.h"
@@ -595,6 +595,14 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
}
+ if (d->pids.ppid > 0) {
+ m->creds.ppid = (pid_t) d->pids.ppid;
+ m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask;
+ } else if (d->pids.pid == 1) {
+ m->creds.ppid = 0;
+ m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask;
+ }
+
break;
case KDBUS_ITEM_CREDS:
@@ -681,15 +689,11 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
break;
case KDBUS_ITEM_AUDIT:
- if ((uint32_t) d->audit.sessionid != (uint32_t) -1) {
- m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
- m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask;
- }
+ m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask;
- if ((uid_t) d->audit.loginuid != UID_INVALID) {
- m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
- m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask;
- }
+ m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask;
break;
case KDBUS_ITEM_CAPS:
@@ -749,10 +753,21 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
case KDBUS_ITEM_AUXGROUPS:
if (bus->creds_mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
- assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+ size_t i, n;
+ gid_t *g;
+
+ n = (d->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
+ g = new(gid_t, n);
+ if (!g) {
+ r = -ENOMEM;
+ goto fail;
+ }
- m->creds.n_supplementary_gids = (d->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
- m->creds.supplementary_gids = (gid_t*) d->data32;
+ for (i = 0; i < n; i++)
+ g[i] = d->data64[i];
+
+ m->creds.supplementary_gids = g;
+ m->creds.n_supplementary_gids = n;
m->creds.mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
}
@@ -841,9 +856,8 @@ fail:
int bus_kernel_take_fd(sd_bus *b) {
struct kdbus_bloom_parameter *bloom = NULL;
+ struct kdbus_item *items, *item;
struct kdbus_cmd_hello *hello;
- struct kdbus_item_list *items;
- struct kdbus_item *item;
_cleanup_free_ char *g = NULL;
const char *name;
size_t l = 0, m = 0, sz;
@@ -948,8 +962,16 @@ int bus_kernel_take_fd(sd_bus *b) {
}
r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
- if (r < 0)
+ if (r < 0) {
+ if (errno == ENOTTY)
+ /* If the ioctl is not supported we assume that the
+ * API version changed in a major incompatible way,
+ * let's indicate an API incompatibility in this
+ * case. */
+ return -ESOCKTNOSUPPORT;
+
return -errno;
+ }
if (!b->kdbus_buffer) {
b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
@@ -963,13 +985,13 @@ int bus_kernel_take_fd(sd_bus *b) {
/* The higher 32bit of the bus_flags fields are considered
* 'incompatible flags'. Refuse them all for now. */
if (hello->bus_flags > 0xFFFFFFFFULL) {
- r = -ENOTSUP;
+ r = -ESOCKTNOSUPPORT;
goto fail;
}
/* extract bloom parameters from items */
items = (void*)((uint8_t*)b->kdbus_buffer + hello->offset);
- KDBUS_ITEM_FOREACH(item, items, items) {
+ KDBUS_FOREACH(item, items, hello->items_size) {
switch (item->type) {
case KDBUS_ITEM_BLOOM_PARAMETER:
bloom = &item->bloom_parameter;
@@ -978,7 +1000,7 @@ int bus_kernel_take_fd(sd_bus *b) {
}
if (!bloom || !bloom_validate_parameters((size_t) bloom->size, (unsigned) bloom->n_hash)) {
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
goto fail;
}
@@ -1345,15 +1367,12 @@ int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
}
r = ioctl(bus->input_fd, KDBUS_CMD_RECV, &recv);
+ if (recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS)
+ log_debug("%s: kdbus reports %" PRIu64 " dropped broadcast messages, ignoring.", strna(bus->description), (uint64_t) recv.dropped_msgs);
if (r < 0) {
if (errno == EAGAIN)
return 0;
- if (errno == EOVERFLOW) {
- log_debug("%s: kdbus reports %" PRIu64 " dropped broadcast messages, ignoring.", strna(bus->description), (uint64_t) recv.dropped_msgs);
- return 0;
- }
-
return -errno;
}
@@ -1389,7 +1408,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al
assert(allocated);
if (!bus || !bus->is_kernel)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
@@ -1499,7 +1518,7 @@ uint64_t attach_flags_to_kdbus(uint64_t mask) {
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID))
m |= KDBUS_ATTACH_CREDS;
- if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))
+ if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID))
m |= KDBUS_ATTACH_PIDS;
if (mask & SD_BUS_CREDS_COMM)
@@ -1574,7 +1593,7 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
make->size += ALIGN8(n->size);
- /* The busses we create make no restrictions on what metadata
+ /* The buses we create make no restrictions on what metadata
* peers can read from incoming messages. */
n = KDBUS_ITEM_NEXT(n);
n->type = KDBUS_ITEM_ATTACH_FLAGS_RECV;
@@ -1600,6 +1619,11 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
safe_close(fd);
+
+ /* Major API change? then the ioctls got shuffled around. */
+ if (errno == ENOTTY)
+ return -ESOCKTNOSUPPORT;
+
return -errno;
}
@@ -1746,32 +1770,6 @@ int bus_kernel_realize_attach_flags(sd_bus *bus) {
return 0;
}
-int bus_kernel_fix_attach_mask(void) {
- _cleanup_free_ char *mask = NULL;
- uint64_t m = (uint64_t) -1;
- char buf[2+16+2];
- int r;
-
- /* By default we don't want any kdbus metadata fields to be
- * suppressed, hence we reset the kernel mask for it to
- * (uint64_t) -1. If the module argument was overwritten by
- * the kernel cmdline, we leave it as is. */
-
- r = get_proc_cmdline_key("kdbus.attach_flags_mask=", &mask);
- if (r < 0)
- return log_warning_errno(r, "Failed to read kernel command line: %m");
-
- if (r == 0) {
- sprintf(buf, "0x%" PRIx64 "\n", m);
- r = write_string_file("/sys/module/kdbus/parameters/attach_flags_mask", buf);
- if (r < 0)
- return log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to write kdbus attach mask: %m");
- }
-
- return 0;
-}
-
int bus_kernel_get_bus_name(sd_bus *bus, char **name) {
struct kdbus_cmd_info cmd = {
.size = sizeof(struct kdbus_cmd_info),
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
index b9f31ba790..bb4dff6d82 100644
--- a/src/libsystemd/sd-bus/bus-kernel.h
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -90,8 +90,6 @@ int bus_kernel_drop_one(int fd);
int bus_kernel_realize_attach_flags(sd_bus *bus);
-int bus_kernel_fix_attach_mask(void);
-
int bus_kernel_get_bus_name(sd_bus *bus, char **name);
int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset);
diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
index 162f0ab608..7c5264fad4 100644
--- a/src/libsystemd/sd-bus/bus-match.c
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -22,7 +22,6 @@
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-match.h"
-#include "bus-error.h"
#include "bus-util.h"
#include "strv.h"
@@ -329,7 +328,7 @@ int bus_match_run(
bus->current_handler = node->leaf.callback->callback;
bus->current_userdata = slot->userdata;
}
- r = node->leaf.callback->callback(bus, m, slot->userdata, &error_buffer);
+ r = node->leaf.callback->callback(m, slot->userdata, &error_buffer);
if (bus) {
bus->current_userdata = NULL;
bus->current_handler = NULL;
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 2959303033..6ee209dd1b 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -27,7 +27,6 @@
#include "utf8.h"
#include "strv.h"
#include "time-util.h"
-#include "cgroup-util.h"
#include "memfd-util.h"
#include "sd-bus.h"
@@ -421,7 +420,7 @@ static int message_append_reply_cookie(sd_bus_message *m, uint64_t cookie) {
else {
/* 64bit cookies are not supported on dbus1 */
if (cookie > 0xffffffffUL)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
return message_append_field_uint32(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) cookie);
}
@@ -441,7 +440,7 @@ int bus_message_from_header(
size_t extra,
sd_bus_message **ret) {
- sd_bus_message *m;
+ _cleanup_free_ sd_bus_message *m = NULL;
struct bus_header *h;
size_t a, label_sz;
@@ -460,15 +459,13 @@ int bus_message_from_header(
return -EBADMSG;
h = header;
- if (h->version != 1 &&
- h->version != 2)
+ if (!IN_SET(h->version, 1, 2))
return -EBADMSG;
if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
return -EBADMSG;
- if (h->endian != BUS_LITTLE_ENDIAN &&
- h->endian != BUS_BIG_ENDIAN)
+ if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
return -EBADMSG;
/* Note that we are happy with unknown flags in the flags header! */
@@ -557,6 +554,7 @@ int bus_message_from_header(
m->bus = sd_bus_ref(bus);
*ret = m;
+ m = NULL;
return 0;
}
@@ -634,6 +632,9 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
m->bus = sd_bus_ref(bus);
+ if (bus->allow_interactive_authorization)
+ m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
+
return m;
}
@@ -749,7 +750,7 @@ static int message_new_reply(
t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
t->reply_cookie = BUS_MESSAGE_COOKIE(call);
if (t->reply_cookie == 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
r = message_append_reply_cookie(t, t->reply_cookie);
if (r < 0)
@@ -1462,7 +1463,7 @@ static int message_push_fd(sd_bus_message *m, int fd) {
return -EINVAL;
if (!m->allow_fds)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (copy < 0)
@@ -2941,7 +2942,7 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
if (cookie > 0xffffffffULL &&
!BUS_MESSAGE_IS_GVARIANT(m))
- return -ENOTSUP;
+ return -EOPNOTSUPP;
/* In vtables the return signature of method calls is listed,
* let's check if they match if this is a response */
@@ -3488,8 +3489,6 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
return r;
} else {
- rindex = m->rindex;
-
if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
uint32_t l;
bool ok;
@@ -4797,7 +4796,7 @@ _public_ int sd_bus_message_read_array(
assert_return(bus_type_is_trivial(type), -EINVAL);
assert_return(ptr, -EINVAL);
assert_return(size, -EINVAL);
- assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -ENOTSUP);
+ assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -EOPNOTSUPP);
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
if (r <= 0)
@@ -5508,7 +5507,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
/* Try to read the error message, but if we can't it's a non-issue */
if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
- sd_bus_message_read(m, "s", &m->error.message);
+ (void) sd_bus_message_read(m, "s", &m->error.message);
return 0;
}
@@ -5551,6 +5550,7 @@ int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
}
int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
+ const char *s;
int r;
assert(m);
@@ -5560,19 +5560,13 @@ int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
if (r <= 0)
return r;
- for (;;) {
- const char *s;
-
- r = sd_bus_message_read_basic(m, 's', &s);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
+ while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) {
r = strv_extend(l, s);
if (r < 0)
return r;
}
+ if (r < 0)
+ return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
index 32955329b4..d784e603dd 100644
--- a/src/libsystemd/sd-bus/bus-message.h
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -27,7 +27,6 @@
#include "macro.h"
#include "sd-bus.h"
-#include "kdbus.h"
#include "time-util.h"
#include "bus-creds.h"
#include "bus-protocol.h"
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index fc6c223283..e4bbd880e5 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -277,7 +277,7 @@ static int node_callbacks_run(
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->callback;
bus->current_userdata = slot->userdata;
- r = c->callback(bus, m, slot->userdata, &error_buffer);
+ r = c->callback(m, slot->userdata, &error_buffer);
bus->current_userdata = NULL;
bus->current_handler = NULL;
bus->current_slot = sd_bus_slot_unref(slot);
@@ -395,7 +395,7 @@ static int method_callbacks_run(
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->vtable->x.method.handler;
bus->current_userdata = u;
- r = c->vtable->x.method.handler(bus, m, u, &error);
+ r = c->vtable->x.method.handler(m, u, &error);
bus->current_userdata = NULL;
bus->current_handler = NULL;
bus->current_slot = sd_bus_slot_unref(slot);
diff --git a/src/libsystemd/sd-bus/bus-signature.h b/src/libsystemd/sd-bus/bus-signature.h
index 2e06e30548..c4fed0b53d 100644
--- a/src/libsystemd/sd-bus/bus-signature.h
+++ b/src/libsystemd/sd-bus/bus-signature.h
@@ -22,7 +22,6 @@
***/
#include <stdbool.h>
-#include <sys/types.h>
bool signature_is_single(const char *s, bool allow_dict_entry);
bool signature_is_pair(const char *s);
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 52883fa8cd..4fffc6581d 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -20,18 +20,17 @@
***/
#include <endian.h>
-#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
-#include <byteswap.h>
+#include "sd-daemon.h"
#include "util.h"
#include "macro.h"
#include "missing.h"
-#include "strv.h"
#include "utf8.h"
-#include "sd-daemon.h"
+#include "formats-util.h"
+#include "signal-util.h"
#include "sd-bus.h"
#include "bus-socket.h"
@@ -179,7 +178,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
/* We expect two response lines: "OK" and possibly
* "AGREE_UNIX_FD" */
- e = memmem(b->rbuffer, b->rbuffer_size, "\r\n", 2);
+ e = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2);
if (!e)
return 0;
@@ -494,7 +493,7 @@ static int bus_socket_auth_verify(sd_bus *b) {
static int bus_socket_read_auth(sd_bus *b) {
struct msghdr mh;
- struct iovec iov;
+ struct iovec iov = {};
size_t n;
ssize_t k;
int r;
@@ -529,7 +528,6 @@ static int bus_socket_read_auth(sd_bus *b) {
b->rbuffer = p;
- zero(iov);
iov.iov_base = (uint8_t*) b->rbuffer + b->rbuffer_size;
iov.iov_len = n - b->rbuffer_size;
@@ -609,10 +607,10 @@ void bus_socket_setup(sd_bus *b) {
/* Enable SO_PASSCRED + SO_PASSEC. We try this on any
* socket, just in case. */
enable = !b->bus_client;
- (void)setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
+ (void) setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
enable = !b->bus_client && (b->attach_flags & KDBUS_ATTACH_SECLABEL);
- (void)setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable));
+ (void) setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable));
/* Increase the buffers to 8 MB */
fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
@@ -810,23 +808,21 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
if (bus->prefer_writev)
k = writev(bus->output_fd, iov, m->n_iovec);
else {
- struct msghdr mh;
- zero(mh);
+ struct msghdr mh = {
+ .msg_iov = iov,
+ .msg_iovlen = m->n_iovec,
+ };
if (m->n_fds > 0) {
struct cmsghdr *control;
- control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
- mh.msg_control = control;
+ mh.msg_control = control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
+ mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
control->cmsg_level = SOL_SOCKET;
control->cmsg_type = SCM_RIGHTS;
- mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds);
memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds);
}
- mh.msg_iov = iov;
- mh.msg_iovlen = m->n_iovec;
-
k = sendmsg(bus->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
if (k < 0 && errno == ENOTSOCK) {
bus->prefer_writev = true;
@@ -917,8 +913,8 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
r = bus_message_from_malloc(bus,
bus->rbuffer, size,
bus->fds, bus->n_fds,
- !bus->bus_client && bus->ucred_valid ? &bus->ucred : NULL,
- !bus->bus_client && bus->label[0] ? bus->label : NULL,
+ NULL,
+ NULL,
&t);
if (r < 0) {
free(b);
@@ -938,7 +934,7 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
int bus_socket_read_message(sd_bus *bus) {
struct msghdr mh;
- struct iovec iov;
+ struct iovec iov = {};
ssize_t k;
size_t need;
int r;
@@ -968,7 +964,6 @@ int bus_socket_read_message(sd_bus *bus) {
bus->rbuffer = b;
- zero(iov);
iov.iov_base = (uint8_t*) bus->rbuffer + bus->rbuffer_size;
iov.iov_len = need - bus->rbuffer_size;
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index 6be8310bbe..ec9340f8e1 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -20,7 +20,6 @@
***/
#include "sd-bus.h"
-#include "set.h"
#include "bus-util.h"
#include "bus-internal.h"
#include "bus-track.h"
@@ -91,6 +90,9 @@ _public_ int sd_bus_track_new(
assert_return(bus, -EINVAL);
assert_return(track, -EINVAL);
+ if (!bus->bus_client)
+ return -EINVAL;
+
t = new0(sd_bus_track, 1);
if (!t)
return -ENOMEM;
@@ -140,12 +142,11 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
return NULL;
}
-static int on_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
sd_bus_track *track = userdata;
const char *name, *old, *new;
int r;
- assert(bus);
assert(message);
assert(track);
diff --git a/src/libsystemd/sd-bus/bus-type.c b/src/libsystemd/sd-bus/bus-type.c
index b7914d15d3..6bc7b880a6 100644
--- a/src/libsystemd/sd-bus/bus-type.c
+++ b/src/libsystemd/sd-bus/bus-type.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "bus-type.h"
bool bus_type_is_valid(char c) {
diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h
index 0e507839ca..581574ab73 100644
--- a/src/libsystemd/sd-bus/bus-type.h
+++ b/src/libsystemd/sd-bus/bus-type.h
@@ -25,7 +25,6 @@
#include "macro.h"
#include "sd-bus.h"
-#include "sd-bus-protocol.h"
bool bus_type_is_valid(char c) _const_;
bool bus_type_is_valid_in_signature(char c) _const_;
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 52d4ebe611..99937799b3 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -30,21 +30,23 @@
#include "path-util.h"
#include "missing.h"
#include "set.h"
+#include "signal-util.h"
+#include "unit-name.h"
#include "sd-bus.h"
#include "bus-error.h"
+#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
#include "bus-internal.h"
-static int name_owner_change_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
sd_event *e = userdata;
- assert(bus);
assert(m);
assert(e);
- sd_bus_close(bus);
+ sd_bus_close(sd_bus_message_get_bus(m));
sd_event_exit(e, 0);
return 1;
@@ -132,7 +134,7 @@ int bus_event_loop_with_idle(
/* Fallback for dbus1 connections: we
* unregister the name and wait for the
* response to come through for it */
- if (r == -ENOTSUP) {
+ if (r == -EOPNOTSUPP) {
/* Inform the service manager that we
* are going down, so that it will
@@ -190,11 +192,35 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
return has_owner;
}
-int bus_verify_polkit(
+static int check_good_user(sd_bus_message *m, uid_t good_user) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ uid_t sender_uid;
+ int r;
+
+ assert(m);
+
+ if (good_user == UID_INVALID)
+ return 0;
+
+ r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
+ if (r < 0)
+ return r;
+
+ /* Don't trust augmented credentials for authorization */
+ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EUID) == 0, -EPERM);
+
+ r = sd_bus_creds_get_euid(creds, &sender_uid);
+ if (r < 0)
+ return r;
+
+ return sender_uid == good_user;
+}
+
+int bus_test_polkit(
sd_bus_message *call,
int capability,
const char *action,
- bool interactive,
+ uid_t good_user,
bool *_challenge,
sd_bus_error *e) {
@@ -203,6 +229,12 @@ int bus_verify_polkit(
assert(call);
assert(action);
+ /* Tests non-interactively! */
+
+ r = check_good_user(call, good_user);
+ if (r != 0)
+ return r;
+
r = sd_bus_query_sender_privilege(call, capability);
if (r < 0)
return r;
@@ -211,19 +243,13 @@ int bus_verify_polkit(
#ifdef ENABLE_POLKIT
else {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- int authorized = false, challenge = false, c;
+ int authorized = false, challenge = false;
const char *sender;
sender = sd_bus_message_get_sender(call);
if (!sender)
return -EBADMSG;
- c = sd_bus_message_get_allow_interactive_authorization(call);
- if (c < 0)
- return c;
- if (c > 0)
- interactive = true;
-
r = sd_bus_call_method(
call->bus,
"org.freedesktop.PolicyKit1",
@@ -236,7 +262,7 @@ int bus_verify_polkit(
"system-bus-name", 1, "name", "s", sender,
action,
0,
- !!interactive,
+ 0,
"");
if (r < 0) {
@@ -296,12 +322,11 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) {
free(q);
}
-static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
_cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL;
AsyncPolkitQuery *q = userdata;
int r;
- assert(bus);
assert(reply);
assert(q);
@@ -314,7 +339,7 @@ static int async_polkit_callback(sd_bus *bus, sd_bus_message *reply, void *userd
goto finish;
}
- r = q->callback(bus, q->request, q->userdata, &error_buffer);
+ r = q->callback(q->request, q->userdata, &error_buffer);
r = bus_maybe_reply_error(q->request, r, &error_buffer);
finish:
@@ -330,6 +355,7 @@ int bus_verify_polkit_async(
int capability,
const char *action,
bool interactive,
+ uid_t good_user,
Hashmap **registry,
sd_bus_error *error) {
@@ -347,6 +373,10 @@ int bus_verify_polkit_async(
assert(action);
assert(registry);
+ r = check_good_user(call, good_user);
+ if (r != 0)
+ return r;
+
#ifdef ENABLE_POLKIT
q = hashmap_get(*registry, call);
if (q) {
@@ -691,6 +721,18 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
return 1;
}
+ case SD_BUS_TYPE_INT64: {
+ int64_t i;
+
+ r = sd_bus_message_read_basic(property, type, &i);
+ if (r < 0)
+ return r;
+
+ printf("%s=%lld\n", name, (long long) i);
+
+ return 1;
+ }
+
case SD_BUS_TYPE_UINT32: {
uint32_t u;
@@ -920,7 +962,6 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
switch (type) {
case SD_BUS_TYPE_STRING: {
const char *s;
- char *str;
char **p = userdata;
r = sd_bus_message_read_basic(m, type, &s);
@@ -930,14 +971,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
if (isempty(s))
break;
- str = strdup(s);
- if (!str) {
- r = -ENOMEM;
- break;
- }
- free(*p);
- *p = str;
-
+ r = free_and_strdup(p, s);
break;
}
@@ -1002,14 +1036,14 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
return r;
}
-int bus_message_map_all_properties(sd_bus *bus,
- sd_bus_message *m,
- const struct bus_properties_map *map,
- void *userdata) {
+int bus_message_map_all_properties(
+ sd_bus_message *m,
+ const struct bus_properties_map *map,
+ void *userdata) {
+
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
- assert(bus);
assert(m);
assert(map);
@@ -1045,9 +1079,9 @@ int bus_message_map_all_properties(sd_bus *bus,
v = (uint8_t *)userdata + prop->offset;
if (map[i].set)
- r = prop->set(bus, member, m, &error, v);
+ r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v);
else
- r = map_basic(bus, member, m, &error, v);
+ r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v);
if (r < 0)
return r;
@@ -1064,22 +1098,24 @@ int bus_message_map_all_properties(sd_bus *bus,
if (r < 0)
return r;
}
+ if (r < 0)
+ return r;
return sd_bus_message_exit_container(m);
}
-int bus_message_map_properties_changed(sd_bus *bus,
- sd_bus_message *m,
- const struct bus_properties_map *map,
- void *userdata) {
+int bus_message_map_properties_changed(
+ sd_bus_message *m,
+ const struct bus_properties_map *map,
+ void *userdata) {
+
const char *member;
int r, invalidated, i;
- assert(bus);
assert(m);
assert(map);
- r = bus_message_map_all_properties(bus, m, map, userdata);
+ r = bus_message_map_all_properties(m, map, userdata);
if (r < 0)
return r;
@@ -1094,6 +1130,8 @@ int bus_message_map_properties_changed(sd_bus *bus,
++invalidated;
break;
}
+ if (r < 0)
+ return r;
r = sd_bus_message_exit_container(m);
if (r < 0)
@@ -1102,11 +1140,13 @@ int bus_message_map_properties_changed(sd_bus *bus,
return invalidated;
}
-int bus_map_all_properties(sd_bus *bus,
- const char *destination,
- const char *path,
- const struct bus_properties_map *map,
- void *userdata) {
+int bus_map_all_properties(
+ sd_bus *bus,
+ const char *destination,
+ const char *path,
+ const struct bus_properties_map *map,
+ void *userdata) {
+
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -1128,7 +1168,7 @@ int bus_map_all_properties(sd_bus *bus,
if (r < 0)
return r;
- return bus_message_map_all_properties(bus, m, map, userdata);
+ return bus_message_map_all_properties(m, map, userdata);
}
int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
@@ -1139,7 +1179,7 @@ int bus_open_transport(BusTransport transport, const char *host, bool user, sd_b
assert(bus);
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
- assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
+ assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
switch (transport) {
@@ -1174,7 +1214,7 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us
assert(bus);
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
- assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -ENOTSUP);
+ assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
switch (transport) {
@@ -1565,24 +1605,22 @@ typedef struct BusWaitForJobs {
sd_bus_slot *slot_disconnected;
} BusWaitForJobs;
-static int match_disconnected(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- assert(bus);
+static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
assert(m);
log_error("Warning! D-Bus connection terminated.");
- sd_bus_close(bus);
+ sd_bus_close(sd_bus_message_get_bus(m));
return 0;
}
-static int match_job_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char *path, *unit, *result;
BusWaitForJobs *d = userdata;
uint32_t id;
char *found;
int r;
- assert(bus);
assert(m);
assert(d);
@@ -1690,6 +1728,73 @@ static int bus_process_wait(sd_bus *bus) {
}
}
+static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
+ _cleanup_free_ char *dbus_path = NULL;
+
+ assert(d);
+ assert(d->name);
+ assert(result);
+
+ dbus_path = unit_dbus_path_from_name(d->name);
+ if (!dbus_path)
+ return -ENOMEM;
+
+ return sd_bus_get_property_string(d->bus,
+ "org.freedesktop.systemd1",
+ dbus_path,
+ "org.freedesktop.systemd1.Service",
+ "Result",
+ NULL,
+ result);
+}
+
+static const struct {
+ const char *result, *explanation;
+} explanations [] = {
+ { "resources", "a configured resource limit was exceeded" },
+ { "timeout", "a timeout was exceeded" },
+ { "exit-code", "the control process exited with error code" },
+ { "signal", "a fatal signal was delivered to the control process" },
+ { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
+ { "watchdog", "the service failed to send watchdog ping" },
+ { "start-limit", "start of the service was attempted too often" }
+};
+
+static void log_job_error_with_service_result(const char* service, const char *result) {
+ _cleanup_free_ char *service_shell_quoted = NULL;
+
+ assert(service);
+
+ service_shell_quoted = shell_maybe_quote(service);
+
+ if (!isempty(result)) {
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(explanations); ++i)
+ if (streq(result, explanations[i].result))
+ break;
+
+ if (i < ELEMENTSOF(explanations)) {
+ log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
+ service,
+ explanations[i].explanation,
+ strna(service_shell_quoted));
+
+ goto finish;
+ }
+ }
+
+ log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n",
+ service,
+ strna(service_shell_quoted));
+
+finish:
+ /* For some results maybe additional explanation is required */
+ if (streq_ptr(result, "start-limit"))
+ log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.",
+ strna(service_shell_quoted));
+}
+
static int check_wait_response(BusWaitForJobs *d, bool quiet) {
int r = 0;
@@ -1710,13 +1815,14 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) {
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
if (d->name) {
- bool quotes;
+ int q;
+ _cleanup_free_ char *result = NULL;
- quotes = chars_intersect(d->name, SHELL_NEED_QUOTES);
+ q = bus_job_get_service_result(d, &result);
+ if (q < 0)
+ log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
- log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xe\" for details.",
- d->name,
- quotes ? "'" : "", d->name, quotes ? "'" : "");
+ log_job_error_with_service_result(d->name, result);
} else
log_error("Job failed. See \"journalctl -xe\" for details.");
}
@@ -1733,7 +1839,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) {
else if (streq(d->result, "assert"))
r = -EPROTO;
else if (streq(d->result, "unsupported"))
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
r = -EIO;
@@ -1759,7 +1865,6 @@ int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) {
if (q < 0 && r == 0)
r = q;
- errno = 0;
log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
}
@@ -1785,7 +1890,17 @@ int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
return set_put_strdup(d->jobs, path);
}
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
+ int r;
+
+ r = bus_wait_for_jobs_add(d, path);
+ if (r < 0)
+ return log_oom();
+
+ return bus_wait_for_jobs(d, quiet);
+}
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
const char *type, *path, *source;
int r;
@@ -1800,6 +1915,10 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
else
log_info("Removed symlink %s.", path);
}
+
+ r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
+ if (r < 0)
+ return r;
}
if (r < 0)
return bus_log_parse_error(r);
@@ -1810,3 +1929,157 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
return 0;
}
+
+/**
+ * bus_path_encode_unique() - encode unique object path
+ * @b: bus connection or NULL
+ * @prefix: object path prefix
+ * @sender_id: unique-name of client, or NULL
+ * @external_id: external ID to be chosen by client, or NULL
+ * @ret_path: storage for encoded object path pointer
+ *
+ * Whenever we provide a bus API that allows clients to create and manage
+ * server-side objects, we need to provide a unique name for these objects. If
+ * we let the server choose the name, we suffer from a race condition: If a
+ * client creates an object asynchronously, it cannot destroy that object until
+ * it received the method reply. It cannot know the name of the new object,
+ * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
+ *
+ * Therefore, many APIs allow the client to choose the unique name for newly
+ * created objects. There're two problems to solve, though:
+ * 1) Object names are usually defined via dbus object paths, which are
+ * usually globally namespaced. Therefore, multiple clients must be able
+ * to choose unique object names without interference.
+ * 2) If multiple libraries share the same bus connection, they must be
+ * able to choose unique object names without interference.
+ * The first problem is solved easily by prefixing a name with the
+ * unique-bus-name of a connection. The server side must enforce this and
+ * reject any other name. The second problem is solved by providing unique
+ * suffixes from within sd-bus.
+ *
+ * This helper allows clients to create unique object-paths. It uses the
+ * template '/prefix/sender_id/external_id' and returns the new path in
+ * @ret_path (must be freed by the caller).
+ * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
+ * NULL, this function allocates a unique suffix via @b (by requesting a new
+ * cookie). If both @sender_id and @external_id are given, @b can be passed as
+ * NULL.
+ *
+ * Returns: 0 on success, negative error code on failure.
+ */
+int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
+ _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
+ char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
+ int r;
+
+ assert_return(b || (sender_id && external_id), -EINVAL);
+ assert_return(object_path_is_valid(prefix), -EINVAL);
+ assert_return(ret_path, -EINVAL);
+
+ if (!sender_id) {
+ r = sd_bus_get_unique_name(b, &sender_id);
+ if (r < 0)
+ return r;
+ }
+
+ if (!external_id) {
+ xsprintf(external_buf, "%"PRIu64, ++b->cookie);
+ external_id = external_buf;
+ }
+
+ sender_label = bus_label_escape(sender_id);
+ if (!sender_label)
+ return -ENOMEM;
+
+ external_label = bus_label_escape(external_id);
+ if (!external_label)
+ return -ENOMEM;
+
+ p = strjoin(prefix, "/", sender_label, "/", external_label, NULL);
+ if (!p)
+ return -ENOMEM;
+
+ *ret_path = p;
+ return 0;
+}
+
+/**
+ * bus_path_decode_unique() - decode unique object path
+ * @path: object path to decode
+ * @prefix: object path prefix
+ * @ret_sender: output parameter for sender-id label
+ * @ret_external: output parameter for external-id label
+ *
+ * This does the reverse of bus_path_encode_unique() (see its description for
+ * details). Both trailing labels, sender-id and external-id, are unescaped and
+ * returned in the given output parameters (the caller must free them).
+ *
+ * Note that this function returns 0 if the path does not match the template
+ * (see bus_path_encode_unique()), 1 if it matched.
+ *
+ * Returns: Negative error code on failure, 0 if the given object path does not
+ * match the template (return parameters are set to NULL), 1 if it was
+ * parsed successfully (return parameters contain allocated labels).
+ */
+int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
+ const char *p, *q;
+ char *sender, *external;
+
+ assert(object_path_is_valid(path));
+ assert(object_path_is_valid(prefix));
+ assert(ret_sender);
+ assert(ret_external);
+
+ p = object_path_startswith(path, prefix);
+ if (!p) {
+ *ret_sender = NULL;
+ *ret_external = NULL;
+ return 0;
+ }
+
+ q = strchr(p, '/');
+ if (!q) {
+ *ret_sender = NULL;
+ *ret_external = NULL;
+ return 0;
+ }
+
+ sender = bus_label_unescape_n(p, q - p);
+ external = bus_label_unescape(q + 1);
+ if (!sender || !external) {
+ free(sender);
+ free(external);
+ return -ENOMEM;
+ }
+
+ *ret_sender = sender;
+ *ret_external = external;
+ return 1;
+}
+
+bool is_kdbus_wanted(void) {
+ _cleanup_free_ char *value = NULL;
+ int r;
+
+ if (get_proc_cmdline_key("kdbus", NULL) <= 0) {
+ r = get_proc_cmdline_key("kdbus=", &value);
+ if (r <= 0 || parse_boolean(value) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+bool is_kdbus_available(void) {
+ _cleanup_close_ int fd = -1;
+ struct kdbus_cmd cmd = { .size = sizeof(cmd), .flags = KDBUS_FLAG_NEGOTIATE };
+
+ if (!is_kdbus_wanted())
+ return false;
+
+ fd = open("/sys/fs/kdbus/control", O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
+ if (fd < 0)
+ return false;
+
+ return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-util.h b/src/libsystemd/sd-bus/bus-util.h
index e8a97cef9e..999a372cdd 100644
--- a/src/libsystemd/sd-bus/bus-util.h
+++ b/src/libsystemd/sd-bus/bus-util.h
@@ -24,8 +24,8 @@
#include "sd-event.h"
#include "sd-bus.h"
#include "hashmap.h"
+#include "install.h"
#include "time-util.h"
-#include "util.h"
typedef enum BusTransport {
BUS_TRANSPORT_LOCAL,
@@ -46,19 +46,9 @@ struct bus_properties_map {
int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
-int bus_message_map_all_properties(sd_bus *bus,
- sd_bus_message *m,
- const struct bus_properties_map *map,
- void *userdata);
-int bus_message_map_properties_changed(sd_bus *bus,
- sd_bus_message *m,
- const struct bus_properties_map *map,
- void *userdata);
-int bus_map_all_properties(sd_bus *bus,
- const char *destination,
- const char *path,
- const struct bus_properties_map *map,
- void *userdata);
+int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map, void *userdata);
+int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, void *userdata);
+int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map, void *userdata);
int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name);
@@ -70,9 +60,9 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error);
int bus_check_peercred(sd_bus *c);
-int bus_verify_polkit(sd_bus_message *call, int capability, const char *action, bool interactive, bool *_challenge, sd_bus_error *e);
+int bus_test_polkit(sd_bus_message *call, int capability, const char *action, uid_t good_user, bool *_challenge, sd_bus_error *e);
-int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, bool interactive, Hashmap **registry, sd_bus_error *error);
+int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
void bus_verify_polkit_async_registry_free(Hashmap *registry);
int bus_open_system_systemd(sd_bus **_bus);
@@ -208,7 +198,14 @@ int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
void bus_wait_for_jobs_free(BusWaitForJobs *d);
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet);
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet);
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
+
+int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path);
+int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);
+
+bool is_kdbus_wanted(void);
+bool is_kdbus_available(void);
diff --git a/src/libsystemd/sd-bus/busctl-introspect.h b/src/libsystemd/sd-bus/busctl-introspect.h
index d6b4cf05a7..ea807d5973 100644
--- a/src/libsystemd/sd-bus/busctl-introspect.h
+++ b/src/libsystemd/sd-bus/busctl-introspect.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <stdbool.h>
typedef struct XMLIntrospectOps {
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index d3c1772019..39caa4e7d6 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -26,18 +26,17 @@
#include "log.h"
#include "build.h"
#include "pager.h"
-#include "xml.h"
#include "path-util.h"
#include "set.h"
#include "sd-bus.h"
-#include "bus-message.h"
#include "bus-internal.h"
#include "bus-util.h"
#include "bus-dump.h"
#include "bus-signature.h"
#include "bus-type.h"
#include "busctl-introspect.h"
+#include "terminal-util.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h
index 1cc475eb1d..fc1d77dd7c 100644
--- a/src/libsystemd/sd-bus/kdbus.h
+++ b/src/libsystemd/sd-bus/kdbus.h
@@ -70,14 +70,14 @@ struct kdbus_notify_name_change {
* KDBUS_ITEM_CREDS
*/
struct kdbus_creds {
- __u32 uid;
- __u32 euid;
- __u32 suid;
- __u32 fsuid;
- __u32 gid;
- __u32 egid;
- __u32 sgid;
- __u32 fsgid;
+ __u64 uid;
+ __u64 euid;
+ __u64 suid;
+ __u64 fsuid;
+ __u64 gid;
+ __u64 egid;
+ __u64 sgid;
+ __u64 fsgid;
} __attribute__((__aligned__(8)));
/**
@@ -457,24 +457,16 @@ struct kdbus_item {
} __attribute__((__aligned__(8)));
/**
- * struct kdbus_item_list - A list of items
- * @size: The total size of the structure
- * @items: Array of items
- */
-struct kdbus_item_list {
- __u64 size;
- struct kdbus_item items[0];
-} __attribute__((__aligned__(8)));
-
-/**
* enum kdbus_msg_flags - type of message
* @KDBUS_MSG_EXPECT_REPLY: Expect a reply message, used for
* method calls. The userspace-supplied
* cookie identifies the message and the
* respective reply carries the cookie
* in cookie_reply
- * @KDBUS_MSG_NO_AUTO_START: Do not start a service, if the addressed
- * name is not currently active
+ * @KDBUS_MSG_NO_AUTO_START: Do not start a service if the addressed
+ * name is not currently active. This flag is
+ * not looked at by the kernel but only
+ * serves as hint for userspace implementations.
* @KDBUS_MSG_SIGNAL: Treat this message as signal
*/
enum kdbus_msg_flags {
@@ -507,9 +499,12 @@ enum kdbus_payload_type {
* @cookie: Userspace-supplied cookie, for the connection
* to identify its messages
* @timeout_ns: The time to wait for a message reply from the peer.
- * If there is no reply, a kernel-generated message
+ * If there is no reply, and the send command is
+ * executed asynchronously, a kernel-generated message
* with an attached KDBUS_ITEM_REPLY_TIMEOUT item
- * is sent to @src_id. The timeout is expected in
+ * is sent to @src_id. For synchronously executed send
+ * command, the value denotes the maximum time the call
+ * blocks to wait for a reply. The timeout is expected in
* nanoseconds and as absolute CLOCK_MONOTONIC value.
* @cookie_reply: A reply to the requesting message with the same
* cookie. The requesting connection can match its
@@ -602,9 +597,15 @@ enum kdbus_recv_flags {
* @KDBUS_RECV_RETURN_INCOMPLETE_FDS: One or more file descriptors could not
* be installed. These descriptors in
* KDBUS_ITEM_FDS will carry the value -1.
+ * @KDBUS_RECV_RETURN_DROPPED_MSGS: There have been dropped messages since
+ * the last time a message was received.
+ * The 'dropped_msgs' counter contains the
+ * number of messages dropped pool
+ * overflows or other missed broadcasts.
*/
enum kdbus_recv_return_flags {
KDBUS_RECV_RETURN_INCOMPLETE_FDS = 1ULL << 0,
+ KDBUS_RECV_RETURN_DROPPED_MSGS = 1ULL << 1,
};
/**
@@ -614,10 +615,12 @@ enum kdbus_recv_return_flags {
* @return_flags: Command return flags, kernel → userspace
* @priority: Minimum priority of the messages to de-queue. Lowest
* values have the highest priority.
- * @dropped_msgs: In case the KDBUS_CMD_RECV ioctl returns
- * -EOVERFLOW, this field will contain the number of
- * broadcast messages that have been lost since the
- * last call.
+ * @dropped_msgs: In case there were any dropped messages since the last
+ * time a message was received, this will be set to the
+ * number of lost messages and
+ * KDBUS_RECV_RETURN_DROPPED_MSGS will be set in
+ * 'return_flags'. This can only happen if the ioctl
+ * returns 0 or EAGAIN.
* @msg: Return storage for received message.
* @items: Additional items for this command.
*
@@ -691,10 +694,10 @@ enum kdbus_hello_flags {
* @id: The ID of this connection (kernel → userspace)
* @pool_size: Size of the connection's buffer where the received
* messages are placed
- * @offset: Pool offset where additional items of type
- * kdbus_item_list are stored. They contain information
- * about the bus and the newly created connection.
- * @items_size: Copy of item_list.size stored in @offset.
+ * @offset: Pool offset where items are returned to report
+ * additional information about the bus and the newly
+ * created connection.
+ * @items_size: Size of buffer returned in the pool slice at @offset.
* @id128: Unique 128-bit ID of the bus (kernel → userspace)
* @items: A list of items
*
@@ -772,11 +775,13 @@ struct kdbus_cmd_list {
/**
* struct kdbus_cmd_info - struct used for KDBUS_CMD_CONN_INFO ioctl
* @size: The total size of the struct
- * @flags: KDBUS_ATTACH_* flags, userspace → kernel
+ * @flags: Flags for this ioctl, userspace → kernel
* @return_flags: Command return flags, kernel → userspace
* @id: The 64-bit ID of the connection. If set to zero, passing
* @name is required. kdbus will look up the name to
* determine the ID in this case.
+ * @attach_flags: Set of attach flags to specify the set of information
+ * to receive, userspace → kernel
* @offset: Returned offset in the caller's pool buffer where the
* kdbus_info struct result is stored. The user must
* use KDBUS_CMD_FREE to free the allocated memory.
@@ -794,6 +799,7 @@ struct kdbus_cmd_info {
__u64 flags;
__u64 return_flags;
__u64 id;
+ __u64 attach_flags;
__u64 offset;
__u64 info_size;
struct kdbus_item items[0];
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index cac9b65601..edc27aef87 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -20,19 +20,16 @@
***/
#include <endian.h>
-#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <poll.h>
-#include <byteswap.h>
#include <sys/mman.h>
#include <pthread.h>
#include "util.h"
#include "macro.h"
#include "strv.h"
-#include "set.h"
#include "missing.h"
#include "def.h"
#include "cgroup-util.h"
@@ -45,8 +42,6 @@
#include "bus-socket.h"
#include "bus-kernel.h"
#include "bus-control.h"
-#include "bus-introspect.h"
-#include "bus-signature.h"
#include "bus-objects.h"
#include "bus-util.h"
#include "bus-container.h"
@@ -357,13 +352,30 @@ _public_ int sd_bus_set_description(sd_bus *bus, const char *description) {
return free_and_strdup(&bus->description, description);
}
-static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+_public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ bus->allow_interactive_authorization = !!b;
+ return 0;
+}
+
+_public_ int sd_bus_get_allow_interactive_authorization(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->allow_interactive_authorization;
+}
+
+static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
const char *s;
+ sd_bus *bus;
int r;
+ assert(reply);
+ bus = reply->bus;
assert(bus);
assert(bus->state == BUS_HELLO || bus->state == BUS_CLOSING);
- assert(reply);
r = sd_bus_message_get_errno(reply);
if (r > 0)
@@ -1513,15 +1525,27 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
}
static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
+ bool remarshal = false;
+
assert(b);
- /* Do packet version and endianness already match? */
- if ((b->message_version == 0 || b->message_version == (*m)->header->version) &&
- (b->message_endian == 0 || b->message_endian == (*m)->header->endian))
- return 0;
+ /* wrong packet version */
+ if (b->message_version != 0 && b->message_version != (*m)->header->version)
+ remarshal = true;
+
+ /* wrong packet endianness */
+ if (b->message_endian != 0 && b->message_endian != (*m)->header->endian)
+ remarshal = true;
- /* No? Then remarshal! */
- return bus_message_remarshal(b, m);
+ /* TODO: kdbus-messages received from the kernel contain data which is
+ * not allowed to be passed to KDBUS_CMD_SEND. Therefore, we have to
+ * force remarshaling of the message. Technically, we could just
+ * recreate the kdbus message, but that is non-trivial as other parts of
+ * the message refer to m->kdbus already. This should be fixed! */
+ if ((*m)->kdbus && (*m)->release_kdbus)
+ remarshal = true;
+
+ return remarshal ? bus_message_remarshal(b, m) : 0;
}
int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) {
@@ -1671,8 +1695,11 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
_cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m);
int r;
- assert_return(bus, -EINVAL);
assert_return(m, -EINVAL);
+
+ if (!bus)
+ bus = m->bus;
+
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
@@ -1684,7 +1711,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
if (r < 0)
return r;
if (r == 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
/* If the cookie number isn't kept, then we know that no reply
@@ -1757,8 +1784,11 @@ _public_ int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie) {
_public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie) {
int r;
- assert_return(bus, -EINVAL);
assert_return(m, -EINVAL);
+
+ if (!bus)
+ bus = m->bus;
+
assert_return(!bus_pid_changed(bus), -ECHILD);
if (!BUS_IS_OPEN(bus->state))
@@ -1814,11 +1844,14 @@ _public_ int sd_bus_call_async(
_cleanup_bus_slot_unref_ sd_bus_slot *s = NULL;
int r;
- assert_return(bus, -EINVAL);
assert_return(m, -EINVAL);
assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
assert_return(callback, -EINVAL);
+
+ if (!bus)
+ bus = m->bus;
+
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
@@ -1912,11 +1945,14 @@ _public_ int sd_bus_call(
unsigned i;
int r;
- assert_return(bus, -EINVAL);
assert_return(m, -EINVAL);
assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
assert_return(!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED), -EINVAL);
assert_return(!bus_error_is_dirty(error), -EINVAL);
+
+ if (!bus)
+ bus = m->bus;
+
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
@@ -2171,7 +2207,7 @@ static int process_timeout(sd_bus *bus) {
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->callback;
bus->current_userdata = slot->userdata;
- r = c->callback(bus, m, slot->userdata, &error_buffer);
+ r = c->callback(m, slot->userdata, &error_buffer);
bus->current_userdata = NULL;
bus->current_handler = NULL;
bus->current_slot = NULL;
@@ -2274,7 +2310,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->callback;
bus->current_userdata = slot->userdata;
- r = c->callback(bus, m, slot->userdata, &error_buffer);
+ r = c->callback(m, slot->userdata, &error_buffer);
bus->current_userdata = NULL;
bus->current_handler = NULL;
bus->current_slot = NULL;
@@ -2321,7 +2357,7 @@ static int process_filter(sd_bus *bus, sd_bus_message *m) {
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = l->callback;
bus->current_userdata = slot->userdata;
- r = l->callback(bus, m, slot->userdata, &error_buffer);
+ r = l->callback(m, slot->userdata, &error_buffer);
bus->current_userdata = NULL;
bus->current_handler = NULL;
bus->current_slot = sd_bus_slot_unref(slot);
@@ -2602,7 +2638,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
bus->current_slot = sd_bus_slot_ref(slot);
bus->current_handler = c->callback;
bus->current_userdata = slot->userdata;
- r = c->callback(bus, m, slot->userdata, &error_buffer);
+ r = c->callback(m, slot->userdata, &error_buffer);
bus->current_userdata = NULL;
bus->current_handler = NULL;
bus->current_slot = NULL;
@@ -3376,7 +3412,7 @@ _public_ int sd_bus_try_close(sd_bus *bus) {
assert_return(!bus_pid_changed(bus), -ECHILD);
if (!bus->is_kernel)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
@@ -3477,7 +3513,7 @@ _public_ int sd_bus_get_address(sd_bus *bus, const char **address) {
return -ENODATA;
}
-int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) {
+_public_ int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) {
assert_return(bus, -EINVAL);
assert_return(mask, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
@@ -3486,35 +3522,35 @@ int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) {
return 0;
}
-int sd_bus_is_bus_client(sd_bus *bus) {
+_public_ int sd_bus_is_bus_client(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
return bus->bus_client;
}
-int sd_bus_is_server(sd_bus *bus) {
+_public_ int sd_bus_is_server(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
return bus->is_server;
}
-int sd_bus_is_anonymous(sd_bus *bus) {
+_public_ int sd_bus_is_anonymous(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
return bus->anonymous_auth;
}
-int sd_bus_is_trusted(sd_bus *bus) {
+_public_ int sd_bus_is_trusted(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
return bus->trusted;
}
-int sd_bus_is_monitor(sd_bus *bus) {
+_public_ int sd_bus_is_monitor(sd_bus *bus) {
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c
index 35f87e91bd..d14110aa04 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel-benchmark.c
+++ b/src/libsystemd/sd-bus/test-bus-benchmark.c
@@ -19,16 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <ctype.h>
#include <sys/wait.h>
+#include "def.h"
#include "util.h"
-#include "log.h"
#include "time-util.h"
#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-error.h"
#include "bus-kernel.h"
#include "bus-internal.h"
#include "bus-util.h"
@@ -37,6 +34,12 @@
static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
+typedef enum Type {
+ TYPE_KDBUS,
+ TYPE_LEGACY,
+ TYPE_DIRECT,
+} Type;
+
static void server(sd_bus *b, size_t *result) {
int r;
@@ -60,7 +63,8 @@ static void server(sd_bus *b, size_t *result) {
/* Make sure the mmap is mapped */
assert_se(sd_bus_message_read_array(m, 'y', &p, &sz) > 0);
- assert_se(sd_bus_reply_method_return(m, NULL) >= 0);
+ r = sd_bus_reply_method_return(m, NULL);
+ assert_se(r >= 0);
} else if (sd_bus_message_is_method_call(m, "benchmark.server", "Exit")) {
uint64_t res;
assert_se(sd_bus_message_read(m, "t", &res) > 0);
@@ -68,16 +72,16 @@ static void server(sd_bus *b, size_t *result) {
*result = res;
return;
- } else
+ } else if (!sd_bus_message_is_signal(m, NULL, NULL))
assert_not_reached("Unknown method");
}
}
-static void transaction(sd_bus *b, size_t sz) {
+static void transaction(sd_bus *b, size_t sz, const char *server_name) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
uint8_t *p;
- assert_se(sd_bus_message_new_method_call(b, &m, ":1.1", "/", "benchmark.server", "Work") >= 0);
+ assert_se(sd_bus_message_new_method_call(b, &m, server_name, "/", "benchmark.server", "Work") >= 0);
assert_se(sd_bus_message_append_array_space(m, 'y', sz, (void**) &p) >= 0);
memset(p, 0x80, sz);
@@ -85,7 +89,7 @@ static void transaction(sd_bus *b, size_t sz) {
assert_se(sd_bus_call(b, m, 0, NULL, &reply) >= 0);
}
-static void client_bisect(const char *address) {
+static void client_bisect(const char *address, const char *server_name) {
_cleanup_bus_message_unref_ sd_bus_message *x = NULL;
size_t lsize, rsize, csize;
sd_bus *b;
@@ -100,7 +104,8 @@ static void client_bisect(const char *address) {
r = sd_bus_start(b);
assert_se(r >= 0);
- assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
+ r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
+ assert_se(r >= 0);
lsize = 1;
rsize = MAX_SIZE;
@@ -125,7 +130,7 @@ static void client_bisect(const char *address) {
t = now(CLOCK_MONOTONIC);
for (n_copying = 0;; n_copying++) {
- transaction(b, csize);
+ transaction(b, csize, server_name);
if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
break;
}
@@ -135,7 +140,7 @@ static void client_bisect(const char *address) {
t = now(CLOCK_MONOTONIC);
for (n_memfd = 0;; n_memfd++) {
- transaction(b, csize);
+ transaction(b, csize, server_name);
if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
break;
}
@@ -151,14 +156,14 @@ static void client_bisect(const char *address) {
}
b->use_memfd = 1;
- assert_se(sd_bus_message_new_method_call(b, &x, ":1.1", "/", "benchmark.server", "Exit") >= 0);
+ assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
assert_se(sd_bus_message_append(x, "t", csize) >= 0);
assert_se(sd_bus_send(b, x, NULL) >= 0);
sd_bus_unref(b);
}
-static void client_chart(const char *address) {
+static void client_chart(Type type, const char *address, const char *server_name, int fd) {
_cleanup_bus_message_unref_ sd_bus_message *x = NULL;
size_t csize;
sd_bus *b;
@@ -167,15 +172,34 @@ static void client_chart(const char *address) {
r = sd_bus_new(&b);
assert_se(r >= 0);
- r = sd_bus_set_address(b, address);
- assert_se(r >= 0);
+ if (type == TYPE_DIRECT) {
+ r = sd_bus_set_fd(b, fd, fd);
+ assert_se(r >= 0);
+ } else {
+ r = sd_bus_set_address(b, address);
+ assert_se(r >= 0);
+
+ r = sd_bus_set_bus_client(b, true);
+ assert_se(r >= 0);
+ }
r = sd_bus_start(b);
assert_se(r >= 0);
- assert_se(sd_bus_call_method(b, ":1.1", "/", "benchmark.server", "Ping", NULL, NULL, NULL) >= 0);
+ r = sd_bus_call_method(b, server_name, "/", "benchmark.server", "Ping", NULL, NULL, NULL);
+ assert_se(r >= 0);
- printf("SIZE\tCOPY\tMEMFD\n");
+ switch (type) {
+ case TYPE_KDBUS:
+ printf("SIZE\tCOPY\tMEMFD\n");
+ break;
+ case TYPE_LEGACY:
+ printf("SIZE\tLEGACY\n");
+ break;
+ case TYPE_DIRECT:
+ printf("SIZE\tDIRECT\n");
+ break;
+ }
for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
usec_t t;
@@ -183,22 +207,24 @@ static void client_chart(const char *address) {
printf("%zu\t", csize);
- b->use_memfd = 0;
+ if (type == TYPE_KDBUS) {
+ b->use_memfd = 0;
- t = now(CLOCK_MONOTONIC);
- for (n_copying = 0;; n_copying++) {
- transaction(b, csize);
- if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
- break;
- }
+ t = now(CLOCK_MONOTONIC);
+ for (n_copying = 0;; n_copying++) {
+ transaction(b, csize, server_name);
+ if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
+ break;
+ }
- printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
+ printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
- b->use_memfd = -1;
+ b->use_memfd = -1;
+ }
t = now(CLOCK_MONOTONIC);
for (n_memfd = 0;; n_memfd++) {
- transaction(b, csize);
+ transaction(b, csize, server_name);
if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
break;
}
@@ -207,7 +233,7 @@ static void client_chart(const char *address) {
}
b->use_memfd = 1;
- assert_se(sd_bus_message_new_method_call(b, &x, ":1.1", "/", "benchmark.server", "Exit") >= 0);
+ assert_se(sd_bus_message_new_method_call(b, &x, server_name, "/", "benchmark.server", "Exit") >= 0);
assert_se(sd_bus_message_append(x, "t", csize) >= 0);
assert_se(sd_bus_send(b, x, NULL) >= 0);
@@ -219,9 +245,11 @@ int main(int argc, char *argv[]) {
MODE_BISECT,
MODE_CHART,
} mode = MODE_BISECT;
- int i;
- _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+ Type type = TYPE_KDBUS;
+ int i, pair[2] = { -1, -1 };
+ _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *server_name = NULL;
_cleanup_close_ int bus_ref = -1;
+ const char *unique;
cpu_set_t cpuset;
size_t result;
sd_bus *b;
@@ -232,33 +260,72 @@ int main(int argc, char *argv[]) {
if (streq(argv[i], "chart")) {
mode = MODE_CHART;
continue;
+ } else if (streq(argv[i], "legacy")) {
+ type = TYPE_LEGACY;
+ continue;
+ } else if (streq(argv[i], "direct")) {
+ type = TYPE_DIRECT;
+ continue;
}
assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
}
+ assert_se(!MODE_BISECT || TYPE_KDBUS);
+
assert_se(arg_loop_usec > 0);
- assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+ if (type == TYPE_KDBUS) {
+ assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+
+ bus_ref = bus_kernel_create_bus(name, false, &bus_name);
+ if (bus_ref == -ENOENT)
+ exit(EXIT_TEST_SKIP);
- bus_ref = bus_kernel_create_bus(name, false, &bus_name);
- if (bus_ref == -ENOENT)
- exit(EXIT_TEST_SKIP);
+ assert_se(bus_ref >= 0);
- assert_se(bus_ref >= 0);
+ address = strappend("kernel:path=", bus_name);
+ assert_se(address);
+ } else if (type == TYPE_LEGACY) {
+ const char *e;
- address = strappend("kernel:path=", bus_name);
- assert_se(address);
+ e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
+ assert_se(e);
+
+ address = strdup(e);
+ assert_se(address);
+ }
r = sd_bus_new(&b);
assert_se(r >= 0);
- r = sd_bus_set_address(b, address);
- assert_se(r >= 0);
+ if (type == TYPE_DIRECT) {
+ assert_se(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) >= 0);
+
+ r = sd_bus_set_fd(b, pair[0], pair[0]);
+ assert_se(r >= 0);
+
+ r = sd_bus_set_server(b, true, SD_ID128_NULL);
+ assert_se(r >= 0);
+ } else {
+ r = sd_bus_set_address(b, address);
+ assert_se(r >= 0);
+
+ r = sd_bus_set_bus_client(b, true);
+ assert_se(r >= 0);
+ }
r = sd_bus_start(b);
assert_se(r >= 0);
+ if (type != TYPE_DIRECT) {
+ r = sd_bus_get_unique_name(b, &unique);
+ assert_se(r >= 0);
+
+ server_name = strdup(unique);
+ assert_se(server_name);
+ }
+
sync();
setpriority(PRIO_PROCESS, 0, -19);
@@ -275,11 +342,11 @@ int main(int argc, char *argv[]) {
switch (mode) {
case MODE_BISECT:
- client_bisect(address);
+ client_bisect(address, server_name);
break;
case MODE_CHART:
- client_chart(address);
+ client_chart(type, address, server_name, pair[1]);
break;
}
@@ -297,6 +364,7 @@ int main(int argc, char *argv[]) {
assert_se(waitpid(pid, NULL, 0) == pid);
+ safe_close(pair[1]);
sd_bus_unref(b);
return 0;
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index 8625ee6d89..046e999008 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -27,24 +27,22 @@
#include "log.h"
#include "util.h"
#include "macro.h"
+#include "formats-util.h"
#include "sd-bus.h"
-#include "bus-message.h"
#include "bus-error.h"
#include "bus-match.h"
#include "bus-internal.h"
#include "bus-util.h"
-static int match_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
return 0;
}
-static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+static int object_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
int r;
- assert_se(bus);
-
if (sd_bus_message_is_method_error(m, NULL))
return 0;
@@ -264,11 +262,11 @@ fail:
static void* client1(void*p) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- sd_bus *bus = NULL;
- sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_close_unref_ sd_bus *bus = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *hello;
int r;
- int pp[2] = { -1, -1 };
+ _cleanup_close_pair_ int pp[2] = { -1, -1 };
char x;
r = sd_bus_open_user(&bus);
@@ -347,18 +345,12 @@ finish:
else
sd_bus_send(bus, q, NULL);
- sd_bus_flush(bus);
- sd_bus_unref(bus);
}
- sd_bus_error_free(&error);
-
- safe_close_pair(pp);
-
return INT_TO_PTR(r);
}
-static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
bool *x = userdata;
log_error("Quit callback: %s", strerror(sd_bus_message_get_errno(m)));
@@ -369,8 +361,8 @@ static int quit_callback(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_er
static void* client2(void*p) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
- sd_bus *bus = NULL;
- sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_close_unref_ sd_bus *bus = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
bool quit = false;
const char *mid;
int r;
@@ -399,8 +391,7 @@ static void* client2(void*p) {
goto finish;
}
- sd_bus_message_unref(m);
- m = NULL;
+ m = sd_bus_message_unref(m);
r = sd_bus_message_new_signal(
bus,
@@ -419,8 +410,7 @@ static void* client2(void*p) {
goto finish;
}
- sd_bus_message_unref(m);
- m = NULL;
+ m = sd_bus_message_unref(m);
r = sd_bus_message_new_method_call(
bus,
@@ -448,8 +438,7 @@ static void* client2(void*p) {
log_info("Machine ID is %s.", mid);
- sd_bus_message_unref(m);
- m = NULL;
+ m = sd_bus_message_unref(m);
r = sd_bus_message_new_method_call(
bus,
@@ -463,8 +452,7 @@ static void* client2(void*p) {
goto finish;
}
- sd_bus_message_unref(reply);
- reply = NULL;
+ reply = sd_bus_message_unref(reply);
r = sd_bus_call(bus, m, 200 * USEC_PER_MSEC, &error, &reply);
if (r < 0)
@@ -472,8 +460,7 @@ static void* client2(void*p) {
else
log_info("Slow call succeed.");
- sd_bus_message_unref(m);
- m = NULL;
+ m = sd_bus_message_unref(m);
r = sd_bus_message_new_method_call(
bus,
@@ -526,12 +513,9 @@ finish:
goto finish;
}
- sd_bus_send(bus, q, NULL);
- sd_bus_flush(bus);
- sd_bus_unref(bus);
+ (void) sd_bus_send(bus, q, NULL);
}
- sd_bus_error_free(&error);
return INT_TO_PTR(r);
}
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
index ff2602ba34..edd5033db2 100644
--- a/src/libsystemd/sd-bus/test-bus-creds.c
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -22,7 +22,6 @@
#include "sd-bus.h"
#include "bus-dump.h"
#include "bus-util.h"
-#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index 463fc81c75..5753c04b0e 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -35,11 +35,11 @@ static void test_error(void) {
};
assert_se(!sd_bus_error_is_set(&error));
- assert_se(sd_bus_error_set(&error, SD_BUS_ERROR_NOT_SUPPORTED, "xxx") == -ENOTSUP);
+ assert_se(sd_bus_error_set(&error, SD_BUS_ERROR_NOT_SUPPORTED, "xxx") == -EOPNOTSUPP);
assert_se(streq(error.name, SD_BUS_ERROR_NOT_SUPPORTED));
assert_se(streq(error.message, "xxx"));
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_NOT_SUPPORTED));
- assert_se(sd_bus_error_get_errno(&error) == ENOTSUP);
+ assert_se(sd_bus_error_get_errno(&error) == EOPNOTSUPP);
assert_se(sd_bus_error_is_set(&error));
sd_bus_error_free(&error);
diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c
index 67b6461f30..b2caa02870 100644
--- a/src/libsystemd/sd-bus/test-bus-introspect.c
+++ b/src/libsystemd/sd-bus/test-bus-introspect.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "log.h"
#include "bus-introspect.h"
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
index 071b7e0cf9..b11c43bd7b 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
@@ -23,8 +23,6 @@
#include "log.h"
#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-error.h"
#include "bus-kernel.h"
#include "bus-util.h"
diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c
index 3aec568229..6506eaab2e 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel.c
@@ -25,8 +25,6 @@
#include "log.h"
#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-error.h"
#include "bus-kernel.h"
#include "bus-util.h"
#include "bus-dump.h"
@@ -45,8 +43,6 @@ int main(int argc, char *argv[]) {
assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
- bus_kernel_fix_attach_mask();
-
bus_ref = bus_kernel_create_bus(name, false, &bus_name);
if (bus_ref == -ENOENT)
return EXIT_TEST_SKIP;
@@ -119,7 +115,7 @@ int main(int argc, char *argv[]) {
assert_se(r == -EBUSY);
r = sd_bus_process_priority(b, -10, &m);
- assert_se(r == -ENOMSG);
+ assert_se(r == 0);
r = sd_bus_process(b, &m);
assert_se(r > 0);
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index d95a03c221..f8ecadf499 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -19,9 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
-#include <byteswap.h>
#include <math.h>
#ifdef HAVE_GLIB
@@ -41,6 +39,16 @@
#include "bus-dump.h"
#include "bus-label.h"
+static void test_bus_path_encode_unique(void) {
+ _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL;
+
+ assert_se(bus_path_encode_unique(NULL, "/foo/bar", "some.sender", "a.suffix", &a) >= 0 && streq_ptr(a, "/foo/bar/some_2esender/a_2esuffix"));
+ assert_se(bus_path_decode_unique(a, "/foo/bar", &b, &c) > 0 && streq_ptr(b, "some.sender") && streq_ptr(c, "a.suffix"));
+ assert_se(bus_path_decode_unique(a, "/bar/foo", &d, &d) == 0 && !d);
+ assert_se(bus_path_decode_unique("/foo/bar/onlyOneSuffix", "/foo/bar", &d, &d) == 0 && !d);
+ assert_se(bus_path_decode_unique("/foo/bar/_/_", "/foo/bar", &d, &e) > 0 && streq_ptr(d, "") && streq_ptr(e, ""));
+}
+
static void test_bus_path_encode(void) {
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL;
@@ -359,6 +367,7 @@ int main(int argc, char *argv[]) {
test_bus_label_escape();
test_bus_path_encode();
+ test_bus_path_encode_unique();
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c
index 76ca0b6bf3..40c67046da 100644
--- a/src/libsystemd/sd-bus/test-bus-match.c
+++ b/src/libsystemd/sd-bus/test-bus-match.c
@@ -20,7 +20,6 @@
***/
#include "log.h"
-#include "util.h"
#include "macro.h"
#include "bus-match.h"
@@ -30,7 +29,7 @@
static bool mask[32];
-static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+static int filter(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
log_info("Ran %u", PTR_TO_UINT(userdata));
assert_se(PTR_TO_UINT(userdata) < ELEMENTSOF(mask));
mask[PTR_TO_UINT(userdata)] = true;
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index acf67a52b3..52952603e4 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -19,11 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
#include "log.h"
#include "util.h"
@@ -44,7 +41,7 @@ struct context {
uint32_t automatic_integer_property;
};
-static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int something_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
struct context *c = userdata;
const char *s;
char *n = NULL;
@@ -70,7 +67,7 @@ static int something_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
return 1;
}
-static int exit_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int exit_handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
struct context *c = userdata;
int r;
@@ -132,10 +129,10 @@ static int value_handler(sd_bus *bus, const char *path, const char *interface, c
return 1;
}
-static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int notify_test(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_properties_changed(bus, m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
+ assert_se(sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", "Value", NULL) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -143,10 +140,10 @@ static int notify_test(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_er
return 1;
}
-static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int notify_test2(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_properties_changed_strv(bus, m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
+ assert_se(sd_bus_emit_properties_changed_strv(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.ValueTest", NULL) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -154,10 +151,10 @@ static int notify_test2(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_e
return 1;
}
-static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int emit_interfaces_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_interfaces_added(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
+ assert_se(sd_bus_emit_interfaces_added(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -165,10 +162,10 @@ static int emit_interfaces_added(sd_bus *bus, sd_bus_message *m, void *userdata,
return 1;
}
-static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int emit_interfaces_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_interfaces_removed(bus, m->path, "org.freedesktop.systemd.test", NULL) >= 0);
+ assert_se(sd_bus_emit_interfaces_removed(sd_bus_message_get_bus(m), m->path, "org.freedesktop.systemd.test", NULL) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -176,10 +173,10 @@ static int emit_interfaces_removed(sd_bus *bus, sd_bus_message *m, void *userdat
return 1;
}
-static int emit_object_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int emit_object_added(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_object_added(bus, m->path) >= 0);
+ assert_se(sd_bus_emit_object_added(sd_bus_message_get_bus(m), m->path) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
@@ -187,10 +184,10 @@ static int emit_object_added(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
return 1;
}
-static int emit_object_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int emit_object_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int r;
- assert_se(sd_bus_emit_object_removed(bus, m->path) >= 0);
+ assert_se(sd_bus_emit_object_removed(sd_bus_message_get_bus(m), m->path) >= 0);
r = sd_bus_reply_method_return(m, NULL);
assert_se(r >= 0);
diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c
index 5f807c3b1e..080d8eddb7 100644
--- a/src/libsystemd/sd-bus/test-bus-server.c
+++ b/src/libsystemd/sd-bus/test-bus-server.c
@@ -19,11 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
#include "log.h"
#include "util.h"
@@ -31,7 +28,6 @@
#include "sd-bus.h"
#include "bus-internal.h"
-#include "bus-message.h"
#include "bus-util.h"
struct context {
diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c
index 3fc565c620..4165c9273a 100644
--- a/src/libsystemd/sd-bus/test-bus-signature.c
+++ b/src/libsystemd/sd-bus/test-bus-signature.c
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <stdlib.h>
#include "log.h"
#include "bus-signature.h"
diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c
index a054f74bf3..2d062fc9b5 100644
--- a/src/libsystemd/sd-bus/test-bus-zero-copy.c
+++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <fcntl.h>
#include <sys/mman.h>
#include "util.h"
@@ -28,7 +27,6 @@
#include "sd-bus.h"
#include "bus-message.h"
-#include "bus-error.h"
#include "bus-kernel.h"
#include "bus-dump.h"
@@ -39,6 +37,7 @@
int main(int argc, char *argv[]) {
_cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+ const char *unique;
uint8_t *p;
sd_bus *a, *b;
int r, bus_ref;
@@ -81,7 +80,10 @@ int main(int argc, char *argv[]) {
r = sd_bus_start(b);
assert_se(r >= 0);
- r = sd_bus_message_new_method_call(b, &m, ":1.1", "/a/path", "an.inter.face", "AMethod");
+ r = sd_bus_get_unique_name(a, &unique);
+ assert_se(r >= 0);
+
+ r = sd_bus_message_new_method_call(b, &m, unique, "/a/path", "an.inter.face", "AMethod");
assert_se(r >= 0);
r = sd_bus_message_open_container(m, 'r', "aysay");
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 028c2a7a5b..82ac72c72a 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -19,11 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <fcntl.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>
@@ -352,16 +350,10 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
.msg_iovlen = 1,
.msg_name = &sockaddr,
};
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * n_fds)];
- } control;
_cleanup_close_ int fd = -1;
struct cmsghdr *cmsg = NULL;
const char *e;
- size_t controllen_without_ucred = 0;
- bool try_without_ucred = false;
+ bool have_pid;
int r;
if (!state) {
@@ -400,40 +392,37 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
msghdr.msg_namelen = sizeof(struct sockaddr_un);
- if (n_fds > 0) {
- msghdr.msg_control = &control;
- msghdr.msg_controllen = CMSG_LEN(sizeof(int) * n_fds);
+ have_pid = pid != 0 && pid != getpid();
- cmsg = CMSG_FIRSTHDR(&msghdr);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
-
- memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
- }
+ if (n_fds > 0 || have_pid) {
+ msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds) +
+ CMSG_SPACE(sizeof(struct ucred) * have_pid);
+ msghdr.msg_control = alloca(msghdr.msg_controllen);
- if (pid != 0 && pid != getpid()) {
- struct ucred *ucred;
+ cmsg = CMSG_FIRSTHDR(&msghdr);
+ if (n_fds > 0) {
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * n_fds);
- try_without_ucred = true;
- controllen_without_ucred = msghdr.msg_controllen;
+ memcpy(CMSG_DATA(cmsg), fds, sizeof(int) * n_fds);
- msghdr.msg_control = &control;
- msghdr.msg_controllen += CMSG_LEN(sizeof(struct ucred));
+ if (have_pid)
+ assert_se(cmsg = CMSG_NXTHDR(&msghdr, cmsg));
+ }
- if (cmsg)
- cmsg = CMSG_NXTHDR(&msghdr, cmsg);
- else
- cmsg = CMSG_FIRSTHDR(&msghdr);
+ if (have_pid) {
+ struct ucred *ucred;
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_CREDENTIALS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDENTIALS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- ucred->pid = pid;
- ucred->uid = getuid();
- ucred->gid = getgid();
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ ucred->pid = pid;
+ ucred->uid = getuid();
+ ucred->gid = getgid();
+ }
}
/* First try with fake ucred data, as requested */
@@ -443,10 +432,10 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
}
/* If that failed, try with our own ucred instead */
- if (try_without_ucred) {
- if (controllen_without_ucred <= 0)
+ if (have_pid) {
+ msghdr.msg_controllen -= CMSG_SPACE(sizeof(struct ucred));
+ if (msghdr.msg_controllen == 0)
msghdr.msg_control = NULL;
- msghdr.msg_controllen = controllen_without_ucred;
if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) >= 0) {
r = 1;
diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h
new file mode 100644
index 0000000000..8d04640dc7
--- /dev/null
+++ b/src/libsystemd/sd-device/device-enumerator-private.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-device.h"
+
+int device_enumerator_scan_devices(sd_device_enumerator *enumeartor);
+int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor);
+int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device);
+int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
+sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
+sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
+
+#define FOREACH_DEVICE_AND_SUBSYSTEM(enumerator, device) \
+ for (device = device_enumerator_get_first(enumerator); \
+ device; \
+ device = device_enumerator_get_next(enumerator))
diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c
new file mode 100644
index 0000000000..7fd77e9480
--- /dev/null
+++ b/src/libsystemd/sd-device/device-enumerator.c
@@ -0,0 +1,983 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "prioq.h"
+#include "strv.h"
+#include "set.h"
+
+#include "sd-device.h"
+
+#include "device-util.h"
+#include "device-enumerator-private.h"
+
+#define DEVICE_ENUMERATE_MAX_DEPTH 256
+
+typedef enum DeviceEnumerationType {
+ DEVICE_ENUMERATION_TYPE_DEVICES,
+ DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
+ _DEVICE_ENUMERATION_TYPE_MAX,
+ _DEVICE_ENUMERATION_TYPE_INVALID = -1,
+} DeviceEnumerationType;
+
+struct sd_device_enumerator {
+ unsigned n_ref;
+
+ DeviceEnumerationType type;
+ Prioq *devices;
+ bool scan_uptodate;
+
+ Set *match_subsystem;
+ Set *nomatch_subsystem;
+ Hashmap *match_sysattr;
+ Hashmap *nomatch_sysattr;
+ Hashmap *match_property;
+ Set *match_sysname;
+ Set *match_tag;
+ sd_device *match_parent;
+ bool match_allow_uninitialized;
+};
+
+_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
+ _cleanup_device_enumerator_unref_ sd_device_enumerator *enumerator = NULL;
+
+ assert(ret);
+
+ enumerator = new0(sd_device_enumerator, 1);
+ if (!enumerator)
+ return -ENOMEM;
+
+ enumerator->n_ref = 1;
+ enumerator->type = _DEVICE_ENUMERATION_TYPE_INVALID;
+
+ *ret = enumerator;
+ enumerator = NULL;
+
+ return 0;
+}
+
+_public_ sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, NULL);
+
+ assert_se((++ enumerator->n_ref) >= 2);
+
+ return enumerator;
+}
+
+_public_ sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator) {
+ if (enumerator && (-- enumerator->n_ref) == 0) {
+ sd_device *device;
+
+ while ((device = prioq_pop(enumerator->devices)))
+ sd_device_unref(device);
+
+ prioq_free(enumerator->devices);
+
+ set_free_free(enumerator->match_subsystem);
+ set_free_free(enumerator->nomatch_subsystem);
+ hashmap_free_free_free(enumerator->match_sysattr);
+ hashmap_free_free_free(enumerator->nomatch_sysattr);
+ hashmap_free_free_free(enumerator->match_property);
+ set_free_free(enumerator->match_sysname);
+ set_free_free(enumerator->match_tag);
+ sd_device_unref(enumerator->match_parent);
+
+ free(enumerator);
+ }
+
+ return NULL;
+}
+
+_public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
+ Set **set;
+ int r;
+
+ assert_return(enumerator, -EINVAL);
+ assert_return(subsystem, -EINVAL);
+
+ if (match)
+ set = &enumerator->match_subsystem;
+ else
+ set = &enumerator->nomatch_subsystem;
+
+ r = set_ensure_allocated(set, NULL);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdup(*set, subsystem);
+ if (r < 0)
+ return r;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *_sysattr, const char *_value, int match) {
+ _cleanup_free_ char *sysattr = NULL, *value = NULL;
+ Hashmap **hashmap;
+ int r;
+
+ assert_return(enumerator, -EINVAL);
+ assert_return(_sysattr, -EINVAL);
+
+ if (match)
+ hashmap = &enumerator->match_sysattr;
+ else
+ hashmap = &enumerator->nomatch_sysattr;
+
+ r = hashmap_ensure_allocated(hashmap, NULL);
+ if (r < 0)
+ return r;
+
+ sysattr = strdup(_sysattr);
+ if (!sysattr)
+ return -ENOMEM;
+
+ if (_value) {
+ value = strdup(_value);
+ if (!value)
+ return -ENOMEM;
+ }
+
+ r = hashmap_put(*hashmap, sysattr, value);
+ if (r < 0)
+ return r;
+
+ sysattr = NULL;
+ value = NULL;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *_property, const char *_value) {
+ _cleanup_free_ char *property = NULL, *value = NULL;
+ int r;
+
+ assert_return(enumerator, -EINVAL);
+ assert_return(_property, -EINVAL);
+
+ r = hashmap_ensure_allocated(&enumerator->match_property, NULL);
+ if (r < 0)
+ return r;
+
+ property = strdup(_property);
+ if (!property)
+ return -ENOMEM;
+
+ if (_value) {
+ value = strdup(_value);
+ if (!value)
+ return -ENOMEM;
+ }
+
+ r = hashmap_put(enumerator->match_property, property, value);
+ if (r < 0)
+ return r;
+
+ property = NULL;
+ value = NULL;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
+ int r;
+
+ assert_return(enumerator, -EINVAL);
+ assert_return(sysname, -EINVAL);
+
+ r = set_ensure_allocated(&enumerator->match_sysname, NULL);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdup(enumerator->match_sysname, sysname);
+ if (r < 0)
+ return r;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag) {
+ int r;
+
+ assert_return(enumerator, -EINVAL);
+ assert_return(tag, -EINVAL);
+
+ r = set_ensure_allocated(&enumerator->match_tag, NULL);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdup(enumerator->match_tag, tag);
+ if (r < 0)
+ return r;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
+ assert_return(enumerator, -EINVAL);
+ assert_return(parent, -EINVAL);
+
+ sd_device_unref(enumerator->match_parent);
+ enumerator->match_parent = sd_device_ref(parent);
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+_public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, -EINVAL);
+
+ enumerator->match_allow_uninitialized = true;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, -EINVAL);
+
+ enumerator->match_allow_uninitialized = false;
+
+ enumerator->scan_uptodate = false;
+
+ return 0;
+}
+
+static int device_compare(const void *_a, const void *_b) {
+ sd_device *a = (sd_device *)_a, *b = (sd_device *)_b;
+ const char *devpath_a, *devpath_b, *sound_a;
+ bool delay_a, delay_b;
+
+ assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
+ assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
+
+ sound_a = strstr(devpath_a, "/sound/card");
+ if (sound_a) {
+ /* For sound cards the control device must be enumerated last to
+ * make sure it's the final device node that gets ACLs applied.
+ * Applications rely on this fact and use ACL changes on the
+ * control node as an indicator that the ACL change of the
+ * entire sound card completed. The kernel makes this guarantee
+ * when creating those devices, and hence we should too when
+ * enumerating them. */
+ sound_a += strlen("/sound/card");
+ sound_a = strchr(sound_a, '/');
+
+ if (sound_a) {
+ unsigned prefix_len;
+
+ prefix_len = sound_a - devpath_a;
+
+ if (strncmp(devpath_a, devpath_b, prefix_len) == 0) {
+ const char *sound_b;
+
+ sound_b = devpath_b + prefix_len;
+
+ if (startswith(sound_a, "/controlC") &&
+ !startswith(sound_b, "/contolC"))
+ return 1;
+
+ if (!startswith(sound_a, "/controlC") &&
+ startswith(sound_b, "/controlC"))
+ return -1;
+ }
+ }
+ }
+
+ /* md and dm devices are enumerated after all other devices */
+ delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-");
+ delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-");
+ if (delay_a != delay_b)
+ return delay_a - delay_b;
+
+ return strcmp(devpath_a, devpath_b);
+}
+
+int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
+ int r;
+
+ assert_return(enumerator, -EINVAL);
+ assert_return(device, -EINVAL);
+
+ r = prioq_ensure_allocated(&enumerator->devices, device_compare);
+ if (r < 0)
+ return r;
+
+ r = prioq_put(enumerator->devices, device, NULL);
+ if (r < 0)
+ return r;
+
+ sd_device_ref(device);
+
+ return 0;
+}
+
+static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) {
+ const char *value;
+ int r;
+
+ assert(device);
+ assert(sysattr);
+
+ r = sd_device_get_sysattr_value(device, sysattr, &value);
+ if (r < 0)
+ return false;
+
+ if (!match_value)
+ return true;
+
+ if (fnmatch(match_value, value, 0) == 0)
+ return true;
+
+ return false;
+}
+
+static bool match_sysattr(sd_device_enumerator *enumerator, sd_device *device) {
+ const char *sysattr;
+ const char *value;
+ Iterator i;
+
+ assert(enumerator);
+ assert(device);
+
+ HASHMAP_FOREACH_KEY(value, sysattr, enumerator->nomatch_sysattr, i)
+ if (match_sysattr_value(device, sysattr, value))
+ return false;
+
+ HASHMAP_FOREACH_KEY(value, sysattr, enumerator->match_sysattr, i)
+ if (!match_sysattr_value(device, sysattr, value))
+ return false;
+
+ return true;
+}
+
+static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
+ const char *property;
+ const char *value;
+ Iterator i;
+
+ assert(enumerator);
+ assert(device);
+
+ if (hashmap_isempty(enumerator->match_property))
+ return true;
+
+ HASHMAP_FOREACH_KEY(value, property, enumerator->match_property, i) {
+ const char *property_dev, *value_dev;
+
+ FOREACH_DEVICE_PROPERTY(device, property_dev, value_dev) {
+ if (fnmatch(property, property_dev, 0) != 0)
+ continue;
+
+ if (!value && !value_dev)
+ return true;
+
+ if (!value || !value_dev)
+ continue;
+
+ if (fnmatch(value, value_dev, 0) == 0)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
+ const char *tag;
+ Iterator i;
+
+ assert(enumerator);
+ assert(device);
+
+ SET_FOREACH(tag, enumerator->match_tag, i)
+ if (!sd_device_has_tag(device, tag))
+ return false;
+
+ return true;
+}
+
+static bool match_parent(sd_device_enumerator *enumerator, sd_device *device) {
+ const char *devpath, *devpath_dev;
+ int r;
+
+ assert(enumerator);
+ assert(device);
+
+ if (!enumerator->match_parent)
+ return true;
+
+ r = sd_device_get_devpath(enumerator->match_parent, &devpath);
+ assert(r >= 0);
+
+ r = sd_device_get_devpath(device, &devpath_dev);
+ assert(r >= 0);
+
+ return startswith(devpath_dev, devpath);
+}
+
+static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
+ const char *sysname_match;
+ Iterator i;
+
+ assert(enumerator);
+ assert(sysname);
+
+ if (set_isempty(enumerator->match_sysname))
+ return true;
+
+ SET_FOREACH(sysname_match, enumerator->match_sysname, i)
+ if (fnmatch(sysname_match, sysname, 0) == 0)
+ return true;
+
+ return false;
+}
+
+static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ char *path;
+ struct dirent *dent;
+ int r = 0;
+
+ assert(enumerator);
+ assert(basedir);
+
+ path = strjoina("/sys/", basedir, "/");
+
+ if (subdir1)
+ path = strjoina(path, subdir1, "/");
+
+ if (subdir2)
+ path = strjoina(path, subdir2, "/");
+
+ dir = opendir(path);
+ if (!dir)
+ return -errno;
+
+ FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ char syspath[strlen(path) + 1 + strlen(dent->d_name) + 1];
+ dev_t devnum;
+ int ifindex, initialized, k;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (!match_sysname(enumerator, dent->d_name))
+ continue;
+
+ (void)sprintf(syspath, "%s%s", path, dent->d_name);
+
+ k = sd_device_new_from_syspath(&device, syspath);
+ if (k < 0) {
+ if (k != -ENODEV)
+ /* this is necessarily racey, so ignore missing devices */
+ r = k;
+
+ continue;
+ }
+
+ k = sd_device_get_devnum(device, &devnum);
+ if (k < 0) {
+ r = k;
+ continue;
+ }
+
+ k = sd_device_get_ifindex(device, &ifindex);
+ if (k < 0) {
+ r = k;
+ continue;
+ }
+
+ k = sd_device_get_is_initialized(device, &initialized);
+ if (k < 0) {
+ r = k;
+ continue;
+ }
+
+ /*
+ * All devices with a device node or network interfaces
+ * possibly need udev to adjust the device node permission
+ * or context, or rename the interface before it can be
+ * reliably used from other processes.
+ *
+ * For now, we can only check these types of devices, we
+ * might not store a database, and have no way to find out
+ * for all other types of devices.
+ */
+ if (!enumerator->match_allow_uninitialized &&
+ !initialized &&
+ (major(devnum) > 0 || ifindex > 0))
+ continue;
+
+ if (!match_parent(enumerator, device))
+ continue;
+
+ if (!match_tag(enumerator, device))
+ continue;
+
+ if (!match_property(enumerator, device))
+ continue;
+
+ if (!match_sysattr(enumerator, device))
+ continue;
+
+ k = device_enumerator_add_device(enumerator, device);
+ if (k < 0)
+ r = k;
+ }
+
+ return r;
+}
+
+static bool match_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
+ const char *subsystem_match;
+ Iterator i;
+
+ assert(enumerator);
+
+ if (!subsystem)
+ return false;
+
+ SET_FOREACH(subsystem_match, enumerator->nomatch_subsystem, i)
+ if (fnmatch(subsystem_match, subsystem, 0) == 0)
+ return false;
+
+ if (set_isempty(enumerator->match_subsystem))
+ return true;
+
+ SET_FOREACH(subsystem_match, enumerator->match_subsystem, i)
+ if (fnmatch(subsystem_match, subsystem, 0) == 0)
+ return true;
+
+ return false;
+}
+
+static int enumerator_scan_dir(sd_device_enumerator *enumerator, const char *basedir, const char *subdir, const char *subsystem) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ char *path;
+ struct dirent *dent;
+ int r = 0;
+
+ path = strjoina("/sys/", basedir);
+
+ dir = opendir(path);
+ if (!dir)
+ return -errno;
+
+ log_debug(" device-enumerator: scanning %s", path);
+
+ FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+ int k;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (!match_subsystem(enumerator, subsystem ? : dent->d_name))
+ continue;
+
+ k = enumerator_scan_dir_and_add_devices(enumerator, basedir, dent->d_name, subdir);
+ if (k < 0)
+ r = k;
+ }
+
+ return r;
+}
+
+static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const char *tag) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ char *path;
+ struct dirent *dent;
+ int r = 0;
+
+ assert(enumerator);
+ assert(tag);
+
+ path = strjoina("/run/udev/tags/", tag);
+
+ dir = opendir(path);
+ if (!dir) {
+ if (errno == ENOENT)
+ return 0;
+ else {
+ log_error("sd-device-enumerator: could not open tags directory %s: %m", path);
+ return -errno;
+ }
+ }
+
+ /* TODO: filter away subsystems? */
+
+ FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ const char *subsystem, *sysname;
+ int k;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ k = sd_device_new_from_device_id(&device, dent->d_name);
+ if (k < 0) {
+ if (k != -ENODEV)
+ /* this is necessarily racy, so ignore missing devices */
+ r = k;
+
+ continue;
+ }
+
+ k = sd_device_get_subsystem(device, &subsystem);
+ if (k < 0) {
+ r = k;
+ continue;
+ }
+
+ if (!match_subsystem(enumerator, subsystem))
+ continue;
+
+ k = sd_device_get_sysname(device, &sysname);
+ if (k < 0) {
+ r = k;
+ continue;
+ }
+
+ if (!match_sysname(enumerator, sysname))
+ continue;
+
+ if (!match_parent(enumerator, device))
+ continue;
+
+ if (!match_property(enumerator, device))
+ continue;
+
+ if (!match_sysattr(enumerator, device))
+ continue;
+
+ k = device_enumerator_add_device(enumerator, device);
+ if (k < 0) {
+ r = k;
+ continue;
+ }
+ }
+
+ return r;
+}
+
+static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) {
+ const char *tag;
+ Iterator i;
+ int r;
+
+ assert(enumerator);
+
+ SET_FOREACH(tag, enumerator->match_tag, i) {
+ r = enumerator_scan_devices_tag(enumerator, tag);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int parent_add_child(sd_device_enumerator *enumerator, const char *path) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ const char *subsystem, *sysname;
+ int r;
+
+ r = sd_device_new_from_syspath(&device, path);
+ if (r == -ENODEV)
+ /* this is necessarily racy, so ignore missing devices */
+ return 0;
+ else if (r < 0)
+ return r;
+
+ r = sd_device_get_subsystem(device, &subsystem);
+ if (r < 0)
+ return r;
+
+ if (!match_subsystem(enumerator, subsystem))
+ return 0;
+
+ r = sd_device_get_sysname(device, &sysname);
+ if (r < 0)
+ return r;
+
+ if (!match_sysname(enumerator, sysname))
+ return 0;
+
+ if (!match_property(enumerator, device))
+ return 0;
+
+ if (!match_sysattr(enumerator, device))
+ return 0;
+
+ r = device_enumerator_add_device(enumerator, device);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int parent_crawl_children(sd_device_enumerator *enumerator, const char *path, unsigned maxdepth) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *dent;
+ int r = 0;
+
+ dir = opendir(path);
+ if (!dir) {
+ log_debug("sd-device-enumerate: could not open parent directory %s: %m", path);
+ return -errno;
+ }
+
+ FOREACH_DIRENT_ALL(dent, dir, return -errno) {
+ _cleanup_free_ char *child = NULL;
+ int k;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (dent->d_type != DT_DIR)
+ continue;
+
+ child = strjoin(path, "/", dent->d_name, NULL);
+ if (!child)
+ return -ENOMEM;
+
+ k = parent_add_child(enumerator, child);
+ if (k < 0)
+ r = k;
+
+ if (maxdepth > 0)
+ parent_crawl_children(enumerator, child, maxdepth - 1);
+ else
+ log_debug("device-enumerate: max depth reached, %s: ignoring devices", child);
+ }
+
+ return r;
+}
+
+static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
+ const char *path;
+ int r = 0, k;
+
+ r = sd_device_get_syspath(enumerator->match_parent, &path);
+ if (r < 0)
+ return r;
+
+ k = parent_add_child(enumerator, path);
+ if (k < 0)
+ r = k;
+
+ k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
+ if (k < 0)
+ r = k;
+
+ return r;
+}
+
+static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
+ int r = 0;
+
+ log_debug("device-enumerator: scan all dirs");
+
+ if (access("/sys/subsystem", F_OK) >= 0) {
+ /* we have /subsystem/, forget all the old stuff */
+ r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
+ if (r < 0) {
+ log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r));
+ return r;
+ }
+ } else {
+ int k;
+
+ k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
+ if (k < 0) {
+ log_debug_errno(k, "device-enumerator: failed to scan /sys/bus: %m");
+ r = k;
+ }
+
+ k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
+ if (k < 0) {
+ log_debug_errno(k, "device-enumerator: failed to scan /sys/class: %m");
+ r = k;
+ }
+ }
+
+ return r;
+}
+
+int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
+ sd_device *device;
+ int r;
+
+ assert(enumerator);
+
+ if (enumerator->scan_uptodate &&
+ enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
+ return 0;
+
+ while ((device = prioq_pop(enumerator->devices)))
+ sd_device_unref(device);
+
+ if (!set_isempty(enumerator->match_tag)) {
+ r = enumerator_scan_devices_tags(enumerator);
+ if (r < 0)
+ return r;
+ } else if (enumerator->match_parent) {
+ r = enumerator_scan_devices_children(enumerator);
+ if (r < 0)
+ return r;
+ } else {
+ r = enumerator_scan_devices_all(enumerator);
+ if (r < 0)
+ return r;
+ }
+
+ enumerator->scan_uptodate = true;
+
+ return 0;
+}
+
+_public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
+ int r;
+
+ assert_return(enumerator, NULL);
+
+ r = device_enumerator_scan_devices(enumerator);
+ if (r < 0)
+ return NULL;
+
+ enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
+
+ return prioq_peek(enumerator->devices);
+}
+
+_public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, NULL);
+
+ if (!enumerator->scan_uptodate ||
+ enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES)
+ return NULL;
+
+ sd_device_unref(prioq_pop(enumerator->devices));
+
+ return prioq_peek(enumerator->devices);
+}
+
+int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
+ sd_device *device;
+ const char *subsysdir;
+ int r = 0, k;
+
+ assert(enumerator);
+
+ if (enumerator->scan_uptodate &&
+ enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
+ return 0;
+
+ while ((device = prioq_pop(enumerator->devices)))
+ sd_device_unref(device);
+
+ /* modules */
+ if (match_subsystem(enumerator, "module")) {
+ k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
+ if (k < 0) {
+ log_debug_errno(k, "device-enumerator: failed to scan modules: %m");
+ r = k;
+ }
+ }
+
+ if (access("/sys/subsystem", F_OK) >= 0)
+ subsysdir = "subsystem";
+ else
+ subsysdir = "bus";
+
+ /* subsystems (only buses support coldplug) */
+ if (match_subsystem(enumerator, "subsystem")) {
+ k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
+ if (k < 0) {
+ log_debug_errno(k, "device-enumerator: failed to scan subsystems: %m");
+ r = k;
+ }
+ }
+
+ /* subsystem drivers */
+ if (match_subsystem(enumerator, "drivers")) {
+ k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
+ if (k < 0) {
+ log_debug_errno(k, "device-enumerator: failed to scan drivers: %m");
+ r = k;
+ }
+ }
+
+ enumerator->scan_uptodate = true;
+
+ return r;
+}
+
+_public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
+ int r;
+
+ assert_return(enumerator, NULL);
+
+ r = device_enumerator_scan_subsystems(enumerator);
+ if (r < 0)
+ return NULL;
+
+ enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
+
+ return prioq_peek(enumerator->devices);
+}
+
+_public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, NULL);
+
+ if (enumerator->scan_uptodate ||
+ enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
+ return NULL;
+
+ sd_device_unref(prioq_pop(enumerator->devices));
+
+ return prioq_peek(enumerator->devices);
+}
+
+sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, NULL);
+
+ return prioq_peek(enumerator->devices);
+}
+
+sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
+ assert_return(enumerator, NULL);
+
+ sd_device_unref(prioq_pop(enumerator->devices));
+
+ return prioq_peek(enumerator->devices);
+}
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h
new file mode 100644
index 0000000000..b96441de56
--- /dev/null
+++ b/src/libsystemd/sd-device/device-internal.h
@@ -0,0 +1,126 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "hashmap.h"
+#include "set.h"
+
+struct sd_device {
+ uint64_t n_ref;
+
+ sd_device *parent;
+ bool parent_set; /* no need to try to reload parent */
+
+ OrderedHashmap *properties;
+ Iterator properties_iterator;
+ uint64_t properties_generation; /* changes whenever the properties are changed */
+ uint64_t properties_iterator_generation; /* generation when iteration was started */
+
+ /* the subset of the properties that should be written to the db*/
+ OrderedHashmap *properties_db;
+
+ Hashmap *sysattr_values; /* cached sysattr values */
+
+ Set *sysattrs; /* names of sysattrs */
+ Iterator sysattrs_iterator;
+ bool sysattrs_read; /* don't try to re-read sysattrs once read */
+
+ Set *tags;
+ Iterator tags_iterator;
+ uint64_t tags_generation; /* changes whenever the tags are changed */
+ uint64_t tags_iterator_generation; /* generation when iteration was started */
+ bool property_tags_outdated; /* need to update TAGS= property */
+
+ Set *devlinks;
+ Iterator devlinks_iterator;
+ uint64_t devlinks_generation; /* changes whenever the devlinks are changed */
+ uint64_t devlinks_iterator_generation; /* generation when iteration was started */
+ bool property_devlinks_outdated; /* need to update DEVLINKS= property */
+ int devlink_priority;
+
+ char **properties_strv; /* the properties hashmap as a strv */
+ uint8_t *properties_nulstr; /* the same as a nulstr */
+ size_t properties_nulstr_len;
+ bool properties_buf_outdated; /* need to reread hashmap */
+
+ int watch_handle;
+
+ char *syspath;
+ const char *devpath;
+ const char *sysnum;
+ char *sysname;
+ bool sysname_set; /* don't reread sysname */
+
+ char *devtype;
+ int ifindex;
+ char *devname;
+ dev_t devnum;
+
+ char *subsystem;
+ bool subsystem_set; /* don't reread subsystem */
+ char *driver;
+ bool driver_set; /* don't reread driver */
+
+ char *id_filename;
+
+ bool is_initialized;
+ uint64_t usec_initialized;
+
+ mode_t devmode;
+ uid_t devuid;
+ gid_t devgid;
+
+ bool uevent_loaded; /* don't reread uevent */
+ bool db_loaded; /* don't reread db */
+
+ bool sealed; /* don't read more information from uevent/db */
+ bool db_persist; /* don't clean up the db when switching from initrd to real root */
+};
+
+typedef enum DeviceAction {
+ DEVICE_ACTION_ADD,
+ DEVICE_ACTION_REMOVE,
+ DEVICE_ACTION_CHANGE,
+ DEVICE_ACTION_MOVE,
+ DEVICE_ACTION_ONLINE,
+ DEVICE_ACTION_OFFLINE,
+ _DEVICE_ACTION_MAX,
+ _DEVICE_ACTION_INVALID = -1,
+} DeviceAction;
+
+int device_new_aux(sd_device **ret);
+int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db);
+int device_add_property_internal(sd_device *device, const char *key, const char *value);
+int device_read_uevent_file(sd_device *device);
+int device_read_db_aux(sd_device *device, bool force);
+
+int device_set_syspath(sd_device *device, const char *_syspath, bool verify);
+int device_set_ifindex(sd_device *device, const char *ifindex);
+int device_set_devmode(sd_device *device, const char *devmode);
+int device_set_devname(sd_device *device, const char *_devname);
+int device_set_devtype(sd_device *device, const char *_devtype);
+int device_set_devnum(sd_device *device, const char *major, const char *minor);
+int device_set_subsystem(sd_device *device, const char *_subsystem);
+int device_set_driver(sd_device *device, const char *_driver);
+int device_set_usec_initialized(sd_device *device, const char *initialized);
+
+DeviceAction device_action_from_string(const char *s) _pure_;
+const char *device_action_to_string(DeviceAction a) _const_;
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
new file mode 100644
index 0000000000..2e60433246
--- /dev/null
+++ b/src/libsystemd/sd-device/device-private.c
@@ -0,0 +1,1117 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <net/if.h>
+
+#include "util.h"
+#include "macro.h"
+#include "refcnt.h"
+#include "path-util.h"
+#include "strxcpyx.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "set.h"
+#include "strv.h"
+#include "mkdir.h"
+
+#include "sd-device.h"
+
+#include "device-util.h"
+#include "device-internal.h"
+#include "device-private.h"
+
+int device_add_property(sd_device *device, const char *key, const char *value) {
+ int r;
+
+ assert(device);
+ assert(key);
+
+ r = device_add_property_aux(device, key, value, false);
+ if (r < 0)
+ return r;
+
+ if (key[0] != '.') {
+ r = device_add_property_aux(device, key, value, true);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int device_add_property_internal_from_string(sd_device *device, const char *str) {
+ _cleanup_free_ char *key = NULL;
+ char *value;
+
+ assert(device);
+ assert(str);
+
+ key = strdup(str);
+ if (!key)
+ return -ENOMEM;
+
+ value = strchr(key, '=');
+ if (!value)
+ return -EINVAL;
+
+ *value = '\0';
+
+ if (isempty(++value))
+ value = NULL;
+
+ return device_add_property_internal(device, key, value);
+}
+
+static int handle_db_line(sd_device *device, char key, const char *value) {
+ char *path;
+ int r;
+
+ assert(device);
+ assert(value);
+
+ switch (key) {
+ case 'S':
+ path = strjoina("/dev/", value);
+ r = device_add_devlink(device, path);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'L':
+ r = safe_atoi(value, &device->devlink_priority);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'E':
+ r = device_add_property_internal_from_string(device, value);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'G':
+ r = device_add_tag(device, value);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'W':
+ r = safe_atoi(value, &device->watch_handle);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'I':
+ r = device_set_usec_initialized(device, value);
+ if (r < 0)
+ return r;
+
+ break;
+ default:
+ log_debug("device db: unknown key '%c'", key);
+ }
+
+ return 0;
+}
+
+void device_set_devlink_priority(sd_device *device, int priority) {
+ assert(device);
+
+ device->devlink_priority = priority;
+}
+
+void device_set_is_initialized(sd_device *device) {
+ assert(device);
+
+ device->is_initialized = true;
+}
+
+int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
+ char num[DECIMAL_STR_MAX(usec_t)];
+ usec_t usec_initialized;
+ int r;
+
+ assert(device);
+
+ if (device_old && device_old->usec_initialized > 0)
+ usec_initialized = device_old->usec_initialized;
+ else
+ usec_initialized = now(CLOCK_MONOTONIC);
+
+ r = snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
+ if (r < 0)
+ return -errno;
+
+ r = device_set_usec_initialized(device, num);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int device_read_db(sd_device *device) {
+ _cleanup_free_ char *db = NULL;
+ char *path;
+ const char *id, *value;
+ char key;
+ size_t db_len;
+ unsigned i;
+ int r;
+
+ enum {
+ PRE_KEY,
+ KEY,
+ PRE_VALUE,
+ VALUE,
+ INVALID_LINE,
+ } state = PRE_KEY;
+
+ assert(device);
+
+ if (device->db_loaded || device->sealed)
+ return 0;
+
+ r = device_get_id_filename(device, &id);
+ if (r < 0)
+ return r;
+
+ path = strjoina("/run/udev/data/", id);
+
+ r = read_full_file(path, &db, &db_len);
+ if (r < 0) {
+ if (r == -ENOENT)
+ return 0;
+ else {
+ log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
+ return r;
+ }
+ }
+
+ /* devices with a database entry are initialized */
+ device_set_is_initialized(device);
+
+ for (i = 0; i < db_len; i++) {
+ switch (state) {
+ case PRE_KEY:
+ if (!strchr(NEWLINE, db[i])) {
+ key = db[i];
+
+ state = KEY;
+ }
+
+ break;
+ case KEY:
+ if (db[i] != ':') {
+ log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
+
+ state = INVALID_LINE;
+ } else {
+ db[i] = '\0';
+
+ state = PRE_VALUE;
+ }
+
+ break;
+ case PRE_VALUE:
+ value = &db[i];
+
+ state = VALUE;
+
+ break;
+ case INVALID_LINE:
+ if (strchr(NEWLINE, db[i]))
+ state = PRE_KEY;
+
+ break;
+ case VALUE:
+ if (strchr(NEWLINE, db[i])) {
+ db[i] = '\0';
+ r = handle_db_line(device, key, value);
+ if (r < 0)
+ log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
+
+ state = PRE_KEY;
+ }
+
+ break;
+ default:
+ assert_not_reached("invalid state when parsing db");
+ }
+ }
+
+ device->db_loaded = true;
+
+ return 0;
+}
+
+uint64_t device_get_properties_generation(sd_device *device) {
+ assert(device);
+
+ return device->properties_generation;
+}
+
+uint64_t device_get_tags_generation(sd_device *device) {
+ assert(device);
+
+ return device->tags_generation;
+}
+
+uint64_t device_get_devlinks_generation(sd_device *device) {
+ assert(device);
+
+ return device->devlinks_generation;
+}
+
+int device_get_devnode_mode(sd_device *device, mode_t *mode) {
+ int r;
+
+ assert(device);
+ assert(mode);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ *mode = device->devmode;
+
+ return 0;
+}
+
+int device_get_devnode_uid(sd_device *device, uid_t *uid) {
+ int r;
+
+ assert(device);
+ assert(uid);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ *uid = device->devuid;
+
+ return 0;
+}
+
+static int device_set_devuid(sd_device *device, const char *uid) {
+ unsigned u;
+ int r;
+
+ assert(device);
+ assert(uid);
+
+ r = safe_atou(uid, &u);
+ if (r < 0)
+ return r;
+
+ r = device_add_property_internal(device, "DEVUID", uid);
+ if (r < 0)
+ return r;
+
+ device->devuid = u;
+
+ return 0;
+}
+
+int device_get_devnode_gid(sd_device *device, gid_t *gid) {
+ int r;
+
+ assert(device);
+ assert(gid);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ *gid = device->devgid;
+
+ return 0;
+}
+
+static int device_set_devgid(sd_device *device, const char *gid) {
+ unsigned g;
+ int r;
+
+ assert(device);
+ assert(gid);
+
+ r = safe_atou(gid, &g);
+ if (r < 0)
+ return r;
+
+ r = device_add_property_internal(device, "DEVGID", gid);
+ if (r < 0)
+ return r;
+
+ device->devgid = g;
+
+ return 0;
+}
+
+static int device_amend(sd_device *device, const char *key, const char *value) {
+ int r;
+
+ assert(device);
+ assert(key);
+ assert(value);
+
+ if (streq(key, "DEVPATH")) {
+ char *path;
+
+ path = strjoina("/sys", value);
+
+ /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
+ r = device_set_syspath(device, path, false);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set syspath to '%s': %m", path);
+ } else if (streq(key, "SUBSYSTEM")) {
+ r = device_set_subsystem(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set subsystem to '%s': %m", value);
+ } else if (streq(key, "DEVTYPE")) {
+ r = device_set_devtype(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devtype to '%s': %m", value);
+ } else if (streq(key, "DEVNAME")) {
+ r = device_set_devname(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devname to '%s': %m", value);
+ } else if (streq(key, "USEC_INITIALIZED")) {
+ r = device_set_usec_initialized(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set usec-initialized to '%s': %m", value);
+ } else if (streq(key, "DRIVER")) {
+ r = device_set_driver(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set driver to '%s': %m", value);
+ } else if (streq(key, "IFINDEX")) {
+ r = device_set_ifindex(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set ifindex to '%s': %m", value);
+ } else if (streq(key, "DEVMODE")) {
+ r = device_set_devmode(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devmode to '%s': %m", value);
+ } else if (streq(key, "DEVUID")) {
+ r = device_set_devuid(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devuid to '%s': %m", value);
+ } else if (streq(key, "DEVGID")) {
+ r = device_set_devgid(device, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devgid to '%s': %m", value);
+ } else if (streq(key, "DEVLINKS")) {
+ const char *word, *state;
+ size_t l;
+
+ FOREACH_WORD(word, l, value, state) {
+ char devlink[l + 1];
+
+ strncpy(devlink, word, l);
+ devlink[l] = '\0';
+
+ r = device_add_devlink(device, devlink);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not add devlink '%s': %m", devlink);
+ }
+ } else if (streq(key, "TAGS")) {
+ const char *word, *state;
+ size_t l;
+
+ FOREACH_WORD_SEPARATOR(word, l, value, ":", state) {
+ char tag[l + 1];
+
+ (void)strncpy(tag, word, l);
+ tag[l] = '\0';
+
+ r = device_add_tag(device, tag);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not add tag '%s': %m", tag);
+ }
+ } else {
+ r = device_add_property_internal(device, key, value);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not add property '%s=%s': %m", key, value);
+ }
+
+ return 0;
+}
+
+static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
+ [DEVICE_ACTION_ADD] = "add",
+ [DEVICE_ACTION_REMOVE] = "remove",
+ [DEVICE_ACTION_CHANGE] = "change",
+ [DEVICE_ACTION_MOVE] = "move",
+ [DEVICE_ACTION_ONLINE] = "online",
+ [DEVICE_ACTION_OFFLINE] = "offline",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
+
+static int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
+ DeviceAction *_action) {
+ DeviceAction action = _DEVICE_ACTION_INVALID;
+ uint64_t seqnum = 0;
+ const char *major = NULL, *minor = NULL;
+ char *value;
+ int r;
+
+ assert(device);
+ assert(key);
+ assert(_major);
+ assert(_minor);
+ assert(_seqnum);
+ assert(_action);
+
+ value = strchr(key, '=');
+ if (!value) {
+ log_debug("sd-device: not a key-value pair: '%s'", key);
+ return -EINVAL;
+ }
+
+ *value = '\0';
+
+ value++;
+
+ if (streq(key, "MAJOR"))
+ major = value;
+ else if (streq(key, "MINOR"))
+ minor = value;
+ else {
+ if (streq(key, "ACTION")) {
+ action = device_action_from_string(value);
+ if (action == _DEVICE_ACTION_INVALID)
+ return -EINVAL;
+ } else if (streq(key, "SEQNUM")) {
+ r = safe_atou64(value, &seqnum);
+ if (r < 0)
+ return r;
+ else if (seqnum == 0)
+ /* kernel only sends seqnum > 0 */
+ return -EINVAL;
+ }
+
+ r = device_amend(device, key, value);
+ if (r < 0)
+ return r;
+ }
+
+ if (major != 0)
+ *_major = major;
+
+ if (minor != 0)
+ *_minor = minor;
+
+ if (action != _DEVICE_ACTION_INVALID)
+ *_action = action;
+
+ if (seqnum > 0)
+ *_seqnum = seqnum;
+
+ return 0;
+}
+
+void device_seal(sd_device *device) {
+ assert(device);
+
+ device->sealed = true;
+}
+
+static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
+ assert(device);
+
+ if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) {
+ log_debug("sd-device: device created from strv lacks devpath, subsystem, action or seqnum");
+ return -EINVAL;
+ }
+
+ device->sealed = true;
+
+ return 0;
+}
+
+int device_new_from_strv(sd_device **ret, char **strv) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ char **key;
+ const char *major = NULL, *minor = NULL;
+ DeviceAction action = _DEVICE_ACTION_INVALID;
+ uint64_t seqnum;
+ int r;
+
+ assert(ret);
+ assert(strv);
+
+ r = device_new_aux(&device);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(key, strv) {
+ r = device_append(device, *key, &major, &minor, &seqnum, &action);
+ if (r < 0)
+ return r;
+ }
+
+ if (major) {
+ r = device_set_devnum(device, major, minor);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
+ }
+
+ r = device_verify(device, action, seqnum);
+ if (r < 0)
+ return r;
+
+ *ret = device;
+ device = NULL;
+
+ return 0;
+}
+
+int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ const char *major = NULL, *minor = NULL;
+ DeviceAction action = _DEVICE_ACTION_INVALID;
+ uint64_t seqnum;
+ unsigned i = 0;
+ int r;
+
+ assert(ret);
+ assert(nulstr);
+ assert(len);
+
+ r = device_new_aux(&device);
+ if (r < 0)
+ return r;
+
+ while (i < len) {
+ char *key;
+ const char *end;
+
+ key = (char*)&nulstr[i];
+ end = memchr(key, '\0', len - i);
+ if (!end) {
+ log_debug("sd-device: failed to parse nulstr");
+ return -EINVAL;
+ }
+ i += end - key + 1;
+
+ r = device_append(device, key, &major, &minor, &seqnum, &action);
+ if (r < 0)
+ return r;
+ }
+
+ if (major) {
+ r = device_set_devnum(device, major, minor);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set devnum %s:%s: %m", major, minor);
+ }
+
+ r = device_verify(device, action, seqnum);
+ if (r < 0)
+ return r;
+
+ *ret = device;
+ device = NULL;
+
+ return 0;
+}
+
+static int device_update_properties_bufs(sd_device *device) {
+ const char *val, *prop;
+ _cleanup_free_ char **buf_strv = NULL;
+ _cleanup_free_ uint8_t *buf_nulstr = NULL;
+ size_t allocated_nulstr = 0;
+ size_t nulstr_len = 0, num = 0, i = 0;
+
+ assert(device);
+
+ if (!device->properties_buf_outdated)
+ return 0;
+
+ FOREACH_DEVICE_PROPERTY(device, prop, val) {
+ size_t len = 0;
+
+ len = strlen(prop) + 1 + strlen(val);
+
+ buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
+ if (!buf_nulstr)
+ return -ENOMEM;
+
+ strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
+ nulstr_len += len + 1;
+ ++num;
+ }
+
+ /* build buf_strv from buf_nulstr */
+ buf_strv = new0(char *, num + 1);
+ if (!buf_strv)
+ return -ENOMEM;
+
+ NULSTR_FOREACH(val, (char*) buf_nulstr) {
+ buf_strv[i] = (char *) val;
+ assert(i < num);
+ i++;
+ }
+
+ free(device->properties_nulstr);
+ device->properties_nulstr = buf_nulstr;
+ buf_nulstr = NULL;
+ device->properties_nulstr_len = nulstr_len;
+ free(device->properties_strv);
+ device->properties_strv = buf_strv;
+ buf_strv = NULL;
+
+ device->properties_buf_outdated = false;
+
+ return 0;
+}
+
+int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
+ int r;
+
+ assert(device);
+ assert(nulstr);
+ assert(len);
+
+ r = device_update_properties_bufs(device);
+ if (r < 0)
+ return r;
+
+ *nulstr = device->properties_nulstr;
+ *len = device->properties_nulstr_len;
+
+ return 0;
+}
+
+int device_get_properties_strv(sd_device *device, char ***strv) {
+ int r;
+
+ assert(device);
+ assert(strv);
+
+ r = device_update_properties_bufs(device);
+ if (r < 0)
+ return r;
+
+ *strv = device->properties_strv;
+
+ return 0;
+}
+
+int device_get_devlink_priority(sd_device *device, int *priority) {
+ int r;
+
+ assert(device);
+ assert(priority);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ *priority = device->devlink_priority;
+
+ return 0;
+}
+
+int device_get_watch_handle(sd_device *device, int *handle) {
+ int r;
+
+ assert(device);
+ assert(handle);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ *handle = device->watch_handle;
+
+ return 0;
+}
+
+void device_set_watch_handle(sd_device *device, int handle) {
+ assert(device);
+
+ device->watch_handle = handle;
+}
+
+int device_rename(sd_device *device, const char *name) {
+ _cleanup_free_ char *dirname = NULL;
+ char *new_syspath;
+ const char *interface;
+ int r;
+
+ assert(device);
+ assert(name);
+
+ dirname = dirname_malloc(device->syspath);
+ if (!dirname)
+ return -ENOMEM;
+
+ new_syspath = strjoina(dirname, "/", name);
+
+ /* the user must trust that the new name is correct */
+ r = device_set_syspath(device, new_syspath, false);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_property_value(device, "INTERFACE", &interface);
+ if (r >= 0) {
+ r = device_add_property_internal(device, "INTERFACE", name);
+ if (r < 0)
+ return r;
+
+ /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
+ r = device_add_property_internal(device, "INTERFACE_OLD", interface);
+ if (r < 0)
+ return r;
+ } else if (r != -ENOENT)
+ return r;
+
+ return 0;
+}
+
+int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
+ _cleanup_device_unref_ sd_device *ret = NULL;
+ int r;
+
+ assert(old_device);
+ assert(new_device);
+
+ r = device_new_aux(&ret);
+ if (r < 0)
+ return r;
+
+ r = device_set_syspath(ret, old_device->syspath, false);
+ if (r < 0)
+ return r;
+
+ r = device_set_subsystem(ret, old_device->subsystem);
+ if (r < 0)
+ return r;
+
+ ret->devnum = old_device->devnum;
+
+ *new_device = ret;
+ ret = NULL;
+
+ return 0;
+}
+
+int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
+ _cleanup_device_unref_ sd_device *ret = NULL;
+ int r;
+
+ assert(old_device);
+ assert(new_device);
+
+ r = device_shallow_clone(old_device, &ret);
+ if (r < 0)
+ return r;
+
+ r = device_read_db(ret);
+ if (r < 0)
+ return r;
+
+ ret->sealed = true;
+
+ *new_device = ret;
+ ret = NULL;
+
+ return 0;
+}
+
+int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
+ _cleanup_device_unref_ sd_device *ret = NULL;
+ int r;
+
+ assert(new_device);
+ assert(syspath);
+ assert(action);
+
+ r = sd_device_new_from_syspath(&ret, syspath);
+ if (r < 0)
+ return r;
+
+ r = device_read_uevent_file(ret);
+ if (r < 0)
+ return r;
+
+ r = device_add_property_internal(ret, "ACTION", action);
+ if (r < 0)
+ return r;
+
+ *new_device = ret;
+ ret = NULL;
+
+ return 0;
+}
+
+int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
+ const char *property, *value;
+ int r;
+
+ assert(device_dst);
+ assert(device_src);
+
+ FOREACH_DEVICE_PROPERTY(device_src, property, value) {
+ r = device_add_property(device_dst, property, value);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+void device_cleanup_tags(sd_device *device) {
+ assert(device);
+
+ set_free_free(device->tags);
+ device->tags = NULL;
+ device->property_tags_outdated = true;
+ device->tags_generation ++;
+}
+
+void device_cleanup_devlinks(sd_device *device) {
+ assert(device);
+
+ set_free_free(device->devlinks);
+ device->devlinks = NULL;
+ device->property_devlinks_outdated = true;
+ device->devlinks_generation ++;
+}
+
+void device_remove_tag(sd_device *device, const char *tag) {
+ assert(device);
+ assert(tag);
+
+ free(set_remove(device->tags, tag));
+ device->property_tags_outdated = true;
+ device->tags_generation ++;
+}
+
+static int device_tag(sd_device *device, const char *tag, bool add) {
+ const char *id;
+ char *path;
+ int r;
+
+ assert(device);
+ assert(tag);
+
+ r = device_get_id_filename(device, &id);
+ if (r < 0)
+ return r;
+
+ path = strjoina("/run/udev/tags/", tag, "/", id);
+
+ if (add) {
+ r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
+ if (r < 0)
+ return r;
+ } else {
+ r = unlink(path);
+ if (r < 0 && errno != ENOENT)
+ return -errno;
+ }
+
+ return 0;
+}
+
+int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
+ const char *tag;
+ int r = 0, k;
+
+ if (add && device_old) {
+ /* delete possible left-over tags */
+ FOREACH_DEVICE_TAG(device_old, tag) {
+ if (!sd_device_has_tag(device, tag)) {
+ k = device_tag(device_old, tag, false);
+ if (r >= 0 && k < 0)
+ r = k;
+ }
+ }
+ }
+
+ FOREACH_DEVICE_TAG(device, tag) {
+ k = device_tag(device, tag, add);
+ if (r >= 0 && k < 0)
+ r = k;
+ }
+
+ return r;
+}
+
+static bool device_has_info(sd_device *device) {
+ assert(device);
+
+ if (!set_isempty(device->devlinks))
+ return true;
+
+ if (device->devlink_priority != 0)
+ return true;
+
+ if (!ordered_hashmap_isempty(device->properties_db))
+ return true;
+
+ if (!set_isempty(device->tags))
+ return true;
+
+ if (device->watch_handle >= 0)
+ return true;
+
+ return false;
+}
+
+void device_set_db_persist(sd_device *device) {
+ assert(device);
+
+ device->db_persist = true;
+}
+
+int device_update_db(sd_device *device) {
+ const char *id;
+ char *path;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *path_tmp = NULL;
+ bool has_info;
+ int r;
+
+ assert(device);
+
+ has_info = device_has_info(device);
+
+ r = device_get_id_filename(device, &id);
+ if (r < 0)
+ return r;
+
+ path = strjoina("/run/udev/data/", id);
+
+ /* do not store anything for otherwise empty devices */
+ if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
+ r = unlink(path);
+ if (r < 0 && errno != ENOENT)
+ return -errno;
+
+ return 0;
+ }
+
+ /* write a database file */
+ r = mkdir_parents(path, 0755);
+ if (r < 0)
+ return r;
+
+ r = fopen_temporary(path, &f, &path_tmp);
+ if (r < 0)
+ return r;
+
+ /*
+ * set 'sticky' bit to indicate that we should not clean the
+ * database when we transition from initramfs to the real root
+ */
+ if (device->db_persist) {
+ r = fchmod(fileno(f), 01644);
+ if (r < 0) {
+ r = -errno;
+ goto fail;
+ }
+ } else {
+ r = fchmod(fileno(f), 0644);
+ if (r < 0) {
+ r = -errno;
+ goto fail;
+ }
+ }
+
+ if (has_info) {
+ const char *property, *value, *tag;
+ Iterator i;
+
+ if (major(device->devnum) > 0) {
+ const char *devlink;
+
+ FOREACH_DEVICE_DEVLINK(device, devlink)
+ fprintf(f, "S:%s\n", devlink + strlen("/dev/"));
+
+ if (device->devlink_priority != 0)
+ fprintf(f, "L:%i\n", device->devlink_priority);
+
+ if (device->watch_handle >= 0)
+ fprintf(f, "W:%i\n", device->watch_handle);
+ }
+
+ if (device->usec_initialized > 0)
+ fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
+
+ ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
+ fprintf(f, "E:%s=%s\n", property, value);
+
+ FOREACH_DEVICE_TAG(device, tag)
+ fprintf(f, "G:%s\n", tag);
+ }
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ goto fail;
+
+ r = rename(path_tmp, path);
+ if (r < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
+ path, device->devpath);
+
+ return 0;
+
+fail:
+ log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty",
+ path, device->devpath);
+ unlink(path);
+ unlink(path_tmp);
+
+ return r;
+}
+
+int device_delete_db(sd_device *device) {
+ const char *id;
+ char *path;
+ int r;
+
+ assert(device);
+
+ r = device_get_id_filename(device, &id);
+ if (r < 0)
+ return r;
+
+ path = strjoina("/run/udev/data/", id);
+
+ r = unlink(path);
+ if (r < 0 && errno != ENOENT)
+ return -errno;
+
+ return 0;
+}
+
+int device_read_db_force(sd_device *device) {
+ assert(device);
+
+ return device_read_db_aux(device, true);
+}
diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
new file mode 100644
index 0000000000..49a7b66a2b
--- /dev/null
+++ b/src/libsystemd/sd-device/device-private.h
@@ -0,0 +1,64 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
+int device_new_from_strv(sd_device **ret, char **strv);
+
+int device_get_id_filename(sd_device *device, const char **ret);
+
+int device_get_devlink_priority(sd_device *device, int *priority);
+int device_get_watch_handle(sd_device *device, int *handle);
+int device_get_devnode_mode(sd_device *device, mode_t *mode);
+int device_get_devnode_uid(sd_device *device, uid_t *uid);
+int device_get_devnode_gid(sd_device *device, gid_t *gid);
+
+void device_seal(sd_device *device);
+void device_set_is_initialized(sd_device *device);
+void device_set_watch_handle(sd_device *device, int fd);
+void device_set_db_persist(sd_device *device);
+void device_set_devlink_priority(sd_device *device, int priority);
+int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
+int device_add_devlink(sd_device *device, const char *devlink);
+int device_add_property(sd_device *device, const char *property, const char *value);
+int device_add_tag(sd_device *device, const char *tag);
+void device_remove_tag(sd_device *device, const char *tag);
+void device_cleanup_tags(sd_device *device);
+void device_cleanup_devlinks(sd_device *device);
+
+uint64_t device_get_properties_generation(sd_device *device);
+uint64_t device_get_tags_generation(sd_device *device);
+uint64_t device_get_devlinks_generation(sd_device *device);
+
+int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len);
+int device_get_properties_strv(sd_device *device, char ***strv);
+
+int device_rename(sd_device *device, const char *name);
+int device_shallow_clone(sd_device *old_device, sd_device **new_device);
+int device_clone_with_db(sd_device *old_device, sd_device **new_device);
+int device_copy_properties(sd_device *device_dst, sd_device *device_src);
+int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action);
+
+int device_tag_index(sd_device *dev, sd_device *dev_old, bool add);
+int device_update_db(sd_device *device);
+int device_delete_db(sd_device *device);
+int device_read_db_force(sd_device *device);
diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h
new file mode 100644
index 0000000000..9b05a2498d
--- /dev/null
+++ b/src/libsystemd/sd-device/device-util.h
@@ -0,0 +1,60 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device*, sd_device_unref);
+#define _cleanup_device_unref_ _cleanup_(sd_device_unrefp)
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device_enumerator*, sd_device_enumerator_unref);
+#define _cleanup_device_enumerator_unref_ _cleanup_(sd_device_enumerator_unrefp)
+
+#define FOREACH_DEVICE_PROPERTY(device, key, value) \
+ for (key = sd_device_get_property_first(device, &(value)); \
+ key; \
+ key = sd_device_get_property_next(device, &(value)))
+
+#define FOREACH_DEVICE_TAG(device, tag) \
+ for (tag = sd_device_get_tag_first(device); \
+ tag; \
+ tag = sd_device_get_tag_next(device))
+
+#define FOREACH_DEVICE_SYSATTR(device, attr) \
+ for (attr = sd_device_get_sysattr_first(device); \
+ attr; \
+ attr = sd_device_get_sysattr_next(device))
+
+#define FOREACH_DEVICE_DEVLINK(device, devlink) \
+ for (devlink = sd_device_get_devlink_first(device); \
+ devlink; \
+ devlink = sd_device_get_devlink_next(device))
+
+#define FOREACH_DEVICE(enumerator, device) \
+ for (device = sd_device_enumerator_get_device_first(enumerator); \
+ device; \
+ device = sd_device_enumerator_get_device_next(enumerator))
+
+#define FOREACH_SUBSYSTEM(enumerator, device) \
+ for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
+ device; \
+ device = sd_device_enumerator_get_subsystem_next(enumerator))
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
new file mode 100644
index 0000000000..8e63b9ef56
--- /dev/null
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -0,0 +1,1839 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <net/if.h>
+
+#include "util.h"
+#include "macro.h"
+#include "path-util.h"
+#include "strxcpyx.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "set.h"
+#include "strv.h"
+
+#include "sd-device.h"
+
+#include "device-util.h"
+#include "device-private.h"
+#include "device-internal.h"
+
+int device_new_aux(sd_device **ret) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+
+ assert(ret);
+
+ device = new0(sd_device, 1);
+ if (!device)
+ return -ENOMEM;
+
+ device->n_ref = 1;
+ device->watch_handle = -1;
+
+ *ret = device;
+ device = NULL;
+
+ return 0;
+}
+
+_public_ sd_device *sd_device_ref(sd_device *device) {
+ if (device)
+ assert_se(++ device->n_ref >= 2);
+
+ return device;
+}
+
+_public_ sd_device *sd_device_unref(sd_device *device) {
+ if (device && -- device->n_ref == 0) {
+ sd_device_unref(device->parent);
+ free(device->syspath);
+ free(device->sysname);
+ free(device->devtype);
+ free(device->devname);
+ free(device->subsystem);
+ free(device->driver);
+ free(device->id_filename);
+ free(device->properties_strv);
+ free(device->properties_nulstr);
+
+ ordered_hashmap_free_free_free(device->properties);
+ ordered_hashmap_free_free_free(device->properties_db);
+ hashmap_free_free_free(device->sysattr_values);
+ set_free_free(device->sysattrs);
+ set_free_free(device->tags);
+ set_free_free(device->devlinks);
+
+ free(device);
+ }
+
+ return NULL;
+}
+
+int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
+ OrderedHashmap **properties;
+
+ assert(device);
+ assert(_key);
+
+ if (db)
+ properties = &device->properties_db;
+ else
+ properties = &device->properties;
+
+ if (_value) {
+ _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
+ int r;
+
+ r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ key = strdup(_key);
+ if (!key)
+ return -ENOMEM;
+
+ value = strdup(_value);
+ if (!value)
+ return -ENOMEM;
+
+ old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
+
+ r = ordered_hashmap_replace(*properties, key, value);
+ if (r < 0)
+ return r;
+
+ key = NULL;
+ value = NULL;
+ } else {
+ _cleanup_free_ char *key = NULL;
+ _cleanup_free_ char *value = NULL;
+
+ value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
+ }
+
+ if (!db) {
+ device->properties_generation ++;
+ device->properties_buf_outdated = true;
+ }
+
+ return 0;
+}
+
+int device_add_property_internal(sd_device *device, const char *key, const char *value) {
+ return device_add_property_aux(device, key, value, false);
+}
+
+int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
+ _cleanup_free_ char *syspath = NULL;
+ const char *devpath;
+ int r;
+
+ assert(device);
+ assert(_syspath);
+
+ /* must be a subdirectory of /sys */
+ if (!path_startswith(_syspath, "/sys/")) {
+ log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
+ return -EINVAL;
+ }
+
+ if (verify) {
+ r = readlink_and_canonicalize(_syspath, &syspath);
+ if (r == -ENOENT)
+ /* the device does not exist (any more?) */
+ return -ENODEV;
+ else if (r == -EINVAL) {
+ /* not a symlink */
+ syspath = canonicalize_file_name(_syspath);
+ if (!syspath) {
+ if (errno == ENOENT)
+ /* the device does not exist (any more?) */
+ return -ENODEV;
+
+ log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
+ return -errno;
+ }
+ } else if (r < 0) {
+ log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
+ return r;
+ }
+
+ if (path_startswith(syspath, "/sys/devices/")) {
+ char *path;
+
+ /* all 'devices' require an 'uevent' file */
+ path = strjoina(syspath, "/uevent");
+ r = access(path, F_OK);
+ if (r < 0) {
+ if (errno == ENOENT)
+ /* this is not a valid device */
+ return -ENODEV;
+
+ log_debug("sd-device: %s does not have an uevent file: %m", syspath);
+ return -errno;
+ }
+ } else {
+ /* everything else just just needs to be a directory */
+ if (!is_dir(syspath, false))
+ return -ENODEV;
+ }
+ } else {
+ syspath = strdup(_syspath);
+ if (!syspath)
+ return -ENOMEM;
+ }
+
+ devpath = syspath + strlen("/sys");
+
+ r = device_add_property_internal(device, "DEVPATH", devpath);
+ if (r < 0)
+ return r;
+
+ free(device->syspath);
+ device->syspath = syspath;
+ syspath = NULL;
+
+ device->devpath = devpath;
+
+ return 0;
+}
+
+_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(syspath, -EINVAL);
+
+ r = device_new_aux(&device);
+ if (r < 0)
+ return r;
+
+ r = device_set_syspath(device, syspath, true);
+ if (r < 0)
+ return r;
+
+ *ret = device;
+ device = NULL;
+
+ return 0;
+}
+
+_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
+ char *syspath;
+ char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
+
+ assert_return(ret, -EINVAL);
+ assert_return(type == 'b' || type == 'c', -EINVAL);
+
+ /* use /sys/dev/{block,char}/<maj>:<min> link */
+ snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
+
+ syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
+
+ return sd_device_new_from_syspath(ret, syspath);
+}
+
+_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
+ char *syspath;
+
+ assert_return(ret, -EINVAL);
+ assert_return(subsystem, -EINVAL);
+ assert_return(sysname, -EINVAL);
+
+ if (streq(subsystem, "subsystem")) {
+ syspath = strjoina("/sys/subsystem/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+
+ syspath = strjoina("/sys/bus/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+
+ syspath = strjoina("/sys/class/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+ } else if (streq(subsystem, "module")) {
+ syspath = strjoina("/sys/module/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+ } else if (streq(subsystem, "drivers")) {
+ char subsys[PATH_MAX];
+ char *driver;
+
+ strscpy(subsys, sizeof(subsys), sysname);
+ driver = strchr(subsys, ':');
+ if (driver) {
+ driver[0] = '\0';
+ driver++;
+
+ syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+
+ syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+ } else
+ return -EINVAL;
+ } else {
+ syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+
+ syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+
+ syspath = strjoina("/sys/class/", subsystem, "/", sysname);
+ if (access(syspath, F_OK) >= 0)
+ return sd_device_new_from_syspath(ret, syspath);
+ }
+
+ return -ENODEV;
+}
+
+int device_set_devtype(sd_device *device, const char *_devtype) {
+ _cleanup_free_ char *devtype = NULL;
+ int r;
+
+ assert(device);
+ assert(_devtype);
+
+ devtype = strdup(_devtype);
+ if (!devtype)
+ return -ENOMEM;
+
+ r = device_add_property_internal(device, "DEVTYPE", devtype);
+ if (r < 0)
+ return r;
+
+ free(device->devtype);
+ device->devtype = devtype;
+ devtype = NULL;
+
+ return 0;
+}
+
+int device_set_ifindex(sd_device *device, const char *_ifindex) {
+ int ifindex, r;
+
+ assert(device);
+ assert(_ifindex);
+
+ r = safe_atoi(_ifindex, &ifindex);
+ if (r < 0)
+ return r;
+
+ if (ifindex <= 0)
+ return -EINVAL;
+
+ r = device_add_property_internal(device, "IFINDEX", _ifindex);
+ if (r < 0)
+ return r;
+
+ device->ifindex = ifindex;
+
+ return 0;
+}
+
+int device_set_devname(sd_device *device, const char *_devname) {
+ _cleanup_free_ char *devname = NULL;
+ int r;
+
+ assert(device);
+ assert(_devname);
+
+ if (_devname[0] != '/') {
+ r = asprintf(&devname, "/dev/%s", _devname);
+ if (r < 0)
+ return -ENOMEM;
+ } else {
+ devname = strdup(_devname);
+ if (!devname)
+ return -ENOMEM;
+ }
+
+ r = device_add_property_internal(device, "DEVNAME", devname);
+ if (r < 0)
+ return r;
+
+ free(device->devname);
+ device->devname = devname;
+ devname = NULL;
+
+ return 0;
+}
+
+int device_set_devmode(sd_device *device, const char *_devmode) {
+ unsigned devmode;
+ int r;
+
+ assert(device);
+ assert(_devmode);
+
+ r = safe_atou(_devmode, &devmode);
+ if (r < 0)
+ return r;
+
+ if (devmode > 07777)
+ return -EINVAL;
+
+ r = device_add_property_internal(device, "DEVMODE", _devmode);
+ if (r < 0)
+ return r;
+
+ device->devmode = devmode;
+
+ return 0;
+}
+
+int device_set_devnum(sd_device *device, const char *major, const char *minor) {
+ unsigned maj = 0, min = 0;
+ int r;
+
+ assert(device);
+ assert(major);
+
+ r = safe_atou(major, &maj);
+ if (r < 0)
+ return r;
+ if (!maj)
+ return 0;
+
+ if (minor) {
+ r = safe_atou(minor, &min);
+ if (r < 0)
+ return r;
+ }
+
+ r = device_add_property_internal(device, "MAJOR", major);
+ if (r < 0)
+ return r;
+
+ if (minor) {
+ r = device_add_property_internal(device, "MINOR", minor);
+ if (r < 0)
+ return r;
+ }
+
+ device->devnum = makedev(maj, min);
+
+ return 0;
+}
+
+static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
+ int r;
+
+ assert(device);
+ assert(key);
+ assert(value);
+ assert(major);
+ assert(minor);
+
+ if (streq(key, "DEVTYPE")) {
+ r = device_set_devtype(device, value);
+ if (r < 0)
+ return r;
+ } else if (streq(key, "IFINDEX")) {
+ r = device_set_ifindex(device, value);
+ if (r < 0)
+ return r;
+ } else if (streq(key, "DEVNAME")) {
+ r = device_set_devname(device, value);
+ if (r < 0)
+ return r;
+ } else if (streq(key, "DEVMODE")) {
+ r = device_set_devmode(device, value);
+ if (r < 0)
+ return r;
+ } else if (streq(key, "MAJOR"))
+ *major = value;
+ else if (streq(key, "MINOR"))
+ *minor = value;
+ else {
+ r = device_add_property_internal(device, key, value);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int device_read_uevent_file(sd_device *device) {
+ _cleanup_free_ char *uevent = NULL;
+ const char *syspath, *key, *value, *major = NULL, *minor = NULL;
+ char *path;
+ size_t uevent_len;
+ unsigned i;
+ int r;
+
+ enum {
+ PRE_KEY,
+ KEY,
+ PRE_VALUE,
+ VALUE,
+ INVALID_LINE,
+ } state = PRE_KEY;
+
+ assert(device);
+
+ if (device->uevent_loaded || device->sealed)
+ return 0;
+
+ device->uevent_loaded = true;
+
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0)
+ return r;
+
+ path = strjoina(syspath, "/uevent");
+
+ r = read_full_file(path, &uevent, &uevent_len);
+ if (r == -EACCES)
+ /* empty uevent files may be write-only */
+ return 0;
+ else if (r == -ENOENT)
+ /* some devices may not have uevent files, see set_syspath() */
+ return 0;
+ else if (r < 0) {
+ log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
+ return r;
+ }
+
+ for (i = 0; i < uevent_len; i++) {
+ switch (state) {
+ case PRE_KEY:
+ if (!strchr(NEWLINE, uevent[i])) {
+ key = &uevent[i];
+
+ state = KEY;
+ }
+
+ break;
+ case KEY:
+ if (uevent[i] == '=') {
+ uevent[i] = '\0';
+
+ state = PRE_VALUE;
+ } else if (strchr(NEWLINE, uevent[i])) {
+ uevent[i] = '\0';
+ log_debug("sd-device: ignoring invalid uevent line '%s'", key);
+
+ state = PRE_KEY;
+ }
+
+ break;
+ case PRE_VALUE:
+ value = &uevent[i];
+
+ state = VALUE;
+
+ break;
+ case VALUE:
+ if (strchr(NEWLINE, uevent[i])) {
+ uevent[i] = '\0';
+
+ r = handle_uevent_line(device, key, value, &major, &minor);
+ if (r < 0)
+ log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
+
+ state = PRE_KEY;
+ }
+
+ break;
+ default:
+ assert_not_reached("invalid state when parsing uevent file");
+ }
+ }
+
+ if (major) {
+ r = device_set_devnum(device, major, minor);
+ if (r < 0)
+ log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
+ }
+
+ return 0;
+}
+
+_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(ifindex, -EINVAL);
+
+ r = device_read_uevent_file(device);
+ if (r < 0)
+ return r;
+
+ *ifindex = device->ifindex;
+
+ return 0;
+}
+
+_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(id, -EINVAL);
+
+ switch (id[0]) {
+ case 'b':
+ case 'c':
+ {
+ char type;
+ int maj, min;
+
+ r = sscanf(id, "%c%i:%i", &type, &maj, &min);
+ if (r != 3)
+ return -EINVAL;
+
+ return sd_device_new_from_devnum(ret, type, makedev(maj, min));
+ }
+ case 'n':
+ {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ _cleanup_close_ int sk = -1;
+ struct ifreq ifr = {};
+ int ifindex;
+
+ r = safe_atoi(&id[1], &ifr.ifr_ifindex);
+ if (r < 0)
+ return r;
+ else if (ifr.ifr_ifindex <= 0)
+ return -EINVAL;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -errno;
+
+ r = ioctl(sk, SIOCGIFNAME, &ifr);
+ if (r < 0)
+ return -errno;
+
+ r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_ifindex(device, &ifindex);
+ if (r < 0)
+ return r;
+
+ /* this is racey, so we might end up with the wrong device */
+ if (ifr.ifr_ifindex != ifindex)
+ return -ENODEV;
+
+ *ret = device;
+ device = NULL;
+
+ return 0;
+ }
+ case '+':
+ {
+ char subsys[PATH_MAX];
+ char *sysname;
+
+ (void)strscpy(subsys, sizeof(subsys), id + 1);
+ sysname = strchr(subsys, ':');
+ if (!sysname)
+ return -EINVAL;
+
+ sysname[0] = '\0';
+ sysname ++;
+
+ return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
+ assert_return(device, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ assert(path_startswith(device->syspath, "/sys/"));
+
+ *ret = device->syspath;
+
+ return 0;
+}
+
+static int device_new_from_child(sd_device **ret, sd_device *child) {
+ _cleanup_free_ char *path = NULL;
+ const char *subdir, *syspath;
+ int r;
+
+ assert(ret);
+ assert(child);
+
+ r = sd_device_get_syspath(child, &syspath);
+ if (r < 0)
+ return r;
+
+ path = strdup(syspath);
+ if (!path)
+ return -ENOMEM;
+ subdir = path + strlen("/sys");
+
+ for (;;) {
+ char *pos;
+
+ pos = strrchr(subdir, '/');
+ if (!pos || pos < subdir + 2)
+ break;
+
+ *pos = '\0';
+
+ r = sd_device_new_from_syspath(ret, path);
+ if (r < 0)
+ continue;
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
+
+ assert_return(ret, -EINVAL);
+ assert_return(child, -EINVAL);
+
+ if (!child->parent_set) {
+ child->parent_set = true;
+
+ (void)device_new_from_child(&child->parent, child);
+ }
+
+ if (!child->parent)
+ return -ENOENT;
+
+ *ret = child->parent;
+
+ return 0;
+}
+
+int device_set_subsystem(sd_device *device, const char *_subsystem) {
+ _cleanup_free_ char *subsystem = NULL;
+ int r;
+
+ assert(device);
+ assert(_subsystem);
+
+ subsystem = strdup(_subsystem);
+ if (!subsystem)
+ return -ENOMEM;
+
+ r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
+ if (r < 0)
+ return r;
+
+ free(device->subsystem);
+ device->subsystem = subsystem;
+ subsystem = NULL;
+
+ device->subsystem_set = true;
+
+ return 0;
+}
+
+_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
+ assert_return(ret, -EINVAL);
+ assert_return(device, -EINVAL);
+
+ if (!device->subsystem_set) {
+ _cleanup_free_ char *subsystem = NULL;
+ const char *syspath;
+ char *path;
+ int r;
+
+ /* read 'subsystem' link */
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0)
+ return r;
+
+ path = strjoina(syspath, "/subsystem");
+ r = readlink_value(path, &subsystem);
+ if (r >= 0)
+ r = device_set_subsystem(device, subsystem);
+ /* use implicit names */
+ else if (path_startswith(device->devpath, "/module/"))
+ r = device_set_subsystem(device, "module");
+ else if (strstr(device->devpath, "/drivers/"))
+ r = device_set_subsystem(device, "drivers");
+ else if (path_startswith(device->devpath, "/subsystem/") ||
+ path_startswith(device->devpath, "/class/") ||
+ path_startswith(device->devpath, "/bus/"))
+ r = device_set_subsystem(device, "subsystem");
+ if (r < 0 && r != -ENOENT)
+ return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
+
+ device->subsystem_set = true;
+ }
+
+ *ret = device->subsystem;
+
+ return 0;
+}
+
+_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
+ int r;
+
+ assert(devtype);
+ assert(device);
+
+ r = device_read_uevent_file(device);
+ if (r < 0)
+ return r;
+
+ *devtype = device->devtype;
+
+ return 0;
+}
+
+_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
+ sd_device *parent = NULL;
+ int r;
+
+ assert_return(child, -EINVAL);
+ assert_return(subsystem, -EINVAL);
+
+ r = sd_device_get_parent(child, &parent);
+ while (r >= 0) {
+ const char *parent_subsystem = NULL;
+ const char *parent_devtype = NULL;
+
+ (void)sd_device_get_subsystem(parent, &parent_subsystem);
+ if (streq_ptr(parent_subsystem, subsystem)) {
+ if (!devtype)
+ break;
+
+ (void)sd_device_get_devtype(parent, &parent_devtype);
+ if (streq_ptr(parent_devtype, devtype))
+ break;
+ }
+ r = sd_device_get_parent(parent, &parent);
+ }
+
+ if (r < 0)
+ return r;
+
+ *ret = parent;
+
+ return 0;
+}
+
+_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(devnum, -EINVAL);
+
+ r = device_read_uevent_file(device);
+ if (r < 0)
+ return r;
+
+ *devnum = device->devnum;
+
+ return 0;
+}
+
+int device_set_driver(sd_device *device, const char *_driver) {
+ _cleanup_free_ char *driver = NULL;
+ int r;
+
+ assert(device);
+ assert(_driver);
+
+ driver = strdup(_driver);
+ if (!driver)
+ return -ENOMEM;
+
+ r = device_add_property_internal(device, "DRIVER", driver);
+ if (r < 0)
+ return r;
+
+ free(device->driver);
+ device->driver = driver;
+ driver = NULL;
+
+ device->driver_set = true;
+
+ return 0;
+}
+
+_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
+ assert_return(device, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!device->driver_set) {
+ _cleanup_free_ char *driver = NULL;
+ const char *syspath;
+ char *path;
+ int r;
+
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0)
+ return r;
+
+ path = strjoina(syspath, "/driver");
+ r = readlink_value(path, &driver);
+ if (r >= 0) {
+ r = device_set_driver(device, driver);
+ if (r < 0)
+ return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
+ } else if (r == -ENOENT)
+ device->driver_set = true;
+ else
+ return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
+ }
+
+ *ret = device->driver;
+
+ return 0;
+}
+
+_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
+ assert_return(device, -EINVAL);
+ assert_return(devpath, -EINVAL);
+
+ assert(device->devpath);
+ assert(device->devpath[0] == '/');
+
+ *devpath = device->devpath;
+
+ return 0;
+}
+
+_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(devname, -EINVAL);
+
+ r = device_read_uevent_file(device);
+ if (r < 0)
+ return r;
+
+ if (!device->devname)
+ return -ENOENT;
+
+ assert(path_startswith(device->devname, "/dev/"));
+
+ *devname = device->devname;
+
+ return 0;
+}
+
+static int device_set_sysname(sd_device *device) {
+ _cleanup_free_ char *sysname = NULL;
+ const char *sysnum = NULL;
+ const char *pos;
+ size_t len = 0;
+
+ pos = strrchr(device->devpath, '/');
+ if (!pos)
+ return -EINVAL;
+ pos ++;
+
+ /* devpath is not a root directory */
+ if (*pos == '\0' || pos <= device->devpath)
+ return -EINVAL;
+
+ sysname = strdup(pos);
+ if (!sysname)
+ return -ENOMEM;
+
+ /* some devices have '!' in their name, change that to '/' */
+ while (sysname[len] != '\0') {
+ if (sysname[len] == '!')
+ sysname[len] = '/';
+
+ len ++;
+ }
+
+ /* trailing number */
+ while (len > 0 && isdigit(sysname[--len]))
+ sysnum = &sysname[len];
+
+ if (len == 0)
+ sysnum = NULL;
+
+ free(device->sysname);
+ device->sysname = sysname;
+ sysname = NULL;
+
+ device->sysnum = sysnum;
+
+ device->sysname_set = true;
+
+ return 0;
+}
+
+_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!device->sysname_set) {
+ r = device_set_sysname(device);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = device->sysname;
+
+ return 0;
+}
+
+_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!device->sysname_set) {
+ r = device_set_sysname(device);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = device->sysnum;
+
+ return 0;
+}
+
+static bool is_valid_tag(const char *tag) {
+ assert(tag);
+
+ return !strchr(tag, ':') && !strchr(tag, ' ');
+}
+
+int device_add_tag(sd_device *device, const char *tag) {
+ int r;
+
+ assert(device);
+ assert(tag);
+
+ if (!is_valid_tag(tag))
+ return -EINVAL;
+
+ r = set_ensure_allocated(&device->tags, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdup(device->tags, tag);
+ if (r < 0)
+ return r;
+
+ device->tags_generation ++;
+ device->property_tags_outdated = true;
+
+ return 0;
+}
+
+int device_add_devlink(sd_device *device, const char *devlink) {
+ int r;
+
+ assert(device);
+ assert(devlink);
+
+ r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdup(device->devlinks, devlink);
+ if (r < 0)
+ return r;
+
+ device->devlinks_generation ++;
+ device->property_devlinks_outdated = true;
+
+ return 0;
+}
+
+static int device_add_property_internal_from_string(sd_device *device, const char *str) {
+ _cleanup_free_ char *key = NULL;
+ char *value;
+
+ assert(device);
+ assert(str);
+
+ key = strdup(str);
+ if (!key)
+ return -ENOMEM;
+
+ value = strchr(key, '=');
+ if (!value)
+ return -EINVAL;
+
+ *value = '\0';
+
+ if (isempty(++value))
+ value = NULL;
+
+ return device_add_property_internal(device, key, value);
+}
+
+int device_set_usec_initialized(sd_device *device, const char *initialized) {
+ uint64_t usec_initialized;
+ int r;
+
+ assert(device);
+ assert(initialized);
+
+ r = safe_atou64(initialized, &usec_initialized);
+ if (r < 0)
+ return r;
+
+ r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
+ if (r < 0)
+ return r;
+
+ device->usec_initialized = usec_initialized;
+
+ return 0;
+}
+
+static int handle_db_line(sd_device *device, char key, const char *value) {
+ char *path;
+ int r;
+
+ assert(device);
+ assert(value);
+
+ switch (key) {
+ case 'G':
+ r = device_add_tag(device, value);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'S':
+ path = strjoina("/dev/", value);
+ r = device_add_devlink(device, path);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'E':
+ r = device_add_property_internal_from_string(device, value);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'I':
+ r = device_set_usec_initialized(device, value);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'L':
+ r = safe_atoi(value, &device->devlink_priority);
+ if (r < 0)
+ return r;
+
+ break;
+ case 'W':
+ r = safe_atoi(value, &device->watch_handle);
+ if (r < 0)
+ return r;
+
+ break;
+ default:
+ log_debug("device db: unknown key '%c'", key);
+ }
+
+ return 0;
+}
+
+int device_get_id_filename(sd_device *device, const char **ret) {
+ assert(device);
+ assert(ret);
+
+ if (!device->id_filename) {
+ _cleanup_free_ char *id = NULL;
+ const char *subsystem;
+ dev_t devnum;
+ int ifindex, r;
+
+ r = sd_device_get_subsystem(device, &subsystem);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_devnum(device, &devnum);
+ if (r < 0)
+ return r;
+
+ r = sd_device_get_ifindex(device, &ifindex);
+ if (r < 0)
+ return r;
+
+ if (major(devnum) > 0) {
+ assert(subsystem);
+
+ /* use dev_t -- b259:131072, c254:0 */
+ r = asprintf(&id, "%c%u:%u",
+ streq(subsystem, "block") ? 'b' : 'c',
+ major(devnum), minor(devnum));
+ if (r < 0)
+ return -ENOMEM;
+ } else if (ifindex > 0) {
+ /* use netdev ifindex -- n3 */
+ r = asprintf(&id, "n%u", ifindex);
+ if (r < 0)
+ return -ENOMEM;
+ } else {
+ /* use $subsys:$sysname -- pci:0000:00:1f.2
+ * sysname() has '!' translated, get it from devpath
+ */
+ const char *sysname;
+
+ sysname = basename(device->devpath);
+ if (!sysname)
+ return -EINVAL;
+
+ if (!subsystem)
+ return -EINVAL;
+
+ r = asprintf(&id, "+%s:%s", subsystem, sysname);
+ if (r < 0)
+ return -ENOMEM;
+ }
+
+ device->id_filename = id;
+ id = NULL;
+ }
+
+ *ret = device->id_filename;
+
+ return 0;
+}
+
+int device_read_db_aux(sd_device *device, bool force) {
+ _cleanup_free_ char *db = NULL;
+ char *path;
+ const char *id, *value;
+ char key;
+ size_t db_len;
+ unsigned i;
+ int r;
+
+ enum {
+ PRE_KEY,
+ KEY,
+ PRE_VALUE,
+ VALUE,
+ INVALID_LINE,
+ } state = PRE_KEY;
+
+ if (device->db_loaded || (!force && device->sealed))
+ return 0;
+
+ device->db_loaded = true;
+
+ r = device_get_id_filename(device, &id);
+ if (r < 0)
+ return r;
+
+ path = strjoina("/run/udev/data/", id);
+
+ r = read_full_file(path, &db, &db_len);
+ if (r < 0) {
+ if (r == -ENOENT)
+ return 0;
+ else {
+ log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
+ return r;
+ }
+ }
+
+ /* devices with a database entry are initialized */
+ device->is_initialized = true;
+
+ for (i = 0; i < db_len; i++) {
+ switch (state) {
+ case PRE_KEY:
+ if (!strchr(NEWLINE, db[i])) {
+ key = db[i];
+
+ state = KEY;
+ }
+
+ break;
+ case KEY:
+ if (db[i] != ':') {
+ log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
+
+ state = INVALID_LINE;
+ } else {
+ db[i] = '\0';
+
+ state = PRE_VALUE;
+ }
+
+ break;
+ case PRE_VALUE:
+ value = &db[i];
+
+ state = VALUE;
+
+ break;
+ case INVALID_LINE:
+ if (strchr(NEWLINE, db[i]))
+ state = PRE_KEY;
+
+ break;
+ case VALUE:
+ if (strchr(NEWLINE, db[i])) {
+ db[i] = '\0';
+ r = handle_db_line(device, key, value);
+ if (r < 0)
+ log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
+
+ state = PRE_KEY;
+ }
+
+ break;
+ default:
+ assert_not_reached("invalid state when parsing db");
+ }
+ }
+
+ return 0;
+}
+
+static int device_read_db(sd_device *device) {
+ return device_read_db_aux(device, false);
+}
+
+_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(initialized, -EINVAL);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ *initialized = device->is_initialized;
+
+ return 0;
+}
+
+_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
+ usec_t now_ts;
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(usec, -EINVAL);
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ if (!device->is_initialized)
+ return -EBUSY;
+
+ if (!device->usec_initialized)
+ return -ENODATA;
+
+ now_ts = now(clock_boottime_or_monotonic());
+
+ if (now_ts < device->usec_initialized)
+ return -EIO;
+
+ *usec = now_ts - device->usec_initialized;
+
+ return 0;
+}
+
+_public_ const char *sd_device_get_tag_first(sd_device *device) {
+ assert_return(device, NULL);
+
+ (void) device_read_db(device);
+
+ device->tags_iterator_generation = device->tags_generation;
+ device->tags_iterator = ITERATOR_FIRST;
+
+ return set_iterate(device->tags, &device->tags_iterator);
+}
+
+_public_ const char *sd_device_get_tag_next(sd_device *device) {
+ assert_return(device, NULL);
+
+ (void) device_read_db(device);
+
+ if (device->tags_iterator_generation != device->tags_generation)
+ return NULL;
+
+ return set_iterate(device->tags, &device->tags_iterator);
+}
+
+_public_ const char *sd_device_get_devlink_first(sd_device *device) {
+ assert_return(device, NULL);
+
+ (void) device_read_db(device);
+
+ device->devlinks_iterator_generation = device->devlinks_generation;
+ device->devlinks_iterator = ITERATOR_FIRST;
+
+ return set_iterate(device->devlinks, &device->devlinks_iterator);
+}
+
+_public_ const char *sd_device_get_devlink_next(sd_device *device) {
+ assert_return(device, NULL);
+
+ (void) device_read_db(device);
+
+ if (device->devlinks_iterator_generation != device->devlinks_generation)
+ return NULL;
+
+ return set_iterate(device->devlinks, &device->devlinks_iterator);
+}
+
+static int device_properties_prepare(sd_device *device) {
+ int r;
+
+ assert(device);
+
+ r = device_read_uevent_file(device);
+ if (r < 0)
+ return r;
+
+ r = device_read_db(device);
+ if (r < 0)
+ return r;
+
+ if (device->property_devlinks_outdated) {
+ char *devlinks = NULL;
+ const char *devlink;
+
+ devlink = sd_device_get_devlink_first(device);
+ if (devlink)
+ devlinks = strdupa(devlink);
+
+ while ((devlink = sd_device_get_devlink_next(device)))
+ devlinks = strjoina(devlinks, " ", devlink);
+
+ r = device_add_property_internal(device, "DEVLINKS", devlinks);
+ if (r < 0)
+ return r;
+
+ device->property_devlinks_outdated = false;
+ }
+
+ if (device->property_tags_outdated) {
+ char *tags = NULL;
+ const char *tag;
+
+ tag = sd_device_get_tag_first(device);
+ if (tag)
+ tags = strjoina(":", tag);
+
+ while ((tag = sd_device_get_tag_next(device)))
+ tags = strjoina(tags, ":", tag);
+
+ tags = strjoina(tags, ":");
+
+ r = device_add_property_internal(device, "TAGS", tags);
+ if (r < 0)
+ return r;
+
+ device->property_tags_outdated = false;
+ }
+
+ return 0;
+}
+
+_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
+ const char *key;
+ const char *value;
+ int r;
+
+ assert_return(device, NULL);
+
+ r = device_properties_prepare(device);
+ if (r < 0)
+ return NULL;
+
+ device->properties_iterator_generation = device->properties_generation;
+ device->properties_iterator = ITERATOR_FIRST;
+
+ value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
+
+ if (_value)
+ *_value = value;
+
+ return key;
+}
+
+_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
+ const char *key;
+ const char *value;
+ int r;
+
+ assert_return(device, NULL);
+
+ r = device_properties_prepare(device);
+ if (r < 0)
+ return NULL;
+
+ if (device->properties_iterator_generation != device->properties_generation)
+ return NULL;
+
+ value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
+
+ if (_value)
+ *_value = value;
+
+ return key;
+}
+
+static int device_sysattrs_read_all(sd_device *device) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ const char *syspath;
+ struct dirent *dent;
+ int r;
+
+ assert(device);
+
+ if (device->sysattrs_read)
+ return 0;
+
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0)
+ return r;
+
+ dir = opendir(syspath);
+ if (!dir)
+ return -errno;
+
+ r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ char *path;
+ struct stat statbuf;
+
+ /* only handle symlinks and regular files */
+ if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
+ continue;
+
+ path = strjoina(syspath, "/", dent->d_name);
+
+ if (lstat(path, &statbuf) != 0)
+ continue;
+
+ if (!(statbuf.st_mode & S_IRUSR))
+ continue;
+
+ r = set_put_strdup(device->sysattrs, dent->d_name);
+ if (r < 0)
+ return r;
+ }
+
+ device->sysattrs_read = true;
+
+ return 0;
+}
+
+_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
+ int r;
+
+ assert_return(device, NULL);
+
+ if (!device->sysattrs_read) {
+ r = device_sysattrs_read_all(device);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
+ }
+ }
+
+ device->sysattrs_iterator = ITERATOR_FIRST;
+
+ return set_iterate(device->sysattrs, &device->sysattrs_iterator);
+}
+
+_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
+ assert_return(device, NULL);
+
+ if (!device->sysattrs_read)
+ return NULL;
+
+ return set_iterate(device->sysattrs, &device->sysattrs_iterator);
+}
+
+_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
+ assert_return(device, -EINVAL);
+ assert_return(tag, -EINVAL);
+
+ (void) device_read_db(device);
+
+ return !!set_contains(device->tags, tag);
+}
+
+_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
+ char *value;
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(key, -EINVAL);
+ assert_return(_value, -EINVAL);
+
+ r = device_properties_prepare(device);
+ if (r < 0)
+ return r;
+
+ value = ordered_hashmap_get(device->properties, key);
+ if (!value)
+ return -ENOENT;
+
+ *_value = value;
+
+ return 0;
+}
+
+/* replaces the value if it already exists */
+static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
+ _cleanup_free_ char *key = NULL;
+ _cleanup_free_ char *value_old = NULL;
+ int r;
+
+ assert(device);
+ assert(_key);
+
+ r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
+ if (!key) {
+ key = strdup(_key);
+ if (!key)
+ return -ENOMEM;
+ }
+
+ r = hashmap_put(device->sysattr_values, key, value);
+ if (r < 0)
+ return r;
+
+ key = NULL;
+
+ return 0;
+}
+
+static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
+ const char *key = NULL, *value;
+
+ assert(device);
+ assert(_key);
+
+ value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
+ if (!key)
+ return -ENOENT;
+
+ if (_value)
+ *_value = value;
+
+ return 0;
+}
+
+/* We cache all sysattr lookups. If an attribute does not exist, it is stored
+ * with a NULL value in the cache, otherwise the returned string is stored */
+_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
+ _cleanup_free_ char *value = NULL;
+ const char *syspath, *cached_value = NULL;
+ char *path;
+ struct stat statbuf;
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(sysattr, -EINVAL);
+
+ /* look for possibly already cached result */
+ r = device_get_sysattr_value(device, sysattr, &cached_value);
+ if (r != -ENOENT) {
+ if (r < 0)
+ return r;
+
+ if (!cached_value)
+ /* we looked up the sysattr before and it did not exist */
+ return -ENOENT;
+
+ if (_value)
+ *_value = cached_value;
+
+ return 0;
+ }
+
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0)
+ return r;
+
+ path = strjoina(syspath, "/", sysattr);
+ r = lstat(path, &statbuf);
+ if (r < 0) {
+ /* remember that we could not access the sysattr */
+ r = device_add_sysattr_value(device, sysattr, NULL);
+ if (r < 0)
+ return r;
+
+ return -ENOENT;
+ } else if (S_ISLNK(statbuf.st_mode)) {
+ /* Some core links return only the last element of the target path,
+ * these are just values, the paths should not be exposed. */
+ if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
+ r = readlink_value(path, &value);
+ if (r < 0)
+ return r;
+ } else
+ return -EINVAL;
+ } else if (S_ISDIR(statbuf.st_mode)) {
+ /* skip directories */
+ return -EINVAL;
+ } else if (!(statbuf.st_mode & S_IRUSR)) {
+ /* skip non-readable files */
+ return -EPERM;
+ } else {
+ size_t size;
+
+ /* read attribute value */
+ r = read_full_file(path, &value, &size);
+ if (r < 0)
+ return r;
+
+ /* drop trailing newlines */
+ while (size > 0 && value[--size] == '\n')
+ value[size] = '\0';
+ }
+
+ r = device_add_sysattr_value(device, sysattr, value);
+ if (r < 0)
+ return r;
+
+ *_value = value;
+ value = NULL;
+
+ return 0;
+}
+
+static void device_remove_sysattr_value(sd_device *device, const char *_key) {
+ _cleanup_free_ char *key = NULL;
+ _cleanup_free_ char *value = NULL;
+
+ assert(device);
+ assert(_key);
+
+ value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
+
+ return;
+}
+
+/* set the attribute and save it in the cache. If a NULL value is passed the
+ * attribute is cleared from the cache */
+_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *value = NULL;
+ const char *syspath;
+ char *path;
+ struct stat statbuf;
+ size_t value_len = 0;
+ ssize_t size;
+ int r;
+
+ assert_return(device, -EINVAL);
+ assert_return(sysattr, -EINVAL);
+
+ if (!_value) {
+ device_remove_sysattr_value(device, sysattr);
+
+ return 0;
+ }
+
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0)
+ return r;
+
+ path = strjoina(syspath, "/", sysattr);
+ r = lstat(path, &statbuf);
+ if (r < 0) {
+ value = strdup("");
+ if (!value)
+ return -ENOMEM;
+
+ r = device_add_sysattr_value(device, sysattr, value);
+ if (r < 0)
+ return r;
+
+ return -ENXIO;
+ }
+
+ if (S_ISLNK(statbuf.st_mode))
+ return -EINVAL;
+
+ /* skip directories */
+ if (S_ISDIR(statbuf.st_mode))
+ return -EISDIR;
+
+ /* skip non-readable files */
+ if ((statbuf.st_mode & S_IRUSR) == 0)
+ return -EACCES;
+
+ value_len = strlen(_value);
+
+ /* drop trailing newlines */
+ while (value_len > 0 && _value[value_len - 1] == '\n')
+ _value[--value_len] = '\0';
+
+ /* value length is limited to 4k */
+ if (value_len > 4096)
+ return -EINVAL;
+
+ fd = open(path, O_WRONLY | O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ value = strdup(_value);
+ if (!value)
+ return -ENOMEM;
+
+ size = write(fd, value, value_len);
+ if (size < 0)
+ return -errno;
+
+ if ((size_t)size != value_len)
+ return -EIO;
+
+ r = device_add_sysattr_value(device, sysattr, value);
+ if (r < 0)
+ return r;
+
+ value = NULL;
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 25089a0335..cc8bc50c04 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -22,7 +22,6 @@
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/wait.h>
-#include <pthread.h>
#include "sd-id128.h"
#include "sd-daemon.h"
@@ -34,10 +33,10 @@
#include "missing.h"
#include "set.h"
#include "list.h"
+#include "signal-util.h"
#include "sd-event.h"
-#define EPOLL_QUEUE_MAX 512U
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
typedef enum EventSourceType {
@@ -463,7 +462,7 @@ _public_ sd_event* sd_event_unref(sd_event *e) {
static bool event_pid_changed(sd_event *e) {
assert(e);
- /* We don't support people creating am event loop and keeping
+ /* We don't support people creating an event loop and keeping
* it around over a fork(). Let's complain. */
return e->original_pid != getpid();
@@ -921,7 +920,7 @@ _public_ int sd_event_add_time(
callback = time_exit_callback;
type = clock_to_event_source_type(clock);
- assert_return(type >= 0, -ENOTSUP);
+ assert_return(type >= 0, -EOPNOTSUPP);
d = event_get_clock_data(e, type);
assert(d);
@@ -2236,7 +2235,7 @@ static int dispatch_exit(sd_event *e) {
r = source_dispatch(p);
- e->state = SD_EVENT_PASSIVE;
+ e->state = SD_EVENT_INITIAL;
sd_event_unref(e);
return r;
@@ -2305,7 +2304,7 @@ _public_ int sd_event_prepare(sd_event *e) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
- assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
+ assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
if (e->exit_requested)
goto pending;
@@ -2339,15 +2338,15 @@ _public_ int sd_event_prepare(sd_event *e) {
if (event_next_pending(e) || e->need_process_child)
goto pending;
- e->state = SD_EVENT_PREPARED;
+ e->state = SD_EVENT_ARMED;
return 0;
pending:
- e->state = SD_EVENT_PREPARED;
+ e->state = SD_EVENT_ARMED;
r = sd_event_wait(e, 0);
if (r == 0)
- e->state = SD_EVENT_PREPARED;
+ e->state = SD_EVENT_ARMED;
return r;
}
@@ -2360,14 +2359,14 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
- assert_return(e->state == SD_EVENT_PREPARED, -EBUSY);
+ assert_return(e->state == SD_EVENT_ARMED, -EBUSY);
if (e->exit_requested) {
e->state = SD_EVENT_PENDING;
return 1;
}
- ev_queue_max = CLAMP(e->n_sources, 1U, EPOLL_QUEUE_MAX);
+ ev_queue_max = MAX(e->n_sources, 1u);
ev_queue = newa(struct epoll_event, ev_queue_max);
m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
@@ -2448,7 +2447,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
r = 0;
finish:
- e->state = SD_EVENT_PASSIVE;
+ e->state = SD_EVENT_INITIAL;
return r;
}
@@ -2471,14 +2470,14 @@ _public_ int sd_event_dispatch(sd_event *e) {
e->state = SD_EVENT_RUNNING;
r = source_dispatch(p);
- e->state = SD_EVENT_PASSIVE;
+ e->state = SD_EVENT_INITIAL;
sd_event_unref(e);
return r;
}
- e->state = SD_EVENT_PASSIVE;
+ e->state = SD_EVENT_INITIAL;
return 1;
}
@@ -2489,19 +2488,23 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
- assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
+ assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
r = sd_event_prepare(e);
- if (r > 0)
- return sd_event_dispatch(e);
- else if (r < 0)
- return r;
+ if (r == 0)
+ /* There was nothing? Then wait... */
+ r = sd_event_wait(e, timeout);
- r = sd_event_wait(e, timeout);
- if (r > 0)
- return sd_event_dispatch(e);
- else
- return r;
+ if (r > 0) {
+ /* There's something now, then let's dispatch it */
+ r = sd_event_dispatch(e);
+ if (r < 0)
+ return r;
+
+ return 1;
+ }
+
+ return r;
}
_public_ int sd_event_loop(sd_event *e) {
@@ -2509,7 +2512,7 @@ _public_ int sd_event_loop(sd_event *e) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
- assert_return(e->state == SD_EVENT_PASSIVE, -EBUSY);
+ assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
sd_event_ref(e);
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index 721700be7b..94e98e0077 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -23,6 +23,7 @@
#include "log.h"
#include "util.h"
#include "macro.h"
+#include "signal-util.h"
static int prepare_handler(sd_event_source *s, void *userdata) {
log_info("preparing %c", PTR_TO_INT(userdata));
diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c
index 61c7b446b3..2a0e00f7d2 100644
--- a/src/libsystemd/sd-hwdb/sd-hwdb.c
+++ b/src/libsystemd/sd-hwdb/sd-hwdb.c
@@ -23,10 +23,8 @@
#include <errno.h>
#include <string.h>
#include <inttypes.h>
-#include <ctype.h>
#include <stdlib.h>
#include <fnmatch.h>
-#include <getopt.h>
#include <sys/mman.h>
#include "sd-hwdb.h"
@@ -319,7 +317,7 @@ _public_ int sd_hwdb_new(sd_hwdb **ret) {
if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
(size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
log_debug("error recognizing the format of %s", hwdb_bin_path);
- return -EINVAL;;
+ return -EINVAL;
}
log_debug("=== trie on-disk ===");
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index c876f6e381..46f2181ea8 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -26,6 +26,7 @@
#include "util.h"
#include "macro.h"
#include "sd-id128.h"
+#include "random-util.h"
_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
unsigned n;
@@ -108,9 +109,9 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local bool saved_machine_id_valid = false;
_cleanup_close_ int fd = -1;
char buf[33];
- ssize_t k;
unsigned j;
sd_id128_t t;
+ int r;
assert_return(ret, -EINVAL);
@@ -123,13 +124,9 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
if (fd < 0)
return -errno;
- k = loop_read(fd, buf, 33, false);
- if (k < 0)
- return (int) k;
-
- if (k != 33)
- return -EIO;
-
+ r = loop_read_exact(fd, buf, 33, false);
+ if (r < 0)
+ return r;
if (buf[32] !='\n')
return -EIO;
@@ -157,10 +154,10 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local bool saved_boot_id_valid = false;
_cleanup_close_ int fd = -1;
char buf[36];
- ssize_t k;
unsigned j;
sd_id128_t t;
char *p;
+ int r;
assert_return(ret, -EINVAL);
@@ -173,22 +170,19 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
if (fd < 0)
return -errno;
- k = loop_read(fd, buf, 36, false);
- if (k < 0)
- return (int) k;
-
- if (k != 36)
- return -EIO;
+ r = loop_read_exact(fd, buf, 36, false);
+ if (r < 0)
+ return r;
for (j = 0, p = buf; j < 16; j++) {
int a, b;
- if (p >= buf + k - 1)
+ if (p >= buf + 35)
return -EIO;
if (*p == '-') {
p++;
- if (p >= buf + k - 1)
+ if (p >= buf + 35)
return -EIO;
}
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index f71749f72d..ed8aa0952a 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -31,6 +31,7 @@
#include "strv.h"
#include "fileio.h"
#include "login-shared.h"
+#include "formats-util.h"
#include "sd-login.h"
_public_ int sd_pid_get_session(pid_t pid, char **session) {
@@ -73,6 +74,14 @@ _public_ int sd_pid_get_slice(pid_t pid, char **slice) {
return cg_pid_get_slice(pid, slice);
}
+_public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
+
+ assert_return(pid >= 0, -EINVAL);
+ assert_return(slice, -EINVAL);
+
+ return cg_pid_get_user_slice(pid, slice);
+}
+
_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
assert_return(pid >= 0, -EINVAL);
@@ -82,7 +91,7 @@ _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
}
_public_ int sd_peer_get_session(int fd, char **session) {
- struct ucred ucred;
+ struct ucred ucred = {};
int r;
assert_return(fd >= 0, -EINVAL);
@@ -165,6 +174,20 @@ _public_ int sd_peer_get_slice(int fd, char **slice) {
return cg_pid_get_slice(ucred.pid, slice);
}
+_public_ int sd_peer_get_user_slice(int fd, char **slice) {
+ struct ucred ucred;
+ int r;
+
+ assert_return(fd >= 0, -EINVAL);
+ assert_return(slice, -EINVAL);
+
+ r = getpeercred(fd, &ucred);
+ if (r < 0)
+ return r;
+
+ return cg_pid_get_user_slice(ucred.pid, slice);
+}
+
static int file_of_uid(uid_t uid, char **p) {
assert(p);
@@ -496,9 +519,9 @@ _public_ int sd_session_get_desktop(const char *session, char **desktop) {
if (r < 0)
return r;
- t = cunescape(escaped);
- if (!t)
- return -ENOMEM;
+ r = cunescape(escaped, 0, &t);
+ if (r < 0)
+ return r;
*desktop = t;
return 0;
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index 2802e8246d..05affa442d 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -26,6 +26,7 @@
#include "util.h"
#include "strv.h"
+#include "formats-util.h"
static void test_login(void) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h
index 02bd545526..11a0012348 100644
--- a/src/libsystemd/sd-network/network-util.h
+++ b/src/libsystemd/sd-network/network-util.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "sd-network.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_network_monitor*, sd_network_monitor_unref);
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index c4713feb5d..db1f6997cb 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -20,19 +20,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/inotify.h>
#include <poll.h>
-#include <net/if.h>
#include "util.h"
#include "macro.h"
#include "strv.h"
#include "fileio.h"
#include "sd-network.h"
-#include "network-internal.h"
_public_ int sd_network_get_operational_state(char **state) {
_cleanup_free_ char *s = NULL;
@@ -264,6 +261,14 @@ _public_ int sd_network_link_get_domains(int ifindex, char ***ret) {
return network_get_link_strv("DOMAINS", ifindex, ret);
}
+_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
+ return network_get_link_strv("CARRIER_BOUND_TO", ifindex, ret);
+}
+
+_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
+ return network_get_link_strv("CARRIER_BOUND_BY", ifindex, ret);
+}
+
_public_ int sd_network_link_get_wildcard_domain(int ifindex) {
int r;
_cleanup_free_ char *p = NULL, *s = NULL;
diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
index 651fceb79d..7363be2794 100644
--- a/src/libsystemd/sd-path/sd-path.c
+++ b/src/libsystemd/sd-path/sd-path.c
@@ -323,7 +323,7 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
return from_user_dir("XDG_DESKTOP_DIR", buffer, ret);
}
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
_public_ int sd_path_home(uint64_t type, const char *suffix, char **path) {
@@ -552,7 +552,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
}
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
_public_ int sd_path_search(uint64_t type, const char *suffix, char ***paths) {
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index 6448280c4f..b0dc822591 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -19,24 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
-#include <sys/select.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
#include <resolv.h>
-#include <dirent.h>
-#include <sys/time.h>
-#include <sys/resource.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/prctl.h>
@@ -461,7 +450,7 @@ static int handle_request(int out_fd, const Packet *packet, size_t length) {
assert(length >= sizeof(ResRequest));
assert(length == sizeof(ResRequest) + res_req->dname_len);
- dname = (const char *) req + sizeof(ResRequest);
+ dname = (const char *) res_req + sizeof(ResRequest);
if (req->type == REQUEST_RES_QUERY)
ret = res_query(dname, res_req->class, res_req->type, (unsigned char *) &answer, BUFSIZE);
@@ -664,7 +653,7 @@ static void resolve_free(sd_resolve *resolve) {
/* Send one termination packet for each worker */
for (i = 0; i < resolve->n_valid_workers; i++)
- send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
+ (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
}
/* Now terminate them and wait until they are gone. */
diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c
index d08e1b5a05..354a4071b7 100644
--- a/src/libsystemd/sd-resolve/test-resolve.c
+++ b/src/libsystemd/sd-resolve/test-resolve.c
@@ -21,14 +21,11 @@
***/
#include <string.h>
-#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netinet/in.h>
-#include <arpa/nameser.h>
#include <resolv.h>
-#include <signal.h>
#include <errno.h>
#include "socket-util.h"
@@ -49,7 +46,7 @@ static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrin
for (i = ai; i; i = i->ai_next) {
_cleanup_free_ char *addr = NULL;
- assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, &addr) == 0);
+ assert_se(sockaddr_pretty(i->ai_addr, i->ai_addrlen, false, true, &addr) == 0);
puts(addr);
}
diff --git a/src/libsystemd/sd-rtnl/local-addresses.h b/src/libsystemd/sd-rtnl/local-addresses.h
index ef7def530d..bdc28d3510 100644
--- a/src/libsystemd/sd-rtnl/local-addresses.h
+++ b/src/libsystemd/sd-rtnl/local-addresses.h
@@ -21,10 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <sys/socket.h>
#include "sd-rtnl.h"
#include "in-addr-util.h"
diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h
index a192198419..05b88b1ad8 100644
--- a/src/libsystemd/sd-rtnl/rtnl-internal.h
+++ b/src/libsystemd/sd-rtnl/rtnl-internal.h
@@ -109,6 +109,7 @@ struct sd_rtnl_message {
size_t *rta_offset_tb[RTNL_CONTAINER_DEPTH];
unsigned short rta_tb_size[RTNL_CONTAINER_DEPTH];
bool sealed:1;
+ bool broadcast:1;
sd_rtnl_message *next; /* next in a chain of multi-part messages */
};
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 276591f31b..bab2a4ff08 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -20,11 +20,11 @@
***/
#include <netinet/in.h>
-#include <netinet/ether.h>
#include <stdbool.h>
#include <unistd.h>
#include "util.h"
+#include "formats-util.h"
#include "refcnt.h"
#include "missing.h"
@@ -45,7 +45,7 @@ static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
/* Note that 'rtnl' is currently unused, if we start using it internally
we must take care to avoid problems due to mutual references between
- busses and their queued messages. See sd-bus.
+ buses and their queued messages. See sd-bus.
*/
m = new0(sd_rtnl_message, 1);
@@ -649,13 +649,13 @@ int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family) {
return 0;
}
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
assert_return(m, -EINVAL);
- return !m->hdr->nlmsg_pid;
+ return m->broadcast;
}
int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
@@ -1475,7 +1475,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
return 0;
}
- if (group)
+ if (_group)
*_group = group;
return r;
@@ -1501,7 +1501,7 @@ int socket_read_message(sd_rtnl *rtnl) {
assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
/* read nothing, just get the pending message size */
- r = socket_recv_message(rtnl->fd, &iov, &group, true);
+ r = socket_recv_message(rtnl->fd, &iov, NULL, true);
if (r <= 0)
return r;
else
@@ -1555,13 +1555,15 @@ int socket_read_message(sd_rtnl *rtnl) {
/* finished reading multi-part message */
done = true;
- continue;
+ /* if first is not defined, put NLMSG_DONE into the receive queue. */
+ if (first)
+ continue;
}
/* check that we support this message type */
r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
if (r < 0) {
- if (r == -ENOTSUP)
+ if (r == -EOPNOTSUPP)
log_debug("sd-rtnl: ignored message with unknown type: %i",
new_msg->nlmsg_type);
@@ -1578,6 +1580,8 @@ int socket_read_message(sd_rtnl *rtnl) {
if (r < 0)
return r;
+ m->broadcast = !!group;
+
m->hdr = memdup(new_msg, new_msg->nlmsg_len);
if (!m->hdr)
return -ENOMEM;
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c
index a4c71f3785..d211684ff1 100644
--- a/src/libsystemd/sd-rtnl/rtnl-types.c
+++ b/src/libsystemd/sd-rtnl/rtnl-types.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stddef.h>
#include <stdint.h>
#include <sys/socket.h>
#include <linux/netlink.h>
@@ -91,6 +90,30 @@ static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
[IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
};
+static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
+ [BOND_ARP_TARGETS_0] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_1] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_2] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_3] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_4] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_5] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_6] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_7] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_8] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_9] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_10] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_11] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_12] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_13] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_14] = { .type = NLA_U32 },
+ [BOND_ARP_TARGETS_MAX] = { .type = NLA_U32 },
+};
+
+static const NLTypeSystem rtnl_bond_arp_type_system = {
+ .max = ELEMENTSOF(rtnl_bond_arp_target_types) - 1,
+ .types = rtnl_bond_arp_target_types,
+};
+
static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
[IFLA_BOND_MODE] = { .type = NLA_U8 },
[IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 },
@@ -99,7 +122,7 @@ static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
[IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 },
[IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 },
[IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 },
- [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED },
+ [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED, .type_system = &rtnl_bond_arp_type_system },
[IFLA_BOND_ARP_VALIDATE] = { .type = NLA_U32 },
[IFLA_BOND_ARP_ALL_TARGETS] = { .type = NLA_U32 },
[IFLA_BOND_PRIMARY] = { .type = NLA_U32 },
@@ -181,6 +204,7 @@ static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_
[NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL] = "ip6gretap",
[NL_UNION_LINK_INFO_DATA_SIT_TUNNEL] = "sit",
[NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti",
+ [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6",
[NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl",
};
@@ -215,6 +239,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_D
.types = rtnl_link_info_data_iptun_types },
[NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
.types = rtnl_link_info_data_ipvti_types },
+ [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_ipvti_types) - 1,
+ .types = rtnl_link_info_data_ipvti_types },
[NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .max = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types) - 1,
.types = rtnl_link_info_data_ip6tnl_types },
@@ -349,7 +375,9 @@ static const NLTypeSystem rtnl_link_type_system = {
.types = rtnl_link_types,
};
-static const NLType rtnl_address_types[IFA_MAX + 1] = {
+/* IFA_FLAGS was defined in kernel 3.14, but we still support older
+ * kernels where IFA_MAX is lower. */
+static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
[IFA_ADDRESS] = { .type = NLA_IN_ADDR },
[IFA_LOCAL] = { .type = NLA_IN_ADDR },
[IFA_LABEL] = { .type = NLA_STRING, .size = IFNAMSIZ - 1 },
@@ -359,9 +387,7 @@ static const NLType rtnl_address_types[IFA_MAX + 1] = {
[IFA_ANYCAST],
[IFA_MULTICAST],
*/
-#ifdef IFA_FLAGS
[IFA_FLAGS] = { .type = NLA_U32 },
-#endif
};
static const NLTypeSystem rtnl_address_type_system = {
@@ -412,6 +438,7 @@ static const NLTypeSystem rtnl_neigh_type_system = {
};
static const NLType rtnl_types[RTM_MAX + 1] = {
+ [NLMSG_DONE] = { .type = NLA_META, .size = 0 },
[NLMSG_ERROR] = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
[RTM_NEWLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
[RTM_DELLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
@@ -444,12 +471,12 @@ int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, ui
assert(type_system->types);
if (type > type_system->max)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
nl_type = &type_system->types[type];
if (nl_type->type == NLA_UNSPEC)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
*ret = nl_type;
@@ -466,8 +493,7 @@ int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSys
if (r < 0)
return r;
- assert_return(nl_type->type == NLA_NESTED, -EINVAL);
-
+ assert(nl_type->type == NLA_NESTED);
assert(nl_type->type_system);
*ret = nl_type->type_system;
@@ -485,8 +511,7 @@ int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLT
if (r < 0)
return r;
- assert_return(nl_type->type == NLA_UNION, -EINVAL);
-
+ assert(nl_type->type == NLA_UNION);
assert(nl_type->type_system_union);
*ret = nl_type->type_system_union;
@@ -498,7 +523,7 @@ int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union
int type;
assert(type_system_union);
- assert_return(type_system_union->match_type == NL_MATCH_SIBLING, -EINVAL);
+ assert(type_system_union->match_type == NL_MATCH_SIBLING);
assert(type_system_union->lookup);
assert(type_system_union->type_systems);
assert(ret);
@@ -506,7 +531,7 @@ int type_system_union_get_type_system(const NLTypeSystemUnion *type_system_union
type = type_system_union->lookup(key);
if (type < 0)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
assert(type < type_system_union->num);
@@ -520,17 +545,15 @@ int type_system_union_protocol_get_type_system(const NLTypeSystemUnion *type_sys
assert(type_system_union);
assert(type_system_union->type_systems);
+ assert(type_system_union->match_type == NL_MATCH_PROTOCOL);
assert(ret);
- assert_return(type_system_union->match_type == NL_MATCH_PROTOCOL, -EINVAL);
- assert_return(protocol < type_system_union->num, -EINVAL);
if (protocol >= type_system_union->num)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
type_system = &type_system_union->type_systems[protocol];
-
- if (!type_system)
- return -ENOTSUP;
+ if (type_system->max == 0)
+ return -EOPNOTSUPP;
*ret = type_system;
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.h b/src/libsystemd/sd-rtnl/rtnl-types.h
index 1ab9444987..de1544bf36 100644
--- a/src/libsystemd/sd-rtnl/rtnl-types.h
+++ b/src/libsystemd/sd-rtnl/rtnl-types.h
@@ -87,6 +87,7 @@ typedef enum NLUnionLinkInfoData {
NL_UNION_LINK_INFO_DATA_IP6GRETAP_TUNNEL,
NL_UNION_LINK_INFO_DATA_SIT_TUNNEL,
NL_UNION_LINK_INFO_DATA_VTI_TUNNEL,
+ NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL,
NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL,
_NL_UNION_LINK_INFO_DATA_MAX,
_NL_UNION_LINK_INFO_DATA_INVALID = -1
@@ -94,3 +95,25 @@ typedef enum NLUnionLinkInfoData {
const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_;
NLUnionLinkInfoData nl_union_link_info_data_from_string(const char *p) _pure_;
+
+/* Maximum ARP IP target defined in kernel */
+#define BOND_MAX_ARP_TARGETS 16
+
+typedef enum BondArpTargets {
+ BOND_ARP_TARGETS_0,
+ BOND_ARP_TARGETS_1,
+ BOND_ARP_TARGETS_2,
+ BOND_ARP_TARGETS_3,
+ BOND_ARP_TARGETS_4,
+ BOND_ARP_TARGETS_5,
+ BOND_ARP_TARGETS_6,
+ BOND_ARP_TARGETS_7,
+ BOND_ARP_TARGETS_8,
+ BOND_ARP_TARGETS_9,
+ BOND_ARP_TARGETS_10,
+ BOND_ARP_TARGETS_11,
+ BOND_ARP_TARGETS_12,
+ BOND_ARP_TARGETS_13,
+ BOND_ARP_TARGETS_14,
+ BOND_ARP_TARGETS_MAX = BOND_MAX_ARP_TARGETS,
+} BondArpTargets;
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c
index 5666ea44cb..9ddf074c24 100644
--- a/src/libsystemd/sd-rtnl/rtnl-util.c
+++ b/src/libsystemd/sd-rtnl/rtnl-util.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include "sd-rtnl.h"
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h
index ca9fbd4f41..9e4bdb867e 100644
--- a/src/libsystemd/sd-rtnl/rtnl-util.h
+++ b/src/libsystemd/sd-rtnl/rtnl-util.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include "util.h"
#include "sd-rtnl.h"
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
index ae49c77e01..40dea1252f 100644
--- a/src/libsystemd/sd-rtnl/sd-rtnl.c
+++ b/src/libsystemd/sd-rtnl/sd-rtnl.c
@@ -61,6 +61,11 @@ static int sd_rtnl_new(sd_rtnl **ret) {
sizeof(struct nlmsghdr), sizeof(uint8_t)))
return -ENOMEM;
+ /* Change notification responses have sequence 0, so we must
+ * start our request sequence numbers at 1, or we may confuse our
+ * responses with notifications from the kernel */
+ rtnl->serial = 1;
+
*ret = rtnl;
rtnl = NULL;
@@ -257,7 +262,9 @@ static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
assert(m);
assert(m->hdr);
- m->hdr->nlmsg_seq = rtnl->serial++;
+ /* don't use seq == 0, as that is used for broadcasts, so we
+ would get confused by replies to such messages */
+ m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
rtnl_message_seal(m);
@@ -414,16 +421,14 @@ static int process_timeout(sd_rtnl *rtnl) {
}
static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
- struct reply_callback *c;
+ _cleanup_free_ struct reply_callback *c = NULL;
uint64_t serial;
+ uint16_t type;
int r;
assert(rtnl);
assert(m);
- if (sd_rtnl_message_is_broadcast(m))
- return 0;
-
serial = rtnl_message_get_serial(m);
c = hashmap_remove(rtnl->reply_callbacks, &serial);
if (!c)
@@ -432,12 +437,17 @@ static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
if (c->timeout != 0)
prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
+ r = sd_rtnl_message_get_type(m, &type);
+ if (r < 0)
+ return 0;
+
+ if (type == NLMSG_DONE)
+ m = NULL;
+
r = c->callback(rtnl, m, c->userdata);
if (r < 0)
log_debug_errno(r, "sd-rtnl: callback failed: %m");
- free(c);
-
return 1;
}
@@ -488,13 +498,15 @@ static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
if (!m)
goto null_message;
- r = process_reply(rtnl, m);
- if (r != 0)
- goto null_message;
-
- r = process_match(rtnl, m);
- if (r != 0)
- goto null_message;
+ if (sd_rtnl_message_is_broadcast(m)) {
+ r = process_match(rtnl, m);
+ if (r != 0)
+ goto null_message;
+ } else {
+ r = process_reply(rtnl, m);
+ if (r != 0)
+ goto null_message;
+ }
if (ret) {
*ret = m;
@@ -696,7 +708,6 @@ int sd_rtnl_call(sd_rtnl *rtnl,
sd_rtnl_message **ret) {
usec_t timeout;
uint32_t serial;
- unsigned i = 0;
int r;
assert_return(rtnl, -EINVAL);
@@ -711,36 +722,44 @@ int sd_rtnl_call(sd_rtnl *rtnl,
for (;;) {
usec_t left;
+ unsigned i;
- while (i < rtnl->rqueue_size) {
- sd_rtnl_message *incoming;
+ for (i = 0; i < rtnl->rqueue_size; i++) {
uint32_t received_serial;
- incoming = rtnl->rqueue[i];
- received_serial = rtnl_message_get_serial(incoming);
+ received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
if (received_serial == serial) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
+ uint16_t type;
+
+ incoming = rtnl->rqueue[i];
+
/* found a match, remove from rqueue and return it */
memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
rtnl->rqueue_size--;
r = sd_rtnl_message_get_errno(incoming);
- if (r < 0) {
- sd_rtnl_message_unref(incoming);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_get_type(incoming, &type);
+ if (r < 0)
return r;
+
+ if (type == NLMSG_DONE) {
+ *ret = NULL;
+ return 0;
}
if (ret) {
*ret = incoming;
- } else
- sd_rtnl_message_unref(incoming);
+ incoming = NULL;
+ }
return 1;
}
-
- /* Try to read more, right away */
- i ++;
}
r = socket_read_message(rtnl);
@@ -993,7 +1012,7 @@ int sd_rtnl_add_match(sd_rtnl *rtnl,
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
assert_return(rtnl_message_type_is_link(type) ||
rtnl_message_type_is_addr(type) ||
- rtnl_message_type_is_route(type), -ENOTSUP);
+ rtnl_message_type_is_route(type), -EOPNOTSUPP);
c = new0(struct match_callback, 1);
if (!c)
diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c
index 02f7a8e38a..47cce64816 100644
--- a/src/libsystemd/sd-rtnl/test-rtnl.c
+++ b/src/libsystemd/sd-rtnl/test-rtnl.c
@@ -29,7 +29,6 @@
#include "rtnl-util.h"
#include "event-util.h"
#include "missing.h"
-#include "rtnl-internal.h"
static void test_message_link_bridge(sd_rtnl *rtnl) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *message = NULL;
diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h
new file mode 100644
index 0000000000..aa36b8cb12
--- /dev/null
+++ b/src/libudev/libudev-device-internal.h
@@ -0,0 +1,57 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2015 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "libudev.h"
+#include "libudev-private.h"
+#include "sd-device.h"
+
+/**
+ * udev_device:
+ *
+ * Opaque object representing one kernel sys device.
+ */
+struct udev_device {
+ struct udev *udev;
+
+ /* real device object */
+ sd_device *device;
+
+ /* legacy */
+ int refcount;
+
+ struct udev_device *parent;
+ bool parent_set;
+
+ struct udev_list properties;
+ uint64_t properties_generation;
+ struct udev_list tags;
+ uint64_t tags_generation;
+ struct udev_list devlinks;
+ uint64_t devlinks_generation;
+ bool properties_read:1;
+ bool tags_read:1;
+ bool devlinks_read:1;
+ struct udev_list sysattrs;
+ bool sysattrs_read;
+};
+
+struct udev_device *udev_device_new(struct udev *udev);
diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c
index fb4c6e2940..4b9c053b54 100644
--- a/src/libudev/libudev-device-private.c
+++ b/src/libudev/libudev-device-private.c
@@ -2,6 +2,7 @@
This file is part of systemd.
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2015 Tom Gundersen <teg@jklm.no>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -17,172 +18,398 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
#include "libudev.h"
#include "libudev-private.h"
+#include "libudev-device-internal.h"
+
+#include "device-private.h"
+
+int udev_device_tag_index(struct udev_device *udev_device, struct udev_device *udev_device_old, bool add) {
+ sd_device *device_old = NULL;
+ int r;
+
+ assert(udev_device);
+
+ if (udev_device_old)
+ device_old = udev_device_old->device;
+
+ r = device_tag_index(udev_device->device, device_old, add);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int udev_device_update_db(struct udev_device *udev_device) {
+ int r;
+
+ assert(udev_device);
+
+ r = device_update_db(udev_device->device);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int udev_device_delete_db(struct udev_device *udev_device) {
+ int r;
+
+ assert(udev_device);
+
+ r = device_delete_db(udev_device->device);
+ if (r < 0)
+ return r;
-static void udev_device_tag(struct udev_device *dev, const char *tag, bool add)
-{
- const char *id;
- char filename[UTIL_PATH_SIZE];
-
- id = udev_device_get_id_filename(dev);
- if (id == NULL)
- return;
- strscpyl(filename, sizeof(filename), "/run/udev/tags/", tag, "/", id, NULL);
-
- if (add) {
- int fd;
-
- mkdir_parents(filename, 0755);
- fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
- if (fd >= 0)
- close(fd);
- } else {
- unlink(filename);
+ return 0;
+}
+
+int udev_device_get_ifindex(struct udev_device *udev_device) {
+ int r, ifindex;
+
+ assert(udev_device);
+
+ r = sd_device_get_ifindex(udev_device->device, &ifindex);
+ if (r < 0)
+ return r;
+
+ return ifindex;
+}
+
+const char *udev_device_get_devpath_old(struct udev_device *udev_device) {
+ const char *devpath_old = NULL;
+ int r;
+
+ assert(udev_device);
+
+ r = sd_device_get_property_value(udev_device->device, "DEVPATH_OLD", &devpath_old);
+ if (r < 0 && r != -ENOENT) {
+ errno = -r;
+ return NULL;
}
+
+ return devpath_old;
}
-int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add)
-{
- struct udev_list_entry *list_entry;
- bool found;
-
- if (add && dev_old != NULL) {
- /* delete possible left-over tags */
- udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) {
- const char *tag_old = udev_list_entry_get_name(list_entry);
- struct udev_list_entry *list_entry_current;
-
- found = false;
- udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) {
- const char *tag = udev_list_entry_get_name(list_entry_current);
-
- if (streq(tag, tag_old)) {
- found = true;
- break;
- }
- }
- if (!found)
- udev_device_tag(dev_old, tag_old, false);
- }
+mode_t udev_device_get_devnode_mode(struct udev_device *udev_device) {
+ mode_t mode;
+ int r;
+
+ assert(udev_device);
+
+ r = device_get_devnode_mode(udev_device->device, &mode);
+ if (r < 0) {
+ errno = -r;
+ return 0;
}
- udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev))
- udev_device_tag(dev, udev_list_entry_get_name(list_entry), add);
+ return mode;
+}
- return 0;
+uid_t udev_device_get_devnode_uid(struct udev_device *udev_device) {
+ uid_t uid;
+ int r;
+
+ assert(udev_device);
+
+ r = device_get_devnode_uid(udev_device->device, &uid);
+ if (r < 0) {
+ errno = -r;
+ return 0;
+ }
+
+ return uid;
}
-static bool device_has_info(struct udev_device *udev_device)
-{
- struct udev_list_entry *list_entry;
-
- if (udev_device_get_devlinks_list_entry(udev_device) != NULL)
- return true;
- if (udev_device_get_devlink_priority(udev_device) != 0)
- return true;
- udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
- if (udev_list_entry_get_num(list_entry))
- return true;
- if (udev_device_get_tags_list_entry(udev_device) != NULL)
- return true;
- if (udev_device_get_watch_handle(udev_device) >= 0)
- return true;
- return false;
-}
-
-int udev_device_update_db(struct udev_device *udev_device)
-{
- bool has_info;
- const char *id;
- char filename[UTIL_PATH_SIZE];
- char filename_tmp[UTIL_PATH_SIZE];
- FILE *f;
- int r;
-
- id = udev_device_get_id_filename(udev_device);
- if (id == NULL)
- return -1;
-
- has_info = device_has_info(udev_device);
- strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
-
- /* do not store anything for otherwise empty devices */
- if (!has_info &&
- major(udev_device_get_devnum(udev_device)) == 0 &&
- udev_device_get_ifindex(udev_device) == 0) {
- unlink(filename);
+gid_t udev_device_get_devnode_gid(struct udev_device *udev_device) {
+ gid_t gid;
+ int r;
+
+ assert(udev_device);
+
+ r = device_get_devnode_gid(udev_device->device, &gid);
+ if (r < 0) {
+ errno = -r;
return 0;
}
- /* write a database file */
- strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
- mkdir_parents(filename_tmp, 0755);
- f = fopen(filename_tmp, "we");
- if (f == NULL)
- return log_debug_errno(errno, "unable to create temporary db file '%s': %m", filename_tmp);
-
- /*
- * set 'sticky' bit to indicate that we should not clean the
- * database when we transition from initramfs to the real root
- */
- if (udev_device_get_db_persist(udev_device))
- fchmod(fileno(f), 01644);
-
- if (has_info) {
- struct udev_list_entry *list_entry;
-
- if (major(udev_device_get_devnum(udev_device)) > 0) {
- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device))
- fprintf(f, "S:%s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
- if (udev_device_get_devlink_priority(udev_device) != 0)
- fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device));
- if (udev_device_get_watch_handle(udev_device) >= 0)
- fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device));
- }
-
- if (udev_device_get_usec_initialized(udev_device) > 0)
- fprintf(f, "I:"USEC_FMT"\n", udev_device_get_usec_initialized(udev_device));
-
- udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
- if (!udev_list_entry_get_num(list_entry))
- continue;
- fprintf(f, "E:%s=%s\n",
- udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry));
- }
-
- udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
- fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry));
+ return gid;
+}
+
+void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *udev_device_old) {
+ sd_device *device_old = NULL;
+
+ assert(udev_device);
+
+ if (udev_device_old)
+ device_old = udev_device_old->device;
+
+ device_ensure_usec_initialized(udev_device->device, device_old);
+}
+
+char **udev_device_get_properties_envp(struct udev_device *udev_device) {
+ char **envp;
+ int r;
+
+ assert(udev_device);
+
+ r = device_get_properties_strv(udev_device->device, &envp);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
}
- fclose(f);
- r = rename(filename_tmp, filename);
+ return envp;
+}
+
+ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf) {
+ const char *nulstr;
+ size_t len;
+ int r;
+
+ assert(udev_device);
+ assert(buf);
+
+ r = device_get_properties_nulstr(udev_device->device, (const uint8_t **)&nulstr, &len);
+ if (r < 0)
+ return r;
+
+ *buf = nulstr;
+
+ return len;
+}
+
+int udev_device_get_devlink_priority(struct udev_device *udev_device) {
+ int priority, r;
+
+ assert(udev_device);
+
+ r = device_get_devlink_priority(udev_device->device, &priority);
+ if (r < 0)
+ return r;
+
+ return priority;
+}
+
+int udev_device_get_watch_handle(struct udev_device *udev_device) {
+ int handle, r;
+
+ assert(udev_device);
+
+ r = device_get_watch_handle(udev_device->device, &handle);
if (r < 0)
- return -1;
- log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
- filename, udev_device_get_devpath(udev_device));
+ return r;
+
+ return handle;
+}
+
+void udev_device_set_is_initialized(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ device_set_is_initialized(udev_device->device);
+}
+
+int udev_device_rename(struct udev_device *udev_device, const char *name) {
+ int r;
+
+ assert(udev_device);
+
+ r = device_rename(udev_device->device, name);
+ if (r < 0)
+ return r;
+
return 0;
}
-int udev_device_delete_db(struct udev_device *udev_device)
-{
- const char *id;
- char filename[UTIL_PATH_SIZE];
+struct udev_device *udev_device_shallow_clone(struct udev_device *old_device) {
+ struct udev_device *device;
+ int r;
+
+ assert(old_device);
+
+ device = udev_device_new(old_device->udev);
+ if (!device)
+ return NULL;
+
+ r = device_shallow_clone(old_device->device, &device->device);
+ if (r < 0) {
+ udev_device_unref(device);
+ errno = -r;
+ return NULL;
+ }
+
+ return device;
+}
+
+struct udev_device *udev_device_clone_with_db(struct udev_device *udev_device_old) {
+ struct udev_device *udev_device;
+ int r;
+
+ assert(udev_device_old);
+
+ udev_device = udev_device_new(udev_device_old->udev);
+ if (!udev_device)
+ return NULL;
+
+ r = device_clone_with_db(udev_device_old->device, &udev_device->device);
+ if (r < 0) {
+ udev_device_unref(udev_device);
+ errno = -r;
+ return NULL;
+ }
+
+ return udev_device;
+}
+
+struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen) {
+ struct udev_device *device;
+ int r;
+
+ device = udev_device_new(udev);
+ if (!device)
+ return NULL;
+
+ r = device_new_from_nulstr(&device->device, (uint8_t*)nulstr, buflen);
+ if (r < 0) {
+ udev_device_unref(device);
+ errno = -r;
+ return NULL;
+ }
+
+ return device;
+}
+
+struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action) {
+ struct udev_device *device;
+ int r;
+
+ device = udev_device_new(udev);
+ if (!device)
+ return NULL;
+
+ r = device_new_from_synthetic_event(&device->device, syspath, action);
+ if (r < 0) {
+ udev_device_unref(device);
+ errno = -r;
+ return NULL;
+ }
+
+ return device;
+}
+
+int udev_device_copy_properties(struct udev_device *udev_device_dst, struct udev_device *udev_device_src) {
+ int r;
+
+ assert(udev_device_dst);
+ assert(udev_device_src);
+
+ r = device_copy_properties(udev_device_dst->device, udev_device_src->device);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+const char *udev_device_get_id_filename(struct udev_device *udev_device) {
+ const char *filename;
+ int r;
+
+ assert(udev_device);
+
+ r = device_get_id_filename(udev_device->device, &filename);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
+ }
+
+ return filename;
+}
+
+int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) {
+
+ assert(udev_device);
+
+ device_set_watch_handle(udev_device->device, handle);
+
+ return 0;
+}
+
+void udev_device_set_db_persist(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ device_set_db_persist(udev_device->device);
+}
+
+int udev_device_set_devlink_priority(struct udev_device *udev_device, int priority) {
+ assert(udev_device);
+
+ device_set_devlink_priority(udev_device->device, priority);
+
+ return 0;
+}
+
+int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink) {
+ int r;
+
+ assert(udev_device);
+
+ r = device_add_devlink(udev_device->device, devlink);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int udev_device_add_property(struct udev_device *udev_device, const char *property, const char *value) {
+ int r;
+
+ assert(udev_device);
+
+ r = device_add_property(udev_device->device, property, value);
+ if (r < 0)
+ return r;
- id = udev_device_get_id_filename(udev_device);
- if (id == NULL)
- return -1;
- strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
- unlink(filename);
return 0;
}
+
+int udev_device_add_tag(struct udev_device *udev_device, const char *tag) {
+ int r;
+
+ assert(udev_device);
+
+ r = device_add_tag(udev_device->device, tag);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+void udev_device_remove_tag(struct udev_device *udev_device, const char *tag) {
+ assert(udev_device);
+
+ device_remove_tag(udev_device->device, tag);
+}
+
+void udev_device_cleanup_tags_list(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ device_cleanup_tags(udev_device->device);
+}
+
+void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ device_cleanup_devlinks(udev_device->device);
+}
+
+void udev_device_set_info_loaded(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ device_seal(udev_device->device);
+}
+
+void udev_device_read_db(struct udev_device *udev_device) {
+ assert(udev_device);
+
+ device_read_db_force(udev_device->device);
+}
diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
index 9863901a33..c27b01db96 100644
--- a/src/libudev/libudev-device.c
+++ b/src/libudev/libudev-device.c
@@ -2,6 +2,7 @@
This file is part of systemd.
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2015 Tom Gundersen <teg@jklm.no>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -33,10 +34,13 @@
#include <sys/socket.h>
#include <linux/sockios.h>
+#include "sd-device.h"
+#include "device-util.h"
+#include "device-private.h"
+
#include "libudev.h"
#include "libudev-private.h"
-
-static int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
+#include "libudev-device-internal.h"
/**
* SECTION:libudev-device
@@ -49,59 +53,6 @@ static int udev_device_set_devnode(struct udev_device *udev_device, const char *
*/
/**
- * udev_device:
- *
- * Opaque object representing one kernel sys device.
- */
-struct udev_device {
- struct udev *udev;
- struct udev_device *parent_device;
- char *syspath;
- const char *devpath;
- char *sysname;
- const char *sysnum;
- char *devnode;
- mode_t devnode_mode;
- uid_t devnode_uid;
- gid_t devnode_gid;
- char *subsystem;
- char *devtype;
- char *driver;
- char *action;
- char *devpath_old;
- char *id_filename;
- char **envp;
- char *monitor_buf;
- size_t monitor_buf_len;
- struct udev_list devlinks_list;
- struct udev_list properties_list;
- struct udev_list sysattr_value_list;
- struct udev_list sysattr_list;
- struct udev_list tags_list;
- unsigned long long int seqnum;
- usec_t usec_initialized;
- int devlink_priority;
- int refcount;
- dev_t devnum;
- int ifindex;
- int watch_handle;
- int maj, min;
- bool parent_set;
- bool subsystem_set;
- bool devtype_set;
- bool devlinks_uptodate;
- bool envp_uptodate;
- bool tags_uptodate;
- bool driver_set;
- bool info_loaded;
- bool db_loaded;
- bool uevent_loaded;
- bool is_initialized;
- bool sysattr_list_read;
- bool db_persist;
-};
-
-/**
* udev_device_get_seqnum:
* @udev_device: udev device
*
@@ -112,36 +63,27 @@ struct udev_device {
**/
_public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return 0;
- return udev_device->seqnum;
-}
-
-static int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
-{
- char num[32];
+ const char *seqnum;
+ unsigned long long ret;
+ int r;
- udev_device->seqnum = seqnum;
- snprintf(num, sizeof(num), "%llu", seqnum);
- udev_device_add_property(udev_device, "SEQNUM", num);
- return 0;
-}
+ assert_return_errno(udev_device, 0, EINVAL);
-int udev_device_get_ifindex(struct udev_device *udev_device)
-{
- if (!udev_device->info_loaded)
- udev_device_read_uevent_file(udev_device);
- return udev_device->ifindex;
-}
+ r = sd_device_get_property_value(udev_device->device, "SEQNUM", &seqnum);
+ if (r == -ENOENT)
+ return 0;
+ else if (r < 0) {
+ errno = -r;
+ return 0;
+ }
-static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex)
-{
- char num[32];
+ r = safe_atollu(seqnum, &ret);
+ if (r < 0) {
+ errno = -r;
+ return 0;
+ }
- udev_device->ifindex = ifindex;
- snprintf(num, sizeof(num), "%d", ifindex);
- udev_device_add_property(udev_device, "IFINDEX", num);
- return 0;
+ return ret;
}
/**
@@ -154,45 +96,18 @@ static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex)
**/
_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return makedev(0, 0);
- if (!udev_device->info_loaded)
- udev_device_read_uevent_file(udev_device);
- return udev_device->devnum;
-}
-
-static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
-{
- char num[32];
-
- udev_device->devnum = devnum;
-
- snprintf(num, sizeof(num), "%u", major(devnum));
- udev_device_add_property(udev_device, "MAJOR", num);
- snprintf(num, sizeof(num), "%u", minor(devnum));
- udev_device_add_property(udev_device, "MINOR", num);
- return 0;
-}
-
-const char *udev_device_get_devpath_old(struct udev_device *udev_device)
-{
- return udev_device->devpath_old;
-}
+ dev_t devnum;
+ int r;
-static int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
-{
- const char *pos;
+ assert_return_errno(udev_device, makedev(0, 0), EINVAL);
- free(udev_device->devpath_old);
- udev_device->devpath_old = strdup(devpath_old);
- if (udev_device->devpath_old == NULL)
- return -ENOMEM;
- udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old);
+ r = sd_device_get_devnum(udev_device->device, &devnum);
+ if (r < 0) {
+ errno = -r;
+ return makedev(0, 0);
+ }
- pos = strrchr(udev_device->devpath_old, '/');
- if (pos == NULL)
- return -EINVAL;
- return 0;
+ return devnum;
}
/**
@@ -205,27 +120,18 @@ static int udev_device_set_devpath_old(struct udev_device *udev_device, const ch
**/
_public_ const char *udev_device_get_driver(struct udev_device *udev_device)
{
- char driver[UTIL_NAME_SIZE];
+ const char *driver;
+ int r;
- if (udev_device == NULL)
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_driver(udev_device->device, &driver);
+ if (r < 0) {
+ errno = -r;
return NULL;
- if (!udev_device->driver_set) {
- udev_device->driver_set = true;
- if (util_get_sys_core_link_value(udev_device->udev, "driver", udev_device->syspath, driver, sizeof(driver)) > 0)
- udev_device->driver = strdup(driver);
}
- return udev_device->driver;
-}
-static int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
-{
- free(udev_device->driver);
- udev_device->driver = strdup(driver);
- if (udev_device->driver == NULL)
- return -ENOMEM;
- udev_device->driver_set = true;
- udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
- return 0;
+ return driver;
}
/**
@@ -238,35 +144,18 @@ static int udev_device_set_driver(struct udev_device *udev_device, const char *d
**/
_public_ const char *udev_device_get_devtype(struct udev_device *udev_device)
{
- if (udev_device == NULL)
+ const char *devtype;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_devtype(udev_device->device, &devtype);
+ if (r < 0) {
+ errno = -r;
return NULL;
- if (!udev_device->devtype_set) {
- udev_device->devtype_set = true;
- udev_device_read_uevent_file(udev_device);
}
- return udev_device->devtype;
-}
-static int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype)
-{
- free(udev_device->devtype);
- udev_device->devtype = strdup(devtype);
- if (udev_device->devtype == NULL)
- return -ENOMEM;
- udev_device->devtype_set = true;
- udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
- return 0;
-}
-
-static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
-{
- free(udev_device->subsystem);
- udev_device->subsystem = strdup(subsystem);
- if (udev_device->subsystem == NULL)
- return -ENOMEM;
- udev_device->subsystem_set = true;
- udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
- return 0;
+ return devtype;
}
/**
@@ -280,251 +169,19 @@ static int udev_device_set_subsystem(struct udev_device *udev_device, const char
**/
_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device)
{
- char subsystem[UTIL_NAME_SIZE];
-
- if (udev_device == NULL)
- return NULL;
- if (!udev_device->subsystem_set) {
- udev_device->subsystem_set = true;
- /* read "subsystem" link */
- if (util_get_sys_core_link_value(udev_device->udev, "subsystem", udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
- udev_device_set_subsystem(udev_device, subsystem);
- return udev_device->subsystem;
- }
- /* implicit names */
- if (startswith(udev_device->devpath, "/module/")) {
- udev_device_set_subsystem(udev_device, "module");
- return udev_device->subsystem;
- }
- if (strstr(udev_device->devpath, "/drivers/") != NULL) {
- udev_device_set_subsystem(udev_device, "drivers");
- return udev_device->subsystem;
- }
- if (startswith(udev_device->devpath, "/subsystem/") ||
- startswith(udev_device->devpath, "/class/") ||
- startswith(udev_device->devpath, "/bus/")) {
- udev_device_set_subsystem(udev_device, "subsystem");
- return udev_device->subsystem;
- }
- }
- return udev_device->subsystem;
-}
-
-mode_t udev_device_get_devnode_mode(struct udev_device *udev_device)
-{
- if (!udev_device->info_loaded)
- udev_device_read_uevent_file(udev_device);
- return udev_device->devnode_mode;
-}
-
-static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t mode)
-{
- char num[32];
-
- udev_device->devnode_mode = mode;
- snprintf(num, sizeof(num), "%#o", mode);
- udev_device_add_property(udev_device, "DEVMODE", num);
- return 0;
-}
-
-uid_t udev_device_get_devnode_uid(struct udev_device *udev_device)
-{
- if (!udev_device->info_loaded)
- udev_device_read_uevent_file(udev_device);
- return udev_device->devnode_uid;
-}
-
-static int udev_device_set_devnode_uid(struct udev_device *udev_device, uid_t uid)
-{
- char num[32];
-
- udev_device->devnode_uid = uid;
- snprintf(num, sizeof(num), "%u", uid);
- udev_device_add_property(udev_device, "DEVUID", num);
- return 0;
-}
-
-gid_t udev_device_get_devnode_gid(struct udev_device *udev_device)
-{
- if (!udev_device->info_loaded)
- udev_device_read_uevent_file(udev_device);
- return udev_device->devnode_gid;
-}
-
-static int udev_device_set_devnode_gid(struct udev_device *udev_device, gid_t gid)
-{
- char num[32];
-
- udev_device->devnode_gid = gid;
- snprintf(num, sizeof(num), "%u", gid);
- udev_device_add_property(udev_device, "DEVGID", num);
- return 0;
-}
-
-struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
-{
- udev_device->envp_uptodate = false;
- if (value == NULL) {
- struct udev_list_entry *list_entry;
-
- list_entry = udev_device_get_properties_list_entry(udev_device);
- list_entry = udev_list_entry_get_by_name(list_entry, key);
- if (list_entry != NULL)
- udev_list_entry_delete(list_entry);
- return NULL;
- }
- return udev_list_entry_add(&udev_device->properties_list, key, value);
-}
+ const char *subsystem;
+ int r;
-static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property)
-{
- char name[UTIL_LINE_SIZE];
- char *val;
+ assert_return_errno(udev_device, NULL, EINVAL);
- strscpy(name, sizeof(name), property);
- val = strchr(name, '=');
- if (val == NULL)
+ r = sd_device_get_subsystem(udev_device->device, &subsystem);
+ if (r < 0) {
+ errno = -r;
return NULL;
- val[0] = '\0';
- val = &val[1];
- if (val[0] == '\0')
- val = NULL;
- return udev_device_add_property(udev_device, name, val);
-}
-
-static int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath)
-{
- const char *pos;
- size_t len;
-
- free(udev_device->syspath);
- udev_device->syspath = strdup(syspath);
- if (udev_device->syspath == NULL)
- return -ENOMEM;
- udev_device->devpath = udev_device->syspath + strlen("/sys");
- udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath);
-
- pos = strrchr(udev_device->syspath, '/');
- if (pos == NULL)
- return -EINVAL;
- udev_device->sysname = strdup(&pos[1]);
- if (udev_device->sysname == NULL)
- return -ENOMEM;
-
- /* some devices have '!' in their name, change that to '/' */
- len = 0;
- while (udev_device->sysname[len] != '\0') {
- if (udev_device->sysname[len] == '!')
- udev_device->sysname[len] = '/';
- len++;
- }
-
- /* trailing number */
- while (len > 0 && isdigit(udev_device->sysname[--len]))
- udev_device->sysnum = &udev_device->sysname[len];
-
- /* sysname is completely numeric */
- if (len == 0)
- udev_device->sysnum = NULL;
-
- return 0;
-}
-
-/*
- * parse property string, and if needed, update internal values accordingly
- *
- * udev_device_add_property_from_string_parse_finish() needs to be
- * called after adding properties, and its return value checked
- *
- * udev_device_set_info_loaded() needs to be set, to avoid trying
- * to use a device without a DEVPATH set
- */
-void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property)
-{
- if (startswith(property, "DEVPATH=")) {
- char path[UTIL_PATH_SIZE];
-
- strscpyl(path, sizeof(path), "/sys", &property[8], NULL);
- udev_device_set_syspath(udev_device, path);
- } else if (startswith(property, "SUBSYSTEM=")) {
- udev_device_set_subsystem(udev_device, &property[10]);
- } else if (startswith(property, "DEVTYPE=")) {
- udev_device_set_devtype(udev_device, &property[8]);
- } else if (startswith(property, "DEVNAME=")) {
- udev_device_set_devnode(udev_device, &property[8]);
- } else if (startswith(property, "DEVLINKS=")) {
- char devlinks[UTIL_PATH_SIZE];
- char *slink;
- char *next;
-
- strscpy(devlinks, sizeof(devlinks), &property[9]);
- slink = devlinks;
- next = strchr(slink, ' ');
- while (next != NULL) {
- next[0] = '\0';
- udev_device_add_devlink(udev_device, slink);
- slink = &next[1];
- next = strchr(slink, ' ');
- }
- if (slink[0] != '\0')
- udev_device_add_devlink(udev_device, slink);
- } else if (startswith(property, "TAGS=")) {
- char tags[UTIL_PATH_SIZE];
- char *next;
-
- strscpy(tags, sizeof(tags), &property[5]);
- next = strchr(tags, ':');
- if (next != NULL) {
- next++;
- while (next[0] != '\0') {
- char *tag;
-
- tag = next;
- next = strchr(tag, ':');
- if (next == NULL)
- break;
- next[0] = '\0';
- next++;
- udev_device_add_tag(udev_device, tag);
- }
- }
- } else if (startswith(property, "USEC_INITIALIZED=")) {
- udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10));
- } else if (startswith(property, "DRIVER=")) {
- udev_device_set_driver(udev_device, &property[7]);
- } else if (startswith(property, "ACTION=")) {
- udev_device_set_action(udev_device, &property[7]);
- } else if (startswith(property, "MAJOR=")) {
- udev_device->maj = strtoull(&property[6], NULL, 10);
- } else if (startswith(property, "MINOR=")) {
- udev_device->min = strtoull(&property[6], NULL, 10);
- } else if (startswith(property, "DEVPATH_OLD=")) {
- udev_device_set_devpath_old(udev_device, &property[12]);
- } else if (startswith(property, "SEQNUM=")) {
- udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10));
- } else if (startswith(property, "IFINDEX=")) {
- udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10));
- } else if (startswith(property, "DEVMODE=")) {
- udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8));
- } else if (startswith(property, "DEVUID=")) {
- udev_device_set_devnode_uid(udev_device, strtoul(&property[7], NULL, 10));
- } else if (startswith(property, "DEVGID=")) {
- udev_device_set_devnode_gid(udev_device, strtoul(&property[7], NULL, 10));
- } else {
- udev_device_add_property_from_string(udev_device, property);
- }
-}
-
-int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device)
-{
- if (udev_device->maj > 0)
- udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min));
- udev_device->maj = 0;
- udev_device->min = 0;
+ } else if (!subsystem)
+ errno = ENODATA;
- if (udev_device->devpath == NULL || udev_device->subsystem == NULL)
- return -EINVAL;
- return 0;
+ return subsystem;
}
/**
@@ -538,165 +195,36 @@ int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_d
**/
_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
{
- struct udev_list_entry *list_entry;
-
- if (udev_device == NULL)
- return NULL;
- if (key == NULL)
- return NULL;
-
- list_entry = udev_device_get_properties_list_entry(udev_device);
- list_entry = udev_list_entry_get_by_name(list_entry, key);
- return udev_list_entry_get_value(list_entry);
-}
-
-int udev_device_read_db(struct udev_device *udev_device, const char *dbfile)
-{
- char filename[UTIL_PATH_SIZE];
- char line[UTIL_LINE_SIZE];
- FILE *f;
-
- /* providing a database file will always force-load it */
- if (dbfile == NULL) {
- const char *id;
-
- if (udev_device->db_loaded)
- return 0;
- udev_device->db_loaded = true;
-
- id = udev_device_get_id_filename(udev_device);
- if (id == NULL)
- return -1;
- strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
- dbfile = filename;
- }
-
- f = fopen(dbfile, "re");
- if (f == NULL)
- return log_debug_errno(errno, "no db file to read %s: %m", dbfile);
-
- /* devices with a database entry are initialized */
- udev_device->is_initialized = true;
-
- while (fgets(line, sizeof(line), f)) {
- ssize_t len;
- const char *val;
- struct udev_list_entry *entry;
-
- len = strlen(line);
- if (len < 4)
- break;
- line[len-1] = '\0';
- val = &line[2];
- switch(line[0]) {
- case 'S':
- strscpyl(filename, sizeof(filename), "/dev/", val, NULL);
- udev_device_add_devlink(udev_device, filename);
- break;
- case 'L':
- udev_device_set_devlink_priority(udev_device, atoi(val));
- break;
- case 'E':
- entry = udev_device_add_property_from_string(udev_device, val);
- udev_list_entry_set_num(entry, true);
- break;
- case 'G':
- udev_device_add_tag(udev_device, val);
- break;
- case 'W':
- udev_device_set_watch_handle(udev_device, atoi(val));
- break;
- case 'I':
- udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10));
- break;
- }
- }
- fclose(f);
-
- log_debug("device %p filled with db file data", udev_device);
- return 0;
-}
-
-int udev_device_read_uevent_file(struct udev_device *udev_device)
-{
- char filename[UTIL_PATH_SIZE];
- FILE *f;
- char line[UTIL_LINE_SIZE];
- int maj = 0;
- int min = 0;
+ const char *value = NULL;
+ int r;
- if (udev_device->uevent_loaded)
- return 0;
+ assert_return_errno(udev_device && key, NULL, EINVAL);
- strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
- f = fopen(filename, "re");
- if (f == NULL)
- return -errno;
- udev_device->uevent_loaded = true;
-
- while (fgets(line, sizeof(line), f)) {
- char *pos;
-
- pos = strchr(line, '\n');
- if (pos == NULL)
- continue;
- pos[0] = '\0';
-
- if (startswith(line, "DEVTYPE=")) {
- udev_device_set_devtype(udev_device, &line[8]);
- continue;
- }
- if (startswith(line, "IFINDEX=")) {
- udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10));
- continue;
- }
- if (startswith(line, "DEVNAME=")) {
- udev_device_set_devnode(udev_device, &line[8]);
- continue;
- }
-
- if (startswith(line, "MAJOR="))
- maj = strtoull(&line[6], NULL, 10);
- else if (startswith(line, "MINOR="))
- min = strtoull(&line[6], NULL, 10);
- else if (startswith(line, "DEVMODE="))
- udev_device->devnode_mode = strtoul(&line[8], NULL, 8);
-
- udev_device_add_property_from_string(udev_device, line);
+ r = sd_device_get_property_value(udev_device->device, key, &value);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
}
- udev_device->devnum = makedev(maj, min);
- fclose(f);
- return 0;
-}
-
-void udev_device_set_info_loaded(struct udev_device *device)
-{
- device->info_loaded = true;
+ return value;
}
-static struct udev_device *udev_device_new(struct udev *udev)
-{
+struct udev_device *udev_device_new(struct udev *udev) {
struct udev_device *udev_device;
- if (udev == NULL) {
- errno = EINVAL;
- return NULL;
- }
+ assert_return_errno(udev, NULL, EINVAL);
udev_device = new0(struct udev_device, 1);
- if (udev_device == NULL) {
+ if (!udev_device) {
errno = ENOMEM;
return NULL;
}
udev_device->refcount = 1;
udev_device->udev = udev;
- udev_list_init(udev, &udev_device->devlinks_list, true);
- udev_list_init(udev, &udev_device->properties_list, true);
- udev_list_init(udev, &udev_device->sysattr_value_list, true);
- udev_list_init(udev, &udev_device->sysattr_list, false);
- udev_list_init(udev, &udev_device->tags_list, true);
- udev_device->watch_handle = -1;
+ udev_list_init(udev, &udev_device->properties, true);
+ udev_list_init(udev, &udev_device->tags, true);
+ udev_list_init(udev, &udev_device->sysattrs, true);
+ udev_list_init(udev, &udev_device->devlinks, true);
return udev_device;
}
@@ -715,68 +243,21 @@ static struct udev_device *udev_device_new(struct udev *udev)
*
* Returns: a new udev device, or #NULL, if it does not exist
**/
-_public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
-{
- const char *subdir;
- char path[UTIL_PATH_SIZE];
- char *pos;
- struct stat statbuf;
+_public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
struct udev_device *udev_device;
+ int r;
- if (udev == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- if (syspath == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- /* path starts in sys */
- if (!startswith(syspath, "/sys")) {
- log_debug("not in sys :%s", syspath);
- errno = EINVAL;
+ udev_device = udev_device_new(udev);
+ if (!udev_device)
return NULL;
- }
- /* path is not a root directory */
- subdir = syspath + strlen("/sys");
- pos = strrchr(subdir, '/');
- if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
- errno = EINVAL;
+ r = sd_device_new_from_syspath(&udev_device->device, syspath);
+ if (r < 0) {
+ errno = -r;
+ udev_device_unref(udev_device);
return NULL;
}
- /* resolve possible symlink to real path */
- strscpy(path, sizeof(path), syspath);
- util_resolve_sys_link(udev, path, sizeof(path));
-
- if (startswith(path + strlen("/sys"), "/devices/")) {
- char file[UTIL_PATH_SIZE];
-
- /* all "devices" require a "uevent" file */
- strscpyl(file, sizeof(file), path, "/uevent", NULL);
- if (stat(file, &statbuf) != 0)
- return NULL;
- } else {
- /* everything else just needs to be a directory */
- if (stat(path, &statbuf) != 0)
- return NULL;
-
- if (!S_ISDIR(statbuf.st_mode)) {
- errno = EISDIR;
- return NULL;
- }
- }
-
- udev_device = udev_device_new(udev);
- if (udev_device == NULL)
- return NULL;
-
- udev_device_set_syspath(udev_device, path);
- log_debug("device %p has devpath '%s'", udev_device, udev_device_get_devpath(udev_device));
-
return udev_device;
}
@@ -798,22 +279,21 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con
**/
_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
{
- char path[UTIL_PATH_SIZE];
- const char *type_str;
-
- if (type == 'b')
- type_str = "block";
- else if (type == 'c')
- type_str = "char";
- else {
- errno = EINVAL;
+ struct udev_device *udev_device;
+ int r;
+
+ udev_device = udev_device_new(udev);
+ if (!udev_device)
+ return NULL;
+
+ r = sd_device_new_from_devnum(&udev_device->device, type, devnum);
+ if (r < 0) {
+ errno = -r;
+ udev_device_unref(udev_device);
return NULL;
}
- /* use /sys/dev/{block,char}/<maj>:<min> link */
- snprintf(path, sizeof(path), "/sys/dev/%s/%u:%u",
- type_str, major(devnum), minor(devnum));
- return udev_device_new_from_syspath(udev, path);
+ return udev_device;
}
/**
@@ -836,65 +316,21 @@ _public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char
**/
_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id)
{
- char type;
- int maj, min;
- char subsys[UTIL_PATH_SIZE];
- char *sysname;
-
- switch(id[0]) {
- case 'b':
- case 'c':
- if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3)
- return NULL;
- return udev_device_new_from_devnum(udev, type, makedev(maj, min));
- case 'n': {
- int sk;
- struct ifreq ifr;
- struct udev_device *dev;
- int ifindex;
-
- ifindex = strtoul(&id[1], NULL, 10);
- if (ifindex <= 0) {
- errno = EINVAL;
- return NULL;
- }
-
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return NULL;
- memzero(&ifr, sizeof(struct ifreq));
- ifr.ifr_ifindex = ifindex;
- if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) {
- close(sk);
- return NULL;
- }
- close(sk);
-
- dev = udev_device_new_from_subsystem_sysname(udev, "net", ifr.ifr_name);
- if (dev == NULL)
- return NULL;
- if (udev_device_get_ifindex(dev) == ifindex)
- return dev;
-
- /* this is racy, so we may end up with the wrong device */
- udev_device_unref(dev);
- errno = ENODEV;
+ struct udev_device *udev_device;
+ int r;
+
+ udev_device = udev_device_new(udev);
+ if (!udev_device)
return NULL;
- }
- case '+':
- strscpy(subsys, sizeof(subsys), &id[1]);
- sysname = strchr(subsys, ':');
- if (sysname == NULL) {
- errno = EINVAL;
- return NULL;
- }
- sysname[0] = '\0';
- sysname = &sysname[1];
- return udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
- default:
- errno = EINVAL;
+
+ r = sd_device_new_from_device_id(&udev_device->device, id);
+ if (r < 0) {
+ errno = -r;
+ udev_device_unref(udev_device);
return NULL;
}
+
+ return udev_device;
}
/**
@@ -914,69 +350,21 @@ _public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, c
**/
_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
{
- char path[UTIL_PATH_SIZE];
- struct stat statbuf;
-
- if (streq(subsystem, "subsystem")) {
- strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
-
- strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
-
- strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
- goto out;
- }
-
- if (streq(subsystem, "module")) {
- strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
- goto out;
- }
-
- if (streq(subsystem, "drivers")) {
- char subsys[UTIL_NAME_SIZE];
- char *driver;
-
- strscpy(subsys, sizeof(subsys), sysname);
- driver = strchr(subsys, ':');
- if (driver != NULL) {
- driver[0] = '\0';
- driver = &driver[1];
-
- strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, "/drivers/", driver, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
+ struct udev_device *udev_device;
+ int r;
- strscpyl(path, sizeof(path), "/sys/bus/", subsys, "/drivers/", driver, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
- } else
- errno = EINVAL;
+ udev_device = udev_device_new(udev);
+ if (!udev_device)
+ return NULL;
- goto out;
+ r = sd_device_new_from_subsystem_sysname(&udev_device->device, subsystem, sysname);
+ if (r < 0) {
+ errno = -r;
+ udev_device_unref(udev_device);
+ return NULL;
}
- strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
-
- strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
-
- strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, NULL);
- if (stat(path, &statbuf) == 0)
- goto found;
-out:
- return NULL;
-found:
- return udev_device_new_from_syspath(udev, path);
+ return udev_device;
}
/**
@@ -995,48 +383,45 @@ found:
**/
_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev)
{
- int i;
struct udev_device *udev_device;
+ int r;
udev_device = udev_device_new(udev);
- if (udev_device == NULL)
+ if (!udev_device)
return NULL;
- udev_device_set_info_loaded(udev_device);
- for (i = 0; environ[i] != NULL; i++)
- udev_device_add_property_from_string_parse(udev_device, environ[i]);
-
- if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
- log_debug("missing values, invalid device");
+ r = device_new_from_strv(&udev_device->device, environ);
+ if (r < 0) {
+ errno = -r;
udev_device_unref(udev_device);
- udev_device = NULL;
+ return NULL;
}
return udev_device;
}
-static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
+static struct udev_device *device_new_from_parent(struct udev_device *child)
{
- struct udev_device *udev_device_parent = NULL;
- char path[UTIL_PATH_SIZE];
- const char *subdir;
-
- strscpy(path, sizeof(path), udev_device->syspath);
- subdir = path + strlen("/sys/");
- for (;;) {
- char *pos;
-
- pos = strrchr(subdir, '/');
- if (pos == NULL || pos < &subdir[2])
- break;
- pos[0] = '\0';
- udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
- if (udev_device_parent != NULL)
- return udev_device_parent;
+ struct udev_device *parent;
+ int r;
+
+ assert_return_errno(child, NULL, EINVAL);
+
+ parent = udev_device_new(child->udev);
+ if (!parent)
+ return NULL;
+
+ r = sd_device_get_parent(child->device, &parent->device);
+ if (r < 0) {
+ errno = -r;
+ udev_device_unref(parent);
+ return NULL;
}
- errno = ENOENT;
- return NULL;
+ /* the parent is unref'ed with the child, so take a ref from libudev as well */
+ sd_device_ref(parent->device);
+
+ return parent;
}
/**
@@ -1059,15 +444,15 @@ static struct udev_device *device_new_from_parent(struct udev_device *udev_devic
**/
_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
{
- if (udev_device == NULL) {
- errno = EINVAL;
- return NULL;
- }
+ assert_return_errno(udev_device, NULL, EINVAL);
+
if (!udev_device->parent_set) {
udev_device->parent_set = true;
- udev_device->parent_device = device_new_from_parent(udev_device);
+ udev_device->parent = device_new_from_parent(udev_device);
}
- return udev_device->parent_device;
+
+ /* TODO: errno will differ here in case parent == NULL */
+ return udev_device->parent;
}
/**
@@ -1093,33 +478,30 @@ _public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_dev
**/
_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
{
- struct udev_device *parent;
+ sd_device *parent;
+ int r;
- if (subsystem == NULL) {
- errno = EINVAL;
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ /* this relies on the fact that finding the subdevice of a parent or the
+ parent of a subdevice commute */
+
+ /* first find the correct sd_device */
+ r = sd_device_get_parent_with_subsystem_devtype(udev_device->device, subsystem, devtype, &parent);
+ if (r < 0) {
+ errno = -r;
return NULL;
}
- parent = udev_device_get_parent(udev_device);
- while (parent != NULL) {
- const char *parent_subsystem;
- const char *parent_devtype;
-
- parent_subsystem = udev_device_get_subsystem(parent);
- if (parent_subsystem != NULL && streq(parent_subsystem, subsystem)) {
- if (devtype == NULL)
- break;
- parent_devtype = udev_device_get_devtype(parent);
- if (parent_devtype != NULL && streq(parent_devtype, devtype))
- break;
- }
- parent = udev_device_get_parent(parent);
+ /* then walk the chain of udev_device parents until the correspanding
+ one is found */
+ while ((udev_device = udev_device_get_parent(udev_device))) {
+ if (udev_device->device == parent)
+ return udev_device;
}
- if (!parent)
- errno = ENOENT;
-
- return parent;
+ errno = ENOENT;
+ return NULL;
}
/**
@@ -1132,8 +514,8 @@ _public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struc
**/
_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return NULL;
+ assert_return_errno(udev_device, NULL, EINVAL);
+
return udev_device->udev;
}
@@ -1147,9 +529,9 @@ _public_ struct udev *udev_device_get_udev(struct udev_device *udev_device)
**/
_public_ struct udev_device *udev_device_ref(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return NULL;
- udev_device->refcount++;
+ if (udev_device)
+ udev_device->refcount++;
+
return udev_device;
}
@@ -1164,30 +546,18 @@ _public_ struct udev_device *udev_device_ref(struct udev_device *udev_device)
**/
_public_ struct udev_device *udev_device_unref(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return NULL;
- udev_device->refcount--;
- if (udev_device->refcount > 0)
- return NULL;
- if (udev_device->parent_device != NULL)
- udev_device_unref(udev_device->parent_device);
- free(udev_device->syspath);
- free(udev_device->sysname);
- free(udev_device->devnode);
- free(udev_device->subsystem);
- free(udev_device->devtype);
- udev_list_cleanup(&udev_device->devlinks_list);
- udev_list_cleanup(&udev_device->properties_list);
- udev_list_cleanup(&udev_device->sysattr_value_list);
- udev_list_cleanup(&udev_device->sysattr_list);
- udev_list_cleanup(&udev_device->tags_list);
- free(udev_device->action);
- free(udev_device->driver);
- free(udev_device->devpath_old);
- free(udev_device->id_filename);
- free(udev_device->envp);
- free(udev_device->monitor_buf);
- free(udev_device);
+ if (udev_device && (-- udev_device->refcount) == 0) {
+ sd_device_unref(udev_device->device);
+ udev_device_unref(udev_device->parent);
+
+ udev_list_cleanup(&udev_device->properties);
+ udev_list_cleanup(&udev_device->sysattrs);
+ udev_list_cleanup(&udev_device->tags);
+ udev_list_cleanup(&udev_device->devlinks);
+
+ free(udev_device);
+ }
+
return NULL;
}
@@ -1202,9 +572,18 @@ _public_ struct udev_device *udev_device_unref(struct udev_device *udev_device)
**/
_public_ const char *udev_device_get_devpath(struct udev_device *udev_device)
{
- if (udev_device == NULL)
+ const char *devpath;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_devpath(udev_device->device, &devpath);
+ if (r < 0) {
+ errno = -r;
return NULL;
- return udev_device->devpath;
+ }
+
+ return devpath;
}
/**
@@ -1218,9 +597,18 @@ _public_ const char *udev_device_get_devpath(struct udev_device *udev_device)
**/
_public_ const char *udev_device_get_syspath(struct udev_device *udev_device)
{
- if (udev_device == NULL)
+ const char *syspath;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_syspath(udev_device->device, &syspath);
+ if (r < 0) {
+ errno = -r;
return NULL;
- return udev_device->syspath;
+ }
+
+ return syspath;
}
/**
@@ -1233,9 +621,18 @@ _public_ const char *udev_device_get_syspath(struct udev_device *udev_device)
**/
_public_ const char *udev_device_get_sysname(struct udev_device *udev_device)
{
- if (udev_device == NULL)
+ const char *sysname;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_sysname(udev_device->device, &sysname);
+ if (r < 0) {
+ errno = -r;
return NULL;
- return udev_device->sysname;
+ }
+
+ return sysname;
}
/**
@@ -1248,9 +645,18 @@ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device)
**/
_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device)
{
- if (udev_device == NULL)
+ const char *sysnum;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_sysnum(udev_device->device, &sysnum);
+ if (r < 0) {
+ errno = -r;
return NULL;
- return udev_device->sysnum;
+ }
+
+ return sysnum;
}
/**
@@ -1264,13 +670,18 @@ _public_ const char *udev_device_get_sysnum(struct udev_device *udev_device)
**/
_public_ const char *udev_device_get_devnode(struct udev_device *udev_device)
{
- if (udev_device == NULL)
+ const char *devnode;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_devname(udev_device->device, &devnode);
+ if (r < 0) {
+ errno = -r;
return NULL;
- if (udev_device->devnode != NULL)
- return udev_device->devnode;
- if (!udev_device->info_loaded)
- udev_device_read_uevent_file(udev_device);
- return udev_device->devnode;
+ }
+
+ return devnode;
}
/**
@@ -1288,21 +699,26 @@ _public_ const char *udev_device_get_devnode(struct udev_device *udev_device)
**/
_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return NULL;
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- return udev_list_get_entry(&udev_device->devlinks_list);
-}
+ assert_return_errno(udev_device, NULL, EINVAL);
-void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
-{
- udev_device->devlinks_uptodate = false;
- udev_list_cleanup(&udev_device->devlinks_list);
+ if (device_get_devlinks_generation(udev_device->device) != udev_device->devlinks_generation ||
+ !udev_device->devlinks_read) {
+ const char *devlink;
+
+ udev_list_cleanup(&udev_device->devlinks);
+
+ FOREACH_DEVICE_DEVLINK(udev_device->device, devlink)
+ udev_list_entry_add(&udev_device->devlinks, devlink, NULL);
+
+ udev_device->devlinks_read = true;
+ udev_device->devlinks_generation = device_get_devlinks_generation(udev_device->device);
+ }
+
+ return udev_list_get_entry(&udev_device->devlinks);
}
/**
- * udev_device_get_properties_list_entry:
+ * udev_device_get_event_properties_entry:
* @udev_device: udev device
*
* Retrieve the list of key/value device properties of the udev
@@ -1315,45 +731,22 @@ void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
**/
_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return NULL;
- if (!udev_device->info_loaded) {
- udev_device_read_uevent_file(udev_device);
- udev_device_read_db(udev_device, NULL);
- }
- if (!udev_device->devlinks_uptodate) {
- char symlinks[UTIL_PATH_SIZE];
- struct udev_list_entry *list_entry;
-
- udev_device->devlinks_uptodate = true;
- list_entry = udev_device_get_devlinks_list_entry(udev_device);
- if (list_entry != NULL) {
- char *s;
- size_t l;
-
- s = symlinks;
- l = strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL);
- udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
- l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL);
- udev_device_add_property(udev_device, "DEVLINKS", symlinks);
- }
- }
- if (!udev_device->tags_uptodate) {
- udev_device->tags_uptodate = true;
- if (udev_device_get_tags_list_entry(udev_device) != NULL) {
- char tags[UTIL_PATH_SIZE];
- struct udev_list_entry *list_entry;
- char *s;
- size_t l;
-
- s = tags;
- l = strpcpyl(&s, sizeof(tags), ":", NULL);
- udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
- l = strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL);
- udev_device_add_property(udev_device, "TAGS", tags);
- }
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ if (device_get_properties_generation(udev_device->device) != udev_device->properties_generation ||
+ !udev_device->properties_read) {
+ const char *key, *value;
+
+ udev_list_cleanup(&udev_device->properties);
+
+ FOREACH_DEVICE_PROPERTY(udev_device->device, key, value)
+ udev_list_entry_add(&udev_device->properties, key, value);
+
+ udev_device->properties_read = true;
+ udev_device->properties_generation = device_get_properties_generation(udev_device->device);
}
- return udev_list_get_entry(&udev_device->properties_list);
+
+ return udev_list_get_entry(&udev_device->properties);
}
/**
@@ -1366,11 +759,19 @@ _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct ud
*
* Returns: the kernel action value, or #NULL if there is no action value available.
**/
-_public_ const char *udev_device_get_action(struct udev_device *udev_device)
-{
- if (udev_device == NULL)
+_public_ const char *udev_device_get_action(struct udev_device *udev_device) {
+ const char *action = NULL;
+ int r;
+
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ r = sd_device_get_property_value(udev_device->device, "ACTION", &action);
+ if (r < 0 && r != -ENOENT) {
+ errno = -r;
return NULL;
- return udev_device->action;
+ }
+
+ return action;
}
/**
@@ -1387,32 +788,18 @@ _public_ const char *udev_device_get_action(struct udev_device *udev_device)
**/
_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
{
- usec_t now_ts;
-
- if (udev_device == NULL)
- return 0;
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- if (udev_device->usec_initialized == 0)
- return 0;
- now_ts = now(CLOCK_MONOTONIC);
- if (now_ts == 0)
- return 0;
- return now_ts - udev_device->usec_initialized;
-}
+ usec_t ts;
+ int r;
-usec_t udev_device_get_usec_initialized(struct udev_device *udev_device)
-{
- return udev_device->usec_initialized;
-}
+ assert_return(udev_device, -EINVAL);
-void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized)
-{
- char num[32];
+ r = sd_device_get_usec_since_initialized(udev_device->device, &ts);
+ if (r < 0) {
+ errno = EINVAL;
+ return 0;
+ }
- udev_device->usec_initialized = usec_initialized;
- snprintf(num, sizeof(num), USEC_FMT, usec_initialized);
- udev_device_add_property(udev_device, "USEC_INITIALIZED", num);
+ return ts;
}
/**
@@ -1427,76 +814,18 @@ void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t us
**/
_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
{
- struct udev_list_entry *list_entry;
- char path[UTIL_PATH_SIZE];
- char value[4096];
- struct stat statbuf;
- int fd;
- ssize_t size;
- const char *val = NULL;
-
- if (udev_device == NULL)
- return NULL;
- if (sysattr == NULL)
- return NULL;
-
- /* look for possibly already cached result */
- list_entry = udev_list_get_entry(&udev_device->sysattr_value_list);
- list_entry = udev_list_entry_get_by_name(list_entry, sysattr);
- if (list_entry != NULL)
- return udev_list_entry_get_value(list_entry);
+ const char *value;
+ int r;
- strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
- if (lstat(path, &statbuf) != 0) {
- udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL);
- goto out;
- }
+ assert_return_errno(udev_device, NULL, EINVAL);
- if (S_ISLNK(statbuf.st_mode)) {
- /*
- * Some core links return only the last element of the target path,
- * these are just values, the paths should not be exposed.
- */
- if (streq(sysattr, "driver") ||
- streq(sysattr, "subsystem") ||
- streq(sysattr, "module")) {
- if (util_get_sys_core_link_value(udev_device->udev, sysattr,
- udev_device->syspath, value, sizeof(value)) < 0)
- return NULL;
- list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
- val = udev_list_entry_get_value(list_entry);
- goto out;
- }
-
- goto out;
+ r = sd_device_get_sysattr_value(udev_device->device, sysattr, &value);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
}
- /* skip directories */
- if (S_ISDIR(statbuf.st_mode))
- goto out;
-
- /* skip non-readable files */
- if ((statbuf.st_mode & S_IRUSR) == 0)
- goto out;
-
- /* read attribute value */
- fd = open(path, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- goto out;
- size = read(fd, value, sizeof(value));
- close(fd);
- if (size < 0)
- goto out;
- if (size == sizeof(value))
- goto out;
-
- /* got a valid value, store it in cache and return it */
- value[size] = '\0';
- util_remove_trailing_chars(value, '\n');
- list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
- val = udev_list_entry_get_value(list_entry);
-out:
- return val;
+ return value;
}
/**
@@ -1511,116 +840,15 @@ out:
**/
_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value)
{
- struct udev_device *dev;
- char path[UTIL_PATH_SIZE];
- struct stat statbuf;
- int fd;
- ssize_t size, value_len;
- int ret = 0;
-
- if (udev_device == NULL)
- return -EINVAL;
- dev = udev_device;
- if (sysattr == NULL)
- return -EINVAL;
- if (value == NULL)
- value_len = 0;
- else
- value_len = strlen(value);
-
- strscpyl(path, sizeof(path), udev_device_get_syspath(dev), "/", sysattr, NULL);
- if (lstat(path, &statbuf) != 0) {
- udev_list_entry_add(&dev->sysattr_value_list, sysattr, NULL);
- ret = -ENXIO;
- goto out;
- }
-
- if (S_ISLNK(statbuf.st_mode)) {
- ret = -EINVAL;
- goto out;
- }
-
- /* skip directories */
- if (S_ISDIR(statbuf.st_mode)) {
- ret = -EISDIR;
- goto out;
- }
-
- /* skip non-readable files */
- if ((statbuf.st_mode & S_IRUSR) == 0) {
- ret = -EACCES;
- goto out;
- }
-
- /* Value is limited to 4k */
- if (value_len > 4096) {
- ret = -EINVAL;
- goto out;
- }
- util_remove_trailing_chars(value, '\n');
-
- /* write attribute value */
- fd = open(path, O_WRONLY|O_CLOEXEC);
- if (fd < 0) {
- ret = -errno;
- goto out;
- }
- size = write(fd, value, value_len);
- close(fd);
- if (size < 0) {
- ret = -errno;
- goto out;
- }
- if (size < value_len) {
- ret = -EIO;
- goto out;
- }
-
- /* wrote a valid value, store it in cache and return it */
- udev_list_entry_add(&dev->sysattr_value_list, sysattr, value);
-out:
- if (dev != udev_device)
- udev_device_unref(dev);
- return ret;
-}
-
-static int udev_device_sysattr_list_read(struct udev_device *udev_device)
-{
- struct dirent *dent;
- DIR *dir;
- int num = 0;
-
- if (udev_device == NULL)
- return -EINVAL;
- if (udev_device->sysattr_list_read)
- return 0;
-
- dir = opendir(udev_device_get_syspath(udev_device));
- if (!dir)
- return -errno;
-
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- char path[UTIL_PATH_SIZE];
- struct stat statbuf;
-
- /* only handle symlinks and regular files */
- if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
- continue;
-
- strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL);
- if (lstat(path, &statbuf) != 0)
- continue;
- if ((statbuf.st_mode & S_IRUSR) == 0)
- continue;
+ int r;
- udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL);
- num++;
- }
+ assert_return(udev_device, -EINVAL);
- closedir(dir);
- udev_device->sysattr_list_read = true;
+ r = sd_device_set_sysattr_value(udev_device->device, sysattr, value);
+ if (r < 0)
+ return r;
- return num;
+ return 0;
}
/**
@@ -1635,74 +863,20 @@ static int udev_device_sysattr_list_read(struct udev_device *udev_device)
**/
_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device)
{
- if (!udev_device->sysattr_list_read) {
- int ret;
- ret = udev_device_sysattr_list_read(udev_device);
- if (0 > ret)
- return NULL;
- }
+ assert_return_errno(udev_device, NULL, EINVAL);
- return udev_list_get_entry(&udev_device->sysattr_list);
-}
+ if (!udev_device->sysattrs_read) {
+ const char *sysattr;
-static int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode)
-{
- free(udev_device->devnode);
- if (devnode[0] != '/') {
- if (asprintf(&udev_device->devnode, "/dev/%s", devnode) < 0)
- udev_device->devnode = NULL;
- } else {
- udev_device->devnode = strdup(devnode);
- }
- if (udev_device->devnode == NULL)
- return -ENOMEM;
- udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode);
- return 0;
-}
+ udev_list_cleanup(&udev_device->sysattrs);
-int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink)
-{
- struct udev_list_entry *list_entry;
-
- udev_device->devlinks_uptodate = false;
- list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL);
- if (list_entry == NULL)
- return -ENOMEM;
- return 0;
-}
+ FOREACH_DEVICE_SYSATTR(udev_device->device, sysattr)
+ udev_list_entry_add(&udev_device->properties, sysattr, NULL);
-const char *udev_device_get_id_filename(struct udev_device *udev_device)
-{
- if (udev_device->id_filename == NULL) {
- if (udev_device_get_subsystem(udev_device) == NULL)
- return NULL;
-
- if (major(udev_device_get_devnum(udev_device)) > 0) {
- /* use dev_t -- b259:131072, c254:0 */
- if (asprintf(&udev_device->id_filename, "%c%u:%u",
- streq(udev_device_get_subsystem(udev_device), "block") ? 'b' : 'c',
- major(udev_device_get_devnum(udev_device)),
- minor(udev_device_get_devnum(udev_device))) < 0)
- udev_device->id_filename = NULL;
- } else if (udev_device_get_ifindex(udev_device) > 0) {
- /* use netdev ifindex -- n3 */
- if (asprintf(&udev_device->id_filename, "n%i", udev_device_get_ifindex(udev_device)) < 0)
- udev_device->id_filename = NULL;
- } else {
- /*
- * use $subsys:$syname -- pci:0000:00:1f.2
- * sysname() has '!' translated, get it from devpath
- */
- const char *sysname;
- sysname = strrchr(udev_device->devpath, '/');
- if (sysname == NULL)
- return NULL;
- sysname = &sysname[1];
- if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0)
- udev_device->id_filename = NULL;
- }
+ udev_device->sysattrs_read = true;
}
- return udev_device->id_filename;
+
+ return udev_list_get_entry(&udev_device->sysattrs);
}
/**
@@ -1720,49 +894,18 @@ const char *udev_device_get_id_filename(struct udev_device *udev_device)
**/
_public_ int udev_device_get_is_initialized(struct udev_device *udev_device)
{
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- return udev_device->is_initialized;
-}
+ int r, initialized;
-void udev_device_set_is_initialized(struct udev_device *udev_device)
-{
- udev_device->is_initialized = true;
-}
+ assert_return(udev_device, -EINVAL);
-static bool is_valid_tag(const char *tag)
-{
- return !strchr(tag, ':') && !strchr(tag, ' ');
-}
+ r = sd_device_get_is_initialized(udev_device->device, &initialized);
+ if (r < 0) {
+ errno = -r;
-int udev_device_add_tag(struct udev_device *udev_device, const char *tag)
-{
- if (!is_valid_tag(tag))
- return -EINVAL;
- udev_device->tags_uptodate = false;
- if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL)
return 0;
- return -ENOMEM;
-}
-
-void udev_device_remove_tag(struct udev_device *udev_device, const char *tag)
-{
- struct udev_list_entry *e;
-
- if (!is_valid_tag(tag))
- return;
- e = udev_list_get_entry(&udev_device->tags_list);
- e = udev_list_entry_get_by_name(e, tag);
- if (e) {
- udev_device->tags_uptodate = false;
- udev_list_entry_delete(e);
}
-}
-void udev_device_cleanup_tags_list(struct udev_device *udev_device)
-{
- udev_device->tags_uptodate = false;
- udev_list_cleanup(&udev_device->tags_list);
+ return initialized;
}
/**
@@ -1778,11 +921,22 @@ void udev_device_cleanup_tags_list(struct udev_device *udev_device)
**/
_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
{
- if (udev_device == NULL)
- return NULL;
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- return udev_list_get_entry(&udev_device->tags_list);
+ assert_return_errno(udev_device, NULL, EINVAL);
+
+ if (device_get_tags_generation(udev_device->device) != udev_device->tags_generation ||
+ !udev_device->tags_read) {
+ const char *tag;
+
+ udev_list_cleanup(&udev_device->tags);
+
+ FOREACH_DEVICE_TAG(udev_device->device, tag)
+ udev_list_entry_add(&udev_device->tags, tag, NULL);
+
+ udev_device->tags_read = true;
+ udev_device->tags_generation = device_get_tags_generation(udev_device->device);
+ }
+
+ return udev_list_get_entry(&udev_device->tags);
}
/**
@@ -1796,217 +950,7 @@ _public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_dev
**/
_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag)
{
- struct udev_list_entry *list_entry;
-
- if (udev_device == NULL)
- return false;
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- list_entry = udev_device_get_tags_list_entry(udev_device);
- if (udev_list_entry_get_by_name(list_entry, tag) != NULL)
- return true;
- return false;
-}
-
-#define ENVP_SIZE 128
-#define MONITOR_BUF_SIZE 4096
-static int update_envp_monitor_buf(struct udev_device *udev_device)
-{
- struct udev_list_entry *list_entry;
- char *s;
- size_t l;
- unsigned int i;
-
- /* monitor buffer of property strings */
- free(udev_device->monitor_buf);
- udev_device->monitor_buf_len = 0;
- udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE);
- if (udev_device->monitor_buf == NULL)
- return -ENOMEM;
-
- /* envp array, strings will point into monitor buffer */
- if (udev_device->envp == NULL)
- udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE);
- if (udev_device->envp == NULL)
- return -ENOMEM;
-
- i = 0;
- s = udev_device->monitor_buf;
- l = MONITOR_BUF_SIZE;
- udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
- const char *key;
-
- key = udev_list_entry_get_name(list_entry);
- /* skip private variables */
- if (key[0] == '.')
- continue;
-
- /* add string to envp array */
- udev_device->envp[i++] = s;
- if (i+1 >= ENVP_SIZE)
- return -EINVAL;
-
- /* add property string to monitor buffer */
- l = strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
- if (l == 0)
- return -EINVAL;
- /* advance past the trailing '\0' that strpcpyl() guarantees */
- s++;
- l--;
- }
- udev_device->envp[i] = NULL;
- udev_device->monitor_buf_len = s - udev_device->monitor_buf;
- udev_device->envp_uptodate = true;
- return 0;
-}
-
-char **udev_device_get_properties_envp(struct udev_device *udev_device)
-{
- if (!udev_device->envp_uptodate)
- if (update_envp_monitor_buf(udev_device) != 0)
- return NULL;
- return udev_device->envp;
-}
-
-ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf)
-{
- if (!udev_device->envp_uptodate)
- if (update_envp_monitor_buf(udev_device) != 0)
- return -EINVAL;
- *buf = udev_device->monitor_buf;
- return udev_device->monitor_buf_len;
-}
-
-int udev_device_set_action(struct udev_device *udev_device, const char *action)
-{
- free(udev_device->action);
- udev_device->action = strdup(action);
- if (udev_device->action == NULL)
- return -ENOMEM;
- udev_device_add_property(udev_device, "ACTION", udev_device->action);
- return 0;
-}
-
-int udev_device_get_devlink_priority(struct udev_device *udev_device)
-{
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- return udev_device->devlink_priority;
-}
-
-int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
-{
- udev_device->devlink_priority = prio;
- return 0;
-}
-
-int udev_device_get_watch_handle(struct udev_device *udev_device)
-{
- if (!udev_device->info_loaded)
- udev_device_read_db(udev_device, NULL);
- return udev_device->watch_handle;
-}
-
-int udev_device_set_watch_handle(struct udev_device *udev_device, int handle)
-{
- udev_device->watch_handle = handle;
- return 0;
-}
-
-bool udev_device_get_db_persist(struct udev_device *udev_device)
-{
- return udev_device->db_persist;
-}
-
-void udev_device_set_db_persist(struct udev_device *udev_device)
-{
- udev_device->db_persist = true;
-}
-
-int udev_device_rename(struct udev_device *udev_device, const char *name)
-{
- _cleanup_free_ char *dirname = NULL;
- char *new_syspath;
- int r;
-
- if (udev_device == NULL || name == NULL)
- return -EINVAL;
-
- dirname = dirname_malloc(udev_device->syspath);
- if (!dirname)
- return -ENOMEM;
-
- new_syspath = strjoina(dirname, "/", name);
-
- r = udev_device_set_syspath(udev_device, new_syspath);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-struct udev_device *udev_device_shallow_clone(struct udev_device *old_device)
-{
- struct udev_device *device;
-
- if (old_device == NULL)
- return NULL;
-
- device = udev_device_new(old_device->udev);
- if (!device) {
- errno = ENOMEM;
-
- return NULL;
- }
-
- udev_device_set_syspath(device, udev_device_get_syspath(old_device));
- udev_device_set_subsystem(device, udev_device_get_subsystem(old_device));
- udev_device_set_devnum(device, udev_device_get_devnum(old_device));
-
- return device;
-}
-
-struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen) {
- struct udev_device *device;
- ssize_t bufpos = 0;
-
- if (nulstr == NULL || buflen <= 0) {
- errno = EINVAL;
-
- return NULL;
- }
-
- device = udev_device_new(udev);
- if (!device) {
- errno = ENOMEM;
-
- return NULL;
- }
-
- udev_device_set_info_loaded(device);
-
- while (bufpos < buflen) {
- char *key;
- size_t keylen;
-
- key = nulstr + bufpos;
- keylen = strlen(key);
- if (keylen == 0)
- break;
-
- bufpos += keylen + 1;
- udev_device_add_property_from_string_parse(device, key);
- }
-
- if (udev_device_add_property_from_string_parse_finish(device) < 0) {
- log_debug("missing values, invalid device");
-
- udev_device_unref(device);
-
- errno = EINVAL;
-
- return NULL;
- }
+ assert_return(udev_device, 0);
- return device;
+ return sd_device_has_tag(udev_device->device, tag);
}
diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c
index 1a880c2a34..df088946df 100644
--- a/src/libudev/libudev-enumerate.c
+++ b/src/libudev/libudev-enumerate.c
@@ -2,6 +2,7 @@
This file is part of systemd.
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2015 Tom Gundersen <teg@jklm.no>
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -20,17 +21,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
-#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <fnmatch.h>
#include <stdbool.h>
#include <sys/stat.h>
-#include <sys/param.h>
#include "libudev.h"
-#include "libudev-private.h"
+#include "libudev-device-internal.h"
+#include "sd-device.h"
+#include "device-util.h"
+#include "device-enumerator-private.h"
+
/**
* SECTION:libudev-enumerate
@@ -40,11 +43,6 @@
* and return a sorted list of devices.
*/
-struct syspath {
- char *syspath;
- size_t len;
-};
-
/**
* udev_enumerate:
*
@@ -53,20 +51,10 @@ struct syspath {
struct udev_enumerate {
struct udev *udev;
int refcount;
- struct udev_list sysattr_match_list;
- struct udev_list sysattr_nomatch_list;
- struct udev_list subsystem_match_list;
- struct udev_list subsystem_nomatch_list;
- struct udev_list sysname_match_list;
- struct udev_list properties_match_list;
- struct udev_list tags_match_list;
- struct udev_device *parent_match;
struct udev_list devices_list;
- struct syspath *devices;
- unsigned int devices_cur;
- unsigned int devices_max;
bool devices_uptodate:1;
- bool match_is_initialized;
+
+ sd_device_enumerator *enumerator;
};
/**
@@ -77,26 +65,40 @@ struct udev_enumerate {
*
* Returns: an enumeration context.
**/
-_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
-{
- struct udev_enumerate *udev_enumerate;
+_public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
+ _cleanup_free_ struct udev_enumerate *udev_enumerate = NULL;
+ struct udev_enumerate *ret;
+ int r;
+
+ assert_return_errno(udev, NULL, EINVAL);
- if (udev == NULL)
- return NULL;
udev_enumerate = new0(struct udev_enumerate, 1);
- if (udev_enumerate == NULL)
+ if (!udev_enumerate) {
+ errno = ENOMEM;
return NULL;
+ }
+
+ r = sd_device_enumerator_new(&udev_enumerate->enumerator);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
+ }
+
+ r = sd_device_enumerator_allow_uninitialized(udev_enumerate->enumerator);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
+ }
+
udev_enumerate->refcount = 1;
udev_enumerate->udev = udev;
- udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
- udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
- udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
- udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
- udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
- udev_list_init(udev, &udev_enumerate->properties_match_list, false);
- udev_list_init(udev, &udev_enumerate->tags_match_list, true);
+
udev_list_init(udev, &udev_enumerate->devices_list, false);
- return udev_enumerate;
+
+ ret = udev_enumerate;
+ udev_enumerate = NULL;
+
+ return ret;
}
/**
@@ -107,11 +109,10 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev)
*
* Returns: the passed enumeration context
**/
-_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
-{
- if (udev_enumerate == NULL)
- return NULL;
- udev_enumerate->refcount++;
+_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
+ if (udev_enumerate)
+ udev_enumerate->refcount ++;
+
return udev_enumerate;
}
@@ -124,28 +125,13 @@ _public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_e
*
* Returns: #NULL
**/
-_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
-{
- unsigned int i;
+_public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) {
+ if (udev_enumerate && (-- udev_enumerate->refcount) == 0) {
+ udev_list_cleanup(&udev_enumerate->devices_list);
+ sd_device_enumerator_unref(udev_enumerate->enumerator);
+ free(udev_enumerate);
+ }
- if (udev_enumerate == NULL)
- return NULL;
- udev_enumerate->refcount--;
- if (udev_enumerate->refcount > 0)
- return NULL;
- udev_list_cleanup(&udev_enumerate->sysattr_match_list);
- udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
- udev_list_cleanup(&udev_enumerate->subsystem_match_list);
- udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list);
- udev_list_cleanup(&udev_enumerate->sysname_match_list);
- udev_list_cleanup(&udev_enumerate->properties_match_list);
- udev_list_cleanup(&udev_enumerate->tags_match_list);
- udev_device_unref(udev_enumerate->parent_match);
- udev_list_cleanup(&udev_enumerate->devices_list);
- for (i = 0; i < udev_enumerate->devices_cur; i++)
- free(udev_enumerate->devices[i].syspath);
- free(udev_enumerate->devices);
- free(udev_enumerate);
return NULL;
}
@@ -157,103 +143,10 @@ _public_ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev
*
* Returns: a pointer to the context.
*/
-_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
-{
- if (udev_enumerate == NULL)
- return NULL;
- return udev_enumerate->udev;
-}
+_public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) {
+ assert_return_errno(udev_enumerate, NULL, EINVAL);
-static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
- char *path;
- struct syspath *entry;
-
- /* double array size if needed */
- if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
- struct syspath *buf;
- unsigned int add;
-
- add = udev_enumerate->devices_max;
- if (add < 1024)
- add = 1024;
- buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
- if (buf == NULL)
- return -ENOMEM;
- udev_enumerate->devices = buf;
- udev_enumerate->devices_max += add;
- }
-
- path = strdup(syspath);
- if (path == NULL)
- return -ENOMEM;
- entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
- entry->syspath = path;
- entry->len = strlen(path);
- udev_enumerate->devices_cur++;
- udev_enumerate->devices_uptodate = false;
- return 0;
-}
-
-static int syspath_cmp(const void *p1, const void *p2)
-{
- const struct syspath *path1 = p1;
- const struct syspath *path2 = p2;
- size_t len;
- int ret;
-
- len = MIN(path1->len, path2->len);
- ret = memcmp(path1->syspath, path2->syspath, len);
- if (ret == 0) {
- if (path1->len < path2->len)
- ret = -1;
- else if (path1->len > path2->len)
- ret = 1;
- }
- return ret;
-}
-
-/* For devices that should be moved to the absolute end of the list */
-static bool devices_delay_end(struct udev *udev, const char *syspath)
-{
- static const char *delay_device_list[] = {
- "/block/md",
- "/block/dm-",
- NULL
- };
- int i;
-
- for (i = 0; delay_device_list[i] != NULL; i++) {
- if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL)
- return true;
- }
- return false;
-}
-
-/* For devices that should just be moved a little bit later, just
- * before the point where some common path prefix changes. Returns the
- * number of characters that make up that common prefix */
-static size_t devices_delay_later(struct udev *udev, const char *syspath)
-{
- const char *c;
-
- /* For sound cards the control device must be enumerated last
- * to make sure it's the final device node that gets ACLs
- * applied. Applications rely on this fact and use ACL changes
- * on the control node as an indicator that the ACL change of
- * the entire sound card completed. The kernel makes this
- * guarantee when creating those devices, and hence we should
- * too when enumerating them. */
-
- if ((c = strstr(syspath, "/sound/card"))) {
- c += 11;
- c += strcspn(c, "/");
-
- if (startswith(c, "/controlC"))
- return c - syspath + 1;
- }
-
- return 0;
+ return udev_enumerate->udev;
}
/**
@@ -264,77 +157,30 @@ static size_t devices_delay_later(struct udev *udev, const char *syspath)
*
* Returns: a udev_list_entry.
*/
-_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
-{
- if (udev_enumerate == NULL)
- return NULL;
+_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
+ assert_return_errno(udev_enumerate, NULL, EINVAL);
+
if (!udev_enumerate->devices_uptodate) {
- unsigned int i;
- int move_later = -1;
- unsigned int max;
- struct syspath *prev = NULL;
- size_t move_later_prefix = 0;
+ sd_device *device;
udev_list_cleanup(&udev_enumerate->devices_list);
- qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
-
- max = udev_enumerate->devices_cur;
- for (i = 0; i < max; i++) {
- struct syspath *entry = &udev_enumerate->devices[i];
-
- /* skip duplicated entries */
- if (prev != NULL &&
- entry->len == prev->len &&
- memcmp(entry->syspath, prev->syspath, entry->len) == 0)
- continue;
- prev = entry;
-
- /* skip to be delayed devices, and add them to the end of the list */
- if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
- syspath_add(udev_enumerate, entry->syspath);
- /* need to update prev here for the case realloc() gives a different address */
- prev = &udev_enumerate->devices[i];
- continue;
- }
- /* skip to be delayed devices, and move the to
- * the point where the prefix changes. We can
- * only move one item at a time. */
- if (move_later == -1) {
- move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
+ FOREACH_DEVICE_AND_SUBSYSTEM(udev_enumerate->enumerator, device) {
+ const char *syspath;
+ int r;
- if (move_later_prefix > 0) {
- move_later = i;
- continue;
- }
+ r = sd_device_get_syspath(device, &syspath);
+ if (r < 0) {
+ errno = -r;
+ return NULL;
}
- if ((move_later >= 0) &&
- !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) {
-
- udev_list_entry_add(&udev_enumerate->devices_list,
- udev_enumerate->devices[move_later].syspath, NULL);
- move_later = -1;
- }
-
- udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
+ udev_list_entry_add(&udev_enumerate->devices_list, syspath, NULL);
}
- if (move_later >= 0)
- udev_list_entry_add(&udev_enumerate->devices_list,
- udev_enumerate->devices[move_later].syspath, NULL);
-
- /* add and cleanup delayed devices from end of list */
- for (i = max; i < udev_enumerate->devices_cur; i++) {
- struct syspath *entry = &udev_enumerate->devices[i];
-
- udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
- free(entry->syspath);
- }
- udev_enumerate->devices_cur = max;
-
udev_enumerate->devices_uptodate = true;
}
+
return udev_list_get_entry(&udev_enumerate->devices_list);
}
@@ -347,15 +193,13 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (subsystem == NULL)
+_public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!subsystem)
return 0;
- if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
- return -ENOMEM;
- return 0;
+
+ return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, true);
}
/**
@@ -367,15 +211,13 @@ _public_ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (subsystem == NULL)
+_public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!subsystem)
return 0;
- if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL)
- return -ENOMEM;
- return 0;
+
+ return sd_device_enumerator_add_match_subsystem(udev_enumerate->enumerator, subsystem, false);
}
/**
@@ -388,15 +230,13 @@ _public_ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_en
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (sysattr == NULL)
+_public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!sysattr)
return 0;
- if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL)
- return -ENOMEM;
- return 0;
+
+ return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, true);
}
/**
@@ -409,35 +249,13 @@ _public_ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumer
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (sysattr == NULL)
+_public_ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!sysattr)
return 0;
- if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL)
- return -ENOMEM;
- return 0;
-}
-static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
-{
- const char *val = NULL;
- bool match = false;
-
- val = udev_device_get_sysattr_value(dev, sysattr);
- if (val == NULL)
- goto exit;
- if (match_val == NULL) {
- match = true;
- goto exit;
- }
- if (fnmatch(match_val, val, 0) == 0) {
- match = true;
- goto exit;
- }
-exit:
- return match;
+ return sd_device_enumerator_add_match_sysattr(udev_enumerate->enumerator, sysattr, value, false);
}
/**
@@ -450,15 +268,13 @@ exit:
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (property == NULL)
+_public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!property)
return 0;
- if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
- return -ENOMEM;
- return 0;
+
+ return sd_device_enumerator_add_match_property(udev_enumerate->enumerator, property, value);
}
/**
@@ -470,15 +286,13 @@ _public_ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enume
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (tag == NULL)
+_public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!tag)
return 0;
- if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL)
- return -ENOMEM;
- return 0;
+
+ return sd_device_enumerator_add_match_tag(udev_enumerate->enumerator, tag);
}
/**
@@ -494,16 +308,13 @@ _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate,
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (parent == NULL)
+_public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ if (!parent)
return 0;
- if (udev_enumerate->parent_match != NULL)
- udev_device_unref(udev_enumerate->parent_match);
- udev_enumerate->parent_match = udev_device_ref(parent);
- return 0;
+
+ return sd_device_enumerator_add_match_parent(udev_enumerate->enumerator, parent->device);
}
/**
@@ -524,12 +335,10 @@ _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumera
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- udev_enumerate->match_is_initialized = true;
- return 0;
+_public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ return device_enumerator_add_match_is_initialized(udev_enumerate->enumerator);
}
/**
@@ -541,224 +350,13 @@ _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (sysname == NULL)
- return 0;
- if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL)
- return -ENOMEM;
- return 0;
-}
-
-static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
- struct udev_list_entry *list_entry;
-
- /* skip list */
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
- if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry)))
- return false;
- }
- /* include list */
- if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
- /* anything that does not match, will make it FALSE */
- if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry)))
- return false;
- }
- return true;
- }
- return true;
-}
-
-static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
- struct udev_list_entry *list_entry;
- bool match = false;
-
- /* no match always matches */
- if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
- return true;
-
- /* loop over matches */
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
- const char *match_key = udev_list_entry_get_name(list_entry);
- const char *match_value = udev_list_entry_get_value(list_entry);
- struct udev_list_entry *property_entry;
-
- /* loop over device properties */
- udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
- const char *dev_key = udev_list_entry_get_name(property_entry);
- const char *dev_value = udev_list_entry_get_value(property_entry);
-
- if (fnmatch(match_key, dev_key, 0) != 0)
- continue;
- if (match_value == NULL && dev_value == NULL) {
- match = true;
- goto out;
- }
- if (match_value == NULL || dev_value == NULL)
- continue;
- if (fnmatch(match_value, dev_value, 0) == 0) {
- match = true;
- goto out;
- }
- }
- }
-out:
- return match;
-}
-
-static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
- struct udev_list_entry *list_entry;
-
- /* no match always matches */
- if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
- return true;
-
- /* loop over matches */
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
- if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
- return false;
-
- return true;
-}
-
-static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
-{
- if (udev_enumerate->parent_match == NULL)
- return true;
-
- return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match));
-}
-
-static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
-{
- struct udev_list_entry *list_entry;
-
- if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
- return true;
-
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
- if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
- continue;
- return true;
- }
- return false;
-}
-
-static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
- const char *basedir, const char *subdir1, const char *subdir2)
-{
- char path[UTIL_PATH_SIZE];
- size_t l;
- char *s;
- DIR *dir;
- struct dirent *dent;
-
- s = path;
- l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL);
- if (subdir1 != NULL)
- l = strpcpyl(&s, l, "/", subdir1, NULL);
- if (subdir2 != NULL)
- strpcpyl(&s, l, "/", subdir2, NULL);
- dir = opendir(path);
- if (dir == NULL)
- return -ENOENT;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- char syspath[UTIL_PATH_SIZE];
- struct udev_device *dev;
-
- if (dent->d_name[0] == '.')
- continue;
-
- if (!match_sysname(udev_enumerate, dent->d_name))
- continue;
-
- strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
- dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
- if (dev == NULL)
- continue;
-
- if (udev_enumerate->match_is_initialized) {
- /*
- * All devices with a device node or network interfaces
- * possibly need udev to adjust the device node permission
- * or context, or rename the interface before it can be
- * reliably used from other processes.
- *
- * For now, we can only check these types of devices, we
- * might not store a database, and have no way to find out
- * for all other types of devices.
- */
- if (!udev_device_get_is_initialized(dev) &&
- (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
- goto nomatch;
- }
- if (!match_parent(udev_enumerate, dev))
- goto nomatch;
- if (!match_tag(udev_enumerate, dev))
- goto nomatch;
- if (!match_property(udev_enumerate, dev))
- goto nomatch;
- if (!match_sysattr(udev_enumerate, dev))
- goto nomatch;
-
- syspath_add(udev_enumerate, udev_device_get_syspath(dev));
-nomatch:
- udev_device_unref(dev);
- }
- closedir(dir);
- return 0;
-}
-
-static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
- struct udev_list_entry *list_entry;
-
- if (!subsystem)
- return false;
-
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
- if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
- return false;
- }
+_public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) {
+ assert_return(udev_enumerate, -EINVAL);
- if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
- if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
- return true;
- }
- return false;
- }
-
- return true;
-}
+ if (!sysname)
+ return 0;
-static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
-{
- char path[UTIL_PATH_SIZE];
- DIR *dir;
- struct dirent *dent;
-
- strscpyl(path, sizeof(path), "/sys/", basedir, NULL);
- dir = opendir(path);
- if (dir == NULL)
- return -1;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- if (dent->d_name[0] == '.')
- continue;
- if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
- continue;
- scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
- }
- closedir(dir);
- return 0;
+ return sd_device_enumerator_add_match_sysname(udev_enumerate->enumerator, sysname);
}
/**
@@ -770,141 +368,23 @@ static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir,
*
* Returns: 0 on success, otherwise a negative error value.
*/
-_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
- struct udev_device *udev_device;
+_public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) {
+ _cleanup_device_unref_ sd_device *device = NULL;
+ int r;
- if (udev_enumerate == NULL)
- return -EINVAL;
- if (syspath == NULL)
- return 0;
- /* resolve to real syspath */
- udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
- if (udev_device == NULL)
- return -EINVAL;
- syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
- udev_device_unref(udev_device);
- return 0;
-}
+ assert_return(udev_enumerate, -EINVAL);
-static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
-{
- struct udev_list_entry *list_entry;
-
- /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
- DIR *dir;
- struct dirent *dent;
- char path[UTIL_PATH_SIZE];
-
- strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL);
- dir = opendir(path);
- if (dir == NULL)
- continue;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- struct udev_device *dev;
-
- if (dent->d_name[0] == '.')
- continue;
-
- dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
- if (dev == NULL)
- continue;
-
- if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
- goto nomatch;
- if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
- goto nomatch;
- if (!match_parent(udev_enumerate, dev))
- goto nomatch;
- if (!match_property(udev_enumerate, dev))
- goto nomatch;
- if (!match_sysattr(udev_enumerate, dev))
- goto nomatch;
-
- syspath_add(udev_enumerate, udev_device_get_syspath(dev));
-nomatch:
- udev_device_unref(dev);
- }
- closedir(dir);
- }
- return 0;
-}
-
-static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
-{
- struct udev_device *dev;
- int r = 0;
-
- dev = udev_device_new_from_syspath(enumerate->udev, path);
- if (dev == NULL)
- return -ENODEV;
-
- if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
- goto nomatch;
- if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
- goto nomatch;
- if (!match_property(enumerate, dev))
- goto nomatch;
- if (!match_sysattr(enumerate, dev))
- goto nomatch;
-
- syspath_add(enumerate, udev_device_get_syspath(dev));
- r = 1;
-
-nomatch:
- udev_device_unref(dev);
- return r;
-}
-
-static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
-{
- DIR *d;
- struct dirent *dent;
-
- d = opendir(path);
- if (d == NULL)
- return -errno;
-
- for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
- char *child;
-
- if (dent->d_name[0] == '.')
- continue;
- if (dent->d_type != DT_DIR)
- continue;
- if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
- continue;
- parent_add_child(enumerate, child);
- if (maxdepth > 0)
- parent_crawl_children(enumerate, child, maxdepth-1);
- free(child);
- }
-
- closedir(d);
- return 0;
-}
+ if (!syspath)
+ return 0;
-static int scan_devices_children(struct udev_enumerate *enumerate)
-{
- const char *path;
+ r = sd_device_new_from_syspath(&device, syspath);
+ if (r < 0)
+ return r;
- path = udev_device_get_syspath(enumerate->parent_match);
- parent_add_child(enumerate, path);
- return parent_crawl_children(enumerate, path, 256);
-}
+ r = device_enumerator_add_device(udev_enumerate->enumerator, device);
+ if (r < 0)
+ return r;
-static int scan_devices_all(struct udev_enumerate *udev_enumerate)
-{
- struct stat statbuf;
-
- if (stat("/sys/subsystem", &statbuf) == 0) {
- /* we have /subsystem/, forget all the old stuff */
- scan_dir(udev_enumerate, "subsystem", "devices", NULL);
- } else {
- scan_dir(udev_enumerate, "bus", "devices", NULL);
- scan_dir(udev_enumerate, "class", NULL, NULL);
- }
return 0;
}
@@ -917,21 +397,10 @@ static int scan_devices_all(struct udev_enumerate *udev_enumerate)
*
* Returns: 0 on success, otherwise a negative error value.
**/
-_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
-{
- if (udev_enumerate == NULL)
- return -EINVAL;
+_public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) {
+ assert_return(udev_enumerate, -EINVAL);
- /* efficiently lookup tags only, we maintain a reverse-index */
- if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
- return scan_devices_tags(udev_enumerate);
-
- /* walk the subtree of one parent device only */
- if (udev_enumerate->parent_match != NULL)
- return scan_devices_children(udev_enumerate);
-
- /* scan devices of all subsystems */
- return scan_devices_all(udev_enumerate);
+ return device_enumerator_scan_devices(udev_enumerate->enumerator);
}
/**
@@ -942,29 +411,8 @@ _public_ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
*
* Returns: 0 on success, otherwise a negative error value.
**/
-_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
-{
- struct stat statbuf;
- const char *subsysdir;
-
- if (udev_enumerate == NULL)
- return -EINVAL;
-
- /* all kernel modules */
- if (match_subsystem(udev_enumerate, "module"))
- scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
-
- if (stat("/sys/subsystem", &statbuf) == 0)
- subsysdir = "subsystem";
- else
- subsysdir = "bus";
-
- /* all subsystems (only buses support coldplug) */
- if (match_subsystem(udev_enumerate, "subsystem"))
- scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
-
- /* all subsystem drivers */
- if (match_subsystem(udev_enumerate, "drivers"))
- scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
- return 0;
+_public_ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) {
+ assert_return(udev_enumerate, -EINVAL);
+
+ return device_enumerator_scan_subsystems(udev_enumerate->enumerator);
}
diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c
index 42fcb853c7..044ee3a0cb 100644
--- a/src/libudev/libudev-list.c
+++ b/src/libudev/libudev-list.c
@@ -17,14 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
-#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include "libudev.h"
#include "libudev-private.h"
/**
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c
index 3f1fee7f7e..282aa2b0d9 100644
--- a/src/libudev/libudev-monitor.c
+++ b/src/libudev/libudev-monitor.c
@@ -23,12 +23,8 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <dirent.h>
#include <poll.h>
-#include <sys/stat.h>
#include <sys/socket.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/filter.h>
@@ -36,6 +32,7 @@
#include "libudev-private.h"
#include "socket-util.h"
#include "missing.h"
+#include "formats-util.h"
/**
* SECTION:libudev-monitor
@@ -147,6 +144,22 @@ static bool udev_has_devtmpfs(struct udev *udev) {
return false;
}
+static void monitor_set_nl_address(struct udev_monitor *udev_monitor) {
+ union sockaddr_union snl;
+ socklen_t addrlen;
+ int r;
+
+ assert(udev_monitor);
+
+ /* get the address the kernel has assigned us
+ * it is usually, but not necessarily the pid
+ */
+ addrlen = sizeof(struct sockaddr_nl);
+ r = getsockname(udev_monitor->sock, &snl.sa, &addrlen);
+ if (r >= 0)
+ udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
+}
+
struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
{
struct udev_monitor *udev_monitor;
@@ -186,7 +199,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
if (fd < 0) {
udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
- if (udev_monitor->sock == -1) {
+ if (udev_monitor->sock < 0) {
log_debug_errno(errno, "error getting socket: %m");
free(udev_monitor);
return NULL;
@@ -194,6 +207,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
} else {
udev_monitor->bound = true;
udev_monitor->sock = fd;
+ monitor_set_nl_address(udev_monitor);
}
udev_monitor->snl.nl.nl_family = AF_NETLINK;
@@ -369,6 +383,7 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct
udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid;
return 0;
}
+
/**
* udev_monitor_enable_receiving:
* @udev_monitor: the monitor which should receive events
@@ -391,19 +406,9 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
udev_monitor->bound = true;
}
- if (err >= 0) {
- union sockaddr_union snl;
- socklen_t addrlen;
-
- /*
- * get the address the kernel has assigned us
- * it is usually, but not necessarily the pid
- */
- addrlen = sizeof(struct sockaddr_nl);
- err = getsockname(udev_monitor->sock, &snl.sa, &addrlen);
- if (err == 0)
- udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
- } else {
+ if (err >= 0)
+ monitor_set_nl_address(udev_monitor);
+ else {
log_debug_errno(errno, "bind failed: %m");
return -errno;
}
@@ -647,6 +652,8 @@ retry:
return NULL;
}
if (buf.nlh.properties_off+32 > (size_t)buflen) {
+ log_debug("message smaller than expected (%u > %zd)",
+ buf.nlh.properties_off+32, buflen);
return NULL;
}
@@ -670,8 +677,10 @@ retry:
}
udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
- if (!udev_device)
+ if (!udev_device) {
+ log_debug("could not create device: %m");
return NULL;
+ }
if (is_initialized)
udev_device_set_is_initialized(udev_device);
@@ -698,32 +707,36 @@ retry:
int udev_monitor_send_device(struct udev_monitor *udev_monitor,
struct udev_monitor *destination, struct udev_device *udev_device)
{
- const char *buf;
- ssize_t blen;
- ssize_t count;
- struct msghdr smsg;
- struct iovec iov[2];
- const char *val;
- struct udev_monitor_netlink_header nlh;
+ const char *buf, *val;
+ ssize_t blen, count;
+ struct udev_monitor_netlink_header nlh = {
+ .prefix = "libudev",
+ .magic = htonl(UDEV_MONITOR_MAGIC),
+ .header_size = sizeof nlh,
+ };
+ struct iovec iov[2] = {
+ { .iov_base = &nlh, .iov_len = sizeof nlh },
+ };
+ struct msghdr smsg = {
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ };
struct udev_list_entry *list_entry;
uint64_t tag_bloom_bits;
blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
- if (blen < 32)
+ if (blen < 32) {
+ log_debug("device buffer is too small to contain a valid device");
return -EINVAL;
+ }
- /* add versioned header */
- memzero(&nlh, sizeof(struct udev_monitor_netlink_header));
- memcpy(nlh.prefix, "libudev", 8);
- nlh.magic = htonl(UDEV_MONITOR_MAGIC);
- nlh.header_size = sizeof(struct udev_monitor_netlink_header);
+ /* fill in versioned header */
val = udev_device_get_subsystem(udev_device);
nlh.filter_subsystem_hash = htonl(util_string_hash32(val));
+
val = udev_device_get_devtype(udev_device);
if (val != NULL)
nlh.filter_devtype_hash = htonl(util_string_hash32(val));
- iov[0].iov_base = &nlh;
- iov[0].iov_len = sizeof(struct udev_monitor_netlink_header);
/* add tag bloom filter */
tag_bloom_bits = 0;
@@ -740,22 +753,27 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
iov[1].iov_base = (char *)buf;
iov[1].iov_len = blen;
- memzero(&smsg, sizeof(struct msghdr));
- smsg.msg_iov = iov;
- smsg.msg_iovlen = 2;
/*
* Use custom address for target, or the default one.
*
* If we send to a multicast group, we will get
* ECONNREFUSED, which is expected.
*/
- if (destination != NULL)
+ if (destination)
smsg.msg_name = &destination->snl;
else
smsg.msg_name = &udev_monitor->snl_destination;
smsg.msg_namelen = sizeof(struct sockaddr_nl);
count = sendmsg(udev_monitor->sock, &smsg, 0);
- log_debug("passed %zi bytes to netlink monitor %p", count, udev_monitor);
+ if (count < 0) {
+ if (!destination && errno == ECONNREFUSED) {
+ log_debug("passed device to netlink monitor %p", udev_monitor);
+ return 0;
+ } else
+ return -errno;
+ }
+
+ log_debug("passed %zi byte device to netlink monitor %p", count, udev_monitor);
return count;
}
diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h
index 96363040a0..1240ea79cc 100644
--- a/src/libudev/libudev-private.h
+++ b/src/libudev/libudev-private.h
@@ -38,21 +38,19 @@ int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]);
/* libudev-device.c */
struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen);
+struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action);
struct udev_device *udev_device_shallow_clone(struct udev_device *old_device);
+struct udev_device *udev_device_clone_with_db(struct udev_device *old_device);
+int udev_device_copy_properties(struct udev_device *dst, struct udev_device *src);
mode_t udev_device_get_devnode_mode(struct udev_device *udev_device);
uid_t udev_device_get_devnode_uid(struct udev_device *udev_device);
gid_t udev_device_get_devnode_gid(struct udev_device *udev_device);
int udev_device_rename(struct udev_device *udev_device, const char *new_name);
int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink);
void udev_device_cleanup_devlinks_list(struct udev_device *udev_device);
-struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value);
-void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property);
-int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device);
+int udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value);
char **udev_device_get_properties_envp(struct udev_device *udev_device);
ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf);
-int udev_device_read_db(struct udev_device *udev_device, const char *dbfile);
-int udev_device_read_uevent_file(struct udev_device *udev_device);
-int udev_device_set_action(struct udev_device *udev_device, const char *action);
const char *udev_device_get_devpath_old(struct udev_device *udev_device);
const char *udev_device_get_id_filename(struct udev_device *udev_device);
void udev_device_set_is_initialized(struct udev_device *udev_device);
@@ -60,7 +58,7 @@ int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
void udev_device_remove_tag(struct udev_device *udev_device, const char *tag);
void udev_device_cleanup_tags_list(struct udev_device *udev_device);
usec_t udev_device_get_usec_initialized(struct udev_device *udev_device);
-void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized);
+void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *old_device);
int udev_device_get_devlink_priority(struct udev_device *udev_device);
int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
int udev_device_get_watch_handle(struct udev_device *udev_device);
@@ -69,6 +67,7 @@ int udev_device_get_ifindex(struct udev_device *udev_device);
void udev_device_set_info_loaded(struct udev_device *device);
bool udev_device_get_db_persist(struct udev_device *udev_device);
void udev_device_set_db_persist(struct udev_device *udev_device);
+void udev_device_read_db(struct udev_device *udev_device);
/* libudev-device-private.c */
int udev_device_update_db(struct udev_device *udev_device);
@@ -94,7 +93,6 @@ struct udev_list {
unsigned int entries_max;
bool unique;
};
-#define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) }
void udev_list_node_init(struct udev_list_node *list);
int udev_list_node_is_empty(struct udev_list_node *list);
void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list);
diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c
index 8ef1f3d4b0..11e15d13e6 100644
--- a/src/libudev/libudev-queue.c
+++ b/src/libudev/libudev-queue.c
@@ -18,17 +18,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
-#include <string.h>
-#include <limits.h>
-#include <sys/stat.h>
#include <sys/inotify.h>
-#include "libudev.h"
#include "libudev-private.h"
/**
diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c
index 291829e6d8..f4656277c6 100644
--- a/src/libudev/libudev-util.c
+++ b/src/libudev/libudev-util.c
@@ -17,20 +17,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <dirent.h>
#include <ctype.h>
-#include <fcntl.h>
-#include <time.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/stat.h>
-#include <sys/param.h>
#include "device-nodes.h"
#include "libudev.h"
@@ -224,7 +216,7 @@ int util_replace_whitespace(const char *str, char *to, size_t len)
/* strip leading whitespace */
i = 0;
- while (isspace(str[i]) && (i < len))
+ while ((i < len) && isspace(str[i]))
i++;
j = 0;
diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c
index 8785f22071..ec15d2576b 100644
--- a/src/libudev/libudev.c
+++ b/src/libudev/libudev.c
@@ -21,11 +21,8 @@
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
#include <string.h>
#include <ctype.h>
-#include <time.h>
#include "libudev.h"
#include "libudev-private.h"
diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h
index a94505c09e..eb58740d26 100644
--- a/src/libudev/libudev.h
+++ b/src/libudev/libudev.h
@@ -22,7 +22,6 @@
#include <stdarg.h>
#include <sys/types.h>
-#include <sys/stat.h>
#ifdef __cplusplus
extern "C" {
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 41a88a828c..8c60339e3e 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -23,25 +23,19 @@
#include <locale.h>
#include <stdlib.h>
#include <stdbool.h>
-#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <ftw.h>
-#include <sys/mman.h>
-#include <fcntl.h>
#include "sd-bus.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "bus-message.h"
#include "util.h"
#include "spawn-polkit-agent.h"
#include "build.h"
#include "strv.h"
#include "pager.h"
#include "set.h"
-#include "path-util.h"
-#include "utf8.h"
#include "def.h"
#include "virt.h"
#include "fileio.h"
@@ -83,7 +77,7 @@ typedef struct StatusInfo {
const char *x11_options;
} StatusInfo;
-static void print_overriden_variables(void) {
+static void print_overridden_variables(void) {
int r;
char *variables[_VARIABLE_LC_MAX] = {};
LocaleVariable j;
@@ -182,7 +176,7 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
goto fail;
}
- print_overriden_variables();
+ print_overridden_variables();
print_status_info(&info);
fail:
diff --git a/src/locale/localed.c b/src/locale/localed.c
index d1c90d613a..0e59350e98 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -33,7 +33,6 @@
#include "env-util.h"
#include "fileio.h"
#include "fileio-label.h"
-#include "label.h"
#include "bus-util.h"
#include "bus-error.h"
#include "bus-message.h"
@@ -228,7 +227,7 @@ static int x11_read_data(Context *c) {
if (in_section && first_word(l, "Option")) {
_cleanup_strv_free_ char **a = NULL;
- r = strv_split_quoted(&a, l, false);
+ r = strv_split_quoted(&a, l, 0);
if (r < 0)
return r;
@@ -251,7 +250,7 @@ static int x11_read_data(Context *c) {
} else if (!in_section && first_word(l, "Section")) {
_cleanup_strv_free_ char **a = NULL;
- r = strv_split_quoted(&a, l, false);
+ r = strv_split_quoted(&a, l, 0);
if (r < 0)
return -ENOMEM;
@@ -540,7 +539,7 @@ static int read_next_mapping(const char* filename,
if (l[0] == 0 || l[0] == '#')
continue;
- r = strv_split_quoted(&b, l, false);
+ r = strv_split_quoted(&b, l, 0);
if (r < 0)
return r;
@@ -870,7 +869,7 @@ static int property_get_locale(
return sd_bus_message_append_strv(reply, l);
}
-static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
_cleanup_strv_free_ char **l = NULL;
char **i;
@@ -881,6 +880,9 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
int p;
int r;
+ assert(m);
+ assert(c);
+
r = bus_message_read_strv_extend(m, &l);
if (r < 0)
return r;
@@ -949,7 +951,14 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
if (modified) {
_cleanup_strv_free_ char **settings = NULL;
- r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-locale", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.locale1.set-locale",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -983,7 +992,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r));
}
- locale_update_system_manager(c, bus);
+ locale_update_system_manager(c, sd_bus_message_get_bus(m));
if (settings) {
_cleanup_free_ char *line;
@@ -993,7 +1002,8 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
} else
log_info("Changed locale to unset.");
- sd_bus_emit_properties_changed(bus,
+ (void) sd_bus_emit_properties_changed(
+ sd_bus_message_get_bus(m),
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"Locale", NULL);
@@ -1004,12 +1014,15 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
return sd_bus_reply_method_return(m, NULL);
}
-static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *keymap, *keymap_toggle;
int convert, interactive;
int r;
+ assert(m);
+ assert(c);
+
r = sd_bus_message_read(m, "ssbb", &keymap, &keymap_toggle, &convert, &interactive);
if (r < 0)
return r;
@@ -1027,7 +1040,14 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
(keymap_toggle && (!filename_is_valid(keymap_toggle) || !string_is_safe(keymap_toggle))))
return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keymap data");
- r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.locale1.set-keyboard",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -1046,17 +1066,18 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
log_info("Changed virtual console keymap to '%s' toggle '%s'",
strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
- r = vconsole_reload(bus);
+ r = vconsole_reload(sd_bus_message_get_bus(m));
if (r < 0)
log_error_errno(r, "Failed to request keymap reload: %m");
- sd_bus_emit_properties_changed(bus,
+ (void) sd_bus_emit_properties_changed(
+ sd_bus_message_get_bus(m),
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"VConsoleKeymap", "VConsoleKeymapToggle", NULL);
if (convert) {
- r = vconsole_convert_to_x11(c, bus);
+ r = vconsole_convert_to_x11(c, sd_bus_message_get_bus(m));
if (r < 0)
log_error_errno(r, "Failed to convert keymap data: %m");
}
@@ -1113,12 +1134,15 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
}
#endif
-static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *layout, *model, *variant, *options;
int convert, interactive;
int r;
+ assert(m);
+ assert(c);
+
r = sd_bus_message_read(m, "ssssbb", &layout, &model, &variant, &options, &convert, &interactive);
if (r < 0)
return r;
@@ -1146,7 +1170,14 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
(options && !string_is_safe(options)))
return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data");
- r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.locale1.set-keyboard",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -1177,13 +1208,14 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
strempty(c->x11_variant),
strempty(c->x11_options));
- sd_bus_emit_properties_changed(bus,
+ (void) sd_bus_emit_properties_changed(
+ sd_bus_message_get_bus(m),
"/org/freedesktop/locale1",
"org.freedesktop.locale1",
"X11Layout", "X11Model", "X11Variant", "X11Options", NULL);
if (convert) {
- r = x11_convert_to_vconsole(c, bus);
+ r = x11_convert_to_vconsole(c, sd_bus_message_get_bus(m));
if (r < 0)
log_error_errno(r, "Failed to convert keymap data: %m");
}
diff --git a/src/login/inhibit.c b/src/login/inhibit.c
index 44bda34aff..57cfb5d0b5 100644
--- a/src/login/inhibit.c
+++ b/src/login/inhibit.c
@@ -20,7 +20,6 @@
***/
#include <getopt.h>
-#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@@ -32,6 +31,8 @@
#include "util.h"
#include "build.h"
#include "strv.h"
+#include "formats-util.h"
+#include "process-util.h"
static const char* arg_what = "idle:sleep:shutdown";
static const char* arg_who = NULL;
@@ -260,7 +261,7 @@ int main(int argc, char *argv[]) {
fd = inhibit(bus, &error);
if (fd < 0) {
- log_error("Failed to inhibit: %s", bus_error_message(&error, -r));
+ log_error("Failed to inhibit: %s", bus_error_message(&error, fd));
return EXIT_FAILURE;
}
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index b0eede9a34..02d240c704 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -23,7 +23,6 @@
#include <errno.h>
#include <string.h>
#include <getopt.h>
-#include <pwd.h>
#include <locale.h>
#include "sd-bus.h"
@@ -42,6 +41,9 @@
#include "cgroup-util.h"
#include "spawn-polkit-agent.h"
#include "verbs.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -869,7 +871,7 @@ static int activate(int argc, char *argv[], void *userdata) {
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -904,7 +906,7 @@ static int kill_session(int argc, char *argv[], void *userdata) {
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -954,7 +956,7 @@ static int enable_linger(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
}
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -988,7 +990,7 @@ static int terminate_user(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1025,7 +1027,7 @@ static int kill_user(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1054,7 +1056,7 @@ static int attach(int argc, char *argv[], void *userdata) {
for (i = 2; i < argc; i++) {
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1082,7 +1084,7 @@ static int flush_devices(int argc, char *argv[], void *userdata) {
polkit_agent_open_if_enabled();
- r = sd_bus_call_method (
+ r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
@@ -1375,6 +1377,8 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
+
r = loginctl_main(argc, argv, bus);
finish:
diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c
index 5856f9079d..466225d69c 100644
--- a/src/login/logind-acl.c
+++ b/src/login/logind-acl.c
@@ -19,11 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <string.h>
#include "util.h"
+#include "formats-util.h"
#include "acl-util.h"
#include "set.h"
#include "logind-acl.h"
@@ -254,8 +254,7 @@ int devnode_acl_all(struct udev *udev,
FOREACH_DIRENT(dent, dir, return -errno) {
_cleanup_free_ char *unescaped_devname = NULL;
- unescaped_devname = cunescape(dent->d_name);
- if (!unescaped_devname)
+ if (cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname) < 0)
return -ENOMEM;
n = strappend("/dev/", unescaped_devname);
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index 0844df20a9..f635fb1b63 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -21,13 +21,15 @@
#include <unistd.h>
-#include "sd-messages.h"
#include "conf-parser.h"
#include "special.h"
#include "sleep-config.h"
#include "bus-util.h"
#include "bus-error.h"
#include "logind-action.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
int manager_handle_action(
Manager *m,
@@ -113,7 +115,7 @@ int manager_handle_action(
if (!supported) {
log_warning("Requested operation not supported, ignoring.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
if (m->action_what) {
diff --git a/src/login/logind-action.h b/src/login/logind-action.h
index e9b424b5f6..ff98065371 100644
--- a/src/login/logind-action.h
+++ b/src/login/logind-action.h
@@ -36,7 +36,6 @@ typedef enum HandleAction {
} HandleAction;
#include "logind.h"
-#include "logind-inhibit.h"
int manager_handle_action(
Manager *m,
diff --git a/src/login/logind-button.c b/src/login/logind-button.c
index d7211e66ce..610adc513e 100644
--- a/src/login/logind-button.c
+++ b/src/login/logind-button.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
@@ -28,9 +27,7 @@
#include <linux/input.h>
#include "sd-messages.h"
-#include "conf-parser.h"
#include "util.h"
-#include "special.h"
#include "logind-button.h"
Button* button_new(Manager *m, const char *name) {
diff --git a/src/login/logind-button.h b/src/login/logind-button.h
index 72a612e914..80d93c7e6b 100644
--- a/src/login/logind-button.h
+++ b/src/login/logind-button.h
@@ -23,8 +23,6 @@
typedef struct Button Button;
-#include "list.h"
-#include "util.h"
#include "logind.h"
struct Button {
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index a6ff5add95..440c32aa2c 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -20,20 +20,18 @@
***/
#include <sys/types.h>
-#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pwd.h>
-#include <unistd.h>
#include <linux/vt.h>
#include "strv.h"
#include "cgroup-util.h"
-#include "audit.h"
#include "bus-util.h"
#include "bus-error.h"
#include "udev-util.h"
#include "logind.h"
+#include "terminal-util.h"
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
Device *d;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 8b0bafd49e..10a9df0961 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -24,7 +24,6 @@
#include <unistd.h>
#include <pwd.h>
-#include "sd-id128.h"
#include "sd-messages.h"
#include "strv.h"
#include "mkdir.h"
@@ -32,17 +31,19 @@
#include "special.h"
#include "sleep-config.h"
#include "fileio-label.h"
-#include "label.h"
-#include "utf8.h"
#include "unit-name.h"
-#include "virt.h"
#include "audit.h"
#include "bus-util.h"
#include "bus-error.h"
#include "bus-common-errors.h"
#include "udev-util.h"
#include "selinux-util.h"
+#include "efivars.h"
#include "logind.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "utmp-wtmp.h"
int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
@@ -213,16 +214,42 @@ static int property_get_preparing(
return sd_bus_message_append(reply, "b", b);
}
+static int property_get_scheduled_shutdown(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ r = sd_bus_message_open_container(reply, 'r', "st");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "st", m->scheduled_shutdown_type, m->scheduled_shutdown_timeout);
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_close_container(reply);
+}
+
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
-static int method_get_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
const char *name;
Session *session;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -241,14 +268,13 @@ static int method_get_session(sd_bus *bus, sd_bus_message *message, void *userda
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Session *session = NULL;
Manager *m = userdata;
pid_t pid;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -278,14 +304,13 @@ static int method_get_session_by_pid(sd_bus *bus, sd_bus_message *message, void
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
uint32_t uid;
User *user;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -304,14 +329,13 @@ static int method_get_user(sd_bus *bus, sd_bus_message *message, void *userdata,
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
User *user = NULL;
pid_t pid;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -340,14 +364,13 @@ static int method_get_user_by_pid(sd_bus *bus, sd_bus_message *message, void *us
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
const char *name;
Seat *seat;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -366,14 +389,13 @@ static int method_get_seat(sd_bus *bus, sd_bus_message *message, void *userdata,
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
Session *session;
Iterator i;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -406,17 +428,16 @@ static int method_list_sessions(sd_bus *bus, sd_bus_message *message, void *user
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
User *user;
Iterator i;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -447,17 +468,16 @@ static int method_list_users(sd_bus *bus, sd_bus_message *message, void *userdat
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_seats(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
Seat *seat;
Iterator i;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -485,16 +505,19 @@ static int method_list_seats(sd_bus *bus, sd_bus_message *message, void *userdat
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
Inhibitor *inhibitor;
Iterator i;
int r;
+ assert(message);
+ assert(m);
+
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
@@ -520,10 +543,10 @@ static int method_list_inhibitors(sd_bus *bus, sd_bus_message *message, void *us
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_create_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
uint32_t uid, leader, audit_id = 0;
_cleanup_free_ char *id = NULL;
@@ -537,7 +560,6 @@ static int method_create_session(sd_bus *bus, sd_bus_message *message, void *use
SessionClass c;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -813,13 +835,12 @@ fail:
return r;
}
-static int method_release_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_release_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Session *session;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -831,18 +852,19 @@ static int method_release_session(sd_bus *bus, sd_bus_message *message, void *us
if (r < 0)
return r;
- session_release(session);
+ r = session_release(session);
+ if (r < 0)
+ return r;
return sd_bus_reply_method_return(message, NULL);
}
-static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Session *session;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -854,21 +876,16 @@ static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *u
if (r < 0)
return r;
- r = session_activate(session);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_session_method_activate(message, session, error);
}
-static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_activate_session_on_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *session_name, *seat_name;
Manager *m = userdata;
Session *session;
Seat *seat;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -897,13 +914,12 @@ static int method_activate_session_on_seat(sd_bus *bus, sd_bus_message *message,
return sd_bus_reply_method_return(message, NULL);
}
-static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_lock_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Session *session;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -915,21 +931,29 @@ static int method_lock_session(sd_bus *bus, sd_bus_message *message, void *userd
if (r < 0)
return r;
- r = session_send_lock(session, streq(sd_bus_message_get_member(message), "LockSession"));
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_session_method_lock(message, session, error);
}
-static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_lock_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.lock-sessions",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
if (r < 0)
return r;
@@ -937,80 +961,52 @@ static int method_lock_sessions(sd_bus *bus, sd_bus_message *message, void *user
return sd_bus_reply_method_return(message, NULL);
}
-static int method_kill_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *swho;
+static int method_kill_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *name;
Manager *m = userdata;
Session *session;
- int32_t signo;
- KillWho who;
int r;
- assert(bus);
assert(message);
assert(m);
- r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
+ r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
- if (isempty(swho))
- who = KILL_ALL;
- else {
- who = kill_who_from_string(swho);
- if (who < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
- }
-
- if (signo <= 0 || signo >= _NSIG)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
-
r = manager_get_session_from_creds(m, message, name, error, &session);
if (r < 0)
return r;
- r = session_kill(session, who, signo);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_session_method_kill(message, session, error);
}
-static int method_kill_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_kill_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
uint32_t uid;
- int32_t signo;
User *user;
int r;
- assert(bus);
assert(message);
assert(m);
- r = sd_bus_message_read(message, "ui", &uid, &signo);
+ r = sd_bus_message_read(message, "u", &uid);
if (r < 0)
return r;
- if (signo <= 0 || signo >= _NSIG)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
-
r = manager_get_user_from_creds(m, message, uid, error, &user);
if (r < 0)
return r;
- r = user_kill(user, signo);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_user_method_kill(message, user, error);
}
-static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_terminate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Session *session;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1022,20 +1018,15 @@ static int method_terminate_session(sd_bus *bus, sd_bus_message *message, void *
if (r < 0)
return r;
- r = session_stop(session, true);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_session_method_terminate(message, session, error);
}
-static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_terminate_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
uint32_t uid;
User *user;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1047,20 +1038,15 @@ static int method_terminate_user(sd_bus *bus, sd_bus_message *message, void *use
if (r < 0)
return r;
- r = user_stop(user, true);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_user_method_terminate(message, user, error);
}
-static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Seat *seat;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1072,14 +1058,10 @@ static int method_terminate_seat(sd_bus *bus, sd_bus_message *message, void *use
if (r < 0)
return r;
- r = seat_stop_sessions(seat, true);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
+ return bus_seat_method_terminate(message, seat, error);
}
-static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *cc = NULL;
Manager *m = userdata;
int b, r;
@@ -1088,7 +1070,6 @@ static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *us
uint32_t uid;
int interactive;
- assert(bus);
assert(message);
assert(m);
@@ -1119,6 +1100,7 @@ static int method_set_user_linger(sd_bus *bus, sd_bus_message *message, void *us
CAP_SYS_ADMIN,
"org.freedesktop.login1.set-user-linger",
interactive,
+ UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
@@ -1267,12 +1249,11 @@ static int flush_devices(Manager *m) {
return trigger_device(m, NULL);
}
-static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *sysfs, *seat;
Manager *m = userdata;
int interactive, r;
- assert(bus);
assert(message);
assert(m);
@@ -1291,6 +1272,7 @@ static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *user
CAP_SYS_ADMIN,
"org.freedesktop.login1.attach-device",
interactive,
+ UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
@@ -1305,11 +1287,10 @@ static int method_attach_device(sd_bus *bus, sd_bus_message *message, void *user
return sd_bus_reply_method_return(message, NULL);
}
-static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
int interactive, r;
- assert(bus);
assert(message);
assert(m);
@@ -1322,6 +1303,7 @@ static int method_flush_devices(sd_bus *bus, sd_bus_message *message, void *user
CAP_SYS_ADMIN,
"org.freedesktop.login1.flush-devices",
interactive,
+ UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
@@ -1481,7 +1463,46 @@ static int execute_shutdown_or_sleep(
m->action_what = w;
/* Make sure the lid switch is ignored for a while */
- manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + IGNORE_LID_SWITCH_SUSPEND_USEC);
+ manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec);
+
+ return 0;
+}
+
+static int manager_inhibit_timeout_handler(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ Inhibitor *offending = NULL;
+ Manager *manager = userdata;
+ int r;
+
+ assert(manager);
+ assert(manager->inhibit_timeout_source == s);
+
+ if (manager->action_what == 0 || manager->action_job)
+ return 0;
+
+ if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
+ _cleanup_free_ char *comm = NULL, *u = NULL;
+
+ (void) get_process_comm(offending->pid, &comm);
+ u = uid_to_name(offending->uid);
+
+ log_notice("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
+ offending->uid, strna(u),
+ offending->pid, strna(comm));
+ }
+
+ /* Actually do the operation */
+ r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
+ if (r < 0) {
+ log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
+
+ manager->action_unit = NULL;
+ manager->action_what = 0;
+ }
return 0;
}
@@ -1491,12 +1512,31 @@ static int delay_shutdown_or_sleep(
InhibitWhat w,
const char *unit_name) {
+ int r;
+ usec_t timeout_val;
+
assert(m);
assert(w >= 0);
assert(w < _INHIBIT_WHAT_MAX);
assert(unit_name);
- m->action_timestamp = now(CLOCK_MONOTONIC);
+ timeout_val = now(CLOCK_MONOTONIC) + m->inhibit_delay_max;
+
+ if (m->inhibit_timeout_source) {
+ r = sd_event_source_set_time(m->inhibit_timeout_source, timeout_val);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_time() failed: %m");
+
+ r = sd_event_source_set_enabled(m->inhibit_timeout_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
+ } else {
+ r = sd_event_add_time(m->event, &m->inhibit_timeout_source, CLOCK_MONOTONIC,
+ timeout_val, 0, manager_inhibit_timeout_handler, m);
+ if (r < 0)
+ return r;
+ }
+
m->action_unit = unit_name;
m->action_what = w;
@@ -1559,49 +1599,25 @@ int bus_manager_shutdown_or_sleep_now_or_later(
return r;
}
-static int method_do_shutdown_or_sleep(
+static int verify_shutdown_creds(
Manager *m,
sd_bus_message *message,
- const char *unit_name,
InhibitWhat w,
+ bool interactive,
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
- const char *sleep_verb,
- sd_bus_message_handler_t method,
sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
bool multiple_sessions, blocked;
- int interactive, r;
uid_t uid;
+ int r;
assert(m);
assert(message);
- assert(unit_name);
assert(w >= 0);
assert(w <= _INHIBIT_WHAT_MAX);
- assert(action);
- assert(action_multiple_sessions);
- assert(action_ignore_inhibit);
- assert(method);
-
- r = sd_bus_message_read(message, "b", &interactive);
- if (r < 0)
- return r;
-
- /* Don't allow multiple jobs being executed at the same time */
- if (m->action_what)
- return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
-
- if (sleep_verb) {
- r = can_sleep(sleep_verb);
- if (r < 0)
- return r;
-
- if (r == 0)
- return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
- }
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
@@ -1618,30 +1634,74 @@ static int method_do_shutdown_or_sleep(
multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
- if (multiple_sessions) {
- r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, interactive, &m->polkit_registry, error);
+ if (multiple_sessions && action_multiple_sessions) {
+ r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, interactive, UID_INVALID, &m->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
- if (blocked) {
- r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, interactive, &m->polkit_registry, error);
+ if (blocked && action_ignore_inhibit) {
+ r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, interactive, UID_INVALID, &m->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
- if (!multiple_sessions && !blocked) {
- r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, interactive, &m->polkit_registry, error);
+ if (!multiple_sessions && !blocked && action) {
+ r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, interactive, UID_INVALID, &m->polkit_registry, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
+ return 0;
+}
+
+static int method_do_shutdown_or_sleep(
+ Manager *m,
+ sd_bus_message *message,
+ const char *unit_name,
+ InhibitWhat w,
+ const char *action,
+ const char *action_multiple_sessions,
+ const char *action_ignore_inhibit,
+ const char *sleep_verb,
+ sd_bus_error *error) {
+
+ int interactive, r;
+
+ assert(m);
+ assert(message);
+ assert(unit_name);
+ assert(w >= 0);
+ assert(w <= _INHIBIT_WHAT_MAX);
+
+ r = sd_bus_message_read(message, "b", &interactive);
+ if (r < 0)
+ return r;
+
+ /* Don't allow multiple jobs being executed at the same time */
+ if (m->action_what)
+ return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
+
+ if (sleep_verb) {
+ r = can_sleep(sleep_verb);
+ if (r < 0)
+ return r;
+
+ if (r == 0)
+ return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
+ }
+
+ r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
+ action_ignore_inhibit, error);
+ if (r != 0)
+ return r;
+
r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
if (r < 0)
return r;
@@ -1649,7 +1709,7 @@ static int method_do_shutdown_or_sleep(
return sd_bus_reply_method_return(message, NULL);
}
-static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_do_shutdown_or_sleep(
@@ -1660,11 +1720,10 @@ static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata,
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
NULL,
- method_poweroff,
error);
}
-static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_do_shutdown_or_sleep(
@@ -1675,11 +1734,10 @@ static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, s
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
NULL,
- method_reboot,
error);
}
-static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_do_shutdown_or_sleep(
@@ -1690,11 +1748,247 @@ static int method_suspend(sd_bus *bus, sd_bus_message *message, void *userdata,
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
"suspend",
- method_suspend,
error);
}
-static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int nologin_timeout_handler(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
+ Manager *m = userdata;
+ int r;
+
+ log_info("Creating /run/nologin, blocking further logins...");
+
+ r = write_string_file_atomic("/run/nologin", "System is going down.");
+ if (r < 0)
+ log_error_errno(r, "Failed to create /run/nologin: %m");
+ else
+ m->unlink_nologin = true;
+
+ return 0;
+}
+
+static int update_schedule_file(Manager *m) {
+
+ int r;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *t = NULL, *temp_path = NULL;
+
+ assert(m);
+
+ r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
+
+ t = cescape(m->wall_message);
+ if (!t)
+ return log_oom();
+
+ r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
+
+ (void) fchmod(fileno(f), 0644);
+
+ fprintf(f,
+ "USEC="USEC_FMT"\n"
+ "WARN_WALL=%i\n"
+ "MODE=%s\n",
+ m->scheduled_shutdown_timeout,
+ m->enable_wall_messages,
+ m->scheduled_shutdown_type);
+
+ if (!isempty(m->wall_message))
+ fprintf(f, "WALL_MESSAGE=%s\n", t);
+
+ (void) fflush_and_check(f);
+
+ if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
+ log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
+ r = -errno;
+
+ (void) unlink(temp_path);
+ (void) unlink("/run/systemd/shutdown/scheduled");
+ }
+
+ return r;
+}
+
+static int manager_scheduled_shutdown_handler(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ Manager *m = userdata;
+ const char *target;
+ int r;
+
+ assert(m);
+
+ if (isempty(m->scheduled_shutdown_type))
+ return 0;
+
+ if (streq(m->scheduled_shutdown_type, "halt"))
+ target = SPECIAL_HALT_TARGET;
+ else if (streq(m->scheduled_shutdown_type, "poweroff"))
+ target = SPECIAL_POWEROFF_TARGET;
+ else
+ target = SPECIAL_REBOOT_TARGET;
+
+ r = execute_shutdown_or_sleep(m, 0, target, &error);
+ if (r < 0)
+ return log_error_errno(r, "Unable to execute transition to %s: %m", target);
+
+ return 0;
+}
+
+static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ const char *action_multiple_sessions = NULL;
+ const char *action_ignore_inhibit = NULL;
+ const char *action = NULL;
+ uint64_t elapse;
+ char *type;
+ int r;
+
+ assert(m);
+ assert(message);
+
+ r = sd_bus_message_read(message, "st", &type, &elapse);
+ if (r < 0)
+ return r;
+
+ if (streq(type, "reboot")) {
+ action = "org.freedesktop.login1.reboot";
+ action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
+ action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
+ } else if (streq(type, "halt")) {
+ action = "org.freedesktop.login1.halt";
+ action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
+ action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
+ } else if (streq(type, "poweroff")) {
+ action = "org.freedesktop.login1.poweroff";
+ action_multiple_sessions = "org.freedesktop.login1.poweroff-multiple-sessions";
+ action_ignore_inhibit = "org.freedesktop.login1.poweroff-ignore-inhibit";
+ } else
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
+
+ r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false,
+ action, action_multiple_sessions, action_ignore_inhibit, error);
+ if (r != 0)
+ return r;
+
+ if (m->scheduled_shutdown_timeout_source) {
+ r = sd_event_source_set_time(m->scheduled_shutdown_timeout_source, elapse);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_time() failed: %m");
+
+ r = sd_event_source_set_enabled(m->scheduled_shutdown_timeout_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
+ } else {
+ r = sd_event_add_time(m->event, &m->scheduled_shutdown_timeout_source,
+ CLOCK_REALTIME, elapse, 0, manager_scheduled_shutdown_handler, m);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_add_time() failed: %m");
+ }
+
+ r = free_and_strdup(&m->scheduled_shutdown_type, type);
+ if (r < 0) {
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ return log_oom();
+ }
+
+ if (m->nologin_timeout_source) {
+ r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_time() failed: %m");
+
+ r = sd_event_source_set_enabled(m->nologin_timeout_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
+ } else {
+ r = sd_event_add_time(m->event, &m->nologin_timeout_source,
+ CLOCK_REALTIME, elapse - 5 * USEC_PER_MINUTE, 0, nologin_timeout_handler, m);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_add_time() failed: %m");
+ }
+
+ m->scheduled_shutdown_timeout = elapse;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
+ if (r >= 0) {
+ const char *tty;
+
+ (void) sd_bus_creds_get_uid(creds, &m->scheduled_shutdown_uid);
+ (void) sd_bus_creds_get_tty(creds, &tty);
+
+ r = free_and_strdup(&m->scheduled_shutdown_tty, tty);
+ if (r < 0) {
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ return log_oom();
+ }
+ }
+
+ r = manager_setup_wall_message_timer(m);
+ if (r < 0)
+ return r;
+
+ if (!isempty(type)) {
+ r = update_schedule_file(m);
+ if (r < 0)
+ return r;
+ } else
+ (void) unlink("/run/systemd/shutdown/scheduled");
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ bool cancelled;
+
+ assert(m);
+ assert(message);
+
+ cancelled = m->scheduled_shutdown_type != NULL;
+
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
+ m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
+ free(m->scheduled_shutdown_type);
+ m->scheduled_shutdown_type = NULL;
+ m->scheduled_shutdown_timeout = 0;
+
+ if (m->unlink_nologin) {
+ (void) unlink("/run/nologin");
+ m->unlink_nologin = false;
+ }
+
+ if (cancelled) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ const char *tty = NULL;
+ uid_t uid = 0;
+ int r;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
+ if (r >= 0) {
+ (void) sd_bus_creds_get_uid(creds, &uid);
+ (void) sd_bus_creds_get_tty(creds, &tty);
+ }
+
+ utmp_wall("The system shutdown has been cancelled",
+ lookup_uid(uid), tty, logind_wall_tty_filter, m);
+ }
+
+ return sd_bus_reply_method_return(message, "b", cancelled);
+}
+
+static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_do_shutdown_or_sleep(
@@ -1705,11 +1999,10 @@ static int method_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hibernate",
- method_hibernate,
error);
}
-static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_do_shutdown_or_sleep(
@@ -1720,7 +2013,6 @@ static int method_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userd
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"hybrid-sleep",
- method_hybrid_sleep,
error);
}
@@ -1772,7 +2064,7 @@ static int method_can_shutdown_or_sleep(
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
if (multiple_sessions) {
- r = bus_verify_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, false, &challenge, error);
+ r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, UID_INVALID, &challenge, error);
if (r < 0)
return r;
@@ -1785,7 +2077,7 @@ static int method_can_shutdown_or_sleep(
}
if (blocked) {
- r = bus_verify_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, false, &challenge, error);
+ r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, UID_INVALID, &challenge, error);
if (r < 0)
return r;
@@ -1801,7 +2093,7 @@ static int method_can_shutdown_or_sleep(
/* If neither inhibit nor multiple sessions
* apply then just check the normal policy */
- r = bus_verify_polkit(message, CAP_SYS_BOOT, action, false, &challenge, error);
+ r = bus_test_polkit(message, CAP_SYS_BOOT, action, UID_INVALID, &challenge, error);
if (r < 0)
return r;
@@ -1816,7 +2108,7 @@ static int method_can_shutdown_or_sleep(
return sd_bus_reply_method_return(message, "s", result);
}
-static int method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_can_shutdown_or_sleep(
@@ -1829,7 +2121,7 @@ static int method_can_poweroff(sd_bus *bus, sd_bus_message *message, void *userd
error);
}
-static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_can_shutdown_or_sleep(
@@ -1842,7 +2134,7 @@ static int method_can_reboot(sd_bus *bus, sd_bus_message *message, void *userdat
error);
}
-static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_can_shutdown_or_sleep(
@@ -1855,7 +2147,7 @@ static int method_can_suspend(sd_bus *bus, sd_bus_message *message, void *userda
error);
}
-static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_can_shutdown_or_sleep(
@@ -1868,7 +2160,7 @@ static int method_can_hibernate(sd_bus *bus, sd_bus_message *message, void *user
error);
}
-static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
return method_can_shutdown_or_sleep(
@@ -1881,7 +2173,100 @@ static int method_can_hybrid_sleep(sd_bus *bus, sd_bus_message *message, void *u
error);
}
-static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int property_get_reboot_to_firmware_setup(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(userdata);
+
+ r = efi_get_reboot_to_firmware();
+ if (r < 0 && r != -EOPNOTSUPP)
+ return r;
+
+ return sd_bus_message_append(reply, "b", r > 0);
+}
+
+static int method_set_reboot_to_firmware_setup(
+ sd_bus_message *message,
+ void *userdata,
+ sd_bus_error *error) {
+
+ int b, r;
+ Manager *m = userdata;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_polkit_async(message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.set-reboot-to-firmware-setup",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ r = efi_set_reboot_to_firmware(b);
+ if (r < 0)
+ return r;
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_to_firmware_setup(
+ sd_bus_message *message,
+ void *userdata,
+ sd_bus_error *error) {
+
+ int r;
+ bool challenge;
+ const char *result;
+ Manager *m = userdata;
+
+ assert(message);
+ assert(m);
+
+ r = efi_reboot_to_firmware_supported();
+ if (r == -EOPNOTSUPP)
+ return sd_bus_reply_method_return(message, "s", "na");
+ else if (r < 0)
+ return r;
+
+ r = bus_test_polkit(message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.set-reboot-to-firmware-setup",
+ UID_INVALID,
+ &challenge,
+ error);
+ if (r < 0)
+ return r;
+
+ if (r > 0)
+ result = "yes";
+ else if (challenge)
+ result = "challenge";
+ else
+ result = "no";
+
+ return sd_bus_reply_method_return(message, "s", result);
+}
+
+static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
const char *who, *why, *what, *mode;
_cleanup_free_ char *id = NULL;
@@ -1894,7 +2279,6 @@ static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata,
uid_t uid;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -1921,15 +2305,20 @@ static int method_inhibit(sd_bus *bus, sd_bus_message *message, void *userdata,
if (m->action_what & w)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
- r = bus_verify_polkit_async(message, CAP_SYS_BOOT,
- w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
- w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
- w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
- w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
- w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
- w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
- "org.freedesktop.login1.inhibit-handle-lid-switch",
- false, &m->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_BOOT,
+ w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
+ w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
+ w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
+ w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
+ w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
+ w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
+ "org.freedesktop.login1.inhibit-handle-lid-switch",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -1992,10 +2381,14 @@ fail:
const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
+ SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
+ SD_BUS_WRITABLE_PROPERTY("WallMessage", "s", NULL, NULL, offsetof(Manager, wall_message), 0),
+
SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -2007,10 +2400,12 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
+ SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2025,21 +2420,23 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0),
SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, 0),
- SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, 0),
- SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, 0),
- SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, 0),
- SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
+ SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2048,6 +2445,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("SessionNew", "so", 0),
SD_BUS_SIGNAL("SessionRemoved", "so", 0),
@@ -2082,7 +2481,7 @@ static int session_jobs_reply(Session *s, const char *unit, const char *result)
return r;
}
-int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path, *result, *unit;
Manager *m = userdata;
Session *session;
@@ -2090,7 +2489,6 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
User *user;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -2151,14 +2549,13 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
return 0;
}
-int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path, *unit;
Manager *m = userdata;
Session *session;
User *user;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -2179,7 +2576,7 @@ int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
return 0;
}
-int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *unit = NULL;
Manager *m = userdata;
const char *path;
@@ -2187,7 +2584,6 @@ int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdat
User *user;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -2212,13 +2608,14 @@ int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdat
return 0;
}
-int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Session *session;
Iterator i;
int b, r;
- assert(bus);
+ assert(message);
+ assert(m);
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
@@ -2238,16 +2635,17 @@ int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus
return 0;
}
-int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name, *old, *new;
Manager *m = userdata;
Session *session;
Iterator i;
int r;
-
-
char *key;
+ assert(message);
+ assert(m);
+
r = sd_bus_message_read(message, "sss", &name, &old, &new);
if (r < 0) {
bus_log_parse_error(r);
@@ -2286,44 +2684,6 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
l);
}
-int manager_dispatch_delayed(Manager *manager) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- Inhibitor *offending = NULL;
- int r;
-
- assert(manager);
-
- if (manager->action_what == 0 || manager->action_job)
- return 0;
-
- /* Continue delay? */
- if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
- _cleanup_free_ char *comm = NULL, *u = NULL;
-
- get_process_comm(offending->pid, &comm);
- u = uid_to_name(offending->uid);
-
- if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
- return 0;
-
- log_info("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
- offending->uid, strna(u),
- offending->pid, strna(comm));
- }
-
- /* Actually do the operation */
- r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
- if (r < 0) {
- log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
-
- manager->action_unit = NULL;
- manager->action_what = 0;
- return r;
- }
-
- return 1;
-}
-
int manager_start_scope(
Manager *manager,
const char *scope,
diff --git a/src/login/logind-device.c b/src/login/logind-device.c
index 76c5a5c88f..ee4c45fb8d 100644
--- a/src/login/logind-device.c
+++ b/src/login/logind-device.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
#include "util.h"
diff --git a/src/login/logind-device.h b/src/login/logind-device.h
index c273d2bfa0..6b2728586c 100644
--- a/src/login/logind-device.h
+++ b/src/login/logind-device.h
@@ -24,8 +24,6 @@
typedef struct Device Device;
#include "list.h"
-#include "util.h"
-#include "logind.h"
#include "logind-seat.h"
#include "logind-session-device.h"
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 62460673b9..9218d098e0 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -29,6 +29,7 @@ Login.PowerKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manag
Login.SuspendKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, suspend_key_ignore_inhibited)
Login.HibernateKeyIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, hibernate_key_ignore_inhibited)
Login.LidSwitchIgnoreInhibited, config_parse_bool, 0, offsetof(Manager, lid_switch_ignore_inhibited)
+Login.HoldoffTimeoutSec, config_parse_sec, 0, offsetof(Manager, holdoff_timeout_usec)
Login.IdleAction, config_parse_handle_action, 0, offsetof(Manager, idle_action)
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 84fee0e773..68304a1610 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -26,9 +26,9 @@
#include "util.h"
#include "mkdir.h"
-#include "path-util.h"
#include "logind-inhibit.h"
#include "fileio.h"
+#include "formats-util.h"
Inhibitor* inhibitor_new(Manager *m, const char* id) {
Inhibitor *i;
@@ -232,18 +232,18 @@ int inhibitor_load(Inhibitor *i) {
}
if (who) {
- cc = cunescape(who);
- if (!cc)
- return -ENOMEM;
+ r = cunescape(who, 0, &cc);
+ if (r < 0)
+ return r;
free(i->who);
i->who = cc;
}
if (why) {
- cc = cunescape(why);
- if (!cc)
- return -ENOMEM;
+ r = cunescape(why, 0, &cc);
+ if (r < 0)
+ return r;
free(i->why);
i->why = cc;
diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h
index f767876a4c..1b77fc1e9e 100644
--- a/src/login/logind-inhibit.h
+++ b/src/login/logind-inhibit.h
@@ -23,8 +23,6 @@
typedef struct Inhibitor Inhibitor;
-#include "list.h"
-#include "util.h"
typedef enum InhibitWhat {
INHIBIT_SHUTDOWN = 1,
@@ -46,7 +44,6 @@ typedef enum InhibitMode {
} InhibitMode;
#include "logind.h"
-#include "logind-seat.h"
struct Inhibitor {
Manager *manager;
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 50b0b8842f..ce67ffde37 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -193,14 +193,26 @@ static int property_get_idle_since_hint(
return sd_bus_message_append(reply, "t", u);
}
-static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Seat *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.login1.manage",
+ false,
+ UID_INVALID,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = seat_stop_sessions(s, true);
if (r < 0)
return r;
@@ -208,13 +220,12 @@ static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, NULL);
}
-static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Seat *s = userdata;
const char *name;
Session *session;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -236,12 +247,11 @@ static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *u
return sd_bus_reply_method_return(message, NULL);
}
-static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Seat *s = userdata;
unsigned int to;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -259,11 +269,10 @@ static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, NULL);
}
-static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Seat *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -274,11 +283,10 @@ static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *use
return sd_bus_reply_method_return(message, NULL);
}
-static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Seat *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -302,7 +310,7 @@ const sd_bus_vtable seat_vtable[] = {
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
+ SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index 126c5b84cc..11d24ce5b4 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -19,21 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
#include <string.h>
-#include "sd-id128.h"
#include "sd-messages.h"
#include "logind-seat.h"
#include "logind-acl.h"
#include "util.h"
#include "mkdir.h"
-#include "path-util.h"
+#include "formats-util.h"
+#include "terminal-util.h"
Seat *seat_new(Manager *m, const char *id) {
Seat *s;
diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h
index 9e469d41c6..248dbeb9d7 100644
--- a/src/login/logind-seat.h
+++ b/src/login/logind-seat.h
@@ -24,9 +24,6 @@
typedef struct Seat Seat;
#include "list.h"
-#include "util.h"
-#include "logind.h"
-#include "logind-device.h"
#include "logind-session.h"
struct Seat {
@@ -96,3 +93,5 @@ char *seat_bus_path(Seat *s);
int seat_send_signal(Seat *s, bool new_seat);
int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_;
+
+int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 4e7edef52d..debaa31a29 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -180,14 +180,26 @@ static int property_get_idle_since_hint(
return sd_bus_message_append(reply, "t", u);
}
-static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.login1.manage",
+ false,
+ s->user->uid,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = session_stop(s, true);
if (r < 0)
return r;
@@ -195,11 +207,10 @@ static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, NULL);
}
-static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -210,28 +221,39 @@ static int method_activate(sd_bus *bus, sd_bus_message *message, void *userdata,
return sd_bus_reply_method_return(message, NULL);
}
-static int method_lock(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
int r;
- assert(bus);
assert(message);
assert(s);
- r = session_send_lock(s, streq(sd_bus_message_get_member(message), "Lock"));
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.login1.lock-sessions",
+ false,
+ s->user->uid,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ r = session_send_lock(s, strstr(sd_bus_message_get_member(message), "Lock"));
if (r < 0)
return r;
return sd_bus_reply_method_return(message, NULL);
}
-static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
Session *s = userdata;
uid_t uid;
int r, b;
- assert(bus);
assert(message);
assert(s);
@@ -255,14 +277,13 @@ static int method_set_idle_hint(sd_bus *bus, sd_bus_message *message, void *user
return sd_bus_reply_method_return(message, NULL);
}
-static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
const char *swho;
int32_t signo;
KillWho who;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -281,6 +302,19 @@ static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
if (signo <= 0 || signo >= _NSIG)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.login1.manage",
+ false,
+ s->user->uid,
+ &s->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = session_kill(s, who, signo);
if (r < 0)
return r;
@@ -288,13 +322,12 @@ static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
return sd_bus_reply_method_return(message, NULL);
}
-static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
Session *s = userdata;
int r, force;
uid_t uid;
- assert(bus);
assert(message);
assert(s);
@@ -320,10 +353,9 @@ static int method_take_control(sd_bus *bus, sd_bus_message *message, void *userd
return sd_bus_reply_method_return(message, NULL);
}
-static int method_release_control(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_release_control(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
- assert(bus);
assert(message);
assert(s);
@@ -335,14 +367,13 @@ static int method_release_control(sd_bus *bus, sd_bus_message *message, void *us
return sd_bus_reply_method_return(message, NULL);
}
-static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
uint32_t major, minor;
SessionDevice *sd;
dev_t dev;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -374,14 +405,13 @@ static int method_take_device(sd_bus *bus, sd_bus_message *message, void *userda
return r;
}
-static int method_release_device(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_release_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
uint32_t major, minor;
SessionDevice *sd;
dev_t dev;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -401,14 +431,13 @@ static int method_release_device(sd_bus *bus, sd_bus_message *message, void *use
return sd_bus_reply_method_return(message, NULL);
}
-static int method_pause_device_complete(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_pause_device_complete(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
uint32_t major, minor;
SessionDevice *sd;
dev_t dev;
int r;
- assert(bus);
assert(message);
assert(s);
@@ -456,12 +485,12 @@ const sd_bus_vtable session_vtable[] = {
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("Activate", NULL, NULL, method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Lock", NULL, NULL, method_lock, 0),
- SD_BUS_METHOD("Unlock", NULL, NULL, method_lock, 0),
+ SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Kill", "si", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
+ SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c
index c2de862250..656f268dba 100644
--- a/src/login/logind-session-device.c
+++ b/src/login/logind-session-device.c
@@ -19,16 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <fcntl.h>
#include <libudev.h>
#include <linux/input.h>
-#include <linux/ioctl.h>
#include <string.h>
#include <sys/ioctl.h>
-#include <sys/stat.h>
#include <sys/types.h>
-#include <unistd.h>
#include "util.h"
#include "missing.h"
diff --git a/src/login/logind-session-device.h b/src/login/logind-session-device.h
index 61a843d09d..1c9f998371 100644
--- a/src/login/logind-session-device.h
+++ b/src/login/logind-session-device.h
@@ -25,11 +25,7 @@ typedef enum DeviceType DeviceType;
typedef struct SessionDevice SessionDevice;
#include "list.h"
-#include "util.h"
#include "logind.h"
-#include "logind-device.h"
-#include "logind-seat.h"
-#include "logind-session.h"
enum DeviceType {
DEVICE_TYPE_UNKNOWN,
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index a02a537f7c..6a450b02a0 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -28,9 +28,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
-#include "sd-id128.h"
#include "sd-messages.h"
-#include "strv.h"
#include "util.h"
#include "mkdir.h"
#include "path-util.h"
@@ -39,6 +37,8 @@
#include "bus-util.h"
#include "bus-error.h"
#include "logind-session.h"
+#include "formats-util.h"
+#include "terminal-util.h"
#define RELEASE_USEC (20*USEC_PER_SEC)
@@ -463,7 +463,7 @@ int session_activate(Session *s) {
assert(s->user);
if (!s->seat)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (s->seat->active == s)
return 0;
@@ -471,7 +471,7 @@ int session_activate(Session *s) {
/* on seats with VTs, we let VTs manage session-switching */
if (seat_has_vts(s->seat)) {
if (!s->vtnr)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
return chvt(s->vtnr);
}
@@ -703,18 +703,20 @@ static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *us
return 0;
}
-void session_release(Session *s) {
+int session_release(Session *s) {
assert(s);
if (!s->started || s->stopping)
- return;
+ return 0;
+
+ if (s->timer_event_source)
+ return 0;
- if (!s->timer_event_source)
- sd_event_add_time(s->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
- release_timeout_callback, s);
+ return sd_event_add_time(s->manager->event,
+ &s->timer_event_source,
+ CLOCK_MONOTONIC,
+ now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
+ release_timeout_callback, s);
}
bool session_is_active(Session *s) {
@@ -1041,15 +1043,15 @@ void session_restore_vt(Session *s) {
if (vt < 0)
return;
- ioctl(vt, KDSETMODE, KD_TEXT);
+ (void) ioctl(vt, KDSETMODE, KD_TEXT);
if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
kb = K_UNICODE;
- ioctl(vt, KDSKBMODE, kb);
+ (void) ioctl(vt, KDSKBMODE, kb);
mode.mode = VT_AUTO;
- ioctl(vt, VT_SETMODE, &mode);
+ (void) ioctl(vt, VT_SETMODE, &mode);
fchown(vt, 0, -1);
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index a007fb5e84..7a329b94ad 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -25,10 +25,6 @@ typedef struct Session Session;
typedef enum KillWho KillWho;
#include "list.h"
-#include "util.h"
-#include "logind.h"
-#include "logind-seat.h"
-#include "logind-session-device.h"
#include "logind-user.h"
#include "login-shared.h"
@@ -141,7 +137,7 @@ int session_create_fifo(Session *s);
int session_start(Session *s);
int session_stop(Session *s, bool force);
int session_finalize(Session *s);
-void session_release(Session *s);
+int session_release(Session *s);
int session_save(Session *s);
int session_load(Session *s);
int session_kill(Session *s, KillWho who, int signo);
@@ -179,3 +175,8 @@ void session_leave_vt(Session *s);
bool session_is_controller(Session *s, const char *sender);
int session_set_controller(Session *s, const char *sender, bool force);
void session_drop_controller(Session *s);
+
+int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index 5cfaac0d4f..8a710cef13 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -26,6 +26,7 @@
#include "bus-util.h"
#include "logind.h"
#include "logind-user.h"
+#include "formats-util.h"
static int property_get_display(
sd_bus *bus,
@@ -171,14 +172,26 @@ static int property_get_linger(
return sd_bus_message_append(reply, "b", r > 0);
}
-static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
User *u = userdata;
int r;
- assert(bus);
assert(message);
assert(u);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.login1.manage",
+ false,
+ u->uid,
+ &u->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = user_stop(u, true);
if (r < 0)
return r;
@@ -186,15 +199,27 @@ static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, NULL);
}
-static int method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
User *u = userdata;
int32_t signo;
int r;
- assert(bus);
assert(message);
assert(u);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.login1.manage",
+ false,
+ u->uid,
+ &u->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = sd_bus_message_read(message, "i", &signo);
if (r < 0)
return r;
@@ -227,8 +252,8 @@ const sd_bus_vtable user_vtable[] = {
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Linger", "b", property_get_linger, 0, 0),
- SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("Kill", "i", NULL, method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
+ SD_BUS_METHOD("Terminate", NULL, NULL, bus_user_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Kill", "i", NULL, bus_user_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index f4c4490e8f..dc3db9abda 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -26,8 +26,8 @@
#include "util.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "hashmap.h"
-#include "strv.h"
#include "fileio.h"
#include "path-util.h"
#include "special.h"
@@ -38,6 +38,7 @@
#include "clean-ipc.h"
#include "logind-user.h"
#include "smack-util.h"
+#include "formats-util.h"
User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
User *u;
@@ -319,7 +320,7 @@ static int user_mkdir_runtime_path(User *u) {
} else
p = u->runtime_path;
- if (path_is_mount_point(p, false) <= 0) {
+ if (path_is_mount_point(p, 0) <= 0) {
_cleanup_free_ char *t = NULL;
(void) mkdir(p, 0700);
@@ -377,7 +378,7 @@ static int user_start_slice(User *u) {
char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
sprintf(lu, UID_FMT, u->uid);
- r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
+ r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
if (r < 0)
return r;
@@ -410,9 +411,9 @@ static int user_start_service(User *u) {
char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
sprintf(lu, UID_FMT, u->uid);
- service = unit_name_build("user", lu, ".service");
- if (!service)
- return log_oom();
+ r = unit_name_build("user", lu, ".service", &service);
+ if (r < 0)
+ return log_error_errno(r, "Failed to build service name: %m");
r = manager_start_unit(u->manager, service, &error, &job);
if (r < 0) {
@@ -522,7 +523,7 @@ static int user_remove_runtime_path(User *u) {
if (!u->runtime_path)
return 0;
- r = rm_rf(u->runtime_path, false, false, false);
+ r = rm_rf(u->runtime_path, 0);
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
@@ -533,7 +534,7 @@ static int user_remove_runtime_path(User *u) {
if (r < 0 && errno != EINVAL && errno != ENOENT)
log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
- r = rm_rf(u->runtime_path, false, true, false);
+ r = rm_rf(u->runtime_path, REMOVE_ROOT);
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
index 4e0568fea9..722247806b 100644
--- a/src/login/logind-user.h
+++ b/src/login/logind-user.h
@@ -24,9 +24,7 @@
typedef struct User User;
#include "list.h"
-#include "util.h"
#include "logind.h"
-#include "logind-session.h"
typedef enum UserState {
USER_OFFLINE, /* Not logged in at all */
@@ -92,3 +90,6 @@ int user_send_changed(User *u, const char *properties, ...) _sentinel_;
const char* user_state_to_string(UserState s) _const_;
UserState user_state_from_string(const char *s) _pure_;
+
+int bus_user_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
new file mode 100644
index 0000000000..1e13ff01de
--- /dev/null
+++ b/src/login/logind-utmp.c
@@ -0,0 +1,182 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Daniel Mack
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "sd-messages.h"
+#include "strv.h"
+#include "special.h"
+#include "unit-name.h"
+#include "audit.h"
+#include "bus-util.h"
+#include "bus-error.h"
+#include "bus-common-errors.h"
+#include "logind.h"
+#include "formats-util.h"
+#include "utmp-wtmp.h"
+
+_const_ static usec_t when_wall(usec_t n, usec_t elapse) {
+
+ usec_t left;
+ unsigned int i;
+ static const int wall_timers[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 25, 40, 55, 70, 100, 130, 150, 180,
+ };
+
+ /* If the time is already passed, then don't announce */
+ if (n >= elapse)
+ return 0;
+
+ left = elapse - n;
+
+ for (i = 1; i < ELEMENTSOF(wall_timers); i++)
+ if (wall_timers[i] * USEC_PER_MINUTE >= left)
+ return left - wall_timers[i-1] * USEC_PER_MINUTE;
+
+ return left % USEC_PER_HOUR;
+}
+
+bool logind_wall_tty_filter(const char *tty, void *userdata) {
+
+ Manager *m = userdata;
+
+ assert(m);
+
+ if (!startswith(tty, "/dev/"))
+ return true;
+
+ return !streq(tty + 5, m->scheduled_shutdown_tty);
+}
+
+static int warn_wall(Manager *m, usec_t n) {
+ char date[FORMAT_TIMESTAMP_MAX] = {};
+ _cleanup_free_ char *l = NULL;
+ usec_t left;
+ int r;
+
+ assert(m);
+
+ if (!m->enable_wall_messages)
+ return 0;
+
+ left = m->scheduled_shutdown_timeout > n;
+
+ r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
+ strempty(m->wall_message),
+ isempty(m->wall_message) ? "" : "\n",
+ m->scheduled_shutdown_type,
+ left ? "at " : "NOW",
+ left ? format_timestamp(date, sizeof(date), m->scheduled_shutdown_timeout) : "");
+ if (r < 0) {
+ log_oom();
+ return 0;
+ }
+
+ utmp_wall(l, lookup_uid(m->scheduled_shutdown_uid),
+ m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
+
+ return 1;
+}
+
+static int wall_message_timeout_handler(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
+ Manager *m = userdata;
+ usec_t n, next;
+ int r;
+
+ assert(m);
+ assert(s == m->wall_message_timeout_source);
+
+ n = now(CLOCK_REALTIME);
+
+ r = warn_wall(m, n);
+ if (r == 0)
+ return 0;
+
+ next = when_wall(n, m->scheduled_shutdown_timeout);
+ if (next > 0) {
+ r = sd_event_source_set_time(s, n + next);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_time() failed. %m");
+
+ r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
+ }
+
+ return 0;
+}
+
+int manager_setup_wall_message_timer(Manager *m) {
+
+ usec_t n, elapse;
+ int r;
+
+ assert(m);
+
+ n = now(CLOCK_REALTIME);
+ elapse = m->scheduled_shutdown_timeout;
+
+ /* wall message handling */
+
+ if (isempty(m->scheduled_shutdown_type)) {
+ warn_wall(m, n);
+ return 0;
+ }
+
+ if (elapse < n)
+ return 0;
+
+ /* Warn immediately if less than 15 minutes are left */
+ if (elapse - n < 15 * USEC_PER_MINUTE) {
+ r = warn_wall(m, n);
+ if (r == 0)
+ return 0;
+ }
+
+ elapse = when_wall(n, elapse);
+ if (elapse == 0)
+ return 0;
+
+ if (m->wall_message_timeout_source) {
+ r = sd_event_source_set_time(m->wall_message_timeout_source, n + elapse);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_time() failed. %m");
+
+ r = sd_event_source_set_enabled(m->wall_message_timeout_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_source_set_enabled() failed. %m");
+ } else {
+ r = sd_event_add_time(m->event, &m->wall_message_timeout_source,
+ CLOCK_REALTIME, n + elapse, 0, wall_message_timeout_handler, m);
+ if (r < 0)
+ return log_error_errno(r, "sd_event_add_time() failed. %m");
+ }
+
+ return 0;
+}
diff --git a/src/login/logind.c b/src/login/logind.c
index b44f376427..00f8dbdab2 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -24,19 +24,20 @@
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
-#include <linux/vt.h>
-#include <sys/timerfd.h>
#include "sd-daemon.h"
#include "strv.h"
#include "conf-parser.h"
-#include "mkdir.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "logind.h"
#include "udev-util.h"
+#include "formats-util.h"
+#include "signal-util.h"
+#include "logind.h"
+
+static void manager_free(Manager *m);
-Manager *manager_new(void) {
+static Manager *manager_new(void) {
Manager *m;
int r;
@@ -57,6 +58,7 @@ Manager *manager_new(void) {
m->handle_lid_switch = HANDLE_SUSPEND;
m->handle_lid_switch_docked = HANDLE_IGNORE;
m->lid_switch_ignore_inhibited = true;
+ m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
m->idle_action_usec = 30 * USEC_PER_MINUTE;
m->idle_action = HANDLE_IGNORE;
@@ -101,7 +103,7 @@ fail:
return NULL;
}
-void manager_free(Manager *m) {
+static void manager_free(Manager *m) {
Session *session;
User *u;
Device *d;
@@ -142,6 +144,10 @@ void manager_free(Manager *m) {
set_free_free(m->busnames);
sd_event_source_unref(m->idle_action_event_source);
+ sd_event_source_unref(m->inhibit_timeout_source);
+ sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ sd_event_source_unref(m->nologin_timeout_source);
+ sd_event_source_unref(m->wall_message_timeout_source);
sd_event_source_unref(m->console_active_event_source);
sd_event_source_unref(m->udev_seat_event_source);
@@ -164,6 +170,9 @@ void manager_free(Manager *m) {
if (m->udev)
udev_unref(m->udev);
+ if (m->unlink_nologin)
+ (void) unlink("/run/nologin");
+
bus_verify_polkit_async_registry_free(m->polkit_registry);
sd_bus_unref(m->bus);
@@ -174,6 +183,9 @@ void manager_free(Manager *m) {
strv_free(m->kill_only_users);
strv_free(m->kill_exclude_users);
+ free(m->scheduled_shutdown_type);
+ free(m->scheduled_shutdown_tty);
+ free(m->wall_message);
free(m->action_job);
free(m);
}
@@ -890,7 +902,7 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
-void manager_gc(Manager *m, bool drop_not_started) {
+static void manager_gc(Manager *m, bool drop_not_started) {
Seat *seat;
Session *session;
User *user;
@@ -1001,7 +1013,7 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
return 0;
}
-int manager_startup(Manager *m) {
+static int manager_startup(Manager *m) {
int r;
Seat *seat;
Session *session;
@@ -1032,7 +1044,7 @@ int manager_startup(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to add seat0: %m");
- r = manager_set_lid_switch_ignore(m, 0 + IGNORE_LID_SWITCH_STARTUP_USEC);
+ r = manager_set_lid_switch_ignore(m, 0 + m->holdoff_timeout_usec);
if (r < 0)
log_warning_errno(r, "Failed to set up lid switch ignore event source: %m");
@@ -1088,14 +1100,12 @@ int manager_startup(Manager *m) {
return 0;
}
-int manager_run(Manager *m) {
+static int manager_run(Manager *m) {
int r;
assert(m);
for (;;) {
- usec_t us = (uint64_t) -1;
-
r = sd_event_get_state(m->event);
if (r < 0)
return r;
@@ -1104,19 +1114,7 @@ int manager_run(Manager *m) {
manager_gc(m, true);
- if (manager_dispatch_delayed(m) > 0)
- continue;
-
- if (m->action_what != 0 && !m->action_job) {
- usec_t x, y;
-
- x = now(CLOCK_MONOTONIC);
- y = m->action_timestamp + m->inhibit_delay_max;
-
- us = x >= y ? 0 : y - x;
- }
-
- r = sd_event_run(m->event, us);
+ r = sd_event_run(m->event, (uint64_t) -1);
if (r < 0)
return r;
}
diff --git a/src/login/logind.conf b/src/login/logind.conf
index 6b1943a2d1..6df6f04c77 100644
--- a/src/login/logind.conf
+++ b/src/login/logind.conf
@@ -5,10 +5,11 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/logind.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
-# See logind.conf(5) for details
+# See logind.conf(5) for details.
[Login]
#NAutoVTs=6
@@ -26,6 +27,7 @@
#SuspendKeyIgnoreInhibited=no
#HibernateKeyIgnoreInhibited=no
#LidSwitchIgnoreInhibited=yes
+#HoldoffTimeoutSec=30s
#IdleAction=ignore
#IdleActionSec=30min
#RuntimeDirectorySize=10%
diff --git a/src/login/logind.h b/src/login/logind.h
index e0cb7d0238..cd226f55fc 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -22,12 +22,10 @@
***/
#include <stdbool.h>
-#include <inttypes.h>
#include <libudev.h>
#include "sd-event.h"
#include "sd-bus.h"
-#include "util.h"
#include "list.h"
#include "hashmap.h"
#include "set.h"
@@ -35,16 +33,10 @@
typedef struct Manager Manager;
#include "logind-device.h"
-#include "logind-seat.h"
-#include "logind-session.h"
-#include "logind-user.h"
#include "logind-inhibit.h"
#include "logind-button.h"
#include "logind-action.h"
-#define IGNORE_LID_SWITCH_STARTUP_USEC (3 * USEC_PER_MINUTE)
-#define IGNORE_LID_SWITCH_SUSPEND_USEC (30 * USEC_PER_SEC)
-
struct Manager {
sd_event *event;
sd_bus *bus;
@@ -103,7 +95,19 @@ struct Manager {
/* If a shutdown/suspend is currently executed, then this is
* the job of it */
char *action_job;
- usec_t action_timestamp;
+ sd_event_source *inhibit_timeout_source;
+
+ char *scheduled_shutdown_type;
+ usec_t scheduled_shutdown_timeout;
+ sd_event_source *scheduled_shutdown_timeout_source;
+ uid_t scheduled_shutdown_uid;
+ char *scheduled_shutdown_tty;
+ sd_event_source *nologin_timeout_source;
+ bool unlink_nologin;
+
+ char *wall_message;
+ unsigned enable_wall_messages;
+ sd_event_source *wall_message_timeout_source;
sd_event_source *idle_action_event_source;
usec_t idle_action_usec;
@@ -125,14 +129,12 @@ struct Manager {
Hashmap *polkit_registry;
+ usec_t holdoff_timeout_usec;
sd_event_source *lid_switch_ignore_event_source;
size_t runtime_dir_size;
};
-Manager *manager_new(void);
-void manager_free(Manager *m);
-
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
int manager_add_button(Manager *m, const char *name, Button **_button);
int manager_add_seat(Manager *m, const char *id, Seat **_seat);
@@ -145,12 +147,8 @@ int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor);
int manager_process_seat_device(Manager *m, struct udev_device *d);
int manager_process_button_device(Manager *m, struct udev_device *d);
-int manager_startup(Manager *m);
-int manager_run(Manager *m);
int manager_spawn_autovt(Manager *m, unsigned int vtnr);
-void manager_gc(Manager *m, bool drop_not_started);
-
bool manager_shall_kill(Manager *m, const char *user);
int manager_get_idle_hint(Manager *m, dual_timestamp *t);
@@ -164,18 +162,16 @@ bool manager_is_docked_or_multiple_displays(Manager *m);
extern const sd_bus_vtable manager_vtable[];
-int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name, InhibitWhat w, sd_bus_error *error);
int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
-int manager_dispatch_delayed(Manager *manager);
-
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
@@ -197,3 +193,6 @@ int config_parse_tmpfs_size(const char *unit, const char *filename, unsigned lin
int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret);
int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret);
int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret);
+
+int manager_setup_wall_message_timer(Manager *m);
+bool logind_wall_tty_filter(const char *tty, void *userdata);
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index 1318328aa0..0ad78802dd 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -130,6 +130,14 @@
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
+ send_member="CanRebootToFirmwareSetup"/>
+
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Manager"
+ send_member="SetRebootToFirmwareSetup"/>
+
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Manager"
send_member="AttachDevice"/>
<allow send_destination="org.freedesktop.login1"
diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in
index 49094eeddb..83e7183323 100644
--- a/src/login/org.freedesktop.login1.policy.in
+++ b/src/login/org.freedesktop.login1.policy.in
@@ -270,4 +270,34 @@
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.hibernate</annotate>
</action>
+ <action id="org.freedesktop.login1.manage">
+ <_description>Manage active sessions, users and seats</_description>
+ <_message>Authentication is required for managing active sessions, users and seats.</_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.login1.lock-sessions">
+ <_description>Lock or unlock active sessions</_description>
+ <_message>Authentication is required to lock or unlock active sessions.</_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.login1.set-reboot-to-firmware-setup">
+ <_description>Allow indication to the firmware to boot to setup interface</_description>
+ <_message>Authentication is required to indicate to the firmware to boot to setup interface.</_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>
+
</policyconfig>
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index d7a708fd0a..b5d419000c 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -40,6 +40,9 @@
#include "socket-util.h"
#include "fileio.h"
#include "bus-error.h"
+#include "formats-util.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
static int parse_argv(
pam_handle_t *handle,
@@ -334,7 +337,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
/* If this fails vtnr will be 0, that's intended */
if (!isempty(cvtnr))
- safe_atou32(cvtnr, &vtnr);
+ (void) safe_atou32(cvtnr, &vtnr);
if (!isempty(display) && !vtnr) {
if (isempty(seat))
diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c
index 9bd9152bed..9a9fb7622d 100644
--- a/src/login/sysfs-show.c
+++ b/src/login/sysfs-show.c
@@ -27,6 +27,7 @@
#include "sysfs-show.h"
#include "path-util.h"
#include "udev-util.h"
+#include "terminal-util.h"
static int show_sysfs_one(
struct udev *udev,
diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c
index 274687d20f..03516de916 100644
--- a/src/login/test-inhibit.c
+++ b/src/login/test-inhibit.c
@@ -25,7 +25,6 @@
#include "util.h"
#include "sd-bus.h"
#include "bus-util.h"
-#include "bus-error.h"
static int inhibit(sd_bus *bus, const char *what) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
diff --git a/src/machine-id-commit/machine-id-commit.c b/src/machine-id-commit/machine-id-commit.c
index c7e4de8889..0f7748e453 100644
--- a/src/machine-id-commit/machine-id-commit.c
+++ b/src/machine-id-commit/machine-id-commit.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
@@ -29,7 +28,7 @@
#include "log.h"
#include "build.h"
-static const char *arg_root = "";
+static const char *arg_root = NULL;
static void help(void) {
printf("%s [OPTIONS...]\n\n"
@@ -99,7 +98,10 @@ int main(int argc, char *argv[]) {
r = parse_argv(argc, argv);
if (r <= 0)
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ goto finish;
- return machine_id_commit(arg_root) < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ r = machine_id_commit(arg_root);
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index 85bbfc4299..20cb60b804 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c
index f5c7d4d880..95d7bca4bf 100644
--- a/src/machine/image-dbus.c
+++ b/src/machine/image-dbus.c
@@ -20,7 +20,6 @@
***/
#include "bus-label.h"
-#include "bus-common-errors.h"
#include "strv.h"
#include "bus-util.h"
#include "machine-image.h"
@@ -29,18 +28,30 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
int bus_image_method_remove(
- sd_bus *bus,
sd_bus_message *message,
void *userdata,
sd_bus_error *error) {
Image *image = userdata;
+ Manager *m = image->userdata;
int r;
- assert(bus);
assert(message);
assert(image);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-images",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = image_remove(image);
if (r < 0)
return r;
@@ -49,16 +60,15 @@ int bus_image_method_remove(
}
int bus_image_method_rename(
- sd_bus *bus,
sd_bus_message *message,
void *userdata,
sd_bus_error *error) {
Image *image = userdata;
+ Manager *m = image->userdata;
const char *new_name;
int r;
- assert(bus);
assert(message);
assert(image);
@@ -69,6 +79,19 @@ int bus_image_method_rename(
if (!image_name_is_valid(new_name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-images",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = image_rename(image, new_name);
if (r < 0)
return r;
@@ -77,16 +100,15 @@ int bus_image_method_rename(
}
int bus_image_method_clone(
- sd_bus *bus,
sd_bus_message *message,
void *userdata,
sd_bus_error *error) {
Image *image = userdata;
+ Manager *m = image->userdata;
const char *new_name;
int r, read_only;
- assert(bus);
assert(message);
assert(image);
@@ -97,6 +119,19 @@ int bus_image_method_clone(
if (!image_name_is_valid(new_name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-images",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = image_clone(image, new_name, read_only);
if (r < 0)
return r;
@@ -105,21 +140,33 @@ int bus_image_method_clone(
}
int bus_image_method_mark_read_only(
- sd_bus *bus,
sd_bus_message *message,
void *userdata,
sd_bus_error *error) {
Image *image = userdata;
+ Manager *m = image->userdata;
int r, read_only;
- assert(bus);
assert(message);
r = sd_bus_message_read(message, "b", &read_only);
if (r < 0)
return r;
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-images",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = image_read_only(image, read_only);
if (r < 0)
return r;
@@ -127,6 +174,42 @@ int bus_image_method_mark_read_only(
return sd_bus_reply_method_return(message, NULL);
}
+int bus_image_method_set_limit(
+ sd_bus_message *message,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Image *image = userdata;
+ Manager *m = image->userdata;
+ uint64_t limit;
+ int r;
+
+ assert(message);
+
+ r = sd_bus_message_read(message, "t", &limit);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-images",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ r = image_set_limit(image, limit);
+ if (r < 0)
+ return r;
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
const sd_bus_vtable image_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
@@ -139,10 +222,11 @@ const sd_bus_vtable image_vtable[] = {
SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, 0),
- SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, 0),
- SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, 0),
- SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, 0),
+ SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
@@ -207,6 +291,8 @@ int image_object_find(sd_bus *bus, const char *path, const char *interface, void
if (r <= 0)
return r;
+ image->userdata = m;
+
r = hashmap_put(m->image_cache, image->name, image);
if (r < 0) {
image_unref(image);
diff --git a/src/machine/image-dbus.h b/src/machine/image-dbus.h
index 1b4364cbea..d56d905c8e 100644
--- a/src/machine/image-dbus.h
+++ b/src/machine/image-dbus.h
@@ -30,7 +30,8 @@ char *image_bus_path(const char *name);
int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-int bus_image_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_image_method_rename(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_image_method_clone(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_image_method_mark_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_image_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_image_method_rename(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_image_method_clone(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_image_method_mark_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_image_method_set_limit(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index b46f0a8dac..0892479a9a 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -21,7 +21,13 @@
#include <errno.h>
#include <string.h>
-#include <arpa/inet.h>
+#include <sys/mount.h>
+
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the XDG
+ * version which is really broken. */
+#include <libgen.h>
+#undef basename
#include "bus-util.h"
#include "bus-label.h"
@@ -32,9 +38,12 @@
#include "in-addr-util.h"
#include "local-addresses.h"
#include "path-util.h"
+#include "mkdir.h"
#include "bus-internal.h"
#include "machine.h"
#include "machine-dbus.h"
+#include "formats-util.h"
+#include "process-util.h"
static int property_get_id(
sd_bus *bus,
@@ -112,14 +121,26 @@ static int property_get_netif(
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
-int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Machine *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.machine1.manage-machines",
+ false,
+ UID_INVALID,
+ &m->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = machine_stop(m);
if (r < 0)
return r;
@@ -127,14 +148,13 @@ int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *use
return sd_bus_reply_method_return(message, NULL);
}
-int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Machine *m = userdata;
const char *swho;
int32_t signo;
KillWho who;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -153,6 +173,19 @@ int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata
if (signo <= 0 || signo >= _NSIG)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
+ r = bus_verify_polkit_async(
+ message,
+ CAP_KILL,
+ "org.freedesktop.machine1.manage-machines",
+ false,
+ UID_INVALID,
+ &m->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
r = machine_kill(m, who, signo);
if (r < 0)
return r;
@@ -160,7 +193,7 @@ int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, NULL);
}
-int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
_cleanup_free_ char *us = NULL, *them = NULL;
@@ -171,7 +204,6 @@ int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void
pid_t child;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -180,26 +212,26 @@ int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void
r = readlink_malloc("/proc/self/ns/net", &us);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
p = procfs_file_alloca(m->leader, "ns/net");
r = readlink_malloc(p, &them);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
if (streq(us, them))
return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
- return sd_bus_error_set_errno(error, -errno);
+ return -errno;
child = fork();
if (child < 0)
- return sd_bus_error_set_errno(error, -errno);
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
if (child == 0) {
_cleanup_free_ struct local_address *addresses = NULL;
@@ -236,11 +268,11 @@ int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
r = sd_bus_message_open_container(reply, 'a', "(iay)");
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
for (;;) {
int family;
@@ -257,56 +289,56 @@ int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void
n = recvmsg(pair[0], &mh, 0);
if (n < 0)
- return sd_bus_error_set_errno(error, -errno);
+ return -errno;
if ((size_t) n < sizeof(family))
break;
r = sd_bus_message_open_container(reply, 'r', "iay");
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
r = sd_bus_message_append(reply, "i", family);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
switch (family) {
case AF_INET:
if (n != sizeof(struct in_addr) + sizeof(family))
- return sd_bus_error_set_errno(error, EIO);
+ return -EIO;
r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
break;
case AF_INET6:
if (n != sizeof(struct in6_addr) + sizeof(family))
- return sd_bus_error_set_errno(error, EIO);
+ return -EIO;
r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
break;
}
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
r = sd_bus_message_close_container(reply);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
}
r = wait_for_terminate(child, &si);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return sd_bus_error_set_errno(error, EIO);
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
r = sd_bus_message_close_container(reply);
if (r < 0)
- return sd_bus_error_set_errno(error, r);
+ return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_close_ int mntns_fd = -1, root_fd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
@@ -318,7 +350,6 @@ int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void
pid_t child;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -334,7 +365,7 @@ int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void
child = fork();
if (child < 0)
- return -errno;
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
if (child == 0) {
_cleanup_close_ int fd = -1;
@@ -373,9 +404,9 @@ int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void
r = wait_for_terminate(child, &si);
if (r < 0)
- return r;
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return -EIO;
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
@@ -395,17 +426,16 @@ int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *pty_name = NULL;
_cleanup_close_ int master = -1;
Machine *m = userdata;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -428,18 +458,22 @@ int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *user
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *pty_name = NULL, *getty = NULL;
_cleanup_bus_unref_ sd_bus *container_bus = NULL;
_cleanup_close_ int master = -1;
Machine *m = userdata;
const char *p;
+ char *address;
int r;
+ assert(message);
+ assert(m);
+
if (m->class != MACHINE_CONTAINER)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
@@ -448,6 +482,7 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us
CAP_SYS_ADMIN,
"org.freedesktop.machine1.login",
false,
+ UID_INVALID,
&m->manager->polkit_registry,
error);
if (r < 0)
@@ -475,13 +510,14 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us
return r;
#ifdef ENABLE_KDBUS
- asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader);
+# define ADDRESS_FMT "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI
#else
- asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT, m->leader);
+# define ADDRESS_FMT "x-machine-unix:pid=%1$" PID_PRI
#endif
- if (!container_bus->address)
- return -ENOMEM;
+ if (asprintf(&address, ADDRESS_FMT, m->leader) < 0)
+ return log_oom();
+ container_bus->address = address;
container_bus->bus_client = true;
container_bus->trusted = false;
container_bus->is_system = true;
@@ -492,7 +528,7 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us
getty = strjoin("container-getty@", p, ".service", NULL);
if (!getty)
- return -ENOMEM;
+ return log_oom();
r = sd_bus_call_method(
container_bus,
@@ -515,7 +551,416 @@ int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *us
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
+}
+
+int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
+ char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
+ bool mount_slave_created = false, mount_slave_mounted = false,
+ mount_tmp_created = false, mount_tmp_mounted = false,
+ mount_outside_created = false, mount_outside_mounted = false;
+ const char *dest, *src;
+ Machine *m = userdata;
+ int read_only, make_directory;
+ pid_t child;
+ siginfo_t si;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ if (m->class != MACHINE_CONTAINER)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
+
+ r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
+ if (r < 0)
+ return r;
+
+ if (!path_is_absolute(src) || !path_is_safe(src))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
+
+ if (isempty(dest))
+ dest = src;
+ else if (!path_is_absolute(dest) || !path_is_safe(dest))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-machines",
+ false,
+ UID_INVALID,
+ &m->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ /* One day, when bind mounting /proc/self/fd/n works across
+ * namespace boundaries we should rework this logic to make
+ * use of it... */
+
+ p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
+ if (laccess(p, F_OK) < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
+
+ /* Our goal is to install a new bind mount into the container,
+ possibly read-only. This is irritatingly complex
+ unfortunately, currently.
+
+ First, we start by creating a private playground in /tmp,
+ that we can mount MS_SLAVE. (Which is necessary, since
+ MS_MOUNT cannot be applied to mounts with MS_SHARED parent
+ mounts.) */
+
+ if (!mkdtemp(mount_slave))
+ return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
+
+ mount_slave_created = true;
+
+ if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
+ goto finish;
+ }
+
+ mount_slave_mounted = true;
+
+ if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
+ goto finish;
+ }
+
+ /* Second, we mount the source directory to a directory inside
+ of our MS_SLAVE playground. */
+ mount_tmp = strjoina(mount_slave, "/mount");
+ if (mkdir(mount_tmp, 0700) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
+ goto finish;
+ }
+
+ mount_tmp_created = true;
+
+ if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
+ goto finish;
+ }
+
+ mount_tmp_mounted = true;
+
+ /* Third, we remount the new bind mount read-only if requested. */
+ if (read_only)
+ if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
+ goto finish;
+ }
+
+ /* Fourth, we move the new bind mount into the propagation
+ * directory. This way it will appear there read-only
+ * right-away. */
+
+ mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
+ if (!mkdtemp(mount_outside)) {
+ r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
+ goto finish;
+ }
+
+ mount_outside_created = true;
+
+ if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
+ goto finish;
+ }
+
+ mount_outside_mounted = true;
+ mount_tmp_mounted = false;
+
+ (void) rmdir(mount_tmp);
+ mount_tmp_created = false;
+
+ (void) umount(mount_slave);
+ mount_slave_mounted = false;
+
+ (void) rmdir(mount_slave);
+ mount_slave_created = false;
+
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+ goto finish;
+ }
+
+ child = fork();
+ if (child < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ goto finish;
+ }
+
+ if (child == 0) {
+ const char *mount_inside;
+ int mntfd;
+ const char *q;
+
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ q = procfs_file_alloca(m->leader, "ns/mnt");
+ mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (mntfd < 0) {
+ r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
+ goto child_fail;
+ }
+
+ if (setns(mntfd, CLONE_NEWNS) < 0) {
+ r = log_error_errno(errno, "Failed to join namespace of leader: %m");
+ goto child_fail;
+ }
+
+ if (make_directory)
+ (void) mkdir_p(dest, 0755);
+
+ /* Fifth, move the mount to the right place inside */
+ mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
+ if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
+ r = log_error_errno(errno, "Failed to mount: %m");
+ goto child_fail;
+ }
+
+ _exit(EXIT_SUCCESS);
+
+ child_fail:
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ _exit(EXIT_FAILURE);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0) {
+ r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ goto finish;
+ }
+ if (si.si_code != CLD_EXITED) {
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ goto finish;
+ }
+ if (si.si_status != EXIT_SUCCESS) {
+
+ if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
+ r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
+ else
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
+ goto finish;
+ }
+
+ r = sd_bus_reply_method_return(message, NULL);
+
+finish:
+ if (mount_outside_mounted)
+ umount(mount_outside);
+ if (mount_outside_created)
+ rmdir(mount_outside);
+
+ if (mount_tmp_mounted)
+ umount(mount_tmp);
+ if (mount_tmp_created)
+ rmdir(mount_tmp);
+
+ if (mount_slave_mounted)
+ umount(mount_slave);
+ if (mount_slave_created)
+ rmdir(mount_slave);
+
+ return r;
+}
+
+static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ MachineOperation *o = userdata;
+ int r;
+
+ assert(o);
+ assert(si);
+
+ o->pid = 0;
+
+ if (si->si_code != CLD_EXITED) {
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ goto fail;
+ }
+
+ if (si->si_status != EXIT_SUCCESS) {
+ if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
+ r = sd_bus_error_set_errnof(&error, r, "%m");
+ else
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
+
+ goto fail;
+ }
+
+ r = sd_bus_reply_method_return(o->message, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ machine_operation_unref(o);
+ return 0;
+
+fail:
+ r = sd_bus_reply_method_error(o->message, &error);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ machine_operation_unref(o);
+ return 0;
+}
+
+int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
+ _cleanup_close_ int hostfd = -1;
+ Machine *m = userdata;
+ MachineOperation *o;
+ bool copy_from;
+ pid_t child;
+ char *t;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ if (m->n_operations >= MACHINE_OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
+
+ if (m->class != MACHINE_CONTAINER)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
+
+ r = sd_bus_message_read(message, "ss", &src, &dest);
+ if (r < 0)
+ return r;
+
+ if (!path_is_absolute(src) || !path_is_safe(src))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
+
+ if (isempty(dest))
+ dest = src;
+ else if (!path_is_absolute(dest) || !path_is_safe(dest))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-machines",
+ false,
+ UID_INVALID,
+ &m->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
+
+ if (copy_from) {
+ container_path = src;
+ host_path = dest;
+ } else {
+ host_path = src;
+ container_path = dest;
+ }
+
+ host_basename = basename(host_path);
+ t = strdupa(host_path);
+ host_dirname = dirname(t);
+
+ container_basename = basename(container_path);
+ t = strdupa(container_path);
+ container_dirname = dirname(t);
+
+ hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
+ if (hostfd < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
+
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+
+ if (child == 0) {
+ int containerfd;
+ const char *q;
+ int mntfd;
+
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ q = procfs_file_alloca(m->leader, "ns/mnt");
+ mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (mntfd < 0) {
+ r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
+ goto child_fail;
+ }
+
+ if (setns(mntfd, CLONE_NEWNS) < 0) {
+ r = log_error_errno(errno, "Failed to join namespace of leader: %m");
+ goto child_fail;
+ }
+
+ containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
+ if (containerfd < 0) {
+ r = log_error_errno(errno, "Failed top open destination directory: %m");
+ goto child_fail;
+ }
+
+ if (copy_from)
+ r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
+ else
+ r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
+
+ hostfd = safe_close(hostfd);
+ containerfd = safe_close(containerfd);
+
+ if (r < 0) {
+ r = log_error_errno(r, "Failed to copy tree: %m");
+ goto child_fail;
+ }
+
+ _exit(EXIT_SUCCESS);
+
+ child_fail:
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ _exit(EXIT_FAILURE);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ /* Copying might take a while, hence install a watch the
+ * child, and return */
+
+ o = new0(MachineOperation, 1);
+ if (!o)
+ return log_oom();
+
+ o->pid = child;
+ o->message = sd_bus_message_ref(message);
+ o->errno_fd = errno_pipe_fd[0];
+ errno_pipe_fd[0] = -1;
+
+ r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
+ if (r < 0) {
+ machine_operation_unref(o);
+ return log_oom();
+ }
+
+ LIST_PREPEND(operations, m->operations, o);
+ m->n_operations++;
+ o->machine = m;
+
+ return 1;
}
const sd_bus_vtable machine_vtable[] = {
@@ -531,12 +976,15 @@ const sd_bus_vtable machine_vtable[] = {
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
- SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
+ SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h
index 601252722d..d309131860 100644
--- a/src/machine/machine-dbus.h
+++ b/src/machine/machine-dbus.h
@@ -22,7 +22,6 @@
***/
#include "sd-bus.h"
-#include "machine.h"
extern const sd_bus_vtable machine_vtable[];
@@ -30,12 +29,14 @@ char *machine_bus_path(Machine *s);
int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
-int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error);
int machine_send_signal(Machine *m, bool new_machine);
int machine_send_create_reply(Machine *m, sd_bus_error *error);
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 223eb0f364..05fc4f849f 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -28,7 +28,6 @@
#include "util.h"
#include "mkdir.h"
#include "hashmap.h"
-#include "strv.h"
#include "fileio.h"
#include "special.h"
#include "unit-name.h"
@@ -36,6 +35,7 @@
#include "bus-error.h"
#include "machine.h"
#include "machine-dbus.h"
+#include "formats-util.h"
Machine* machine_new(Manager *manager, const char *name) {
Machine *m;
@@ -74,20 +74,20 @@ fail:
void machine_free(Machine *m) {
assert(m);
+ while (m->operations)
+ machine_operation_unref(m->operations);
+
if (m->in_gc_queue)
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
- if (m->unit) {
- hashmap_remove(m->manager->machine_units, m->unit);
- free(m->unit);
- }
+ machine_release_unit(m);
free(m->scope_job);
- hashmap_remove(m->manager->machines, m->name);
+ (void) hashmap_remove(m->manager->machines, m->name);
if (m->leader > 0)
- hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
+ (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
sd_bus_message_unref(m->create_message);
@@ -210,9 +210,9 @@ int machine_save(Machine *m) {
/* Create a symlink from the unit name to the machine
* name, so that we can quickly find the machine for
- * each given unit */
+ * each given unit. Ignore error. */
sl = strjoina("/run/systemd/machines/unit:", m->unit);
- symlink(m->name, sl);
+ (void) symlink(m->name, sl);
}
finish:
@@ -501,6 +501,39 @@ int machine_kill(Machine *m, KillWho who, int signo) {
return manager_kill_unit(m->manager, m->unit, signo, NULL);
}
+MachineOperation *machine_operation_unref(MachineOperation *o) {
+ if (!o)
+ return NULL;
+
+ sd_event_source_unref(o->event_source);
+
+ safe_close(o->errno_fd);
+
+ if (o->pid > 1)
+ (void) kill(o->pid, SIGKILL);
+
+ sd_bus_message_unref(o->message);
+
+ if (o->machine) {
+ LIST_REMOVE(operations, o->machine->operations, o);
+ o->machine->n_operations--;
+ }
+
+ free(o);
+ return NULL;
+}
+
+void machine_release_unit(Machine *m) {
+ assert(m);
+
+ if (!m->unit)
+ return;
+
+ (void) hashmap_remove(m->manager->machine_units, m->unit);
+ free(m->unit);
+ m->unit = NULL;
+}
+
static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
[MACHINE_CONTAINER] = "container",
[MACHINE_VM] = "vm"
diff --git a/src/machine/machine.h b/src/machine/machine.h
index 4827ba332f..bbe5217f65 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -22,10 +22,10 @@
***/
typedef struct Machine Machine;
+typedef struct MachineOperation MachineOperation;
typedef enum KillWho KillWho;
#include "list.h"
-#include "util.h"
#include "machined.h"
typedef enum MachineState {
@@ -50,6 +50,17 @@ enum KillWho {
_KILL_WHO_INVALID = -1
};
+#define MACHINE_OPERATIONS_MAX 64
+
+struct MachineOperation {
+ Machine *machine;
+ pid_t pid;
+ sd_bus_message *message;
+ int errno_fd;
+ sd_event_source *event_source;
+ LIST_FIELDS(MachineOperation, operations);
+};
+
struct Machine {
Manager *manager;
@@ -79,6 +90,9 @@ struct Machine {
unsigned n_netif;
LIST_FIELDS(Machine, gc_queue);
+
+ MachineOperation *operations;
+ unsigned n_operations;
};
Machine* machine_new(Manager *manager, const char *name);
@@ -91,8 +105,12 @@ int machine_save(Machine *m);
int machine_load(Machine *m);
int machine_kill(Machine *m, KillWho who, int signo);
+void machine_release_unit(Machine *m);
+
MachineState machine_get_state(Machine *u);
+MachineOperation *machine_operation_unref(MachineOperation *o);
+
const char* machine_class_to_string(MachineClass t) _const_;
MachineClass machine_class_from_string(const char *s) _pure_;
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 9f8c68b184..c86c36c2de 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -24,7 +24,6 @@
#include <errno.h>
#include <string.h>
#include <getopt.h>
-#include <pwd.h>
#include <locale.h>
#include <fcntl.h>
#include <netinet/in.h>
@@ -32,12 +31,6 @@
#include <net/if.h>
#include <sys/mount.h>
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the XDG
- * version which is really broken. */
-#include <libgen.h>
-#undef basename
-
#include "sd-bus.h"
#include "log.h"
#include "util.h"
@@ -59,6 +52,9 @@
#include "copy.h"
#include "verbs.h"
#include "import-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -78,6 +74,7 @@ static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_force = false;
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
static const char* arg_dkr_index_url = NULL;
+static const char* arg_format = NULL;
static void pager_open_if_enabled(void) {
@@ -810,7 +807,7 @@ static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
printf("\t Limit: %s\n", s3);
}
-static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
+static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
@@ -829,7 +826,6 @@ static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool
ImageStatusInfo info = {};
int r;
- assert(verb);
assert(bus);
assert(path);
assert(new_line);
@@ -855,6 +851,59 @@ static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool
return r;
}
+typedef struct PoolStatusInfo {
+ char *path;
+ uint64_t usage;
+ uint64_t limit;
+} PoolStatusInfo;
+
+static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
+ char bs[FORMAT_BYTES_MAX], *s;
+
+ if (i->path)
+ printf("\t Path: %s\n", i->path);
+
+ s = format_bytes(bs, sizeof(bs), i->usage);
+ if (s)
+ printf("\t Usage: %s\n", s);
+
+ s = format_bytes(bs, sizeof(bs), i->limit);
+ if (s)
+ printf("\t Limit: %s\n", s);
+}
+
+static int show_pool_info(sd_bus *bus) {
+
+ static const struct bus_properties_map map[] = {
+ { "PoolPath", "s", NULL, offsetof(PoolStatusInfo, path) },
+ { "PoolUsage", "t", NULL, offsetof(PoolStatusInfo, usage) },
+ { "PoolLimit", "t", NULL, offsetof(PoolStatusInfo, limit) },
+ {}
+ };
+
+ PoolStatusInfo info = {
+ .usage = (uint64_t) -1,
+ .limit = (uint64_t) -1,
+ };
+ int r;
+
+ assert(bus);
+
+ r = bus_map_all_properties(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ map,
+ &info);
+ if (r < 0)
+ return log_error_errno(r, "Could not get properties: %m");
+
+ print_pool_status_info(bus, &info);
+
+ free(info.path);
+ return 0;
+}
+
+
static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
int r;
@@ -888,11 +937,15 @@ static int show_image(int argc, char *argv[], void *userdata) {
pager_open_if_enabled();
- if (properties && argc <= 1) {
+ if (argc <= 1) {
/* If no argument is specified, inspect the manager
* itself */
- r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
+
+ if (properties)
+ r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
+ else
+ r = show_pool_info(bus);
if (r < 0)
return r;
}
@@ -901,14 +954,14 @@ static int show_image(int argc, char *argv[], void *userdata) {
const char *path = NULL;
r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetImage",
- &error,
- &reply,
- "s", argv[i]);
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "GetImage",
+ &error,
+ &reply,
+ "s", argv[i]);
if (r < 0) {
log_error("Could not get path to image: %s", bus_error_message(&error, -r));
return r;
@@ -921,7 +974,7 @@ static int show_image(int argc, char *argv[], void *userdata) {
if (properties)
r = show_image_properties(bus, path, &new_line);
else
- r = show_image_info(argv[0], bus, path, &new_line);
+ r = show_image_info(bus, path, &new_line);
}
return r;
@@ -930,7 +983,7 @@ static int show_image(int argc, char *argv[], void *userdata) {
static int kill_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
- int i;
+ int r, i;
assert(bus);
@@ -940,8 +993,6 @@ static int kill_machine(int argc, char *argv[], void *userdata) {
arg_kill_who = "all";
for (i = 1; i < argc; i++) {
- int r;
-
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
@@ -977,15 +1028,13 @@ static int poweroff_machine(int argc, char *argv[], void *userdata) {
static int terminate_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
- int i;
+ int r, i;
assert(bus);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
- int r;
-
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
@@ -1004,333 +1053,73 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
return 0;
}
-static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) {
+static int copy_files(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL;
- const char *object;
- uint32_t leader;
+ sd_bus *bus = userdata;
+ bool copy_from;
int r;
assert(bus);
- assert(name);
- assert(ret);
+
+ polkit_agent_open_if_enabled();
+
+ copy_from = streq(argv[0], "copy-from");
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "GetMachine",
+ copy_from ? "CopyFromMachine" : "CopyToMachine",
&error,
- &reply,
- "s", name);
+ NULL,
+ "sss",
+ argv[1],
+ argv[2],
+ argv[3]);
if (r < 0) {
- log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
- return r;
- }
-
- r = sd_bus_message_read(reply, "o", &object);
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_get_property(
- bus,
- "org.freedesktop.machine1",
- object,
- "org.freedesktop.machine1.Machine",
- "Leader",
- &error,
- &reply2,
- "u");
- if (r < 0)
- return log_error_errno(r, "Failed to retrieve PID of leader: %m");
-
- r = sd_bus_message_read(reply2, "u", &leader);
- if (r < 0)
- return bus_log_parse_error(r);
-
- *ret = leader;
- return 0;
-}
-
-static int copy_files(int argc, char *argv[], void *userdata) {
- char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
- _cleanup_close_ int hostfd = -1;
- sd_bus *bus = userdata;
- pid_t child, leader;
- bool copy_from;
- siginfo_t si;
- int r;
-
- assert(bus);
-
- copy_from = streq(argv[0], "copy-from");
- dest = argv[3] ?: argv[2];
- host_path = strdupa(copy_from ? dest : argv[2]);
- container_path = strdupa(copy_from ? argv[2] : dest);
-
- if (!path_is_absolute(container_path)) {
- log_error("Container path not absolute.");
- return -EINVAL;
- }
-
- t = strdupa(host_path);
- host_basename = basename(t);
- host_dirname = dirname(host_path);
-
- t = strdupa(container_path);
- container_basename = basename(t);
- container_dirname = dirname(container_path);
-
- r = machine_get_leader(bus, argv[1], &leader);
- if (r < 0)
+ log_error("Failed to copy: %s", bus_error_message(&error, -r));
return r;
-
- hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
- if (r < 0)
- return log_error_errno(errno, "Failed to open source directory: %m");
-
- child = fork();
- if (child < 0)
- return log_error_errno(errno, "Failed to fork(): %m");
-
- if (child == 0) {
- int containerfd;
- const char *q;
- int mntfd;
-
- q = procfs_file_alloca(leader, "ns/mnt");
- mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (mntfd < 0) {
- log_error_errno(errno, "Failed to open mount namespace of leader: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (setns(mntfd, CLONE_NEWNS) < 0) {
- log_error_errno(errno, "Failed to join namespace of leader: %m");
- _exit(EXIT_FAILURE);
- }
-
- containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
- if (containerfd < 0) {
- log_error_errno(errno, "Failed top open destination directory: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (copy_from)
- r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
- else
- r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
- if (r < 0) {
- log_error_errno(errno, "Failed to copy tree: %m");
- _exit(EXIT_FAILURE);
- }
-
- _exit(EXIT_SUCCESS);
- }
-
- r = wait_for_terminate(child, &si);
- if (r < 0)
- return log_error_errno(r, "Failed to wait for client: %m");
- if (si.si_code != CLD_EXITED) {
- log_error("Client died abnormally.");
- return -EIO;
}
- if (si.si_status != EXIT_SUCCESS)
- return -EIO;
return 0;
}
static int bind_mount(int argc, char *argv[], void *userdata) {
- char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
- pid_t child, leader;
- const char *dest;
- siginfo_t si;
- bool mount_slave_created = false, mount_slave_mounted = false,
- mount_tmp_created = false, mount_tmp_mounted = false,
- mount_outside_created = false, mount_outside_mounted = false;
int r;
assert(bus);
- /* One day, when bind mounting /proc/self/fd/n works across
- * namespace boundaries we should rework this logic to make
- * use of it... */
-
- dest = argv[3] ?: argv[2];
- if (!path_is_absolute(dest)) {
- log_error("Destination path not absolute.");
- return -EINVAL;
- }
-
- p = strjoina("/run/systemd/nspawn/propagate/", argv[1], "/");
- if (access(p, F_OK) < 0) {
- log_error("Container does not allow propagation of mount points.");
- return -ENOTSUP;
- }
-
- r = machine_get_leader(bus, argv[1], &leader);
- if (r < 0)
- return r;
-
- /* Our goal is to install a new bind mount into the container,
- possibly read-only. This is irritatingly complex
- unfortunately, currently.
-
- First, we start by creating a private playground in /tmp,
- that we can mount MS_SLAVE. (Which is necessary, since
- MS_MOUNT cannot be applied to mounts with MS_SHARED parent
- mounts.) */
-
- if (!mkdtemp(mount_slave))
- return log_error_errno(errno, "Failed to create playground: %m");
-
- mount_slave_created = true;
-
- if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
- r = log_error_errno(errno, "Failed to make bind mount: %m");
- goto finish;
- }
-
- mount_slave_mounted = true;
-
- if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
- r = log_error_errno(errno, "Failed to remount slave: %m");
- goto finish;
- }
-
- /* Second, we mount the source directory to a directory inside
- of our MS_SLAVE playground. */
- mount_tmp = strjoina(mount_slave, "/mount");
- if (mkdir(mount_tmp, 0700) < 0) {
- r = log_error_errno(errno, "Failed to create temporary mount: %m");
- goto finish;
- }
-
- mount_tmp_created = true;
-
- if (mount(argv[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
- r = log_error_errno(errno, "Failed to overmount: %m");
- goto finish;
- }
-
- mount_tmp_mounted = true;
-
- /* Third, we remount the new bind mount read-only if requested. */
- if (arg_read_only)
- if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
- r = log_error_errno(errno, "Failed to mark read-only: %m");
- goto finish;
- }
-
- /* Fourth, we move the new bind mount into the propagation
- * directory. This way it will appear there read-only
- * right-away. */
-
- mount_outside = strjoina("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
- if (!mkdtemp(mount_outside)) {
- r = log_error_errno(errno, "Cannot create propagation directory: %m");
- goto finish;
- }
-
- mount_outside_created = true;
-
- if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
- r = log_error_errno(errno, "Failed to move: %m");
- goto finish;
- }
-
- mount_outside_mounted = true;
- mount_tmp_mounted = false;
-
- (void) rmdir(mount_tmp);
- mount_tmp_created = false;
-
- (void) umount(mount_slave);
- mount_slave_mounted = false;
-
- (void) rmdir(mount_slave);
- mount_slave_created = false;
-
- child = fork();
- if (child < 0) {
- r = log_error_errno(errno, "Failed to fork(): %m");
- goto finish;
- }
-
- if (child == 0) {
- const char *mount_inside;
- int mntfd;
- const char *q;
-
- q = procfs_file_alloca(leader, "ns/mnt");
- mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (mntfd < 0) {
- log_error_errno(errno, "Failed to open mount namespace of leader: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (setns(mntfd, CLONE_NEWNS) < 0) {
- log_error_errno(errno, "Failed to join namespace of leader: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (arg_mkdir)
- mkdir_p(dest, 0755);
-
- /* Fifth, move the mount to the right place inside */
- mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
- if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
- log_error_errno(errno, "Failed to mount: %m");
- _exit(EXIT_FAILURE);
- }
-
- _exit(EXIT_SUCCESS);
- }
+ polkit_agent_open_if_enabled();
- r = wait_for_terminate(child, &si);
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "BindMountMachine",
+ &error,
+ NULL,
+ "sssbb",
+ argv[1],
+ argv[2],
+ argv[3],
+ arg_read_only,
+ arg_mkdir);
if (r < 0) {
- log_error_errno(r, "Failed to wait for client: %m");
- goto finish;
- }
- if (si.si_code != CLD_EXITED) {
- log_error("Client died abnormally.");
- r = -EIO;
- goto finish;
- }
- if (si.si_status != EXIT_SUCCESS) {
- r = -EIO;
- goto finish;
+ log_error("Failed to bind mount: %s", bus_error_message(&error, -r));
+ return r;
}
- r = 0;
-
-finish:
- if (mount_outside_mounted)
- umount(mount_outside);
- if (mount_outside_created)
- rmdir(mount_outside);
-
- if (mount_tmp_mounted)
- umount(mount_tmp);
- if (mount_tmp_created)
- umount(mount_tmp);
-
- if (mount_slave_mounted)
- umount(mount_slave);
- if (mount_slave_created)
- umount(mount_slave);
-
- return r;
+ return 0;
}
-static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
PTYForward ** forward = (PTYForward**) userdata;
int r;
- assert(bus);
assert(m);
assert(forward);
@@ -1347,13 +1136,13 @@ static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd
}
/* On error, or when the forwarder is not initialized yet, quit immediately */
- sd_event_exit(sd_bus_get_event(bus), EXIT_FAILURE);
+ sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
return 0;
}
static int login_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
@@ -1368,7 +1157,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
if (arg_transport != BUS_TRANSPORT_LOCAL &&
arg_transport != BUS_TRANSPORT_MACHINE) {
log_error("Login only supported on local machines.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
polkit_agent_open_if_enabled();
@@ -1394,24 +1183,15 @@ static int login_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to add machine removal match: %m");
- r = sd_bus_message_new_method_call(bus,
- &m,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "OpenMachineLogin");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "s", argv[1]);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "OpenMachineLogin",
+ &error,
+ &reply,
+ "s", argv[1]);
if (r < 0) {
log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
return r;
@@ -1428,7 +1208,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
- r = pty_forward_new(event, master, true, &forward);
+ r = pty_forward_new(event, master, true, false, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
@@ -1561,6 +1341,29 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
return 0;
}
+static int make_service_name(const char *name, char **ret) {
+ _cleanup_free_ char *e = NULL;
+ int r;
+
+ assert(name);
+ assert(ret);
+
+ if (!machine_name_is_valid(name)) {
+ log_error("Invalid machine name %s.", name);
+ return -EINVAL;
+ }
+
+ e = unit_name_escape(name);
+ if (!e)
+ return log_oom();
+
+ r = unit_name_build("systemd-nspawn", e, ".service", ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to build unit name: %m");
+
+ return 0;
+}
+
static int start_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
@@ -1576,42 +1379,23 @@ static int start_machine(int argc, char *argv[], void *userdata) {
return log_oom();
for (i = 1; i < argc; i++) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
- _cleanup_free_ char *e = NULL, *unit = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_free_ char *unit = NULL;
const char *object;
- if (!machine_name_is_valid(argv[i])) {
- log_error("Invalid machine name %s.", argv[i]);
- return -EINVAL;
- }
-
- e = unit_name_escape(argv[i]);
- if (!e)
- return log_oom();
-
- unit = unit_name_build("systemd-nspawn", e, ".service");
- if (!unit)
- return log_oom();
+ r = make_service_name(argv[i], &unit);
+ if (r < 0)
+ return r;
- r = sd_bus_message_new_method_call(
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "StartUnit");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "ss", unit, "fail");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
+ "StartUnit",
+ &error,
+ &reply,
+ "ss", unit, "fail");
if (r < 0) {
log_error("Failed to start unit: %s", bus_error_message(&error, -r));
return r;
@@ -1657,29 +1441,16 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
r = sd_bus_message_open_container(m, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
for (i = 1; i < argc; i++) {
- _cleanup_free_ char *e = NULL, *unit = NULL;
-
- if (!machine_name_is_valid(argv[i])) {
- log_error("Invalid machine name %s.", argv[i]);
- return -EINVAL;
- }
-
- e = unit_name_escape(argv[i]);
- if (!e)
- return log_oom();
+ _cleanup_free_ char *unit = NULL;
- unit = unit_name_build("systemd-nspawn", e, ".service");
- if (!unit)
- return log_oom();
+ r = make_service_name(argv[i], &unit);
+ if (r < 0)
+ return r;
r = sd_bus_message_append(m, "s", unit);
if (r < 0)
@@ -1709,27 +1480,19 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
return bus_log_parse_error(r);
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
- m = sd_bus_message_unref(m);
-
- r = sd_bus_message_new_method_call(
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "Reload");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, NULL);
+ "Reload",
+ &error,
+ NULL,
+ NULL);
if (r < 0) {
log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
return r;
@@ -1738,12 +1501,11 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
return 0;
}
-static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char **our_path = userdata, *line;
unsigned priority;
int r;
- assert(bus);
assert(m);
assert(our_path);
@@ -1763,12 +1525,11 @@ static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
return 0;
}
-static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int match_transfer_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char **our_path = userdata, *path, *result;
uint32_t id;
int r;
- assert(bus);
assert(m);
assert(our_path);
@@ -1781,7 +1542,7 @@ static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata
if (!streq_ptr(*our_path, path))
return 0;
- sd_event_exit(sd_bus_get_event(bus), !streq_ptr(result, "done"));
+ sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), !streq_ptr(result, "done"));
return 0;
}
@@ -1796,7 +1557,7 @@ static int transfer_signal_handler(sd_event_source *s, const struct signalfd_sig
return 0;
}
-static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
+static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
_cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
@@ -1818,10 +1579,6 @@ static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
r = sd_bus_add_match(
bus,
&slot_job_removed,
@@ -1847,7 +1604,7 @@ static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
- log_error("Failed pull image: %s", bus_error_message(&error, -r));
+ log_error("Failed transfer image: %s", bus_error_message(&error, -r));
return r;
}
@@ -1870,6 +1627,255 @@ static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
return -r;
}
+static int import_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_free_ char *ll = NULL;
+ _cleanup_close_ int fd = -1;
+ const char *local = NULL, *path = NULL;
+ sd_bus *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ if (argc >= 2)
+ path = argv[1];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ if (argc >= 3)
+ local = argv[2];
+ else if (path)
+ local = basename(path);
+ if (isempty(local) || streq(local, "-"))
+ local = NULL;
+
+ if (!local) {
+ log_error("Need either path or local name.");
+ return -EINVAL;
+ }
+
+ r = tar_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!machine_name_is_valid(local)) {
+ log_error("Local name %s is not a suitable machine name.", local);
+ return -EINVAL;
+ }
+
+ if (path) {
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.import1",
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ "ImportTar");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsbb",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ arg_force,
+ arg_read_only);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int import_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_free_ char *ll = NULL;
+ _cleanup_close_ int fd = -1;
+ const char *local = NULL, *path = NULL;
+ sd_bus *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ if (argc >= 2)
+ path = argv[1];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ if (argc >= 3)
+ local = argv[2];
+ else if (path)
+ local = basename(path);
+ if (isempty(local) || streq(local, "-"))
+ local = NULL;
+
+ if (!local) {
+ log_error("Need either path or local name.");
+ return -EINVAL;
+ }
+
+ r = raw_strip_suffixes(local, &ll);
+ if (r < 0)
+ return log_oom();
+
+ local = ll;
+
+ if (!machine_name_is_valid(local)) {
+ log_error("Local name %s is not a suitable machine name.", local);
+ return -EINVAL;
+ }
+
+ if (path) {
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.import1",
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ "ImportRaw");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "hsbb",
+ fd >= 0 ? fd : STDIN_FILENO,
+ local,
+ arg_force,
+ arg_read_only);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static void determine_compression_from_filename(const char *p) {
+ if (arg_format)
+ return;
+
+ if (!p)
+ return;
+
+ if (endswith(p, ".xz"))
+ arg_format = "xz";
+ else if (endswith(p, ".gz"))
+ arg_format = "gzip";
+ else if (endswith(p, ".bz2"))
+ arg_format = "bzip2";
+}
+
+static int export_tar(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_close_ int fd = -1;
+ const char *local = NULL, *path = NULL;
+ sd_bus *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ local = argv[1];
+ if (!machine_name_is_valid(local)) {
+ log_error("Machine name %s is not valid.", local);
+ return -EINVAL;
+ }
+
+ if (argc >= 3)
+ path = argv[2];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ if (path) {
+ determine_compression_from_filename(path);
+
+ fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.import1",
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ "ExportTar");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "shs",
+ local,
+ fd >= 0 ? fd : STDOUT_FILENO,
+ arg_format);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
+static int export_raw(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_close_ int fd = -1;
+ const char *local = NULL, *path = NULL;
+ sd_bus *bus = userdata;
+ int r;
+
+ assert(bus);
+
+ local = argv[1];
+ if (!machine_name_is_valid(local)) {
+ log_error("Machine name %s is not valid.", local);
+ return -EINVAL;
+ }
+
+ if (argc >= 3)
+ path = argv[2];
+ if (isempty(path) || streq(path, "-"))
+ path = NULL;
+
+ if (path) {
+ determine_compression_from_filename(path);
+
+ fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", path);
+ }
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.import1",
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ "ExportRaw");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
+ "shs",
+ local,
+ fd >= 0 ? fd : STDOUT_FILENO,
+ arg_format);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return transfer_image_common(bus, m);
+}
+
static int pull_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *l = NULL, *ll = NULL;
@@ -1901,7 +1907,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
if (local) {
r = tar_strip_suffixes(local, &ll);
if (r < 0)
- return log_error_errno(r, "Failed to strip tar suffixes: %m");
+ return log_oom();
local = ll;
@@ -1931,7 +1937,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_create_error(r);
- return pull_image_common(bus, m);
+ return transfer_image_common(bus, m);
}
static int pull_raw(int argc, char *argv[], void *userdata) {
@@ -1965,7 +1971,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
if (local) {
r = raw_strip_suffixes(local, &ll);
if (r < 0)
- return log_error_errno(r, "Failed to strip tar suffixes: %m");
+ return log_oom();
local = ll;
@@ -1995,7 +2001,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_create_error(r);
- return pull_image_common(bus, m);
+ return transfer_image_common(bus, m);
}
static int pull_dkr(int argc, char *argv[], void *userdata) {
@@ -2067,7 +2073,7 @@ static int pull_dkr(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_create_error(r);
- return pull_image_common(bus, m);
+ return transfer_image_common(bus, m);
}
typedef struct TransferInfo {
@@ -2210,6 +2216,56 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) {
return 0;
}
+static int set_limit(int argc, char *argv[], void *userdata) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus = userdata;
+ uint64_t limit;
+ int r;
+
+ if (streq(argv[argc-1], "-"))
+ limit = (uint64_t) -1;
+ else {
+ off_t off;
+
+ r = parse_size(argv[argc-1], 1024, &off);
+ if (r < 0)
+ return log_error("Failed to parse size: %s", argv[argc-1]);
+
+ limit = (uint64_t) off;
+ }
+
+ if (argc > 2)
+ /* With two arguments changes the quota limit of the
+ * specified image */
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "SetImageLimit",
+ &error,
+ NULL,
+ "st", argv[1], limit);
+ else
+ /* With one argument changes the pool quota limit */
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "SetPoolLimit",
+ &error,
+ NULL,
+ "t", limit);
+
+ if (r < 0) {
+ log_error("Could not set limit: %s", bus_error_message(&error, -r));
+ return r;
+ }
+
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -2261,11 +2317,16 @@ static int help(int argc, char *argv[], void *userdata) {
" clone NAME NAME Clone an image\n"
" rename NAME NAME Rename an image\n"
" read-only NAME [BOOL] Mark or unmark image read-only\n"
- " remove NAME... Remove an image\n\n"
+ " remove NAME... Remove an image\n"
+ " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n"
"Image Transfer Commands:\n"
" pull-tar URL [NAME] Download a TAR container image\n"
" pull-raw URL [NAME] Download a RAW container or VM image\n"
" pull-dkr REMOTE [NAME] Download a DKR container image\n"
+ " import-tar FILE [NAME] Import a local TAR container image\n"
+ " import-raw FILE [NAME] Import a local RAW container or VM image\n"
+ " export-tar NAME [FILE] Export a TAR container image locally\n"
+ " export-raw NAME [FILE] Export a RAW container or VM image locally\n"
" list-transfers Show list of downloads in progress\n"
" cancel-transfer Cancel a download\n"
, program_invocation_short_name);
@@ -2286,6 +2347,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERIFY,
ARG_FORCE,
ARG_DKR_INDEX_URL,
+ ARG_FORMAT,
};
static const struct option options[] = {
@@ -2309,6 +2371,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "verify", required_argument, NULL, ARG_VERIFY },
{ "force", no_argument, NULL, ARG_FORCE },
{ "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
+ { "format", required_argument, NULL, ARG_FORMAT },
{}
};
@@ -2430,6 +2493,15 @@ static int parse_argv(int argc, char *argv[]) {
arg_dkr_index_url = optarg;
break;
+ case ARG_FORMAT:
+ if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2")) {
+ log_error("Unknown format: %s", optarg);
+ return -EINVAL;
+ }
+
+ arg_format = optarg;
+ break;
+
case '?':
return -EINVAL;
@@ -2447,7 +2519,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
{ "list-images", VERB_ANY, 1, 0, list_images },
{ "status", 2, VERB_ANY, 0, show_machine },
- { "image-status", 2, VERB_ANY, 0, show_image },
+ { "image-status", VERB_ANY, VERB_ANY, 0, show_image },
{ "show", VERB_ANY, VERB_ANY, 0, show_machine },
{ "show-image", VERB_ANY, VERB_ANY, 0, show_image },
{ "terminate", 2, VERB_ANY, 0, terminate_machine },
@@ -2465,11 +2537,16 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "start", 2, VERB_ANY, 0, start_machine },
{ "enable", 2, VERB_ANY, 0, enable_machine },
{ "disable", 2, VERB_ANY, 0, enable_machine },
+ { "import-tar", 2, 3, 0, import_tar },
+ { "import-raw", 2, 3, 0, import_raw },
+ { "export-tar", 2, 3, 0, export_tar },
+ { "export-raw", 2, 3, 0, export_raw },
{ "pull-tar", 2, 3, 0, pull_tar },
{ "pull-raw", 2, 3, 0, pull_raw },
{ "pull-dkr", 2, 3, 0, pull_dkr },
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
+ { "set-limit", 2, 3, 0, set_limit },
{}
};
@@ -2494,6 +2571,8 @@ int main(int argc, char*argv[]) {
goto finish;
}
+ sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
+
r = machinectl_main(argc, argv, bus);
finish:
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index ac19695c92..0e971a6789 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -22,35 +22,116 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <pwd.h>
#include "sd-id128.h"
-#include "sd-messages.h"
#include "strv.h"
-#include "mkdir.h"
#include "path-util.h"
-#include "special.h"
-#include "fileio-label.h"
-#include "label.h"
-#include "utf8.h"
#include "unit-name.h"
#include "bus-util.h"
#include "bus-common-errors.h"
-#include "time-util.h"
#include "cgroup-util.h"
+#include "btrfs-util.h"
#include "machine-image.h"
+#include "machine-pool.h"
#include "image-dbus.h"
#include "machined.h"
#include "machine-dbus.h"
+#include "formats-util.h"
-static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int property_get_pool_path(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ assert(bus);
+ assert(reply);
+
+ return sd_bus_message_append(reply, "s", "/var/lib/machines");
+}
+
+static int property_get_pool_usage(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ _cleanup_close_ int fd = -1;
+ uint64_t usage = (uint64_t) -1;
+ struct stat st;
+
+ assert(bus);
+ assert(reply);
+
+ /* We try to read the quota info from /var/lib/machines, as
+ * well as the usage of the loopback file
+ * /var/lib/machines.raw, and pick the larger value. */
+
+ fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (fd >= 0) {
+ BtrfsQuotaInfo q;
+
+ if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
+ usage = q.referenced;
+ }
+
+ if (stat("/var/lib/machines.raw", &st) >= 0) {
+ if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
+ usage = st.st_blocks * 512ULL;
+ }
+
+ return sd_bus_message_append(reply, "t", usage);
+}
+
+static int property_get_pool_limit(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ _cleanup_close_ int fd = -1;
+ uint64_t size = (uint64_t) -1;
+ struct stat st;
+
+ assert(bus);
+ assert(reply);
+
+ /* We try to read the quota limit from /var/lib/machines, as
+ * well as the size of the loopback file
+ * /var/lib/machines.raw, and pick the smaller value. */
+
+ fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (fd >= 0) {
+ BtrfsQuotaInfo q;
+
+ if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
+ size = q.referenced_max;
+ }
+
+ if (stat("/var/lib/machines.raw", &st) >= 0) {
+ if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
+ size = st.st_size;
+ }
+
+ return sd_bus_message_append(reply, "t", size);
+}
+
+static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -69,13 +150,12 @@ static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userda
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -96,14 +176,13 @@ static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
Machine *machine = NULL;
pid_t pid;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -138,14 +217,13 @@ static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void
return sd_bus_reply_method_return(message, "o", p);
}
-static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
Machine *machine;
Iterator i;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -177,7 +255,7 @@ static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *user
if (r < 0)
return sd_bus_error_set_errno(error, r);
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
@@ -305,11 +383,14 @@ fail:
return r;
}
-static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
+static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
Machine *m = NULL;
int r;
+ assert(message);
+ assert(manager);
+
r = method_create_or_register_machine(manager, message, read_network, &m, error);
if (r < 0)
return r;
@@ -330,20 +411,23 @@ fail:
return r;
}
-static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_create_machine_internal(bus, message, true, userdata, error);
+static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_create_machine_internal(message, true, userdata, error);
}
-static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_create_machine_internal(bus, message, false, userdata, error);
+static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_create_machine_internal(message, false, userdata, error);
}
-static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
+static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
Manager *manager = userdata;
_cleanup_free_ char *p = NULL;
Machine *m = NULL;
int r;
+ assert(message);
+ assert(manager);
+
r = method_create_or_register_machine(manager, message, read_network, &m, error);
if (r < 0)
return r;
@@ -371,21 +455,20 @@ fail:
return r;
}
-static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_register_machine_internal(bus, message, true, userdata, error);
+static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_register_machine_internal(message, true, userdata, error);
}
-static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_register_machine_internal(bus, message, false, userdata, error);
+static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return method_register_machine_internal(message, false, userdata, error);
}
-static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -397,16 +480,15 @@ static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *
if (!machine)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
- return bus_machine_method_terminate(bus, message, machine, error);
+ return bus_machine_method_terminate(message, machine, error);
}
-static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -418,16 +500,15 @@ static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userd
if (!machine)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
- return bus_machine_method_kill(bus, message, machine, error);
+ return bus_machine_method_kill(message, machine, error);
}
-static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -439,16 +520,15 @@ static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, vo
if (!machine)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
- return bus_machine_method_get_addresses(bus, message, machine, error);
+ return bus_machine_method_get_addresses(message, machine, error);
}
-static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -460,10 +540,10 @@ static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, v
if (!machine)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
- return bus_machine_method_get_os_release(bus, message, machine, error);
+ return bus_machine_method_get_os_release(message, machine, error);
}
-static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_(image_hashmap_freep) Hashmap *images = NULL;
Manager *m = userdata;
@@ -471,7 +551,6 @@ static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userda
Iterator i;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -514,16 +593,15 @@ static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userda
if (r < 0)
return r;
- return sd_bus_send(bus, reply, NULL);
+ return sd_bus_send(NULL, reply, NULL);
}
-static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -535,16 +613,55 @@ static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *u
if (!machine)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
- return bus_machine_method_open_pty(bus, message, machine, error);
+ return bus_machine_method_open_pty(message, machine, error);
}
-static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Machine *machine;
+ const char *name;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ return bus_machine_method_open_login(message, machine, error);
+}
+
+static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Machine *machine;
+ const char *name;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ return bus_machine_method_bind_mount(message, machine, error);
+}
+
+static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
const char *name;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -556,15 +673,14 @@ static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void
if (!machine)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
- return bus_machine_method_open_login(bus, message, machine, error);
+ return bus_machine_method_copy(message, machine, error);
}
-static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(image_unrefp) Image* i = NULL;
const char *name;
int r;
- assert(bus);
assert(message);
r = sd_bus_message_read(message, "s", &name);
@@ -580,15 +696,15 @@ static int method_remove_image(sd_bus *bus, sd_bus_message *message, void *userd
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
- return bus_image_method_remove(bus, message, i, error);
+ i->userdata = userdata;
+ return bus_image_method_remove(message, i, error);
}
-static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(image_unrefp) Image* i = NULL;
const char *old_name;
int r;
- assert(bus);
assert(message);
r = sd_bus_message_read(message, "s", &old_name);
@@ -604,15 +720,17 @@ static int method_rename_image(sd_bus *bus, sd_bus_message *message, void *userd
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
- return bus_image_method_rename(bus, message, i, error);
+ i->userdata = userdata;
+ return bus_image_method_rename(message, i, error);
}
-static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(image_unrefp) Image *i = NULL;
const char *old_name;
int r;
- assert(bus);
+ assert(message);
+
r = sd_bus_message_read(message, "s", &old_name);
if (r < 0)
return r;
@@ -626,15 +744,17 @@ static int method_clone_image(sd_bus *bus, sd_bus_message *message, void *userda
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
- return bus_image_method_clone(bus, message, i, error);
+ i->userdata = userdata;
+ return bus_image_method_clone(message, i, error);
}
-static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(image_unrefp) Image *i = NULL;
const char *name;
int r;
- assert(bus);
+ assert(message);
+
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
@@ -648,11 +768,83 @@ static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, voi
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
- return bus_image_method_mark_read_only(bus, message, i, error);
+ i->userdata = userdata;
+ return bus_image_method_mark_read_only(message, i, error);
+}
+
+static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ uint64_t limit;
+ int r;
+
+ assert(message);
+
+ r = sd_bus_message_read(message, "t", &limit);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-machines",
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ /* Set up the machine directory if necessary */
+ r = setup_machine_directory(limit, error);
+ if (r < 0)
+ return r;
+
+ r = btrfs_resize_loopback("/var/lib/machines", limit, false);
+ if (r == -ENOTTY)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
+ if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
+ return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
+
+ r = btrfs_quota_limit("/var/lib/machines", limit);
+ if (r == -ENOTTY)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(image_unrefp) Image *i = NULL;
+ const char *name;
+ int r;
+
+ assert(message);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ if (!image_name_is_valid(name))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
+
+ r = image_find(name, &i);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
+
+ i->userdata = userdata;
+ return bus_image_method_set_limit(message, i, error);
}
const sd_bus_vtable manager_vtable[] = {
SD_BUS_VTABLE_START(0),
+ SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
+ SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
+ SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -662,29 +854,33 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
- SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
- SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
+ SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, 0),
- SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, 0),
- SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, 0),
- SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, 0),
+ SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("MachineNew", "so", 0),
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
SD_BUS_VTABLE_END
};
-int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path, *result, *unit;
Manager *m = userdata;
Machine *machine;
uint32_t id;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -720,14 +916,13 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b
return 0;
}
-int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *unit = NULL;
+ const char *path, *interface;
Manager *m = userdata;
Machine *machine;
- const char *path;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -738,46 +933,82 @@ int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdat
r = unit_name_from_dbus_path(path, &unit);
if (r == -EINVAL) /* not for a unit */
return 0;
- if (r < 0)
- return r;
+ if (r < 0){
+ log_oom();
+ return 0;
+ }
machine = hashmap_get(m->machine_units, unit);
- if (machine)
- machine_add_to_gc_queue(machine);
+ if (!machine)
+ return 0;
+
+ r = sd_bus_message_read(message, "s", &interface);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ if (streq(interface, "org.freedesktop.systemd1.Unit")) {
+ struct properties {
+ char *active_state;
+ char *sub_state;
+ } properties = {};
+
+ const struct bus_properties_map map[] = {
+ { "ActiveState", "s", NULL, offsetof(struct properties, active_state) },
+ { "SubState", "s", NULL, offsetof(struct properties, sub_state) },
+ {}
+ };
+ r = bus_message_map_properties_changed(message, map, &properties);
+ if (r < 0)
+ bus_log_parse_error(r);
+ else if (streq_ptr(properties.active_state, "inactive") ||
+ streq_ptr(properties.active_state, "failed") ||
+ streq_ptr(properties.sub_state, "auto-restart"))
+ machine_release_unit(machine);
+
+ free(properties.active_state);
+ free(properties.sub_state);
+ }
+
+ machine_add_to_gc_queue(machine);
return 0;
}
-int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *path, *unit;
Manager *m = userdata;
Machine *machine;
int r;
- assert(bus);
assert(message);
assert(m);
r = sd_bus_message_read(message, "so", &unit, &path);
if (r < 0) {
bus_log_parse_error(r);
- return r;
+ return 0;
}
machine = hashmap_get(m->machine_units, unit);
- if (machine)
- machine_add_to_gc_queue(machine);
+ if (!machine)
+ return 0;
+
+ machine_release_unit(machine);
+ machine_add_to_gc_queue(machine);
return 0;
}
-int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
Machine *machine;
Iterator i;
int b, r;
- assert(bus);
+ assert(message);
+ assert(m);
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
@@ -989,7 +1220,7 @@ int manager_unit_is_active(Manager *manager, const char *unit) {
if (r < 0)
return -EINVAL;
- return !streq(state, "inactive") && !streq(state, "failed");
+ return !STR_IN_SET(state, "inactive", "failed");
}
int manager_job_is_active(Manager *manager, const char *path) {
diff --git a/src/machine/machined.c b/src/machine/machined.c
index 6877c2b313..754c770040 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -20,20 +20,16 @@
***/
#include <errno.h>
-#include <pwd.h>
-#include <fcntl.h>
#include <string.h>
#include <unistd.h>
-#include <sys/epoll.h>
#include "sd-daemon.h"
-#include "strv.h"
-#include "conf-parser.h"
#include "cgroup-util.h"
-#include "mkdir.h"
#include "bus-util.h"
#include "bus-error.h"
#include "label.h"
+#include "formats-util.h"
+#include "signal-util.h"
#include "machine-image.h"
#include "machined.h"
@@ -199,7 +195,8 @@ static int manager_connect_bus(Manager *m) {
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.DBus.Properties',"
- "member='PropertiesChanged'",
+ "member='PropertiesChanged',"
+ "arg0='org.freedesktop.systemd1.Unit'",
match_properties_changed,
m);
if (r < 0)
@@ -325,6 +322,8 @@ int main(int argc, char *argv[]) {
* check stays in. */
mkdir_label("/run/systemd/machines", 0755);
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGCHLD, -1) >= 0);
+
m = manager_new();
if (!m) {
r = log_oom();
diff --git a/src/machine/machined.h b/src/machine/machined.h
index df0cb82f8d..61dbefb5f1 100644
--- a/src/machine/machined.h
+++ b/src/machine/machined.h
@@ -22,9 +22,7 @@
***/
#include <stdbool.h>
-#include <inttypes.h>
-#include "util.h"
#include "list.h"
#include "hashmap.h"
#include "sd-event.h"
@@ -67,10 +65,10 @@ int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine);
extern const sd_bus_vtable manager_vtable[];
-int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, sd_bus_message *more_properties, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf
index 37f84bd6f3..93aaf6a377 100644
--- a/src/machine/org.freedesktop.machine1.conf
+++ b/src/machine/org.freedesktop.machine1.conf
@@ -69,6 +69,50 @@
send_member="OpenMachineLogin"/>
<allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="TerminateMachine"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="KillMachine"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="BindMountMachine"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="CopyFromMachine"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="CopyToMachine"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="RemoveImage"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="RenameImage"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="CloneImage"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="MarkImageReadOnly"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="SetPoolLimit"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Manager"
+ send_member="SetImageLimit"/>
+
+ <allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Machine"
send_member="GetAddresses"/>
@@ -80,6 +124,46 @@
send_interface="org.freedesktop.machine1.Machine"
send_member="OpenLogin"/>
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Machine"
+ send_member="Terminate"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Machine"
+ send_member="Kill"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Machine"
+ send_member="BindMount"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Machine"
+ send_member="CopyFrom"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Machine"
+ send_member="CopyTo"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Image"
+ send_member="Remove"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Image"
+ send_member="Rename"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Image"
+ send_member="Clone"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Image"
+ send_member="SetLimit"/>
+
+ <allow send_destination="org.freedesktop.machine1"
+ send_interface="org.freedesktop.machine1.Image"
+ send_member="MarkReadOnly"/>
+
<allow receive_sender="org.freedesktop.machine1"/>
</policy>
diff --git a/src/machine/org.freedesktop.machine1.policy.in b/src/machine/org.freedesktop.machine1.policy.in
index 43478a84d6..02714e83ae 100644
--- a/src/machine/org.freedesktop.machine1.policy.in
+++ b/src/machine/org.freedesktop.machine1.policy.in
@@ -18,7 +18,27 @@
<action id="org.freedesktop.machine1.login">
<_description>Log into a local container</_description>
- <_message>Authentication is required to log into a local container</_message>
+ <_message>Authentication is required to log into a local container.</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.machine1.manage-machines">
+ <_description>Manage local virtual machines and containers</_description>
+ <_message>Authentication is required to manage local virtual machines and containers.</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
+ <action id="org.freedesktop.machine1.manage-images">
+ <_description>Manage local virtual machine and container images</_description>
+ <_message>Authentication is required to manage local virtual machine and container images.</_message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 5f678789ce..5bbe314ba0 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -19,13 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <limits.h>
-#include <dirent.h>
#include <getopt.h>
#include <libkmod.h>
@@ -33,7 +30,6 @@
#include "util.h"
#include "strv.h"
#include "conf-files.h"
-#include "fileio.h"
#include "build.h"
static char **arg_proc_cmdline_modules = NULL;
@@ -256,7 +252,7 @@ int main(int argc, char *argv[]) {
}
} else {
- _cleanup_free_ char **files = NULL;
+ _cleanup_strv_free_ char **files = NULL;
char **fn, **i;
STRV_FOREACH(i, arg_proc_cmdline_modules) {
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index aa83f32f53..3454394977 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -26,7 +26,7 @@
#include "sd-network.h"
#include "sd-rtnl.h"
#include "sd-hwdb.h"
-#include "libudev.h"
+#include "sd-device.h"
#include "strv.h"
#include "build.h"
@@ -34,13 +34,14 @@
#include "pager.h"
#include "lldp.h"
#include "rtnl-util.h"
-#include "udev-util.h"
+#include "device-util.h"
#include "hwdb-util.h"
#include "arphrd-list.h"
#include "local-addresses.h"
#include "socket-util.h"
#include "ether-addr-util.h"
#include "verbs.h"
+#include "terminal-util.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -54,17 +55,20 @@ static void pager_open_if_enabled(void) {
pager_open(false);
}
-static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
+static int link_get_type_string(int iftype, sd_device *d, char **ret) {
const char *t;
char *p;
+ assert(ret);
+
if (iftype == ARPHRD_ETHER && d) {
- const char *devtype, *id = NULL;
+ const char *devtype = NULL, *id = NULL;
/* WLANs have iftype ARPHRD_ETHER, but we want
* to show a more useful type string for
* them */
- devtype = udev_device_get_devtype(d);
+ (void)sd_device_get_devtype(d, &devtype);
+
if (streq_ptr(devtype, "wlan"))
id = "wlan";
else if (streq_ptr(devtype, "wwan"))
@@ -189,7 +193,6 @@ static void setup_state_to_color(const char *state, const char **on, const char
static int list_links(int argc, char *argv[], void *userdata) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
int r, c, i;
@@ -200,10 +203,6 @@ static int list_links(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- udev = udev_new();
- if (!udev)
- return log_error_errno(errno, "Failed to connect to udev: %m");
-
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
return rtnl_log_create_error(r);
@@ -225,7 +224,7 @@ static int list_links(int argc, char *argv[], void *userdata) {
for (i = 0; i < c; i++) {
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ _cleanup_device_unref_ sd_device *d = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
char devid[2 + DECIMAL_STR_MAX(int)];
@@ -238,7 +237,7 @@ static int list_links(int argc, char *argv[], void *userdata) {
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
sprintf(devid, "n%i", links[i].ifindex);
- d = udev_device_new_from_device_id(udev, devid);
+ (void)sd_device_new_from_device_id(&d, devid);
link_get_type_string(links[i].iftype, d, &t);
@@ -495,19 +494,19 @@ static void dump_list(const char *prefix, char **l) {
static int link_status_one(
sd_rtnl *rtnl,
- struct udev *udev,
sd_hwdb *hwdb,
const char *name) {
-
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ _cleanup_device_unref_ sd_device *d = NULL;
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL, *network = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
+ _cleanup_strv_free_ char **carrier_bound_to = NULL;
+ _cleanup_strv_free_ char **carrier_bound_by = NULL;
struct ether_addr e;
unsigned iftype;
int r, ifindex;
@@ -515,7 +514,6 @@ static int link_status_one(
uint32_t mtu;
assert(rtnl);
- assert(udev);
assert(name);
if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
@@ -587,31 +585,36 @@ static int link_status_one(
}
sprintf(devid, "n%i", ifindex);
- d = udev_device_new_from_device_id(udev, devid);
+
+ (void)sd_device_new_from_device_id(&d, devid);
+
if (d) {
- link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
- driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
- path = udev_device_get_property_value(d, "ID_PATH");
+ (void)sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
+ (void)sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
+ (void)sd_device_get_property_value(d, "ID_PATH", &path);
- vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
- if (!vendor)
- vendor = udev_device_get_property_value(d, "ID_VENDOR");
+ r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
+ if (r < 0)
+ (void)sd_device_get_property_value(d, "ID_VENDOR", &vendor);
- model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
- if (!model)
- model = udev_device_get_property_value(d, "ID_MODEL");
+ r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
+ if (r < 0)
+ (void)sd_device_get_property_value(d, "ID_MODEL", &model);
}
link_get_type_string(iftype, d, &t);
sd_network_link_get_network_file(ifindex, &network);
+ sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
+ sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
+
printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
- printf(" Link File: %s\n"
- "Network File: %s\n"
- " Type: %s\n"
- " State: %s%s%s (%s%s%s)\n",
+ printf(" Link File: %s\n"
+ " Network File: %s\n"
+ " Type: %s\n"
+ " State: %s%s%s (%s%s%s)\n",
strna(link),
strna(network),
strna(t),
@@ -619,13 +622,13 @@ static int link_status_one(
on_color_setup, strna(setup_state), off_color_setup);
if (path)
- printf(" Path: %s\n", path);
+ printf(" Path: %s\n", path);
if (driver)
- printf(" Driver: %s\n", driver);
+ printf(" Driver: %s\n", driver);
if (vendor)
- printf(" Vendor: %s\n", vendor);
+ printf(" Vendor: %s\n", vendor);
if (model)
- printf(" Model: %s\n", model);
+ printf(" Model: %s\n", model);
if (have_mac) {
_cleanup_free_ char *description = NULL;
@@ -634,30 +637,35 @@ static int link_status_one(
ieee_oui(hwdb, &e, &description);
if (description)
- printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
+ printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
else
- printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
+ printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
}
if (mtu > 0)
- printf(" MTU: %u\n", mtu);
+ printf(" MTU: %u\n", mtu);
- dump_addresses(rtnl, " Address: ", ifindex);
- dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
+ dump_addresses(rtnl, " Address: ", ifindex);
+ dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
if (!strv_isempty(dns))
- dump_list(" DNS: ", dns);
+ dump_list(" DNS: ", dns);
if (!strv_isempty(domains))
- dump_list(" Domain: ", domains);
+ dump_list(" Domain: ", domains);
if (!strv_isempty(ntp))
- dump_list(" NTP: ", ntp);
+ dump_list(" NTP: ", ntp);
+
+ if (!strv_isempty(carrier_bound_to))
+ dump_list("Carrier Bound To: ", carrier_bound_to);
+
+ if (!strv_isempty(carrier_bound_by))
+ dump_list("Carrier Bound By: ", carrier_bound_by);
return 0;
}
static int link_status(int argc, char *argv[], void *userdata) {
_cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
char **name;
int r;
@@ -666,10 +674,6 @@ static int link_status(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- udev = udev_new();
- if (!udev)
- return log_error_errno(errno, "Failed to connect to udev: %m");
-
r = sd_hwdb_new(&hwdb);
if (r < 0)
log_debug_errno(r, "Failed to open hardware database: %m");
@@ -731,14 +735,14 @@ static int link_status(int argc, char *argv[], void *userdata) {
if (i > 0)
fputc('\n', stdout);
- link_status_one(rtnl, udev, hwdb, links[i].name);
+ link_status_one(rtnl, hwdb, links[i].name);
}
} else {
STRV_FOREACH(name, argv + 1) {
if (name != argv + 1)
fputc('\n', stdout);
- link_status_one(rtnl, udev, hwdb, *name);
+ link_status_one(rtnl, hwdb, *name);
}
}
@@ -954,17 +958,17 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
continue;
if (streq(a, "_Chassis")) {
- chassis = strdup(b);
- if (!chassis)
- return -ENOMEM;
+ r = free_and_strdup(&chassis, b);
+ if (r < 0)
+ return r;
} else if (streq(a, "_Port")) {
- port = strdup(b);
- if (!port)
- return -ENOMEM;
+ r = free_and_strdup(&port, b);
+ if (r < 0)
+ return r;
} else if (streq(a, "_TTL")) {
- long long unsigned x;
+ long long unsigned x = 0;
usec_t time;
r = safe_atollu(b, &x);
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index 7ad11c6177..584a956a7e 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <arpa/inet.h>
#include "networkd.h"
#include "networkd-link.h"
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 47033acde4..069ba3eccb 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -25,7 +25,6 @@
#include "util.h"
#include "conf-parser.h"
#include "fw-util.h"
-#include "network-internal.h"
#include "networkd.h"
#include "networkd-link.h"
@@ -210,10 +209,18 @@ int address_update(Address *address, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set prefixlen: %m");
- r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
+ address->flags |= IFA_F_PERMANENT;
+
+ r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff);
if (r < 0)
return log_error_errno(r, "Could not set flags: %m");
+ if (address->flags & ~0xff && link->rtnl_extended_attrs) {
+ r = sd_rtnl_message_append_u32(req, IFA_FLAGS, address->flags);
+ if (r < 0)
+ return log_error_errno(r, "Could not set extended flags: %m");
+ }
+
r = sd_rtnl_message_addr_set_scope(req, address->scope);
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
@@ -267,10 +274,8 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
/* The address is configured to be 0.0.0.0 or [::] by the user?
* Then let's acquire something more useful from the pool. */
r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
- if (r < 0) {
- log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
if (r == 0) {
log_link_error(link, "Couldn't find free address for interface, all taken.");
return -EBUSY;
@@ -336,10 +341,18 @@ int address_configure(Address *address, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set prefixlen: %m");
- r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
+ address->flags |= IFA_F_PERMANENT;
+
+ r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
if (r < 0)
return log_error_errno(r, "Could not set flags: %m");
+ if (address->flags & ~0xff) {
+ r = sd_rtnl_message_append_u32(req, IFA_FLAGS, address->flags);
+ if (r < 0)
+ return log_error_errno(r, "Could not set extended flags: %m");
+ }
+
r = sd_rtnl_message_addr_set_scope(req, address->scope);
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index c3d0e3d39d..20aee53d6e 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -22,6 +22,7 @@
#include <netinet/ether.h>
#include <linux/if.h>
+#include "hostname-util.h"
#include "networkd-link.h"
#include "network-internal.h"
#include "dhcp-lease-internal.h"
@@ -409,62 +410,43 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
assert(link);
r = sd_dhcp_client_get_lease(client, &lease);
- if (r < 0) {
- log_link_warning(link, "DHCP error: no lease: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP error: no lease: %m");
r = sd_dhcp_lease_get_address(lease, &address);
- if (r < 0) {
- log_link_warning(link, "DHCP error: no address: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP error: no address: %m");
r = sd_dhcp_lease_get_netmask(lease, &netmask);
- if (r < 0) {
- log_link_warning(link, "DHCP error: no netmask: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP error: no netmask: %m");
prefixlen = in_addr_netmask_to_prefixlen(&netmask);
r = sd_dhcp_lease_get_router(lease, &gateway);
- if (r < 0 && r != -ENOENT) {
- log_link_warning(link, "DHCP error: could not get gateway: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0 && r != -ENOENT)
+ return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
if (r >= 0)
- log_link_struct(link, LOG_INFO,
- "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
- IFNAMSIZ,
- link->ifname,
- ADDRESS_FMT_VAL(address),
- prefixlen,
- ADDRESS_FMT_VAL(gateway),
- "ADDRESS=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(address),
- "PREFIXLEN=%u",
- prefixlen,
- "GATEWAY=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(gateway),
- NULL);
+ log_struct(LOG_INFO,
+ LOG_LINK_INTERFACE(link),
+ LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
+ ADDRESS_FMT_VAL(address),
+ prefixlen,
+ ADDRESS_FMT_VAL(gateway)),
+ "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
+ "PREFIXLEN=%u", prefixlen,
+ "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
+ NULL);
else
- log_link_struct(link, LOG_INFO,
- "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
- IFNAMSIZ,
- link->ifname,
- ADDRESS_FMT_VAL(address),
- prefixlen,
- "ADDRESS=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(address),
- "PREFIXLEN=%u",
- prefixlen,
- NULL);
+ log_struct(LOG_INFO,
+ LOG_LINK_INTERFACE(link),
+ LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
+ ADDRESS_FMT_VAL(address),
+ prefixlen),
+ "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
+ "PREFIXLEN=%u", prefixlen,
+ NULL);
link->dhcp_lease = lease;
@@ -475,8 +457,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
if (r >= 0) {
r = link_set_mtu(link, mtu);
if (r < 0)
- log_link_error(link, "Failed to set MTU "
- "to %" PRIu16, mtu);
+ log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
}
}
@@ -487,27 +468,21 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
if (r >= 0) {
r = link_set_hostname(link, hostname);
if (r < 0)
- log_link_error(link,
- "Failed to set transient hostname to '%s'",
- hostname);
+ log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
}
}
if (!link->network->dhcp_critical) {
- r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
- &lifetime);
+ r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
if (r < 0) {
- log_link_warning(link,
- "DHCP error: no lifetime: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
return r;
}
}
r = dhcp4_update_address(link, &address, &netmask, lifetime);
if (r < 0) {
- log_link_warning(link, "could not update IP address: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not update IP address: %m");
link_enter_failed(link);
return r;
}
@@ -661,5 +636,21 @@ int dhcp4_configure(Link *link) {
return r;
}
+ switch (link->network->dhcp_client_identifier) {
+ case DHCP_CLIENT_ID_DUID:
+ /* Library defaults to this. */
+ break;
+ case DHCP_CLIENT_ID_MAC:
+ r = sd_dhcp_client_set_client_id(link->dhcp_client,
+ ARPHRD_ETHER,
+ (const uint8_t *) &link->mac,
+ sizeof (link->mac));
+ if (r < 0)
+ return r;
+ break;
+ default:
+ assert_not_reached("Unknown client identifier type.");
+ }
+
return 0;
}
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index bcfad4c03f..33e18137d2 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -28,6 +28,8 @@
#include "sd-icmp6-nd.h"
#include "sd-dhcp6-client.h"
+static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
+
static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
Link *link) {
return 0;
@@ -42,6 +44,15 @@ static int dhcp6_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
+ if (link->rtnl_extended_attrs) {
+ log_link_warning(link, "Could not set extended netlink attributes, reverting to fallback mechanism");
+
+ link->rtnl_extended_attrs = false;
+ dhcp6_lease_address_acquired(link->dhcp6_client, link);
+
+ return 1;
+ }
+
log_link_error(link, "Could not set DHCPv6 address: %s",
strerror(-r));
@@ -65,61 +76,25 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
addr->family = AF_INET6;
memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
+
+ addr->flags = IFA_F_NOPREFIXROUTE;
addr->prefixlen = prefixlen;
addr->cinfo.ifa_prefered = lifetime_preferred;
addr->cinfo.ifa_valid = lifetime_valid;
- log_link_struct(link, LOG_INFO, "MESSAGE=%-*s: DHCPv6 address "SD_ICMP6_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
- IFNAMSIZ,
- link->ifname, SD_ICMP6_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
- addr->prefixlen, lifetime_preferred, lifetime_valid,
- NULL);
+ log_link_info(link,
+ "DHCPv6 address "SD_ICMP6_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
+ SD_ICMP6_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
+ addr->prefixlen, lifetime_preferred, lifetime_valid);
r = address_update(addr, link, dhcp6_address_handler);
if (r < 0)
- log_link_warning(link, "Could not assign DHCPv6 address: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
return r;
}
-static int dhcp6_prefix_expired(Link *link) {
- int r;
- sd_dhcp6_lease *lease;
- struct in6_addr *expired_prefix, ip6_addr;
- uint8_t expired_prefixlen;
- uint32_t lifetime_preferred, lifetime_valid;
-
- r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
- &expired_prefix, &expired_prefixlen);
- if (r < 0)
- return r;
-
- r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
- if (r < 0)
- return r;
-
- sd_dhcp6_lease_reset_address_iter(lease);
-
- while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
- &lifetime_preferred,
- &lifetime_valid) >= 0) {
-
- r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
- &ip6_addr);
- if (r >= 0) {
- r = dhcp6_address_update(link, &ip6_addr, 128,
- lifetime_preferred,
- lifetime_valid);
-
- return r;
- }
- }
-
- return 0;
-}
-
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
int r;
sd_dhcp6_lease *lease;
@@ -296,6 +271,45 @@ static int dhcp6_configure(Link *link, int event) {
return r;
}
+static int dhcp6_prefix_expired(Link *link) {
+ int r;
+ sd_dhcp6_lease *lease;
+ struct in6_addr *expired_prefix, ip6_addr;
+ uint8_t expired_prefixlen;
+ uint32_t lifetime_preferred, lifetime_valid;
+
+ r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
+ &expired_prefix, &expired_prefixlen);
+ if (r < 0)
+ return r;
+
+ r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
+ if (r < 0)
+ return r;
+
+ log_link_info(link, "IPv6 prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d expired",
+ SD_ICMP6_ADDRESS_FORMAT_VAL(*expired_prefix),
+ expired_prefixlen);
+
+ sd_dhcp6_lease_reset_address_iter(lease);
+
+ while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
+ &lifetime_preferred,
+ &lifetime_valid) >= 0) {
+
+ r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
+ &ip6_addr);
+ if (r < 0)
+ continue;
+
+ log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ADDRESS_FORMAT_VAL(ip6_addr), 128);
+
+ dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
+ }
+
+ return 0;
+}
+
static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
Link *link = userdata;
@@ -318,7 +332,8 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
break;
case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
- dhcp6_prefix_expired(link);
+ if (!link->rtnl_extended_attrs)
+ dhcp6_prefix_expired(link);
break;
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index feab8d421e..796d1117b6 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -19,16 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <ctype.h>
#include <net/if.h>
#include <net/ethernet.h>
#include "networkd.h"
-#include "networkd-netdev.h"
#include "networkd-link.h"
-#include "network-internal.h"
-#include "path-util.h"
-#include "conf-files.h"
#include "conf-parser.h"
#include "util.h"
@@ -93,7 +88,7 @@ static int set_fdb_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_error(link, "Could not add FDB entry: %s", strerror(-r));
+ log_link_error_errno(link, r, "Could not add FDB entry: %m");
return 1;
}
@@ -138,10 +133,8 @@ int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
/* send message to the kernel to update its internal static MAC table. */
r = sd_rtnl_call_async(rtnl, req, set_fdb_handler, link, 0, NULL);
- if (r < 0) {
- log_link_error(link, "Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
return 0;
}
@@ -155,9 +148,9 @@ void fdb_entry_free(FdbEntry *fdb_entry) {
LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries,
fdb_entry);
- if(fdb_entry->section)
- hashmap_remove(fdb_entry->network->fdb_entries_by_section,
- UINT_TO_PTR(fdb_entry->section));
+ if (fdb_entry->section)
+ hashmap_remove(fdb_entry->network->fdb_entries_by_section,
+ UINT_TO_PTR(fdb_entry->section));
}
free(fdb_entry->mac_addr);
@@ -166,16 +159,18 @@ void fdb_entry_free(FdbEntry *fdb_entry) {
}
/* parse the HW address from config files. */
-int config_parse_fdb_hwaddr(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_fdb_hwaddr(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
Network *network = userdata;
_cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
int r;
@@ -187,10 +182,8 @@ int config_parse_fdb_hwaddr(const char *unit,
assert(data);
r = fdb_entry_new_static(network, section_line, &fdb_entry);
- if (r < 0) {
- log_error("Failed to allocate a new FDB entry: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_oom();
/* read in the MAC address for the FDB table. */
r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
@@ -201,9 +194,8 @@ int config_parse_fdb_hwaddr(const char *unit,
&fdb_entry->mac_addr->ether_addr_octet[4],
&fdb_entry->mac_addr->ether_addr_octet[5]);
- if (ETHER_ADDR_LEN != r) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not a valid MAC address, ignoring assignment: %s", rvalue);
+ if (ETHER_ADDR_LEN != r) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not a valid MAC address, ignoring assignment: %s", rvalue);
return 0;
}
@@ -213,16 +205,18 @@ int config_parse_fdb_hwaddr(const char *unit,
}
/* parse the VLAN Id from config files. */
-int config_parse_fdb_vlan_id(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_fdb_vlan_id(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
Network *network = userdata;
_cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
int r;
@@ -234,18 +228,14 @@ int config_parse_fdb_vlan_id(const char *unit,
assert(data);
r = fdb_entry_new_static(network, section_line, &fdb_entry);
- if (r < 0) {
- log_error("Failed to allocate a new FDB entry: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_oom();
r = config_parse_unsigned(unit, filename, line, section,
section_line, lvalue, ltype,
rvalue, &fdb_entry->vlan_id, userdata);
- if (r < 0) {
- log_error("Failed to parse the unsigned integer: %s", strerror(-r));
+ if (r < 0)
return r;
- }
fdb_entry = NULL;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index f716e8231a..b30fd7ae89 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -26,14 +26,12 @@
#include "util.h"
#include "virt.h"
#include "fileio.h"
+#include "socket-util.h"
#include "bus-util.h"
#include "udev-util.h"
-#include "libudev-private.h"
#include "network-internal.h"
#include "networkd-link.h"
#include "networkd-netdev.h"
-#include "conf-parser.h"
-#include "dhcp-lease-internal.h"
bool link_dhcp6_enabled(Link *link) {
if (link->flags & IFF_LOOPBACK)
@@ -131,10 +129,8 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
assert(link);
r = sd_rtnl_message_link_get_flags(m, &flags);
- if (r < 0) {
- log_link_warning(link, "Could not get link flags");
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not get link flags: %m");
r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
if (r < 0)
@@ -146,7 +142,7 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
return 0;
if (link->flags != flags) {
- log_link_debug(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ log_link_debug(link, "Flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
@@ -180,12 +176,12 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
* printing 20 */
if (unknown_flags_added)
log_link_debug(link,
- "unknown link flags gained: %#.5x (ignoring)",
+ "Unknown link flags gained: %#.5x (ignoring)",
unknown_flags_added);
if (unknown_flags_removed)
log_link_debug(link,
- "unknown link flags lost: %#.5x (ignoring)",
+ "Unknown link flags lost: %#.5x (ignoring)",
unknown_flags_removed);
}
@@ -230,6 +226,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
link->n_ref = 1;
link->manager = manager;
link->state = LINK_STATE_PENDING;
+ link->rtnl_extended_attrs = true;
link->ifindex = ifindex;
link->ifname = strdup(ifname);
if (!link->ifname)
@@ -275,6 +272,8 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
static void link_free(Link *link) {
Address *address;
+ Iterator i;
+ Link *carrier;
if (!link)
return;
@@ -312,6 +311,14 @@ static void link_free(Link *link) {
udev_device_unref(link->udev_device);
+ HASHMAP_FOREACH (carrier, link->bound_to_links, i)
+ hashmap_remove(link->bound_to_links, INT_TO_PTR(carrier->ifindex));
+ hashmap_free(link->bound_to_links);
+
+ HASHMAP_FOREACH (carrier, link->bound_by_links, i)
+ hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex));
+ hashmap_free(link->bound_by_links);
+
free(link);
}
@@ -358,23 +365,10 @@ static void link_set_state(Link *link, LinkState state) {
return;
}
-void link_drop(Link *link) {
- if (!link || link->state == LINK_STATE_LINGER)
- return;
-
- link_set_state(link, LINK_STATE_LINGER);
-
- log_link_debug(link, "link removed");
-
- link_unref(link);
-
- return;
-}
-
static void link_enter_unmanaged(Link *link) {
assert(link);
- log_link_debug(link, "unmanaged");
+ log_link_debug(link, "Unmanaged");
link_set_state(link, LINK_STATE_UNMANAGED);
@@ -393,50 +387,32 @@ static int link_stop_clients(Link *link) {
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
- if (k < 0) {
- log_link_warning(link, "Could not stop DHCPv4 client: %s",
- strerror(-r));
- r = k;
- }
+ if (k < 0)
+ r = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m");
}
if (link->ipv4ll) {
k = sd_ipv4ll_stop(link->ipv4ll);
- if (k < 0) {
- log_link_warning(link, "Could not stop IPv4 link-local: %s",
- strerror(-r));
- r = k;
- }
+ if (k < 0)
+ r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
}
if(link->icmp6_router_discovery) {
-
if (link->dhcp6_client) {
k = sd_dhcp6_client_stop(link->dhcp6_client);
- if (k < 0) {
- log_link_warning(link, "Could not stop DHCPv6 client: %s",
- strerror(-r));
- r = k;
- }
+ if (k < 0)
+ r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
}
k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
- if (k < 0) {
- log_link_warning(link,
- "Could not stop ICMPv6 router discovery: %s",
- strerror(-r));
- r = k;
- }
+ if (k < 0)
+ r = log_link_warning_errno(link, r, "Could not stop ICMPv6 router discovery: %m");
}
if (link->lldp) {
-
k = sd_lldp_stop(link->lldp);
- if (k < 0) {
- log_link_warning(link, "Could not stop LLDP : %s",
- strerror(-r));
- r = k;
- }
+ if (k < 0)
+ r = log_link_warning_errno(link, r, "Could not stop LLDP: %m");
}
return r;
@@ -448,7 +424,7 @@ void link_enter_failed(Link *link) {
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
- log_link_warning(link, "failed");
+ log_link_warning(link, "Failed");
link_set_state(link, LINK_STATE_FAILED);
@@ -491,7 +467,7 @@ static int link_enter_configured(Link *link) {
assert(link->network);
assert(link->state == LINK_STATE_SETTING_ROUTES);
- log_link_info(link, "link configured");
+ log_link_info(link, "Configured");
link_set_state(link, LINK_STATE_CONFIGURED);
@@ -537,10 +513,10 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, -r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
if (link->link_messages == 0) {
- log_link_debug(link, "routes set");
+ log_link_debug(link, "Routes set");
link->static_configured = true;
link_client_handler(link);
}
@@ -561,9 +537,7 @@ static int link_enter_set_routes(Link *link) {
LIST_FOREACH(routes, rt, link->network->static_routes) {
r = route_configure(rt, link, &route_handler);
if (r < 0) {
- log_link_warning(link,
- "could not set routes: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not set routes: %m");
link_enter_failed(link);
return r;
}
@@ -575,7 +549,7 @@ static int link_enter_set_routes(Link *link) {
link->static_configured = true;
link_client_handler(link);
} else
- log_link_debug(link, "setting routes");
+ log_link_debug(link, "Setting routes");
return 0;
}
@@ -593,7 +567,7 @@ int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -ESRCH)
- log_link_warning_errno(link, -r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
return 1;
}
@@ -617,12 +591,12 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, -r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
else if (r >= 0)
link_rtnl_process_address(rtnl, m, link->manager);
if (link->link_messages == 0) {
- log_link_debug(link, "addresses set");
+ log_link_debug(link, "Addresses set");
link_enter_set_routes(link);
}
@@ -658,8 +632,7 @@ static int link_enter_set_addresses(Link *link) {
address = link_find_dhcp_server_address(link);
if (!address) {
- log_link_warning(link,
- "Failed to find suitable address for DHCPv4 server instance.");
+ log_link_warning(link, "Failed to find suitable address for DHCPv4 server instance.");
link_enter_failed(link);
return 0;
}
@@ -691,21 +664,20 @@ static int link_enter_set_addresses(Link *link) {
r = sd_dhcp_server_start(link->dhcp_server);
if (r < 0) {
- log_link_warning(link, "could not start DHCPv4 server "
- "instance: %s", strerror(-r));
+ log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");
link_enter_failed(link);
return 0;
}
- log_link_debug(link, "offering DHCPv4 leases");
+ log_link_debug(link, "Offering DHCPv4 leases");
}
- if (link->link_messages == 0) {
+ if (link->link_messages == 0)
link_enter_set_routes(link);
- } else
- log_link_debug(link, "setting addresses");
+ else
+ log_link_debug(link, "Setting addresses");
return 0;
}
@@ -723,7 +695,7 @@ int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
- log_link_warning_errno(link, -r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
return 1;
}
@@ -735,7 +707,7 @@ static int link_set_bridge_fdb(Link *const link) {
LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
r = fdb_entry_configure(link, fdb_entry);
if(r < 0) {
- log_link_error(link, "Failed to add MAC entry to static MAC table: %s", strerror(-r));
+ log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
break;
}
}
@@ -747,16 +719,11 @@ static int link_set_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
- log_link_debug(link, "set link");
+ log_link_debug(link, "Set link");
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_struct(link, LOG_ERR,
- "MESSAGE=%-*s: could not join netdev: %s",
- IFNAMSIZ,
- link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
+ log_link_error_errno(link, r, "Could not join netdev: %m");
link_enter_failed(link);
return 1;
}
@@ -764,11 +731,11 @@ static int link_set_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
return 0;
}
-static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
- sd_bus_error *ret_error) {
+static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
_cleanup_link_unref_ Link *link = userdata;
int r;
+ assert(m);
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
@@ -776,8 +743,7 @@ static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
r = sd_bus_message_get_errno(m);
if (r > 0)
- log_link_warning(link, "Could not set hostname: %s",
- strerror(r));
+ log_link_warning_errno(link, r, "Could not set hostname: %m");
return 1;
}
@@ -794,8 +760,7 @@ int link_set_hostname(Link *link, const char *hostname) {
if (!link->manager->bus) {
/* TODO: replace by assert when we can rely on kdbus */
- log_link_info(link,
- "Not connected to system bus, ignoring transient hostname.");
+ log_link_info(link, "Not connected to system bus, ignoring transient hostname.");
return 0;
}
@@ -815,11 +780,8 @@ int link_set_hostname(Link *link, const char *hostname) {
r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler,
link, 0);
- if (r < 0) {
- log_link_error(link, "Could not set transient hostname: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set transient hostname: %m");
link_ref(link);
@@ -839,7 +801,7 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, -r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
return 1;
}
@@ -852,29 +814,19 @@ int link_set_mtu(Link *link, uint32_t mtu) {
assert(link->manager);
assert(link->manager->rtnl);
- log_link_debug(link, "setting MTU: %" PRIu32, mtu);
+ log_link_debug(link, "Setting MTU: %" PRIu32, mtu);
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
- RTM_SETLINK, link->ifindex);
- if (r < 0) {
- log_link_error(link, "Could not allocate RTM_SETLINK message");
- return r;
- }
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
- if (r < 0) {
- log_link_error(link, "Could not append MTU: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append MTU: %m");
- r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link,
- 0, NULL);
- if (r < 0) {
- log_link_error(link,
- "Could not send rtnetlink message: %s",
- strerror(-r));
- return r;
- }
+ r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
@@ -891,53 +843,31 @@ static int link_set_bridge(Link *link) {
if(link->network->cost == 0)
return 0;
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
- RTM_SETLINK, link->ifindex);
- if (r < 0) {
- log_link_error(link, "Could not allocate RTM_SETLINK message");
- return r;
- }
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
- if (r < 0) {
- log_link_error(link,
- "Could not set message family %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set message family: %m");
r = sd_rtnl_message_open_container(req, IFLA_PROTINFO);
- if (r < 0) {
- log_link_error(link,
- "Could not append IFLA_PROTINFO attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m");
if(link->network->cost != 0) {
r = sd_rtnl_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
- if (r < 0) {
- log_link_error(link,
- "Could not append IFLA_BRPORT_COST attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
}
r = sd_rtnl_message_close_container(req);
- if (r < 0) {
- log_link_error(link,
- "Could not append IFLA_LINKINFO attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m");
r = sd_rtnl_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL);
- if (r < 0) {
- log_link_error(link,
- "Could not send rtnetlink message: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
@@ -957,7 +887,7 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
r = sd_lldp_save(link->lldp, link->lldp_file);
if (r < 0)
- log_link_warning(link, "could not save LLDP");
+ log_link_warning_errno(link, r, "Could not save LLDP: %m");
}
@@ -972,40 +902,31 @@ static int link_acquire_conf(Link *link) {
if (link_ipv4ll_enabled(link)) {
assert(link->ipv4ll);
- log_link_debug(link, "acquiring IPv4 link-local address");
+ log_link_debug(link, "Acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll);
- if (r < 0) {
- log_link_warning(link, "could not acquire IPv4 "
- "link-local address");
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
}
if (link_dhcp4_enabled(link)) {
assert(link->dhcp_client);
- log_link_debug(link, "acquiring DHCPv4 lease");
+ log_link_debug(link, "Acquiring DHCPv4 lease");
r = sd_dhcp_client_start(link->dhcp_client);
- if (r < 0) {
- log_link_warning(link, "could not acquire DHCPv4 "
- "lease");
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
}
if (link_dhcp6_enabled(link)) {
assert(link->icmp6_router_discovery);
- log_link_debug(link, "discovering IPv6 routers");
+ log_link_debug(link, "Discovering IPv6 routers");
r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
- if (r < 0) {
- log_link_warning(link,
- "could not start IPv6 router discovery");
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not start IPv6 router discovery: %m");
}
if (link_lldp_enabled(link)) {
@@ -1014,10 +935,8 @@ static int link_acquire_conf(Link *link) {
log_link_debug(link, "Starting LLDP");
r = sd_lldp_start(link->lldp);
- if (r < 0) {
- log_link_warning(link, "could not start LLDP ");
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not start LLDP: %m");
}
return 0;
@@ -1047,11 +966,10 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
return 1;
r = sd_rtnl_message_get_errno(m);
- if (r < 0) {
- /* we warn but don't fail the link, as it may
- be brought up later */
- log_link_warning_errno(link, -r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
- }
+ if (r < 0)
+ /* we warn but don't fail the link, as it may be
+ brought up later */
+ log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
return 1;
}
@@ -1066,98 +984,370 @@ static int link_up(Link *link) {
assert(link->manager);
assert(link->manager->rtnl);
- log_link_debug(link, "bringing link up");
+ log_link_debug(link, "Bringing link up");
- r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
- RTM_SETLINK, link->ifindex);
- if (r < 0) {
- log_link_error(link, "Could not allocate RTM_SETLINK message");
- return r;
- }
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
- if (r < 0) {
- log_link_error(link, "Could not set link flags: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set link flags: %m");
if (link->network->mac) {
r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
- if (r < 0) {
- log_link_error(link, "Could not set MAC address: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set MAC address: %m");
}
if (link->network->mtu) {
r = sd_rtnl_message_append_u32(req, IFLA_MTU, link->network->mtu);
- if (r < 0) {
- log_link_error(link, "Could not set MTU: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set MTU: %m");
}
r = sd_rtnl_message_open_container(req, IFLA_AF_SPEC);
- if (r < 0) {
- log_link_error(link, "Could not open IFLA_AF_SPEC container: %s", strerror(-r));
- return r;
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
+
+ if (socket_ipv6_is_supported()) {
+ /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
+ r = sd_rtnl_message_open_container(req, AF_INET6);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not open AF_INET6 container: %m");
+
+ ipv6ll_mode = link_ipv6ll_enabled(link) ? IN6_ADDR_GEN_MODE_EUI64 : IN6_ADDR_GEN_MODE_NONE;
+ r = sd_rtnl_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m");
+
+ if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
+ r = sd_rtnl_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m");
+ }
+
+ r = sd_rtnl_message_close_container(req);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m");
}
- r = sd_rtnl_message_open_container(req, AF_INET6);
- if (r < 0) {
- log_link_error(link, "Could not open AF_INET6 container: %s", strerror(-r));
- return r;
+ r = sd_rtnl_message_close_container(req);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
+
+ r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
+static int link_down_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+ _cleanup_link_unref_ Link *link = userdata;
+ int r;
+
+ assert(link);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ r = sd_rtnl_message_get_errno(m);
+ if (r < 0)
+ log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname);
+
+ return 1;
+}
+
+static int link_down(Link *link) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+
+ log_link_debug(link, "Bringing link down");
+
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
+ RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+
+ r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set link flags: %m");
+
+ r = sd_rtnl_call_async(link->manager->rtnl, req, link_down_handler, link, 0, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
+static int link_handle_bound_to_list(Link *link) {
+ Link *l;
+ Iterator i;
+ int r;
+ bool required_up = false;
+ bool link_is_up = false;
+
+ assert(link);
+
+ if (hashmap_isempty(link->bound_to_links))
+ return 0;
+
+ if (link->flags & IFF_UP)
+ link_is_up = true;
+
+ HASHMAP_FOREACH (l, link->bound_to_links, i)
+ if (link_has_carrier(l)) {
+ required_up = true;
+ break;
+ }
+
+ if (!required_up && link_is_up) {
+ r = link_down(link);
+ if (r < 0)
+ return r;
+ } else if (required_up && !link_is_up) {
+ r = link_up(link);
+ if (r < 0)
+ return r;
}
- ipv6ll_mode = link_ipv6ll_enabled(link) ? IN6_ADDR_GEN_MODE_EUI64 : IN6_ADDR_GEN_MODE_NONE;
- r = sd_rtnl_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
- if (r < 0) {
- log_link_error(link, "Could not append IFLA_INET6_ADDR_GEN_MODE: %s", strerror(-r));
+ return 0;
+}
+
+static int link_handle_bound_by_list(Link *link) {
+ Iterator i;
+ Link *l;
+ int r;
+
+ assert(link);
+
+ if (hashmap_isempty(link->bound_by_links))
+ return 0;
+
+ HASHMAP_FOREACH (l, link->bound_by_links, i) {
+ r = link_handle_bound_to_list(l);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) {
+ int r;
+
+ assert(link);
+ assert(carrier);
+
+ if (link == carrier)
+ return 0;
+
+ if (hashmap_get(*h, INT_TO_PTR(carrier->ifindex)))
+ return 0;
+
+ r = hashmap_ensure_allocated(h, NULL);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(*h, INT_TO_PTR(carrier->ifindex), carrier);
+ if (r < 0)
return r;
+
+ return 0;
+}
+
+static int link_new_bound_by_list(Link *link) {
+ Manager *m;
+ Link *carrier;
+ Iterator i;
+ int r;
+ bool list_updated = false;
+
+ assert(link);
+ assert(link->manager);
+
+ m = link->manager;
+
+ HASHMAP_FOREACH (carrier, m->links, i) {
+ if (!carrier->network)
+ continue;
+
+ if (strv_isempty(carrier->network->bind_carrier))
+ continue;
+
+ if (strv_fnmatch(carrier->network->bind_carrier, link->ifname, 0)) {
+ r = link_put_carrier(link, carrier, &link->bound_by_links);
+ if (r < 0)
+ return r;
+
+ list_updated = true;
+ }
}
- if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
- r = sd_rtnl_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
- if (r < 0) {
- log_link_error(link, "Could not append IFLA_INET6_TOKEN: %s", strerror(-r));
+ if (list_updated)
+ link_save(link);
+
+ HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
+ r = link_put_carrier(carrier, link, &carrier->bound_to_links);
+ if (r < 0)
return r;
+
+ link_save(carrier);
+ }
+
+ return 0;
+}
+
+static int link_new_bound_to_list(Link *link) {
+ Manager *m;
+ Link *carrier;
+ Iterator i;
+ int r;
+ bool list_updated = false;
+
+ assert(link);
+ assert(link->manager);
+
+ if (!link->network)
+ return 0;
+
+ if (strv_isempty(link->network->bind_carrier))
+ return 0;
+
+ m = link->manager;
+
+ HASHMAP_FOREACH (carrier, m->links, i) {
+ if (strv_fnmatch(link->network->bind_carrier, carrier->ifname, 0)) {
+ r = link_put_carrier(link, carrier, &link->bound_to_links);
+ if (r < 0)
+ return r;
+
+ list_updated = true;
}
}
- r = sd_rtnl_message_close_container(req);
- if (r < 0) {
- log_link_error(link, "Could not close AF_INET6 container: %s", strerror(-r));
- return r;
+ if (list_updated)
+ link_save(link);
+
+ HASHMAP_FOREACH (carrier, link->bound_to_links, i) {
+ r = link_put_carrier(carrier, link, &carrier->bound_by_links);
+ if (r < 0)
+ return r;
+
+ link_save(carrier);
}
- r = sd_rtnl_message_close_container(req);
- if (r < 0) {
- log_link_error(link, "Could not close IFLA_AF_SPEC container: %s", strerror(-r));
+ return 0;
+}
+
+static int link_new_carrier_maps(Link *link) {
+ int r;
+
+ r = link_new_bound_by_list(link);
+ if (r < 0)
return r;
- }
- r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link,
- 0, NULL);
- if (r < 0) {
- log_link_error(link,
- "Could not send rtnetlink message: %s",
- strerror(-r));
+ r = link_handle_bound_by_list(link);
+ if (r < 0)
return r;
- }
- link_ref(link);
+ r = link_new_bound_to_list(link);
+ if (r < 0)
+ return r;
+
+ r = link_handle_bound_to_list(link);
+ if (r < 0)
+ return r;
return 0;
}
+static void link_free_bound_to_list(Link *link) {
+ Link *bound_to;
+ Iterator i;
+
+ HASHMAP_FOREACH (bound_to, link->bound_to_links, i) {
+ hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));
+
+ if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
+ link_save(bound_to);
+ }
+
+ return;
+}
+
+static void link_free_bound_by_list(Link *link) {
+ Link *bound_by;
+ Iterator i;
+
+ HASHMAP_FOREACH (bound_by, link->bound_by_links, i) {
+ hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex));
+
+ if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) {
+ link_save(bound_by);
+ link_handle_bound_to_list(bound_by);
+ }
+ }
+
+ return;
+}
+
+static void link_free_carrier_maps(Link *link) {
+ bool list_updated = false;
+
+ assert(link);
+
+ if (!hashmap_isempty(link->bound_to_links)) {
+ link_free_bound_to_list(link);
+ list_updated = true;
+ }
+
+ if (!hashmap_isempty(link->bound_by_links)) {
+ link_free_bound_by_list(link);
+ list_updated = true;
+ }
+
+ if (list_updated)
+ link_save(link);
+
+ return;
+}
+
+void link_drop(Link *link) {
+ if (!link || link->state == LINK_STATE_LINGER)
+ return;
+
+ link_set_state(link, LINK_STATE_LINGER);
+
+ link_free_carrier_maps(link);
+
+ log_link_debug(link, "Link removed");
+
+ link_unref(link);
+
+ return;
+}
+
static int link_joined(Link *link) {
int r;
assert(link);
assert(link->network);
- if (!(link->flags & IFF_UP)) {
+ if (!hashmap_isempty(link->bound_to_links)) {
+ r = link_handle_bound_to_list(link);
+ if (r < 0)
+ return r;
+ } else if (!(link->flags & IFF_UP)) {
r = link_up(link);
if (r < 0) {
link_enter_failed(link);
@@ -1167,11 +1357,8 @@ static int link_joined(Link *link) {
if(link->network->bridge) {
r = link_set_bridge(link);
- if (r < 0) {
- log_link_error(link,
- "Could not set bridge message: %s",
- strerror(-r));
- }
+ if (r < 0)
+ log_link_error_errno(link, r, "Could not set bridge message: %m");
}
return link_enter_set_addresses(link);
@@ -1192,11 +1379,11 @@ static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error_errno(link, -r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
+ log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
link_enter_failed(link);
return 1;
} else
- log_link_debug(link, "joined netdev");
+ log_link_debug(link, "Joined netdev");
if (link->enslaving <= 0)
link_joined(link);
@@ -1223,22 +1410,20 @@ static int link_enter_join_netdev(Link *link) {
return link_joined(link);
if (link->network->bond) {
- log_link_struct(link, LOG_DEBUG,
- "MESSAGE=%-*s: enslaving by '%s'",
- IFNAMSIZ,
- link->ifname, link->network->bond->ifname,
- NETDEVIF(link->network->bond),
- NULL);
-
- r = netdev_join(link->network->bond, link, &netdev_join_handler);
+ log_struct(LOG_DEBUG,
+ LOG_LINK_INTERFACE(link),
+ LOG_NETDEV_INTERFACE(link->network->bond),
+ LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bond->ifname),
+ NULL);
+
+ r = netdev_join(link->network->bond, link, netdev_join_handler);
if (r < 0) {
- log_link_struct(link, LOG_WARNING,
- "MESSAGE=%-*s: could not join netdev '%s': %s",
- IFNAMSIZ,
- link->ifname, link->network->bond->ifname,
- strerror(-r),
- NETDEVIF(link->network->bond),
- NULL);
+ log_struct_errno(LOG_WARNING, r,
+ LOG_LINK_INTERFACE(link),
+ LOG_NETDEV_INTERFACE(link->network->bond),
+ LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->bond->ifname),
+ NULL);
+
link_enter_failed(link);
return r;
}
@@ -1247,23 +1432,19 @@ static int link_enter_join_netdev(Link *link) {
}
if (link->network->bridge) {
- log_link_struct(link, LOG_DEBUG,
- "MESSAGE=%-*s: enslaving by '%s'",
- IFNAMSIZ,
- link->ifname, link->network->bridge->ifname,
- NETDEVIF(link->network->bridge),
- NULL);
-
- r = netdev_join(link->network->bridge, link,
- &netdev_join_handler);
+ log_struct(LOG_DEBUG,
+ LOG_LINK_INTERFACE(link),
+ LOG_NETDEV_INTERFACE(link->network->bridge),
+ LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bridge->ifname),
+ NULL);
+
+ r = netdev_join(link->network->bridge, link, netdev_join_handler);
if (r < 0) {
- log_link_struct(link, LOG_WARNING,
- "MESSAGE=%-*s: could not join netdev '%s': %s",
- IFNAMSIZ,
- link->ifname, link->network->bridge->ifname,
- strerror(-r),
- NETDEVIF(link->network->bridge),
- NULL);
+ log_struct_errno(LOG_WARNING, r,
+ LOG_LINK_INTERFACE(link),
+ LOG_NETDEV_INTERFACE(link->network->bridge),
+ LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->bridge->ifname),
+ NULL),
link_enter_failed(link);
return r;
}
@@ -1272,20 +1453,20 @@ static int link_enter_join_netdev(Link *link) {
}
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
- log_link_struct(link, LOG_DEBUG,
- "MESSAGE=%-*s: enslaving by '%s'",
- IFNAMSIZ,
- link->ifname, netdev->ifname, NETDEVIF(netdev),
- NULL);
- r = netdev_join(netdev, link, &netdev_join_handler);
+ log_struct(LOG_DEBUG,
+ LOG_LINK_INTERFACE(link),
+ LOG_NETDEV_INTERFACE(netdev),
+ LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname),
+ NULL);
+
+ r = netdev_join(netdev, link, netdev_join_handler);
if (r < 0) {
- log_link_struct(link, LOG_WARNING,
- "MESSAGE=%-*s: could not join netdev '%s': %s",
- IFNAMSIZ,
- link->ifname, netdev->ifname,
- strerror(-r),
- NETDEVIF(netdev), NULL);
+ log_struct_errno(LOG_WARNING, r,
+ LOG_LINK_INTERFACE(link),
+ LOG_NETDEV_INTERFACE(netdev),
+ LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", netdev->ifname),
+ NULL);
link_enter_failed(link);
return r;
}
@@ -1298,39 +1479,16 @@ static int link_enter_join_netdev(Link *link) {
static int link_set_ipv4_forward(Link *link) {
const char *p = NULL;
- bool b;
int r;
- b = link_ipv4_forward_enabled(link);
+ if (link->network->ip_forward == ADDRESS_FAMILY_KERNEL)
+ return 0;
p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding");
- r = write_string_file_no_create(p, one_zero(b));
+ r = write_string_file_no_create(p, one_zero(link_ipv4_forward_enabled(link)));
if (r < 0)
log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname);
- if (b) {
- _cleanup_free_ char *buf = NULL;
-
- /* If IP forwarding is turned on for this interface,
- * then propagate this to the global setting. Given
- * that turning this on has side-effects on other
- * fields, we'll try to avoid doing this unless
- * necessary, hence check the previous value
- * first. Note that we never turn this option off
- * again, since all interfaces we manage do not do
- * forwarding anyway by default, and ownership rules
- * of this control are so unclear. */
-
- r = read_one_line_file("/proc/sys/net/ipv4/ip_forward", &buf);
- if (r < 0)
- log_link_warning_errno(link, r, "Cannot read /proc/sys/net/ipv4/ip_forward: %m");
- else if (!streq(buf, "1")) {
- r = write_string_file_no_create("/proc/sys/net/ipv4/ip_forward", "1");
- if (r < 0)
- log_link_warning_errno(link, r, "Cannot write /proc/sys/net/ipv4/ip_forward: %m");
- }
- }
-
return 0;
}
@@ -1338,6 +1496,13 @@ static int link_set_ipv6_forward(Link *link) {
const char *p = NULL;
int r;
+ /* Make this a NOP if IPv6 is not available */
+ if (!socket_ipv6_is_supported())
+ return 0;
+
+ if (link->network->ip_forward == ADDRESS_FAMILY_KERNEL)
+ return 0;
+
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding");
r = write_string_file_no_create(p, one_zero(link_ipv6_forward_enabled(link)));
if (r < 0)
@@ -1430,7 +1595,15 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
if (link->state != LINK_STATE_PENDING)
return 1;
- log_link_debug(link, "link state is up-to-date");
+ log_link_debug(link, "Link state is up-to-date");
+
+ r = link_new_bound_by_list(link);
+ if (r < 0)
+ return r;
+
+ r = link_handle_bound_by_list(link);
+ if (r < 0)
+ return r;
r = network_get(link->manager, link->udev_device, link->ifname,
&link->mac, &network);
@@ -1442,19 +1615,23 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
if (link->flags & IFF_LOOPBACK) {
if (network->link_local != ADDRESS_FAMILY_NO)
- log_link_debug(link, "ignoring link-local autoconfiguration for loopback link");
+ log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
if (network->dhcp != ADDRESS_FAMILY_NO)
- log_link_debug(link, "ignoring DHCP clients for loopback link");
+ log_link_debug(link, "Ignoring DHCP clients for loopback link");
if (network->dhcp_server)
- log_link_debug(link, "ignoring DHCP server for loopback link");
+ log_link_debug(link, "Ignoring DHCP server for loopback link");
}
r = network_apply(link->manager, network, link);
if (r < 0)
return r;
+ r = link_new_bound_to_list(link);
+ if (r < 0)
+ return r;
+
r = link_configure(link);
if (r < 0)
return r;
@@ -1519,6 +1696,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
Link *link = NULL;
uint16_t type;
_cleanup_address_free_ Address *address = NULL;
+ unsigned char flags;
Address *existing;
char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
const char *valid_str = NULL;
@@ -1538,13 +1716,16 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
r = sd_rtnl_message_get_type(message, &type);
if (r < 0) {
- log_warning("rtnl: could not get message type");
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+ log_warning("rtnl: received unexpected message type when processing address");
return 0;
}
r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
if (r < 0) {
- log_warning_errno(r, "rtnl: could not get ifindex: %m");
+ log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
@@ -1566,33 +1747,34 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
r = sd_rtnl_message_addr_get_family(message, &address->family);
if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
- log_link_warning(link, "rtnl: received address with invalid family, ignoring");
+ log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
return 0;
}
r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
if (r < 0) {
- log_link_warning(link, "rtnl: received address with invalid prefixlen, ignoring");
+ log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
return 0;
}
r = sd_rtnl_message_addr_get_scope(message, &address->scope);
if (r < 0) {
- log_link_warning(link, "rtnl: received address with invalid scope, ignoring");
+ log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
return 0;
}
- r = sd_rtnl_message_addr_get_flags(message, &address->flags);
+ r = sd_rtnl_message_addr_get_flags(message, &flags);
if (r < 0) {
- log_link_warning(link, "rtnl: received address with invalid flags, ignoring");
+ log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
return 0;
}
+ address->flags = flags;
switch (address->family) {
case AF_INET:
r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
if (r < 0) {
- log_link_warning(link, "rtnl: received address without valid address, ignoring");
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
return 0;
}
@@ -1601,7 +1783,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
case AF_INET6:
r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
if (r < 0) {
- log_link_warning(link, "rtnl: received address without valid address, ignoring");
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
return 0;
}
@@ -1612,7 +1794,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
}
if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
- log_link_warning(link, "could not print address");
+ log_link_warning(link, "Could not print address");
return 0;
}
@@ -1686,17 +1868,14 @@ int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
link = *ret;
- log_link_debug(link, "link %d added", link->ifindex);
+ log_link_debug(link, "Link %d added", link->ifindex);
if (detect_container(NULL) <= 0) {
/* not in a container, udev will be around */
sprintf(ifindex_str, "n%d", link->ifindex);
device = udev_device_new_from_device_id(m->udev, ifindex_str);
- if (!device) {
- log_link_warning(link,
- "could not find udev device: %m");
- return -errno;
- }
+ if (!device)
+ return log_link_warning_errno(link, errno, "Could not find udev device: %m");
if (udev_device_get_is_initialized(device) <= 0) {
/* not yet ready */
@@ -1732,6 +1911,10 @@ static int link_carrier_gained(Link *link) {
}
}
+ r = link_handle_bound_by_list(link);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -1746,6 +1929,10 @@ static int link_carrier_lost(Link *link) {
return r;
}
+ r = link_handle_bound_by_list(link);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -1763,7 +1950,7 @@ int link_carrier_reset(Link *link) {
if (r < 0)
return r;
- log_link_info(link, "reset carrier");
+ log_link_info(link, "Reset carrier");
}
return 0;
@@ -1783,18 +1970,28 @@ int link_update(Link *link, sd_rtnl_message *m) {
if (link->state == LINK_STATE_LINGER) {
link_ref(link);
- log_link_info(link, "link readded");
+ log_link_info(link, "Link readded");
link_set_state(link, LINK_STATE_ENSLAVING);
+
+ r = link_new_carrier_maps(link);
+ if (r < 0)
+ return r;
}
r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
if (r >= 0 && !streq(ifname, link->ifname)) {
- log_link_info(link, "renamed to %s", ifname);
+ log_link_info(link, "Renamed to %s", ifname);
+
+ link_free_carrier_maps(link);
free(link->ifname);
link->ifname = strdup(ifname);
if (!link->ifname)
return -ENOMEM;
+
+ r = link_new_carrier_maps(link);
+ if (r < 0)
+ return r;
}
r = sd_rtnl_message_read_u32(m, IFLA_MTU, &mtu);
@@ -1802,17 +1999,14 @@ int link_update(Link *link, sd_rtnl_message *m) {
link->mtu = mtu;
if (!link->original_mtu) {
link->original_mtu = mtu;
- log_link_debug(link, "saved original MTU: %"
- PRIu32, link->original_mtu);
+ log_link_debug(link, "Saved original MTU: %" PRIu32, link->original_mtu);
}
if (link->dhcp_client) {
r = sd_dhcp_client_set_mtu(link->dhcp_client,
link->mtu);
if (r < 0) {
- log_link_warning(link,
- "Could not update MTU in DHCP client: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not update MTU in DHCP client: %m");
return r;
}
}
@@ -1839,12 +2033,8 @@ int link_update(Link *link, sd_rtnl_message *m) {
if (link->ipv4ll) {
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
- if (r < 0) {
- log_link_warning(link,
- "Could not update MAC address in IPv4LL client: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
}
if (link->dhcp_client) {
@@ -1852,12 +2042,8 @@ int link_update(Link *link, sd_rtnl_message *m) {
(const uint8_t *) &link->mac,
sizeof (link->mac),
ARPHRD_ETHER);
- if (r < 0) {
- log_link_warning(link,
- "Could not update MAC address in DHCP client: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
}
if (link->dhcp6_client) {
@@ -1865,12 +2051,8 @@ int link_update(Link *link, sd_rtnl_message *m) {
(const uint8_t *) &link->mac,
sizeof (link->mac),
ARPHRD_ETHER);
- if (r < 0) {
- log_link_warning(link,
- "Could not update MAC address in DHCPv6 client: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
}
}
}
@@ -1885,13 +2067,13 @@ int link_update(Link *link, sd_rtnl_message *m) {
carrier_lost = had_carrier && !link_has_carrier(link);
if (carrier_gained) {
- log_link_info(link, "gained carrier");
+ log_link_info(link, "Gained carrier");
r = link_carrier_gained(link);
if (r < 0)
return r;
} else if (carrier_lost) {
- log_link_info(link, "lost carrier");
+ log_link_info(link, "Lost carrier");
r = link_carrier_lost(link);
if (r < 0)
@@ -1971,7 +2153,7 @@ int link_save(Link *link) {
r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0)
- return r;
+ goto fail;
fchmod(fileno(f), 0644);
@@ -2063,6 +2245,38 @@ int link_save(Link *link) {
llmnr_support_to_string(link->network->llmnr));
}
+ if (!hashmap_isempty(link->bound_to_links)) {
+ Link *carrier;
+ Iterator i;
+ bool space = false;
+
+ fputs("CARRIER_BOUND_TO=", f);
+ HASHMAP_FOREACH(carrier, link->bound_to_links, i) {
+ if (space)
+ fputc(' ', f);
+ fputs(carrier->ifname, f);
+ space = true;
+ }
+
+ fputs("\n", f);
+ }
+
+ if (!hashmap_isempty(link->bound_by_links)) {
+ Link *carrier;
+ Iterator i;
+ bool space = false;
+
+ fputs("CARRIER_BOUND_BY=", f);
+ HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
+ if (space)
+ fputc(' ', f);
+ fputs(carrier->ifname, f);
+ space = true;
+ }
+
+ fputs("\n", f);
+ }
+
if (link->dhcp_lease) {
assert(link->network);
@@ -2100,9 +2314,12 @@ int link_save(Link *link) {
return 0;
fail:
- log_link_error(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
- unlink(link->state_file);
- unlink(temp_path);
+ log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
+ (void) unlink(link->state_file);
+
+ if (temp_path)
+ (void) unlink(temp_path);
+
return r;
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index cec158e47d..c599952c45 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -82,9 +82,13 @@ struct Link {
sd_icmp6_nd *icmp6_router_discovery;
sd_dhcp6_client *dhcp6_client;
+ bool rtnl_extended_attrs;
sd_lldp *lldp;
char *lldp_file;
+
+ Hashmap *bound_by_links;
+ Hashmap *bound_to_links;
};
Link *link_unref(Link *link);
@@ -137,14 +141,18 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
/* Macros which append INTERFACE= to the message */
-#define log_link_full(link, level, error, fmt, ...) \
- log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", link->ifname, "%-*s: " fmt, IFNAMSIZ, link->ifname, ##__VA_ARGS__)
+#define log_link_full(link, level, error, ...) \
+ ({ \
+ Link *_l = (link); \
+ _l ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _l->ifname, ##__VA_ARGS__) : \
+ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
+ }) \
-#define log_link_debug(link, ...) log_link_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_link_info(link, ...) log_link_full(link, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_link_error(link, ...) log_link_full(link, LOG_ERR, 0, ##__VA_ARGS__)
+#define log_link_debug(link, ...) log_link_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_link_info(link, ...) log_link_full(link, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_link_error(link, ...) log_link_full(link, LOG_ERR, 0, ##__VA_ARGS__)
#define log_link_debug_errno(link, error, ...) log_link_full(link, LOG_DEBUG, error, ##__VA_ARGS__)
#define log_link_info_errno(link, error, ...) log_link_full(link, LOG_INFO, error, ##__VA_ARGS__)
@@ -152,7 +160,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
#define log_link_warning_errno(link, error, ...) log_link_full(link, LOG_WARNING, error, ##__VA_ARGS__)
#define log_link_error_errno(link, error, ...) log_link_full(link, LOG_ERR, error, ##__VA_ARGS__)
-#define log_link_struct(link, level, ...) log_struct(level, "INTERFACE=%s", link->ifname, __VA_ARGS__)
+#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__
+#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname
#define ADDRESS_FMT_VAL(address) \
be32toh((address).s_addr) >> 24, \
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index ce97ac0778..2cc53df4b1 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -27,13 +27,11 @@
#include "networkd.h"
#include "networkd-netdev.h"
#include "networkd-link.h"
-#include "network-internal.h"
#include "libudev-private.h"
#include "udev-util.h"
#include "rtnl-util.h"
#include "bus-util.h"
#include "def.h"
-#include "mkdir.h"
#include "virt.h"
#include "sd-rtnl.h"
@@ -107,12 +105,11 @@ static int manager_reset_all(Manager *m) {
return 0;
}
-static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
+static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
int b, r;
- assert(bus);
- assert(bus);
+ assert(message);
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
@@ -301,11 +298,14 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type: %m");
return 0;
+ } else if (type != RTM_NEWLINK && type != RTM_DELLINK) {
+ log_warning("rtnl: received unexpected message type when processing link");
+ return 0;
}
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
if (r < 0) {
- log_warning_errno(r, "rtnl: could not get ifindex: %m");
+ log_warning_errno(r, "rtnl: could not get ifindex from link: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
@@ -853,6 +853,8 @@ const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
return "ipv4";
if (b == ADDRESS_FAMILY_IPV6)
return "ipv6";
+ if (b == ADDRESS_FAMILY_KERNEL)
+ return "kernel";
return NULL;
}
@@ -872,6 +874,8 @@ AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
return ADDRESS_FAMILY_IPV4;
if (streq(s, "ipv6"))
return ADDRESS_FAMILY_IPV6;
+ if (streq(s, "kernel"))
+ return ADDRESS_FAMILY_KERNEL;
return _ADDRESS_FAMILY_BOOLEAN_INVALID;
}
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 88321ef84c..70df08a5e1 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -21,14 +21,45 @@
***/
#include <netinet/ether.h>
-#include <arpa/inet.h>
#include <linux/if_bonding.h>
#include "conf-parser.h"
#include "sd-rtnl.h"
+#include "rtnl-types.h"
#include "networkd-netdev-bond.h"
#include "missing.h"
+/*
+ * Number of seconds between instances where the bonding
+ * driver sends learning packets to each slaves peer switch
+ */
+#define LEARNING_PACKETS_INTERVAL_MIN_SEC (1 * USEC_PER_SEC)
+#define LEARNING_PACKETS_INTERVAL_MAX_SEC (0x7fffffff * USEC_PER_SEC)
+
+/* Number of IGMP membership reports to be issued after
+ * a failover event.
+ */
+#define RESEND_IGMP_MIN 0
+#define RESEND_IGMP_MAX 255
+#define RESEND_IGMP_DEFAULT 1
+
+/*
+ * Number of packets to transmit through a slave before
+ * moving to the next one.
+ */
+#define PACKETS_PER_SLAVE_MIN 0
+#define PACKETS_PER_SLAVE_MAX 65535
+#define PACKETS_PER_SLAVE_DEFAULT 1
+
+/*
+ * Number of peer notifications (gratuitous ARPs and
+ * unsolicited IPv6 Neighbor Advertisements) to be issued after a
+ * failover event.
+ */
+#define GRATUITOUS_ARP_MIN 0
+#define GRATUITOUS_ARP_MAX 255
+#define GRATUITOUS_ARP_DEFAULT 1
+
static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
[NETDEV_BOND_MODE_BALANCE_RR] = "balance-rr",
[NETDEV_BOND_MODE_ACTIVE_BACKUP] = "active-backup",
@@ -42,7 +73,6 @@ static const char* const bond_mode_table[_NETDEV_BOND_MODE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(bond_mode, BondMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_mode, bond_mode, BondMode, "Failed to parse bond mode");
-
static const char* const bond_xmit_hash_policy_table[_NETDEV_BOND_XMIT_HASH_POLICY_MAX] = {
[NETDEV_BOND_XMIT_HASH_POLICY_LAYER2] = "layer2",
[NETDEV_BOND_XMIT_HASH_POLICY_LAYER34] = "layer3+4",
@@ -65,6 +95,51 @@ static const char* const bond_lacp_rate_table[_NETDEV_BOND_LACP_RATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(bond_lacp_rate, BondLacpRate);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_lacp_rate, bond_lacp_rate, BondLacpRate, "Failed to parse bond lacp rate")
+static const char* const bond_ad_select_table[_NETDEV_BOND_AD_SELECT_MAX] = {
+ [NETDEV_BOND_AD_SELECT_STABLE] = "stable",
+ [NETDEV_BOND_AD_SELECT_BANDWIDTH] = "bandwidth",
+ [NETDEV_BOND_AD_SELECT_COUNT] = "count",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_ad_select, BondAdSelect);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_ad_select, bond_ad_select, BondAdSelect, "Failed to parse bond AD select");
+
+static const char* const bond_fail_over_mac_table[_NETDEV_BOND_FAIL_OVER_MAC_MAX] = {
+ [NETDEV_BOND_FAIL_OVER_MAC_NONE] = "none",
+ [NETDEV_BOND_FAIL_OVER_MAC_ACTIVE] = "active",
+ [NETDEV_BOND_FAIL_OVER_MAC_FOLLOW] = "follow",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_fail_over_mac, BondFailOverMac);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_fail_over_mac, bond_fail_over_mac, BondFailOverMac, "Failed to parse bond fail over MAC");
+
+static const char *const bond_arp_validate_table[_NETDEV_BOND_ARP_VALIDATE_MAX] = {
+ [NETDEV_BOND_ARP_VALIDATE_NONE] = "none",
+ [NETDEV_BOND_ARP_VALIDATE_ACTIVE]= "active",
+ [NETDEV_BOND_ARP_VALIDATE_BACKUP]= "backup",
+ [NETDEV_BOND_ARP_VALIDATE_ALL]= "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_validate, BondArpValidate);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_validate, bond_arp_validate, BondArpValidate, "Failed to parse bond arp validate");
+
+static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS_MAX] = {
+ [NETDEV_BOND_ARP_ALL_TARGETS_ANY] = "any",
+ [NETDEV_BOND_ARP_ALL_TARGETS_ALL] = "all",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
+
+static const char *bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
+ [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
+ [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
+ [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
+
static uint8_t bond_mode_to_kernel(BondMode mode) {
switch (mode) {
case NETDEV_BOND_MODE_BALANCE_RR:
@@ -105,7 +180,8 @@ static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
Bond *b = BOND(netdev);
- int r;
+ ArpIpTarget *target = NULL;
+ int r, i = 0;
assert(netdev);
assert(!link);
@@ -175,9 +251,230 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
}
}
+ if (b->arp_interval != 0) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_INTERVAL, b->arp_interval / USEC_PER_MSEC);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_ARP_INTERVAL attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if ((b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC) &&
+ (b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC)) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_LP_INTERVAL attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
+ b->mode == BOND_MODE_8023AD) {
+ r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_AD_SELECT attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
+ b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) {
+ r = sd_rtnl_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_FAIL_OVER_MAC attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->arp_validate != _NETDEV_BOND_ARP_VALIDATE_INVALID) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_VALIDATE, b->arp_validate);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_ARP_VALIDATE attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_ARP_VALIDATE attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->resend_igmp <= RESEND_IGMP_MAX) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_RESEND_IGMP, b->resend_igmp);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_RESEND_IGMP attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->packets_per_slave <= PACKETS_PER_SLAVE_MAX) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_PACKETS_PER_SLAVE, b->packets_per_slave);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_PACKETS_PER_SLAVE attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->num_grat_arp <= GRATUITOUS_ARP_MAX) {
+ r = sd_rtnl_message_append_u8(m, IFLA_BOND_NUM_PEER_NOTIF, b->num_grat_arp);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_NUM_PEER_NOTIF attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ if (b->min_links != 0) {
+ r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIN_LINKS, b->min_links);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_MIN_LINKS attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ r = sd_rtnl_message_append_u8(m, IFLA_BOND_ALL_SLAVES_ACTIVE, b->all_slaves_active);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_ALL_SLAVES_ACTIVE attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ if (b->arp_interval > 0) {
+ if (b->n_arp_ip_targets > 0) {
+
+ r = sd_rtnl_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %s",
+ strerror(-r));
+ return r;
+ }
+
+ LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
+ r = sd_rtnl_message_append_u32(m, i++, target->ip.in.s_addr);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ r = sd_rtnl_message_close_container(m);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %s",
+ strerror(-r));
+ return r;
+ }
+ }
+ }
+
return 0;
}
+int config_parse_arp_ip_target_address(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Bond *b = userdata;
+ const char *word, *state;
+ size_t l;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+ _cleanup_free_ ArpIpTarget *buffer = NULL;
+ _cleanup_free_ char *n = NULL;
+ int f;
+
+ n = strndup(word, l);
+ if (!n)
+ return -ENOMEM;
+
+ buffer = new0(ArpIpTarget, 1);
+ if (!buffer)
+ return -ENOMEM;
+
+ r = in_addr_from_string_auto(n, &f, &buffer->ip);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ return 0;
+ }
+
+ if (f != AF_INET) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ return 0;
+ }
+
+ LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
+ b->n_arp_ip_targets ++;
+
+ buffer = NULL;
+
+ if (b->n_arp_ip_targets > BOND_ARP_TARGETS_MAX)
+ break;
+ }
+
+ return 0;
+}
+
+static void bond_done(NetDev *netdev) {
+ ArpIpTarget *t = NULL, *n = NULL;
+ Bond *b = BOND(netdev);
+
+ assert(netdev);
+ assert(b);
+
+ LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
+ free(t);
+
+ b->arp_ip_targets = NULL;
+}
+
static void bond_init(NetDev *netdev) {
Bond *b = BOND(netdev);
@@ -187,11 +484,27 @@ static void bond_init(NetDev *netdev) {
b->mode = _NETDEV_BOND_MODE_INVALID;
b->xmit_hash_policy = _NETDEV_BOND_XMIT_HASH_POLICY_INVALID;
b->lacp_rate = _NETDEV_BOND_LACP_RATE_INVALID;
+ b->ad_select = _NETDEV_BOND_AD_SELECT_INVALID;
+ b->fail_over_mac = _NETDEV_BOND_FAIL_OVER_MAC_INVALID;
+ b->arp_validate = _NETDEV_BOND_ARP_VALIDATE_INVALID;
+ b->arp_all_targets = _NETDEV_BOND_ARP_ALL_TARGETS_INVALID;
+ b->primary_reselect = _NETDEV_BOND_PRIMARY_RESELECT_INVALID;
+
+ b->all_slaves_active = false;
+
+ b->resend_igmp = RESEND_IGMP_DEFAULT;
+ b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
+ b->num_grat_arp = GRATUITOUS_ARP_DEFAULT;
+ b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC;
+
+ LIST_HEAD_INIT(b->arp_ip_targets);
+ b->n_arp_ip_targets = 0;
}
const NetDevVTable bond_vtable = {
.object_size = sizeof(Bond),
.init = bond_init,
+ .done = bond_done,
.sections = "Match\0NetDev\0Bond\0",
.fill_message_create = netdev_bond_fill_message_create,
.create_type = NETDEV_CREATE_MASTER,
diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h
index c09af5fa52..32d1702d58 100644
--- a/src/network/networkd-netdev-bond.h
+++ b/src/network/networkd-netdev-bond.h
@@ -47,7 +47,6 @@ typedef enum BondXmitHashPolicy {
_NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
} BondXmitHashPolicy;
-
typedef enum BondLacpRate {
NETDEV_BOND_LACP_RATE_SLOW,
NETDEV_BOND_LACP_RATE_FAST,
@@ -55,16 +54,79 @@ typedef enum BondLacpRate {
_NETDEV_BOND_LACP_RATE_INVALID = -1,
} BondLacpRate;
+typedef enum BondAdSelect {
+ NETDEV_BOND_AD_SELECT_STABLE,
+ NETDEV_BOND_AD_SELECT_BANDWIDTH,
+ NETDEV_BOND_AD_SELECT_COUNT,
+ _NETDEV_BOND_AD_SELECT_MAX,
+ _NETDEV_BOND_AD_SELECT_INVALID = -1,
+} BondAdSelect;
+
+typedef enum BondFailOverMac {
+ NETDEV_BOND_FAIL_OVER_MAC_NONE,
+ NETDEV_BOND_FAIL_OVER_MAC_ACTIVE,
+ NETDEV_BOND_FAIL_OVER_MAC_FOLLOW,
+ _NETDEV_BOND_FAIL_OVER_MAC_MAX,
+ _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1,
+} BondFailOverMac;
+
+typedef enum BondArpValidate {
+ NETDEV_BOND_ARP_VALIDATE_NONE,
+ NETDEV_BOND_ARP_VALIDATE_ACTIVE,
+ NETDEV_BOND_ARP_VALIDATE_BACKUP,
+ NETDEV_BOND_ARP_VALIDATE_ALL,
+ _NETDEV_BOND_ARP_VALIDATE_MAX,
+ _NETDEV_BOND_ARP_VALIDATE_INVALID = -1,
+} BondArpValidate;
+
+typedef enum BondArpAllTargets {
+ NETDEV_BOND_ARP_ALL_TARGETS_ANY,
+ NETDEV_BOND_ARP_ALL_TARGETS_ALL,
+ _NETDEV_BOND_ARP_ALL_TARGETS_MAX,
+ _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1,
+} BondArpAllTargets;
+
+typedef enum BondPrimaryReselect {
+ NETDEV_BOND_PRIMARY_RESELECT_ALWAYS,
+ NETDEV_BOND_PRIMARY_RESELECT_BETTER,
+ NETDEV_BOND_PRIMARY_RESELECT_FAILURE,
+ _NETDEV_BOND_PRIMARY_RESELECT_MAX,
+ _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
+} BondPrimaryReselect;
+
+typedef struct ArpIpTarget {
+ union in_addr_union ip;
+
+ LIST_FIELDS(struct ArpIpTarget, arp_ip_target);
+} ArpIpTarget;
+
struct Bond {
NetDev meta;
BondMode mode;
BondXmitHashPolicy xmit_hash_policy;
BondLacpRate lacp_rate;
+ BondAdSelect ad_select;
+ BondFailOverMac fail_over_mac;
+ BondArpValidate arp_validate;
+ BondArpAllTargets arp_all_targets;
+ BondPrimaryReselect primary_reselect;
+
+ bool all_slaves_active;
+
+ unsigned resend_igmp;
+ unsigned packets_per_slave;
+ unsigned num_grat_arp;
+ unsigned min_links;
usec_t miimon;
usec_t updelay;
usec_t downdelay;
+ usec_t arp_interval;
+ usec_t lp_interval;
+
+ int n_arp_ip_targets;
+ ArpIpTarget *arp_ip_targets;
};
extern const NetDevVTable bond_vtable;
@@ -78,6 +140,27 @@ BondXmitHashPolicy bond_xmit_hash_policy_from_string(const char *d) _pure_;
const char *bond_lacp_rate_to_string(BondLacpRate d) _const_;
BondLacpRate bond_lacp_rate_from_string(const char *d) _pure_;
+const char *bond_fail_over_mac_to_string(BondFailOverMac d) _const_;
+BondFailOverMac bond_fail_over_mac_from_string(const char *d) _pure_;
+
+const char *bond_ad_select_to_string(BondAdSelect d) _const_;
+BondAdSelect bond_ad_select_from_string(const char *d) _pure_;
+
+const char *bond_arp_validate_to_string(BondArpValidate d) _const_;
+BondArpValidate bond_arp_validate_from_string(const char *d) _pure_;
+
+const char *bond_arp_all_targets_to_string(BondArpAllTargets d) _const_;
+BondArpAllTargets bond_arp_all_targets_from_string(const char *d) _pure_;
+
+const char *bond_primary_reselect_to_string(BondPrimaryReselect d) _const_;
+BondPrimaryReselect bond_primary_reselect_from_string(const char *d) _pure_;
+
int config_parse_bond_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bond_xmit_hash_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bond_lacp_rate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bond_ad_select(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bond_fail_over_mac(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bond_arp_validate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bond_arp_all_targets(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bond_primary_reselect(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_arp_ip_target_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 91b7051a06..fd6af7e99b 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -20,11 +20,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include "sd-rtnl.h"
#include "networkd-netdev-bridge.h"
#include "missing.h"
diff --git a/src/network/networkd-netdev-dummy.c b/src/network/networkd-netdev-dummy.c
index 01c10a2d73..bb246a2be0 100644
--- a/src/network/networkd-netdev-dummy.c
+++ b/src/network/networkd-netdev-dummy.c
@@ -20,12 +20,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <linux/veth.h>
-#include "sd-rtnl.h"
#include "networkd-netdev-dummy.h"
const NetDevVTable dummy_vtable = {
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 963c47c3e5..66ed2e013c 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -18,49 +18,65 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host)
-Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel)
-Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch)
-NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
-NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
-NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
-NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu)
-NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac)
-VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id)
-MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
-IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
-Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local)
-Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote)
-Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
-Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
-Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
-Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode)
-Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
-Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
-VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
-VXLAN.Group, config_parse_vxlan_group_address, 0, offsetof(VxLan, group)
-VXLAN.TOS, config_parse_unsigned, 0, offsetof(VxLan, tos)
-VXLAN.TTL, config_parse_unsigned, 0, offsetof(VxLan, ttl)
-VXLAN.MacLearning, config_parse_bool, 0, offsetof(VxLan, learning)
-VXLAN.ARPProxy, config_parse_bool, 0, offsetof(VxLan, arp_proxy)
-VXLAN.L2MissNotification, config_parse_bool, 0, offsetof(VxLan, l2miss)
-VXLAN.L3MissNotification, config_parse_bool, 0, offsetof(VxLan, l3miss)
-VXLAN.RouteShortCircuit, config_parse_bool, 0, offsetof(VxLan, route_short_circuit)
-VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing)
-Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
-Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
-Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
-Tun.User, config_parse_string, 0, offsetof(TunTap, user_name)
-Tun.Group, config_parse_string, 0, offsetof(TunTap, group_name)
-Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
-Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
-Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
-Tap.User, config_parse_string, 0, offsetof(TunTap, user_name)
-Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name)
-Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
-Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
-Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)
-Bond.MIIMonitorSec, config_parse_sec, 0, offsetof(Bond, miimon)
-Bond.UpDelaySec, config_parse_sec, 0, offsetof(Bond, updelay)
-Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
+Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host)
+Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel)
+Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch)
+NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
+NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
+NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
+NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu)
+NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac)
+VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id)
+MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
+IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
+Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local)
+Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote)
+Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
+Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
+Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
+Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode)
+Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
+Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
+VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
+VXLAN.Group, config_parse_vxlan_group_address, 0, offsetof(VxLan, group)
+VXLAN.TOS, config_parse_unsigned, 0, offsetof(VxLan, tos)
+VXLAN.TTL, config_parse_unsigned, 0, offsetof(VxLan, ttl)
+VXLAN.MacLearning, config_parse_bool, 0, offsetof(VxLan, learning)
+VXLAN.ARPProxy, config_parse_bool, 0, offsetof(VxLan, arp_proxy)
+VXLAN.L2MissNotification, config_parse_bool, 0, offsetof(VxLan, l2miss)
+VXLAN.L3MissNotification, config_parse_bool, 0, offsetof(VxLan, l3miss)
+VXLAN.RouteShortCircuit, config_parse_bool, 0, offsetof(VxLan, route_short_circuit)
+VXLAN.UDPCheckSum, config_parse_bool, 0, offsetof(VxLan, udpcsum)
+VXLAN.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumrx)
+VXLAN.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumtx)
+VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing)
+Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
+Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
+Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
+Tun.User, config_parse_string, 0, offsetof(TunTap, user_name)
+Tun.Group, config_parse_string, 0, offsetof(TunTap, group_name)
+Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
+Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
+Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
+Tap.User, config_parse_string, 0, offsetof(TunTap, user_name)
+Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name)
+Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
+Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
+Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)
+Bond.AdSelect, config_parse_bond_ad_select, 0, offsetof(Bond, ad_select)
+Bond.FailOverMACPolicy, config_parse_bond_fail_over_mac, 0, offsetof(Bond, fail_over_mac)
+Bond.ARPIPTargets, config_parse_arp_ip_target_address, 0, 0
+Bond.ARPValidate, config_parse_bond_arp_validate, 0, offsetof(Bond, arp_validate)
+Bond.ARPAllTargets, config_parse_bond_arp_all_targets, 0, offsetof(Bond, arp_all_targets)
+Bond.PrimaryReselectPolicy, config_parse_bond_primary_reselect, 0, offsetof(Bond, primary_reselect)
+Bond.ResendIGMP, config_parse_unsigned, 0, offsetof(Bond, resend_igmp)
+Bond.PacketsPerSlave, config_parse_unsigned, 0, offsetof(Bond, packets_per_slave)
+Bond.GratuitousARP, config_parse_unsigned, 0, offsetof(Bond, num_grat_arp)
+Bond.AllSlavesActive, config_parse_unsigned, 0, offsetof(Bond, all_slaves_active)
+Bond.MinLinks, config_parse_unsigned, 0, offsetof(Bond, min_links)
+Bond.MIIMonitorSec, config_parse_sec, 0, offsetof(Bond, miimon)
+Bond.UpDelaySec, config_parse_sec, 0, offsetof(Bond, updelay)
+Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
+Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval)
+Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval)
diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/networkd-netdev-ipvlan.c
index 9a7c280c6b..5189000c1f 100644
--- a/src/network/networkd-netdev-ipvlan.c
+++ b/src/network/networkd-netdev-ipvlan.c
@@ -20,12 +20,9 @@
***/
#include <net/if.h>
-#include <linux/if_link.h>
#include "networkd-netdev-ipvlan.h"
-#include "network-internal.h"
#include "conf-parser.h"
-#include "list.h"
static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
[NETDEV_IPVLAN_MODE_L2] = "L2",
diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c
index 198fb575ee..5f41f1c865 100644
--- a/src/network/networkd-netdev-macvlan.c
+++ b/src/network/networkd-netdev-macvlan.c
@@ -22,9 +22,7 @@
#include <net/if.h>
#include "networkd-netdev-macvlan.h"
-#include "network-internal.h"
#include "conf-parser.h"
-#include "list.h"
static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
[NETDEV_MACVLAN_MODE_PRIVATE] = "private",
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index e95082d119..8af4be4974 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/ip.h>
@@ -29,7 +28,6 @@
#include "sd-rtnl.h"
#include "networkd-netdev-tunnel.h"
#include "networkd-link.h"
-#include "network-internal.h"
#include "util.h"
#include "missing.h"
#include "conf-parser.h"
@@ -56,44 +54,24 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
assert(t->family == AF_INET);
r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_REMOTE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_TTL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
return r;
}
@@ -109,44 +87,24 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
assert(t->family == AF_INET);
r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_REMOTE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_TTL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
return r;
}
@@ -158,9 +116,9 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
assert(netdev);
if (netdev->kind == NETDEV_KIND_GRE)
- t = GRE(netdev);
+ t = GRE(netdev);
else
- t = GRETAP(netdev);
+ t = GRETAP(netdev);
assert(t);
assert(t->family == AF_INET);
@@ -168,52 +126,28 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
assert(m);
r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_REMOTE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_TTL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, t->tos);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_TOS attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_PMTUDISC attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
return r;
}
@@ -225,9 +159,9 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
assert(netdev);
if (netdev->kind == NETDEV_KIND_IP6GRE)
- t = IP6GRE(netdev);
+ t = IP6GRE(netdev);
else
- t = IP6GRETAP(netdev);
+ t = IP6GRETAP(netdev);
assert(t);
assert(t->family == AF_INET6);
@@ -235,36 +169,20 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
assert(m);
r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
r = sd_rtnl_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
r = sd_rtnl_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_REMOTE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_GRE_TTL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
return r;
}
@@ -280,28 +198,41 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
assert(t->family == AF_INET);
r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_REMOTE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
+
+ return r;
+}
+
+static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
+ Tunnel *t = VTI6(netdev);
+ int r;
+
+ assert(netdev);
+ assert(link);
+ assert(m);
+ assert(t);
+ assert(t->family == AF_INET6);
+
+ r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+
+ r = sd_rtnl_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
+
+ r = sd_rtnl_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
return r;
}
@@ -318,36 +249,20 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
assert(t->family == AF_INET6);
r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
r = sd_rtnl_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_REMOTE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_TTL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
switch (t->ip6tnl_mode) {
case NETDEV_IP6_TNL_MODE_IP6IP6:
@@ -363,12 +278,8 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_rtnl
}
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IPTUN_MODE attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_MODE attribute: %m");
return r;
}
@@ -401,6 +312,9 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
case NETDEV_KIND_VTI:
t = VTI(netdev);
break;
+ case NETDEV_KIND_VTI6:
+ t = VTI6(netdev);
+ break;
case NETDEV_KIND_IP6TNL:
t = IP6TNL(netdev);
break;
@@ -411,13 +325,13 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
assert(t);
if (t->remote.in.s_addr == INADDR_ANY) {
- log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
- return -EINVAL;
+ log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
+ return -EINVAL;
}
if (t->family != AF_INET && t->family != AF_INET6) {
- log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
- return -EINVAL;
+ log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
+ return -EINVAL;
}
if (netdev->kind == NETDEV_KIND_IP6TNL) {
@@ -485,9 +399,15 @@ static void sit_init(NetDev *n) {
}
static void vti_init(NetDev *n) {
- Tunnel *t = VTI(n);
+ Tunnel *t;
assert(n);
+
+ if (n->kind == NETDEV_KIND_VTI)
+ t = VTI(n);
+ else
+ t = VTI6(n);
+
assert(t);
t->pmtudisc = true;
@@ -561,6 +481,15 @@ const NetDevVTable vti_vtable = {
.config_verify = netdev_tunnel_verify,
};
+const NetDevVTable vti6_vtable = {
+ .object_size = sizeof(Tunnel),
+ .init = vti_init,
+ .sections = "Match\0NetDev\0Tunnel\0",
+ .fill_message_create = netdev_vti6_fill_message_create,
+ .create_type = NETDEV_CREATE_STACKED,
+ .config_verify = netdev_tunnel_verify,
+};
+
const NetDevVTable gre_vtable = {
.object_size = sizeof(Tunnel),
.init = gre_init,
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index 453d73c596..88f57ac105 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -55,6 +55,7 @@ struct Tunnel {
extern const NetDevVTable ipip_vtable;
extern const NetDevVTable sit_vtable;
extern const NetDevVTable vti_vtable;
+extern const NetDevVTable vti6_vtable;
extern const NetDevVTable gre_vtable;
extern const NetDevVTable gretap_vtable;
extern const NetDevVTable ip6gre_vtable;
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 4f449aea48..4e974927cb 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -108,7 +108,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
}
}
- if(t->group_name) {
+ if (t->group_name) {
group = t->group_name;
@@ -173,15 +173,11 @@ static void tuntap_done(NetDev *netdev) {
static int tuntap_verify(NetDev *netdev, const char *filename) {
assert(netdev);
- if (netdev->mtu) {
- log_warning_netdev(netdev, "MTU configured for %s, ignoring",
- netdev_kind_to_string(netdev->kind));
- }
+ if (netdev->mtu)
+ log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
- if (netdev->mac) {
- log_warning_netdev(netdev, "MAC configured for %s, ignoring",
- netdev_kind_to_string(netdev->kind));
- }
+ if (netdev->mac)
+ log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
return 0;
}
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index 251cf92aec..9e9e1225e7 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
-#include <arpa/inet.h>
#include <net/if.h>
#include <linux/veth.h>
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c
index 665559f895..0ed024b41d 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/networkd-netdev-vlan.c
@@ -22,8 +22,6 @@
#include <net/if.h>
#include "networkd-netdev-vlan.h"
-#include "network-internal.h"
-#include "list.h"
static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *req) {
VLan *v = VLAN(netdev);
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index d5128cb7c0..e2c2b108b9 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
-#include <arpa/inet.h>
#include <net/if.h>
#include "sd-rtnl.h"
@@ -135,6 +133,30 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
}
}
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_UDP_CSUM attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, v->udp6zerocsumtx);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_TX attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, v->udp6zerocsumrx);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_RX attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
return r;
}
@@ -199,6 +221,9 @@ static void vxlan_init(NetDev *netdev) {
v->id = VXLAN_VID_MAX + 1;
v->learning = true;
+ v->udpcsum = false;
+ v->udp6zerocsumtx = false;
+ v->udp6zerocsumrx = false;
}
const NetDevVTable vxlan_vtable = {
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index 6339af9add..fe5254e91f 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -47,6 +47,9 @@ struct VxLan {
bool route_short_circuit;
bool l2miss;
bool l3miss;
+ bool udpcsum;
+ bool udp6zerocsumtx;
+ bool udp6zerocsumrx;
};
extern const NetDevVTable vxlan_vtable;
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 8119205dde..66fd0fac0a 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -24,7 +24,6 @@
#include "networkd-netdev.h"
#include "networkd-link.h"
#include "network-internal.h"
-#include "path-util.h"
#include "conf-files.h"
#include "conf-parser.h"
#include "list.h"
@@ -44,6 +43,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
[NETDEV_KIND_SIT] = &sit_vtable,
[NETDEV_KIND_VTI] = &vti_vtable,
+ [NETDEV_KIND_VTI6] = &vti6_vtable,
[NETDEV_KIND_VETH] = &veth_vtable,
[NETDEV_KIND_DUMMY] = &dummy_vtable,
[NETDEV_KIND_TUN] = &tun_vtable,
@@ -66,6 +66,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_SIT] = "sit",
[NETDEV_KIND_VETH] = "veth",
[NETDEV_KIND_VTI] = "vti",
+ [NETDEV_KIND_VTI6] = "vti6",
[NETDEV_KIND_DUMMY] = "dummy",
[NETDEV_KIND_TUN] = "tun",
[NETDEV_KIND_TAP] = "tap",
@@ -191,34 +192,21 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_hand
assert(link);
assert(callback);
- r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
- RTM_SETLINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not allocate RTM_SETLINK message: %s",
- strerror(-r));
- return r;
- }
+ r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_MASTER attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not send rtnetlink message: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error(netdev, "Could not send rtnetlink message: %m");
link_ref(link);
- log_netdev_debug(netdev, "enslaving link '%s'", link->ifname);
+ log_netdev_debug(netdev, "Enslaving link '%s'", link->ifname);
return 0;
}
@@ -235,7 +223,7 @@ static int netdev_enter_ready(NetDev *netdev) {
netdev->state = NETDEV_STATE_READY;
- log_info_netdev(netdev, "netdev ready");
+ log_netdev_info(netdev, "netdev ready");
LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
/* enslave the links that were attempted to be enslaved before the
@@ -261,15 +249,15 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
r = sd_rtnl_message_get_errno(m);
if (r == -EEXIST)
- log_netdev_debug(netdev, "netdev exists, using existing");
+ log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
else if (r < 0) {
- log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
+ log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
netdev_drop(netdev);
return 1;
}
- log_netdev_debug(netdev, "created");
+ log_netdev_debug(netdev, "Created");
return 1;
}
@@ -298,8 +286,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callbac
LIST_PREPEND(callbacks, netdev->callbacks, cb);
- log_netdev_debug(netdev, "will enslave '%s', when reday",
- link->ifname);
+ log_netdev_debug(netdev, "Will enslave '%s', when ready", link->ifname);
}
return 0;
@@ -316,25 +303,23 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
assert(message);
r = sd_rtnl_message_get_type(message, &type);
- if (r < 0) {
- log_netdev_error(netdev, "Could not get rtnl message type");
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m");
if (type != RTM_NEWLINK) {
- log_netdev_error(netdev, "Can not set ifindex from unexpected rtnl message type");
+ log_netdev_error(netdev, "Cannot set ifindex from unexpected rtnl message type.");
return -EINVAL;
}
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
if (r < 0) {
- log_netdev_error(netdev, "Could not get ifindex: %s", strerror(-r));
+ log_netdev_error_errno(netdev, r, "Could not get ifindex: %m");
netdev_enter_failed(netdev);
return r;
} else if (ifindex <= 0) {
log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
netdev_enter_failed(netdev);
- return r;
+ return -EINVAL;
}
if (netdev->ifindex > 0) {
@@ -349,35 +334,26 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
}
r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
- if (r < 0) {
- log_netdev_error(netdev, "Could not get IFNAME");
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not get IFNAME: %m");
if (!streq(netdev->ifname, received_name)) {
- log_netdev_error(netdev, "Received newlink with wrong IFNAME %s",
- received_name);
+ log_netdev_error(netdev, "Received newlink with wrong IFNAME %s", received_name);
netdev_enter_failed(netdev);
return r;
}
r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
- if (r < 0) {
- log_netdev_error(netdev, "Could not get LINKINFO");
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
- if (r < 0) {
- log_netdev_error(netdev, "Could not get KIND");
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
r = sd_rtnl_message_exit_container(message);
- if (r < 0) {
- log_netdev_error(netdev, "Could not exit container");
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
if (netdev->kind == NETDEV_KIND_TAP)
/* the kernel does not distinguish between tun and tap */
@@ -469,72 +445,43 @@ static int netdev_create(NetDev *netdev, Link *link,
if (r < 0)
return r;
- log_netdev_debug(netdev, "created");
+ log_netdev_debug(netdev, "Created");
} else {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not allocate RTM_NEWLINK message: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_IFNAME, attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
if (netdev->mac) {
r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_ADDRESS attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
}
if (netdev->mtu) {
r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_MTU attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
}
if (link) {
r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_LINK attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINK attribute: %m");
}
r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_LINKINFO attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
- r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
- netdev_kind_to_string(netdev->kind));
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_INFO_DATA attribute: %s",
- strerror(-r));
- return r;
- }
+ r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
if (NETDEV_VTABLE(netdev)->fill_message_create) {
r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
@@ -543,50 +490,30 @@ static int netdev_create(NetDev *netdev, Link *link,
}
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_LINKINFO attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not append IFLA_LINKINFO attribute: %s",
- strerror(-r));
- return r;
- }
-
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
if (link) {
- r = sd_rtnl_call_async(netdev->manager->rtnl, m,
- callback, link, 0, NULL);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not send rtnetlink message: %s",
- strerror(-r));
- return r;
- }
+ r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
link_ref(link);
} else {
- r = sd_rtnl_call_async(netdev->manager->rtnl, m,
- netdev_create_handler, netdev, 0,
- NULL);
- if (r < 0) {
- log_netdev_error(netdev,
- "Could not send rtnetlink message: %s",
- strerror(-r));
- return r;
- }
+ r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
netdev_ref(netdev);
}
netdev->state = NETDEV_STATE_CREATING;
- log_netdev_debug(netdev, "creating");
+ log_netdev_debug(netdev, "Creating");
}
return 0;
@@ -710,11 +637,8 @@ static int netdev_load_one(Manager *manager, const char *filename) {
if (!netdev->mac) {
r = netdev_get_mac(netdev->ifname, &netdev->mac);
- if (r < 0) {
- log_error("Failed to generate predictable MAC address for %s",
- netdev->ifname);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
}
r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
@@ -743,8 +667,9 @@ static int netdev_load_one(Manager *manager, const char *filename) {
}
int netdev_load(Manager *manager) {
+ _cleanup_strv_free_ char **files = NULL;
NetDev *netdev;
- char **files, **f;
+ char **f;
int r;
assert(manager);
@@ -762,7 +687,5 @@ int netdev_load(Manager *manager) {
return r;
}
- strv_free(files);
-
return 0;
}
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 3756b1e5a7..1ded495e4a 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -22,10 +22,7 @@
#pragma once
#include "networkd.h"
-#include "hashmap.h"
#include "list.h"
-#include "set.h"
-#include "in-addr-util.h"
typedef struct NetDevVTable NetDevVTable;
@@ -53,6 +50,7 @@ typedef enum NetDevKind {
NETDEV_KIND_SIT,
NETDEV_KIND_VETH,
NETDEV_KIND_VTI,
+ NETDEV_KIND_VTI6,
NETDEV_KIND_IP6TNL,
NETDEV_KIND_DUMMY,
NETDEV_KIND_TUN,
@@ -172,6 +170,7 @@ DEFINE_CAST(IP6GRE, Tunnel);
DEFINE_CAST(IP6GRETAP, Tunnel);
DEFINE_CAST(SIT, Tunnel);
DEFINE_CAST(VTI, Tunnel);
+DEFINE_CAST(VTI6, Tunnel);
DEFINE_CAST(IP6TNL, Tunnel);
DEFINE_CAST(VETH, Veth);
DEFINE_CAST(DUMMY, Dummy);
@@ -203,13 +202,24 @@ const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsign
/* Macros which append INTERFACE= to the message */
-#define log_full_netdev(level, netdev, fmt, ...) log_object_internal(level, 0, __FILE__, __LINE__, __func__, "INTERFACE=", netdev->ifname, "%-*s: " fmt, IFNAMSIZ, netdev->ifname, ##__VA_ARGS__)
-#define log_netdev_debug(netdev, ...) log_full_netdev(LOG_DEBUG, netdev, ##__VA_ARGS__)
-#define log_info_netdev(netdev, ...) log_full_netdev(LOG_INFO, netdev, ##__VA_ARGS__)
-#define log_notice_netdev(netdev, ...) log_full_netdev(LOG_NOTICE, netdev, ##__VA_ARGS__)
-#define log_warning_netdev(netdev, ...) log_full_netdev(LOG_WARNING, netdev,## __VA_ARGS__)
-#define log_netdev_error(netdev, ...) log_full_netdev(LOG_ERR, netdev, ##__VA_ARGS__)
-
-#define log_struct_netdev(level, netdev, ...) log_struct(level, "INTERFACE=%s", netdev->ifname, __VA_ARGS__)
-
-#define NETDEVIF(netdev) "INTERFACE=%s", netdev->ifname
+#define log_netdev_full(netdev, level, error, ...) \
+ ({ \
+ NetDev *_n = (netdev); \
+ _n ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _n->ifname, ##__VA_ARGS__) : \
+ log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
+ })
+
+#define log_netdev_debug(netdev, ...) log_netdev_full(netdev, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_netdev_info(netdev, ...) log_netdev_full(netdev, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_netdev_notice(netdev, ...) log_netdev_full(netdev, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_netdev_warning(netdev, ...) log_netdev_full(netdev, LOG_WARNING, 0, ## __VA_ARGS__)
+#define log_netdev_error(netdev, ...) log_netdev_full(netdev, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_netdev_debug_errno(netdev, error, ...) log_netdev_full(netdev, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_netdev_info_errno(netdev, error, ...) log_netdev_full(netdev, LOG_INFO, error, ##__VA_ARGS__)
+#define log_netdev_notice_errno(netdev, error, ...) log_netdev_full(netdev, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_netdev_warning_errno(netdev, error, ...) log_netdev_full(netdev, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_netdev_error_errno(netdev, error, ...) log_netdev_full(netdev, LOG_ERR, error, ##__VA_ARGS__)
+
+#define LOG_NETDEV_MESSAGE(netdev, fmt, ...) "MESSAGE=%s: " fmt, (netdev)->ifname, ##__VA_ARGS__
+#define LOG_NETDEV_INTERFACE(netdev) "INTERFACE=%s", (netdev)->ifname
diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c
index 36b40d32b9..b5f8f5cfb2 100644
--- a/src/network/networkd-network-bus.c
+++ b/src/network/networkd-network-bus.c
@@ -19,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "bus-util.h"
-#include "bus-label.h"
#include "strv.h"
#include "networkd.h"
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index fc277df949..8abf5bcf2e 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -48,6 +48,7 @@ Network.LLMNR, config_parse_llmnr, 0,
Network.NTP, config_parse_strv, 0, offsetof(Network, ntp)
Network.IPForward, config_parse_address_family_boolean,0, offsetof(Network, ip_forward)
Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
+Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
Address.Broadcast, config_parse_broadcast, 0, 0
@@ -57,7 +58,9 @@ Route.Destination, config_parse_destination, 0,
Route.Source, config_parse_destination, 0, 0
Route.Metric, config_parse_route_priority, 0, 0
Route.Scope, config_parse_route_scope, 0, 0
+DHCP.ClientIdentifier, config_parse_dhcp_client_identifier,0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
+DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp)
DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 35ac064cf6..5947084106 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -22,10 +22,10 @@
#include <ctype.h>
#include <net/if.h>
-#include "path-util.h"
#include "conf-files.h"
#include "conf-parser.h"
#include "util.h"
+#include "hostname-util.h"
#include "networkd.h"
#include "networkd-netdev.h"
#include "networkd-link.h"
@@ -104,6 +104,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->dhcp_routes = true;
network->dhcp_sendhost = true;
network->dhcp_route_metric = DHCP_ROUTE_METRIC;
+ network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
network->llmnr = LLMNR_SUPPORT_YES;
@@ -209,6 +210,7 @@ void network_free(Network *network) {
strv_free(network->ntp);
strv_free(network->dns);
strv_free(network->domains);
+ strv_free(network->bind_carrier);
netdev_unref(network->bridge);
@@ -271,29 +273,39 @@ int network_get(Manager *manager, struct udev_device *device,
const char *ifname, const struct ether_addr *address,
Network **ret) {
Network *network;
+ struct udev_device *parent;
+ const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
assert(manager);
assert(ret);
+ if (device) {
+ path = udev_device_get_property_value(device, "ID_PATH");
+
+ parent = udev_device_get_parent(device);
+ if (parent)
+ parent_driver = udev_device_get_driver(parent);
+
+ driver = udev_device_get_property_value(device, "ID_NET_DRIVER");
+
+ devtype = udev_device_get_devtype(device);
+ }
+
LIST_FOREACH(networks, network, manager->networks) {
if (net_match_config(network->match_mac, network->match_path,
network->match_driver, network->match_type,
network->match_name, network->match_host,
network->match_virt, network->match_kernel,
network->match_arch,
- address,
- udev_device_get_property_value(device, "ID_PATH"),
- udev_device_get_driver(udev_device_get_parent(device)),
- udev_device_get_property_value(device, "ID_NET_DRIVER"),
- udev_device_get_devtype(device),
- ifname)) {
- if (network->match_name) {
+ address, path, parent_driver, driver,
+ devtype, ifname)) {
+ if (network->match_name && device) {
const char *attr;
uint8_t name_assign_type = NET_NAME_UNKNOWN;
attr = udev_device_get_sysattr_value(device, "name_assign_type");
if (attr)
- (void)safe_atou8(attr, &name_assign_type);
+ (void) safe_atou8(attr, &name_assign_type);
if (name_assign_type == NET_NAME_ENUM)
log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
@@ -413,8 +425,8 @@ int config_parse_netdev(const char *unit,
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Can not add VLAN '%s' to network: %s",
- rvalue, strerror(-r));
+ "Can not add VLAN '%s' to network: %m",
+ rvalue);
return 0;
}
@@ -490,8 +502,7 @@ int config_parse_tunnel(const char *unit,
r = netdev_get(network->manager, rvalue, &netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Tunnel is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
return 0;
}
@@ -502,6 +513,7 @@ int config_parse_tunnel(const char *unit,
netdev->kind != NETDEV_KIND_IP6GRE &&
netdev->kind != NETDEV_KIND_IP6GRETAP &&
netdev->kind != NETDEV_KIND_VTI &&
+ netdev->kind != NETDEV_KIND_VTI6 &&
netdev->kind != NETDEV_KIND_IP6TNL
) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
@@ -511,9 +523,7 @@ int config_parse_tunnel(const char *unit,
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Can not add VLAN '%s' to network: %s",
- rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
return 0;
}
@@ -600,6 +610,14 @@ int config_parse_dhcp(
return 0;
}
+static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
+ [DHCP_CLIENT_ID_MAC] = "mac",
+ [DHCP_CLIENT_ID_DUID] = "duid"
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
+
static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = {
[LLMNR_SUPPORT_NO] = "no",
[LLMNR_SUPPORT_YES] = "yes",
@@ -674,13 +692,13 @@ int config_parse_ipv6token(
r = in_addr_from_string(AF_INET6, rvalue, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
return 0;
}
r = in_addr_is_null(AF_INET6, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index c2d1ffca25..7f110a5217 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -19,15 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/if.h>
#include "networkd.h"
#include "networkd-link.h"
-#include "utf8.h"
#include "util.h"
#include "conf-parser.h"
-#include "network-internal.h"
int route_new_static(Network *network, unsigned section, Route **ret) {
_cleanup_route_free_ Route *route = NULL;
diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c
index e091b20ed9..341bcae3fb 100644
--- a/src/network/networkd-wait-online-link.c
+++ b/src/network/networkd-wait-online-link.c
@@ -20,10 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <net/if.h>
#include "sd-network.h"
-#include "strv.h"
#include "networkd-wait-online-link.h"
diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c
index cafe110e50..1c997a50a4 100644
--- a/src/network/networkd-wait-online-manager.c
+++ b/src/network/networkd-wait-online-manager.c
@@ -25,7 +25,6 @@
#include "rtnl-util.h"
-#include "network-util.h"
#include "network-internal.h"
#include "networkd-wait-online-link.h"
#include "networkd-wait-online.h"
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index f0ca6def87..6a96f1de55 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -21,11 +21,10 @@
#include <getopt.h>
#include "sd-daemon.h"
-
-#include "networkd-wait-online.h"
-
#include "strv.h"
#include "build.h"
+#include "signal-util.h"
+#include "networkd-wait-online.h"
static bool arg_quiet = false;
static usec_t arg_timeout = 120 * USEC_PER_SEC;
diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h
index 66b865cfe2..73d129699d 100644
--- a/src/network/networkd-wait-online.h
+++ b/src/network/networkd-wait-online.h
@@ -25,7 +25,6 @@
#include "sd-rtnl.h"
#include "sd-network.h"
-#include "util.h"
#include "hashmap.h"
typedef struct Manager Manager;
diff --git a/src/network/networkd.c b/src/network/networkd.c
index 7319276c53..41ec7cf904 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -19,10 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "capability.h"
-#include "sd-event.h"
#include "sd-daemon.h"
-
+#include "capability.h"
+#include "signal-util.h"
#include "networkd.h"
int main(int argc, char *argv[]) {
@@ -54,21 +53,19 @@ int main(int argc, char *argv[]) {
* watches in. */
r = mkdir_safe_label("/run/systemd/netif", 0755, uid, gid);
if (r < 0)
- log_error_errno(r, "Could not create runtime directory: %m");
+ log_warning_errno(r, "Could not create runtime directory: %m");
r = mkdir_safe_label("/run/systemd/netif/links", 0755, uid, gid);
if (r < 0)
- log_error_errno(r, "Could not create runtime directory 'links': %m");
+ log_warning_errno(r, "Could not create runtime directory 'links': %m");
r = mkdir_safe_label("/run/systemd/netif/leases", 0755, uid, gid);
if (r < 0)
- log_error_errno(r, "Could not create runtime directory 'leases': %m");
+ log_warning_errno(r, "Could not create runtime directory 'leases': %m");
r = mkdir_safe_label("/run/systemd/netif/lldp", 0755, uid, gid);
if (r < 0)
- log_error("Could not create runtime directory 'lldp': %s",
- strerror(-r));
-
+ log_warning_errno(r, "Could not create runtime directory 'lldp': %m");
r = drop_privileges(uid, gid,
(1ULL << CAP_NET_ADMIN) |
diff --git a/src/network/networkd.h b/src/network/networkd.h
index bdb2f20e2f..49afeffe81 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -60,6 +60,7 @@ typedef enum AddressFamilyBoolean {
ADDRESS_FAMILY_IPV4 = 1,
ADDRESS_FAMILY_IPV6 = 2,
ADDRESS_FAMILY_YES = 3,
+ ADDRESS_FAMILY_KERNEL = 4,
_ADDRESS_FAMILY_BOOLEAN_MAX,
_ADDRESS_FAMILY_BOOLEAN_INVALID = -1,
} AddressFamilyBoolean;
@@ -83,6 +84,13 @@ typedef enum LinkOperationalState {
_LINK_OPERSTATE_INVALID = -1
} LinkOperationalState;
+typedef enum DCHPClientIdentifier {
+ DHCP_CLIENT_ID_MAC,
+ DHCP_CLIENT_ID_DUID,
+ _DHCP_CLIENT_ID_MAX,
+ _DHCP_CLIENT_ID_INVALID = -1,
+} DCHPClientIdentifier;
+
struct FdbEntry {
Network *network;
unsigned section;
@@ -115,6 +123,7 @@ struct Network {
NetDev *bond;
Hashmap *stacked_netdevs;
AddressFamilyBoolean dhcp;
+ DCHPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
bool dhcp_dns;
bool dhcp_ntp;
@@ -151,7 +160,7 @@ struct Network {
Hashmap *fdb_entries_by_section;
bool wildcard_domain;
- char **domains, **dns, **ntp;
+ char **domains, **dns, **ntp, **bind_carrier;
LLMNRSupport llmnr;
@@ -165,7 +174,7 @@ struct Address {
int family;
unsigned char prefixlen;
unsigned char scope;
- unsigned char flags;
+ uint32_t flags;
char *label;
struct in_addr broadcast;
@@ -403,6 +412,9 @@ int config_parse_fdb_vlan_id(const char *unit, const char *filename, unsigned li
int config_parse_dhcp(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_dhcp_client_identifier(const char *unit, const char *filename, unsigned line,
+ const char *section, unsigned section_line, const char *lvalue,
+ int ltype, const char *rvalue, void *data, void *userdata);
/* IPv4LL support (legacy) */
@@ -437,7 +449,7 @@ AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_;
int config_parse_address_family_boolean(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-/* Opeartional State */
+/* Operational State */
const char* link_operstate_to_string(LinkOperationalState s) _const_;
LinkOperationalState link_operstate_from_string(const char *s) _pure_;
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index 6709ab0957..67fcca2ac0 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -1,5 +1,4 @@
#include "networkd.h"
-#include "networkd-link.h"
#include "networkd-netdev-bond.h"
#include "networkd-netdev-macvlan.h"
#include "dhcp6-internal.h"
diff --git a/src/notify/notify.c b/src/notify/notify.c
index f98075d513..c920b29297 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -24,7 +24,6 @@
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
-#include <string.h>
#include "systemd/sd-daemon.h"
@@ -33,6 +32,7 @@
#include "log.h"
#include "build.h"
#include "env-util.h"
+#include "formats-util.h"
static bool arg_ready = false;
static pid_t arg_pid = 0;
@@ -198,7 +198,7 @@ int main(int argc, char* argv[]) {
}
if (r == 0)
- r = -ENOTSUP;
+ r = -EOPNOTSUPP;
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index fb672510b4..4211a3d779 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -23,27 +23,21 @@
#include <sched.h>
#include <unistd.h>
#include <sys/types.h>
-#include <sys/syscall.h>
#include <sys/mount.h>
-#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/prctl.h>
#include <getopt.h>
-#include <termios.h>
-#include <sys/signalfd.h>
#include <grp.h>
#include <linux/fs.h>
-#include <sys/un.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <net/if.h>
#include <linux/veth.h>
#include <sys/personality.h>
#include <linux/loop.h>
-#include <poll.h>
#include <sys/file.h>
#ifdef HAVE_SELINUX
@@ -62,11 +56,12 @@
#include "sd-bus.h"
#include "sd-id128.h"
#include "sd-rtnl.h"
+#include "random-util.h"
#include "log.h"
#include "util.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "macro.h"
-#include "audit.h"
#include "missing.h"
#include "cgroup-util.h"
#include "strv.h"
@@ -79,9 +74,7 @@
#include "bus-util.h"
#include "bus-error.h"
#include "ptyfwd.h"
-#include "bus-kernel.h"
#include "env-util.h"
-#include "def.h"
#include "rtnl-util.h"
#include "udev-util.h"
#include "blkid-util.h"
@@ -99,6 +92,11 @@
#include "in-addr-util.h"
#include "fw-util.h"
#include "local-addresses.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
@@ -129,6 +127,22 @@ typedef enum Volatile {
VOLATILE_STATE,
} Volatile;
+typedef enum CustomMountType {
+ CUSTOM_MOUNT_BIND,
+ CUSTOM_MOUNT_TMPFS,
+ CUSTOM_MOUNT_OVERLAY,
+} CustomMountType;
+
+typedef struct CustomMount {
+ CustomMountType type;
+ bool read_only;
+ char *source; /* for overlayfs this is the upper directory */
+ char *destination;
+ char *options;
+ char *work_dir;
+ char **lower;
+} CustomMount;
+
static char *arg_directory = NULL;
static char *arg_template = NULL;
static char *arg_user = NULL;
@@ -170,9 +184,8 @@ static uint64_t arg_retain =
(1ULL << CAP_AUDIT_WRITE) |
(1ULL << CAP_AUDIT_CONTROL) |
(1ULL << CAP_MKNOD);
-static char **arg_bind = NULL;
-static char **arg_bind_ro = NULL;
-static char **arg_tmpfs = NULL;
+static CustomMount *arg_custom_mounts = NULL;
+static unsigned arg_n_custom_mounts = 0;
static char **arg_setenv = NULL;
static bool arg_quiet = false;
static bool arg_share_system = false;
@@ -183,10 +196,14 @@ static char **arg_network_macvlan = NULL;
static char **arg_network_ipvlan = NULL;
static bool arg_network_veth = false;
static const char *arg_network_bridge = NULL;
-static unsigned long arg_personality = 0xffffffffLU;
+static unsigned long arg_personality = PERSONALITY_INVALID;
static char *arg_image = NULL;
static Volatile arg_volatile = VOLATILE_NO;
static ExposePort *arg_expose_ports = NULL;
+static char **arg_property = NULL;
+static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U;
+static bool arg_userns = false;
+static int arg_kill_signal = 0;
static void help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
@@ -205,6 +222,9 @@ static void help(void) {
" -M --machine=NAME Set the machine name for the container\n"
" --uuid=UUID Set a specific machine UUID for the container\n"
" -S --slice=SLICE Place the container in the specified slice\n"
+ " --property=NAME=VALUE Set scope unit property\n"
+ " --private-users[=UIDBASE[:NUIDS]]\n"
+ " Run within user namespace\n"
" --private-network Disable network in container\n"
" --network-interface=INTERFACE\n"
" Assign an existing network interface to the\n"
@@ -232,6 +252,7 @@ static void help(void) {
" --capability=CAP In addition to the default, retain specified\n"
" capability\n"
" --drop-capability=CAP Drop the specified capability from the default set\n"
+ " --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
" --link-journal=MODE Link up guest journal, one of no, auto, guest, host,\n"
" try-guest, try-host\n"
" -j Equivalent to --link-journal=try-guest\n"
@@ -240,6 +261,11 @@ static void help(void) {
" the container\n"
" --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n"
" --tmpfs=PATH:[OPTIONS] Mount an empty tmpfs to the specified directory\n"
+ " --overlay=PATH[:PATH...]:PATH\n"
+ " Create an overlay mount from the host to \n"
+ " the container\n"
+ " --overlay-ro=PATH[:PATH...]:PATH\n"
+ " Similar, but creates a read-only overlay mount\n"
" --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
" --share-system Share system namespaces with host\n"
" --register=BOOLEAN Register container as machine\n"
@@ -249,6 +275,89 @@ static void help(void) {
, program_invocation_short_name);
}
+static CustomMount* custom_mount_add(CustomMountType t) {
+ CustomMount *c, *ret;
+
+ c = realloc(arg_custom_mounts, (arg_n_custom_mounts + 1) * sizeof(CustomMount));
+ if (!c)
+ return NULL;
+
+ arg_custom_mounts = c;
+ ret = arg_custom_mounts + arg_n_custom_mounts;
+ arg_n_custom_mounts++;
+
+ *ret = (CustomMount) { .type = t };
+
+ return ret;
+}
+
+static void custom_mount_free_all(void) {
+ unsigned i;
+
+ for (i = 0; i < arg_n_custom_mounts; i++) {
+ CustomMount *m = &arg_custom_mounts[i];
+
+ free(m->source);
+ free(m->destination);
+ free(m->options);
+
+ if (m->work_dir) {
+ (void) rm_rf(m->work_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
+ free(m->work_dir);
+ }
+
+ strv_free(m->lower);
+ }
+
+ free(arg_custom_mounts);
+ arg_custom_mounts = NULL;
+ arg_n_custom_mounts = 0;
+}
+
+static int custom_mount_compare(const void *a, const void *b) {
+ const CustomMount *x = a, *y = b;
+ int r;
+
+ r = path_compare(x->destination, y->destination);
+ if (r != 0)
+ return r;
+
+ if (x->type < y->type)
+ return -1;
+ if (x->type > y->type)
+ return 1;
+
+ return 0;
+}
+
+static int custom_mounts_prepare(void) {
+ unsigned i;
+ int r;
+
+ /* Ensure the mounts are applied prefix first. */
+ qsort_safe(arg_custom_mounts, arg_n_custom_mounts, sizeof(CustomMount), custom_mount_compare);
+
+ /* Allocate working directories for the overlay file systems that need it */
+ for (i = 0; i < arg_n_custom_mounts; i++) {
+ CustomMount *m = &arg_custom_mounts[i];
+
+ if (m->type != CUSTOM_MOUNT_OVERLAY)
+ continue;
+
+ if (m->work_dir)
+ continue;
+
+ if (m->read_only)
+ continue;
+
+ r = tempfn_random(m->source, &m->work_dir);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate work directory from %s: %m", m->source);
+ }
+
+ return 0;
+}
+
static int set_sanitized_path(char **b, const char *path) {
char *p;
@@ -283,6 +392,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_BIND,
ARG_BIND_RO,
ARG_TMPFS,
+ ARG_OVERLAY,
+ ARG_OVERLAY_RO,
ARG_SETENV,
ARG_SHARE_SYSTEM,
ARG_REGISTER,
@@ -294,6 +405,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PERSONALITY,
ARG_VOLATILE,
ARG_TEMPLATE,
+ ARG_PROPERTY,
+ ARG_PRIVATE_USERS,
+ ARG_KILL_SIGNAL,
};
static const struct option options[] = {
@@ -313,6 +427,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "bind", required_argument, NULL, ARG_BIND },
{ "bind-ro", required_argument, NULL, ARG_BIND_RO },
{ "tmpfs", required_argument, NULL, ARG_TMPFS },
+ { "overlay", required_argument, NULL, ARG_OVERLAY },
+ { "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO },
{ "machine", required_argument, NULL, 'M' },
{ "slice", required_argument, NULL, 'S' },
{ "setenv", required_argument, NULL, ARG_SETENV },
@@ -331,6 +447,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "image", required_argument, NULL, 'i' },
{ "volatile", optional_argument, NULL, ARG_VOLATILE },
{ "port", required_argument, NULL, 'p' },
+ { "property", required_argument, NULL, ARG_PROPERTY },
+ { "private-users", optional_argument, NULL, ARG_PRIVATE_USERS },
+ { "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL },
{}
};
@@ -534,72 +653,131 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_BIND:
case ARG_BIND_RO: {
- _cleanup_free_ char *a = NULL, *b = NULL;
+ _cleanup_free_ char *source = NULL, *destination = NULL;
+ CustomMount *m;
char *e;
- char ***x;
-
- x = c == ARG_BIND ? &arg_bind : &arg_bind_ro;
e = strchr(optarg, ':');
if (e) {
- a = strndup(optarg, e - optarg);
- b = strdup(e + 1);
+ source = strndup(optarg, e - optarg);
+ destination = strdup(e + 1);
} else {
- a = strdup(optarg);
- b = strdup(optarg);
+ source = strdup(optarg);
+ destination = strdup(optarg);
}
- if (!a || !b)
+ if (!source || !destination)
return log_oom();
- if (!path_is_absolute(a) || !path_is_absolute(b)) {
+ if (!path_is_absolute(source) || !path_is_absolute(destination)) {
log_error("Invalid bind mount specification: %s", optarg);
return -EINVAL;
}
- r = strv_extend(x, a);
- if (r < 0)
+ m = custom_mount_add(CUSTOM_MOUNT_BIND);
+ if (!m)
return log_oom();
- r = strv_extend(x, b);
- if (r < 0)
- return log_oom();
+ m->source = source;
+ m->destination = destination;
+ m->read_only = c == ARG_BIND_RO;
+
+ source = destination = NULL;
break;
}
case ARG_TMPFS: {
- _cleanup_free_ char *a = NULL, *b = NULL;
+ _cleanup_free_ char *path = NULL, *opts = NULL;
+ CustomMount *m;
char *e;
e = strchr(optarg, ':');
if (e) {
- a = strndup(optarg, e - optarg);
- b = strdup(e + 1);
+ path = strndup(optarg, e - optarg);
+ opts = strdup(e + 1);
} else {
- a = strdup(optarg);
- b = strdup("mode=0755");
+ path = strdup(optarg);
+ opts = strdup("mode=0755");
}
- if (!a || !b)
+ if (!path || !opts)
return log_oom();
- if (!path_is_absolute(a)) {
+ if (!path_is_absolute(path)) {
log_error("Invalid tmpfs specification: %s", optarg);
return -EINVAL;
}
- r = strv_push(&arg_tmpfs, a);
- if (r < 0)
+ m = custom_mount_add(CUSTOM_MOUNT_TMPFS);
+ if (!m)
return log_oom();
- a = NULL;
+ m->destination = path;
+ m->options = opts;
- r = strv_push(&arg_tmpfs, b);
- if (r < 0)
+ path = opts = NULL;
+
+ break;
+ }
+
+ case ARG_OVERLAY:
+ case ARG_OVERLAY_RO: {
+ _cleanup_free_ char *upper = NULL, *destination = NULL;
+ _cleanup_strv_free_ char **lower = NULL;
+ CustomMount *m;
+ unsigned n = 0;
+ char **i;
+
+ lower = strv_split(optarg, ":");
+ if (!lower)
+ return log_oom();
+
+ STRV_FOREACH(i, lower) {
+ if (!path_is_absolute(*i)) {
+ log_error("Overlay path %s is not absolute.", *i);
+ return -EINVAL;
+ }
+
+ n++;
+ }
+
+ if (n < 2) {
+ log_error("--overlay= needs at least two colon-separated directories specified.");
+ return -EINVAL;
+ }
+
+ if (n == 2) {
+ /* If two parameters are specified,
+ * the first one is the lower, the
+ * second one the upper directory. And
+ * we'll also define the the
+ * destination mount point the same as
+ * the upper. */
+ upper = lower[1];
+ lower[1] = NULL;
+
+ destination = strdup(upper);
+ if (!destination)
+ return log_oom();
+
+ } else {
+ upper = lower[n - 2];
+ destination = lower[n - 1];
+ lower[n - 2] = NULL;
+ }
+
+ m = custom_mount_add(CUSTOM_MOUNT_OVERLAY);
+ if (!m)
return log_oom();
- b = NULL;
+ m->destination = destination;
+ m->source = upper;
+ m->lower = lower;
+ m->read_only = c == ARG_OVERLAY_RO;
+
+ upper = destination = NULL;
+ lower = NULL;
break;
}
@@ -646,7 +824,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_PERSONALITY:
arg_personality = personality_from_string(optarg);
- if (arg_personality == 0xffffffffLU) {
+ if (arg_personality == PERSONALITY_INVALID) {
log_error("Unknown or unsupported personality '%s'.", optarg);
return -EINVAL;
}
@@ -731,6 +909,50 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case ARG_PROPERTY:
+ if (strv_extend(&arg_property, optarg) < 0)
+ return log_oom();
+
+ break;
+
+ case ARG_PRIVATE_USERS:
+ if (optarg) {
+ _cleanup_free_ char *buffer = NULL;
+ const char *range, *shift;
+
+ range = strchr(optarg, ':');
+ if (range) {
+ buffer = strndup(optarg, range - optarg);
+ if (!buffer)
+ return log_oom();
+ shift = buffer;
+
+ range++;
+ if (safe_atou32(range, &arg_uid_range) < 0 || arg_uid_range <= 0) {
+ log_error("Failed to parse UID range: %s", range);
+ return -EINVAL;
+ }
+ } else
+ shift = optarg;
+
+ if (parse_uid(shift, &arg_uid_shift) < 0) {
+ log_error("Failed to parse UID: %s", optarg);
+ return -EINVAL;
+ }
+ }
+
+ arg_userns = true;
+ break;
+
+ case ARG_KILL_SIGNAL:
+ arg_kill_signal = signal_from_string_try_harder(optarg);
+ if (arg_kill_signal < 0) {
+ log_error("Cannot parse signal: %s", optarg);
+ return -EINVAL;
+ }
+
+ break;
+
case '?':
return -EINVAL;
@@ -793,10 +1015,50 @@ static int parse_argv(int argc, char *argv[]) {
arg_retain = (arg_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus;
+ if (arg_boot && arg_kill_signal <= 0)
+ arg_kill_signal = SIGRTMIN+3;
+
return 1;
}
-static int mount_all(const char *dest) {
+static int tmpfs_patch_options(const char *options, char **ret) {
+ char *buf = NULL;
+
+ if (arg_userns && arg_uid_shift != 0) {
+
+ if (options)
+ (void) asprintf(&buf, "%s,uid=" UID_FMT ",gid=" UID_FMT, options, arg_uid_shift, arg_uid_shift);
+ else
+ (void) asprintf(&buf, "uid=" UID_FMT ",gid=" UID_FMT, arg_uid_shift, arg_uid_shift);
+ if (!buf)
+ return -ENOMEM;
+
+ options = buf;
+ }
+
+#ifdef HAVE_SELINUX
+ if (arg_selinux_apifs_context) {
+ char *t;
+
+ if (options)
+ t = strjoin(options, ",context=\"", arg_selinux_apifs_context, "\"", NULL);
+ else
+ t = strjoin("context=\"", arg_selinux_apifs_context, "\"", NULL);
+ if (!t) {
+ free(buf);
+ return -ENOMEM;
+ }
+
+ free(buf);
+ buf = t;
+ }
+#endif
+
+ *ret = buf;
+ return !!buf;
+}
+
+static int mount_all(const char *dest, bool userns) {
typedef struct MountPoint {
const char *what;
@@ -805,78 +1067,64 @@ static int mount_all(const char *dest) {
const char *options;
unsigned long flags;
bool fatal;
+ bool userns;
} MountPoint;
static const MountPoint mount_table[] = {
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
- { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true }, /* Bind mount first */
- { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */
- { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
- { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true },
- { "devpts", "/dev/pts", "devpts","newinstance,ptmxmode=0666,mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, true },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true },
- { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true },
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true },
+ { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true }, /* Bind mount first */
+ { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true, true }, /* Then, make it r/o */
+ { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false },
+ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, true, false },
+ { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
+ { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false },
#ifdef HAVE_SELINUX
- { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false }, /* Bind mount first */
- { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, false }, /* Then, make it r/o */
+ { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false }, /* Bind mount first */
+ { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, false, false }, /* Then, make it r/o */
#endif
};
unsigned k;
- int r = 0;
+ int r;
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
- _cleanup_free_ char *where = NULL;
-#ifdef HAVE_SELINUX
- _cleanup_free_ char *options = NULL;
-#endif
+ _cleanup_free_ char *where = NULL, *options = NULL;
const char *o;
- int t;
- where = strjoin(dest, "/", mount_table[k].where, NULL);
+ if (userns != mount_table[k].userns)
+ continue;
+
+ where = prefix_root(dest, mount_table[k].where);
if (!where)
return log_oom();
- t = path_is_mount_point(where, true);
- if (t < 0) {
- log_error_errno(t, "Failed to detect whether %s is a mount point: %m", where);
-
- if (r == 0)
- r = t;
-
- continue;
- }
+ r = path_is_mount_point(where, AT_SYMLINK_FOLLOW);
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
/* Skip this entry if it is not a remount. */
- if (mount_table[k].what && t > 0)
+ if (mount_table[k].what && r > 0)
continue;
- t = mkdir_p(where, 0755);
- if (t < 0) {
- if (mount_table[k].fatal) {
- log_error_errno(t, "Failed to create directory %s: %m", where);
-
- if (r == 0)
- r = t;
- } else
- log_warning_errno(t, "Failed to create directory %s: %m", where);
+ r = mkdir_p(where, 0755);
+ if (r < 0) {
+ if (mount_table[k].fatal)
+ return log_error_errno(r, "Failed to create directory %s: %m", where);
+ log_warning_errno(r, "Failed to create directory %s: %m", where);
continue;
}
-#ifdef HAVE_SELINUX
- if (arg_selinux_apifs_context &&
- (streq_ptr(mount_table[k].what, "tmpfs") || streq_ptr(mount_table[k].what, "devpts"))) {
- options = strjoin(mount_table[k].options, ",context=\"", arg_selinux_apifs_context, "\"", NULL);
- if (!options)
+ o = mount_table[k].options;
+ if (streq_ptr(mount_table[k].type, "tmpfs")) {
+ r = tmpfs_patch_options(o, &options);
+ if (r < 0)
return log_oom();
-
- o = options;
- } else
-#endif
- o = mount_table[k].options;
-
+ if (r > 0)
+ o = options;
+ }
if (mount(mount_table[k].what,
where,
@@ -884,75 +1132,162 @@ static int mount_all(const char *dest) {
mount_table[k].flags,
o) < 0) {
- if (mount_table[k].fatal) {
- log_error_errno(errno, "mount(%s) failed: %m", where);
+ if (mount_table[k].fatal)
+ return log_error_errno(errno, "mount(%s) failed: %m", where);
- if (r == 0)
- r = -errno;
- } else
- log_warning_errno(errno, "mount(%s) failed: %m", where);
+ log_warning_errno(errno, "mount(%s) failed, ignoring: %m", where);
}
}
- return r;
+ return 0;
}
-static int mount_binds(const char *dest, char **l, bool ro) {
- char **x, **y;
+static int mount_bind(const char *dest, CustomMount *m) {
+ struct stat source_st, dest_st;
+ const char *where;
+ int r;
- STRV_FOREACH_PAIR(x, y, l) {
- _cleanup_free_ char *where = NULL;
- struct stat source_st, dest_st;
- int r;
+ assert(m);
- if (stat(*x, &source_st) < 0)
- return log_error_errno(errno, "Failed to stat %s: %m", *x);
+ if (stat(m->source, &source_st) < 0)
+ return log_error_errno(errno, "Failed to stat %s: %m", m->source);
- where = strappend(dest, *y);
- if (!where)
- return log_oom();
+ where = prefix_roota(dest, m->destination);
- r = stat(where, &dest_st);
- if (r == 0) {
- if (S_ISDIR(source_st.st_mode) && !S_ISDIR(dest_st.st_mode)) {
- log_error("Cannot bind mount directory %s on file %s.", *x, where);
- return -EINVAL;
- }
- if (!S_ISDIR(source_st.st_mode) && S_ISDIR(dest_st.st_mode)) {
- log_error("Cannot bind mount file %s on directory %s.", *x, where);
- return -EINVAL;
- }
- } else if (errno == ENOENT) {
- r = mkdir_parents_label(where, 0755);
- if (r < 0)
- return log_error_errno(r, "Failed to bind mount %s: %m", *x);
- } else {
- log_error_errno(errno, "Failed to bind mount %s: %m", *x);
- return -errno;
+ if (stat(where, &dest_st) >= 0) {
+ if (S_ISDIR(source_st.st_mode) && !S_ISDIR(dest_st.st_mode)) {
+ log_error("Cannot bind mount directory %s on file %s.", m->source, where);
+ return -EINVAL;
}
- /* Create the mount point. Any non-directory file can be
- * mounted on any non-directory file (regular, fifo, socket,
- * char, block).
- */
- if (S_ISDIR(source_st.st_mode)) {
- r = mkdir_label(where, 0755);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(r, "Failed to create mount point %s: %m", where);
- } else {
- r = touch(where);
- if (r < 0)
- return log_error_errno(r, "Failed to create mount point %s: %m", where);
+ if (!S_ISDIR(source_st.st_mode) && S_ISDIR(dest_st.st_mode)) {
+ log_error("Cannot bind mount file %s on directory %s.", m->source, where);
+ return -EINVAL;
}
- if (mount(*x, where, "bind", MS_BIND, NULL) < 0)
- return log_error_errno(errno, "mount(%s) failed: %m", where);
+ } else if (errno == ENOENT) {
+ r = mkdir_parents_label(where, 0755);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make parents of %s: %m", where);
+ } else {
+ log_error_errno(errno, "Failed to stat %s: %m", where);
+ return -errno;
+ }
+
+ /* Create the mount point. Any non-directory file can be
+ * mounted on any non-directory file (regular, fifo, socket,
+ * char, block).
+ */
+ if (S_ISDIR(source_st.st_mode))
+ r = mkdir_label(where, 0755);
+ else
+ r = touch(where);
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Failed to create mount point %s: %m", where);
- if (ro) {
- r = bind_remount_recursive(where, true);
- if (r < 0)
- return log_error_errno(r, "Read-Only bind mount failed: %m");
+ if (mount(m->source, where, NULL, MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "mount(%s) failed: %m", where);
+
+ if (m->read_only) {
+ r = bind_remount_recursive(where, true);
+ if (r < 0)
+ return log_error_errno(r, "Read-only bind mount failed: %m");
+ }
+
+ return 0;
+}
+
+static int mount_tmpfs(const char *dest, CustomMount *m) {
+ const char *where, *options;
+ _cleanup_free_ char *buf = NULL;
+ int r;
+
+ assert(dest);
+ assert(m);
+
+ where = prefix_roota(dest, m->destination);
+
+ r = mkdir_p_label(where, 0755);
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where);
+
+ r = tmpfs_patch_options(m->options, &buf);
+ if (r < 0)
+ return log_oom();
+ options = r > 0 ? buf : m->options;
+
+ if (mount("tmpfs", where, "tmpfs", MS_NODEV|MS_STRICTATIME, options) < 0)
+ return log_error_errno(errno, "tmpfs mount to %s failed: %m", where);
+
+ return 0;
+}
+
+static int mount_overlay(const char *dest, CustomMount *m) {
+ _cleanup_free_ char *lower = NULL;
+ const char *where, *options;
+ int r;
+
+ assert(dest);
+ assert(m);
+
+ where = prefix_roota(dest, m->destination);
+
+ r = mkdir_label(where, 0755);
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Creating mount point for overlay %s failed: %m", where);
+
+ (void) mkdir_p_label(m->source, 0755);
+
+ strv_reverse(m->lower);
+ lower = strv_join(m->lower, ":");
+ strv_reverse(m->lower);
+ if (!lower)
+ return log_oom();
+
+ if (m->read_only)
+ options = strjoina("lowerdir=", m->source, ":", lower);
+ else {
+ assert(m->work_dir);
+ (void) mkdir_label(m->work_dir, 0700);
+
+ options = strjoina("lowerdir=", lower, ",upperdir=", m->source, ",workdir=", m->work_dir);
+ }
+
+ if (mount("overlay", where, "overlay", m->read_only ? MS_RDONLY : 0, options) < 0)
+ return log_error_errno(errno, "overlay mount to %s failed: %m", where);
+
+ return 0;
+}
+
+static int mount_custom(const char *dest) {
+ unsigned i;
+ int r;
+
+ assert(dest);
+
+ for (i = 0; i < arg_n_custom_mounts; i++) {
+ CustomMount *m = &arg_custom_mounts[i];
+
+ switch (m->type) {
+
+ case CUSTOM_MOUNT_BIND:
+ r = mount_bind(dest, m);
+ break;
+
+ case CUSTOM_MOUNT_TMPFS:
+ r = mount_tmpfs(dest, m);
+ break;
+
+ case CUSTOM_MOUNT_OVERLAY:
+ r = mount_overlay(dest, m);
+ break;
+
+ default:
+ assert_not_reached("Unknown custom mount type");
}
+
+ if (r < 0)
+ return r;
}
return 0;
@@ -964,8 +1299,8 @@ static int mount_cgroup_hierarchy(const char *dest, const char *controller, cons
to = strjoina(dest, "/sys/fs/cgroup/", hierarchy);
- r = path_is_mount_point(to, false);
- if (r < 0)
+ r = path_is_mount_point(to, 0);
+ if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to);
if (r > 0)
return 0;
@@ -988,8 +1323,7 @@ static int mount_cgroup_hierarchy(const char *dest, const char *controller, cons
static int mount_cgroup(const char *dest) {
_cleanup_set_free_free_ Set *controllers = NULL;
- _cleanup_free_ char *own_cgroup_path = NULL;
- const char *cgroup_root, *systemd_root, *systemd_own;
+ const char *cgroup_root;
int r;
controllers = set_new(&string_hash_ops);
@@ -1000,14 +1334,6 @@ static int mount_cgroup(const char *dest) {
if (r < 0)
return log_error_errno(r, "Failed to determine cgroup controllers: %m");
- r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
- if (r < 0)
- return log_error_errno(r, "Failed to determine our own cgroup path: %m");
-
- cgroup_root = strjoina(dest, "/sys/fs/cgroup");
- if (mount("tmpfs", cgroup_root, "tmpfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, "mode=755") < 0)
- return log_error_errno(errno, "Failed to mount tmpfs to /sys/fs/cgroup: %m");
-
for (;;) {
_cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;
@@ -1015,7 +1341,7 @@ static int mount_cgroup(const char *dest) {
if (!controller)
break;
- origin = strappend("/sys/fs/cgroup/", controller);
+ origin = prefix_root("/sys/fs/cgroup/", controller);
if (!origin)
return log_oom();
@@ -1032,7 +1358,7 @@ static int mount_cgroup(const char *dest) {
else {
_cleanup_free_ char *target = NULL;
- target = strjoin(dest, "/sys/fs/cgroup/", controller, NULL);
+ target = prefix_root(dest, origin);
if (!target)
return log_oom();
@@ -1047,8 +1373,13 @@ static int mount_cgroup(const char *dest) {
if (r < 0)
return r;
- if (symlink(combined, target) < 0)
- return log_error_errno(errno, "Failed to create symlink for combined hierarchy: %m");
+ r = symlink_idempotent(combined, target);
+ if (r == -EINVAL) {
+ log_error("Invalid existing symlink for combined hierarchy");
+ return r;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
}
}
@@ -1056,46 +1387,82 @@ static int mount_cgroup(const char *dest) {
if (r < 0)
return r;
+ cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
+ if (mount(NULL, cgroup_root, NULL, MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755") < 0)
+ return log_error_errno(errno, "Failed to remount %s read-only: %m", cgroup_root);
+
+ return 0;
+}
+
+static int mount_systemd_cgroup_writable(const char *dest) {
+ _cleanup_free_ char *own_cgroup_path = NULL;
+ const char *systemd_root, *systemd_own;
+ int r;
+
+ assert(dest);
+
+ r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine our own cgroup path: %m");
+
/* Make our own cgroup a (writable) bind mount */
systemd_own = strjoina(dest, "/sys/fs/cgroup/systemd", own_cgroup_path);
if (mount(systemd_own, systemd_own, NULL, MS_BIND, NULL) < 0)
return log_error_errno(errno, "Failed to turn %s into a bind mount: %m", own_cgroup_path);
/* And then remount the systemd cgroup root read-only */
- systemd_root = strjoina(dest, "/sys/fs/cgroup/systemd");
+ systemd_root = prefix_roota(dest, "/sys/fs/cgroup/systemd");
if (mount(NULL, systemd_root, NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL) < 0)
return log_error_errno(errno, "Failed to mount cgroup root read-only: %m");
- if (mount(NULL, cgroup_root, NULL, MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755") < 0)
- return log_error_errno(errno, "Failed to remount %s read-only: %m", cgroup_root);
-
return 0;
}
-static int mount_tmpfs(const char *dest) {
- char **i, **o;
+static int userns_lchown(const char *p, uid_t uid, gid_t gid) {
+ assert(p);
- STRV_FOREACH_PAIR(i, o, arg_tmpfs) {
- _cleanup_free_ char *where = NULL;
- int r;
+ if (!arg_userns)
+ return 0;
- where = strappend(dest, *i);
- if (!where)
- return log_oom();
+ if (uid == UID_INVALID && gid == GID_INVALID)
+ return 0;
- r = mkdir_label(where, 0755);
- if (r < 0 && r != -EEXIST)
- return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where);
+ if (uid != UID_INVALID) {
+ uid += arg_uid_shift;
- if (mount("tmpfs", where, "tmpfs", MS_NODEV|MS_STRICTATIME, *o) < 0)
- return log_error_errno(errno, "tmpfs mount to %s failed: %m", where);
+ if (uid < arg_uid_shift || uid >= arg_uid_shift + arg_uid_range)
+ return -EOVERFLOW;
}
+ if (gid != GID_INVALID) {
+ gid += (gid_t) arg_uid_shift;
+
+ if (gid < (gid_t) arg_uid_shift || gid >= (gid_t) (arg_uid_shift + arg_uid_range))
+ return -EOVERFLOW;
+ }
+
+ if (lchown(p, uid, gid) < 0)
+ return -errno;
+
return 0;
}
+static int userns_mkdir(const char *root, const char *path, mode_t mode, uid_t uid, gid_t gid) {
+ const char *q;
+
+ q = prefix_roota(root, path);
+ if (mkdir(q, mode) < 0) {
+ if (errno == EEXIST)
+ return 0;
+ return -errno;
+ }
+
+ return userns_lchown(q, uid, gid);
+}
+
static int setup_timezone(const char *dest) {
- _cleanup_free_ char *where = NULL, *p = NULL, *q = NULL, *check = NULL, *what = NULL;
+ _cleanup_free_ char *p = NULL, *q = NULL;
+ const char *where, *check, *what;
char *z, *y;
int r;
@@ -1116,10 +1483,7 @@ static int setup_timezone(const char *dest) {
return 0;
}
- where = strappend(dest, "/etc/localtime");
- if (!where)
- return log_oom();
-
+ where = prefix_roota(dest, "/etc/localtime");
r = readlink_malloc(where, &q);
if (r >= 0) {
y = path_startswith(q, "../usr/share/zoneinfo/");
@@ -1131,43 +1495,34 @@ static int setup_timezone(const char *dest) {
return 0;
}
- check = strjoin(dest, "/usr/share/zoneinfo/", z, NULL);
- if (!check)
- return log_oom();
-
- if (access(check, F_OK) < 0) {
+ check = strjoina("/usr/share/zoneinfo/", z);
+ check = prefix_root(dest, check);
+ if (laccess(check, F_OK) < 0) {
log_warning("Timezone %s does not exist in container, not updating container timezone.", z);
return 0;
}
- what = strappend("../usr/share/zoneinfo/", z);
- if (!what)
- return log_oom();
-
- r = mkdir_parents(where, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create directory for timezone info %s in container: %m", where);
-
- return 0;
- }
-
r = unlink(where);
if (r < 0 && errno != ENOENT) {
log_error_errno(errno, "Failed to remove existing timezone info %s in container: %m", where);
-
return 0;
}
+ what = strjoina("../usr/share/zoneinfo/", z);
if (symlink(what, where) < 0) {
log_error_errno(errno, "Failed to correct timezone of container: %m");
return 0;
}
+ r = userns_lchown(where, 0, 0);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to chown /etc/localtime: %m");
+
return 0;
}
static int setup_resolv_conf(const char *dest) {
- _cleanup_free_ char *where = NULL;
+ const char *where = NULL;
int r;
assert(dest);
@@ -1176,31 +1531,24 @@ static int setup_resolv_conf(const char *dest) {
return 0;
/* Fix resolv.conf, if possible */
- where = strappend(dest, "/etc/resolv.conf");
- if (!where)
- return log_oom();
-
- /* We don't really care for the results of this really. If it
- * fails, it fails, but meh... */
- r = mkdir_parents(where, 0755);
- if (r < 0) {
- log_warning_errno(r, "Failed to create parent directory for resolv.conf %s: %m", where);
-
- return 0;
- }
+ where = prefix_roota(dest, "/etc/resolv.conf");
r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0);
if (r < 0) {
log_warning_errno(r, "Failed to copy /etc/resolv.conf to %s: %m", where);
-
return 0;
}
+ r = userns_lchown(where, 0, 0);
+ if (r < 0)
+ log_warning_errno(r, "Failed to chown /etc/resolv.conf: %m");
+
return 0;
}
static int setup_volatile_state(const char *directory) {
- const char *p;
+ _cleanup_free_ char *buf = NULL;
+ const char *p, *options;
int r;
assert(directory);
@@ -1215,12 +1563,19 @@ static int setup_volatile_state(const char *directory) {
if (r < 0)
return log_error_errno(r, "Failed to remount %s read-only: %m", directory);
- p = strjoina(directory, "/var");
+ p = prefix_roota(directory, "/var");
r = mkdir(p, 0755);
if (r < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create %s: %m", directory);
- if (mount("tmpfs", p, "tmpfs", MS_STRICTATIME, "mode=755") < 0)
+ options = "mode=755";
+ r = tmpfs_patch_options(options, &buf);
+ if (r < 0)
+ return log_oom();
+ if (r > 0)
+ options = buf;
+
+ if (mount("tmpfs", p, "tmpfs", MS_STRICTATIME, options) < 0)
return log_error_errno(errno, "Failed to mount tmpfs to /var: %m");
return 0;
@@ -1229,7 +1584,8 @@ static int setup_volatile_state(const char *directory) {
static int setup_volatile(const char *directory) {
bool tmpfs_mounted = false, bind_mounted = false;
char template[] = "/tmp/nspawn-volatile-XXXXXX";
- const char *f, *t;
+ _cleanup_free_ char *buf = NULL;
+ const char *f, *t, *options;
int r;
assert(directory);
@@ -1243,27 +1599,31 @@ static int setup_volatile(const char *directory) {
if (!mkdtemp(template))
return log_error_errno(errno, "Failed to create temporary directory: %m");
- if (mount("tmpfs", template, "tmpfs", MS_STRICTATIME, "mode=755") < 0) {
- log_error_errno(errno, "Failed to mount tmpfs for root directory: %m");
- r = -errno;
+ options = "mode=755";
+ r = tmpfs_patch_options(options, &buf);
+ if (r < 0)
+ return log_oom();
+ if (r > 0)
+ options = buf;
+
+ if (mount("tmpfs", template, "tmpfs", MS_STRICTATIME, options) < 0) {
+ r = log_error_errno(errno, "Failed to mount tmpfs for root directory: %m");
goto fail;
}
tmpfs_mounted = true;
- f = strjoina(directory, "/usr");
- t = strjoina(template, "/usr");
+ f = prefix_roota(directory, "/usr");
+ t = prefix_roota(template, "/usr");
r = mkdir(t, 0755);
if (r < 0 && errno != EEXIST) {
- log_error_errno(errno, "Failed to create %s: %m", t);
- r = -errno;
+ r = log_error_errno(errno, "Failed to create %s: %m", t);
goto fail;
}
- if (mount(f, t, "bind", MS_BIND|MS_REC, NULL) < 0) {
- log_error_errno(errno, "Failed to create /usr bind mount: %m");
- r = -errno;
+ if (mount(f, t, NULL, MS_BIND|MS_REC, NULL) < 0) {
+ r = log_error_errno(errno, "Failed to create /usr bind mount: %m");
goto fail;
}
@@ -1276,25 +1636,26 @@ static int setup_volatile(const char *directory) {
}
if (mount(template, directory, NULL, MS_MOVE, NULL) < 0) {
- log_error_errno(errno, "Failed to move root mount: %m");
- r = -errno;
+ r = log_error_errno(errno, "Failed to move root mount: %m");
goto fail;
}
- rmdir(template);
+ (void) rmdir(template);
return 0;
fail:
if (bind_mounted)
- umount(t);
+ (void) umount(t);
+
if (tmpfs_mounted)
- umount(template);
- rmdir(template);
+ (void) umount(template);
+ (void) rmdir(template);
return r;
}
static char* id128_format_as_uuid(sd_id128_t id, char s[37]) {
+ assert(s);
snprintf(s, 37,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
@@ -1304,23 +1665,19 @@ static char* id128_format_as_uuid(sd_id128_t id, char s[37]) {
}
static int setup_boot_id(const char *dest) {
- _cleanup_free_ char *from = NULL, *to = NULL;
+ const char *from, *to;
sd_id128_t rnd = {};
char as_uuid[37];
int r;
- assert(dest);
-
if (arg_share_system)
return 0;
/* Generate a new randomized boot ID, so that each boot-up of
* the container gets a new one */
- from = strappend(dest, "/dev/proc-sys-kernel-random-boot-id");
- to = strappend(dest, "/proc/sys/kernel/random/boot_id");
- if (!from || !to)
- return log_oom();
+ from = prefix_roota(dest, "/run/proc-sys-kernel-random-boot-id");
+ to = prefix_roota(dest, "/proc/sys/kernel/random/boot_id");
r = sd_id128_randomize(&rnd);
if (r < 0)
@@ -1332,10 +1689,9 @@ static int setup_boot_id(const char *dest) {
if (r < 0)
return log_error_errno(r, "Failed to write boot id: %m");
- if (mount(from, to, "bind", MS_BIND, NULL) < 0) {
- log_error_errno(errno, "Failed to bind mount boot id: %m");
- r = -errno;
- } else if (mount(from, to, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL))
+ if (mount(from, to, NULL, MS_BIND, NULL) < 0)
+ r = log_error_errno(errno, "Failed to bind mount boot id: %m");
+ else if (mount(NULL, to, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL) < 0)
log_warning_errno(errno, "Failed to make boot id read-only: %m");
unlink(from);
@@ -1361,14 +1717,16 @@ static int copy_devnodes(const char *dest) {
u = umask(0000);
+ /* Create /dev/net, so that we can create /dev/net/tun in it */
+ if (userns_mkdir(dest, "/dev/net", 0755, 0, 0) < 0)
+ return log_error_errno(r, "Failed to create /dev/net directory: %m");
+
NULSTR_FOREACH(d, devnodes) {
_cleanup_free_ char *from = NULL, *to = NULL;
struct stat st;
from = strappend("/dev/", d);
- to = strjoin(dest, "/dev/", d, NULL);
- if (!from || !to)
- return log_oom();
+ to = prefix_root(dest, from);
if (stat(from, &st) < 0) {
@@ -1377,33 +1735,73 @@ static int copy_devnodes(const char *dest) {
} else if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
- log_error("%s is not a char or block device, cannot copy", from);
+ log_error("%s is not a char or block device, cannot copy.", from);
return -EIO;
} else {
- r = mkdir_parents(to, 0775);
- if (r < 0) {
- log_error_errno(r, "Failed to create parent directory of %s: %m", to);
- return -r;
+ if (mknod(to, st.st_mode, st.st_rdev) < 0) {
+ if (errno != EPERM)
+ return log_error_errno(errno, "mknod(%s) failed: %m", to);
+
+ /* Some systems abusively restrict mknod but
+ * allow bind mounts. */
+ r = touch(to);
+ if (r < 0)
+ return log_error_errno(r, "touch (%s) failed: %m", to);
+ if (mount(from, to, NULL, MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Both mknod and bind mount (%s) failed: %m", to);
}
- if (mknod(to, st.st_mode, st.st_rdev) < 0)
- return log_error_errno(errno, "mknod(%s) failed: %m", to);
+ r = userns_lchown(to, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "chown() of device node %s failed: %m", to);
}
}
return r;
}
-static int setup_ptmx(const char *dest) {
- _cleanup_free_ char *p = NULL;
+static int setup_pts(const char *dest) {
+ _cleanup_free_ char *options = NULL;
+ const char *p;
- p = strappend(dest, "/dev/ptmx");
- if (!p)
+#ifdef HAVE_SELINUX
+ if (arg_selinux_apifs_context)
+ (void) asprintf(&options,
+ "newinstance,ptmxmode=0666,mode=620,uid=" UID_FMT ",gid=" GID_FMT ",context=\"%s\"",
+ arg_uid_shift,
+ arg_uid_shift + TTY_GID,
+ arg_selinux_apifs_context);
+ else
+#endif
+ (void) asprintf(&options,
+ "newinstance,ptmxmode=0666,mode=620,uid=" UID_FMT ",gid=" GID_FMT,
+ arg_uid_shift,
+ arg_uid_shift + TTY_GID);
+
+ if (!options)
return log_oom();
+ /* Mount /dev/pts itself */
+ p = prefix_roota(dest, "/dev/pts");
+ if (mkdir(p, 0755) < 0)
+ return log_error_errno(errno, "Failed to create /dev/pts: %m");
+ if (mount("devpts", p, "devpts", MS_NOSUID|MS_NOEXEC, options) < 0)
+ return log_error_errno(errno, "Failed to mount /dev/pts: %m");
+ if (userns_lchown(p, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to chown /dev/pts: %m");
+
+ /* Create /dev/ptmx symlink */
+ p = prefix_roota(dest, "/dev/ptmx");
if (symlink("pts/ptmx", p) < 0)
return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m");
+ if (userns_lchown(p, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to chown /dev/ptmx: %m");
+
+ /* And fix /dev/pts/ptmx ownership */
+ p = prefix_roota(dest, "/dev/pts/ptmx");
+ if (userns_lchown(p, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to chown /dev/pts/ptmx: %m");
return 0;
}
@@ -1411,7 +1809,6 @@ static int setup_ptmx(const char *dest) {
static int setup_dev_console(const char *dest, const char *console) {
_cleanup_umask_ mode_t u;
const char *to;
- struct stat st;
int r;
assert(dest);
@@ -1419,35 +1816,29 @@ static int setup_dev_console(const char *dest, const char *console) {
u = umask(0000);
- if (stat("/dev/null", &st) < 0)
- return log_error_errno(errno, "Failed to stat /dev/null: %m");
-
- r = chmod_and_chown(console, 0600, 0, 0);
+ r = chmod_and_chown(console, 0600, arg_uid_shift, arg_uid_shift);
if (r < 0)
return log_error_errno(r, "Failed to correct access mode for TTY: %m");
/* We need to bind mount the right tty to /dev/console since
* ptys can only exist on pts file systems. To have something
- * to bind mount things on we create a device node first, and
- * use /dev/null for that since we the cgroups device policy
- * allows us to create that freely, while we cannot create
- * /dev/console. (Note that the major minor doesn't actually
- * matter here, since we mount it over anyway). */
+ * to bind mount things on we create a empty regular file. */
- to = strjoina(dest, "/dev/console");
- if (mknod(to, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0)
- return log_error_errno(errno, "mknod() for /dev/console failed: %m");
+ to = prefix_roota(dest, "/dev/console");
+ r = touch(to);
+ if (r < 0)
+ return log_error_errno(r, "touch() for /dev/console failed: %m");
- if (mount(console, to, "bind", MS_BIND, NULL) < 0)
+ if (mount(console, to, NULL, MS_BIND, NULL) < 0)
return log_error_errno(errno, "Bind mount for /dev/console failed: %m");
return 0;
}
static int setup_kmsg(const char *dest, int kmsg_socket) {
- _cleanup_free_ char *from = NULL, *to = NULL;
+ const char *from, *to;
_cleanup_umask_ mode_t u;
- int r, fd, k;
+ int fd, k;
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -1458,30 +1849,23 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
};
struct cmsghdr *cmsg;
- assert(dest);
assert(kmsg_socket >= 0);
u = umask(0000);
- /* We create the kmsg FIFO as /dev/kmsg, but immediately
+ /* We create the kmsg FIFO as /run/kmsg, but immediately
* delete it after bind mounting it to /proc/kmsg. While FIFOs
* on the reading side behave very similar to /proc/kmsg,
* their writing side behaves differently from /dev/kmsg in
* that writing blocks when nothing is reading. In order to
* avoid any problems with containers deadlocking due to this
* we simply make /dev/kmsg unavailable to the container. */
- if (asprintf(&from, "%s/dev/kmsg", dest) < 0 ||
- asprintf(&to, "%s/proc/kmsg", dest) < 0)
- return log_oom();
+ from = prefix_roota(dest, "/run/kmsg");
+ to = prefix_roota(dest, "/proc/kmsg");
if (mkfifo(from, 0600) < 0)
- return log_error_errno(errno, "mkfifo() for /dev/kmsg failed: %m");
-
- r = chmod_and_chown(from, 0600, 0, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to correct access mode for /dev/kmsg: %m");
-
- if (mount(from, to, "bind", MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "mkfifo() for /run/kmsg failed: %m");
+ if (mount(from, to, NULL, MS_BIND, NULL) < 0)
return log_error_errno(errno, "Bind mount for /proc/kmsg failed: %m");
fd = open(from, O_RDWR|O_NDELAY|O_CLOEXEC);
@@ -1504,8 +1888,9 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
if (k < 0)
return log_error_errno(errno, "Failed to send FIFO fd: %m");
- /* And now make the FIFO unavailable as /dev/kmsg... */
- unlink(from);
+ /* And now make the FIFO unavailable as /run/kmsg... */
+ (void) unlink(from);
+
return 0;
}
@@ -1529,7 +1914,7 @@ static int send_rtnl(int send_fd) {
fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
if (fd < 0)
- return log_error_errno(errno, "failed to allocate container netlink: %m");
+ return log_error_errno(errno, "Failed to allocate container netlink: %m");
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = SOL_SOCKET;
@@ -1714,7 +2099,8 @@ static int setup_hostname(void) {
static int setup_journal(const char *directory) {
sd_id128_t machine_id, this_id;
- _cleanup_free_ char *p = NULL, *b = NULL, *q = NULL, *d = NULL;
+ _cleanup_free_ char *b = NULL, *d = NULL;
+ const char *etc_machine_id, *p, *q;
char *id;
int r;
@@ -1722,15 +2108,13 @@ static int setup_journal(const char *directory) {
if (arg_ephemeral)
return 0;
- p = strappend(directory, "/etc/machine-id");
- if (!p)
- return log_oom();
+ etc_machine_id = prefix_roota(directory, "/etc/machine-id");
- r = read_one_line_file(p, &b);
+ r = read_one_line_file(etc_machine_id, &b);
if (r == -ENOENT && arg_link_journal == LINK_AUTO)
return 0;
else if (r < 0)
- return log_error_errno(r, "Failed to read machine ID from %s: %m", p);
+ return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
id = strstrip(b);
if (isempty(id) && arg_link_journal == LINK_AUTO)
@@ -1739,7 +2123,7 @@ static int setup_journal(const char *directory) {
/* Verify validity */
r = sd_id128_from_string(id, &machine_id);
if (r < 0)
- return log_error_errno(r, "Failed to parse machine ID from %s: %m", p);
+ return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
r = sd_id128_get_machine(&this_id);
if (r < 0)
@@ -1756,13 +2140,22 @@ static int setup_journal(const char *directory) {
if (arg_link_journal == LINK_NO)
return 0;
- free(p);
- p = strappend("/var/log/journal/", id);
- q = strjoin(directory, "/var/log/journal/", id, NULL);
- if (!p || !q)
- return log_oom();
+ r = userns_mkdir(directory, "/var", 0755, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /var: %m");
- if (path_is_mount_point(p, false) > 0) {
+ r = userns_mkdir(directory, "/var/log", 0755, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /var/log: %m");
+
+ r = userns_mkdir(directory, "/var/log/journal", 0755, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /var/log/journal: %m");
+
+ p = strjoina("/var/log/journal/", id);
+ q = prefix_roota(directory, p);
+
+ if (path_is_mount_point(p, 0) > 0) {
if (arg_link_journal != LINK_AUTO) {
log_error("%s: already a mount point, refusing to use for journal", p);
return -EEXIST;
@@ -1771,7 +2164,7 @@ static int setup_journal(const char *directory) {
return 0;
}
- if (path_is_mount_point(q, false) > 0) {
+ if (path_is_mount_point(q, 0) > 0) {
if (arg_link_journal != LINK_AUTO) {
log_error("%s: already a mount point, refusing to use for journal", q);
return -EEXIST;
@@ -1786,7 +2179,7 @@ static int setup_journal(const char *directory) {
arg_link_journal == LINK_AUTO) &&
path_equal(d, q)) {
- r = mkdir_p(q, 0755);
+ r = userns_mkdir(directory, p, 0755, 0, 0);
if (r < 0)
log_warning_errno(errno, "Failed to create directory %s: %m", q);
return 0;
@@ -1824,7 +2217,7 @@ static int setup_journal(const char *directory) {
}
}
- r = mkdir_p(q, 0755);
+ r = userns_mkdir(directory, p, 0755, 0, 0);
if (r < 0)
log_warning_errno(errno, "Failed to create directory %s: %m", q);
return 0;
@@ -1850,13 +2243,13 @@ static int setup_journal(const char *directory) {
if (dir_is_empty(q) == 0)
log_warning("%s is not empty, proceeding anyway.", q);
- r = mkdir_p(q, 0755);
+ r = userns_mkdir(directory, p, 0755, 0, 0);
if (r < 0) {
log_error_errno(errno, "Failed to create %s: %m", q);
return r;
}
- if (mount(p, q, "bind", MS_BIND, NULL) < 0)
+ if (mount(p, q, NULL, MS_BIND, NULL) < 0)
return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m");
return 0;
@@ -1897,6 +2290,8 @@ static int register_machine(pid_t pid, int local_ifindex) {
local_ifindex > 0 ? 1 : 0, local_ifindex);
} else {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ char **i;
+ unsigned j;
r = sd_bus_message_new_method_call(
bus,
@@ -1906,7 +2301,7 @@ static int register_machine(pid_t pid, int local_ifindex) {
"org.freedesktop.machine1.Manager",
"CreateMachineWithNetwork");
if (r < 0)
- return log_error_errno(r, "Failed to create message: %m");
+ return bus_log_create_error(r);
r = sd_bus_message_append(
m,
@@ -1919,22 +2314,26 @@ static int register_machine(pid_t pid, int local_ifindex) {
strempty(arg_directory),
local_ifindex > 0 ? 1 : 0, local_ifindex);
if (r < 0)
- return log_error_errno(r, "Failed to append message arguments: %m");
+ return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
- return log_error_errno(r, "Failed to open container: %m");
+ return bus_log_create_error(r);
if (!isempty(arg_slice)) {
r = sd_bus_message_append(m, "(sv)", "Slice", "s", arg_slice);
if (r < 0)
- return log_error_errno(r, "Failed to append slice: %m");
+ return bus_log_create_error(r);
}
r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict");
if (r < 0)
- return log_error_errno(r, "Failed to add device policy: %m");
+ return bus_log_create_error(r);
+ /* If you make changes here, also make sure to update
+ * systemd-nspawn@.service, to keep the device
+ * policies in sync regardless if we are run with or
+ * without the --keep-unit switch. */
r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 9,
/* Allow the container to
* access and create the API
@@ -1957,11 +2356,53 @@ static int register_machine(pid_t pid, int local_ifindex) {
"/dev/pts/ptmx", "rw",
"char-pts", "rw");
if (r < 0)
- return log_error_errno(r, "Failed to add device whitelist: %m");
+ return bus_log_create_error(r);
+
+ for (j = 0; j < arg_n_custom_mounts; j++) {
+ CustomMount *cm = &arg_custom_mounts[j];
+
+ if (cm->type != CUSTOM_MOUNT_BIND)
+ continue;
+
+ r = is_device_node(cm->source);
+ if (r < 0)
+ return log_error_errno(r, "Failed to stat %s: %m", cm->source);
+
+ if (r) {
+ r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1,
+ cm->source, cm->read_only ? "r" : "rw");
+ if (r < 0)
+ return log_error_errno(r, "Failed to append message arguments: %m");
+ }
+ }
+
+ if (arg_kill_signal != 0) {
+ r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", arg_kill_signal);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed");
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ STRV_FOREACH(i, arg_property) {
+ r = sd_bus_message_open_container(m, 'r', "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = bus_append_unit_property_assignment(m, *i);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
r = sd_bus_message_close_container(m);
if (r < 0)
- return log_error_errno(r, "Failed to close container: %m");
+ return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
}
@@ -1984,6 +2425,11 @@ static int terminate_machine(pid_t pid) {
if (!arg_register)
return 0;
+ /* If we are reusing the unit, then just exit, systemd will do
+ * the right thing when we exit. */
+ if (arg_keep_unit)
+ return 0;
+
r = sd_bus_default_system(&bus);
if (r < 0)
return log_error_errno(r, "Failed to open system bus: %m");
@@ -2046,11 +2492,12 @@ static int reset_audit_loginuid(void) {
r = write_string_file("/proc/self/loginuid", "4294967295");
if (r < 0) {
- log_error("Failed to reset audit login UID. This probably means that your kernel is too\n"
- "old and you have audit enabled. Note that the auditing subsystem is known to\n"
- "be incompatible with containers on old kernels. Please make sure to upgrade\n"
- "your kernel or to off auditing with 'audit=0' on the kernel command line before\n"
- "using systemd-nspawn. Sleeping for 5s... (%s)\n", strerror(-r));
+ log_error_errno(r,
+ "Failed to reset audit login UID. This probably means that your kernel is too\n"
+ "old and you have audit enabled. Note that the auditing subsystem is known to\n"
+ "be incompatible with containers on old kernels. Please make sure to upgrade\n"
+ "your kernel or to off auditing with 'audit=0' on the kernel command line before\n"
+ "using systemd-nspawn. Sleeping for 5s... (%m)");
sleep(5);
}
@@ -2181,7 +2628,7 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) {
r = sd_rtnl_call(rtnl, m, 0, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to add new veth interfaces: %m");
+ return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name);
i = (int) if_nametoindex(iface_name);
if (i <= 0)
@@ -2482,19 +2929,20 @@ static int setup_ipvlan(pid_t pid) {
static int setup_seccomp(void) {
#ifdef HAVE_SECCOMP
- static const int blacklist[] = {
- SCMP_SYS(kexec_load),
- SCMP_SYS(open_by_handle_at),
- SCMP_SYS(iopl),
- SCMP_SYS(ioperm),
- SCMP_SYS(swapon),
- SCMP_SYS(swapoff),
- };
-
- static const int kmod_blacklist[] = {
- SCMP_SYS(init_module),
- SCMP_SYS(finit_module),
- SCMP_SYS(delete_module),
+ static const struct {
+ uint64_t capability;
+ int syscall_num;
+ } blacklist[] = {
+ { CAP_SYS_RAWIO, SCMP_SYS(iopl) },
+ { CAP_SYS_RAWIO, SCMP_SYS(ioperm) },
+ { CAP_SYS_BOOT, SCMP_SYS(kexec_load) },
+ { CAP_SYS_ADMIN, SCMP_SYS(swapon) },
+ { CAP_SYS_ADMIN, SCMP_SYS(swapoff) },
+ { CAP_SYS_ADMIN, SCMP_SYS(open_by_handle_at) },
+ { CAP_SYS_MODULE, SCMP_SYS(init_module) },
+ { CAP_SYS_MODULE, SCMP_SYS(finit_module) },
+ { CAP_SYS_MODULE, SCMP_SYS(delete_module) },
+ { CAP_SYSLOG, SCMP_SYS(syslog) },
};
scmp_filter_ctx seccomp;
@@ -2512,7 +2960,10 @@ static int setup_seccomp(void) {
}
for (i = 0; i < ELEMENTSOF(blacklist); i++) {
- r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), blacklist[i], 0);
+ if (arg_retain & (1ULL << blacklist[i].capability))
+ continue;
+
+ r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0);
if (r == -EFAULT)
continue; /* unknown syscall */
if (r < 0) {
@@ -2521,19 +2972,6 @@ static int setup_seccomp(void) {
}
}
- /* If the CAP_SYS_MODULE capability is not requested then
- * we'll block the kmod syscalls too */
- if (!(arg_retain & (1ULL << CAP_SYS_MODULE))) {
- for (i = 0; i < ELEMENTSOF(kmod_blacklist); i++) {
- r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), kmod_blacklist[i], 0);
- if (r == -EFAULT)
- continue; /* unknown syscall */
- if (r < 0) {
- log_error_errno(r, "Failed to block syscall: %m");
- goto finish;
- }
- }
- }
/*
Audit is broken in containers, much of the userspace audit
@@ -2584,10 +3022,16 @@ static int setup_propagate(const char *root) {
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
(void) mkdir_p(p, 0600);
- q = strjoina(root, "/run/systemd/nspawn/incoming");
- mkdir_parents(q, 0755);
- mkdir_p(q, 0600);
+ if (userns_mkdir(root, "/run/systemd", 0755, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to create /run/systemd: %m");
+
+ if (userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to create /run/systemd/nspawn: %m");
+
+ if (userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0) < 0)
+ return log_error_errno(errno, "Failed to create /run/systemd/nspawn/incoming: %m");
+ q = prefix_roota(root, "/run/systemd/nspawn/incoming");
if (mount(p, q, NULL, MS_BIND, NULL) < 0)
return log_error_errno(errno, "Failed to install propagation bind mount.");
@@ -2676,7 +3120,7 @@ static int setup_image(char **device_path, int *loop_nr) {
#define PARTITION_TABLE_BLURB \
"Note that the disk image needs to either contain only a single MBR partition of\n" \
- "type 0x83 that is marked bootable, or a sinlge GPT partition of type" \
+ "type 0x83 that is marked bootable, or a single GPT partition of type " \
"0FC63DAF-8483-4772-8E79-3D69D8477DE4 or follow\n" \
" http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" \
"to be bootable with systemd-nspawn."
@@ -2748,7 +3192,7 @@ static int dissect_image(
return -errno;
}
- blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
+ (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
is_gpt = streq_ptr(pttype, "gpt");
is_mbr = streq_ptr(pttype, "dos");
@@ -3050,7 +3494,7 @@ static int dissect_image(
return 0;
#else
log_error("--image= is not supported, compiled without blkid support.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
#endif
}
@@ -3105,7 +3549,7 @@ static int mount_device(const char *what, const char *where, const char *directo
if (streq(fstype, "crypto_LUKS")) {
log_error("nspawn currently does not support LUKS disk images.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
if (mount(what, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), NULL) < 0)
@@ -3114,7 +3558,7 @@ static int mount_device(const char *what, const char *where, const char *directo
return 0;
#else
log_error("--image= is not supported, compiled without blkid support.");
- return -ENOTSUP;
+ return -EOPNOTSUPP;
#endif
}
@@ -3246,14 +3690,9 @@ static int change_uid_gid(char **_home) {
if (!arg_user || streq(arg_user, "root") || streq(arg_user, "0")) {
/* Reset everything fully to 0, just in case */
- if (setgroups(0, NULL) < 0)
- return log_error_errno(errno, "setgroups() failed: %m");
-
- if (setresgid(0, 0, 0) < 0)
- return log_error_errno(errno, "setregid() failed: %m");
-
- if (setresuid(0, 0, 0) < 0)
- return log_error_errno(errno, "setreuid() failed: %m");
+ r = reset_uid_gid();
+ if (r < 0)
+ return log_error_errno(r, "Failed to become root: %m");
*_home = NULL;
return 0;
@@ -3397,9 +3836,9 @@ static int change_uid_gid(char **_home) {
if (r < 0 && r != -EEXIST)
return log_error_errno(r, "Failed to make home directory: %m");
- fchown(STDIN_FILENO, uid, gid);
- fchown(STDOUT_FILENO, uid, gid);
- fchown(STDERR_FILENO, uid, gid);
+ (void) fchown(STDIN_FILENO, uid, gid);
+ (void) fchown(STDOUT_FILENO, uid, gid);
+ (void) fchown(STDERR_FILENO, uid, gid);
if (setgroups(n_uids, uids) < 0)
return log_error_errno(errno, "Failed to set auxiliary groups: %m");
@@ -3490,7 +3929,7 @@ static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo
pid = PTR_TO_UINT32(userdata);
if (pid > 0) {
- if (kill(pid, SIGRTMIN+3) >= 0) {
+ if (kill(pid, arg_kill_signal) >= 0) {
log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
sd_event_source_set_userdata(s, NULL);
return 0;
@@ -3523,7 +3962,8 @@ static int determine_names(void) {
if (r < 0)
return log_error_errno(r, "Invalid image directory: %m");
- arg_read_only = arg_read_only || i->read_only;
+ if (!arg_ephemeral)
+ arg_read_only = arg_read_only || i->read_only;
} else
arg_directory = get_current_dir_name();
@@ -3567,6 +4007,447 @@ static int determine_names(void) {
return 0;
}
+static int determine_uid_shift(const char *directory) {
+ int r;
+
+ if (!arg_userns) {
+ arg_uid_shift = 0;
+ return 0;
+ }
+
+ if (arg_uid_shift == UID_INVALID) {
+ struct stat st;
+
+ r = stat(directory, &st);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to determine UID base of %s: %m", directory);
+
+ arg_uid_shift = st.st_uid & UINT32_C(0xffff0000);
+
+ if (arg_uid_shift != (st.st_gid & UINT32_C(0xffff0000))) {
+ log_error("UID and GID base of %s don't match.", directory);
+ return -EINVAL;
+ }
+
+ arg_uid_range = UINT32_C(0x10000);
+ }
+
+ if (arg_uid_shift > (uid_t) -1 - arg_uid_range) {
+ log_error("UID base too high for UID range.");
+ return -EINVAL;
+ }
+
+ log_info("Using user namespaces with base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
+ return 0;
+}
+
+static int inner_child(
+ Barrier *barrier,
+ const char *directory,
+ bool secondary,
+ int kmsg_socket,
+ int rtnl_socket,
+ FDSet *fds,
+ int argc,
+ char *argv[]) {
+
+ _cleanup_free_ char *home = NULL;
+ unsigned n_env = 2;
+ const char *envp[] = {
+ "PATH=" DEFAULT_PATH_SPLIT_USR,
+ "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
+ NULL, /* TERM */
+ NULL, /* HOME */
+ NULL, /* USER */
+ NULL, /* LOGNAME */
+ NULL, /* container_uuid */
+ NULL, /* LISTEN_FDS */
+ NULL, /* LISTEN_PID */
+ NULL
+ };
+
+ _cleanup_strv_free_ char **env_use = NULL;
+ int r;
+
+ assert(barrier);
+ assert(directory);
+ assert(kmsg_socket >= 0);
+
+ if (arg_userns) {
+ /* Tell the parent, that it now can write the UID map. */
+ (void) barrier_place(barrier); /* #1 */
+
+ /* Wait until the parent wrote the UID map */
+ if (!barrier_place_and_sync(barrier)) { /* #2 */
+ log_error("Parent died too early");
+ return -ESRCH;
+ }
+ }
+
+ r = mount_all(NULL, true);
+ if (r < 0)
+ return r;
+
+ /* Wait until we are cgroup-ified, so that we
+ * can mount the right cgroup path writable */
+ if (!barrier_place_and_sync(barrier)) { /* #3 */
+ log_error("Parent died too early");
+ return -ESRCH;
+ }
+
+ r = mount_systemd_cgroup_writable("");
+ if (r < 0)
+ return r;
+
+ r = reset_uid_gid();
+ if (r < 0)
+ return log_error_errno(r, "Couldn't become new root: %m");
+
+ r = setup_boot_id(NULL);
+ if (r < 0)
+ return r;
+
+ r = setup_kmsg(NULL, kmsg_socket);
+ if (r < 0)
+ return r;
+ kmsg_socket = safe_close(kmsg_socket);
+
+ umask(0022);
+
+ if (setsid() < 0)
+ return log_error_errno(errno, "setsid() failed: %m");
+
+ if (arg_private_network)
+ loopback_setup();
+
+ r = send_rtnl(rtnl_socket);
+ if (r < 0)
+ return r;
+ rtnl_socket = safe_close(rtnl_socket);
+
+ if (drop_capabilities() < 0)
+ return log_error_errno(errno, "drop_capabilities() failed: %m");
+
+ setup_hostname();
+
+ if (arg_personality != PERSONALITY_INVALID) {
+ if (personality(arg_personality) < 0)
+ return log_error_errno(errno, "personality() failed: %m");
+ } else if (secondary) {
+ if (personality(PER_LINUX32) < 0)
+ return log_error_errno(errno, "personality() failed: %m");
+ }
+
+#ifdef HAVE_SELINUX
+ if (arg_selinux_context)
+ if (setexeccon((security_context_t) arg_selinux_context) < 0)
+ return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
+#endif
+
+ r = change_uid_gid(&home);
+ if (r < 0)
+ return r;
+
+ envp[n_env] = strv_find_prefix(environ, "TERM=");
+ if (envp[n_env])
+ n_env ++;
+
+ if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) ||
+ (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) ||
+ (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
+ return log_oom();
+
+ if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) {
+ char as_uuid[37];
+
+ if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
+ return log_oom();
+ }
+
+ if (fdset_size(fds) > 0) {
+ r = fdset_cloexec(fds, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to unset O_CLOEXEC for file descriptors.");
+
+ if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", fdset_size(fds)) < 0) ||
+ (asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0))
+ return log_oom();
+ }
+
+ env_use = strv_env_merge(2, envp, arg_setenv);
+ if (!env_use)
+ return log_oom();
+
+ /* Let the parent know that we are ready and
+ * wait until the parent is ready with the
+ * setup, too... */
+ if (!barrier_place_and_sync(barrier)) { /* #4 */
+ log_error("Parent died too early");
+ return -ESRCH;
+ }
+
+ /* Now, explicitly close the log, so that we
+ * then can close all remaining fds. Closing
+ * the log explicitly first has the benefit
+ * that the logging subsystem knows about it,
+ * and is thus ready to be reopened should we
+ * need it again. Note that the other fds
+ * closed here are at least the locking and
+ * barrier fds. */
+ log_close();
+ (void) fdset_close_others(fds);
+
+ if (arg_boot) {
+ char **a;
+ size_t m;
+
+ /* Automatically search for the init system */
+
+ m = 1 + argc - optind;
+ a = newa(char*, m + 1);
+ memcpy(a + 1, argv + optind, m * sizeof(char*));
+
+ a[0] = (char*) "/usr/lib/systemd/systemd";
+ execve(a[0], a, env_use);
+
+ a[0] = (char*) "/lib/systemd/systemd";
+ execve(a[0], a, env_use);
+
+ a[0] = (char*) "/sbin/init";
+ execve(a[0], a, env_use);
+ } else if (argc > optind)
+ execvpe(argv[optind], argv + optind, env_use);
+ else {
+ chdir(home ? home : "/root");
+ execle("/bin/bash", "-bash", NULL, env_use);
+ execle("/bin/sh", "-sh", NULL, env_use);
+ }
+
+ (void) log_open();
+ return log_error_errno(errno, "execv() failed: %m");
+}
+
+static int outer_child(
+ Barrier *barrier,
+ const char *directory,
+ const char *console,
+ const char *root_device, bool root_device_rw,
+ const char *home_device, bool home_device_rw,
+ const char *srv_device, bool srv_device_rw,
+ bool interactive,
+ bool secondary,
+ int pid_socket,
+ int kmsg_socket,
+ int rtnl_socket,
+ FDSet *fds,
+ int argc,
+ char *argv[]) {
+
+ pid_t pid;
+ ssize_t l;
+ int r;
+
+ assert(barrier);
+ assert(directory);
+ assert(console);
+ assert(pid_socket >= 0);
+ assert(kmsg_socket >= 0);
+
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
+ return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
+
+ if (interactive) {
+ close_nointr(STDIN_FILENO);
+ close_nointr(STDOUT_FILENO);
+ close_nointr(STDERR_FILENO);
+
+ r = open_terminal(console, O_RDWR);
+ if (r != STDIN_FILENO) {
+ if (r >= 0) {
+ safe_close(r);
+ r = -EINVAL;
+ }
+
+ return log_error_errno(r, "Failed to open console: %m");
+ }
+
+ if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
+ dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
+ return log_error_errno(errno, "Failed to duplicate console: %m");
+ }
+
+ r = reset_audit_loginuid();
+ if (r < 0)
+ return r;
+
+ /* Mark everything as slave, so that we still
+ * receive mounts from the real root, but don't
+ * propagate mounts to the real root. */
+ if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
+ return log_error_errno(errno, "MS_SLAVE|MS_REC failed: %m");
+
+ r = mount_devices(directory,
+ root_device, root_device_rw,
+ home_device, home_device_rw,
+ srv_device, srv_device_rw);
+ if (r < 0)
+ return r;
+
+ r = determine_uid_shift(directory);
+ if (r < 0)
+ return r;
+
+ /* Turn directory into bind mount */
+ if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0)
+ return log_error_errno(errno, "Failed to make bind mount: %m");
+
+ r = setup_volatile(directory);
+ if (r < 0)
+ return r;
+
+ r = setup_volatile_state(directory);
+ if (r < 0)
+ return r;
+
+ r = base_filesystem_create(directory, arg_uid_shift, (gid_t) arg_uid_shift);
+ if (r < 0)
+ return r;
+
+ if (arg_read_only) {
+ r = bind_remount_recursive(directory, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make tree read-only: %m");
+ }
+
+ r = mount_all(directory, false);
+ if (r < 0)
+ return r;
+
+ if (copy_devnodes(directory) < 0)
+ return r;
+
+ dev_setup(directory, arg_uid_shift, arg_uid_shift);
+
+ if (setup_pts(directory) < 0)
+ return r;
+
+ r = setup_propagate(directory);
+ if (r < 0)
+ return r;
+
+ r = setup_dev_console(directory, console);
+ if (r < 0)
+ return r;
+
+ r = setup_seccomp();
+ if (r < 0)
+ return r;
+
+ r = setup_timezone(directory);
+ if (r < 0)
+ return r;
+
+ r = setup_resolv_conf(directory);
+ if (r < 0)
+ return r;
+
+ r = setup_journal(directory);
+ if (r < 0)
+ return r;
+
+ r = mount_custom(directory);
+ if (r < 0)
+ return r;
+
+ r = mount_cgroup(directory);
+ if (r < 0)
+ return r;
+
+ r = mount_move_root(directory);
+ if (r < 0)
+ return log_error_errno(r, "Failed to move root directory: %m");
+
+ pid = raw_clone(SIGCHLD|CLONE_NEWNS|
+ (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) |
+ (arg_private_network ? CLONE_NEWNET : 0) |
+ (arg_userns ? CLONE_NEWUSER : 0),
+ NULL);
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork inner child: %m");
+
+ if (pid == 0) {
+ pid_socket = safe_close(pid_socket);
+
+ /* The inner child has all namespaces that are
+ * requested, so that we all are owned by the user if
+ * user namespaces are turned on. */
+
+ r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, fds, argc, argv);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ l = send(pid_socket, &pid, sizeof(pid), MSG_NOSIGNAL);
+ if (l < 0)
+ return log_error_errno(errno, "Failed to send PID: %m");
+ if (l != sizeof(pid)) {
+ log_error("Short write while sending PID.");
+ return -EIO;
+ }
+
+ pid_socket = safe_close(pid_socket);
+
+ return 0;
+}
+
+static int setup_uid_map(pid_t pid) {
+ char uid_map[strlen("/proc//uid_map") + DECIMAL_STR_MAX(uid_t) + 1], line[DECIMAL_STR_MAX(uid_t)*3+3+1];
+ int r;
+
+ assert(pid > 1);
+
+ xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid);
+ xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, arg_uid_shift, arg_uid_range);
+ r = write_string_file(uid_map, line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write UID map: %m");
+
+ /* We always assign the same UID and GID ranges */
+ xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid);
+ r = write_string_file(uid_map, line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write GID map: %m");
+
+ return 0;
+}
+
+static int chown_cgroup(pid_t pid) {
+ _cleanup_free_ char *path = NULL, *fs = NULL;
+ _cleanup_close_ int fd = -1;
+ const char *fn;
+ int r;
+
+ r = cg_pid_get_path(NULL, pid, &path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get container cgroup path: %m");
+
+ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &fs);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
+
+ fd = open(fs, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", fs);
+
+ FOREACH_STRING(fn, ".", "tasks", "notify_on_release", "cgroup.procs", "cgroup.clone_children")
+ if (fchownat(fd, fn, arg_uid_shift, arg_uid_shift, 0) < 0)
+ log_warning_errno(errno, "Failed to chown() cgroup file %s, ignoring: %m", fn);
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
_cleanup_free_ char *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL, *console = NULL;
@@ -3581,6 +4462,7 @@ int main(int argc, char *argv[]) {
int ret = EXIT_SUCCESS;
union in_addr_union exposed = {};
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
+ bool interactive;
log_parse_environment();
log_open();
@@ -3599,13 +4481,6 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (sd_booted() <= 0) {
- log_error("Not running on a systemd system.");
- r = -EINVAL;
- goto finish;
- }
-
- log_close();
n_fd_passed = sd_listen_fds(false);
if (n_fd_passed > 0) {
r = fdset_new_listen_fds(&fds, false);
@@ -3614,8 +4489,6 @@ int main(int argc, char *argv[]) {
goto finish;
}
}
- fdset_close_others(fds);
- log_open();
if (arg_directory) {
assert(!arg_image);
@@ -3627,7 +4500,7 @@ int main(int argc, char *argv[]) {
}
if (arg_ephemeral) {
- char *np;
+ _cleanup_free_ char *np = NULL;
/* If the specified path is a mount point we
* generate the new snapshot immediately
@@ -3635,7 +4508,7 @@ int main(int argc, char *argv[]) {
* the specified is not a mount point we
* create the new snapshot in the parent
* directory, just next to it. */
- r = path_is_mount_point(arg_directory, false);
+ r = path_is_mount_point(arg_directory, 0);
if (r < 0) {
log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory);
goto finish;
@@ -3655,15 +4528,15 @@ int main(int argc, char *argv[]) {
goto finish;
}
- r = btrfs_subvol_snapshot(arg_directory, np, arg_read_only, true);
+ r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
if (r < 0) {
- free(np);
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
goto finish;
}
free(arg_directory);
arg_directory = np;
+ np = NULL;
remove_subvol = true;
@@ -3679,7 +4552,7 @@ int main(int argc, char *argv[]) {
}
if (arg_template) {
- r = btrfs_subvol_snapshot(arg_template, arg_directory, arg_read_only, true);
+ r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
if (r == -EEXIST) {
if (!arg_quiet)
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
@@ -3754,6 +4627,14 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ r = custom_mounts_prepare();
+ if (r < 0)
+ goto finish;
+
+ interactive =
+ isatty(STDIN_FILENO) > 0 &&
+ isatty(STDOUT_FILENO) > 0;
+
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
if (master < 0) {
r = log_error_errno(errno, "Failed to acquire pseudo tty: %m");
@@ -3766,15 +4647,15 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (!arg_quiet)
- log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.",
- arg_machine, arg_image ?: arg_directory);
-
if (unlockpt(master) < 0) {
r = log_error_errno(errno, "Failed to unlock tty: %m");
goto finish;
}
+ if (!arg_quiet)
+ log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.",
+ arg_machine, arg_image ?: arg_directory);
+
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1);
assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
@@ -3782,14 +4663,25 @@ int main(int argc, char *argv[]) {
assert_se(sigemptyset(&mask_chld) == 0);
assert_se(sigaddset(&mask_chld, SIGCHLD) == 0);
+ if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
+ r = log_error_errno(errno, "Failed to become subreaper: %m");
+ goto finish;
+ }
+
for (;;) {
- _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 };
+ _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 };
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
- struct sigaction sa = {
+ static const struct sigaction sa = {
.sa_handler = nop_handler,
.sa_flags = SA_NOCLDSTOP,
};
+ int ifi = 0;
+ ssize_t l;
+ _cleanup_event_unref_ sd_event *event = NULL;
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
+ _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+ char last_char = 0;
r = barrier_create(&barrier);
if (r < 0) {
@@ -3807,6 +4699,11 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, pid_socket_pair) < 0) {
+ r = log_error_errno(errno, "Failed to create pid socket pair: %m");
+ goto finish;
+ }
+
/* Child can be killed before execv(), so handle SIGCHLD
* in order to interrupt parent's blocking calls and
* give it a chance to call wait() and terminate. */
@@ -3822,9 +4719,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- pid = raw_clone(SIGCHLD|CLONE_NEWNS|
- (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS)|
- (arg_private_network ? CLONE_NEWNET : 0), NULL);
+ pid = raw_clone(SIGCHLD|CLONE_NEWNS, NULL);
if (pid < 0) {
if (errno == EINVAL)
r = log_error_errno(errno, "clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m");
@@ -3835,421 +4730,191 @@ int main(int argc, char *argv[]) {
}
if (pid == 0) {
- /* child */
- _cleanup_free_ char *home = NULL;
- unsigned n_env = 2;
- const char *envp[] = {
- "PATH=" DEFAULT_PATH_SPLIT_USR,
- "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
- NULL, /* TERM */
- NULL, /* HOME */
- NULL, /* USER */
- NULL, /* LOGNAME */
- NULL, /* container_uuid */
- NULL, /* LISTEN_FDS */
- NULL, /* LISTEN_PID */
- NULL
- };
- char **env_use;
-
+ /* The outer child only has a file system namespace. */
barrier_set_role(&barrier, BARRIER_CHILD);
- envp[n_env] = strv_find_prefix(environ, "TERM=");
- if (envp[n_env])
- n_env ++;
-
master = safe_close(master);
- close_nointr(STDIN_FILENO);
- close_nointr(STDOUT_FILENO);
- close_nointr(STDERR_FILENO);
-
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
+ pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
reset_all_signal_handlers();
reset_signal_mask();
- r = open_terminal(console, O_RDWR);
- if (r != STDIN_FILENO) {
- if (r >= 0) {
- safe_close(r);
- r = -EINVAL;
- }
-
- log_error_errno(r, "Failed to open console: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
- dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
- log_error_errno(errno, "Failed to duplicate console: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (setsid() < 0) {
- log_error_errno(errno, "setsid() failed: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (reset_audit_loginuid() < 0)
- _exit(EXIT_FAILURE);
-
- if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) {
- log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
- _exit(EXIT_FAILURE);
- }
-
- /* Mark everything as slave, so that we still
- * receive mounts from the real root, but don't
- * propagate mounts to the real root. */
- if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
- log_error_errno(errno, "MS_SLAVE|MS_REC failed: %m");
- _exit(EXIT_FAILURE);
- }
-
- if (mount_devices(arg_directory,
- root_device, root_device_rw,
- home_device, home_device_rw,
- srv_device, srv_device_rw) < 0)
- _exit(EXIT_FAILURE);
-
- /* Turn directory into bind mount */
- if (mount(arg_directory, arg_directory, "bind", MS_BIND|MS_REC, NULL) < 0) {
- log_error_errno(errno, "Failed to make bind mount: %m");
- _exit(EXIT_FAILURE);
- }
-
- r = setup_volatile(arg_directory);
- if (r < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_volatile_state(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- r = base_filesystem_create(arg_directory);
+ r = outer_child(&barrier,
+ arg_directory,
+ console,
+ root_device, root_device_rw,
+ home_device, home_device_rw,
+ srv_device, srv_device_rw,
+ interactive,
+ secondary,
+ pid_socket_pair[1],
+ kmsg_socket_pair[1],
+ rtnl_socket_pair[1],
+ fds,
+ argc, argv);
if (r < 0)
_exit(EXIT_FAILURE);
- if (arg_read_only) {
- r = bind_remount_recursive(arg_directory, true);
- if (r < 0) {
- log_error_errno(r, "Failed to make tree read-only: %m");
- _exit(EXIT_FAILURE);
- }
- }
-
- if (mount_all(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (copy_devnodes(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_ptmx(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- dev_setup(arg_directory);
-
- if (setup_propagate(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_seccomp() < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_dev_console(arg_directory, console) < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_kmsg(arg_directory, kmsg_socket_pair[1]) < 0)
- _exit(EXIT_FAILURE);
- kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
-
- if (send_rtnl(rtnl_socket_pair[1]) < 0)
- _exit(EXIT_FAILURE);
- rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
-
- /* Tell the parent that we are ready, and that
- * it can cgroupify us to that we lack access
- * to certain devices and resources. */
- (void) barrier_place(&barrier);
-
- if (setup_boot_id(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_timezone(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_resolv_conf(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (setup_journal(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- if (mount_binds(arg_directory, arg_bind, false) < 0)
- _exit(EXIT_FAILURE);
-
- if (mount_binds(arg_directory, arg_bind_ro, true) < 0)
- _exit(EXIT_FAILURE);
-
- if (mount_tmpfs(arg_directory) < 0)
- _exit(EXIT_FAILURE);
-
- /* Wait until we are cgroup-ified, so that we
- * can mount the right cgroup path writable */
- (void) barrier_sync_next(&barrier);
-
- if (mount_cgroup(arg_directory) < 0)
- _exit(EXIT_FAILURE);
+ _exit(EXIT_SUCCESS);
+ }
- if (chdir(arg_directory) < 0) {
- log_error_errno(errno, "chdir(%s) failed: %m", arg_directory);
- _exit(EXIT_FAILURE);
- }
+ barrier_set_role(&barrier, BARRIER_PARENT);
- if (mount(arg_directory, "/", NULL, MS_MOVE, NULL) < 0) {
- log_error_errno(errno, "mount(MS_MOVE) failed: %m");
- _exit(EXIT_FAILURE);
- }
+ fdset_free(fds);
+ fds = NULL;
- if (chroot(".") < 0) {
- log_error_errno(errno, "chroot() failed: %m");
- _exit(EXIT_FAILURE);
- }
+ kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
+ rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
+ pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
- if (chdir("/") < 0) {
- log_error_errno(errno, "chdir() failed: %m");
- _exit(EXIT_FAILURE);
- }
+ /* Wait for the outer child. */
+ r = wait_for_terminate_and_warn("namespace helper", pid, NULL);
+ if (r < 0)
+ goto finish;
+ if (r != 0) {
+ r = -EIO;
+ goto finish;
+ }
+ pid = 0;
- umask(0022);
+ /* And now retrieve the PID of the inner child. */
+ l = recv(pid_socket_pair[0], &pid, sizeof(pid), 0);
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read inner child PID: %m");
+ goto finish;
+ }
+ if (l != sizeof(pid)) {
+ log_error("Short read while reading inner child PID: %m");
+ r = EIO;
+ goto finish;
+ }
- if (arg_private_network)
- loopback_setup();
+ log_debug("Init process invoked as PID " PID_FMT, pid);
- if (drop_capabilities() < 0) {
- log_error_errno(errno, "drop_capabilities() failed: %m");
- _exit(EXIT_FAILURE);
+ if (arg_userns) {
+ if (!barrier_place_and_sync(&barrier)) { /* #1 */
+ log_error("Child died too early.");
+ r = -ESRCH;
+ goto finish;
}
- r = change_uid_gid(&home);
+ r = setup_uid_map(pid);
if (r < 0)
- _exit(EXIT_FAILURE);
-
- if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) ||
- (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) ||
- (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) {
- log_oom();
- _exit(EXIT_FAILURE);
- }
-
- if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) {
- char as_uuid[37];
-
- if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0) {
- log_oom();
- _exit(EXIT_FAILURE);
- }
- }
-
- if (fdset_size(fds) > 0) {
- r = fdset_cloexec(fds, false);
- if (r < 0) {
- log_error_errno(r, "Failed to unset O_CLOEXEC for file descriptors.");
- _exit(EXIT_FAILURE);
- }
-
- if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", n_fd_passed) < 0) ||
- (asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0)) {
- log_oom();
- _exit(EXIT_FAILURE);
- }
- }
-
- setup_hostname();
-
- if (arg_personality != 0xffffffffLU) {
- if (personality(arg_personality) < 0) {
- log_error_errno(errno, "personality() failed: %m");
- _exit(EXIT_FAILURE);
- }
- } else if (secondary) {
- if (personality(PER_LINUX32) < 0) {
- log_error_errno(errno, "personality() failed: %m");
- _exit(EXIT_FAILURE);
- }
- }
-
-#ifdef HAVE_SELINUX
- if (arg_selinux_context)
- if (setexeccon((security_context_t) arg_selinux_context) < 0) {
- log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
- _exit(EXIT_FAILURE);
- }
-#endif
+ goto finish;
- if (!strv_isempty(arg_setenv)) {
- char **n;
+ (void) barrier_place(&barrier); /* #2 */
+ }
- n = strv_env_merge(2, envp, arg_setenv);
- if (!n) {
- log_oom();
- _exit(EXIT_FAILURE);
- }
+ r = move_network_interfaces(pid);
+ if (r < 0)
+ goto finish;
- env_use = n;
- } else
- env_use = (char**) envp;
+ r = setup_veth(pid, veth_name, &ifi);
+ if (r < 0)
+ goto finish;
- /* Wait until the parent is ready with the setup, too... */
- if (!barrier_place_and_sync(&barrier))
- _exit(EXIT_FAILURE);
+ r = setup_bridge(veth_name, &ifi);
+ if (r < 0)
+ goto finish;
- if (arg_boot) {
- char **a;
- size_t l;
+ r = setup_macvlan(pid);
+ if (r < 0)
+ goto finish;
- /* Automatically search for the init system */
+ r = setup_ipvlan(pid);
+ if (r < 0)
+ goto finish;
- l = 1 + argc - optind;
- a = newa(char*, l + 1);
- memcpy(a + 1, argv + optind, l * sizeof(char*));
+ r = register_machine(pid, ifi);
+ if (r < 0)
+ goto finish;
- a[0] = (char*) "/usr/lib/systemd/systemd";
- execve(a[0], a, env_use);
+ r = chown_cgroup(pid);
+ if (r < 0)
+ goto finish;
- a[0] = (char*) "/lib/systemd/systemd";
- execve(a[0], a, env_use);
+ /* Notify the child that the parent is ready with all
+ * its setup (including cgroup-ification), and that
+ * the child can now hand over control to the code to
+ * run inside the container. */
+ (void) barrier_place(&barrier); /* #3 */
- a[0] = (char*) "/sbin/init";
- execve(a[0], a, env_use);
- } else if (argc > optind)
- execvpe(argv[optind], argv + optind, env_use);
- else {
- chdir(home ? home : "/root");
- execle("/bin/bash", "-bash", NULL, env_use);
- execle("/bin/sh", "-sh", NULL, env_use);
- }
+ /* Block SIGCHLD here, before notifying child.
+ * process_pty() will handle it with the other signals. */
+ assert_se(sigprocmask(SIG_BLOCK, &mask_chld, NULL) >= 0);
- log_error_errno(errno, "execv() failed: %m");
- _exit(EXIT_FAILURE);
+ /* Reset signal to default */
+ r = default_signals(SIGCHLD, -1);
+ if (r < 0) {
+ log_error_errno(r, "Failed to reset SIGCHLD: %m");
+ goto finish;
}
- barrier_set_role(&barrier, BARRIER_PARENT);
- fdset_free(fds);
- fds = NULL;
-
- kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
- rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
-
- /* Wait for the most basic Child-setup to be done,
- * before we add hardware to it, and place it in a
- * cgroup. */
- if (barrier_sync_next(&barrier)) {
- int ifi = 0;
-
- r = move_network_interfaces(pid);
- if (r < 0)
- goto finish;
-
- r = setup_veth(pid, veth_name, &ifi);
- if (r < 0)
- goto finish;
+ /* Let the child know that we are ready and wait that the child is completely ready now. */
+ if (!barrier_place_and_sync(&barrier)) { /* #5 */
+ log_error("Client died too early.");
+ r = -ESRCH;
+ goto finish;
+ }
- r = setup_bridge(veth_name, &ifi);
- if (r < 0)
- goto finish;
+ sd_notifyf(false,
+ "READY=1\n"
+ "STATUS=Container running.\n"
+ "X_NSPAWN_LEADER_PID=" PID_FMT, pid);
- r = setup_macvlan(pid);
- if (r < 0)
- goto finish;
-
- r = setup_ipvlan(pid);
- if (r < 0)
- goto finish;
+ r = sd_event_new(&event);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get default event source: %m");
+ goto finish;
+ }
- r = register_machine(pid, ifi);
- if (r < 0)
- goto finish;
+ if (arg_kill_signal > 0) {
+ /* Try to kill the init system on SIGINT or SIGTERM */
+ sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ } else {
+ /* Immediately exit */
+ sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+ }
- /* Block SIGCHLD here, before notifying child.
- * process_pty() will handle it with the other signals. */
- r = sigprocmask(SIG_BLOCK, &mask_chld, NULL);
- if (r < 0)
- goto finish;
+ /* simply exit on sigchld */
+ sd_event_add_signal(event, NULL, SIGCHLD, NULL, NULL);
- /* Reset signal to default */
- r = default_signals(SIGCHLD, -1);
+ if (arg_expose_ports) {
+ r = watch_rtnl(event, rtnl_socket_pair[0], &exposed, &rtnl);
if (r < 0)
goto finish;
- /* Notify the child that the parent is ready with all
- * its setup, and that the child can now hand over
- * control to the code to run inside the container. */
- (void) barrier_place(&barrier);
-
- /* And wait that the child is completely ready now. */
- if (barrier_place_and_sync(&barrier)) {
- _cleanup_event_unref_ sd_event *event = NULL;
- _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- char last_char = 0;
-
- sd_notifyf(false,
- "READY=1\n"
- "STATUS=Container running.\n"
- "X_NSPAWN_LEADER_PID=" PID_FMT, pid);
-
- r = sd_event_new(&event);
- if (r < 0) {
- log_error_errno(r, "Failed to get default event source: %m");
- goto finish;
- }
-
- if (arg_boot) {
- /* Try to kill the init system on SIGINT or SIGTERM */
- sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid));
- sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid));
- } else {
- /* Immediately exit */
- sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
- sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
- }
-
- /* simply exit on sigchld */
- sd_event_add_signal(event, NULL, SIGCHLD, NULL, NULL);
-
- if (arg_expose_ports) {
- r = watch_rtnl(event, rtnl_socket_pair[0], &exposed, &rtnl);
- if (r < 0)
- goto finish;
-
- (void) expose_ports(rtnl, &exposed);
- }
+ (void) expose_ports(rtnl, &exposed);
+ }
- rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
+ rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
- r = pty_forward_new(event, master, true, &forward);
- if (r < 0) {
- log_error_errno(r, "Failed to create PTY forwarder: %m");
- goto finish;
- }
+ r = pty_forward_new(event, master, true, !interactive, &forward);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create PTY forwarder: %m");
+ goto finish;
+ }
- r = sd_event_loop(event);
- if (r < 0) {
- log_error_errno(r, "Failed to run event loop: %m");
- goto finish;
- }
+ r = sd_event_loop(event);
+ if (r < 0) {
+ log_error_errno(r, "Failed to run event loop: %m");
+ goto finish;
+ }
- pty_forward_get_last_char(forward, &last_char);
+ pty_forward_get_last_char(forward, &last_char);
- forward = pty_forward_free(forward);
+ forward = pty_forward_free(forward);
- if (!arg_quiet && last_char != '\n')
- putc('\n', stdout);
+ if (!arg_quiet && last_char != '\n')
+ putc('\n', stdout);
- /* Kill if it is not dead yet anyway */
- terminate_machine(pid);
- }
- }
+ /* Kill if it is not dead yet anyway */
+ terminate_machine(pid);
/* Normally redundant, but better safe than sorry */
kill(pid, SIGKILL);
@@ -4295,15 +4960,15 @@ finish:
"STOPPING=1\n"
"STATUS=Terminating...");
- loop_remove(loop_nr, &image_fd);
-
if (pid > 0)
kill(pid, SIGKILL);
+ loop_remove(loop_nr, &image_fd);
+
if (remove_subvol && arg_directory) {
int k;
- k = btrfs_subvol_remove(arg_directory);
+ k = btrfs_subvol_remove(arg_directory, true);
if (k < 0)
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
}
@@ -4312,7 +4977,7 @@ finish:
const char *p;
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
- (void) rm_rf(p, false, true, false);
+ (void) rm_rf(p, REMOVE_ROOT);
}
free(arg_directory);
@@ -4324,9 +4989,7 @@ finish:
strv_free(arg_network_interfaces);
strv_free(arg_network_macvlan);
strv_free(arg_network_ipvlan);
- strv_free(arg_bind);
- strv_free(arg_bind_ro);
- strv_free(arg_tmpfs);
+ custom_mount_free_all();
flush_ports(&exposed);
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index a939bb267c..31db1aaf68 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -19,20 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <limits.h>
#include <nss.h>
-#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
-#include <unistd.h>
#include <net/if.h>
#include <stdlib.h>
-#include <arpa/inet.h>
#include "local-addresses.h"
#include "macro.h"
#include "nss-util.h"
+#include "hostname-util.h"
#include "util.h"
/* We use 127.0.0.2 as IPv4 address. This has the advantage over
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index 3f32ed0650..bc6c5dc2a0 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -19,16 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <limits.h>
#include <nss.h>
-#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
-#include <unistd.h>
-#include <net/if.h>
#include <stdlib.h>
-#include <arpa/inet.h>
#include <dlfcn.h>
#include "sd-bus.h"
diff --git a/src/path/path.c b/src/path/path.c
index 2f0148f074..f7736a4202 100644
--- a/src/path/path.c
+++ b/src/path/path.c
@@ -22,9 +22,7 @@
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <string.h>
#include "sd-path.h"
#include "build.h"
@@ -117,7 +115,7 @@ static int print_home(const char *n) {
}
log_error("Path %s not known.", n);
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
static void help(void) {
diff --git a/src/python-systemd/_daemon.c b/src/python-systemd/_daemon.c
index 65cfec7ce8..7c5f1b2bb6 100644
--- a/src/python-systemd/_daemon.c
+++ b/src/python-systemd/_daemon.c
@@ -225,7 +225,7 @@ static PyObject* is_socket_inet(PyObject *self, PyObject *args) {
&fd, &family, &type, &listening, &port))
return NULL;
- if (port < 0 || port > INT16_MAX) {
+ if (port < 0 || port > UINT16_MAX) {
set_error(-EINVAL, NULL, "port must fit into uint16_t");
return NULL;
}
diff --git a/src/python-systemd/daemon.py b/src/python-systemd/daemon.py
index 1c386bb6fc..82011ca606 100644
--- a/src/python-systemd/daemon.py
+++ b/src/python-systemd/daemon.py
@@ -26,7 +26,7 @@ def is_socket(fileobj, family=_AF_UNSPEC, type=0, listening=-1):
def is_socket_inet(fileobj, family=_AF_UNSPEC, type=0, listening=-1, port=0):
fd = _convert_fileobj(fileobj)
- return _is_socket_inet(fd, family, type, listening)
+ return _is_socket_inet(fd, family, type, listening, port)
def is_socket_unix(fileobj, type=0, listening=-1, path=None):
fd = _convert_fileobj(fileobj)
diff --git a/src/python-systemd/docs/layout.html b/src/python-systemd/docs/layout.html
index be5ff980ef..930a6a7afe 100644
--- a/src/python-systemd/docs/layout.html
+++ b/src/python-systemd/docs/layout.html
@@ -4,8 +4,6 @@
<a href="../man/systemd.index.html">Index </a>·
<a href="../man/systemd.directives.html">Directives </a>·
<a href="index.html">Python </a>·
- <a href="../libudev/index.html">libudev </a>·
- <a href="../libudev/index.html">gudev </a>
<span style="float:right">systemd {{release}}</span>
<hr />
{% endblock %}
diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c
index 9ae3abd990..a729f592cf 100644
--- a/src/quotacheck/quotacheck.c
+++ b/src/quotacheck/quotacheck.c
@@ -21,12 +21,11 @@
#include <stdio.h>
#include <stdbool.h>
-#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "util.h"
-#include "fileio.h"
+#include "process-util.h"
static bool arg_skip = false;
static bool arg_force = false;
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index ce1bd195d2..92176b1e9f 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
ssize_t k;
int r;
FILE *f;
- bool cleanup_seed_file = true;
+ bool refresh_seed_file = true;
if (argc != 2) {
log_error("This program requires one argument.");
@@ -87,33 +87,29 @@ int main(int argc, char *argv[]) {
if (seed_fd < 0) {
seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (seed_fd < 0) {
- log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
- r = -errno;
+ r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
goto finish;
}
- cleanup_seed_file = false;
+
+ refresh_seed_file = false;
}
random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
if (random_fd < 0) {
random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
if (random_fd < 0) {
- log_error_errno(errno, "Failed to open /dev/urandom: %m");
- r = -errno;
+ r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
goto finish;
}
}
k = loop_read(seed_fd, buf, buf_size, false);
- if (k <= 0) {
-
- if (r != 0)
- log_error_errno(errno, "Failed to read seed from " RANDOM_SEED ": %m");
-
- r = k == 0 ? -EIO : (int) k;
-
- } else {
- lseek(seed_fd, 0, SEEK_SET);
+ if (k < 0)
+ r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m");
+ else if (k == 0)
+ log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding.");
+ else {
+ (void) lseek(seed_fd, 0, SEEK_SET);
r = loop_write(random_fd, buf, (size_t) k, false);
if (r < 0)
@@ -124,40 +120,44 @@ int main(int argc, char *argv[]) {
seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
if (seed_fd < 0) {
- log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
- r = -errno;
+ r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
goto finish;
}
random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (random_fd < 0) {
- log_error_errno(errno, "Failed to open /dev/urandom: %m");
- r = -errno;
+ r = log_error_errno(errno, "Failed to open /dev/urandom: %m");
goto finish;
}
} else {
- log_error("Unknown verb %s.", argv[1]);
+ log_error("Unknown verb '%s'.", argv[1]);
r = -EINVAL;
goto finish;
}
- if (cleanup_seed_file) {
+ if (refresh_seed_file) {
+
/* This is just a safety measure. Given that we are root and
* most likely created the file ourselves the mode and owner
* should be correct anyway. */
- fchmod(seed_fd, 0600);
- fchown(seed_fd, 0, 0);
+ (void) fchmod(seed_fd, 0600);
+ (void) fchown(seed_fd, 0, 0);
k = loop_read(random_fd, buf, buf_size, false);
- if (k <= 0) {
- log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(-r) : "EOF");
- r = k == 0 ? -EIO : (int) k;
- } else {
- r = loop_write(seed_fd, buf, (size_t) k, false);
- if (r < 0)
- log_error_errno(r, "Failed to write new random seed file: %m");
+ if (k < 0) {
+ r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m");
+ goto finish;
}
+ if (k == 0) {
+ log_error("Got EOF while reading from /dev/urandom.");
+ r = -EIO;
+ goto finish;
+ }
+
+ r = loop_write(seed_fd, buf, (size_t) k, false);
+ if (r < 0)
+ log_error_errno(r, "Failed to write new random seed file: %m");
}
finish:
diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c
index 57b47021e4..e701fc9fae 100644
--- a/src/remount-fs/remount-fs.c
+++ b/src/remount-fs/remount-fs.c
@@ -20,7 +20,6 @@
***/
#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
@@ -30,7 +29,7 @@
#include "log.h"
#include "util.h"
#include "path-util.h"
-#include "set.h"
+#include "signal-util.h"
#include "mount-setup.h"
#include "exit-status.h"
@@ -96,15 +95,15 @@ int main(int argc, char *argv[]) {
const char *arguments[5];
/* Child */
- arguments[0] = "/bin/mount";
+ arguments[0] = MOUNT_PATH;
arguments[1] = me->mnt_dir;
arguments[2] = "-o";
arguments[3] = "remount";
arguments[4] = NULL;
- execv("/bin/mount", (char **) arguments);
+ execv(MOUNT_PATH, (char **) arguments);
- log_error_errno(errno, "Failed to execute /bin/mount: %m");
+ log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
_exit(EXIT_FAILURE);
}
@@ -144,9 +143,9 @@ int main(int argc, char *argv[]) {
if (s) {
if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
if (si.si_code == CLD_EXITED)
- log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status);
+ log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status);
else
- log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status));
+ log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status));
ret = EXIT_FAILURE;
}
diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c
index abf5f525dd..d0d61b98ed 100644
--- a/src/reply-password/reply-password.c
+++ b/src/reply-password/reply-password.c
@@ -20,17 +20,9 @@
***/
#include <sys/socket.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <assert.h>
#include <string.h>
#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/signalfd.h>
-#include <getopt.h>
#include <stddef.h>
#include "log.h"
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 43ecf81ef6..068756cab1 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -19,14 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <arpa/inet.h>
#include <net/if.h>
#include <getopt.h>
#include "sd-bus.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "bus-common-errors.h"
#include "in-addr-util.h"
#include "af-list.h"
#include "build.h"
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 03c84786db..171141e3a4 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -183,7 +183,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
}
}
- if (added <= 0) {
+ if (added == 0) {
if (!cname) {
r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of requested type", q->request_hostname);
goto finish;
@@ -220,6 +220,8 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
added++;
}
+ // what about the cache?
+
/* If we didn't find anything, then let's restart the
* query, this time with the cname */
if (added <= 0) {
@@ -273,7 +275,7 @@ static int check_ifindex_flags(int ifindex, uint64_t *flags, sd_bus_error *error
return 0;
}
-static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
Manager *m = userdata;
const char *hostname;
@@ -282,7 +284,6 @@ static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, voi
DnsQuery *q;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -338,7 +339,7 @@ static int bus_method_resolve_hostname(sd_bus *bus, sd_bus_message *message, voi
q->request_hostname = hostname;
q->complete = bus_method_resolve_hostname_complete;
- r = dns_query_bus_track(q, bus, message);
+ r = dns_query_bus_track(q, message);
if (r < 0)
return r;
@@ -398,7 +399,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
}
}
- if (added <= 0) {
+ if (added == 0) {
_cleanup_free_ char *ip = NULL;
in_addr_to_string(q->request_family, &q->request_address, &ip);
@@ -426,7 +427,7 @@ finish:
dns_query_free(q);
}
-static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
_cleanup_free_ char *reverse = NULL;
@@ -438,7 +439,6 @@ static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void
size_t sz;
int r;
- assert(bus);
assert(message);
assert(m);
@@ -491,7 +491,7 @@ static int bus_method_resolve_address(sd_bus *bus, sd_bus_message *message, void
memcpy(&q->request_address, d, sz);
q->complete = bus_method_resolve_address_complete;
- r = dns_query_bus_track(q, bus, message);
+ r = dns_query_bus_track(q, message);
if (r < 0)
return r;
@@ -598,7 +598,7 @@ finish:
dns_query_free(q);
}
-static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
Manager *m = userdata;
@@ -608,7 +608,6 @@ static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void
uint64_t flags;
DnsQuery *q;
- assert(bus);
assert(message);
assert(m);
@@ -644,7 +643,7 @@ static int bus_method_resolve_record(sd_bus *bus, sd_bus_message *message, void
q->request_hostname = name;
q->complete = bus_method_resolve_record_complete;
- r = dns_query_bus_track(q, bus, message);
+ r = dns_query_bus_track(q, message);
if (r < 0)
return r;
@@ -681,12 +680,12 @@ static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
return 0;
}
-static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
+static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
Manager *m = userdata;
int b, r;
- assert(bus);
- assert(bus);
+ assert(message);
+ assert(m);
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c
index 7c4ab18b58..e08eb667cc 100644
--- a/src/resolve/resolved-dns-answer.c
+++ b/src/resolve/resolved-dns-answer.c
@@ -25,8 +25,6 @@
DnsAnswer *dns_answer_new(unsigned n) {
DnsAnswer *a;
- assert(n > 0);
-
a = malloc0(offsetof(DnsAnswer, rrs) + sizeof(DnsResourceRecord*) * n);
if (!a)
return NULL;
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 33ca4d1a45..be52891681 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -91,11 +91,8 @@ void dns_cache_flush(DnsCache *c) {
assert(hashmap_size(c->by_key) == 0);
assert(prioq_size(c->by_expiry) == 0);
- hashmap_free(c->by_key);
- c->by_key = NULL;
-
- prioq_free(c->by_expiry);
- c->by_expiry = NULL;
+ c->by_key = hashmap_free(c->by_key);
+ c->by_expiry = prioq_free(c->by_expiry);
}
static void dns_cache_remove(DnsCache *c, DnsResourceKey *key) {
diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h
index e92280c319..8a9b3d459d 100644
--- a/src/resolve/resolved-dns-cache.h
+++ b/src/resolve/resolved-dns-cache.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include "hashmap.h"
#include "prioq.h"
diff --git a/src/resolve/resolved-dns-domain.h b/src/resolve/resolved-dns-domain.h
index 36f27ea031..516d244f7a 100644
--- a/src/resolve/resolved-dns-domain.h
+++ b/src/resolve/resolved-dns-domain.h
@@ -21,7 +21,6 @@
#pragma once
-#include <sys/types.h>
#include "hashmap.h"
#include "in-addr-util.h"
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 561dd3adfa..c5867386c6 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include "macro.h"
#include "sparse-endian.h"
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index f0483c9806..418d9721ef 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -19,10 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "af-list.h"
#include "resolved-dns-query.h"
-#include "resolved-dns-domain.h"
/* How long to wait for the query in total */
#define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
@@ -469,14 +467,14 @@ static int on_bus_track(sd_bus_track *t, void *userdata) {
return 0;
}
-int dns_query_bus_track(DnsQuery *q, sd_bus *bus, sd_bus_message *m) {
+int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) {
int r;
assert(q);
assert(m);
if (!q->bus_track) {
- r = sd_bus_track_new(bus, &q->bus_track, on_bus_track, q);
+ r = sd_bus_track_new(sd_bus_message_get_bus(m), &q->bus_track, on_bus_track, q);
if (r < 0)
return r;
}
diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h
index 13b3ee4f81..5a319f0a62 100644
--- a/src/resolve/resolved-dns-query.h
+++ b/src/resolve/resolved-dns-query.h
@@ -21,21 +21,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include "sd-bus.h"
-#include "util.h"
#include "set.h"
typedef struct DnsQuery DnsQuery;
-#include "resolved-dns-scope.h"
-#include "resolved-dns-rr.h"
#include "resolved-dns-question.h"
#include "resolved-dns-answer.h"
#include "resolved-dns-stream.h"
-#include "resolved-dns-transaction.h"
-#include "resolved-manager.h"
struct DnsQuery {
Manager *manager;
@@ -81,6 +75,6 @@ void dns_query_ready(DnsQuery *q);
int dns_query_cname_redirect(DnsQuery *q, const char *name);
-int dns_query_bus_track(DnsQuery *q, sd_bus *bus, sd_bus_message *m);
+int dns_query_bus_track(DnsQuery *q, sd_bus_message *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free);
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 9d9a89d383..26796c842b 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -21,10 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <netinet/in.h>
-#include "util.h"
#include "hashmap.h"
#include "in-addr-util.h"
#include "dns-type.h"
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index abdb2e0732..7369cbf50f 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -25,6 +25,8 @@
#include "strv.h"
#include "socket-util.h"
#include "af-list.h"
+#include "random-util.h"
+#include "hostname-util.h"
#include "resolved-dns-domain.h"
#include "resolved-dns-scope.h"
@@ -144,7 +146,7 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
DnsServer *srv;
if (DNS_PACKET_QDCOUNT(p) > 1)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
srv = dns_scope_get_dns_server(s);
if (!srv)
@@ -172,7 +174,7 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) {
} else if (s->protocol == DNS_PROTOCOL_LLMNR) {
if (DNS_PACKET_QDCOUNT(p) > 1)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (!ratelimit_test(&s->ratelimit))
return -EBUSY;
@@ -387,7 +389,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {
* one. This is necessary on some devices, such as
* veth. */
if (b)
- (void)setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
+ (void) setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
return -errno;
@@ -403,7 +405,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {
return fd;
if (b)
- (void)setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
+ (void) setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index f05648e5a5..cfbde1343f 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -27,11 +27,8 @@ typedef struct DnsScope DnsScope;
#include "resolved-dns-server.h"
#include "resolved-dns-packet.h"
-#include "resolved-dns-query.h"
#include "resolved-dns-cache.h"
#include "resolved-dns-zone.h"
-#include "resolved-dns-stream.h"
-#include "resolved-manager.h"
#include "resolved-link.h"
typedef enum DnsScopeMatch {
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index caf06fe450..9a62a63258 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -78,23 +78,24 @@ DnsServer* dns_server_free(DnsServer *s) {
if (!s)
return NULL;
- if (s->manager) {
+ if (s->link) {
if (s->type == DNS_SERVER_LINK)
LIST_REMOVE(servers, s->link->dns_servers, s);
- else if (s->type == DNS_SERVER_SYSTEM)
+
+ if (s->link->current_dns_server == s)
+ link_set_dns_server(s->link, NULL);
+ }
+
+ if (s->manager) {
+ if (s->type == DNS_SERVER_SYSTEM)
LIST_REMOVE(servers, s->manager->dns_servers, s);
else if (s->type == DNS_SERVER_FALLBACK)
LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
- else
- assert_not_reached("Unknown server type");
if (s->manager->current_dns_server == s)
manager_set_dns_server(s->manager, NULL);
}
- if (s->link && s->link->current_dns_server == s)
- link_set_dns_server(s->link, NULL);
-
free(s);
return NULL;
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index a438a27763..70ff35b08f 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -32,7 +32,6 @@ typedef enum DnsServerType {
DNS_SERVER_LINK,
} DnsServerType;
-#include "resolved-manager.h"
#include "resolved-link.h"
struct DnsServer {
diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h
index 46eae31c60..fb81e9f1ac 100644
--- a/src/resolve/resolved-dns-stream.h
+++ b/src/resolve/resolved-dns-stream.h
@@ -27,7 +27,6 @@ typedef struct DnsStream DnsStream;
#include "resolved-dns-packet.h"
#include "resolved-dns-transaction.h"
-#include "resolved-manager.h"
struct DnsStream {
Manager *manager;
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 74b0634142..214938986d 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -22,6 +22,7 @@
#include "af-list.h"
#include "resolved-dns-transaction.h"
+#include "random-util.h"
DnsTransaction* dns_transaction_free(DnsTransaction *t) {
DnsQuery *q;
@@ -252,7 +253,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
else {
union in_addr_union address;
- int family;
+ int family = AF_UNSPEC;
/* Otherwise, try to talk to the owner of a
* the IP address, in case this is a reverse
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 182fb7714c..f6d539d315 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -40,11 +40,9 @@ enum DnsTransactionState {
};
#include "resolved-dns-scope.h"
-#include "resolved-dns-rr.h"
#include "resolved-dns-packet.h"
#include "resolved-dns-question.h"
#include "resolved-dns-answer.h"
-#include "resolved-dns-stream.h"
struct DnsTransaction {
DnsScope *scope;
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index f94e4bb6f0..27d9129e00 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -68,13 +68,13 @@ Link *link_free(Link *l) {
if (l->manager)
hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
+ while (l->dns_servers)
+ dns_server_free(l->dns_servers);
+
dns_scope_free(l->unicast_scope);
dns_scope_free(l->llmnr_ipv4_scope);
dns_scope_free(l->llmnr_ipv6_scope);
- while (l->dns_servers)
- dns_server_free(l->dns_servers);
-
free(l);
return NULL;
}
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index 4f0702e872..eee1846108 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -29,8 +29,6 @@
typedef struct Link Link;
typedef struct LinkAddress LinkAddress;
-#include "resolved-dns-server.h"
-#include "resolved-dns-scope.h"
#include "resolved-dns-rr.h"
#include "resolved-manager.h"
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index b5ad701611..52695376f0 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -19,22 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <arpa/inet.h>
#include <resolv.h>
-#include <net/if.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <netinet/in.h>
#include "rtnl-util.h"
-#include "event-util.h"
-#include "network-util.h"
#include "network-internal.h"
-#include "conf-parser.h"
#include "socket-util.h"
#include "af-list.h"
#include "utf8.h"
#include "fileio-label.h"
+#include "ordered-set.h"
+#include "random-util.h"
+#include "hostname-util.h"
#include "resolved-dns-domain.h"
#include "resolved-conf.h"
@@ -536,11 +534,11 @@ Manager *manager_free(Manager *m) {
while (m->dns_queries)
dns_query_free(m->dns_queries);
- dns_scope_free(m->unicast_scope);
-
manager_flush_dns_servers(m, DNS_SERVER_SYSTEM);
manager_flush_dns_servers(m, DNS_SERVER_FALLBACK);
+ dns_scope_free(m->unicast_scope);
+
hashmap_free(m->links);
hashmap_free(m->dns_transactions);
@@ -707,8 +705,11 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
(*count) ++;
}
-static void write_resolv_conf_search(const char *domain, FILE *f,
- unsigned *count, unsigned *length) {
+static void write_resolv_conf_search(
+ const char *domain, FILE *f,
+ unsigned *count,
+ unsigned *length) {
+
assert(domain);
assert(f);
assert(length);
@@ -729,7 +730,7 @@ static void write_resolv_conf_search(const char *domain, FILE *f,
(*count) ++;
}
-static int write_resolv_conf_contents(FILE *f, Set *dns, Set *domains) {
+static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
Iterator i;
fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n"
@@ -738,22 +739,22 @@ static int write_resolv_conf_contents(FILE *f, Set *dns, Set *domains) {
"# resolv.conf(5) in a different way, replace the symlink by a\n"
"# static file or a different symlink.\n\n", f);
- if (set_isempty(dns))
+ if (ordered_set_isempty(dns))
fputs("# No DNS servers known.\n", f);
else {
DnsServer *s;
unsigned count = 0;
- SET_FOREACH(s, dns, i)
+ ORDERED_SET_FOREACH(s, dns, i)
write_resolv_conf_server(s, f, &count);
}
- if (!set_isempty(domains)) {
+ if (!ordered_set_isempty(domains)) {
unsigned length = 0, count = 0;
char *domain;
fputs("search", f);
- SET_FOREACH(domain, domains, i)
+ ORDERED_SET_FOREACH(domain, domains, i)
write_resolv_conf_search(domain, f, &count, &length);
fputs("\n", f);
}
@@ -761,12 +762,11 @@ static int write_resolv_conf_contents(FILE *f, Set *dns, Set *domains) {
return fflush_and_check(f);
}
-
int manager_write_resolv_conf(Manager *m) {
static const char path[] = "/run/systemd/resolve/resolv.conf";
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
- _cleanup_set_free_ Set *dns = NULL, *domains = NULL;
+ _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL;
DnsServer *s;
Iterator i;
Link *l;
@@ -778,17 +778,17 @@ int manager_write_resolv_conf(Manager *m) {
manager_read_resolv_conf(m);
/* Add the full list to a set, to filter out duplicates */
- dns = set_new(&dns_server_hash_ops);
+ dns = ordered_set_new(&dns_server_hash_ops);
if (!dns)
return -ENOMEM;
- domains = set_new(&dns_name_hash_ops);
+ domains = ordered_set_new(&dns_name_hash_ops);
if (!domains)
return -ENOMEM;
/* First add the system-wide servers */
LIST_FOREACH(servers, s, m->dns_servers) {
- r = set_put(dns, s);
+ r = ordered_set_put(dns, s);
if (r == -EEXIST)
continue;
if (r < 0)
@@ -800,7 +800,7 @@ int manager_write_resolv_conf(Manager *m) {
char **domain;
LIST_FOREACH(servers, s, l->dns_servers) {
- r = set_put(dns, s);
+ r = ordered_set_put(dns, s);
if (r == -EEXIST)
continue;
if (r < 0)
@@ -811,7 +811,7 @@ int manager_write_resolv_conf(Manager *m) {
continue;
STRV_FOREACH(domain, l->unicast_scope->domains) {
- r = set_put(domains, *domain);
+ r = ordered_set_put(domains, *domain);
if (r == -EEXIST)
continue;
if (r < 0)
@@ -820,9 +820,9 @@ int manager_write_resolv_conf(Manager *m) {
}
/* If we found nothing, add the fallback servers */
- if (set_isempty(dns)) {
+ if (ordered_set_isempty(dns)) {
LIST_FOREACH(servers, s, m->fallback_dns_servers) {
- r = set_put(dns, s);
+ r = ordered_set_put(dns, s);
if (r == -EEXIST)
continue;
if (r < 0)
@@ -848,8 +848,8 @@ int manager_write_resolv_conf(Manager *m) {
return 0;
fail:
- unlink(path);
- unlink(temp_path);
+ (void) unlink(path);
+ (void) unlink(temp_path);
return r;
}
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 1151029d29..5a581cc13a 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -24,9 +24,7 @@
#include "sd-event.h"
#include "sd-network.h"
#include "sd-rtnl.h"
-#include "util.h"
#include "list.h"
-#include "in-addr-util.h"
#include "hashmap.h"
typedef struct Manager Manager;
@@ -41,8 +39,6 @@ enum Support {
};
#include "resolved-dns-query.h"
-#include "resolved-dns-server.h"
-#include "resolved-dns-scope.h"
#include "resolved-dns-stream.h"
#include "resolved-link.h"
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index ce15a8011d..e283d8a749 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -22,9 +22,9 @@
#include "sd-event.h"
#include "sd-daemon.h"
#include "mkdir.h"
-#include "label.h"
#include "capability.h"
#include "selinux-util.h"
+#include "signal-util.h"
#include "resolved-manager.h"
#include "resolved-conf.h"
diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
index e5a19ee474..3eb19e42b7 100644
--- a/src/resolve/resolved.conf.in
+++ b/src/resolve/resolved.conf.in
@@ -5,8 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/resolved.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
# See resolved.conf(5) for details
diff --git a/src/resolve/test-dns-domain.c b/src/resolve/test-dns-domain.c
index ebc8d98fce..c3208abc78 100644
--- a/src/resolve/test-dns-domain.c
+++ b/src/resolve/test-dns-domain.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "log.h"
#include "macro.h"
#include "resolved-dns-domain.h"
@@ -162,7 +161,7 @@ static void test_dns_name_single_label(void) {
static void test_dns_name_reverse_one(const char *address, const char *name) {
_cleanup_free_ char *p = NULL;
- union in_addr_union a, b;
+ union in_addr_union a, b = {};
int familya, familyb;
assert_se(in_addr_from_string_auto(address, &familya, &a) >= 0);
diff --git a/src/run/run.c b/src/run/run.c
index 0661b3bee9..5b9f31c4aa 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -34,9 +34,12 @@
#include "bus-error.h"
#include "calendarspec.h"
#include "ptyfwd.h"
+#include "formats-util.h"
+#include "signal-util.h"
static bool arg_scope = false;
static bool arg_remain_after_exit = false;
+static bool arg_no_block = false;
static const char *arg_unit = NULL;
static const char *arg_description = NULL;
static const char *arg_slice = NULL;
@@ -76,6 +79,7 @@ static void help(void) {
" -p --property=NAME=VALUE Set unit property\n"
" --description=TEXT Description for unit\n"
" --slice=SLICE Run in the specified slice\n"
+ " --no-block Do not wait until operation finished\n"
" -r --remain-after-exit Leave service around until explicitly stopped\n"
" --send-sighup Send SIGHUP when terminating\n"
" --service-type=TYPE Service type\n"
@@ -123,7 +127,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ON_UNIT_ACTIVE,
ARG_ON_UNIT_INACTIVE,
ARG_ON_CALENDAR,
- ARG_TIMER_PROPERTY
+ ARG_TIMER_PROPERTY,
+ ARG_NO_BLOCK,
};
static const struct option options[] = {
@@ -154,6 +159,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
{ "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
{ "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
+ { "no-block", no_argument, NULL, ARG_NO_BLOCK },
{},
};
@@ -241,14 +247,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_SETENV:
-
if (strv_extend(&arg_environment, optarg) < 0)
return log_oom();
break;
case 'p':
-
if (strv_extend(&arg_property, optarg) < 0)
return log_oom();
@@ -330,6 +334,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_NO_BLOCK:
+ arg_no_block = true;
+ break;
+
case '?':
return -EINVAL;
@@ -389,11 +397,8 @@ static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
return r;
r = bus_append_unit_property_assignment(m, *i);
- if (r < 0) {
- r = sd_bus_message_append(m, "sv", 0);
- if (r < 0)
- return r;
- }
+ if (r < 0)
+ return r;
r = sd_bus_message_close_container(m);
if (r < 0)
@@ -410,9 +415,9 @@ static int transient_cgroup_set_properties(sd_bus_message *m) {
if (!isempty(arg_slice)) {
_cleanup_free_ char *slice;
- slice = unit_name_mangle_with_suffix(arg_slice, MANGLE_NOGLOB, ".slice");
- if (!slice)
- return -ENOMEM;
+ r = unit_name_mangle_with_suffix(arg_slice, UNIT_NAME_NOGLOB, ".slice", &slice);
+ if (r < 0)
+ return r;
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
if (r < 0)
@@ -655,8 +660,9 @@ static int start_transient_service(
sd_bus *bus,
char **argv) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_free_ char *service = NULL, *pty_path = NULL;
_cleanup_close_ int master = -1;
int r;
@@ -677,7 +683,6 @@ static int start_transient_service(
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
_cleanup_bus_unref_ sd_bus *system_bus = NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *s;
r = sd_bus_open_system(&system_bus);
@@ -701,6 +706,8 @@ static int start_transient_service(
if (r < 0)
return bus_log_parse_error(r);
+ reply = sd_bus_message_unref(reply);
+
master = fcntl(master, F_DUPFD_CLOEXEC, 3);
if (master < 0)
return log_error_errno(errno, "Failed to duplicate master fd: %m");
@@ -715,10 +722,16 @@ static int start_transient_service(
return log_error_errno(errno, "Failed to unlock tty: %m");
}
+ if (!arg_no_block) {
+ r = bus_wait_for_jobs_new(bus, &w);
+ if (r < 0)
+ return log_error_errno(r, "Could not watch jobs: %m");
+ }
+
if (arg_unit) {
- service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
- if (!service)
- return log_oom();
+ r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
} else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0)
return log_oom();
@@ -755,12 +768,24 @@ static int start_transient_service(
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_call(bus, m, 0, &error, NULL);
+ r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to start transient service unit: %s", bus_error_message(&error, -r));
return r;
}
+ if (w) {
+ const char *object;
+
+ r = sd_bus_message_read(reply, "o", &object);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = bus_wait_for_jobs_one(w, object, arg_quiet);
+ if (r < 0)
+ return r;
+ }
+
if (master >= 0) {
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
@@ -781,7 +806,7 @@ static int start_transient_service(
if (!arg_quiet)
log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service);
- r = pty_forward_new(event, master, false, &forward);
+ r = pty_forward_new(event, master, false, false, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
@@ -807,18 +832,24 @@ static int start_transient_scope(
char **argv) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_strv_free_ char **env = NULL, **user_env = NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *scope = NULL;
+ const char *object = NULL;
int r;
assert(bus);
assert(argv);
+ r = bus_wait_for_jobs_new(bus, &w);
+ if (r < 0)
+ return log_oom();
+
if (arg_unit) {
- scope = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
- if (!scope)
- return log_oom();
+ r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle scope name: %m");
} else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0)
return log_oom();
@@ -855,7 +886,7 @@ static int start_transient_scope(
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_call(bus, m, 0, &error, NULL);
+ r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to start transient scope unit: %s", bus_error_message(&error, -r));
return r;
@@ -915,8 +946,16 @@ static int start_transient_scope(
if (!env)
return log_oom();
+ r = sd_bus_message_read(reply, "o", &object);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = bus_wait_for_jobs_one(w, object, arg_quiet);
+ if (r < 0)
+ return r;
+
if (!arg_quiet)
- log_info("Running as unit %s.", scope);
+ log_info("Running scope as unit %s.", scope);
execvpe(argv[0], argv, env);
@@ -928,24 +967,30 @@ static int start_transient_timer(
char **argv) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_free_ char *timer = NULL, *service = NULL;
+ const char *object = NULL;
int r;
assert(bus);
assert(argv);
+ r = bus_wait_for_jobs_new(bus, &w);
+ if (r < 0)
+ return log_oom();
+
if (arg_unit) {
- switch(unit_name_to_type(arg_unit)) {
+ switch (unit_name_to_type(arg_unit)) {
case UNIT_SERVICE:
service = strdup(arg_unit);
if (!service)
return log_oom();
- timer = unit_name_change_suffix(service, ".timer");
- if (!timer)
- return log_oom();
+ r = unit_name_change_suffix(service, ".timer", &timer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to change unit suffix: %m");
break;
case UNIT_TIMER:
@@ -953,19 +998,19 @@ static int start_transient_timer(
if (!timer)
return log_oom();
- service = unit_name_change_suffix(timer, ".service");
- if (!service)
- return log_oom();
+ r = unit_name_change_suffix(timer, ".service", &service);
+ if (r < 0)
+ return log_error_errno(r, "Failed to change unit suffix: %m");
break;
default:
- service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
- if (!service)
- return log_oom();
+ r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
- timer = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".timer");
- if (!timer)
- return log_oom();
+ r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
break;
}
@@ -1035,15 +1080,23 @@ static int start_transient_timer(
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_call(bus, m, 0, &error, NULL);
+ r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r));
return r;
}
- log_info("Running as unit %s.", timer);
+ r = sd_bus_message_read(reply, "o", &object);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = bus_wait_for_jobs_one(w, object, arg_quiet);
+ if (r < 0)
+ return r;
+
+ log_info("Running timer as unit %s.", timer);
if (argv[0])
- log_info("Will run as unit %s.", service);
+ log_info("Will run service as unit %s.", service);
return 0;
}
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c
index a4ff1ab878..466f9aa601 100644
--- a/src/shared/acl-util.c
+++ b/src/shared/acl-util.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <stdbool.h>
@@ -82,17 +81,18 @@ int calc_acl_mask_if_needed(acl_t *acl_p) {
if (tag == ACL_MASK)
return 0;
- if (IN_SET(tag, ACL_USER, ACL_GROUP))
- goto calc;
+
+ if (IN_SET(tag, ACL_USER, ACL_GROUP)) {
+ if (acl_calc_mask(acl_p) < 0)
+ return -errno;
+
+ return 1;
+ }
}
if (r < 0)
return -errno;
- return 0;
-calc:
- if (acl_calc_mask(acl_p) < 0)
- return -errno;
- return 1;
+ return 0;
}
int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
@@ -159,59 +159,68 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
return 0;
}
-int search_acl_groups(char*** dst, const char* path, bool* belong) {
- acl_t acl;
+int acl_search_groups(const char *path, char ***ret_groups) {
+ _cleanup_strv_free_ char **g = NULL;
+ _cleanup_(acl_free) acl_t acl = NULL;
+ bool ret = false;
+ acl_entry_t entry;
+ int r;
assert(path);
- assert(belong);
acl = acl_get_file(path, ACL_TYPE_DEFAULT);
- if (acl) {
- acl_entry_t entry;
- int r;
-
- r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
- while (r > 0) {
- acl_tag_t tag;
- gid_t *gid;
- char *name;
+ if (!acl)
+ return -errno;
- r = acl_get_tag_type(entry, &tag);
- if (r < 0)
- break;
+ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ for (;;) {
+ _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL;
+ acl_tag_t tag;
+
+ if (r < 0)
+ return -errno;
+ if (r == 0)
+ break;
- if (tag != ACL_GROUP)
- goto next;
+ if (acl_get_tag_type(entry, &tag) < 0)
+ return -errno;
- gid = acl_get_qualifier(entry);
- if (!gid)
- break;
+ if (tag != ACL_GROUP)
+ goto next;
- if (in_gid(*gid) > 0) {
- *belong = true;
- break;
- }
+ gid = acl_get_qualifier(entry);
+ if (!gid)
+ return -errno;
+
+ if (in_gid(*gid) > 0) {
+ if (!ret_groups)
+ return true;
+
+ ret = true;
+ }
+
+ if (ret_groups) {
+ char *name;
name = gid_to_name(*gid);
- if (!name) {
- acl_free(acl);
- return log_oom();
- }
-
- r = strv_consume(dst, name);
- if (r < 0) {
- acl_free(acl);
- return log_oom();
- }
-
- next:
- r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ if (!name)
+ return -ENOMEM;
+
+ r = strv_consume(&g, name);
+ if (r < 0)
+ return r;
}
- acl_free(acl);
+ next:
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
}
- return 0;
+ if (ret_groups) {
+ *ret_groups = g;
+ g = NULL;
+ }
+
+ return ret;
}
int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
@@ -282,6 +291,77 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask)
return 0;
}
+static int acl_entry_equal(acl_entry_t a, acl_entry_t b) {
+ acl_tag_t tag_a, tag_b;
+
+ if (acl_get_tag_type(a, &tag_a) < 0)
+ return -errno;
+
+ if (acl_get_tag_type(b, &tag_b) < 0)
+ return -errno;
+
+ if (tag_a != tag_b)
+ return false;
+
+ switch (tag_a) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ /* can have only one of those */
+ return true;
+ case ACL_USER: {
+ _cleanup_(acl_free_uid_tpp) uid_t *uid_a = NULL, *uid_b = NULL;
+
+ uid_a = acl_get_qualifier(a);
+ if (!uid_a)
+ return -errno;
+
+ uid_b = acl_get_qualifier(b);
+ if (!uid_b)
+ return -errno;
+
+ return *uid_a == *uid_b;
+ }
+ case ACL_GROUP: {
+ _cleanup_(acl_free_gid_tpp) gid_t *gid_a = NULL, *gid_b = NULL;
+
+ gid_a = acl_get_qualifier(a);
+ if (!gid_a)
+ return -errno;
+
+ gid_b = acl_get_qualifier(b);
+ if (!gid_b)
+ return -errno;
+
+ return *gid_a == *gid_b;
+ }
+ default:
+ assert_not_reached("Unknown acl tag type");
+ }
+}
+
+static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) {
+ acl_entry_t i;
+ int r;
+
+ for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+ r > 0;
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+
+ r = acl_entry_equal(i, entry);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ *out = i;
+ return 1;
+ }
+ }
+ if (r < 0)
+ return -errno;
+ return 0;
+}
+
int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
_cleanup_(acl_freep) acl_t old;
acl_entry_t i;
@@ -297,8 +377,12 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
acl_entry_t j;
- if (acl_create_entry(&old, &j) < 0)
- return -errno;
+ r = find_acl_entry(old, i, &j);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ if (acl_create_entry(&old, &j) < 0)
+ return -errno;
if (acl_copy_entry(j, i) < 0)
return -errno;
diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h
index 90e88ffa26..c8bcc266d0 100644
--- a/src/shared/acl-util.h
+++ b/src/shared/acl-util.h
@@ -32,7 +32,7 @@
int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry);
int calc_acl_mask_if_needed(acl_t *acl_p);
int add_base_acls_if_needed(acl_t *acl_p, const char *path);
-int search_acl_groups(char*** dst, const char* path, bool* belong);
+int acl_search_groups(const char* path, char ***ret_groups);
int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask);
int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl);
@@ -41,5 +41,9 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl);
DEFINE_TRIVIAL_CLEANUP_FUNC(acl_t, acl_free);
#define acl_free_charp acl_free
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, acl_free_charp);
+#define acl_free_uid_tp acl_free
+DEFINE_TRIVIAL_CLEANUP_FUNC(uid_t*, acl_free_uid_tp);
+#define acl_free_gid_tp acl_free
+DEFINE_TRIVIAL_CLEANUP_FUNC(gid_t*, acl_free_gid_tp);
#endif
diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c
index 390c3236e0..64e50401b9 100644
--- a/src/shared/acpi-fpdt.c
+++ b/src/shared/acpi-fpdt.c
@@ -19,13 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
-#include <sys/types.h>
#include <util.h>
#include <fileio.h>
diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c
index c14843da49..c2bbd330bd 100644
--- a/src/shared/apparmor-util.c
+++ b/src/shared/apparmor-util.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include "util.h"
#include "fileio.h"
diff --git a/src/shared/architecture.c b/src/shared/architecture.c
index 34c5a53fa9..8e72e7a36a 100644
--- a/src/shared/architecture.c
+++ b/src/shared/architecture.c
@@ -35,7 +35,7 @@ int uname_architecture(void) {
* 1:1. Instead we try to clean it up and break down the
* confusion on x86 and arm in particular.
*
- * We do not try to distuingish CPUs not CPU features, but
+ * We do not try to distinguish CPUs not CPU features, but
* actual architectures, i.e. that have genuinely different
* code. */
@@ -108,8 +108,12 @@ int uname_architecture(void) {
{ "armv8l", ARCHITECTURE_ARM },
{ "armv8b", ARCHITECTURE_ARM_BE },
#elif defined(__sh__) || defined(__sh64__)
- { "sh64", ARCHITECTURE_SH64 },
- { "sh", ARCHITECTURE_SH },
+ { "sh5", ARCHITECTURE_SH64 },
+ { "sh2", ARCHITECTURE_SH },
+ { "sh2a", ARCHITECTURE_SH },
+ { "sh3", ARCHITECTURE_SH },
+ { "sh4", ARCHITECTURE_SH },
+ { "sh4a", ARCHITECTURE_SH },
#elif defined(__m68k__)
{ "m68k", ARCHITECTURE_M68K },
#elif defined(__tilegx__)
diff --git a/src/shared/architecture.h b/src/shared/architecture.h
index cb82418a5e..f5bbf65a90 100644
--- a/src/shared/architecture.h
+++ b/src/shared/architecture.h
@@ -27,7 +27,7 @@
/* A cleaned up architecture definition. We don't want to get lost in
* processor features, models, generations or even ABIs. Hence we
- * focus on general family, and distuignish word width and
+ * focus on general family, and distinguish word width and
* endianness. */
enum {
diff --git a/src/shared/arphrd-list.c b/src/shared/arphrd-list.c
index 6e113eff7a..284043cd90 100644
--- a/src/shared/arphrd-list.c
+++ b/src/shared/arphrd-list.c
@@ -20,7 +20,6 @@
***/
#include <net/if_arp.h>
-#include <sys/socket.h>
#include <string.h>
#include "util.h"
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 0a61dafc59..ef3788be68 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -32,9 +32,12 @@
#include <sys/signalfd.h>
#include "util.h"
+#include "formats-util.h"
#include "mkdir.h"
#include "strv.h"
-
+#include "random-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
#include "ask-password-api.h"
static void backspace_chars(int ttyfd, size_t p) {
@@ -475,6 +478,8 @@ int ask_password_agent(
goto finish;
}
+ cmsg_close_all(&msghdr);
+
if (n <= 0) {
log_error("Message too short");
continue;
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 704ee6e1b4..0954e072be 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase);
diff --git a/src/shared/audit.c b/src/shared/audit.c
index 4701c0a8de..54148fcf18 100644
--- a/src/shared/audit.c
+++ b/src/shared/audit.c
@@ -19,20 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <string.h>
-#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <ctype.h>
#include "macro.h"
#include "audit.h"
#include "util.h"
-#include "log.h"
+#include "process-util.h"
#include "fileio.h"
-#include "virt.h"
int audit_session_from_pid(pid_t pid, uint32_t *id) {
_cleanup_free_ char *s = NULL;
@@ -52,7 +46,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
if (r < 0)
return r;
- if (u == (uint32_t) -1 || u <= 0)
+ if (u == AUDIT_SESSION_INVALID || u <= 0)
return -ENXIO;
*id = u;
diff --git a/src/shared/audit.h b/src/shared/audit.h
index b4aecffb30..6de331c73e 100644
--- a/src/shared/audit.h
+++ b/src/shared/audit.h
@@ -21,9 +21,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdint.h>
+#include <stdbool.h>
#include <sys/types.h>
-#include "capability.h"
+#define AUDIT_SESSION_INVALID ((uint32_t) -1)
int audit_session_from_pid(pid_t pid, uint32_t *id);
int audit_loginuid_from_pid(pid_t pid, uid_t *uid);
diff --git a/src/shared/barrier.c b/src/shared/barrier.c
index f65363a67b..436ba95989 100644
--- a/src/shared/barrier.c
+++ b/src/shared/barrier.c
@@ -21,13 +21,10 @@
#include <errno.h>
#include <fcntl.h>
-#include <limits.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/eventfd.h>
#include <sys/types.h>
#include <unistd.h>
@@ -141,7 +138,7 @@ int barrier_create(Barrier *b) {
* barrier_create(). The object is released and reset to invalid
* state. Therefore, it is safe to call barrier_destroy() multiple
* times or even if barrier_create() failed. However, barrier must be
- * always initalized with BARRIER_NULL.
+ * always initialized with BARRIER_NULL.
*
* If @b is NULL, this is a no-op.
*/
@@ -178,7 +175,7 @@ void barrier_set_role(Barrier *b, unsigned int role) {
assert(b);
assert(role == BARRIER_PARENT || role == BARRIER_CHILD);
/* make sure this is only called once */
- assert(b->pipe[1] >= 0 && b->pipe[1] >= 0);
+ assert(b->pipe[0] >= 0 && b->pipe[1] >= 0);
if (role == BARRIER_PARENT)
b->pipe[1] = safe_close(b->pipe[1]);
diff --git a/src/shared/barrier.h b/src/shared/barrier.h
index d4ad2a419b..b8954694d3 100644
--- a/src/shared/barrier.h
+++ b/src/shared/barrier.h
@@ -21,14 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
#include <sys/types.h>
#include "macro.h"
-#include "util.h"
/* See source file for an API description. */
@@ -91,6 +86,6 @@ static inline bool barrier_is_aborted(Barrier *b) {
}
static inline bool barrier_place_and_sync(Barrier *b) {
- (void)barrier_place(b);
+ (void) barrier_place(b);
return barrier_sync(b);
}
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index 73907c6354..ab6fc171b0 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -22,17 +22,12 @@
#include <errno.h>
#include <sys/stat.h>
#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
#include <unistd.h>
#include "base-filesystem.h"
#include "log.h"
#include "macro.h"
-#include "strv.h"
#include "util.h"
-#include "label.h"
-#include "mkdir.h"
typedef struct BaseFilesystem {
const char *dir;
@@ -46,16 +41,19 @@ static const BaseFilesystem table[] = {
{ "lib", 0, "usr/lib\0", NULL },
{ "root", 0755, NULL, NULL },
{ "sbin", 0, "usr/sbin\0", NULL },
+ { "usr", 0755, NULL, NULL },
+ { "var", 0755, NULL, NULL },
+ { "etc", 0755, NULL, NULL },
#if defined(__i386__) || defined(__x86_64__)
{ "lib64", 0, "usr/lib/x86_64-linux-gnu\0"
"usr/lib64\0", "ld-linux-x86-64.so.2" },
#endif
};
-int base_filesystem_create(const char *root) {
+int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
_cleanup_close_ int fd = -1;
unsigned i;
- int r;
+ int r = 0;
fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
if (fd < 0)
@@ -95,6 +93,12 @@ int base_filesystem_create(const char *root) {
r = symlinkat(target, fd, table[i].dir);
if (r < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir);
+
+ if (uid != UID_INVALID || gid != UID_INVALID) {
+ if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
+ return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir);
+ }
+
continue;
}
@@ -102,6 +106,11 @@ int base_filesystem_create(const char *root) {
r = mkdirat(fd, table[i].dir, table[i].mode);
if (r < 0 && errno != EEXIST)
return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir);
+
+ if (uid != UID_INVALID || gid != UID_INVALID) {
+ if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
+ return log_error_errno(errno, "Failed to chown directory at %s/%s: %m", root, table[i].dir);
+ }
}
return 0;
diff --git a/src/shared/base-filesystem.h b/src/shared/base-filesystem.h
index 03201f7083..39a496090f 100644
--- a/src/shared/base-filesystem.h
+++ b/src/shared/base-filesystem.h
@@ -21,4 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int base_filesystem_create(const char *root);
+#include <sys/types.h>
+
+int base_filesystem_create(const char *root, uid_t uid, gid_t gid);
diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c
index 54e0537a21..ecbe1aaa0f 100644
--- a/src/shared/boot-timestamps.c
+++ b/src/shared/boot-timestamps.c
@@ -19,7 +19,6 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include "boot-timestamps.h"
#include "acpi-fpdt.h"
@@ -40,10 +39,8 @@ int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_time
r = acpi_get_boot_usec(&x, &y);
if (r < 0) {
-#ifdef ENABLE_EFI
r = efi_loader_get_boot_usec(&x, &y);
if (r < 0)
-#endif
return r;
}
diff --git a/src/shared/btrfs-ctree.h b/src/shared/btrfs-ctree.h
index 8b6f1ab4f4..d3ae57331c 100644
--- a/src/shared/btrfs-ctree.h
+++ b/src/shared/btrfs-ctree.h
@@ -90,3 +90,9 @@ struct btrfs_qgroup_limit_item {
le64_t rsv_rfer;
le64_t rsv_excl;
} _packed_;
+
+struct btrfs_root_ref {
+ le64_t dirid;
+ le64_t sequence;
+ le16_t name_len;
+} _packed_;
diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c
index b34ac8b15a..49528dbf01 100644
--- a/src/shared/btrfs-util.c
+++ b/src/shared/btrfs-util.c
@@ -31,13 +31,21 @@
#include "util.h"
#include "path-util.h"
#include "macro.h"
-#include "strv.h"
#include "copy.h"
#include "selinux-util.h"
#include "smack-util.h"
+#include "fileio.h"
#include "btrfs-ctree.h"
#include "btrfs-util.h"
+/* WARNING: Be careful with file system ioctls! When we get an fd, we
+ * need to make sure it either refers to only a regular file or
+ * directory, or that it is located on btrfs, before invoking any
+ * btrfs ioctls. The ioctl numbers are reused by some device drivers
+ * (such as DRM), and hence might have bad effects when invoked on
+ * device nodes (that reference drivers) rather than fds to normal
+ * files or directories. */
+
static int validate_subvolume_name(const char *name) {
if (!filename_is_valid(name))
@@ -83,17 +91,10 @@ static int extract_subvolume_name(const char *path, const char **subvolume) {
return 0;
}
-int btrfs_is_snapshot(int fd) {
- struct stat st;
+int btrfs_is_filesystem(int fd) {
struct statfs sfs;
- /* On btrfs subvolumes always have the inode 256 */
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
- return 0;
+ assert(fd >= 0);
if (fstatfs(fd, &sfs) < 0)
return -errno;
@@ -101,65 +102,20 @@ int btrfs_is_snapshot(int fd) {
return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
}
-int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) {
- struct btrfs_ioctl_vol_args_v2 args = {
- .flags = read_only ? BTRFS_SUBVOL_RDONLY : 0,
- };
- _cleanup_close_ int old_fd = -1, new_fd = -1;
- const char *subvolume;
- int r;
-
- assert(old_path);
-
- old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (old_fd < 0)
- return -errno;
-
- r = btrfs_is_snapshot(old_fd);
- if (r < 0)
- return r;
- if (r == 0) {
-
- if (fallback_copy) {
- r = btrfs_subvol_make(new_path);
- if (r < 0)
- return r;
-
- r = copy_directory_fd(old_fd, new_path, true);
- if (r < 0) {
- btrfs_subvol_remove(new_path);
- return r;
- }
-
- if (read_only) {
- r = btrfs_subvol_set_read_only(new_path, true);
- if (r < 0) {
- btrfs_subvol_remove(new_path);
- return r;
- }
- }
-
- return 0;
- }
-
- return -EISDIR;
- }
-
- r = extract_subvolume_name(new_path, &subvolume);
- if (r < 0)
- return r;
+int btrfs_is_subvol(int fd) {
+ struct stat st;
- new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (new_fd < 0)
- return new_fd;
+ assert(fd >= 0);
- strncpy(args.name, subvolume, sizeof(args.name)-1);
- args.fd = old_fd;
+ /* On btrfs subvolumes always have the inode 256 */
- if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &args) < 0)
+ if (fstat(fd, &st) < 0)
return -errno;
- return 0;
+ if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
+ return 0;
+
+ return btrfs_is_filesystem(fd);
}
int btrfs_subvol_make(const char *path) {
@@ -204,30 +160,6 @@ int btrfs_subvol_make_label(const char *path) {
return mac_smack_fix(path, false, false);
}
-int btrfs_subvol_remove(const char *path) {
- struct btrfs_ioctl_vol_args args = {};
- _cleanup_close_ int fd = -1;
- const char *subvolume;
- int r;
-
- assert(path);
-
- r = extract_subvolume_name(path, &subvolume);
- if (r < 0)
- return r;
-
- fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (fd < 0)
- return fd;
-
- strncpy(args.name, subvolume, sizeof(args.name)-1);
-
- if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args) < 0)
- return -errno;
-
- return 0;
-}
-
int btrfs_subvol_set_read_only_fd(int fd, bool b) {
uint64_t flags, nflags;
struct stat st;
@@ -269,6 +201,15 @@ int btrfs_subvol_set_read_only(const char *path, bool b) {
int btrfs_subvol_get_read_only_fd(int fd) {
uint64_t flags;
+ struct stat st;
+
+ assert(fd >= 0);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode) || st.st_ino != 256)
+ return -EINVAL;
if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0)
return -errno;
@@ -277,11 +218,21 @@ int btrfs_subvol_get_read_only_fd(int fd) {
}
int btrfs_reflink(int infd, int outfd) {
+ struct stat st;
int r;
assert(infd >= 0);
assert(outfd >= 0);
+ /* Make sure we invoke the ioctl on a regular file, so that no
+ * device driver accidentally gets it. */
+
+ if (fstat(outfd, &st) < 0)
+ return -errno;
+
+ if (!S_ISREG(st.st_mode))
+ return -EINVAL;
+
r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
if (r < 0)
return -errno;
@@ -296,12 +247,19 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offs
.src_length = sz,
.dest_offset = out_offset,
};
+ struct stat st;
int r;
assert(infd >= 0);
assert(outfd >= 0);
assert(sz > 0);
+ if (fstat(outfd, &st) < 0)
+ return -errno;
+
+ if (!S_ISREG(st.st_mode))
+ return -EINVAL;
+
r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
if (r < 0)
return -errno;
@@ -309,17 +267,19 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offs
return 0;
}
-int btrfs_get_block_device(const char *path, dev_t *dev) {
+int btrfs_get_block_device_fd(int fd, dev_t *dev) {
struct btrfs_ioctl_fs_info_args fsi = {};
- _cleanup_close_ int fd = -1;
uint64_t id;
+ int r;
- assert(path);
+ assert(fd >= 0);
assert(dev);
- fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (fd < 0)
- return -errno;
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
return -errno;
@@ -357,14 +317,34 @@ int btrfs_get_block_device(const char *path, dev_t *dev) {
return -ENODEV;
}
+int btrfs_get_block_device(const char *path, dev_t *dev) {
+ _cleanup_close_ int fd = -1;
+
+ assert(path);
+ assert(dev);
+
+ fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_get_block_device_fd(fd, dev);
+}
+
int btrfs_subvol_get_id_fd(int fd, uint64_t *ret) {
struct btrfs_ioctl_ino_lookup_args args = {
.objectid = BTRFS_FIRST_FREE_OBJECTID
};
+ int r;
assert(fd >= 0);
assert(ret);
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+
if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
return -errno;
@@ -584,7 +564,7 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
if (sh->type == BTRFS_QGROUP_INFO_KEY) {
const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
- ret->referred = le64toh(qii->rfer);
+ ret->referenced = le64toh(qii->rfer);
ret->exclusive = le64toh(qii->excl);
found_info = true;
@@ -592,11 +572,11 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
} else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
- ret->referred_max = le64toh(qli->max_rfer);
+ ret->referenced_max = le64toh(qli->max_rfer);
ret->exclusive_max = le64toh(qli->max_excl);
- if (ret->referred_max == 0)
- ret->referred_max = (uint64_t) -1;
+ if (ret->referenced_max == 0)
+ ret->referenced_max = (uint64_t) -1;
if (ret->exclusive_max == 0)
ret->exclusive_max = (uint64_t) -1;
@@ -617,12 +597,12 @@ finish:
return -ENODATA;
if (!found_info) {
- ret->referred = (uint64_t) -1;
+ ret->referenced = (uint64_t) -1;
ret->exclusive = (uint64_t) -1;
}
if (!found_limit) {
- ret->referred_max = (uint64_t) -1;
+ ret->referenced_max = (uint64_t) -1;
ret->exclusive_max = (uint64_t) -1;
}
@@ -630,8 +610,16 @@ finish:
}
int btrfs_defrag_fd(int fd) {
+ struct stat st;
+
assert(fd >= 0);
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISREG(st.st_mode))
+ return -EINVAL;
+
if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
return -errno;
@@ -647,3 +635,518 @@ int btrfs_defrag(const char *p) {
return btrfs_defrag_fd(fd);
}
+
+int btrfs_quota_enable_fd(int fd, bool b) {
+ struct btrfs_ioctl_quota_ctl_args args = {
+ .cmd = b ? BTRFS_QUOTA_CTL_ENABLE : BTRFS_QUOTA_CTL_DISABLE,
+ };
+ int r;
+
+ assert(fd >= 0);
+
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+
+ if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_quota_enable(const char *path, bool b) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_quota_enable_fd(fd, b);
+}
+
+int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) {
+ struct btrfs_ioctl_qgroup_limit_args args = {
+ .lim.max_rfer =
+ referenced_max == (uint64_t) -1 ? 0 :
+ referenced_max == 0 ? 1 : referenced_max,
+ .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
+ };
+ int r;
+
+ assert(fd >= 0);
+
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+
+ if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_quota_limit(const char *path, uint64_t referenced_max) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_quota_limit_fd(fd, referenced_max);
+}
+
+int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
+ struct btrfs_ioctl_vol_args args = {};
+ _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
+ _cleanup_close_ int loop_fd = -1, backing_fd = -1;
+ struct stat st;
+ dev_t dev = 0;
+ int r;
+
+ /* btrfs cannot handle file systems < 16M, hence use this as minimum */
+ if (new_size < 16*1024*1024)
+ new_size = 16*1024*1024;
+
+ r = btrfs_get_block_device_fd(fd, &dev);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENODEV;
+
+ if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
+ return -ENOMEM;
+ r = read_one_line_file(p, &backing);
+ if (r == -ENOENT)
+ return -ENODEV;
+ if (r < 0)
+ return r;
+ if (isempty(backing) || !path_is_absolute(backing))
+ return -ENODEV;
+
+ backing_fd = open(backing, O_RDWR|O_CLOEXEC|O_NOCTTY);
+ if (backing_fd < 0)
+ return -errno;
+
+ if (fstat(backing_fd, &st) < 0)
+ return -errno;
+ if (!S_ISREG(st.st_mode))
+ return -ENODEV;
+
+ if (new_size == (uint64_t) st.st_size)
+ return 0;
+
+ if (grow_only && new_size < (uint64_t) st.st_size)
+ return -EINVAL;
+
+ if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
+ return -ENOMEM;
+ loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
+ if (loop_fd < 0)
+ return -errno;
+
+ if (snprintf(args.name, sizeof(args.name), "%" PRIu64, new_size) >= (int) sizeof(args.name))
+ return -EINVAL;
+
+ if (new_size < (uint64_t) st.st_size) {
+ /* Decrease size: first decrease btrfs size, then shorten loopback */
+ if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
+ return -errno;
+ }
+
+ if (ftruncate(backing_fd, new_size) < 0)
+ return -errno;
+
+ if (ioctl(loop_fd, LOOP_SET_CAPACITY, 0) < 0)
+ return -errno;
+
+ if (new_size > (uint64_t) st.st_size) {
+ /* Increase size: first enlarge loopback, then increase btrfs size */
+ if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
+ return -errno;
+ }
+
+ /* Make sure the free disk space is correctly updated for both file systems */
+ (void) fsync(fd);
+ (void) fsync(backing_fd);
+
+ return 1;
+}
+
+int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_resize_loopback_fd(fd, new_size, grow_only);
+}
+
+static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
+ struct btrfs_ioctl_search_args args = {
+ .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
+
+ .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
+ .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
+
+ .key.min_type = BTRFS_ROOT_BACKREF_KEY,
+ .key.max_type = BTRFS_ROOT_BACKREF_KEY,
+
+ .key.min_transid = 0,
+ .key.max_transid = (uint64_t) -1,
+ };
+
+ struct btrfs_ioctl_vol_args vol_args = {};
+ _cleanup_close_ int subvol_fd = -1;
+ struct stat st;
+ bool made_writable = false;
+ int r;
+
+ assert(fd >= 0);
+ assert(subvolume);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return -EINVAL;
+
+ /* First, try to remove the subvolume. If it happens to be
+ * already empty, this will just work. */
+ strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
+ if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0)
+ return 0;
+ if (!recursive || errno != ENOTEMPTY)
+ return -errno;
+
+ /* OK, the subvolume is not empty, let's look for child
+ * subvolumes, and remove them, first */
+ subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (subvol_fd < 0)
+ return -errno;
+
+ if (subvol_id == 0) {
+ r = btrfs_subvol_get_id_fd(subvol_fd, &subvol_id);
+ if (r < 0)
+ return r;
+ }
+
+ args.key.min_offset = args.key.max_offset = subvol_id;
+
+ while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+ const struct btrfs_ioctl_search_header *sh;
+ unsigned i;
+
+ args.key.nr_items = 256;
+ if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+ return -errno;
+
+ if (args.key.nr_items <= 0)
+ break;
+
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ _cleanup_free_ char *p = NULL;
+ const struct btrfs_root_ref *ref;
+ struct btrfs_ioctl_ino_lookup_args ino_args;
+
+ btrfs_ioctl_search_args_set(&args, sh);
+
+ if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ continue;
+ if (sh->offset != subvol_id)
+ continue;
+
+ ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+
+ p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
+ if (!p)
+ return -ENOMEM;
+
+ zero(ino_args);
+ ino_args.treeid = subvol_id;
+ ino_args.objectid = htole64(ref->dirid);
+
+ if (ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
+ return -errno;
+
+ if (!made_writable) {
+ r = btrfs_subvol_set_read_only_fd(subvol_fd, false);
+ if (r < 0)
+ return r;
+
+ made_writable = true;
+ }
+
+ if (isempty(ino_args.name))
+ /* Subvolume is in the top-level
+ * directory of the subvolume. */
+ r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive);
+ else {
+ _cleanup_close_ int child_fd = -1;
+
+ /* Subvolume is somewhere further down,
+ * hence we need to open the
+ * containing directory first */
+
+ child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (child_fd < 0)
+ return -errno;
+
+ r = subvol_remove_children(child_fd, p, sh->objectid, recursive);
+ }
+ if (r < 0)
+ return r;
+ }
+
+ /* Increase search key by one, to read the next item, if we can. */
+ if (!btrfs_ioctl_search_args_inc(&args))
+ break;
+ }
+
+ /* OK, the child subvolumes should all be gone now, let's try
+ * again to remove the subvolume */
+ if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_subvol_remove(const char *path, bool recursive) {
+ _cleanup_close_ int fd = -1;
+ const char *subvolume;
+ int r;
+
+ assert(path);
+
+ r = extract_subvolume_name(path, &subvolume);
+ if (r < 0)
+ return r;
+
+ fd = open_parent(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return fd;
+
+ return subvol_remove_children(fd, subvolume, 0, recursive);
+}
+
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) {
+ return subvol_remove_children(fd, subvolume, 0, recursive);
+}
+
+static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t subvol_id, BtrfsSnapshotFlags flags) {
+
+ struct btrfs_ioctl_search_args args = {
+ .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
+
+ .key.min_objectid = BTRFS_FIRST_FREE_OBJECTID,
+ .key.max_objectid = BTRFS_LAST_FREE_OBJECTID,
+
+ .key.min_type = BTRFS_ROOT_BACKREF_KEY,
+ .key.max_type = BTRFS_ROOT_BACKREF_KEY,
+
+ .key.min_transid = 0,
+ .key.max_transid = (uint64_t) -1,
+ };
+
+ struct btrfs_ioctl_vol_args_v2 vol_args = {
+ .flags = flags & BTRFS_SNAPSHOT_READ_ONLY ? BTRFS_SUBVOL_RDONLY : 0,
+ .fd = old_fd,
+ };
+ int r;
+ _cleanup_close_ int subvolume_fd = -1;
+
+ assert(old_fd >= 0);
+ assert(new_fd >= 0);
+ assert(subvolume);
+
+ strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
+ vol_args.fd = old_fd;
+
+ if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
+ return -errno;
+
+ if (!(flags & BTRFS_SNAPSHOT_RECURSIVE))
+ return 0;
+
+ if (subvol_id == 0) {
+ r = btrfs_subvol_get_id_fd(old_fd, &subvol_id);
+ if (r < 0)
+ return r;
+ }
+
+ args.key.min_offset = args.key.max_offset = subvol_id;
+
+ while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+ const struct btrfs_ioctl_search_header *sh;
+ unsigned i;
+
+ args.key.nr_items = 256;
+ if (ioctl(old_fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+ return -errno;
+
+ if (args.key.nr_items <= 0)
+ break;
+
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ _cleanup_free_ char *p = NULL, *c = NULL, *np = NULL;
+ struct btrfs_ioctl_ino_lookup_args ino_args;
+ const struct btrfs_root_ref *ref;
+ _cleanup_close_ int old_child_fd = -1, new_child_fd = -1;
+
+ btrfs_ioctl_search_args_set(&args, sh);
+
+ if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ continue;
+ if (sh->offset != subvol_id)
+ continue;
+
+ ref = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+
+ p = strndup((char*) ref + sizeof(struct btrfs_root_ref), le64toh(ref->name_len));
+ if (!p)
+ return -ENOMEM;
+
+ zero(ino_args);
+ ino_args.treeid = subvol_id;
+ ino_args.objectid = htole64(ref->dirid);
+
+ if (ioctl(old_fd, BTRFS_IOC_INO_LOOKUP, &ino_args) < 0)
+ return -errno;
+
+ /* The kernel returns an empty name if the
+ * subvolume is in the top-level directory,
+ * and otherwise appends a slash, so that we
+ * can just concatenate easily here, without
+ * adding a slash. */
+ c = strappend(ino_args.name, p);
+ if (!c)
+ return -ENOMEM;
+
+ old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (old_child_fd < 0)
+ return -errno;
+
+ np = strjoin(subvolume, "/", ino_args.name, NULL);
+ if (!np)
+ return -ENOMEM;
+
+ new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (new_child_fd < 0)
+ return -errno;
+
+ if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
+ /* If the snapshot is read-only we
+ * need to mark it writable
+ * temporarily, to put the subsnapshot
+ * into place. */
+
+ if (subvolume_fd < 0) {
+ subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (subvolume_fd < 0)
+ return -errno;
+ }
+
+ r = btrfs_subvol_set_read_only_fd(subvolume_fd, false);
+ if (r < 0)
+ return r;
+ }
+
+ /* When btrfs clones the subvolumes, child
+ * subvolumes appear as directories. Remove
+ * them, so that we can create a new snapshot
+ * in their place */
+ if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) {
+ int k = -errno;
+
+ if (flags & BTRFS_SNAPSHOT_READ_ONLY)
+ (void) btrfs_subvol_set_read_only_fd(subvolume_fd, true);
+
+ return k;
+ }
+
+ r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY);
+
+ /* Restore the readonly flag */
+ if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
+ int k;
+
+ k = btrfs_subvol_set_read_only_fd(subvolume_fd, true);
+ if (r >= 0 && k < 0)
+ return k;
+ }
+
+ if (r < 0)
+ return r;
+ }
+
+ /* Increase search key by one, to read the next item, if we can. */
+ if (!btrfs_ioctl_search_args_inc(&args))
+ break;
+ }
+
+ return 0;
+}
+
+int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) {
+ _cleanup_close_ int new_fd = -1;
+ const char *subvolume;
+ int r;
+
+ assert(old_fd >= 0);
+ assert(new_path);
+
+ r = btrfs_is_subvol(old_fd);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
+ return -EISDIR;
+
+ r = btrfs_subvol_make(new_path);
+ if (r < 0)
+ return r;
+
+ r = copy_directory_fd(old_fd, new_path, true);
+ if (r < 0) {
+ btrfs_subvol_remove(new_path, false);
+ return r;
+ }
+
+ if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
+ r = btrfs_subvol_set_read_only(new_path, true);
+ if (r < 0) {
+ btrfs_subvol_remove(new_path, false);
+ return r;
+ }
+ }
+
+ return 0;
+ }
+
+ r = extract_subvolume_name(new_path, &subvolume);
+ if (r < 0)
+ return r;
+
+ new_fd = open_parent(new_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (new_fd < 0)
+ return new_fd;
+
+ return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags);
+}
+
+int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) {
+ _cleanup_close_ int old_fd = -1;
+
+ assert(old_path);
+ assert(new_path);
+
+ old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (old_fd < 0)
+ return -errno;
+
+ return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
+}
diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h
index 1b9c142e5c..a7eb895c93 100644
--- a/src/shared/btrfs-util.h
+++ b/src/shared/btrfs-util.h
@@ -37,18 +37,26 @@ typedef struct BtrfsSubvolInfo {
} BtrfsSubvolInfo;
typedef struct BtrfsQuotaInfo {
- uint64_t referred;
+ uint64_t referenced;
uint64_t exclusive;
- uint64_t referred_max;
+ uint64_t referenced_max;
uint64_t exclusive_max;
} BtrfsQuotaInfo;
-int btrfs_is_snapshot(int fd);
+typedef enum BtrfsSnapshotFlags {
+ BTRFS_SNAPSHOT_FALLBACK_COPY = 1,
+ BTRFS_SNAPSHOT_READ_ONLY = 2,
+ BTRFS_SNAPSHOT_RECURSIVE = 4,
+} BtrfsSnapshotFlags;
+
+int btrfs_is_filesystem(int fd);
+int btrfs_is_subvol(int fd);
int btrfs_subvol_make(const char *path);
int btrfs_subvol_make_label(const char *path);
-int btrfs_subvol_remove(const char *path);
-int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy);
+
+int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
+int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_set_read_only_fd(int fd, bool b);
int btrfs_subvol_set_read_only(const char *path, bool b);
@@ -60,7 +68,20 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota);
int btrfs_reflink(int infd, int outfd);
int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
+int btrfs_get_block_device_fd(int fd, dev_t *dev);
int btrfs_get_block_device(const char *path, dev_t *dev);
int btrfs_defrag_fd(int fd);
int btrfs_defrag(const char *p);
+
+int btrfs_quota_enable_fd(int fd, bool b);
+int btrfs_quota_enable(const char *path, bool b);
+
+int btrfs_quota_limit_fd(int fd, uint64_t referenced_max);
+int btrfs_quota_limit(const char *path, uint64_t referenced_max);
+
+int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
+int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
+
+int btrfs_subvol_remove(const char *path, bool recursive);
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive);
diff --git a/src/shared/bus-label.c b/src/shared/bus-label.c
index 61eb75bca2..ccc9f2bf8e 100644
--- a/src/shared/bus-label.c
+++ b/src/shared/bus-label.c
@@ -19,13 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
-#include <unistd.h>
#include "util.h"
#include "macro.h"
-#include "def.h"
#include "bus-label.h"
@@ -66,34 +63,35 @@ char *bus_label_escape(const char *s) {
return r;
}
-char *bus_label_unescape(const char *f) {
+char *bus_label_unescape_n(const char *f, size_t l) {
char *r, *t;
+ size_t i;
assert_return(f, NULL);
/* Special case for the empty string */
- if (streq(f, "_"))
+ if (l == 1 && *f == '_')
return strdup("");
- r = new(char, strlen(f) + 1);
+ r = new(char, l + 1);
if (!r)
return NULL;
- for (t = r; *f; f++) {
-
- if (*f == '_') {
+ for (i = 0, t = r; i < l; ++i) {
+ if (f[i] == '_') {
int a, b;
- if ((a = unhexchar(f[1])) < 0 ||
- (b = unhexchar(f[2])) < 0) {
+ if (l - i < 3 ||
+ (a = unhexchar(f[i + 1])) < 0 ||
+ (b = unhexchar(f[i + 2])) < 0) {
/* Invalid escape code, let's take it literal then */
*(t++) = '_';
} else {
*(t++) = (char) ((a << 4) | b);
- f += 2;
+ i += 2;
}
} else
- *(t++) = *f;
+ *(t++) = f[i];
}
*t = 0;
diff --git a/src/shared/bus-label.h b/src/shared/bus-label.h
index c27c8517fd..ed1dc4e0a7 100644
--- a/src/shared/bus-label.h
+++ b/src/shared/bus-label.h
@@ -21,5 +21,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdlib.h>
+#include <string.h>
+
char *bus_label_escape(const char *s);
-char *bus_label_unescape(const char *f);
+char *bus_label_unescape_n(const char *f, size_t l);
+
+static inline char *bus_label_unescape(const char *f) {
+ return bus_label_unescape_n(f, f ? strlen(f) : 0);
+}
diff --git a/src/shared/cap-list.c b/src/shared/cap-list.c
index 8033e8c7b2..bd5bffbfa5 100644
--- a/src/shared/cap-list.c
+++ b/src/shared/cap-list.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <linux/capability.h>
#include <string.h>
#include "util.h"
diff --git a/src/shared/capability.c b/src/shared/capability.c
index 915ceb9d9b..58f00e6dae 100644
--- a/src/shared/capability.c
+++ b/src/shared/capability.c
@@ -19,14 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
-#include <sys/types.h>
-#include <stdarg.h>
-#include <ctype.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include "grp.h"
@@ -55,7 +50,7 @@ unsigned long cap_last_cap(void) {
static thread_local unsigned long saved;
static thread_local bool valid = false;
_cleanup_free_ char *content = NULL;
- unsigned long p;
+ unsigned long p = 0;
int r;
if (valid)
diff --git a/src/shared/capability.h b/src/shared/capability.h
index 6f2f6f997d..4eb5c2a835 100644
--- a/src/shared/capability.h
+++ b/src/shared/capability.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
#include <stdbool.h>
#include <sys/capability.h>
@@ -32,7 +31,7 @@ int have_effective_cap(int value);
int capability_bounding_set_drop(uint64_t drop, bool right_now);
int capability_bounding_set_drop_usermode(uint64_t drop);
-int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites);
+int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities);
int drop_capability(cap_value_t cv);
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index cbd94e86d9..1a2c4b28cd 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -25,10 +25,13 @@
#include <errno.h>
#include "util.h"
+#include "formats-util.h"
+#include "process-util.h"
#include "macro.h"
#include "path-util.h"
#include "cgroup-util.h"
#include "cgroup-show.h"
+#include "terminal-util.h"
static int compare(const void *a, const void *b) {
const pid_t *p = a, *q = b;
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index 3146f56cad..aa832454b5 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -23,7 +23,6 @@
#include <stdbool.h>
#include <sys/types.h>
-#include "util.h"
#include "logs-show.h"
int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index dfd8689b72..9988e5c574 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -30,16 +30,17 @@
#include <ftw.h>
#include "cgroup-util.h"
-#include "log.h"
#include "set.h"
#include "macro.h"
#include "util.h"
+#include "formats-util.h"
+#include "process-util.h"
#include "path-util.h"
-#include "strv.h"
#include "unit-name.h"
#include "fileio.h"
#include "special.h"
#include "mkdir.h"
+#include "login-shared.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
_cleanup_free_ char *fs = NULL;
@@ -488,9 +489,11 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (_unlikely_(!good)) {
int r;
- r = path_is_mount_point("/sys/fs/cgroup", false);
- if (r <= 0)
- return r < 0 ? r : -ENOENT;
+ r = path_is_mount_point("/sys/fs/cgroup", 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
/* Cache this to save a few stat()s */
good = true;
@@ -1138,17 +1141,21 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
}
int cg_path_decode_unit(const char *cgroup, char **unit){
- char *e, *c, *s;
+ char *c, *s;
+ size_t n;
assert(cgroup);
assert(unit);
- e = strchrnul(cgroup, '/');
- c = strndupa(cgroup, e - cgroup);
+ n = strcspn(cgroup, "/");
+ if (n < 3)
+ return -ENXIO;
+
+ c = strndupa(cgroup, n);
c = cg_unescape(c);
- if (!unit_name_is_valid(c, TEMPLATE_INVALID))
- return -EINVAL;
+ if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
+ return -ENXIO;
s = strdup(c);
if (!s)
@@ -1158,7 +1165,31 @@ int cg_path_decode_unit(const char *cgroup, char **unit){
return 0;
}
+static bool valid_slice_name(const char *p, size_t n) {
+
+ if (!p)
+ return false;
+
+ if (n < strlen("x.slice"))
+ return false;
+
+ if (memcmp(p + n - 6, ".slice", 6) == 0) {
+ char buf[n+1], *c;
+
+ memcpy(buf, p, n);
+ buf[n] = 0;
+
+ c = cg_unescape(buf);
+
+ return unit_name_is_valid(c, UNIT_NAME_PLAIN);
+ }
+
+ return false;
+}
+
static const char *skip_slices(const char *p) {
+ assert(p);
+
/* Skips over all slice assignments */
for (;;) {
@@ -1167,22 +1198,35 @@ static const char *skip_slices(const char *p) {
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0)
+ if (!valid_slice_name(p, n))
return p;
p += n;
}
}
-int cg_path_get_unit(const char *path, char **unit) {
+int cg_path_get_unit(const char *path, char **ret) {
const char *e;
+ char *unit;
+ int r;
assert(path);
- assert(unit);
+ assert(ret);
e = skip_slices(path);
- return cg_path_decode_unit(e, unit);
+ r = cg_path_decode_unit(e, &unit);
+ if (r < 0)
+ return r;
+
+ /* We skipped over the slices, don't accept any now */
+ if (endswith(unit, ".slice")) {
+ free(unit);
+ return -ENXIO;
+ }
+
+ *ret = unit;
+ return 0;
}
int cg_pid_get_unit(pid_t pid, char **unit) {
@@ -1204,18 +1248,35 @@ int cg_pid_get_unit(pid_t pid, char **unit) {
static const char *skip_session(const char *p) {
size_t n;
- assert(p);
+ if (isempty(p))
+ return NULL;
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
+ if (n < strlen("session-x.scope"))
return NULL;
- p += n;
- p += strspn(p, "/");
+ if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
+ char buf[n - 8 - 6 + 1];
+
+ memcpy(buf, p + 8, n - 8 - 6);
+ buf[n - 8 - 6] = 0;
+
+ /* Note that session scopes never need unescaping,
+ * since they cannot conflict with the kernel's own
+ * names, hence we don't need to call cg_unescape()
+ * here. */
+
+ if (!session_id_valid(buf))
+ return false;
- return p;
+ p += n;
+ p += strspn(p, "/");
+ return p;
+ }
+
+ return NULL;
}
/**
@@ -1224,44 +1285,69 @@ static const char *skip_session(const char *p) {
static const char *skip_user_manager(const char *p) {
size_t n;
- assert(p);
+ if (isempty(p))
+ return NULL;
p += strspn(p, "/");
n = strcspn(p, "/");
- if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0)
+ if (n < strlen("user@x.service"))
return NULL;
- p += n;
- p += strspn(p, "/");
+ if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
+ char buf[n - 5 - 8 + 1];
- return p;
+ memcpy(buf, p + 5, n - 5 - 8);
+ buf[n - 5 - 8] = 0;
+
+ /* Note that user manager services never need unescaping,
+ * since they cannot conflict with the kernel's own
+ * names, hence we don't need to call cg_unescape()
+ * here. */
+
+ if (parse_uid(buf, NULL) < 0)
+ return NULL;
+
+ p += n;
+ p += strspn(p, "/");
+
+ return p;
+ }
+
+ return NULL;
}
-int cg_path_get_user_unit(const char *path, char **unit) {
+static const char *skip_user_prefix(const char *path) {
const char *e, *t;
assert(path);
- assert(unit);
-
- /* We always have to parse the path from the beginning as unit
- * cgroups might have arbitrary child cgroups and we shouldn't get
- * confused by those */
/* Skip slices, if there are any */
e = skip_slices(path);
- /* Skip the session scope or user manager... */
- t = skip_session(e);
- if (!t)
- t = skip_user_manager(e);
- if (!t)
- return -ENOENT;
+ /* Skip the user manager, if it's in the path now... */
+ t = skip_user_manager(e);
+ if (t)
+ return t;
+
+ /* Alternatively skip the user session if it is in the path... */
+ return skip_session(e);
+}
- /* ... and skip more slices if there are any */
- e = skip_slices(t);
+int cg_path_get_user_unit(const char *path, char **ret) {
+ const char *t;
- return cg_path_decode_unit(e, unit);
+ assert(path);
+ assert(ret);
+
+ t = skip_user_prefix(path);
+ if (!t)
+ return -ENXIO;
+
+ /* And from here on it looks pretty much the same as for a
+ * system unit, hence let's use the same parser from here
+ * on. */
+ return cg_path_get_unit(t, ret);
}
int cg_pid_get_user_unit(pid_t pid, char **unit) {
@@ -1306,36 +1392,35 @@ int cg_pid_get_machine_name(pid_t pid, char **machine) {
}
int cg_path_get_session(const char *path, char **session) {
- const char *e, *n, *x, *y;
- char *s;
+ _cleanup_free_ char *unit = NULL;
+ char *start, *end;
+ int r;
assert(path);
- /* Skip slices, if there are any */
- e = skip_slices(path);
-
- n = strchrnul(e, '/');
- if (e == n)
- return -ENOENT;
+ r = cg_path_get_unit(path, &unit);
+ if (r < 0)
+ return r;
- s = strndupa(e, n - e);
- s = cg_unescape(s);
+ start = startswith(unit, "session-");
+ if (!start)
+ return -ENXIO;
+ end = endswith(start, ".scope");
+ if (!end)
+ return -ENXIO;
- x = startswith(s, "session-");
- if (!x)
- return -ENOENT;
- y = endswith(x, ".scope");
- if (!y || x == y)
- return -ENOENT;
+ *end = 0;
+ if (!session_id_valid(start))
+ return -ENXIO;
if (session) {
- char *r;
+ char *rr;
- r = strndup(x, y - x);
- if (!r)
+ rr = strdup(start);
+ if (!rr)
return -ENOMEM;
- *session = r;
+ *session = rr;
}
return 0;
@@ -1354,9 +1439,7 @@ int cg_pid_get_session(pid_t pid, char **session) {
int cg_path_get_owner_uid(const char *path, uid_t *uid) {
_cleanup_free_ char *slice = NULL;
- const char *start, *end;
- char *s;
- uid_t u;
+ char *start, *end;
int r;
assert(path);
@@ -1367,20 +1450,14 @@ int cg_path_get_owner_uid(const char *path, uid_t *uid) {
start = startswith(slice, "user-");
if (!start)
- return -ENOENT;
- end = endswith(slice, ".slice");
+ return -ENXIO;
+ end = endswith(start, ".slice");
if (!end)
- return -ENOENT;
+ return -ENXIO;
- s = strndupa(start, end - start);
- if (!s)
- return -ENOENT;
-
- if (parse_uid(s, &u) < 0)
- return -EIO;
-
- if (uid)
- *uid = u;
+ *end = 0;
+ if (parse_uid(start, uid) < 0)
+ return -ENXIO;
return 0;
}
@@ -1398,34 +1475,36 @@ int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
int cg_path_get_slice(const char *p, char **slice) {
const char *e = NULL;
- size_t m = 0;
assert(p);
assert(slice);
+ /* 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, "/");
n = strcspn(p, "/");
- if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) {
- char *s;
+ if (!valid_slice_name(p, n)) {
- if (!e)
- return -ENOENT;
+ if (!e) {
+ char *s;
- s = strndup(e, m);
- if (!s)
- return -ENOMEM;
+ s = strdup("-.slice");
+ if (!s)
+ return -ENOMEM;
- *slice = s;
- return 0;
+ *slice = s;
+ return 0;
+ }
+
+ return cg_path_decode_unit(e, slice);
}
e = p;
- m = n;
-
p += n;
}
}
@@ -1443,6 +1522,33 @@ int cg_pid_get_slice(pid_t pid, char **slice) {
return cg_path_get_slice(cgroup, slice);
}
+int cg_path_get_user_slice(const char *p, char **slice) {
+ const char *t;
+ assert(p);
+ assert(slice);
+
+ t = skip_user_prefix(p);
+ if (!t)
+ return -ENXIO;
+
+ /* And now it looks pretty much the same as for a system
+ * slice, so let's just use the same parser from here on. */
+ return cg_path_get_slice(t, slice);
+}
+
+int cg_pid_get_user_slice(pid_t pid, char **slice) {
+ _cleanup_free_ char *cgroup = NULL;
+ int r;
+
+ assert(slice);
+
+ r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
+ if (r < 0)
+ return r;
+
+ return cg_path_get_user_slice(cgroup, slice);
+}
+
char *cg_escape(const char *p) {
bool need_prefix = false;
@@ -1532,28 +1638,47 @@ bool cg_controller_is_valid(const char *p, bool allow_named) {
int cg_slice_to_path(const char *unit, char **ret) {
_cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
const char *dash;
+ int r;
assert(unit);
assert(ret);
- if (!unit_name_is_valid(unit, TEMPLATE_INVALID))
+ if (streq(unit, "-.slice")) {
+ char *x;
+
+ x = strdup("");
+ if (!x)
+ return -ENOMEM;
+ *ret = x;
+ return 0;
+ }
+
+ if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
return -EINVAL;
if (!endswith(unit, ".slice"))
return -EINVAL;
- p = unit_name_to_prefix(unit);
- if (!p)
- return -ENOMEM;
+ r = unit_name_to_prefix(unit, &p);
+ if (r < 0)
+ return r;
dash = strchr(p, '-');
+
+ /* Don't allow initial dashes */
+ if (dash == p)
+ return -EINVAL;
+
while (dash) {
_cleanup_free_ char *escaped = NULL;
char n[dash - p + sizeof(".slice")];
- strcpy(stpncpy(n, p, dash - p), ".slice");
+ /* Don't allow trailing or double dashes */
+ if (dash[1] == 0 || dash[1] == '-')
+ return -EINVAL;
- if (!unit_name_is_valid(n, TEMPLATE_INVALID))
+ strcpy(stpncpy(n, p, dash - p), ".slice");
+ if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
return -EINVAL;
escaped = cg_escape(n);
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index 96a3d3bafa..cbf7201370 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -104,6 +104,7 @@ int cg_path_get_unit(const char *path, char **unit);
int cg_path_get_user_unit(const char *path, char **unit);
int cg_path_get_machine_name(const char *path, char **machine);
int cg_path_get_slice(const char *path, char **slice);
+int cg_path_get_user_slice(const char *path, char **slice);
int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted);
int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup);
@@ -114,6 +115,7 @@ int cg_pid_get_unit(pid_t pid, char **unit);
int cg_pid_get_user_unit(pid_t pid, char **unit);
int cg_pid_get_machine_name(pid_t pid, char **machine);
int cg_pid_get_slice(pid_t pid, char **slice);
+int cg_pid_get_user_slice(pid_t pid, char **slice);
int cg_path_decode_unit(const char *cgroup, char **unit);
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index 39ab645133..48b10865da 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -24,12 +24,12 @@
#include <sys/sem.h>
#include <sys/msg.h>
#include <sys/stat.h>
-#include <sys/mman.h>
#include <fcntl.h>
#include <dirent.h>
#include <mqueue.h>
#include "util.h"
+#include "formats-util.h"
#include "strv.h"
#include "clean-ipc.h"
diff --git a/src/shared/clock-util.c b/src/shared/clock-util.c
index 96684681a4..e4e03df1e4 100644
--- a/src/shared/clock-util.c
+++ b/src/shared/clock-util.c
@@ -19,29 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <string.h>
-#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <sys/prctl.h>
#include <sys/time.h>
#include <linux/rtc.h>
#include "macro.h"
#include "util.h"
-#include "log.h"
-#include "strv.h"
#include "clock-util.h"
-#include "fileio.h"
int clock_get_hwclock(struct tm *tm) {
_cleanup_close_ int fd = -1;
diff --git a/src/shared/clock-util.h b/src/shared/clock-util.h
index 198a7b2753..8c2d235430 100644
--- a/src/shared/clock-util.h
+++ b/src/shared/clock-util.h
@@ -21,7 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
int clock_is_localtime(void);
int clock_set_timezone(int *min);
diff --git a/src/shared/condition.c b/src/shared/condition.c
index da7560f05f..24871b0dae 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -23,22 +23,21 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <sys/statvfs.h>
#include <fnmatch.h>
#include "sd-id128.h"
#include "util.h"
#include "virt.h"
#include "path-util.h"
-#include "fileio.h"
#include "architecture.h"
#include "smack-util.h"
#include "apparmor-util.h"
#include "ima-util.h"
#include "selinux-util.h"
#include "audit.h"
-#include "condition.h"
#include "cap-list.h"
+#include "hostname-util.h"
+#include "condition.h"
Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
Condition *c;
@@ -46,7 +45,7 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
assert(type >= 0);
assert(type < _CONDITION_TYPE_MAX);
- assert(!parameter == (type == CONDITION_NULL));
+ assert((!parameter) == (type == CONDITION_NULL));
c = new0(Condition, 1);
if (!c)
@@ -102,7 +101,7 @@ static int condition_test_kernel_command_line(Condition *c) {
_cleanup_free_ char *word = NULL;
bool found;
- r = unquote_first_word(&p, &word, true);
+ r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -350,7 +349,7 @@ static int condition_test_path_is_mount_point(Condition *c) {
assert(c->parameter);
assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
- return path_is_mount_point(c->parameter, true) > 0;
+ return path_is_mount_point(c->parameter, AT_SYMLINK_FOLLOW) > 0;
}
static int condition_test_path_is_read_write(Condition *c) {
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index db4937db88..da8745b284 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -19,13 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
-#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
-#include <sys/stat.h>
#include <dirent.h>
#include "macro.h"
@@ -39,12 +36,13 @@
static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
_cleanup_closedir_ DIR *dir = NULL;
- char *dirpath;
+ const char *dirpath;
+ int r;
assert(path);
assert(suffix);
- dirpath = strjoina(root ? root : "", path);
+ dirpath = prefix_roota(root, path);
dir = opendir(dirpath);
if (!dir) {
@@ -56,7 +54,6 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
for (;;) {
struct dirent *de;
char *p;
- int r;
errno = 0;
de = readdir(dir);
diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h
index 368c112eb3..3169a907f1 100644
--- a/src/shared/conf-files.h
+++ b/src/shared/conf-files.h
@@ -22,7 +22,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "macro.h"
int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 0b1af6c577..7370c786f9 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -22,9 +22,7 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
-#include <assert.h>
#include <stdlib.h>
-#include <netinet/ether.h>
#include "conf-parser.h"
#include "conf-files.h"
@@ -34,54 +32,8 @@
#include "log.h"
#include "utf8.h"
#include "path-util.h"
-#include "set.h"
-#include "exit-status.h"
#include "sd-messages.h"
-int log_syntax_internal(
- const char *unit,
- int level,
- const char *file,
- int line,
- const char *func,
- const char *config_file,
- unsigned config_line,
- int error,
- const char *format, ...) {
-
- _cleanup_free_ char *msg = NULL;
- int r;
- va_list ap;
-
- va_start(ap, format);
- r = vasprintf(&msg, format, ap);
- va_end(ap);
- if (r < 0)
- return log_oom();
-
- if (unit)
- r = log_struct_internal(level,
- error,
- file, line, func,
- getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
- LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
- "CONFIG_FILE=%s", config_file,
- "CONFIG_LINE=%u", config_line,
- LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
- NULL);
- else
- r = log_struct_internal(level,
- error,
- file, line, func,
- LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
- "CONFIG_FILE=%s", config_file,
- "CONFIG_LINE=%u", config_line,
- LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
- NULL);
-
- return r;
-}
-
int config_item_table_lookup(
const void *table,
const char *section,
@@ -492,7 +444,7 @@ int config_parse_many(const char *conf_file,
if (r < 0) \
log_syntax(unit, LOG_ERR, filename, line, -r, \
"Failed to parse %s value, ignoring: %s", \
- #vartype, rvalue); \
+ #type, rvalue); \
\
return 0; \
}
@@ -763,41 +715,30 @@ int config_parse_strv(const char *unit,
return 0;
}
-int config_parse_mode(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
+int config_parse_mode(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
mode_t *m = data;
- long l;
- char *x = NULL;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- errno = 0;
- l = strtol(rvalue, &x, 8);
- if (!x || x == rvalue || *x || errno) {
- log_syntax(unit, LOG_ERR, filename, line, errno,
- "Failed to parse mode value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (l < 0000 || l > 07777) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Mode value out of range, ignoring: %s", rvalue);
+ if (parse_mode(rvalue, m) < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
return 0;
}
- *m = (mode_t) l;
return 0;
}
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 7a2f855f9f..6152ee33b9 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -119,23 +119,6 @@ int config_parse_mode(const char *unit, const char *filename, unsigned line, con
int config_parse_log_facility(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_log_level(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int log_syntax_internal(
- const char *unit,
- int level,
- const char *file,
- int line,
- const char *func,
- const char *config_file,
- unsigned config_line,
- int error,
- const char *format, ...) _printf_(9, 10);
-
-#define log_syntax(unit, level, config_file, config_line, error, ...) \
- log_syntax_internal(unit, level, \
- __FILE__, __LINE__, __func__, \
- config_file, config_line, \
- error, __VA_ARGS__)
-
#define log_invalid_utf8(unit, level, config_file, config_line, error, rvalue) \
do { \
_cleanup_free_ char *_p = utf8_escape_invalid(rvalue); \
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 0239a58066..1282cb88be 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -285,7 +285,7 @@ static int fd_copy_directory(
else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
else
- q = -ENOTSUP;
+ q = -EOPNOTSUPP;
if (q == -EEXIST && merge)
q = 0;
@@ -317,7 +317,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
return fd_copy_node(fdf, from, &st, fdt, to);
else
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
int copy_tree(const char *from, const char *to, bool merge) {
@@ -360,7 +360,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
}
int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
- int fdt, r;
+ int fdt = -1, r;
assert(from);
assert(to);
@@ -372,7 +372,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
}
if (chattr_flags != 0)
- (void) chattr_fd(fdt, true, chattr_flags);
+ (void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
r = copy_file_fd(from, fdt, true);
if (r < 0) {
@@ -390,7 +390,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
}
int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
- _cleanup_free_ char *t;
+ _cleanup_free_ char *t = NULL;
int r;
assert(from);
@@ -404,9 +404,15 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
if (r < 0)
return r;
- if (renameat2(AT_FDCWD, t, AT_FDCWD, to, replace ? 0 : RENAME_NOREPLACE) < 0) {
- unlink_noerrno(t);
- return -errno;
+ if (replace) {
+ r = renameat(AT_FDCWD, t, AT_FDCWD, to);
+ if (r < 0)
+ r = -errno;
+ } else
+ r = rename_noreplace(AT_FDCWD, t, AT_FDCWD, to);
+ if (r < 0) {
+ (void) unlink_noerrno(t);
+ return r;
}
return 0;
@@ -415,7 +421,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
int copy_times(int fdf, int fdt) {
struct timespec ut[2];
struct stat st;
- usec_t crtime;
+ usec_t crtime = 0;
assert(fdf >= 0);
assert(fdt >= 0);
diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c
index e8b0810d23..25ad918b85 100644
--- a/src/shared/dev-setup.c
+++ b/src/shared/dev-setup.c
@@ -20,21 +20,15 @@
***/
#include <errno.h>
-#include <sys/stat.h>
#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
#include <unistd.h>
-#include "dev-setup.h"
-#include "log.h"
-#include "macro.h"
#include "util.h"
#include "label.h"
+#include "path-util.h"
+#include "dev-setup.h"
-int dev_setup(const char *prefix) {
- const char *j, *k;
-
+int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
static const char symlinks[] =
"-/proc/kcore\0" "/dev/core\0"
"/proc/self/fd\0" "/dev/fd\0"
@@ -42,7 +36,13 @@ int dev_setup(const char *prefix) {
"/proc/self/fd/1\0" "/dev/stdout\0"
"/proc/self/fd/2\0" "/dev/stderr\0";
+ const char *j, *k;
+ int r;
+
NULSTR_FOREACH_PAIR(j, k, symlinks) {
+ _cleanup_free_ char *link_name = NULL;
+ const char *n;
+
if (j[0] == '-') {
j++;
@@ -51,15 +51,21 @@ int dev_setup(const char *prefix) {
}
if (prefix) {
- _cleanup_free_ char *link_name = NULL;
-
- link_name = strjoin(prefix, "/", k, NULL);
+ link_name = prefix_root(prefix, k);
if (!link_name)
return -ENOMEM;
- symlink_label(j, link_name);
+ n = link_name;
} else
- symlink_label(j, k);
+ n = k;
+
+ r = symlink_label(j, n);
+ if (r < 0)
+ log_debug_errno(r, "Failed to symlink %s to %s: %m", j, n);
+
+ if (uid != UID_INVALID || gid != GID_INVALID)
+ if (lchown(n, uid, gid) < 0)
+ log_debug_errno(errno, "Failed to chown %s: %m", n);
}
return 0;
diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h
index d41b6eefba..ab2748db7f 100644
--- a/src/shared/dev-setup.h
+++ b/src/shared/dev-setup.h
@@ -21,4 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int dev_setup(const char *pathprefix);
+#include <sys/types.h>
+
+int dev_setup(const char *prefix, uid_t uid, gid_t gid);
diff --git a/src/shared/device-nodes.c b/src/shared/device-nodes.c
index 73e9edd29d..9d5af72d27 100644
--- a/src/shared/device-nodes.c
+++ b/src/shared/device-nodes.c
@@ -19,21 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <sys/types.h>
#include "device-nodes.h"
#include "utf8.h"
int whitelisted_char_for_devnode(char c, const char *white) {
+
if ((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
strchr("#+-.:=@_", c) != NULL ||
(white != NULL && strchr(white, c) != NULL))
return 1;
+
return 0;
}
@@ -48,27 +47,34 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) {
seqlen = utf8_encoded_valid_unichar(&str[i]);
if (seqlen > 1) {
+
if (len-j < (size_t)seqlen)
- goto err;
+ return -EINVAL;
+
memcpy(&str_enc[j], &str[i], seqlen);
j += seqlen;
i += (seqlen-1);
+
} else if (str[i] == '\\' || !whitelisted_char_for_devnode(str[i], NULL)) {
+
if (len-j < 4)
- goto err;
+ return -EINVAL;
+
sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
j += 4;
+
} else {
if (len-j < 1)
- goto err;
+ return -EINVAL;
+
str_enc[j] = str[i];
j++;
}
}
+
if (len-j < 1)
- goto err;
+ return -EINVAL;
+
str_enc[j] = '\0';
return 0;
-err:
- return -EINVAL;
}
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index d1baad6192..963d05d32e 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -164,7 +164,7 @@ static int iterate_dir(
}
int unit_file_process_dir(
- Set * unit_path_cache,
+ Set *unit_path_cache,
const char *unit_path,
const char *name,
const char *suffix,
@@ -174,6 +174,7 @@ int unit_file_process_dir(
char ***strv) {
_cleanup_free_ char *path = NULL;
+ int r;
assert(unit_path);
assert(name);
@@ -184,22 +185,22 @@ int unit_file_process_dir(
return log_oom();
if (!unit_path_cache || set_get(unit_path_cache, path))
- iterate_dir(path, dependency, consumer, arg, strv);
+ (void) iterate_dir(path, dependency, consumer, arg, strv);
- if (unit_name_is_instance(name)) {
+ if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
_cleanup_free_ char *template = NULL, *p = NULL;
/* Also try the template dir */
- template = unit_name_template(name);
- if (!template)
- return log_oom();
+ r = unit_name_template(name, &template);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate template from unit name: %m");
p = strjoin(unit_path, "/", template, suffix, NULL);
if (!p)
return log_oom();
if (!unit_path_cache || set_get(unit_path_cache, p))
- iterate_dir(p, dependency, consumer, arg, strv);
+ (void) iterate_dir(p, dependency, consumer, arg, strv);
}
return 0;
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index a319574527..d34d977b9a 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -22,15 +22,49 @@
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
-#include <ctype.h>
-#include "acpi-fpdt.h"
#include "util.h"
#include "utf8.h"
+#include "virt.h"
#include "efivars.h"
#ifdef ENABLE_EFI
+#define LOAD_OPTION_ACTIVE 0x00000001
+#define MEDIA_DEVICE_PATH 0x04
+#define MEDIA_HARDDRIVE_DP 0x01
+#define MEDIA_FILEPATH_DP 0x04
+#define SIGNATURE_TYPE_GUID 0x02
+#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
+#define END_DEVICE_PATH_TYPE 0x7f
+#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
+
+struct boot_option {
+ uint32_t attr;
+ uint16_t path_len;
+ uint16_t title[];
+} _packed_;
+
+struct drive_path {
+ uint32_t part_nr;
+ uint64_t part_start;
+ uint64_t part_size;
+ char signature[16];
+ uint8_t mbr_type;
+ uint8_t signature_type;
+} _packed_;
+
+struct device_path {
+ uint8_t type;
+ uint8_t sub_type;
+ uint16_t length;
+ union {
+ uint16_t path[0];
+ struct drive_path drive;
+ };
+} _packed_;
+
bool is_efi_boot(void) {
return access("/sys/firmware/efi", F_OK) >= 0;
}
@@ -53,12 +87,82 @@ static int read_flag(const char *varname) {
return r;
}
-int is_efi_secure_boot(void) {
- return read_flag("SecureBoot");
+bool is_efi_secure_boot(void) {
+ return read_flag("SecureBoot") > 0;
+}
+
+bool is_efi_secure_boot_setup_mode(void) {
+ return read_flag("SetupMode") > 0;
+}
+
+int efi_reboot_to_firmware_supported(void) {
+ int r;
+ size_t s;
+ uint64_t b;
+ _cleanup_free_ void *v = NULL;
+
+ if (!is_efi_boot() || detect_container(NULL) > 0)
+ return -EOPNOTSUPP;
+
+ r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
+ if (r < 0)
+ return r;
+ else if (s != sizeof(uint64_t))
+ return -EINVAL;
+
+ b = *(uint64_t *)v;
+ b &= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+ return b > 0 ? 0 : -EOPNOTSUPP;
+}
+
+static int get_os_indications(uint64_t *os_indication) {
+ int r;
+ size_t s;
+ _cleanup_free_ void *v = NULL;
+
+ r = efi_reboot_to_firmware_supported();
+ if (r < 0)
+ return r;
+
+ r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
+ if (r < 0)
+ return r;
+ else if (s != sizeof(uint64_t))
+ return -EINVAL;
+
+ *os_indication = *(uint64_t *)v;
+ return 0;
+}
+
+int efi_get_reboot_to_firmware(void) {
+ int r;
+ uint64_t b;
+
+ r = get_os_indications(&b);
+ if (r < 0)
+ return r;
+
+ return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
}
-int is_efi_secure_boot_setup_mode(void) {
- return read_flag("SetupMode");
+int efi_set_reboot_to_firmware(bool value) {
+ int r;
+ uint64_t b, b_new;
+
+ r = get_os_indications(&b);
+ if (r < 0)
+ return r;
+
+ if (value)
+ b_new = b | EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+ else
+ b_new = b & ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+
+ /* Avoid writing to efi vars store if we can due to firmware bugs. */
+ if (b != b_new)
+ return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t));
+
+ return 0;
}
int efi_get_variable(
@@ -73,7 +177,7 @@ int efi_get_variable(
uint32_t a;
ssize_t n;
struct stat st;
- void *r;
+ _cleanup_free_ void *buf = NULL;
assert(name);
assert(value);
@@ -101,25 +205,22 @@ int efi_get_variable(
if (n != sizeof(a))
return -EIO;
- r = malloc(st.st_size - 4 + 2);
- if (!r)
+ buf = malloc(st.st_size - 4 + 2);
+ if (!buf)
return -ENOMEM;
- n = read(fd, r, (size_t) st.st_size - 4);
- if (n < 0) {
- free(r);
+ n = read(fd, buf, (size_t) st.st_size - 4);
+ if (n < 0)
return -errno;
- }
- if (n != (ssize_t) st.st_size - 4) {
- free(r);
+ if (n != (ssize_t) st.st_size - 4)
return -EIO;
- }
/* Always NUL terminate (2 bytes, to protect UTF-16) */
- ((char*) r)[st.st_size - 4] = 0;
- ((char*) r)[st.st_size - 4 + 1] = 0;
+ ((char*) buf)[st.st_size - 4] = 0;
+ ((char*) buf)[st.st_size - 4 + 1] = 0;
- *value = r;
+ *value = buf;
+ buf = NULL;
*size = (size_t) st.st_size - 4;
if (attribute)
@@ -128,6 +229,46 @@ int efi_get_variable(
return 0;
}
+int efi_set_variable(
+ sd_id128_t vendor,
+ const char *name,
+ const void *value,
+ size_t size) {
+
+ struct var {
+ uint32_t attr;
+ char buf[];
+ } _packed_ * _cleanup_free_ buf = NULL;
+ _cleanup_free_ char *p = NULL;
+ _cleanup_close_ int fd = -1;
+
+ assert(name);
+
+ if (asprintf(&p,
+ "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ name, SD_ID128_FORMAT_VAL(vendor)) < 0)
+ return -ENOMEM;
+
+ if (size == 0) {
+ if (unlink(p) < 0)
+ return -errno;
+ return 0;
+ }
+
+ fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
+ if (fd < 0)
+ return -errno;
+
+ buf = malloc(sizeof(uint32_t) + size);
+ if (!buf)
+ return -ENOMEM;
+
+ buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
+ memcpy(buf->buf, value, size);
+
+ return loop_write(fd, buf, sizeof(uint32_t) + size, false);
+}
+
int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
_cleanup_free_ void *s = NULL;
size_t ss = 0;
@@ -179,47 +320,22 @@ int efi_get_boot_option(
uint16_t id,
char **title,
sd_id128_t *part_uuid,
- char **path) {
-
- struct boot_option {
- uint32_t attr;
- uint16_t path_len;
- uint16_t title[];
- } _packed_;
-
- struct drive_path {
- uint32_t part_nr;
- uint64_t part_start;
- uint64_t part_size;
- char signature[16];
- uint8_t mbr_type;
- uint8_t signature_type;
- } _packed_;
-
- struct device_path {
- uint8_t type;
- uint8_t sub_type;
- uint16_t length;
- union {
- uint16_t path[0];
- struct drive_path drive;
- };
- } _packed_;
+ char **path,
+ bool *active) {
char boot_id[9];
_cleanup_free_ uint8_t *buf = NULL;
size_t l;
struct boot_option *header;
size_t title_size;
- char *s = NULL;
- char *p = NULL;
+ _cleanup_free_ char *s = NULL, *p = NULL;
sd_id128_t p_uuid = SD_ID128_NULL;
- int err;
+ int r;
- snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
- err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
- if (err < 0)
- return err;
+ xsprintf(boot_id, "Boot%04X", id);
+ r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
+ if (r < 0)
+ return r;
if (l < sizeof(struct boot_option))
return -ENOENT;
@@ -230,10 +346,8 @@ int efi_get_boot_option(
if (title) {
s = utf16_to_utf8(header->title, title_size);
- if (!s) {
- err = -ENOMEM;
- goto err;
- }
+ if (!s)
+ return -ENOMEM;
}
if (header->path_len > 0) {
@@ -250,23 +364,23 @@ int efi_get_boot_option(
break;
/* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
- if (dpath->type == 0x7f && dpath->sub_type == 0xff)
+ if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
break;
dnext += dpath->length;
/* Type 0x04 – Media Device Path */
- if (dpath->type != 0x04)
+ if (dpath->type != MEDIA_DEVICE_PATH)
continue;
/* Sub-Type 1 – Hard Drive */
- if (dpath->sub_type == 0x01) {
+ if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
/* 0x02 – GUID Partition Table */
- if (dpath->drive.mbr_type != 0x02)
+ if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
continue;
/* 0x02 – GUID signature */
- if (dpath->drive.signature_type != 0x02)
+ if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
continue;
if (part_uuid)
@@ -275,29 +389,135 @@ int efi_get_boot_option(
}
/* Sub-Type 4 – File Path */
- if (dpath->sub_type == 0x04 && !p && path) {
+ if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
p = utf16_to_utf8(dpath->path, dpath->length-4);
+ efi_tilt_backslashes(p);
continue;
}
}
}
- if (title)
+ if (title) {
*title = s;
+ s = NULL;
+ }
if (part_uuid)
*part_uuid = p_uuid;
- if (path)
+ if (path) {
*path = p;
+ p = NULL;
+ }
+ if (active)
+ *active = !!(header->attr & LOAD_OPTION_ACTIVE);
return 0;
-err:
- free(s);
- free(p);
- return err;
+}
+
+static void to_utf16(uint16_t *dest, const char *src) {
+ int i;
+
+ for (i = 0; src[i] != '\0'; i++)
+ dest[i] = src[i];
+ dest[i] = '\0';
+}
+
+struct guid {
+ uint32_t u1;
+ uint16_t u2;
+ uint16_t u3;
+ uint8_t u4[8];
+} _packed_;
+
+static void id128_to_efi_guid(sd_id128_t id, void *guid) {
+ struct guid *uuid = guid;
+
+ uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
+ uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
+ uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
+ memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
+}
+
+static uint16_t *tilt_slashes(uint16_t *s) {
+ uint16_t *p;
+
+ for (p = s; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+
+ return s;
+}
+
+int efi_add_boot_option(uint16_t id, const char *title,
+ uint32_t part, uint64_t pstart, uint64_t psize,
+ sd_id128_t part_uuid, const char *path) {
+ char boot_id[9];
+ size_t size;
+ size_t title_len;
+ size_t path_len;
+ struct boot_option *option;
+ struct device_path *devicep;
+ _cleanup_free_ char *buf = NULL;
+
+ title_len = (strlen(title)+1) * 2;
+ path_len = (strlen(path)+1) * 2;
+
+ buf = calloc(sizeof(struct boot_option) + title_len +
+ sizeof(struct drive_path) +
+ sizeof(struct device_path) + path_len, 1);
+ if (!buf)
+ return -ENOMEM;
+
+ /* header */
+ option = (struct boot_option *)buf;
+ option->attr = LOAD_OPTION_ACTIVE;
+ option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
+ offsetof(struct device_path, path) + path_len +
+ offsetof(struct device_path, path);
+ to_utf16(option->title, title);
+ size = offsetof(struct boot_option, title) + title_len;
+
+ /* partition info */
+ devicep = (struct device_path *)(buf + size);
+ devicep->type = MEDIA_DEVICE_PATH;
+ devicep->sub_type = MEDIA_HARDDRIVE_DP;
+ devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
+ devicep->drive.part_nr = part;
+ devicep->drive.part_start = pstart;
+ devicep->drive.part_size = psize;
+ devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
+ devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+ id128_to_efi_guid(part_uuid, devicep->drive.signature);
+ size += devicep->length;
+
+ /* path to loader */
+ devicep = (struct device_path *)(buf + size);
+ devicep->type = MEDIA_DEVICE_PATH;
+ devicep->sub_type = MEDIA_FILEPATH_DP;
+ devicep->length = offsetof(struct device_path, path) + path_len;
+ to_utf16(devicep->path, path);
+ tilt_slashes(devicep->path);
+ size += devicep->length;
+
+ /* end of path */
+ devicep = (struct device_path *)(buf + size);
+ devicep->type = END_DEVICE_PATH_TYPE;
+ devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ devicep->length = offsetof(struct device_path, path);
+ size += devicep->length;
+
+ xsprintf(boot_id, "Boot%04X", id);
+ return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
+}
+
+int efi_remove_boot_option(uint16_t id) {
+ char boot_id[9];
+
+ xsprintf(boot_id, "Boot%04X", id);
+ return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
}
int efi_get_boot_order(uint16_t **order) {
- void *buf;
+ _cleanup_free_ void *buf = NULL;
size_t l;
int r;
@@ -305,21 +525,22 @@ int efi_get_boot_order(uint16_t **order) {
if (r < 0)
return r;
- if (l <= 0) {
- free(buf);
+ if (l <= 0)
return -ENOENT;
- }
- if ((l % sizeof(uint16_t) > 0) ||
- (l / sizeof(uint16_t) > INT_MAX)) {
- free(buf);
+ if (l % sizeof(uint16_t) > 0 ||
+ l / sizeof(uint16_t) > INT_MAX)
return -EINVAL;
- }
*order = buf;
+ buf = NULL;
return (int) (l / sizeof(uint16_t));
}
+int efi_set_boot_order(uint16_t *order, size_t n) {
+ return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
+}
+
static int boot_id_hex(const char s[4]) {
int i;
int id = 0;
@@ -344,8 +565,9 @@ static int cmp_uint16(const void *_a, const void *_b) {
int efi_get_boot_options(uint16_t **options) {
_cleanup_closedir_ DIR *dir = NULL;
struct dirent *de;
- uint16_t *list = NULL;
- int count = 0, r;
+ _cleanup_free_ uint16_t *list = NULL;
+ size_t alloc = 0;
+ int count = 0;
assert(options);
@@ -353,9 +575,8 @@ int efi_get_boot_options(uint16_t **options) {
if (!dir)
return -errno;
- FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
+ FOREACH_DIRENT(de, dir, return -errno) {
int id;
- uint16_t *t;
if (strncmp(de->d_name, "Boot", 4) != 0)
continue;
@@ -370,24 +591,17 @@ int efi_get_boot_options(uint16_t **options) {
if (id < 0)
continue;
- t = realloc(list, (count + 1) * sizeof(uint16_t));
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!GREEDY_REALLOC(list, alloc, count + 1))
+ return -ENOMEM;
- list = t;
- list[count ++] = id;
+ list[count++] = id;
}
qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
*options = list;
+ list = NULL;
return count;
-
-fail:
- free(list);
- return r;
}
static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
@@ -463,3 +677,13 @@ int efi_loader_get_device_part_uuid(sd_id128_t *u) {
}
#endif
+
+char *efi_tilt_backslashes(char *s) {
+ char *p;
+
+ for (p = s; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+
+ return s;
+}
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index 7921bedc9f..e953a12737 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -21,8 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <inttypes.h>
#include <stdbool.h>
#include "sd-id128.h"
@@ -30,17 +28,103 @@
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
#define EFI_VENDOR_GLOBAL SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c)
+#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
+
+#ifdef ENABLE_EFI
bool is_efi_boot(void);
-int is_efi_secure_boot(void);
-int is_efi_secure_boot_setup_mode(void);
+bool is_efi_secure_boot(void);
+bool is_efi_secure_boot_setup_mode(void);
+int efi_reboot_to_firmware_supported(void);
+int efi_get_reboot_to_firmware(void);
+int efi_set_reboot_to_firmware(bool value);
int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size);
+int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size);
int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p);
-int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *partuuid, char **path);
+int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active);
+int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, const char *path);
+int efi_remove_boot_option(uint16_t id);
int efi_get_boot_order(uint16_t **order);
+int efi_set_boot_order(uint16_t *order, size_t n);
int efi_get_boot_options(uint16_t **options);
int efi_loader_get_device_part_uuid(sd_id128_t *u);
int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader);
+
+#else
+
+static inline bool is_efi_boot(void) {
+ return false;
+}
+
+static inline bool is_efi_secure_boot(void) {
+ return false;
+}
+
+static inline bool is_efi_secure_boot_setup_mode(void) {
+ return false;
+}
+
+static inline int efi_reboot_to_firmware_supported(void) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_reboot_to_firmware(void) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_set_reboot_to_firmware(bool value) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_set_variable(sd_id128_t vendor, const char *name, const void *value, size_t size) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_boot_option(uint16_t nr, char **title, sd_id128_t *part_uuid, char **path, bool *active) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_add_boot_option(uint16_t id, const char *title, uint32_t part, uint64_t pstart, uint64_t psize, sd_id128_t part_uuid, const char *path) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_remove_boot_option(uint16_t id) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_boot_order(uint16_t **order) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_set_boot_order(uint16_t *order, size_t n) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_get_boot_options(uint16_t **options) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
+ return -EOPNOTSUPP;
+}
+
+static inline int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
+ return -EOPNOTSUPP;
+}
+
+#endif
+
+char *efi_tilt_backslashes(char *s);
diff --git a/src/shared/env-util.c b/src/shared/env-util.c
index 038246d21b..ac7bbdc711 100644
--- a/src/shared/env-util.c
+++ b/src/shared/env-util.c
@@ -20,7 +20,6 @@
***/
#include <limits.h>
-#include <sys/param.h>
#include <unistd.h>
#include "strv.h"
@@ -449,3 +448,147 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha
return e;
}
+
+char *replace_env(const char *format, char **env) {
+ enum {
+ WORD,
+ CURLY,
+ VARIABLE
+ } state = WORD;
+
+ const char *e, *word = format;
+ char *r = NULL, *k;
+
+ assert(format);
+
+ for (e = format; *e; e ++) {
+
+ switch (state) {
+
+ case WORD:
+ if (*e == '$')
+ state = CURLY;
+ break;
+
+ case CURLY:
+ if (*e == '{') {
+ k = strnappend(r, word, e-word-1);
+ if (!k)
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e-1;
+ state = VARIABLE;
+
+ } else if (*e == '$') {
+ k = strnappend(r, word, e-word);
+ if (!k)
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e+1;
+ state = WORD;
+ } else
+ state = WORD;
+ break;
+
+ case VARIABLE:
+ if (*e == '}') {
+ const char *t;
+
+ t = strempty(strv_env_get_n(env, word+2, e-word-2));
+
+ k = strappend(r, t);
+ if (!k)
+ goto fail;
+
+ free(r);
+ r = k;
+
+ word = e+1;
+ state = WORD;
+ }
+ break;
+ }
+ }
+
+ k = strnappend(r, word, e-word);
+ if (!k)
+ goto fail;
+
+ free(r);
+ return k;
+
+fail:
+ free(r);
+ return NULL;
+}
+
+char **replace_env_argv(char **argv, char **env) {
+ char **ret, **i;
+ unsigned k = 0, l = 0;
+
+ l = strv_length(argv);
+
+ ret = new(char*, l+1);
+ if (!ret)
+ return NULL;
+
+ STRV_FOREACH(i, argv) {
+
+ /* If $FOO appears as single word, replace it by the split up variable */
+ if ((*i)[0] == '$' && (*i)[1] != '{') {
+ char *e;
+ char **w, **m = NULL;
+ unsigned q;
+
+ e = strv_env_get(env, *i+1);
+ if (e) {
+ int r;
+
+ r = strv_split_quoted(&m, e, UNQUOTE_RELAX);
+ if (r < 0) {
+ ret[k] = NULL;
+ strv_free(ret);
+ return NULL;
+ }
+ } else
+ m = NULL;
+
+ q = strv_length(m);
+ l = l + q - 1;
+
+ w = realloc(ret, sizeof(char*) * (l+1));
+ if (!w) {
+ ret[k] = NULL;
+ strv_free(ret);
+ strv_free(m);
+ return NULL;
+ }
+
+ ret = w;
+ if (m) {
+ memcpy(ret + k, m, q * sizeof(char*));
+ free(m);
+ }
+
+ k += q;
+ continue;
+ }
+
+ /* If ${FOO} appears as part of a word, replace it by the variable as-is */
+ ret[k] = replace_env(*i, env);
+ if (!ret[k]) {
+ strv_free(ret);
+ return NULL;
+ }
+ k++;
+ }
+
+ ret[k] = NULL;
+ return ret;
+}
diff --git a/src/shared/env-util.h b/src/shared/env-util.h
index 618441a655..803aa61cad 100644
--- a/src/shared/env-util.h
+++ b/src/shared/env-util.h
@@ -22,7 +22,6 @@
***/
#include <stdbool.h>
-#include <sys/types.h>
#include "macro.h"
@@ -30,6 +29,9 @@ bool env_name_is_valid(const char *e);
bool env_value_is_valid(const char *e);
bool env_assignment_is_valid(const char *e);
+char *replace_env(const char *format, char **env);
+char **replace_env_argv(char **argv, char **env);
+
bool strv_env_is_valid(char **e);
#define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
diff --git a/src/shared/errno-list.c b/src/shared/errno-list.c
index c63296f292..34d1331486 100644
--- a/src/shared/errno-list.c
+++ b/src/shared/errno-list.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
#include <string.h>
#include "util.h"
diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c
index 5c73b4d3c0..c09efdd2cb 100644
--- a/src/shared/exit-status.c
+++ b/src/shared/exit-status.c
@@ -20,7 +20,6 @@
***/
#include <stdlib.h>
-#include <sys/wait.h>
#include "exit-status.h"
#include "set.h"
@@ -167,7 +166,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
return "NOPERMISSION";
case EXIT_NOTINSTALLED:
- return "NOTINSSTALLED";
+ return "NOTINSTALLED";
case EXIT_NOTCONFIGURED:
return "NOTCONFIGURED";
@@ -226,3 +225,17 @@ bool exit_status_set_is_empty(ExitStatusSet *x) {
return set_isempty(x->status) && set_isempty(x->signal);
}
+
+bool exit_status_set_test(ExitStatusSet *x, int code, int status) {
+
+ if (exit_status_set_is_empty(x))
+ return false;
+
+ if (code == CLD_EXITED && set_contains(x->status, INT_TO_PTR(status)))
+ return true;
+
+ if (IN_SET(code, CLD_KILLED, CLD_DUMPED) && set_contains(x->signal, INT_TO_PTR(status)))
+ return true;
+
+ return false;
+}
diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h
index 1d774f25dc..7259cd1d18 100644
--- a/src/shared/exit-status.h
+++ b/src/shared/exit-status.h
@@ -100,3 +100,4 @@ bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status);
void exit_status_set_free(ExitStatusSet *x);
bool exit_status_set_is_empty(ExitStatusSet *x);
+bool exit_status_set_test(ExitStatusSet *x, int code, int status);
diff --git a/src/shared/fdset.c b/src/shared/fdset.c
index 9e35ce5cec..6101b628ec 100644
--- a/src/shared/fdset.c
+++ b/src/shared/fdset.c
@@ -22,7 +22,6 @@
#include <errno.h>
#include <dirent.h>
#include <fcntl.h>
-#include <unistd.h>
#include "set.h"
#include "util.h"
@@ -33,7 +32,7 @@
#define MAKE_SET(s) ((Set*) s)
#define MAKE_FDSET(s) ((FDSet*) s)
-/* Make sure we can distuingish fd 0 and NULL */
+/* Make sure we can distinguish fd 0 and NULL */
#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
diff --git a/src/shared/fdset.h b/src/shared/fdset.h
index c3c5e52286..340438d7c4 100644
--- a/src/shared/fdset.h
+++ b/src/shared/fdset.h
@@ -22,7 +22,6 @@
***/
#include "set.h"
-#include "util.h"
typedef struct FDSet FDSet;
diff --git a/src/shared/fileio-label.c b/src/shared/fileio-label.c
index 5fd69e0580..bec988ca78 100644
--- a/src/shared/fileio-label.c
+++ b/src/shared/fileio-label.c
@@ -19,13 +19,9 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
#include "util.h"
#include "selinux-util.h"
-#include "label.h"
#include "fileio-label.h"
int write_string_file_atomic_label(const char *fn, const char *line) {
diff --git a/src/shared/formats-util.h b/src/shared/formats-util.h
new file mode 100644
index 0000000000..ce516b117d
--- /dev/null
+++ b/src/shared/formats-util.h
@@ -0,0 +1,63 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Ronny Chevalier
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+
+#if SIZEOF_PID_T == 4
+# define PID_PRI PRIi32
+#elif SIZEOF_PID_T == 2
+# define PID_PRI PRIi16
+#else
+# error Unknown pid_t size
+#endif
+#define PID_FMT "%" PID_PRI
+
+#if SIZEOF_UID_T == 4
+# define UID_FMT "%" PRIu32
+#elif SIZEOF_UID_T == 2
+# define UID_FMT "%" PRIu16
+#else
+# error Unknown uid_t size
+#endif
+
+#if SIZEOF_GID_T == 4
+# define GID_FMT "%" PRIu32
+#elif SIZEOF_GID_T == 2
+# define GID_FMT "%" PRIu16
+#else
+# error Unknown gid_t size
+#endif
+
+#if SIZEOF_TIME_T == 8
+# define PRI_TIME PRIi64
+#elif SIZEOF_TIME_T == 4
+# define PRI_TIME PRIu32
+#else
+# error Unknown time_t size
+#endif
+
+#if SIZEOF_RLIM_T == 8
+# define RLIM_FMT "%" PRIu64
+#elif SIZEOF_RLIM_T == 4
+# define RLIM_FMT "%" PRIu32
+#else
+# error Unknown rlim_t size
+#endif
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index cf317e17bd..e231a0ff80 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -125,6 +125,36 @@ answer:
return !!n;
}
+int fstab_extract_values(const char *opts, const char *name, char ***values) {
+ _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
+ char **s;
+
+ assert(opts);
+ assert(name);
+ assert(values);
+
+ optsv = strv_split(opts, ",");
+ if (!optsv)
+ return -ENOMEM;
+
+ STRV_FOREACH(s, optsv) {
+ char *arg;
+ int r;
+
+ arg = startswith(*s, name);
+ if (!arg || *arg != '=')
+ continue;
+ r = strv_extend(&res, arg + 1);
+ if (r < 0)
+ return r;
+ }
+
+ *values = res;
+ res = NULL;
+
+ return !!*values;
+}
+
int fstab_find_pri(const char *options, int *ret) {
_cleanup_free_ char *opt = NULL;
int r;
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 9f6b32eaf4..387c562a96 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -28,6 +28,8 @@
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered);
+int fstab_extract_values(const char *opts, const char *name, char ***values);
+
static inline bool fstab_test_option(const char *opts, const char *names) {
return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
}
diff --git a/src/shared/fw-util.c b/src/shared/fw-util.c
index ceb1ae508c..6b3599d90d 100644
--- a/src/shared/fw-util.c
+++ b/src/shared/fw-util.c
@@ -91,10 +91,10 @@ int fw_add_masquerade(
int r;
if (af != AF_INET)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (protocol != 0 && protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
h = iptc_init("nat");
if (!h)
@@ -175,10 +175,10 @@ int fw_add_local_dnat(
assert(add || !previous_remote);
if (af != AF_INET)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
- return -ENOTSUP;
+ return -EOPNOTSUPP;
if (local_port <= 0)
return -EINVAL;
diff --git a/src/shared/fw-util.h b/src/shared/fw-util.h
index 698cc43daa..93152e3978 100644
--- a/src/shared/fw-util.h
+++ b/src/shared/fw-util.h
@@ -60,7 +60,7 @@ static inline int fw_add_masquerade(
const char *out_interface,
const union in_addr_union *destination,
unsigned destination_prefixlen) {
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
static inline int fw_add_local_dnat(
@@ -76,7 +76,7 @@ static inline int fw_add_local_dnat(
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote) {
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
#endif
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 7f16d5cbef..807569a1b8 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <unistd.h>
#include "util.h"
@@ -29,17 +28,63 @@
#include "generator.h"
#include "path-util.h"
#include "fstab-util.h"
+#include "fileio.h"
#include "dropin.h"
+static int write_fsck_sysroot_service(const char *dir, const char *what) {
+ const char *unit;
+ _cleanup_free_ char *device = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ unit = strjoina(dir, "/systemd-fsck-root.service");
+ log_debug("Creating %s", unit);
+
+ r = unit_name_from_path(what, ".device", &device);
+ if (r < 0)
+ return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
+
+ f = fopen(unit, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
+
+ fprintf(f,
+ "# Automatically generated by %1$s\n\n"
+ "[Unit]\n"
+ "Documentation=man:systemd-fsck-root.service(8)\n"
+ "Description=File System Check on %2$s\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%3$s\n"
+ "After=%3$s\n"
+ "Before=shutdown.target\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart=" SYSTEMD_FSCK_PATH " %2$s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ what,
+ device);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit);
+
+ return 0;
+}
+
int generator_write_fsck_deps(
FILE *f,
- const char *dest,
+ const char *dir,
const char *what,
const char *where,
const char *fstype) {
+ int r;
+
assert(f);
- assert(dest);
+ assert(dir);
assert(what);
assert(where);
@@ -49,7 +94,6 @@ int generator_write_fsck_deps(
}
if (!isempty(fstype) && !streq(fstype, "auto")) {
- int r;
r = fsck_exists(fstype);
if (r == -ENOENT) {
/* treat missing check as essentially OK */
@@ -59,34 +103,48 @@ int generator_write_fsck_deps(
return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype);
}
- if (streq(where, "/")) {
+ if (path_equal(where, "/")) {
char *lnk;
- lnk = strjoina(dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
+ lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
mkdir_parents(lnk, 0755);
if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
} else {
- _cleanup_free_ char *fsck = NULL;
+ _cleanup_free_ char *_fsck = NULL;
+ const char *fsck;
+
+ if (in_initrd() && path_equal(where, "/sysroot")) {
+ r = write_fsck_sysroot_service(dir, what);
+ if (r < 0)
+ return r;
+
+ fsck = "systemd-fsck-root.service";
+ } else {
+ r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create fsck service name: %m");
- fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
- if (!fsck)
- return log_oom();
+ fsck = _fsck;
+ }
fprintf(f,
- "RequiresOverridable=%s\n"
- "After=%s\n",
- fsck,
+ "RequiresOverridable=%1$s\n"
+ "After=%1$s\n",
fsck);
}
return 0;
}
-int generator_write_timeouts(const char *dir, const char *what, const char *where,
- const char *opts, char **filtered) {
+int generator_write_timeouts(
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *opts,
+ char **filtered) {
/* Allow configuration how long we wait for a device that
* backs a mount point to show up. This is useful to support
@@ -104,8 +162,7 @@ int generator_write_timeouts(const char *dir, const char *what, const char *wher
r = parse_sec(timeout, &u);
if (r < 0) {
- log_warning("Failed to parse timeout for %s, ignoring: %s",
- where, timeout);
+ log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
return 0;
}
@@ -113,9 +170,9 @@ int generator_write_timeouts(const char *dir, const char *what, const char *wher
if (!node)
return log_oom();
- unit = unit_name_from_path(node, ".device");
- if (!unit)
- return log_oom();
+ r = unit_name_from_path(node, ".device", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path: %m");
return write_drop_in_format(dir, unit, 50, "device-timeout",
"# Automatically generated by %s\n\n"
diff --git a/src/shared/generator.h b/src/shared/generator.h
index 64bd28f596..6c3f38abba 100644
--- a/src/shared/generator.h
+++ b/src/shared/generator.h
@@ -23,7 +23,16 @@
#include <stdio.h>
-int generator_write_fsck_deps(FILE *f, const char *dest, const char *what, const char *where, const char *type);
-
-int generator_write_timeouts(const char *dir, const char *what, const char *where,
- const char *opts, char **filtered);
+int generator_write_fsck_deps(
+ FILE *f,
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *type);
+
+int generator_write_timeouts(
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *opts,
+ char **filtered);
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index e63ba4bb5a..20d599d04b 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -20,9 +20,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
-#include <string.h>
#include <errno.h>
#include "util.h"
@@ -31,8 +29,12 @@
#include "macro.h"
#include "siphash24.h"
#include "strv.h"
-#include "list.h"
#include "mempool.h"
+#include "random-util.h"
+
+#ifdef ENABLE_DEBUG_HASHMAP
+#include "list.h"
+#endif
/*
* Implementation of hashmaps.
@@ -130,10 +132,10 @@ struct swap_entries {
/* Distance from Initial Bucket */
typedef uint8_t dib_raw_t;
-#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */
-#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */
-#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */
-#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
+#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */
+#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */
+#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */
+#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
#define DIB_FREE UINT_MAX
@@ -771,7 +773,7 @@ static void reset_direct_storage(HashmapBase *h) {
memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
}
-static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
+static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *h;
const struct hashmap_type_info *hi = &hashmap_type_info[type];
bool use_pool;
@@ -810,19 +812,19 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
}
Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
+ return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
+ return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
+ return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
- enum HashmapType type HASHMAP_DEBUG_PARAMS) {
+ enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *q;
assert(h);
@@ -830,7 +832,7 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops
if (*h)
return 0;
- q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
+ q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
if (!q)
return -ENOMEM;
@@ -839,15 +841,15 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops
}
int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
+ return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
}
int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
+ return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
}
int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
- return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
+ return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
static void hashmap_free_no_clear(HashmapBase *h) {
@@ -864,38 +866,41 @@ static void hashmap_free_no_clear(HashmapBase *h) {
free(h);
}
-void internal_hashmap_free(HashmapBase *h) {
+HashmapBase *internal_hashmap_free(HashmapBase *h) {
/* Free the hashmap, but nothing in it */
- if (!h)
- return;
+ if (h) {
+ internal_hashmap_clear(h);
+ hashmap_free_no_clear(h);
+ }
- internal_hashmap_clear(h);
- hashmap_free_no_clear(h);
+ return NULL;
}
-void internal_hashmap_free_free(HashmapBase *h) {
+HashmapBase *internal_hashmap_free_free(HashmapBase *h) {
/* Free the hashmap and all data objects in it, but not the
* keys */
- if (!h)
- return;
+ if (h) {
+ internal_hashmap_clear_free(h);
+ hashmap_free_no_clear(h);
+ }
- internal_hashmap_clear_free(h);
- hashmap_free_no_clear(h);
+ return NULL;
}
-void hashmap_free_free_free(Hashmap *h) {
+Hashmap *hashmap_free_free_free(Hashmap *h) {
/* Free the hashmap and all data and key objects in it */
- if (!h)
- return;
+ if (h) {
+ hashmap_clear_free_free(h);
+ hashmap_free_no_clear(HASHMAP_BASE(h));
+ }
- hashmap_clear_free_free(h);
- hashmap_free_no_clear(HASHMAP_BASE(h));
+ return NULL;
}
void internal_hashmap_clear(HashmapBase *h) {
@@ -990,7 +995,6 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
if (dib < distance) {
/* Found a wealthier entry. Go Robin Hood! */
-
bucket_set_dib(h, idx, distance);
/* swap the entries */
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 894f67939e..a03ee5812a 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -144,25 +144,25 @@ OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HA
#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
-void internal_hashmap_free(HashmapBase *h);
-static inline void hashmap_free(Hashmap *h) {
- internal_hashmap_free(HASHMAP_BASE(h));
+HashmapBase *internal_hashmap_free(HashmapBase *h);
+static inline Hashmap *hashmap_free(Hashmap *h) {
+ return (void*)internal_hashmap_free(HASHMAP_BASE(h));
}
-static inline void ordered_hashmap_free(OrderedHashmap *h) {
- internal_hashmap_free(HASHMAP_BASE(h));
+static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
+ return (void*)internal_hashmap_free(HASHMAP_BASE(h));
}
-void internal_hashmap_free_free(HashmapBase *h);
-static inline void hashmap_free_free(Hashmap *h) {
- internal_hashmap_free_free(HASHMAP_BASE(h));
+HashmapBase *internal_hashmap_free_free(HashmapBase *h);
+static inline Hashmap *hashmap_free_free(Hashmap *h) {
+ return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
}
-static inline void ordered_hashmap_free_free(OrderedHashmap *h) {
- internal_hashmap_free_free(HASHMAP_BASE(h));
+static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
+ return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
}
-void hashmap_free_free_free(Hashmap *h);
-static inline void ordered_hashmap_free_free_free(OrderedHashmap *h) {
- hashmap_free_free_free(PLAIN_HASHMAP(h));
+Hashmap *hashmap_free_free_free(Hashmap *h);
+static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
+ return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h));
}
HashmapBase *internal_hashmap_copy(HashmapBase *h);
diff --git a/src/shared/hostname-util.c b/src/shared/hostname-util.c
new file mode 100644
index 0000000000..e336f269fa
--- /dev/null
+++ b/src/shared/hostname-util.c
@@ -0,0 +1,193 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/utsname.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "hostname-util.h"
+
+bool hostname_is_set(void) {
+ struct utsname u;
+
+ assert_se(uname(&u) >= 0);
+
+ if (isempty(u.nodename))
+ return false;
+
+ /* This is the built-in kernel default host name */
+ if (streq(u.nodename, "(none)"))
+ return false;
+
+ return true;
+}
+
+char* gethostname_malloc(void) {
+ struct utsname u;
+
+ assert_se(uname(&u) >= 0);
+
+ if (isempty(u.nodename) || streq(u.nodename, "(none)"))
+ return strdup(u.sysname);
+
+ return strdup(u.nodename);
+}
+
+static bool hostname_valid_char(char c) {
+ return
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '-' ||
+ c == '_' ||
+ c == '.';
+}
+
+bool hostname_is_valid(const char *s) {
+ const char *p;
+ bool dot;
+
+ if (isempty(s))
+ return false;
+
+ /* Doesn't accept empty hostnames, hostnames with trailing or
+ * leading dots, and hostnames with multiple dots in a
+ * sequence. Also ensures that the length stays below
+ * HOST_NAME_MAX. */
+
+ for (p = s, dot = true; *p; p++) {
+ if (*p == '.') {
+ if (dot)
+ return false;
+
+ dot = true;
+ } else {
+ if (!hostname_valid_char(*p))
+ return false;
+
+ dot = false;
+ }
+ }
+
+ if (dot)
+ return false;
+
+ if (p-s > HOST_NAME_MAX)
+ return false;
+
+ return true;
+}
+
+char* hostname_cleanup(char *s, bool lowercase) {
+ char *p, *d;
+ bool dot;
+
+ assert(s);
+
+ for (p = s, d = s, dot = true; *p; p++) {
+ if (*p == '.') {
+ if (dot)
+ continue;
+
+ *(d++) = '.';
+ dot = true;
+ } else if (hostname_valid_char(*p)) {
+ *(d++) = lowercase ? tolower(*p) : *p;
+ dot = false;
+ }
+
+ }
+
+ if (dot && d > s)
+ d[-1] = 0;
+ else
+ *d = 0;
+
+ strshorten(s, HOST_NAME_MAX);
+
+ return s;
+}
+
+bool is_localhost(const char *hostname) {
+ assert(hostname);
+
+ /* This tries to identify local host and domain names
+ * described in RFC6761 plus the redhatism of .localdomain */
+
+ return streq(hostname, "localhost") ||
+ streq(hostname, "localhost.") ||
+ streq(hostname, "localdomain.") ||
+ streq(hostname, "localdomain") ||
+ endswith(hostname, ".localhost") ||
+ endswith(hostname, ".localhost.") ||
+ endswith(hostname, ".localdomain") ||
+ endswith(hostname, ".localdomain.");
+}
+
+int sethostname_idempotent(const char *s) {
+ char buf[HOST_NAME_MAX + 1] = {};
+
+ assert(s);
+
+ if (gethostname(buf, sizeof(buf)) < 0)
+ return -errno;
+
+ if (streq(buf, s))
+ return 0;
+
+ if (sethostname(s, strlen(s)) < 0)
+ return -errno;
+
+ return 1;
+}
+
+int read_hostname_config(const char *path, char **hostname) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char l[LINE_MAX];
+ char *name = NULL;
+
+ assert(path);
+ assert(hostname);
+
+ f = fopen(path, "re");
+ if (!f)
+ return -errno;
+
+ /* may have comments, ignore them */
+ FOREACH_LINE(l, f, return -errno) {
+ truncate_nl(l);
+ if (l[0] != '\0' && l[0] != '#') {
+ /* found line with value */
+ name = hostname_cleanup(l, false);
+ name = strdup(name);
+ if (!name)
+ return -ENOMEM;
+ break;
+ }
+ }
+
+ if (!name)
+ /* no non-empty line found */
+ return -ENOENT;
+
+ *hostname = name;
+ return 0;
+}
diff --git a/src/shared/hostname-util.h b/src/shared/hostname-util.h
new file mode 100644
index 0000000000..0c4763cf5a
--- /dev/null
+++ b/src/shared/hostname-util.h
@@ -0,0 +1,39 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "macro.h"
+
+bool hostname_is_set(void);
+
+char* gethostname_malloc(void);
+
+bool hostname_is_valid(const char *s) _pure_;
+char* hostname_cleanup(char *s, bool lowercase);
+
+bool is_localhost(const char *hostname);
+
+int sethostname_idempotent(const char *s);
+
+int read_hostname_config(const char *path, char **hostname);
diff --git a/src/shared/import-util.c b/src/shared/import-util.c
index 660d92ac5d..001a8a37e8 100644
--- a/src/shared/import-util.c
+++ b/src/shared/import-util.c
@@ -150,6 +150,27 @@ int raw_strip_suffixes(const char *p, char **ret) {
return 0;
}
+bool dkr_digest_is_valid(const char *digest) {
+ /* 7 chars for prefix, 64 chars for the digest itself */
+ if (strlen(digest) != 71)
+ return false;
+
+ return startswith(digest, "sha256:") && in_charset(digest + 7, "0123456789abcdef");
+}
+
+bool dkr_ref_is_valid(const char *ref) {
+ const char *colon;
+
+ if (isempty(ref))
+ return false;
+
+ colon = strchr(ref, ':');
+ if (!colon)
+ return filename_is_valid(ref);
+
+ return dkr_digest_is_valid(ref);
+}
+
bool dkr_name_is_valid(const char *name) {
const char *slash, *p;
diff --git a/src/shared/import-util.h b/src/shared/import-util.h
index ff155b0ff2..7bf7d4ca40 100644
--- a/src/shared/import-util.h
+++ b/src/shared/import-util.h
@@ -44,4 +44,6 @@ int raw_strip_suffixes(const char *name, char **ret);
bool dkr_name_is_valid(const char *name);
bool dkr_id_is_valid(const char *id);
+bool dkr_ref_is_valid(const char *ref);
+bool dkr_digest_is_valid(const char *digest);
#define dkr_tag_is_valid(tag) filename_is_valid(tag)
diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c
index d853f17772..cbe984d2fb 100644
--- a/src/shared/install-printf.c
+++ b/src/shared/install-printf.c
@@ -19,44 +19,32 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
#include "specifier.h"
#include "unit-name.h"
#include "util.h"
#include "install-printf.h"
+#include "formats-util.h"
static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
- InstallInfo *i = userdata;
- char *n;
+ UnitFileInstallInfo *i = userdata;
assert(i);
- n = unit_name_to_prefix_and_instance(i->name);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return unit_name_to_prefix_and_instance(i->name, ret);
}
static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
- InstallInfo *i = userdata;
- char *n;
+ UnitFileInstallInfo *i = userdata;
assert(i);
- n = unit_name_to_prefix(i->name);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
+ return unit_name_to_prefix(i->name, ret);
}
static int specifier_instance(char specifier, void *data, void *userdata, char **ret) {
- InstallInfo *i = userdata;
+ UnitFileInstallInfo *i = userdata;
char *instance;
int r;
@@ -77,7 +65,7 @@ static int specifier_instance(char specifier, void *data, void *userdata, char *
}
static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
- InstallInfo *i = userdata;
+ UnitFileInstallInfo *i = userdata;
const char *username;
_cleanup_free_ char *tmp = NULL;
char *printed = NULL;
@@ -114,7 +102,7 @@ static int specifier_user_name(char specifier, void *data, void *userdata, char
}
-int install_full_printf(InstallInfo *i, const char *format, char **ret) {
+int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) {
/* This is similar to unit_full_printf() but does not support
* anything path-related.
diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h
index 6ffa488b1b..6550337824 100644
--- a/src/shared/install-printf.h
+++ b/src/shared/install-printf.h
@@ -22,4 +22,5 @@
#pragma once
#include "install.h"
-int install_full_printf(InstallInfo *i, const char *format, char **ret);
+
+int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret);
diff --git a/src/shared/install.c b/src/shared/install.c
index 65f1c245c6..6172c42d69 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -36,7 +36,6 @@
#include "install.h"
#include "conf-parser.h"
#include "conf-files.h"
-#include "specifier.h"
#include "install-printf.h"
#include "special.h"
@@ -113,51 +112,6 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d
return 0;
}
-static int add_file_change(
- UnitFileChange **changes,
- unsigned *n_changes,
- UnitFileChangeType type,
- const char *path,
- const char *source) {
-
- UnitFileChange *c;
- unsigned i;
-
- assert(path);
- assert(!changes == !n_changes);
-
- if (!changes)
- return 0;
-
- c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
- if (!c)
- return -ENOMEM;
-
- *changes = c;
- i = *n_changes;
-
- c[i].type = type;
- c[i].path = strdup(path);
- if (!c[i].path)
- return -ENOMEM;
-
- path_kill_slashes(c[i].path);
-
- if (source) {
- c[i].source = strdup(source);
- if (!c[i].source) {
- free(c[i].path);
- return -ENOMEM;
- }
-
- path_kill_slashes(c[i].path);
- } else
- c[i].source = NULL;
-
- *n_changes = i+1;
- return 0;
-}
-
static int mark_symlink_for_removal(
Set **remove_symlinks_to,
const char *p) {
@@ -259,10 +213,10 @@ static int remove_marked_symlinks_fd(
int q;
bool found;
- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
+ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
- if (unit_name_is_instance(de->d_name) &&
+ if (unit_name_is_valid(de->d_name, UNIT_NAME_INSTANCE) &&
instance_whitelist &&
!strv_contains(instance_whitelist, de->d_name)) {
@@ -273,9 +227,9 @@ static int remove_marked_symlinks_fd(
* the template of it might be
* listed. */
- w = unit_name_template(de->d_name);
- if (!w)
- return -ENOMEM;
+ r = unit_name_template(de->d_name, &w);
+ if (r < 0)
+ return r;
if (!strv_contains(instance_whitelist, w))
continue;
@@ -310,7 +264,7 @@ static int remove_marked_symlinks_fd(
path_kill_slashes(p);
rmdir_parents(p, config_path);
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
if (!set_get(remove_symlinks_to, p)) {
@@ -515,7 +469,7 @@ static int find_symlinks_in_scope(
UnitFileState *state) {
int r;
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL;
bool same_name_link_runtime = false, same_name_link = false;
assert(scope >= 0);
@@ -523,11 +477,11 @@ static int find_symlinks_in_scope(
assert(name);
/* First look in runtime config path */
- r = get_config_path(scope, true, root_dir, &path);
+ r = get_config_path(scope, true, root_dir, &normal_path);
if (r < 0)
return r;
- r = find_symlinks(name, path, &same_name_link_runtime);
+ r = find_symlinks(name, normal_path, &same_name_link_runtime);
if (r < 0)
return r;
else if (r > 0) {
@@ -536,11 +490,11 @@ static int find_symlinks_in_scope(
}
/* Then look in the normal config path */
- r = get_config_path(scope, false, root_dir, &path);
+ r = get_config_path(scope, false, root_dir, &runtime_path);
if (r < 0)
return r;
- r = find_symlinks(name, path, &same_name_link);
+ r = find_symlinks(name, runtime_path, &same_name_link);
if (r < 0)
return r;
else if (r > 0) {
@@ -584,7 +538,7 @@ int unit_file_mask(
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
+ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
if (r == 0)
r = -EINVAL;
continue;
@@ -597,7 +551,7 @@ int unit_file_mask(
}
if (symlink("/dev/null", path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
continue;
}
@@ -608,8 +562,8 @@ int unit_file_mask(
if (force) {
if (symlink_atomic("/dev/null", path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
continue;
}
}
@@ -647,7 +601,7 @@ int unit_file_unmask(
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
- if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
+ if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
if (r == 0)
r = -EINVAL;
continue;
@@ -665,7 +619,7 @@ int unit_file_unmask(
q = -errno;
else {
q = mark_symlink_for_removal(&remove_symlinks_to, path);
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
}
}
@@ -718,7 +672,7 @@ int unit_file_link(
fn = basename(*i);
if (!path_is_absolute(*i) ||
- !unit_name_is_valid(fn, TEMPLATE_VALID)) {
+ !unit_name_is_valid(fn, UNIT_NAME_ANY)) {
if (r == 0)
r = -EINVAL;
continue;
@@ -747,7 +701,7 @@ int unit_file_link(
return -ENOMEM;
if (symlink(*i, path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
continue;
}
@@ -766,8 +720,8 @@ int unit_file_link(
if (force) {
if (symlink_atomic(*i, path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
continue;
}
}
@@ -794,6 +748,51 @@ void unit_file_list_free(Hashmap *h) {
hashmap_free(h);
}
+int unit_file_changes_add(
+ UnitFileChange **changes,
+ unsigned *n_changes,
+ UnitFileChangeType type,
+ const char *path,
+ const char *source) {
+
+ UnitFileChange *c;
+ unsigned i;
+
+ assert(path);
+ assert(!changes == !n_changes);
+
+ if (!changes)
+ return 0;
+
+ c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
+ if (!c)
+ return -ENOMEM;
+
+ *changes = c;
+ i = *n_changes;
+
+ c[i].type = type;
+ c[i].path = strdup(path);
+ if (!c[i].path)
+ return -ENOMEM;
+
+ path_kill_slashes(c[i].path);
+
+ if (source) {
+ c[i].source = strdup(source);
+ if (!c[i].source) {
+ free(c[i].path);
+ return -ENOMEM;
+ }
+
+ path_kill_slashes(c[i].path);
+ } else
+ c[i].source = NULL;
+
+ *n_changes = i+1;
+ return 0;
+}
+
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
unsigned i;
@@ -810,7 +809,7 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
free(changes);
}
-static void install_info_free(InstallInfo *i) {
+static void install_info_free(UnitFileInstallInfo *i) {
assert(i);
free(i->name);
@@ -824,7 +823,7 @@ static void install_info_free(InstallInfo *i) {
}
static void install_info_hashmap_free(OrderedHashmap *m) {
- InstallInfo *i;
+ UnitFileInstallInfo *i;
if (!m)
return;
@@ -848,7 +847,7 @@ static int install_info_add(
InstallContext *c,
const char *name,
const char *path) {
- InstallInfo *i = NULL;
+ UnitFileInstallInfo *i = NULL;
int r;
assert(c);
@@ -857,7 +856,7 @@ static int install_info_add(
if (!name)
name = basename(path);
- if (!unit_name_is_valid(name, TEMPLATE_VALID))
+ if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
if (ordered_hashmap_get(c->have_installed, name) ||
@@ -868,7 +867,7 @@ static int install_info_add(
if (r < 0)
return r;
- i = new0(InstallInfo, 1);
+ i = new0(UnitFileInstallInfo, 1);
if (!i)
return -ENOMEM;
@@ -927,7 +926,7 @@ static int config_parse_also(
size_t l;
const char *word, *state;
InstallContext *c = data;
- InstallInfo *i = userdata;
+ UnitFileInstallInfo *i = userdata;
assert(filename);
assert(lvalue);
@@ -968,7 +967,7 @@ static int config_parse_user(
void *data,
void *userdata) {
- InstallInfo *i = data;
+ UnitFileInstallInfo *i = data;
char *printed;
int r;
@@ -998,7 +997,7 @@ static int config_parse_default_instance(
void *data,
void *userdata) {
- InstallInfo *i = data;
+ UnitFileInstallInfo *i = data;
char *printed;
int r;
@@ -1023,7 +1022,7 @@ static int config_parse_default_instance(
static int unit_file_load(
InstallContext *c,
- InstallInfo *info,
+ UnitFileInstallInfo *info,
const char *path,
const char *root_dir,
bool allow_symlink,
@@ -1083,8 +1082,8 @@ static int unit_file_load(
static int unit_file_search(
InstallContext *c,
- InstallInfo *info,
- LookupPaths *paths,
+ UnitFileInstallInfo *info,
+ const LookupPaths *paths,
const char *root_dir,
bool allow_symlink,
bool load,
@@ -1119,7 +1118,7 @@ static int unit_file_search(
return r;
}
- if (unit_name_is_instance(info->name)) {
+ if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
/* Unit file doesn't exist, however instance
* enablement was requested. We will check if it is
@@ -1127,9 +1126,9 @@ static int unit_file_search(
_cleanup_free_ char *template = NULL;
- template = unit_name_template(info->name);
- if (!template)
- return -ENOMEM;
+ r = unit_name_template(info->name, &template);
+ if (r < 0)
+ return r;
STRV_FOREACH(p, paths->unit_path) {
_cleanup_free_ char *path = NULL;
@@ -1153,14 +1152,14 @@ static int unit_file_search(
}
static int unit_file_can_install(
- LookupPaths *paths,
+ const LookupPaths *paths,
const char *root_dir,
const char *name,
bool allow_symlink,
bool *also) {
_cleanup_(install_context_done) InstallContext c = {};
- InstallInfo *i;
+ UnitFileInstallInfo *i;
int r;
assert(paths);
@@ -1199,7 +1198,7 @@ static int create_symlink(
mkdir_parents_label(new_path, 0755);
if (symlink(old_path, new_path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
return 0;
}
@@ -1220,14 +1219,14 @@ static int create_symlink(
if (r < 0)
return r;
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
return 0;
}
static int install_info_symlink_alias(
- InstallInfo *i,
+ UnitFileInstallInfo *i,
const char *config_path,
bool force,
UnitFileChange **changes,
@@ -1259,7 +1258,7 @@ static int install_info_symlink_alias(
}
static int install_info_symlink_wants(
- InstallInfo *i,
+ UnitFileInstallInfo *i,
const char *config_path,
char **list,
const char *suffix,
@@ -1275,7 +1274,7 @@ static int install_info_symlink_wants(
assert(i);
assert(config_path);
- if (unit_name_is_template(i->name)) {
+ if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
/* Don't install any symlink if there's no default
* instance configured */
@@ -1283,9 +1282,9 @@ static int install_info_symlink_wants(
if (!i->default_instance)
return 0;
- buf = unit_name_replace_instance(i->name, i->default_instance);
- if (!buf)
- return -ENOMEM;
+ r = unit_name_replace_instance(i->name, i->default_instance, &buf);
+ if (r < 0)
+ return r;
n = buf;
} else
@@ -1298,7 +1297,7 @@ static int install_info_symlink_wants(
if (q < 0)
return q;
- if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
+ if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
r = -EINVAL;
continue;
}
@@ -1316,8 +1315,8 @@ static int install_info_symlink_wants(
}
static int install_info_symlink_link(
- InstallInfo *i,
- LookupPaths *paths,
+ UnitFileInstallInfo *i,
+ const LookupPaths *paths,
const char *config_path,
const char *root_dir,
bool force,
@@ -1344,8 +1343,8 @@ static int install_info_symlink_link(
}
static int install_info_apply(
- InstallInfo *i,
- LookupPaths *paths,
+ UnitFileInstallInfo *i,
+ const LookupPaths *paths,
const char *config_path,
const char *root_dir,
bool force,
@@ -1377,14 +1376,14 @@ static int install_info_apply(
static int install_context_apply(
InstallContext *c,
- LookupPaths *paths,
+ const LookupPaths *paths,
const char *config_path,
const char *root_dir,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
- InstallInfo *i;
+ UnitFileInstallInfo *i;
int r, q;
assert(c);
@@ -1424,12 +1423,12 @@ static int install_context_apply(
static int install_context_mark_for_removal(
InstallContext *c,
- LookupPaths *paths,
+ const LookupPaths *paths,
Set **remove_symlinks_to,
const char *config_path,
const char *root_dir) {
- InstallInfo *i;
+ UnitFileInstallInfo *i;
int r, q;
assert(c);
@@ -1463,13 +1462,13 @@ static int install_context_mark_for_removal(
} else if (r >= 0)
r += q;
- if (unit_name_is_instance(i->name)) {
+ if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
char *unit_file;
if (i->path) {
unit_file = basename(i->path);
- if (unit_name_is_instance(unit_file))
+ if (unit_name_is_valid(unit_file, UNIT_NAME_INSTANCE))
/* unit file named as instance exists, thus all symlinks
* pointing to it will be removed */
q = mark_symlink_for_removal(remove_symlinks_to, i->name);
@@ -1481,9 +1480,9 @@ static int install_context_mark_for_removal(
/* If i->path is not set, it means that we didn't actually find
* the unit file. But we can still remove symlinks to the
* nonexistent template. */
- unit_file = unit_name_template(i->name);
- if (!unit_file)
- return log_oom();
+ r = unit_name_template(i->name, &unit_file);
+ if (r < 0)
+ return r;
q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
free(unit_file);
@@ -1514,7 +1513,7 @@ int unit_file_add_dependency(
_cleanup_free_ char *config_path = NULL;
char **i;
int r;
- InstallInfo *info;
+ UnitFileInstallInfo *info;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
@@ -1536,7 +1535,7 @@ int unit_file_add_dependency(
if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
log_error("Failed to enable unit: Unit %s is masked", *i);
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
r = install_info_add_auto(&c, *i);
@@ -1614,7 +1613,7 @@ int unit_file_enable(
state = unit_file_get_state(scope, root_dir, *i);
if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
log_error("Failed to enable unit: Unit %s is masked", *i);
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
r = install_info_add_auto(&c, *i);
@@ -1703,7 +1702,7 @@ int unit_file_set_default(
_cleanup_free_ char *config_path = NULL;
char *path;
int r;
- InstallInfo *i = NULL;
+ UnitFileInstallInfo *i = NULL;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
@@ -1785,39 +1784,28 @@ int unit_file_get_default(
return -ENOENT;
}
-UnitFileState unit_file_get_state(
+UnitFileState unit_file_lookup_state(
UnitFileScope scope,
const char *root_dir,
+ const LookupPaths *paths,
const char *name) {
- _cleanup_lookup_paths_free_ LookupPaths paths = {};
UnitFileState state = _UNIT_FILE_STATE_INVALID;
char **i;
_cleanup_free_ char *path = NULL;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
+ int r = 0;
- if (root_dir && scope != UNIT_FILE_SYSTEM)
- return -EINVAL;
+ assert(paths);
- if (!unit_name_is_valid(name, TEMPLATE_VALID))
+ if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, paths.unit_path) {
+ STRV_FOREACH(i, paths->unit_path) {
struct stat st;
char *partial;
bool also = false;
free(path);
- path = NULL;
-
path = path_join(root_dir, *i, name);
if (!path)
return -ENOMEM;
@@ -1836,7 +1824,7 @@ UnitFileState unit_file_get_state(
if (errno != ENOENT)
return r;
- if (!unit_name_is_instance(name))
+ if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE))
continue;
} else {
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
@@ -1846,8 +1834,7 @@ UnitFileState unit_file_get_state(
if (r < 0 && r != -ENOENT)
return r;
else if (r > 0) {
- state = path_startswith(*i, "/run") ?
- UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+ state = path_startswith(*i, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
return state;
}
}
@@ -1858,7 +1845,7 @@ UnitFileState unit_file_get_state(
else if (r > 0)
return state;
- r = unit_file_can_install(&paths, root_dir, partial, true, &also);
+ r = unit_file_can_install(paths, root_dir, partial, true, &also);
if (r < 0 && errno != ENOENT)
return r;
else if (r > 0)
@@ -1873,6 +1860,28 @@ UnitFileState unit_file_get_state(
return r < 0 ? r : state;
}
+UnitFileState unit_file_get_state(
+ UnitFileScope scope,
+ const char *root_dir,
+ const char *name) {
+
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ int r;
+
+ assert(scope >= 0);
+ assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(name);
+
+ if (root_dir && scope != UNIT_FILE_SYSTEM)
+ return -EINVAL;
+
+ r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ if (r < 0)
+ return r;
+
+ return unit_file_lookup_state(scope, root_dir, &paths, name);
+}
+
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
_cleanup_strv_free_ char **files = NULL;
char **p;
@@ -1985,7 +1994,7 @@ int unit_file_preset(
STRV_FOREACH(i, files) {
- if (!unit_name_is_valid(*i, TEMPLATE_VALID))
+ if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
return -EINVAL;
r = unit_file_query_preset(scope, root_dir, *i);
@@ -2081,7 +2090,7 @@ int unit_file_preset_all(
if (hidden_file(de->d_name))
continue;
- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
+ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
dirent_ensure_type(d, de);
@@ -2193,7 +2202,7 @@ int unit_file_get_list(
if (hidden_file(de->d_name))
continue;
- if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
+ if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
if (hashmap_get(h, de->d_name))
diff --git a/src/shared/install.h b/src/shared/install.h
index 357be0f92d..a9d77dd91b 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -21,18 +21,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+typedef enum UnitFileScope UnitFileScope;
+typedef enum UnitFileState UnitFileState;
+typedef enum UnitFilePresetMode UnitFilePresetMode;
+typedef enum UnitFileChangeType UnitFileChangeType;
+typedef struct UnitFileChange UnitFileChange;
+typedef struct UnitFileList UnitFileList;
+typedef struct UnitFileInstallInfo UnitFileInstallInfo;
+
#include "hashmap.h"
#include "unit-name.h"
+#include "path-lookup.h"
-typedef enum UnitFileScope {
+enum UnitFileScope {
UNIT_FILE_SYSTEM,
UNIT_FILE_GLOBAL,
UNIT_FILE_USER,
_UNIT_FILE_SCOPE_MAX,
_UNIT_FILE_SCOPE_INVALID = -1
-} UnitFileScope;
+};
-typedef enum UnitFileState {
+enum UnitFileState {
UNIT_FILE_ENABLED,
UNIT_FILE_ENABLED_RUNTIME,
UNIT_FILE_LINKED,
@@ -45,35 +54,35 @@ typedef enum UnitFileState {
UNIT_FILE_INVALID,
_UNIT_FILE_STATE_MAX,
_UNIT_FILE_STATE_INVALID = -1
-} UnitFileState;
+};
-typedef enum UnitFilePresetMode {
+enum UnitFilePresetMode {
UNIT_FILE_PRESET_FULL,
UNIT_FILE_PRESET_ENABLE_ONLY,
UNIT_FILE_PRESET_DISABLE_ONLY,
_UNIT_FILE_PRESET_MAX,
_UNIT_FILE_PRESET_INVALID = -1
-} UnitFilePresetMode;
+};
-typedef enum UnitFileChangeType {
+enum UnitFileChangeType {
UNIT_FILE_SYMLINK,
UNIT_FILE_UNLINK,
_UNIT_FILE_CHANGE_TYPE_MAX,
_UNIT_FILE_CHANGE_TYPE_INVALID = -1
-} UnitFileChangeType;
+};
-typedef struct UnitFileChange {
+struct UnitFileChange {
UnitFileChangeType type;
char *path;
char *source;
-} UnitFileChange;
+};
-typedef struct UnitFileList {
+struct UnitFileList {
char *path;
UnitFileState state;
-} UnitFileList;
+};
-typedef struct {
+struct UnitFileInstallInfo {
char *name;
char *path;
char *user;
@@ -84,7 +93,7 @@ typedef struct {
char **also;
char *default_instance;
-} InstallInfo;
+};
int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
@@ -98,11 +107,20 @@ int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char
int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name);
int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
-UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename);
+UnitFileState unit_file_lookup_state(
+ UnitFileScope scope,
+ const char *root_dir,
+ const LookupPaths *paths,
+ const char *name);
+UnitFileState unit_file_get_state(
+ UnitFileScope scope,
+ const char *root_dir,
+ const char *filename);
int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
void unit_file_list_free(Hashmap *h);
+int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source);
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
diff --git a/src/shared/json.c b/src/shared/json.c
index bb3d26f0e5..be40a0d203 100644
--- a/src/shared/json.c
+++ b/src/shared/json.c
@@ -21,18 +21,178 @@
#include <sys/types.h>
#include <math.h>
-
#include "macro.h"
-#include "log.h"
-#include "util.h"
#include "utf8.h"
#include "json.h"
-enum {
- STATE_NULL,
- STATE_VALUE,
- STATE_VALUE_POST,
-};
+int json_variant_new(JsonVariant **ret, JsonVariantType type) {
+ JsonVariant *v;
+
+ v = new0(JsonVariant, 1);
+ if (!v)
+ return -ENOMEM;
+ v->type = type;
+ *ret = v;
+ return 0;
+}
+
+static int json_variant_deep_copy(JsonVariant *ret, JsonVariant *variant) {
+ int r;
+
+ assert(ret);
+ assert(variant);
+
+ ret->type = variant->type;
+ ret->size = variant->size;
+
+ if (variant->type == JSON_VARIANT_STRING) {
+ ret->string = memdup(variant->string, variant->size+1);
+ if (!ret->string)
+ return -ENOMEM;
+ } else if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT) {
+ size_t i;
+
+ ret->objects = new0(JsonVariant, variant->size);
+ if (!ret->objects)
+ return -ENOMEM;
+
+ for (i = 0; i < variant->size; ++i) {
+ r = json_variant_deep_copy(&ret->objects[i], &variant->objects[i]);
+ if (r < 0)
+ return r;
+ }
+ } else
+ ret->value = variant->value;
+
+ return 0;
+}
+
+static JsonVariant *json_object_unref(JsonVariant *variant);
+
+static JsonVariant *json_variant_unref_inner(JsonVariant *variant) {
+ if (!variant)
+ return NULL;
+
+ if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT)
+ return json_object_unref(variant);
+ else if (variant->type == JSON_VARIANT_STRING)
+ free(variant->string);
+
+ return NULL;
+}
+
+static JsonVariant *json_raw_unref(JsonVariant *variant, size_t size) {
+ if (!variant)
+ return NULL;
+
+ for (size_t i = 0; i < size; ++i)
+ json_variant_unref_inner(&variant[i]);
+
+ free(variant);
+ return NULL;
+}
+
+static JsonVariant *json_object_unref(JsonVariant *variant) {
+ size_t i;
+
+ assert(variant);
+
+ if (!variant->objects)
+ return NULL;
+
+ for (i = 0; i < variant->size; ++i)
+ json_variant_unref_inner(&variant->objects[i]);
+
+ free(variant->objects);
+ return NULL;
+}
+
+static JsonVariant **json_variant_array_unref(JsonVariant **variant) {
+ size_t i = 0;
+ JsonVariant *p = NULL;
+
+ if (!variant)
+ return NULL;
+
+ while((p = (variant[i++])) != NULL) {
+ if (p->type == JSON_VARIANT_STRING)
+ free(p->string);
+ free(p);
+ }
+
+ free(variant);
+
+ return NULL;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant **, json_variant_array_unref);
+
+JsonVariant *json_variant_unref(JsonVariant *variant) {
+ if (!variant)
+ return NULL;
+
+ if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT)
+ json_object_unref(variant);
+ else if (variant->type == JSON_VARIANT_STRING)
+ free(variant->string);
+
+ free(variant);
+
+ return NULL;
+}
+
+char *json_variant_string(JsonVariant *variant){
+ assert(variant);
+ assert(variant->type == JSON_VARIANT_STRING);
+
+ return variant->string;
+}
+
+bool json_variant_bool(JsonVariant *variant) {
+ assert(variant);
+ assert(variant->type == JSON_VARIANT_BOOLEAN);
+
+ return variant->value.boolean;
+}
+
+intmax_t json_variant_integer(JsonVariant *variant) {
+ assert(variant);
+ assert(variant->type == JSON_VARIANT_INTEGER);
+
+ return variant->value.integer;
+}
+
+double json_variant_real(JsonVariant *variant) {
+ assert(variant);
+ assert(variant->type == JSON_VARIANT_REAL);
+
+ return variant->value.real;
+}
+
+JsonVariant *json_variant_element(JsonVariant *variant, unsigned index) {
+ assert(variant);
+ assert(variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT);
+ assert(index < variant->size);
+ assert(variant->objects);
+
+ return &variant->objects[index];
+}
+
+JsonVariant *json_variant_value(JsonVariant *variant, const char *key) {
+ size_t i;
+
+ assert(variant);
+ assert(variant->type == JSON_VARIANT_OBJECT);
+ assert(variant->objects);
+
+ for (i = 0; i < variant->size; i += 2) {
+ JsonVariant *p = &variant->objects[i];
+ if (p->type == JSON_VARIANT_STRING && streq(key, p->string))
+ return &variant->objects[i + 1];
+ }
+
+ return NULL;
+}
static void inc_lines(unsigned *line, const char *s, size_t n) {
const char *p = s;
@@ -286,9 +446,6 @@ static int json_parse_number(const char **p, union json_value *ret) {
} while (strchr("0123456789", *c) && *c != 0);
}
- if (*c != 0)
- return -EINVAL;
-
*p = c;
if (is_double) {
@@ -311,6 +468,12 @@ int json_tokenize(
int t;
int r;
+ enum {
+ STATE_NULL,
+ STATE_VALUE,
+ STATE_VALUE_POST,
+ };
+
assert(p);
assert(*p);
assert(ret_string);
@@ -444,3 +607,260 @@ int json_tokenize(
}
}
+
+static bool json_is_value(JsonVariant *var) {
+ assert(var);
+
+ return var->type != JSON_VARIANT_CONTROL;
+}
+
+static int json_scoped_parse(JsonVariant **tokens, size_t *i, size_t n, JsonVariant *scope) {
+ bool arr = scope->type == JSON_VARIANT_ARRAY;
+ int terminator = arr ? JSON_ARRAY_CLOSE : JSON_OBJECT_CLOSE;
+ size_t allocated = 0, size = 0;
+ JsonVariant *key = NULL, *value = NULL, *var = NULL, *items = NULL;
+ enum {
+ STATE_KEY,
+ STATE_COLON,
+ STATE_COMMA,
+ STATE_VALUE
+ } state = arr ? STATE_VALUE : STATE_KEY;
+
+ assert(tokens);
+ assert(i);
+ assert(scope);
+
+ while((var = *i < n ? tokens[(*i)++] : NULL) != NULL) {
+ bool stopper;
+ int r;
+
+ stopper = !json_is_value(var) && var->value.integer == terminator;
+
+ if (stopper) {
+ if (state != STATE_COMMA && size > 0)
+ goto error;
+
+ goto out;
+ }
+
+ if (state == STATE_KEY) {
+ if (var->type != JSON_VARIANT_STRING)
+ goto error;
+ else {
+ key = var;
+ state = STATE_COLON;
+ }
+ }
+ else if (state == STATE_COLON) {
+ if (key == NULL)
+ goto error;
+
+ if (json_is_value(var))
+ goto error;
+
+ if (var->value.integer != JSON_COLON)
+ goto error;
+
+ state = STATE_VALUE;
+ }
+ else if (state == STATE_VALUE) {
+ _cleanup_json_variant_unref_ JsonVariant *v = NULL;
+ size_t toadd = arr ? 1 : 2;
+
+ if (!json_is_value(var)) {
+ int type = (var->value.integer == JSON_ARRAY_OPEN) ? JSON_VARIANT_ARRAY : JSON_VARIANT_OBJECT;
+
+ r = json_variant_new(&v, type);
+ if (r < 0)
+ goto error;
+
+ r = json_scoped_parse(tokens, i, n, v);
+ if (r < 0)
+ goto error;
+
+ value = v;
+ }
+ else
+ value = var;
+
+ if(!GREEDY_REALLOC(items, allocated, size + toadd))
+ goto error;
+
+ if (arr) {
+ r = json_variant_deep_copy(&items[size], value);
+ if (r < 0)
+ goto error;
+ } else {
+ r = json_variant_deep_copy(&items[size], key);
+ if (r < 0)
+ goto error;
+
+ r = json_variant_deep_copy(&items[size+1], value);
+ if (r < 0)
+ goto error;
+ }
+
+ size += toadd;
+ state = STATE_COMMA;
+ }
+ else if (state == STATE_COMMA) {
+ if (json_is_value(var))
+ goto error;
+
+ if (var->value.integer != JSON_COMMA)
+ goto error;
+
+ key = NULL;
+ value = NULL;
+
+ state = arr ? STATE_VALUE : STATE_KEY;
+ }
+ }
+
+error:
+ json_raw_unref(items, size);
+ return -EBADMSG;
+
+out:
+ scope->size = size;
+ scope->objects = items;
+
+ return scope->type;
+}
+
+static int json_parse_tokens(JsonVariant **tokens, size_t ntokens, JsonVariant **rv) {
+ size_t it = 0;
+ int r;
+ JsonVariant *e;
+ _cleanup_json_variant_unref_ JsonVariant *p = NULL;
+
+ assert(tokens);
+ assert(ntokens);
+
+ e = tokens[it++];
+ r = json_variant_new(&p, JSON_VARIANT_OBJECT);
+ if (r < 0)
+ return r;
+
+ if (e->type != JSON_VARIANT_CONTROL && e->value.integer != JSON_OBJECT_OPEN)
+ return -EBADMSG;
+
+ r = json_scoped_parse(tokens, &it, ntokens, p);
+ if (r < 0)
+ return r;
+
+ *rv = p;
+ p = NULL;
+
+ return 0;
+}
+
+static int json_tokens(const char *string, size_t size, JsonVariant ***tokens, size_t *n) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_(json_variant_array_unrefp) JsonVariant **items = NULL;
+ union json_value v = {};
+ void *json_state = NULL;
+ const char *p;
+ int t, r;
+ size_t allocated = 0, s = 0;
+
+ assert(string);
+ assert(n);
+
+ if (size <= 0)
+ return -EBADMSG;
+
+ buf = strndup(string, size);
+ if (!buf)
+ return -ENOMEM;
+
+ p = buf;
+ for (;;) {
+ _cleanup_json_variant_unref_ JsonVariant *var = NULL;
+ _cleanup_free_ char *rstr = NULL;
+
+ t = json_tokenize(&p, &rstr, &v, &json_state, NULL);
+
+ if (t < 0)
+ return t;
+ else if (t == JSON_END)
+ break;
+
+ if (t <= JSON_ARRAY_CLOSE) {
+ r = json_variant_new(&var, JSON_VARIANT_CONTROL);
+ if (r < 0)
+ return r;
+ var->value.integer = t;
+ } else {
+ switch (t) {
+ case JSON_STRING:
+ r = json_variant_new(&var, JSON_VARIANT_STRING);
+ if (r < 0)
+ return r;
+ var->size = strlen(rstr);
+ var->string = strdup(rstr);
+ if (!var->string) {
+ return -ENOMEM;
+ }
+ break;
+ case JSON_INTEGER:
+ r = json_variant_new(&var, JSON_VARIANT_INTEGER);
+ if (r < 0)
+ return r;
+ var->value = v;
+ break;
+ case JSON_REAL:
+ r = json_variant_new(&var, JSON_VARIANT_REAL);
+ if (r < 0)
+ return r;
+ var->value = v;
+ break;
+ case JSON_BOOLEAN:
+ r = json_variant_new(&var, JSON_VARIANT_BOOLEAN);
+ if (r < 0)
+ return r;
+ var->value = v;
+ break;
+ case JSON_NULL:
+ r = json_variant_new(&var, JSON_VARIANT_NULL);
+ if (r < 0)
+ return r;
+ break;
+ }
+ }
+
+ if (!GREEDY_REALLOC(items, allocated, s+2))
+ return -ENOMEM;
+
+ items[s++] = var;
+ items[s] = NULL;
+ var = NULL;
+ }
+
+ *n = s;
+ *tokens = items;
+ items = NULL;
+
+ return 0;
+}
+
+int json_parse(const char *string, JsonVariant **rv) {
+ _cleanup_(json_variant_array_unrefp) JsonVariant **s = NULL;
+ JsonVariant *v = NULL;
+ size_t n = 0;
+ int r;
+
+ assert(string);
+ assert(rv);
+
+ r = json_tokens(string, strlen(string), &s, &n);
+ if (r < 0)
+ return r;
+
+ r = json_parse_tokens(s, n, &v);
+ if (r < 0)
+ return r;
+
+ *rv = v;
+ return 0;
+}
diff --git a/src/shared/json.h b/src/shared/json.h
index a8457132e7..e0b4d810b5 100644
--- a/src/shared/json.h
+++ b/src/shared/json.h
@@ -22,7 +22,7 @@
***/
#include <stdbool.h>
-#include <inttypes.h>
+#include "util.h"
enum {
JSON_END,
@@ -39,12 +39,50 @@ enum {
JSON_NULL,
};
+typedef enum {
+ JSON_VARIANT_CONTROL,
+ JSON_VARIANT_STRING,
+ JSON_VARIANT_INTEGER,
+ JSON_VARIANT_BOOLEAN,
+ JSON_VARIANT_REAL,
+ JSON_VARIANT_ARRAY,
+ JSON_VARIANT_OBJECT,
+ JSON_VARIANT_NULL
+} JsonVariantType;
+
union json_value {
bool boolean;
double real;
intmax_t integer;
};
+typedef struct JsonVariant {
+ JsonVariantType type;
+ size_t size;
+ union {
+ char *string;
+ struct JsonVariant *objects;
+ union json_value value;
+ };
+} JsonVariant;
+
+int json_variant_new(JsonVariant **ret, JsonVariantType type);
+JsonVariant *json_variant_unref(JsonVariant *v);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref);
+#define _cleanup_json_variant_unref_ _cleanup_(json_variant_unrefp)
+
+char *json_variant_string(JsonVariant *v);
+bool json_variant_bool(JsonVariant *v);
+intmax_t json_variant_integer(JsonVariant *v);
+double json_variant_real(JsonVariant *v);
+
+JsonVariant *json_variant_element(JsonVariant *v, unsigned index);
+JsonVariant *json_variant_value(JsonVariant *v, const char *key);
+
#define JSON_VALUE_NULL ((union json_value) {})
int json_tokenize(const char **p, char **ret_string, union json_value *ret_value, void **state, unsigned *line);
+
+int json_parse(const char *string, JsonVariant **rv);
+int json_parse_measure(const char *string, size_t *size);
diff --git a/src/shared/lockfile-util.c b/src/shared/lockfile-util.c
new file mode 100644
index 0000000000..05e16d1caa
--- /dev/null
+++ b/src/shared/lockfile-util.c
@@ -0,0 +1,154 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/file.h>
+
+#include "util.h"
+#include "lockfile-util.h"
+#include "fileio.h"
+
+int make_lock_file(const char *p, int operation, LockFile *ret) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ /*
+ * We use UNPOSIX locks if they are available. They have nice
+ * semantics, and are mostly compatible with NFS. However,
+ * they are only available on new kernels. When we detect we
+ * are running on an older kernel, then we fall back to good
+ * old BSD locks. They also have nice semantics, but are
+ * slightly problematic on NFS, where they are upgraded to
+ * POSIX locks, even though locally they are orthogonal to
+ * POSIX locks.
+ */
+
+ t = strdup(p);
+ if (!t)
+ return -ENOMEM;
+
+ for (;;) {
+ struct flock fl = {
+ .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
+ .l_whence = SEEK_SET,
+ };
+ struct stat st;
+
+ fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
+ if (fd < 0)
+ return -errno;
+
+ r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
+ if (r < 0) {
+
+ /* If the kernel is too old, use good old BSD locks */
+ if (errno == EINVAL)
+ r = flock(fd, operation);
+
+ if (r < 0)
+ return errno == EAGAIN ? -EBUSY : -errno;
+ }
+
+ /* If we acquired the lock, let's check if the file
+ * still exists in the file system. If not, then the
+ * previous exclusive owner removed it and then closed
+ * it. In such a case our acquired lock is worthless,
+ * hence try again. */
+
+ r = fstat(fd, &st);
+ if (r < 0)
+ return -errno;
+ if (st.st_nlink > 0)
+ break;
+
+ fd = safe_close(fd);
+ }
+
+ ret->path = t;
+ ret->fd = fd;
+ ret->operation = operation;
+
+ fd = -1;
+ t = NULL;
+
+ return r;
+}
+
+int make_lock_file_for(const char *p, int operation, LockFile *ret) {
+ const char *fn;
+ char *t;
+
+ assert(p);
+ assert(ret);
+
+ fn = basename(p);
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ t = newa(char, strlen(p) + 2 + 4 + 1);
+ stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
+
+ return make_lock_file(t, operation, ret);
+}
+
+void release_lock_file(LockFile *f) {
+ int r;
+
+ if (!f)
+ return;
+
+ if (f->path) {
+
+ /* If we are the exclusive owner we can safely delete
+ * the lock file itself. If we are not the exclusive
+ * owner, we can try becoming it. */
+
+ if (f->fd >= 0 &&
+ (f->operation & ~LOCK_NB) == LOCK_SH) {
+ static const struct flock fl = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ };
+
+ r = fcntl(f->fd, F_OFD_SETLK, &fl);
+ if (r < 0 && errno == EINVAL)
+ r = flock(f->fd, LOCK_EX|LOCK_NB);
+
+ if (r >= 0)
+ f->operation = LOCK_EX|LOCK_NB;
+ }
+
+ if ((f->operation & ~LOCK_NB) == LOCK_EX)
+ unlink_noerrno(f->path);
+
+ free(f->path);
+ f->path = NULL;
+ }
+
+ f->fd = safe_close(f->fd);
+ f->operation = 0;
+}
diff --git a/src/shared/lockfile-util.h b/src/shared/lockfile-util.h
new file mode 100644
index 0000000000..38d47094bd
--- /dev/null
+++ b/src/shared/lockfile-util.h
@@ -0,0 +1,39 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2011 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+#include "missing.h"
+
+typedef struct LockFile {
+ char *path;
+ int fd;
+ int operation;
+} LockFile;
+
+int make_lock_file(const char *p, int operation, LockFile *ret);
+int make_lock_file_for(const char *p, int operation, LockFile *ret);
+void release_lock_file(LockFile *f);
+
+#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
+
+#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
diff --git a/src/shared/log.c b/src/shared/log.c
index 646a1d6389..b96afc4de4 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -29,11 +29,16 @@
#include <stddef.h>
#include <printf.h>
+#include "sd-messages.h"
#include "log.h"
#include "util.h"
#include "missing.h"
#include "macro.h"
#include "socket-util.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
#define SNDBUF_SIZE (8*1024*1024)
@@ -689,7 +694,8 @@ int log_object_internalv(
va_list ap) {
PROTECT_ERRNO;
- char buffer[LINE_MAX];
+ char *buffer, *b;
+ size_t l;
if (error < 0)
error = -error;
@@ -701,7 +707,21 @@ int log_object_internalv(
if (error != 0)
errno = error;
- vsnprintf(buffer, sizeof(buffer), format, ap);
+ /* Prepend the object name before the message */
+ if (object) {
+ size_t n;
+
+ n = strlen(object);
+ l = n + 2 + LINE_MAX;
+
+ buffer = newa(char, l);
+ b = stpcpy(stpcpy(buffer, object), ": ");
+ } else {
+ l = LINE_MAX;
+ b = buffer = newa(char, l);
+ }
+
+ vsnprintf(b, l, format, ap);
return log_dispatch(level, error, file, line, func, object_field, object, buffer);
}
@@ -1061,3 +1081,58 @@ void log_received_signal(int level, const struct signalfd_siginfo *si) {
void log_set_upgrade_syslog_to_journal(bool b) {
upgrade_syslog_to_journal = b;
}
+
+int log_syntax_internal(
+ const char *unit,
+ int level,
+ const char *config_file,
+ unsigned config_line,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format, ...) {
+
+ PROTECT_ERRNO;
+ char buffer[LINE_MAX];
+ int r;
+ va_list ap;
+
+ if (error < 0)
+ error = -error;
+
+ if (_likely_(LOG_PRI(level) > log_max_level))
+ return -error;
+
+ if (log_target == LOG_TARGET_NULL)
+ return -error;
+
+ if (error != 0)
+ errno = error;
+
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ if (unit)
+ r = log_struct_internal(
+ level, error,
+ file, line, func,
+ getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
+ LOG_MESSAGE_ID(SD_MESSAGE_INVALID_CONFIGURATION),
+ "CONFIG_FILE=%s", config_file,
+ "CONFIG_LINE=%u", config_line,
+ LOG_MESSAGE("[%s:%u] %s", config_file, config_line, buffer),
+ NULL);
+ else
+ r = log_struct_internal(
+ level, error,
+ file, line, func,
+ LOG_MESSAGE_ID(SD_MESSAGE_INVALID_CONFIGURATION),
+ "CONFIG_FILE=%s", config_file,
+ "CONFIG_LINE=%u", config_line,
+ LOG_MESSAGE("[%s:%u] %s", config_file, config_line, buffer),
+ NULL);
+
+ return r;
+}
diff --git a/src/shared/log.h b/src/shared/log.h
index 2889e1e77f..569762d083 100644
--- a/src/shared/log.h
+++ b/src/shared/log.h
@@ -23,14 +23,13 @@
#include <stdbool.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <syslog.h>
#include <sys/signalfd.h>
-#include <sys/types.h>
-#include <unistd.h>
#include <errno.h>
-#include "macro.h"
#include "sd-id128.h"
+#include "macro.h"
typedef enum LogTarget{
LOG_TARGET_CONSOLE,
@@ -156,12 +155,12 @@ void log_assert_failed_return(
const char *func);
/* Logging with level */
-#define log_full_errno(level, error, ...) \
- ({ \
- int _l = (level), _e = (error); \
- (log_get_max_level() >= LOG_PRI(_l)) \
- ? log_internal(_l, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
- : -abs(_e); \
+#define log_full_errno(level, error, ...) \
+ ({ \
+ int _level = (level), _e = (error); \
+ (log_get_max_level() >= LOG_PRI(_level)) \
+ ? log_internal(_level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
+ : -abs(_e); \
})
#define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__)
@@ -205,8 +204,26 @@ LogTarget log_target_from_string(const char *s) _pure_;
/* Helpers to prepare various fields for structured logging */
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
-#define LOG_ERRNO(error) "ERRNO=%i", abs(error)
void log_received_signal(int level, const struct signalfd_siginfo *si);
void log_set_upgrade_syslog_to_journal(bool b);
+
+int log_syntax_internal(
+ const char *unit,
+ int level,
+ const char *config_file,
+ unsigned config_line,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format, ...) _printf_(9, 10);
+
+#define log_syntax(unit, level, config_file, config_line, error, ...) \
+ ({ \
+ int _level = (level), _e = (error); \
+ (log_get_max_level() >= LOG_PRI(_level)) \
+ ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
+ : -abs(_e); \
+ })
diff --git a/src/shared/login-shared.c b/src/shared/login-shared.c
index 054c77503b..64650a9134 100644
--- a/src/shared/login-shared.c
+++ b/src/shared/login-shared.c
@@ -23,7 +23,9 @@
#include "def.h"
bool session_id_valid(const char *id) {
- assert(id);
- return id[0] && id[strspn(id, LETTERS DIGITS)] == '\0';
+ if (isempty(id))
+ return false;
+
+ return id[strspn(id, LETTERS DIGITS)] == '\0';
}
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index c2495056d7..ac5eb16f62 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -20,9 +20,7 @@
***/
#include <time.h>
-#include <assert.h>
#include <errno.h>
-#include <poll.h>
#include <sys/socket.h>
#include <string.h>
#include <fcntl.h>
@@ -32,8 +30,10 @@
#include "util.h"
#include "utf8.h"
#include "hashmap.h"
-#include "fileio.h"
#include "journal-internal.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
/* up to three lines (each up to 100 characters),
or 300 characters, whichever is less */
@@ -272,7 +272,7 @@ static int output_short(
}
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to get journal fields: %m");
if (!message)
return 0;
@@ -408,11 +408,9 @@ static int output_verbose(
r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
if (r == -ENOENT)
log_debug("Source realtime timestamp not found");
- else if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
- "Failed to get source realtime timestamp: %s", strerror(-r));
- return r;
- } else {
+ else if (r < 0)
+ return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
+ else {
_cleanup_free_ char *value = NULL;
size_t size;
@@ -428,11 +426,8 @@ static int output_verbose(
if (r < 0) {
r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
- "Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
}
r = sd_journal_get_cursor(j, &cursor);
@@ -682,7 +677,7 @@ static int output_json(
h = hashmap_new(&string_hash_ops);
if (!h)
- return -ENOMEM;
+ return log_oom();
/* First round, iterate through the entry and count how often each field appears */
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
@@ -700,7 +695,7 @@ static int output_json(
n = strndup(data, eq - (const char*) data);
if (!n) {
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
@@ -709,13 +704,16 @@ static int output_json(
r = hashmap_put(h, n, UINT_TO_PTR(1));
if (r < 0) {
free(n);
+ log_oom();
goto finish;
}
} else {
r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
free(n);
- if (r < 0)
+ if (r < 0) {
+ log_oom();
goto finish;
+ }
}
}
@@ -753,7 +751,7 @@ static int output_json(
n = strndup(data, m);
if (!n) {
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
@@ -948,11 +946,11 @@ static int show_journal(FILE *f,
/* Seek to end */
r = sd_journal_seek_tail(j);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to seek to tail: %m");
r = sd_journal_previous_skip(j, how_many);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to skip previous: %m");
for (;;) {
for (;;) {
@@ -961,7 +959,7 @@ static int show_journal(FILE *f,
if (need_seek) {
r = sd_journal_next(j);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to iterate through journal: %m");
}
if (r == 0)
@@ -977,7 +975,7 @@ static int show_journal(FILE *f,
if (r == -ESTALE)
continue;
else if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to get journal time: %m");
if (usec < not_before)
continue;
@@ -988,22 +986,22 @@ static int show_journal(FILE *f,
r = output_journal(f, j, mode, n_columns, flags, ellipsized);
if (r < 0)
- goto finish;
+ return r;
}
if (warn_cutoff && line < how_many && not_before > 0) {
sd_id128_t boot_id;
- usec_t cutoff;
+ usec_t cutoff = 0;
/* Check whether the cutoff line is too early */
r = sd_id128_get_boot(&boot_id);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to get boot id: %m");
r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to get journal cutoff time: %m");
if (r > 0 && not_before < cutoff) {
maybe_print_begin_newline(f, &flags);
@@ -1018,12 +1016,11 @@ static int show_journal(FILE *f,
r = sd_journal_wait(j, USEC_INFINITY);
if (r < 0)
- goto finish;
+ return log_error_errno(r, "Failed to wait for journal: %m");
}
-finish:
- return r;
+ return 0;
}
int add_matches_for_unit(sd_journal *j, const char *unit) {
@@ -1166,9 +1163,9 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
if (fd < 0)
_exit(EXIT_FAILURE);
- k = loop_read(fd, buf, 36, false);
+ r = loop_read_exact(fd, buf, 36, false);
safe_close(fd);
- if (k != 36)
+ if (r < 0)
_exit(EXIT_FAILURE);
k = send(pair[1], buf, 36, MSG_NOSIGNAL);
@@ -1220,7 +1217,7 @@ int add_match_this_boot(sd_journal *j, const char *machine) {
r = sd_journal_add_conjunction(j);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add conjunction: %m");
return 0;
}
@@ -1250,7 +1247,7 @@ int show_journal_by_unit(
r = sd_journal_open(&j, journal_open_flags);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to open journal: %m");
r = add_match_this_boot(j, NULL);
if (r < 0)
@@ -1261,12 +1258,15 @@ int show_journal_by_unit(
else
r = add_matches_for_user_unit(j, unit, uid);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add unit matches: %m");
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *filter;
filter = journal_make_match_string(j);
+ if (!filter)
+ return log_oom();
+
log_debug("Journal filter: %s", filter);
}
diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h
index 8d9641e8ac..569e1faa55 100644
--- a/src/shared/logs-show.h
+++ b/src/shared/logs-show.h
@@ -22,7 +22,6 @@
***/
#include <stdbool.h>
-#include <unistd.h>
#include <sys/types.h>
#include "sd-journal.h"
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 8d61507e84..273dacff1f 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -23,12 +23,12 @@
#include <linux/fs.h>
#include <fcntl.h>
-#include "strv.h"
#include "utf8.h"
#include "btrfs-util.h"
#include "path-util.h"
#include "copy.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "machine-image.h"
static const char image_search_path[] =
@@ -136,12 +136,11 @@ static int image_make(
/* btrfs subvolumes have inode 256 */
if (st.st_ino == 256) {
- struct statfs sfs;
- if (fstatfs(fd, &sfs) < 0)
- return -errno;
-
- if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (r) {
BtrfsSubvolInfo info;
BtrfsQuotaInfo quota;
@@ -164,10 +163,10 @@ static int image_make(
r = btrfs_subvol_get_quota_fd(fd, &quota);
if (r >= 0) {
- (*ret)->usage = quota.referred;
+ (*ret)->usage = quota.referenced;
(*ret)->usage_exclusive = quota.exclusive;
- (*ret)->limit = quota.referred_max;
+ (*ret)->limit = quota.referenced_max;
(*ret)->limit_exclusive = quota.exclusive_max;
}
@@ -358,19 +357,21 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
- return btrfs_subvol_remove(i->path);
+ return btrfs_subvol_remove(i->path, true);
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
(void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
-
- /* fall through */
+ return rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
case IMAGE_RAW:
- return rm_rf_dangerous(i->path, false, true, false);
+ if (unlink(i->path) < 0)
+ return -errno;
+
+ return 0;
default:
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
}
@@ -431,7 +432,7 @@ int image_rename(Image *i, const char *new_name) {
}
default:
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
if (!new_path)
@@ -441,8 +442,9 @@ int image_rename(Image *i, const char *new_name) {
if (!nn)
return -ENOMEM;
- if (renameat2(AT_FDCWD, i->path, AT_FDCWD, new_path, RENAME_NOREPLACE) < 0)
- return -errno;
+ r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
+ if (r < 0)
+ return r;
/* Restore the immutable bit, if it was set before */
if (file_attr & FS_IMMUTABLE_FL)
@@ -488,7 +490,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_DIRECTORY:
new_path = strjoina("/var/lib/machines/", new_name);
- r = btrfs_subvol_snapshot(i->path, new_path, read_only, true);
+ r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
break;
case IMAGE_RAW:
@@ -498,7 +500,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
break;
default:
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
if (r < 0)
@@ -563,7 +565,7 @@ int image_read_only(Image *i, bool b) {
}
default:
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
return 0;
@@ -601,7 +603,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
return r;
if (p) {
- mkdir_p("/run/systemd/nspawn/locks", 0600);
+ mkdir_p("/run/systemd/nspawn/locks", 0700);
r = make_lock_file(p, operation, global);
if (r < 0) {
@@ -614,6 +616,19 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
return 0;
}
+int image_set_limit(Image *i, uint64_t referenced_max) {
+ assert(i);
+
+ if (path_equal(i->path, "/") ||
+ path_startswith(i->path, "/usr"))
+ return -EROFS;
+
+ if (i->type != IMAGE_SUBVOLUME)
+ return -EOPNOTSUPP;
+
+ return btrfs_quota_limit(i->path, referenced_max);
+}
+
int image_name_lock(const char *name, int operation, LockFile *ret) {
const char *p;
@@ -628,7 +643,7 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
if (streq(name, ".host"))
return -EBUSY;
- mkdir_p("/run/systemd/nspawn/locks", 0600);
+ mkdir_p("/run/systemd/nspawn/locks", 0700);
p = strjoina("/run/systemd/nspawn/locks/name-", name);
return make_lock_file(p, operation, ret);
diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h
index 75fa5f4533..f041600fbf 100644
--- a/src/shared/machine-image.h
+++ b/src/shared/machine-image.h
@@ -22,6 +22,7 @@
***/
#include "time-util.h"
+#include "lockfile-util.h"
#include "hashmap.h"
typedef enum ImageType {
@@ -45,6 +46,8 @@ typedef struct Image {
uint64_t usage_exclusive;
uint64_t limit;
uint64_t limit_exclusive;
+
+ void *userdata;
} Image;
Image *image_unref(Image *i);
@@ -68,3 +71,5 @@ bool image_name_is_valid(const char *s) _pure_;
int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
int image_name_lock(const char *name, int operation, LockFile *ret);
+
+int image_set_limit(Image *i, uint64_t referenced_max);
diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
new file mode 100644
index 0000000000..d27931cb4a
--- /dev/null
+++ b/src/shared/machine-pool.c
@@ -0,0 +1,379 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/prctl.h>
+#include <sys/vfs.h>
+#include <sys/statvfs.h>
+#include <sys/mount.h>
+
+#include "util.h"
+#include "process-util.h"
+#include "lockfile-util.h"
+#include "mkdir.h"
+#include "btrfs-util.h"
+#include "path-util.h"
+#include "signal-util.h"
+#include "machine-pool.h"
+
+#define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
+#define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
+
+static int check_btrfs(void) {
+ struct statfs sfs;
+
+ if (statfs("/var/lib/machines", &sfs) < 0) {
+ if (errno != ENOENT)
+ return -errno;
+
+ if (statfs("/var/lib", &sfs) < 0)
+ return -errno;
+ }
+
+ return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC);
+}
+
+static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
+ _cleanup_free_ char *tmp = NULL;
+ _cleanup_close_ int fd = -1;
+ struct statvfs ss;
+ pid_t pid = 0;
+ siginfo_t si;
+ int r;
+
+ /* We want to be able to make use of btrfs-specific file
+ * system features, in particular subvolumes, reflinks and
+ * quota. Hence, if we detect that /var/lib/machines.raw is
+ * not located on btrfs, let's create a loopback file, place a
+ * btrfs file system into it, and mount it to
+ * /var/lib/machines. */
+
+ fd = open("/var/lib/machines.raw", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (fd >= 0) {
+ r = fd;
+ fd = -1;
+ return r;
+ }
+
+ if (errno != ENOENT)
+ return sd_bus_error_set_errnof(error, errno, "Failed to open /var/lib/machines.raw: %m");
+
+ r = tempfn_xxxxxx("/var/lib/machines.raw", &tmp);
+ if (r < 0)
+ return r;
+
+ (void) mkdir_p_label("/var/lib", 0755);
+ fd = open(tmp, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0600);
+ if (fd < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create /var/lib/machines.raw: %m");
+
+ if (fstatvfs(fd, &ss) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to determine free space on /var/lib/machines.raw: %m");
+ goto fail;
+ }
+
+ if (ss.f_bsize * ss.f_bavail < VAR_LIB_MACHINES_FREE_MIN) {
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Not enough free disk space to set up /var/lib/machines.");
+ goto fail;
+ }
+
+ if (ftruncate(fd, size) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to enlarge /var/lib/machines.raw: %m");
+ goto fail;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
+ goto fail;
+ }
+
+ if (pid == 0) {
+
+ /* Child */
+
+ reset_all_signal_handlers();
+ reset_signal_mask();
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+ fd = safe_close(fd);
+
+ execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
+ if (errno == ENOENT)
+ return 99;
+
+ _exit(EXIT_FAILURE);
+ }
+
+ r = wait_for_terminate(pid, &si);
+ if (r < 0) {
+ sd_bus_error_set_errnof(error, r, "Failed to wait for mkfs.btrfs: %m");
+ goto fail;
+ }
+
+ pid = 0;
+
+ if (si.si_code != CLD_EXITED) {
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs died abnormally.");
+ goto fail;
+ }
+ if (si.si_status == 99) {
+ r = sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
+ goto fail;
+ }
+ if (si.si_status != 0) {
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "mkfs.btrfs failed with error code %i", si.si_status);
+ goto fail;
+ }
+
+ r = rename_noreplace(AT_FDCWD, tmp, AT_FDCWD, "/var/lib/machines.raw");
+ if (r < 0) {
+ sd_bus_error_set_errnof(error, r, "Failed to move /var/lib/machines.raw into place: %m");
+ goto fail;
+ }
+
+ r = fd;
+ fd = -1;
+
+ return r;
+
+fail:
+ unlink_noerrno(tmp);
+
+ if (pid > 1)
+ kill_and_sigcont(pid, SIGKILL);
+
+ return r;
+}
+
+int setup_machine_directory(uint64_t size, sd_bus_error *error) {
+ _cleanup_release_lock_file_ LockFile lock_file = LOCK_FILE_INIT;
+ struct loop_info64 info = {
+ .lo_flags = LO_FLAGS_AUTOCLEAR,
+ };
+ _cleanup_close_ int fd = -1, control = -1, loop = -1;
+ _cleanup_free_ char* loopdev = NULL;
+ char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
+ bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
+ char buf[FORMAT_BYTES_MAX];
+ int r, nr = -1;
+
+ /* btrfs cannot handle file systems < 16M, hence use this as minimum */
+ if (size == (uint64_t) -1)
+ size = VAR_LIB_MACHINES_SIZE_START;
+ else if (size < 16*1024*1024)
+ size = 16*1024*1024;
+
+ /* Make sure we only set the directory up once at a time */
+ r = make_lock_file("/run/systemd/machines.lock", LOCK_EX, &lock_file);
+ if (r < 0)
+ return r;
+
+ r = check_btrfs();
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to determine whether /var/lib/machines is located on btrfs: %m");
+ if (r > 0) {
+ (void) btrfs_subvol_make_label("/var/lib/machines");
+
+ r = btrfs_quota_enable("/var/lib/machines", true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+
+ return 0;
+ }
+
+ if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 ||
+ dir_is_empty("/var/lib/machines") == 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
+
+ fd = setup_machine_raw(size, error);
+ if (fd < 0)
+ return fd;
+
+ control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+ if (control < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to open /dev/loop-control: %m");
+
+ nr = ioctl(control, LOOP_CTL_GET_FREE);
+ if (nr < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to allocate loop device: %m");
+
+ if (asprintf(&loopdev, "/dev/loop%i", nr) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ loop = open(loopdev, O_CLOEXEC|O_RDWR|O_NOCTTY|O_NONBLOCK);
+ if (loop < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to open loopback device: %m");
+ goto fail;
+ }
+
+ if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to bind loopback device: %m");
+ goto fail;
+ }
+
+ if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to enable auto-clear for loopback device: %m");
+ goto fail;
+ }
+
+ /* We need to make sure the new /var/lib/machines directory
+ * has an access mode of 0700 at the time it is first made
+ * available. mkfs will create it with 0755 however. Hence,
+ * let's mount the directory into an inaccessible directory
+ * below /tmp first, fix the access mode, and move it to the
+ * public place then. */
+
+ if (!mkdtemp(tmpdir)) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount parent directory: %m");
+ goto fail;
+ }
+ tmpdir_made = true;
+
+ mntdir = strjoina(tmpdir, "/mnt");
+ if (mkdir(mntdir, 0700) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount directory: %m");
+ goto fail;
+ }
+ mntdir_made = true;
+
+ if (mount(loopdev, mntdir, "btrfs", 0, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to mount loopback device: %m");
+ goto fail;
+ }
+ mntdir_mounted = true;
+
+ r = btrfs_quota_enable(mntdir, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+
+ if (chmod(mntdir, 0700) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
+ goto fail;
+ }
+
+ (void) mkdir_p_label("/var/lib/machines", 0700);
+
+ if (mount(mntdir, "/var/lib/machines", NULL, MS_BIND, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to mount directory into right place: %m");
+ goto fail;
+ }
+
+ (void) syncfs(fd);
+
+ log_info("Set up /var/lib/machines as btrfs loopback file system of size %s mounted on /var/lib/machines.raw.", format_bytes(buf, sizeof(buf), size));
+
+ (void) umount2(mntdir, MNT_DETACH);
+ (void) rmdir(mntdir);
+ (void) rmdir(tmpdir);
+
+ return 0;
+
+fail:
+ if (mntdir_mounted)
+ (void) umount2(mntdir, MNT_DETACH);
+
+ if (mntdir_made)
+ (void) rmdir(mntdir);
+ if (tmpdir_made)
+ (void) rmdir(tmpdir);
+
+ if (loop >= 0) {
+ (void) ioctl(loop, LOOP_CLR_FD);
+ loop = safe_close(loop);
+ }
+
+ if (control >= 0 && nr >= 0)
+ (void) ioctl(control, LOOP_CTL_REMOVE, nr);
+
+ return r;
+}
+
+static int sync_path(const char *p) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+
+ if (syncfs(fd) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int grow_machine_directory(void) {
+ char buf[FORMAT_BYTES_MAX];
+ struct statvfs a, b;
+ uint64_t old_size, new_size, max_add;
+ int r;
+
+ /* Ensure the disk space data is accurate */
+ sync_path("/var/lib/machines");
+ sync_path("/var/lib/machines.raw");
+
+ if (statvfs("/var/lib/machines.raw", &a) < 0)
+ return -errno;
+
+ if (statvfs("/var/lib/machines", &b) < 0)
+ return -errno;
+
+ /* Don't grow if not enough disk space is available on the host */
+ if (((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) <= VAR_LIB_MACHINES_FREE_MIN)
+ return 0;
+
+ /* Don't grow if at least 1/3th of the fs is still free */
+ if (b.f_bavail > b.f_blocks / 3)
+ return 0;
+
+ /* Calculate how much we are willing to add at maximum */
+ max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN;
+
+ /* Calculate the old size */
+ old_size = (uint64_t) b.f_blocks * (uint64_t) b.f_bsize;
+
+ /* Calculate the new size as three times the size of what is used right now */
+ new_size = ((uint64_t) b.f_blocks - (uint64_t) b.f_bavail) * (uint64_t) b.f_bsize * 3;
+
+ /* Always, grow at least to the start size */
+ if (new_size < VAR_LIB_MACHINES_SIZE_START)
+ new_size = VAR_LIB_MACHINES_SIZE_START;
+
+ /* If the new size is smaller than the old size, don't grow */
+ if (new_size < old_size)
+ return 0;
+
+ /* Ensure we never add more than the maximum */
+ if (new_size > old_size + max_add)
+ new_size = old_size + max_add;
+
+ r = btrfs_resize_loopback("/var/lib/machines", new_size, true);
+ if (r <= 0)
+ return r;
+
+ r = btrfs_quota_limit("/var/lib/machines", new_size);
+ if (r < 0)
+ return r;
+
+ log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
+ return 1;
+}
diff --git a/src/shared/machine-pool.h b/src/shared/machine-pool.h
new file mode 100644
index 0000000000..fe01d3d47c
--- /dev/null
+++ b/src/shared/machine-pool.h
@@ -0,0 +1,30 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+
+/* Grow the /var/lib/machines directory after each 10MiB written */
+#define GROW_INTERVAL_BYTES (UINT64_C(10) * UINT64_C(1024) * UINT64_C(1024))
+
+int setup_machine_directory(uint64_t size, sd_bus_error *error);
+int grow_machine_directory(void);
diff --git a/src/shared/macro.h b/src/shared/macro.h
index 7f89951d62..7ae1ed80b6 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -256,6 +256,15 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
} \
} while (false)
+#define assert_return_errno(expr, r, err) \
+ do { \
+ if (_unlikely_(!(expr))) { \
+ log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ errno = err; \
+ return (r); \
+ } \
+ } while (false)
+
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
diff --git a/src/shared/memfd-util.c b/src/shared/memfd-util.c
index 6624c5e7db..e99a738e1f 100644
--- a/src/shared/memfd-util.c
+++ b/src/shared/memfd-util.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <fcntl.h>
-#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
@@ -30,7 +29,6 @@
#endif
#include "util.h"
-#include "bus-label.h"
#include "memfd-util.h"
#include "utf8.h"
#include "missing.h"
diff --git a/src/shared/memfd-util.h b/src/shared/memfd-util.h
index cf588fe02f..3ed551fb37 100644
--- a/src/shared/memfd-util.h
+++ b/src/shared/memfd-util.h
@@ -21,12 +21,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include "macro.h"
-#include "util.h"
int memfd_new(const char *name);
int memfd_new_and_map(const char *name, size_t sz, void **p);
diff --git a/src/shared/missing.h b/src/shared/missing.h
index b33a70cb2c..be7f6186fc 100644
--- a/src/shared/missing.h
+++ b/src/shared/missing.h
@@ -35,6 +35,7 @@
#include <linux/loop.h>
#include <linux/audit.h>
#include <linux/capability.h>
+#include <linux/neighbour.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
@@ -179,6 +180,16 @@ static inline int memfd_create(const char *name, unsigned int flags) {
# define __NR_getrandom 349
# elif defined(__powerpc__)
# define __NR_getrandom 359
+# elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_getrandom 4353
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_getrandom 6317
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_getrandom 5313
+# endif
# else
# warning "__NR_getrandom unknown for your architecture"
# define __NR_getrandom 0xffffffff
@@ -219,12 +230,64 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
#define BTRFS_UUID_SIZE 16
#endif
+#ifndef BTRFS_SUBVOL_RDONLY
+#define BTRFS_SUBVOL_RDONLY (1ULL << 1)
+#endif
+
+#ifndef BTRFS_SUBVOL_NAME_MAX
+#define BTRFS_SUBVOL_NAME_MAX 4039
+#endif
+
+#ifndef BTRFS_INO_LOOKUP_PATH_MAX
+#define BTRFS_INO_LOOKUP_PATH_MAX 4080
+#endif
+
+#ifndef BTRFS_SEARCH_ARGS_BUFSIZE
+#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
+#endif
+
#ifndef HAVE_LINUX_BTRFS_H
struct btrfs_ioctl_vol_args {
int64_t fd;
char name[BTRFS_PATH_NAME_MAX + 1];
};
+struct btrfs_qgroup_limit {
+ __u64 flags;
+ __u64 max_rfer;
+ __u64 max_excl;
+ __u64 rsv_rfer;
+ __u64 rsv_excl;
+};
+
+struct btrfs_qgroup_inherit {
+ __u64 flags;
+ __u64 num_qgroups;
+ __u64 num_ref_copies;
+ __u64 num_excl_copies;
+ struct btrfs_qgroup_limit lim;
+ __u64 qgroups[0];
+};
+
+struct btrfs_ioctl_qgroup_limit_args {
+ __u64 qgroupid;
+ struct btrfs_qgroup_limit lim;
+};
+
+struct btrfs_ioctl_vol_args_v2 {
+ __s64 fd;
+ __u64 transid;
+ __u64 flags;
+ union {
+ struct {
+ __u64 size;
+ struct btrfs_qgroup_inherit *qgroup_inherit;
+ };
+ __u64 unused[4];
+ };
+ char name[BTRFS_SUBVOL_NAME_MAX + 1];
+};
+
struct btrfs_ioctl_dev_info_args {
uint64_t devid; /* in/out */
uint8_t uuid[BTRFS_UUID_SIZE]; /* in/out */
@@ -240,6 +303,76 @@ struct btrfs_ioctl_fs_info_args {
uint8_t fsid[BTRFS_FSID_SIZE]; /* out */
uint64_t reserved[124]; /* pad to 1k */
};
+
+struct btrfs_ioctl_ino_lookup_args {
+ __u64 treeid;
+ __u64 objectid;
+ char name[BTRFS_INO_LOOKUP_PATH_MAX];
+};
+
+struct btrfs_ioctl_search_key {
+ /* which root are we searching. 0 is the tree of tree roots */
+ __u64 tree_id;
+
+ /* keys returned will be >= min and <= max */
+ __u64 min_objectid;
+ __u64 max_objectid;
+
+ /* keys returned will be >= min and <= max */
+ __u64 min_offset;
+ __u64 max_offset;
+
+ /* max and min transids to search for */
+ __u64 min_transid;
+ __u64 max_transid;
+
+ /* keys returned will be >= min and <= max */
+ __u32 min_type;
+ __u32 max_type;
+
+ /*
+ * how many items did userland ask for, and how many are we
+ * returning
+ */
+ __u32 nr_items;
+
+ /* align to 64 bits */
+ __u32 unused;
+
+ /* some extra for later */
+ __u64 unused1;
+ __u64 unused2;
+ __u64 unused3;
+ __u64 unused4;
+};
+
+struct btrfs_ioctl_search_header {
+ __u64 transid;
+ __u64 objectid;
+ __u64 offset;
+ __u32 type;
+ __u32 len;
+};
+
+
+struct btrfs_ioctl_search_args {
+ struct btrfs_ioctl_search_key key;
+ char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
+};
+
+struct btrfs_ioctl_clone_range_args {
+ __s64 src_fd;
+ __u64 src_offset, src_length;
+ __u64 dest_offset;
+};
+
+#define BTRFS_QUOTA_CTL_ENABLE 1
+#define BTRFS_QUOTA_CTL_DISABLE 2
+#define BTRFS_QUOTA_CTL_RESCAN__NOTUSED 3
+struct btrfs_ioctl_quota_ctl_args {
+ __u64 cmd;
+ __u64 status;
+};
#endif
#ifndef BTRFS_IOC_DEFRAG
@@ -247,6 +380,53 @@ struct btrfs_ioctl_fs_info_args {
struct btrfs_ioctl_vol_args)
#endif
+#ifndef BTRFS_IOC_RESIZE
+#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \
+ struct btrfs_ioctl_vol_args)
+#endif
+
+#ifndef BTRFS_IOC_CLONE
+#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int)
+#endif
+
+#ifndef BTRFS_IOC_CLONE_RANGE
+#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \
+ struct btrfs_ioctl_clone_range_args)
+#endif
+
+#ifndef BTRFS_IOC_SUBVOL_CREATE
+#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
+ struct btrfs_ioctl_vol_args)
+#endif
+
+#ifndef BTRFS_IOC_SNAP_DESTROY
+#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
+ struct btrfs_ioctl_vol_args)
+#endif
+
+#ifndef BTRFS_IOC_TREE_SEARCH
+#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+ struct btrfs_ioctl_search_args)
+#endif
+
+#ifndef BTRFS_IOC_INO_LOOKUP
+#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
+ struct btrfs_ioctl_ino_lookup_args)
+#endif
+
+#ifndef BTRFS_IOC_SNAP_CREATE_V2
+#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
+ struct btrfs_ioctl_vol_args_v2)
+#endif
+
+#ifndef BTRFS_IOC_SUBVOL_GETFLAGS
+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
+#endif
+
+#ifndef BTRFS_IOC_SUBVOL_SETFLAGS
+#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
+#endif
+
#ifndef BTRFS_IOC_DEV_INFO
#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
struct btrfs_ioctl_dev_info_args)
@@ -262,10 +442,24 @@ struct btrfs_ioctl_fs_info_args {
struct btrfs_ioctl_vol_args)
#endif
+#ifndef BTRFS_IOC_QUOTA_CTL
+#define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \
+ struct btrfs_ioctl_quota_ctl_args)
+#endif
+
+#ifndef BTRFS_IOC_QGROUP_LIMIT
+#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \
+ struct btrfs_ioctl_qgroup_limit_args)
+#endif
+
#ifndef BTRFS_FIRST_FREE_OBJECTID
#define BTRFS_FIRST_FREE_OBJECTID 256
#endif
+#ifndef BTRFS_LAST_FREE_OBJECTID
+#define BTRFS_LAST_FREE_OBJECTID -256ULL
+#endif
+
#ifndef BTRFS_ROOT_TREE_OBJECTID
#define BTRFS_ROOT_TREE_OBJECTID 1
#endif
@@ -290,6 +484,10 @@ struct btrfs_ioctl_fs_info_args {
#define BTRFS_QGROUP_LIMIT_KEY 244
#endif
+#ifndef BTRFS_ROOT_BACKREF_KEY
+#define BTRFS_ROOT_BACKREF_KEY 144
+#endif
+
#ifndef BTRFS_SUPER_MAGIC
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
@@ -543,7 +741,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_VXLAN_LOCAL6
+#if !HAVE_DECL_IFLA_VXLAN_REMCSUM_NOPARTIAL
#define IFLA_VXLAN_UNSPEC 0
#define IFLA_VXLAN_ID 1
#define IFLA_VXLAN_GROUP 2
@@ -562,7 +760,14 @@ static inline int setns(int fd, int nstype) {
#define IFLA_VXLAN_PORT 15
#define IFLA_VXLAN_GROUP6 16
#define IFLA_VXLAN_LOCAL6 17
-#define __IFLA_VXLAN_MAX 18
+#define IFLA_VXLAN_UDP_CSUM 18
+#define IFLA_VXLAN_UDP_ZERO_CSUM6_TX 19
+#define IFLA_VXLAN_UDP_ZERO_CSUM6_RX 20
+#define IFLA_VXLAN_REMCSUM_TX 21
+#define IFLA_VXLAN_REMCSUM_RX 22
+#define IFLA_VXLAN_GBP 23
+#define IFLA_VXLAN_REMCSUM_NOPARTIAL 24
+#define __IFLA_VXLAN_MAX 25
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
#endif
@@ -613,6 +818,21 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#endif
+#if !HAVE_DECL_NDA_IFINDEX
+#define NDA_UNSPEC 0
+#define NDA_DST 1
+#define NDA_LLADDR 2
+#define NDA_CACHEINFO 3
+#define NDA_PROBES 4
+#define NDA_VLAN 5
+#define NDA_PORT 6
+#define NDA_VNI 7
+#define NDA_IFINDEX 8
+#define __NDA_MAX 9
+
+#define NDA_MAX (__NDA_MAX - 1)
+#endif
+
#ifndef IPV6_UNICAST_IF
#define IPV6_UNICAST_IF 76
#endif
@@ -674,6 +894,14 @@ static inline int setns(int fd, int nstype) {
#define LOOPBACK_IFINDEX 1
#endif
+#if !HAVE_DECL_IFA_FLAGS
+#define IFA_FLAGS 8
+#endif
+
+#ifndef IFA_F_NOPREFIXROUTE
+#define IFA_F_NOPREFIXROUTE 0x200
+#endif
+
#ifndef MAX_AUDIT_MESSAGE_LENGTH
#define MAX_AUDIT_MESSAGE_LENGTH 8970
#endif
@@ -763,3 +991,11 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
#ifndef KCMP_FILE
#define KCMP_FILE 0
#endif
+
+#ifndef INPUT_PROP_POINTING_STICK
+#define INPUT_PROP_POINTING_STICK 0x05
+#endif
+
+#ifndef INPUT_PROP_ACCELEROMETER
+#define INPUT_PROP_ACCELEROMETER 0x06
+#endif
diff --git a/src/shared/mkdir-label.c b/src/shared/mkdir-label.c
index ee11ac06ff..76bbc1edda 100644
--- a/src/shared/mkdir-label.c
+++ b/src/shared/mkdir-label.c
@@ -20,16 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
-#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
#include <stdio.h>
#include "label.h"
-#include "util.h"
-#include "path-util.h"
#include "mkdir.h"
int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) {
diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c
index beefd1052a..7ee4546988 100644
--- a/src/shared/mkdir.c
+++ b/src/shared/mkdir.c
@@ -19,14 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
-#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "label.h"
#include "util.h"
#include "path-util.h"
#include "mkdir.h"
@@ -46,10 +41,8 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd
(st.st_mode & 0700) > (mode & 0700) ||
(uid != UID_INVALID && st.st_uid != uid) ||
(gid != GID_INVALID && st.st_gid != gid) ||
- !S_ISDIR(st.st_mode)) {
- errno = EEXIST;
- return -errno;
- }
+ !S_ISDIR(st.st_mode))
+ return -EEXIST;
return 0;
}
diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h
index e317df300e..2392d1fd1b 100644
--- a/src/shared/mkdir.h
+++ b/src/shared/mkdir.h
@@ -22,7 +22,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <sys/types.h>
int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid);
diff --git a/src/shared/ordered-set.h b/src/shared/ordered-set.h
new file mode 100644
index 0000000000..766a1f2e83
--- /dev/null
+++ b/src/shared/ordered-set.h
@@ -0,0 +1,59 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "hashmap.h"
+
+typedef struct OrderedSet OrderedSet;
+
+static inline OrderedSet* ordered_set_new(const struct hash_ops *ops) {
+ return (OrderedSet*) ordered_hashmap_new(ops);
+}
+
+static inline OrderedSet* ordered_set_free(OrderedSet *s) {
+ ordered_hashmap_free((OrderedHashmap*) s);
+ return NULL;
+}
+
+static inline OrderedSet* ordered_set_free_free(OrderedSet *s) {
+ ordered_hashmap_free_free((OrderedHashmap*) s);
+ return NULL;
+}
+
+static inline int ordered_set_put(OrderedSet *s, void *p) {
+ return ordered_hashmap_put((OrderedHashmap*) s, p, p);
+}
+
+static inline bool ordered_set_isempty(OrderedSet *s) {
+ return ordered_hashmap_isempty((OrderedHashmap*) s);
+}
+
+static inline void *ordered_set_iterate(OrderedSet *s, Iterator *i) {
+ return ordered_hashmap_iterate((OrderedHashmap*) s, i, NULL);
+}
+
+#define ORDERED_SET_FOREACH(e, s, i) \
+ for ((i) = ITERATOR_FIRST, (e) = ordered_set_iterate((s), &(i)); (e); (e) = ordered_set_iterate((s), &(i)))
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free);
+
+#define _cleanup_ordered_set_free_ _cleanup_(ordered_set_freep)
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 8635d9a600..58b62fdccf 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
@@ -28,7 +27,9 @@
#include "pager.h"
#include "util.h"
+#include "process-util.h"
#include "macro.h"
+#include "terminal-util.h"
static pid_t pager_pid = 0;
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index 291a2f4054..f6a127174c 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -19,18 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <unistd.h>
#include <errno.h>
#include "util.h"
-#include "mkdir.h"
#include "strv.h"
#include "path-util.h"
#include "path-lookup.h"
+#include "install.h"
int user_config_home(char **config_home) {
const char *e;
@@ -220,8 +218,8 @@ static char** user_dirs(
return tmp;
}
-char **generator_paths(SystemdRunningAs running_as) {
- if (running_as == SYSTEMD_USER)
+char **generator_paths(ManagerRunningAs running_as) {
+ if (running_as == MANAGER_USER)
return strv_new("/run/systemd/user-generators",
"/etc/systemd/user-generators",
"/usr/local/lib/systemd/user-generators",
@@ -237,7 +235,7 @@ char **generator_paths(SystemdRunningAs running_as) {
int lookup_paths_init(
LookupPaths *p,
- SystemdRunningAs running_as,
+ ManagerRunningAs running_as,
bool personal,
const char *root_dir,
const char *generator,
@@ -279,7 +277,7 @@ int lookup_paths_init(
* we include /lib in the search path for the system
* stuff but avoid it for user stuff. */
- if (running_as == SYSTEMD_USER) {
+ if (running_as == MANAGER_USER) {
if (personal)
unit_path = user_dirs(generator, generator_early, generator_late);
else
@@ -339,7 +337,7 @@ int lookup_paths_init(
p->unit_path = NULL;
}
- if (running_as == SYSTEMD_SYSTEM) {
+ if (running_as == MANAGER_SYSTEM) {
#ifdef HAVE_SYSV_COMPAT
/* /etc/init.d/ compatibility does not matter to users */
@@ -439,7 +437,7 @@ int lookup_paths_init_from_scope(LookupPaths *paths,
zero(*paths);
return lookup_paths_init(paths,
- scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
+ scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
scope == UNIT_FILE_USER,
root_dir,
NULL, NULL, NULL);
diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h
index 2ec888da81..e35c8d3c04 100644
--- a/src/shared/path-lookup.h
+++ b/src/shared/path-lookup.h
@@ -22,7 +22,6 @@
***/
#include "macro.h"
-#include "install.h"
typedef struct LookupPaths {
char **unit_path;
@@ -32,28 +31,31 @@ typedef struct LookupPaths {
#endif
} LookupPaths;
-typedef enum SystemdRunningAs {
- SYSTEMD_SYSTEM,
- SYSTEMD_USER,
- _SYSTEMD_RUNNING_AS_MAX,
- _SYSTEMD_RUNNING_AS_INVALID = -1
-} SystemdRunningAs;
+typedef enum ManagerRunningAs {
+ MANAGER_SYSTEM,
+ MANAGER_USER,
+ _MANAGER_RUNNING_AS_MAX,
+ _MANAGER_RUNNING_AS_INVALID = -1
+} ManagerRunningAs;
int user_config_home(char **config_home);
int user_runtime_dir(char **runtime_dir);
-char **generator_paths(SystemdRunningAs running_as);
+char **generator_paths(ManagerRunningAs running_as);
int lookup_paths_init(LookupPaths *p,
- SystemdRunningAs running_as,
+ ManagerRunningAs running_as,
bool personal,
const char *root_dir,
const char *generator,
const char *generator_early,
const char *generator_late);
-void lookup_paths_free(LookupPaths *p);
+
+#include "install.h"
+
int lookup_paths_init_from_scope(LookupPaths *paths,
UnitFileScope scope,
const char *root_dir);
+void lookup_paths_free(LookupPaths *p);
#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free)
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index b9db7f1047..be50a1865d 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -19,15 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
-#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
-#include <dirent.h>
#include <sys/statvfs.h>
#include "macro.h"
@@ -36,6 +33,7 @@
#include "strv.h"
#include "path-util.h"
#include "missing.h"
+#include "fileio.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
@@ -403,12 +401,18 @@ char* path_startswith(const char *path, const char *prefix) {
}
}
-bool path_equal(const char *a, const char *b) {
+int path_compare(const char *a, const char *b) {
+ int d;
+
assert(a);
assert(b);
- if ((a[0] == '/') != (b[0] == '/'))
- return false;
+ /* A relative path and an abolute path must not compare as equal.
+ * Which one is sorted before the other does not really matter.
+ * Here a relative path is ordered before an absolute path. */
+ d = (a[0] == '/') - (b[0] == '/');
+ if (d)
+ return d;
for (;;) {
size_t j, k;
@@ -417,25 +421,40 @@ bool path_equal(const char *a, const char *b) {
b += strspn(b, "/");
if (*a == 0 && *b == 0)
- return true;
+ return 0;
- if (*a == 0 || *b == 0)
- return false;
+ /* Order prefixes first: "/foo" before "/foo/bar" */
+ if (*a == 0)
+ return -1;
+ if (*b == 0)
+ return 1;
j = strcspn(a, "/");
k = strcspn(b, "/");
- if (j != k)
- return false;
+ /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
+ d = memcmp(a, b, MIN(j, k));
+ if (d)
+ return (d > 0) - (d < 0); /* sign of d */
- if (memcmp(a, b, j) != 0)
- return false;
+ /* Sort "/foo/a" before "/foo/aaa" */
+ d = (j > k) - (j < k); /* sign of (j - k) */
+ if (d)
+ return d;
a += j;
b += k;
}
}
+bool path_equal(const char *a, const char *b) {
+ return path_compare(a, b) == 0;
+}
+
+bool path_equal_or_files_same(const char *a, const char *b) {
+ return path_equal(a, b) || files_same(a, b) > 0;
+}
+
char* path_join(const char *root, const char *path, const char *rest) {
assert(path);
@@ -452,87 +471,192 @@ char* path_join(const char *root, const char *path, const char *rest) {
NULL);
}
-int path_is_mount_point(const char *t, bool allow_symlink) {
+static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
+ char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
+ _cleanup_free_ char *fdinfo = NULL;
+ _cleanup_close_ int subfd = -1;
+ char *p;
+ int r;
+
+ if ((flags & AT_EMPTY_PATH) && isempty(filename))
+ xsprintf(path, "/proc/self/fdinfo/%i", fd);
+ else {
+ subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
+ if (subfd < 0)
+ return -errno;
+
+ xsprintf(path, "/proc/self/fdinfo/%i", subfd);
+ }
+
+ r = read_full_file(path, &fdinfo, NULL);
+ if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
+ return -EOPNOTSUPP;
+ if (r < 0)
+ return -errno;
+
+ p = startswith(fdinfo, "mnt_id:");
+ if (!p) {
+ p = strstr(fdinfo, "\nmnt_id:");
+ if (!p) /* The mnt_id field is a relatively new addition */
+ return -EOPNOTSUPP;
+
+ p += 8;
+ }
- union file_handle_union h = FILE_HANDLE_INIT;
+ p += strspn(p, WHITESPACE);
+ p[strcspn(p, WHITESPACE)] = 0;
+
+ return safe_atoi(p, mnt_id);
+}
+
+int fd_is_mount_point(int fd, const char *filename, int flags) {
+ union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
int mount_id = -1, mount_id_parent = -1;
- _cleanup_free_ char *parent = NULL;
+ bool nosupp = false, check_st_dev = true;
struct stat a, b;
int r;
- bool nosupp = false;
- /* We are not actually interested in the file handles, but
- * name_to_handle_at() also passes us the mount ID, hence use
- * it but throw the handle away */
+ assert(fd >= 0);
+ assert(filename);
- if (path_equal(t, "/"))
- return 1;
-
- r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0);
+ /* First we will try the name_to_handle_at() syscall, which
+ * tells us the mount id and an opaque file "handle". It is
+ * not supported everywhere though (kernel compile-time
+ * option, not all file systems are hooked up). If it works
+ * the mount id is usually good enough to tell us whether
+ * something is a mount point.
+ *
+ * If that didn't work we will try to read the mount id from
+ * /proc/self/fdinfo/<fd>. This is almost as good as
+ * name_to_handle_at(), however, does not return the the
+ * opaque file handle. The opaque file handle is pretty useful
+ * to detect the root directory, which we should always
+ * consider a mount point. Hence we use this only as
+ * fallback. Exporting the mnt_id in fdinfo is a pretty recent
+ * kernel addition.
+ *
+ * As last fallback we do traditional fstat() based st_dev
+ * comparisons. This is how things were traditionally done,
+ * but unionfs breaks breaks this since it exposes file
+ * systems with a variety of st_dev reported. Also, btrfs
+ * subvolumes have different st_dev, even though they aren't
+ * real mounts of their own. */
+
+ r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
if (r < 0) {
if (errno == ENOSYS)
/* This kernel does not support name_to_handle_at()
- * fall back to the traditional stat() logic. */
- goto fallback;
+ * fall back to simpler logic. */
+ goto fallback_fdinfo;
else if (errno == EOPNOTSUPP)
/* This kernel or file system does not support
- * name_to_handle_at(), hence fallback to the
+ * name_to_handle_at(), hence let's see if the
+ * upper fs supports it (in which case it is a
+ * mount point), otherwise fallback to the
* traditional stat() logic */
nosupp = true;
- else if (errno == ENOENT)
- return 0;
else
return -errno;
}
- r = path_get_parent(t, &parent);
- if (r < 0)
- return r;
-
- h.handle.handle_bytes = MAX_HANDLE_SZ;
- r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, AT_SYMLINK_FOLLOW);
- if (r < 0)
- if (errno == EOPNOTSUPP)
+ r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
+ if (r < 0) {
+ if (errno == EOPNOTSUPP) {
if (nosupp)
/* Neither parent nor child do name_to_handle_at()?
We have no choice but to fall back. */
- goto fallback;
+ goto fallback_fdinfo;
else
- /* The parent can't do name_to_handle_at() but
- * the directory we are interested in can?
- * Or the other way around?
+ /* The parent can't do name_to_handle_at() but the
+ * directory we are interested in can?
* If so, it must be a mount point. */
return 1;
- else
+ } else
return -errno;
- else
- return mount_id != mount_id_parent;
+ }
-fallback:
- if (allow_symlink)
- r = stat(t, &a);
- else
- r = lstat(t, &a);
+ /* The parent can do name_to_handle_at() but the
+ * directory we are interested in can't? If so, it
+ * must be a mount point. */
+ if (nosupp)
+ return 1;
- if (r < 0) {
- if (errno == ENOENT)
- return 0;
+ /* If the file handle for the directory we are
+ * interested in and its parent are identical, we
+ * assume this is the root directory, which is a mount
+ * point. */
+
+ if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
+ h.handle.handle_type == h_parent.handle.handle_type &&
+ memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
+ return 1;
+
+ return mount_id != mount_id_parent;
+
+fallback_fdinfo:
+ r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
+ if (r == -EOPNOTSUPP)
+ goto fallback_fstat;
+ if (r < 0)
+ return r;
+
+ r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
+ if (r < 0)
+ return r;
+
+ if (mount_id != mount_id_parent)
+ return 1;
+ /* Hmm, so, the mount ids are the same. This leaves one
+ * special case though for the root file system. For that,
+ * let's see if the parent directory has the same inode as we
+ * are interested in. Hence, let's also do fstat() checks now,
+ * too, but avoid the st_dev comparisons, since they aren't
+ * that useful on unionfs mounts. */
+ check_st_dev = false;
+
+fallback_fstat:
+ /* yay for fstatat() taking a different set of flags than the other
+ * _at() above */
+ if (flags & AT_SYMLINK_FOLLOW)
+ flags &= ~AT_SYMLINK_FOLLOW;
+ else
+ flags |= AT_SYMLINK_NOFOLLOW;
+ if (fstatat(fd, filename, &a, flags) < 0)
return -errno;
- }
- free(parent);
- parent = NULL;
+ if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
+ return -errno;
+
+ /* A directory with same device and inode as its parent? Must
+ * be the root directory */
+ if (a.st_dev == b.st_dev &&
+ a.st_ino == b.st_ino)
+ return 1;
+
+ return check_st_dev && (a.st_dev != b.st_dev);
+}
+
+/* flags can be AT_SYMLINK_FOLLOW or 0 */
+int path_is_mount_point(const char *t, int flags) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *parent = NULL;
+ int r;
+
+ assert(t);
+
+ if (path_equal(t, "/"))
+ return 1;
r = path_get_parent(t, &parent);
if (r < 0)
return r;
- r = stat(parent, &b);
- if (r < 0)
+ fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
+ if (fd < 0)
return -errno;
- return a.st_dev != b.st_dev;
+ return fd_is_mount_point(fd, basename(t), flags);
}
int path_is_read_only_fs(const char *path) {
@@ -683,3 +807,37 @@ int fsck_exists(const char *fstype) {
return 0;
}
+
+char *prefix_root(const char *root, const char *path) {
+ char *n, *p;
+ size_t l;
+
+ /* If root is passed, prefixes path with it. Otherwise returns
+ * it as is. */
+
+ assert(path);
+
+ /* First, drop duplicate prefixing slashes from the path */
+ while (path[0] == '/' && path[1] == '/')
+ path++;
+
+ if (isempty(root) || path_equal(root, "/"))
+ return strdup(path);
+
+ l = strlen(root) + 1 + strlen(path) + 1;
+
+ n = new(char, l);
+ if (!n)
+ return NULL;
+
+ p = stpcpy(n, root);
+
+ while (p > n && p[-1] == '/')
+ p--;
+
+ if (path[0] != '/')
+ *(p++) = '/';
+
+ strcpy(p, path);
+ return n;
+}
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index bd0d32473f..1eac89c51b 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -44,14 +44,17 @@ char* path_make_absolute_cwd(const char *p);
int path_make_relative(const char *from_dir, const char *to_path, char **_r);
char* path_kill_slashes(char *path);
char* path_startswith(const char *path, const char *prefix) _pure_;
+int path_compare(const char *a, const char *b) _pure_;
bool path_equal(const char *a, const char *b) _pure_;
+bool path_equal_or_files_same(const char *a, const char *b);
char* path_join(const char *root, const char *path, const char *rest);
char** path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix);
-int path_is_mount_point(const char *path, bool allow_symlink);
+int fd_is_mount_point(int fd, const char *filename, int flags);
+int path_is_mount_point(const char *path, int flags);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
@@ -70,3 +73,30 @@ int fsck_exists(const char *fstype);
/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+
+char *prefix_root(const char *root, const char *path);
+
+/* Similar to prefix_root(), but returns an alloca() buffer, or
+ * possibly a const pointer into the path parameter */
+#define prefix_roota(root, path) \
+ ({ \
+ const char* _path = (path), *_root = (root), *_ret; \
+ char *_p, *_n; \
+ size_t _l; \
+ while (_path[0] == '/' && _path[1] == '/') \
+ _path ++; \
+ if (isempty(_root) || path_equal(_root, "/")) \
+ _ret = _path; \
+ else { \
+ _l = strlen(_root) + 1 + strlen(_path) + 1; \
+ _n = alloca(_l); \
+ _p = stpcpy(_n, _root); \
+ while (_p > _n && _p[-1] == '/') \
+ _p--; \
+ if (_path[0] != '/') \
+ *(_p++) = '/'; \
+ strcpy(_p, _path); \
+ _ret = _n; \
+ } \
+ _ret; \
+ })
diff --git a/src/shared/prioq.c b/src/shared/prioq.c
index 8af4c51c2f..b89888be0e 100644
--- a/src/shared/prioq.c
+++ b/src/shared/prioq.c
@@ -45,12 +45,14 @@ Prioq *prioq_new(compare_func_t compare_func) {
return q;
}
-void prioq_free(Prioq *q) {
+Prioq* prioq_free(Prioq *q) {
if (!q)
- return;
+ return NULL;
free(q->items);
free(q);
+
+ return NULL;
}
int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
diff --git a/src/shared/prioq.h b/src/shared/prioq.h
index d836b36cd9..1c044b135c 100644
--- a/src/shared/prioq.h
+++ b/src/shared/prioq.h
@@ -28,7 +28,7 @@ typedef struct Prioq Prioq;
#define PRIOQ_IDX_NULL ((unsigned) -1)
Prioq *prioq_new(compare_func_t compare);
-void prioq_free(Prioq *q);
+Prioq *prioq_free(Prioq *q);
int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func);
int prioq_put(Prioq *q, void *data, unsigned *idx);
diff --git a/src/shared/process-util.c b/src/shared/process-util.c
new file mode 100644
index 0000000000..cfc876567d
--- /dev/null
+++ b/src/shared/process-util.c
@@ -0,0 +1,539 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <ctype.h>
+
+#include "fileio.h"
+#include "util.h"
+#include "log.h"
+#include "signal-util.h"
+#include "process-util.h"
+
+int get_process_state(pid_t pid) {
+ const char *p;
+ char state;
+ int r;
+ _cleanup_free_ char *line = NULL;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "stat");
+ r = read_one_line_file(p, &line);
+ if (r < 0)
+ return r;
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " %c", &state) != 1)
+ return -EIO;
+
+ return (unsigned char) state;
+}
+
+int get_process_comm(pid_t pid, char **name) {
+ const char *p;
+ int r;
+
+ assert(name);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "comm");
+
+ r = read_one_line_file(p, name);
+ if (r == -ENOENT)
+ return -ESRCH;
+
+ return r;
+}
+
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char *r = NULL, *k;
+ const char *p;
+ int c;
+
+ assert(line);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cmdline");
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ if (max_length == 0) {
+ size_t len = 0, allocated = 0;
+
+ while ((c = getc(f)) != EOF) {
+
+ if (!GREEDY_REALLOC(r, allocated, len+2)) {
+ free(r);
+ return -ENOMEM;
+ }
+
+ r[len++] = isprint(c) ? c : ' ';
+ }
+
+ if (len > 0)
+ r[len-1] = 0;
+
+ } else {
+ bool space = false;
+ size_t left;
+
+ r = new(char, max_length);
+ if (!r)
+ return -ENOMEM;
+
+ k = r;
+ left = max_length;
+ while ((c = getc(f)) != EOF) {
+
+ if (isprint(c)) {
+ if (space) {
+ if (left <= 4)
+ break;
+
+ *(k++) = ' ';
+ left--;
+ space = false;
+ }
+
+ if (left <= 4)
+ break;
+
+ *(k++) = (char) c;
+ left--;
+ } else
+ space = true;
+ }
+
+ if (left <= 4) {
+ size_t n = MIN(left-1, 3U);
+ memcpy(k, "...", n);
+ k[n] = 0;
+ } else
+ *k = 0;
+ }
+
+ /* Kernel threads have no argv[] */
+ if (isempty(r)) {
+ _cleanup_free_ char *t = NULL;
+ int h;
+
+ free(r);
+
+ if (!comm_fallback)
+ return -ENOENT;
+
+ h = get_process_comm(pid, &t);
+ if (h < 0)
+ return h;
+
+ r = strjoin("[", t, "]", NULL);
+ if (!r)
+ return -ENOMEM;
+ }
+
+ *line = r;
+ return 0;
+}
+
+int is_kernel_thread(pid_t pid) {
+ const char *p;
+ size_t count;
+ char c;
+ bool eof;
+ FILE *f;
+
+ if (pid == 0)
+ return 0;
+
+ assert(pid > 0);
+
+ p = procfs_file_alloca(pid, "cmdline");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ count = fread(&c, 1, 1, f);
+ eof = feof(f);
+ fclose(f);
+
+ /* Kernel threads have an empty cmdline */
+
+ if (count <= 0)
+ return eof ? 1 : -errno;
+
+ return 0;
+}
+
+int get_process_capeff(pid_t pid, char **capeff) {
+ const char *p;
+
+ assert(capeff);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "status");
+
+ return get_status_field(p, "\nCapEff:", capeff);
+}
+
+static int get_process_link_contents(const char *proc_file, char **name) {
+ int r;
+
+ assert(proc_file);
+ assert(name);
+
+ r = readlink_malloc(proc_file, name);
+ if (r < 0)
+ return r == -ENOENT ? -ESRCH : r;
+
+ return 0;
+}
+
+int get_process_exe(pid_t pid, char **name) {
+ const char *p;
+ char *d;
+ int r;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "exe");
+ r = get_process_link_contents(p, name);
+ if (r < 0)
+ return r;
+
+ d = endswith(*name, " (deleted)");
+ if (d)
+ *d = '\0';
+
+ return 0;
+}
+
+static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char line[LINE_MAX];
+ const char *p;
+
+ assert(field);
+ assert(uid);
+
+ if (pid == 0)
+ return getuid();
+
+ p = procfs_file_alloca(pid, "status");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ FOREACH_LINE(line, f, return -errno) {
+ char *l;
+
+ l = strstrip(line);
+
+ if (startswith(l, field)) {
+ l += strlen(field);
+ l += strspn(l, WHITESPACE);
+
+ l[strcspn(l, WHITESPACE)] = 0;
+
+ return parse_uid(l, uid);
+ }
+ }
+
+ return -EIO;
+}
+
+int get_process_uid(pid_t pid, uid_t *uid) {
+ return get_process_id(pid, "Uid:", uid);
+}
+
+int get_process_gid(pid_t pid, gid_t *gid) {
+ assert_cc(sizeof(uid_t) == sizeof(gid_t));
+ return get_process_id(pid, "Gid:", gid);
+}
+
+int get_process_cwd(pid_t pid, char **cwd) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cwd");
+
+ return get_process_link_contents(p, cwd);
+}
+
+int get_process_root(pid_t pid, char **root) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "root");
+
+ return get_process_link_contents(p, root);
+}
+
+int get_process_environ(pid_t pid, char **env) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *outcome = NULL;
+ int c;
+ const char *p;
+ size_t allocated = 0, sz = 0;
+
+ assert(pid >= 0);
+ assert(env);
+
+ p = procfs_file_alloca(pid, "environ");
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
+ return -ENOMEM;
+
+ if (c == '\0')
+ outcome[sz++] = '\n';
+ else
+ sz += cescape_char(c, outcome + sz);
+ }
+
+ outcome[sz] = '\0';
+ *env = outcome;
+ outcome = NULL;
+
+ return 0;
+}
+
+int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
+ int r;
+ _cleanup_free_ char *line = NULL;
+ long unsigned ppid;
+ const char *p;
+
+ assert(pid >= 0);
+ assert(_ppid);
+
+ if (pid == 0) {
+ *_ppid = getppid();
+ return 0;
+ }
+
+ p = procfs_file_alloca(pid, "stat");
+ r = read_one_line_file(p, &line);
+ if (r < 0)
+ return r;
+
+ /* Let's skip the pid and comm fields. The latter is enclosed
+ * in () but does not escape any () in its value, so let's
+ * skip over it manually */
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " "
+ "%*c " /* state */
+ "%lu ", /* ppid */
+ &ppid) != 1)
+ return -EIO;
+
+ if ((long unsigned) (pid_t) ppid != ppid)
+ return -ERANGE;
+
+ *_ppid = (pid_t) ppid;
+
+ return 0;
+}
+
+int wait_for_terminate(pid_t pid, siginfo_t *status) {
+ siginfo_t dummy;
+
+ assert(pid >= 1);
+
+ if (!status)
+ status = &dummy;
+
+ for (;;) {
+ zero(*status);
+
+ if (waitid(P_PID, pid, status, WEXITED) < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+ }
+
+ return 0;
+ }
+}
+
+/*
+ * Return values:
+ * < 0 : wait_for_terminate() failed to get the state of the
+ * process, the process was terminated by a signal, or
+ * failed for an unknown reason.
+ * >=0 : The process terminated normally, and its exit code is
+ * returned.
+ *
+ * That is, success is indicated by a return value of zero, and an
+ * error is indicated by a non-zero value.
+ *
+ * A warning is emitted if the process terminates abnormally,
+ * and also if it returns non-zero unless check_exit_code is true.
+ */
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
+ int r;
+ siginfo_t status;
+
+ assert(name);
+ assert(pid > 1);
+
+ r = wait_for_terminate(pid, &status);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for %s: %m", name);
+
+ if (status.si_code == CLD_EXITED) {
+ if (status.si_status != 0)
+ log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
+ "%s failed with error code %i.", name, status.si_status);
+ else
+ log_debug("%s succeeded.", name);
+
+ return status.si_status;
+ } else if (status.si_code == CLD_KILLED ||
+ status.si_code == CLD_DUMPED) {
+
+ log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
+ return -EPROTO;
+ }
+
+ log_warning("%s failed due to unknown reason.", name);
+ return -EPROTO;
+}
+
+int kill_and_sigcont(pid_t pid, int sig) {
+ int r;
+
+ r = kill(pid, sig) < 0 ? -errno : 0;
+
+ if (r >= 0)
+ kill(pid, SIGCONT);
+
+ return r;
+}
+
+int getenv_for_pid(pid_t pid, const char *field, char **_value) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char *value = NULL;
+ int r;
+ bool done = false;
+ size_t l;
+ const char *path;
+
+ assert(pid >= 0);
+ assert(field);
+ assert(_value);
+
+ path = procfs_file_alloca(pid, "environ");
+
+ f = fopen(path, "re");
+ if (!f)
+ return -errno;
+
+ l = strlen(field);
+ r = 0;
+
+ do {
+ char line[LINE_MAX];
+ unsigned i;
+
+ for (i = 0; i < sizeof(line)-1; i++) {
+ int c;
+
+ c = getc(f);
+ if (_unlikely_(c == EOF)) {
+ done = true;
+ break;
+ } else if (c == 0)
+ break;
+
+ line[i] = c;
+ }
+ line[i] = 0;
+
+ if (memcmp(line, field, l) == 0 && line[l] == '=') {
+ value = strdup(line + l + 1);
+ if (!value)
+ return -ENOMEM;
+
+ r = 1;
+ break;
+ }
+
+ } while (!done);
+
+ *_value = value;
+ return r;
+}
+
+bool pid_is_unwaited(pid_t pid) {
+ /* Checks whether a PID is still valid at all, including a zombie */
+
+ if (pid <= 0)
+ return false;
+
+ if (kill(pid, 0) >= 0)
+ return true;
+
+ return errno != ESRCH;
+}
+
+bool pid_is_alive(pid_t pid) {
+ int r;
+
+ /* Checks whether a PID is still valid and not a zombie */
+
+ if (pid <= 0)
+ return false;
+
+ r = get_process_state(pid);
+ if (r == -ENOENT || r == 'Z')
+ return false;
+
+ return true;
+}
diff --git a/src/shared/process-util.h b/src/shared/process-util.h
new file mode 100644
index 0000000000..07431d043b
--- /dev/null
+++ b/src/shared/process-util.h
@@ -0,0 +1,65 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <alloca.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "formats-util.h"
+
+#define procfs_file_alloca(pid, field) \
+ ({ \
+ pid_t _pid_ = (pid); \
+ const char *_r_; \
+ if (_pid_ == 0) { \
+ _r_ = ("/proc/self/" field); \
+ } else { \
+ _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
+ sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
+ } \
+ _r_; \
+ })
+
+int get_process_state(pid_t pid);
+int get_process_comm(pid_t pid, char **name);
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
+int get_process_exe(pid_t pid, char **name);
+int get_process_uid(pid_t pid, uid_t *uid);
+int get_process_gid(pid_t pid, gid_t *gid);
+int get_process_capeff(pid_t pid, char **capeff);
+int get_process_cwd(pid_t pid, char **cwd);
+int get_process_root(pid_t pid, char **root);
+int get_process_environ(pid_t pid, char **environ);
+
+int wait_for_terminate(pid_t pid, siginfo_t *status);
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
+
+int kill_and_sigcont(pid_t pid, int sig);
+pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
+void rename_process(const char name[8]);
+int is_kernel_thread(pid_t pid);
+int getenv_for_pid(pid_t pid, const char *field, char **_value);
+
+bool pid_is_alive(pid_t pid);
+bool pid_is_unwaited(pid_t pid);
diff --git a/src/shared/pty.c b/src/shared/pty.c
index fbe6295ea5..119d66e9a2 100644
--- a/src/shared/pty.c
+++ b/src/shared/pty.c
@@ -44,18 +44,12 @@
#include <errno.h>
#include <fcntl.h>
-#include <limits.h>
-#include <linux/ioctl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/epoll.h>
-#include <sys/eventfd.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <termios.h>
@@ -63,9 +57,10 @@
#include "barrier.h"
#include "macro.h"
-#include "pty.h"
#include "ring.h"
#include "util.h"
+#include "signal-util.h"
+#include "pty.h"
#define PTY_BUFSIZE 4096
diff --git a/src/shared/pty.h b/src/shared/pty.h
index a87ceb58ca..63c7db2833 100644
--- a/src/shared/pty.h
+++ b/src/shared/pty.h
@@ -21,17 +21,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
#include "barrier.h"
#include "macro.h"
#include "sd-event.h"
-#include "util.h"
typedef struct Pty Pty;
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 31274a1418..789f217efc 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -20,7 +20,6 @@
***/
#include <sys/epoll.h>
-#include <sys/signalfd.h>
#include <sys/ioctl.h>
#include <limits.h>
#include <termios.h>
@@ -42,6 +41,8 @@ struct PTYForward {
struct termios saved_stdin_attr;
struct termios saved_stdout_attr;
+ bool read_only:1;
+
bool saved_stdin:1;
bool saved_stdout:1;
@@ -298,7 +299,13 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
return 0;
}
-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward **ret) {
+int pty_forward_new(
+ sd_event *event,
+ int master,
+ bool ignore_vhangup,
+ bool read_only,
+ PTYForward **ret) {
+
_cleanup_(pty_forward_freep) PTYForward *f = NULL;
struct winsize ws;
int r;
@@ -307,6 +314,7 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward
if (!f)
return -ENOMEM;
+ f->read_only = read_only;
f->ignore_vhangup = ignore_vhangup;
if (event)
@@ -317,13 +325,15 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward
return r;
}
- r = fd_nonblock(STDIN_FILENO, true);
- if (r < 0)
- return r;
+ if (!read_only) {
+ r = fd_nonblock(STDIN_FILENO, true);
+ if (r < 0)
+ return r;
- r = fd_nonblock(STDOUT_FILENO, true);
- if (r < 0)
- return r;
+ r = fd_nonblock(STDOUT_FILENO, true);
+ if (r < 0)
+ return r;
+ }
r = fd_nonblock(master, true);
if (r < 0)
@@ -332,38 +342,36 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward
f->master = master;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
- (void)ioctl(master, TIOCSWINSZ, &ws);
-
- if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
- struct termios raw_stdin_attr;
+ (void) ioctl(master, TIOCSWINSZ, &ws);
- f->saved_stdin = true;
+ if (!read_only) {
+ if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
+ struct termios raw_stdin_attr;
- raw_stdin_attr = f->saved_stdin_attr;
- cfmakeraw(&raw_stdin_attr);
- raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag;
- tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
- }
+ f->saved_stdin = true;
- if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) {
- struct termios raw_stdout_attr;
+ raw_stdin_attr = f->saved_stdin_attr;
+ cfmakeraw(&raw_stdin_attr);
+ raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag;
+ tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
+ }
- f->saved_stdout = true;
+ if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) {
+ struct termios raw_stdout_attr;
- raw_stdout_attr = f->saved_stdout_attr;
- cfmakeraw(&raw_stdout_attr);
- raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag;
- raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag;
- tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
- }
+ f->saved_stdout = true;
- r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f);
- if (r < 0)
- return r;
+ raw_stdout_attr = f->saved_stdout_attr;
+ cfmakeraw(&raw_stdout_attr);
+ raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag;
+ raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag;
+ tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
+ }
- r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
- if (r < 0 && r != -EPERM)
- return r;
+ r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
+ if (r < 0 && r != -EPERM)
+ return r;
+ }
r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f);
if (r == -EPERM)
@@ -372,6 +380,10 @@ int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward
else if (r < 0)
return r;
+ r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f);
+ if (r < 0)
+ return r;
+
r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
if (r < 0)
return r;
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index d3e229bd70..6f84e4036a 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -21,16 +21,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <signal.h>
#include <stdbool.h>
-#include "util.h"
#include "sd-event.h"
typedef struct PTYForward PTYForward;
-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, PTYForward **f);
+int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f);
PTYForward *pty_forward_free(PTYForward *f);
int pty_forward_get_last_char(PTYForward *f, char *ch);
diff --git a/src/shared/random-util.c b/src/shared/random-util.c
new file mode 100644
index 0000000000..b230044f50
--- /dev/null
+++ b/src/shared/random-util.c
@@ -0,0 +1,129 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+#include <linux/random.h>
+
+#include "random-util.h"
+#include "time-util.h"
+#include "missing.h"
+#include "util.h"
+
+int dev_urandom(void *p, size_t n) {
+ static int have_syscall = -1;
+
+ _cleanup_close_ int fd = -1;
+ int r;
+
+ /* Gathers some randomness from the kernel. This call will
+ * never block, and will always return some data from the
+ * kernel, regardless if the random pool is fully initialized
+ * or not. It thus makes no guarantee for the quality of the
+ * returned entropy, but is good enough for or usual usecases
+ * of seeding the hash functions for hashtable */
+
+ /* Use the getrandom() syscall unless we know we don't have
+ * it, or when the requested size is too large for it. */
+ if (have_syscall != 0 || (size_t) (int) n != n) {
+ r = getrandom(p, n, GRND_NONBLOCK);
+ if (r == (int) n) {
+ have_syscall = true;
+ return 0;
+ }
+
+ if (r < 0) {
+ if (errno == ENOSYS)
+ /* we lack the syscall, continue with
+ * reading from /dev/urandom */
+ have_syscall = false;
+ else if (errno == EAGAIN)
+ /* not enough entropy for now. Let's
+ * remember to use the syscall the
+ * next time, again, but also read
+ * from /dev/urandom for now, which
+ * doesn't care about the current
+ * amount of entropy. */
+ have_syscall = true;
+ else
+ return -errno;
+ } else
+ /* too short read? */
+ return -ENODATA;
+ }
+
+ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return errno == ENOENT ? -ENOSYS : -errno;
+
+ return loop_read_exact(fd, p, n, true);
+}
+
+void initialize_srand(void) {
+ static bool srand_called = false;
+ unsigned x;
+#ifdef HAVE_SYS_AUXV_H
+ void *auxv;
+#endif
+
+ if (srand_called)
+ return;
+
+ x = 0;
+
+#ifdef HAVE_SYS_AUXV_H
+ /* The kernel provides us with a bit of entropy in auxv, so
+ * let's try to make use of that to seed the pseudo-random
+ * generator. It's better than nothing... */
+
+ auxv = (void*) getauxval(AT_RANDOM);
+ if (auxv)
+ x ^= *(unsigned*) auxv;
+#endif
+
+ x ^= (unsigned) now(CLOCK_REALTIME);
+ x ^= (unsigned) gettid();
+
+ srand(x);
+ srand_called = true;
+}
+
+void random_bytes(void *p, size_t n) {
+ uint8_t *q;
+ int r;
+
+ r = dev_urandom(p, n);
+ if (r >= 0)
+ return;
+
+ /* If some idiot made /dev/urandom unavailable to us, he'll
+ * get a PRNG instead. */
+
+ initialize_srand();
+
+ for (q = p; q < (uint8_t*) p + n; q ++)
+ *q = rand();
+}
diff --git a/src/shared/random-util.h b/src/shared/random-util.h
new file mode 100644
index 0000000000..f7862c8c8b
--- /dev/null
+++ b/src/shared/random-util.h
@@ -0,0 +1,38 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdint.h>
+
+int dev_urandom(void *p, size_t n);
+void random_bytes(void *p, size_t n);
+void initialize_srand(void);
+
+static inline uint64_t random_u64(void) {
+ uint64_t u;
+ random_bytes(&u, sizeof(u));
+ return u;
+}
+
+static inline uint32_t random_u32(void) {
+ uint32_t u;
+ random_bytes(&u, sizeof(u));
+ return u;
+}
diff --git a/src/shared/ratelimit.c b/src/shared/ratelimit.c
index 01b62b7b38..81fc9c19ff 100644
--- a/src/shared/ratelimit.c
+++ b/src/shared/ratelimit.c
@@ -19,10 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include "ratelimit.h"
-#include "log.h"
/* Modelled after Linux' lib/ratelimit.c by Dave Young
* <hidave.darkstar@gmail.com>, which is licensed GPLv2. */
diff --git a/src/shared/ring.c b/src/shared/ring.c
index 309075e348..6814918464 100644
--- a/src/shared/ring.c
+++ b/src/shared/ring.c
@@ -20,7 +20,6 @@
***/
#include <errno.h>
-#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
diff --git a/src/shared/ring.h b/src/shared/ring.h
index 1210aabdf6..a7c44d1b56 100644
--- a/src/shared/ring.h
+++ b/src/shared/ring.h
@@ -21,11 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/uio.h>
typedef struct Ring Ring;
diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c
new file mode 100644
index 0000000000..bafd483be2
--- /dev/null
+++ b/src/shared/rm-rf.c
@@ -0,0 +1,224 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "path-util.h"
+#include "btrfs-util.h"
+#include "rm-rf.h"
+
+int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
+ _cleanup_closedir_ DIR *d = NULL;
+ int ret = 0, r;
+
+ assert(fd >= 0);
+
+ /* This returns the first error we run into, but nevertheless
+ * tries to go on. This closes the passed fd. */
+
+ if (!(flags & REMOVE_PHYSICAL)) {
+
+ r = fd_is_temporary_fs(fd);
+ if (r < 0) {
+ safe_close(fd);
+ return r;
+ }
+
+ if (!r) {
+ /* We refuse to clean physical file systems
+ * with this call, unless explicitly
+ * requested. This is extra paranoia just to
+ * be sure we never ever remove non-state
+ * data */
+
+ log_error("Attempted to remove disk file system, and we can't allow that.");
+ safe_close(fd);
+ return -EPERM;
+ }
+ }
+
+ d = fdopendir(fd);
+ if (!d) {
+ safe_close(fd);
+ return errno == ENOENT ? 0 : -errno;
+ }
+
+ for (;;) {
+ struct dirent *de;
+ bool is_dir;
+ struct stat st;
+
+ errno = 0;
+ de = readdir(d);
+ if (!de) {
+ if (errno != 0 && ret == 0)
+ ret = -errno;
+ return ret;
+ }
+
+ if (streq(de->d_name, ".") || streq(de->d_name, ".."))
+ continue;
+
+ if (de->d_type == DT_UNKNOWN ||
+ (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
+ if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ continue;
+ }
+
+ is_dir = S_ISDIR(st.st_mode);
+ } else
+ is_dir = de->d_type == DT_DIR;
+
+ if (is_dir) {
+ int subdir_fd;
+
+ /* if root_dev is set, remove subdirectories only if device is same */
+ if (root_dev && st.st_dev != root_dev->st_dev)
+ continue;
+
+ subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (subdir_fd < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ continue;
+ }
+
+ /* Stop at mount points */
+ r = fd_is_mount_point(fd, de->d_name, 0);
+ if (r < 0) {
+ if (ret == 0 && r != -ENOENT)
+ ret = r;
+
+ safe_close(subdir_fd);
+ continue;
+ }
+ if (r) {
+ safe_close(subdir_fd);
+ continue;
+ }
+
+ if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
+
+ /* This could be a subvolume, try to remove it */
+
+ r = btrfs_subvol_remove_fd(fd, de->d_name, true);
+ if (r < 0) {
+ if (r != -ENOTTY && r != -EINVAL) {
+ if (ret == 0)
+ ret = r;
+
+ safe_close(subdir_fd);
+ continue;
+ }
+
+ /* ENOTTY, then it wasn't a
+ * btrfs subvolume, continue
+ * below. */
+ } else {
+ /* It was a subvolume, continue. */
+ safe_close(subdir_fd);
+ continue;
+ }
+ }
+
+ /* We pass REMOVE_PHYSICAL here, to avoid
+ * doing the fstatfs() to check the file
+ * system type again for each directory */
+ r = rm_rf_children(subdir_fd, flags | REMOVE_PHYSICAL, root_dev);
+ if (r < 0 && ret == 0)
+ ret = r;
+
+ if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ }
+
+ } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
+
+ if (unlinkat(fd, de->d_name, 0) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ }
+ }
+ }
+}
+
+int rm_rf(const char *path, RemoveFlags flags) {
+ int fd, r;
+ struct statfs s;
+
+ assert(path);
+
+ /* We refuse to clean the root file system with this
+ * call. This is extra paranoia to never cause a really
+ * seriously broken system. */
+ if (path_equal(path, "/")) {
+ log_error("Attempted to remove entire root file system, and we can't allow that.");
+ return -EPERM;
+ }
+
+ if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
+ /* Try to remove as subvolume first */
+ r = btrfs_subvol_remove(path, true);
+ if (r >= 0)
+ return r;
+
+ if (r != -ENOTTY && r != -EINVAL)
+ return r;
+
+ /* Not btrfs or not a subvolume */
+ }
+
+ fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (fd < 0) {
+
+ if (errno != ENOTDIR && errno != ELOOP)
+ return -errno;
+
+ if (!(flags & REMOVE_PHYSICAL)) {
+ if (statfs(path, &s) < 0)
+ return -errno;
+
+ if (!is_temporary_fs(&s)) {
+ log_error("Attempted to remove disk file system, and we can't allow that.");
+ return -EPERM;
+ }
+ }
+
+ if ((flags & REMOVE_ROOT) && !(flags & REMOVE_ONLY_DIRECTORIES))
+ if (unlink(path) < 0 && errno != ENOENT)
+ return -errno;
+
+ return 0;
+ }
+
+ r = rm_rf_children(fd, flags, NULL);
+
+ if (flags & REMOVE_ROOT) {
+ if (rmdir(path) < 0) {
+ if (r == 0 && errno != ENOENT)
+ r = -errno;
+ }
+ }
+
+ return r;
+}
diff --git a/src/shared/rm-rf.h b/src/shared/rm-rf.h
new file mode 100644
index 0000000000..96579eb182
--- /dev/null
+++ b/src/shared/rm-rf.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/stat.h>
+
+typedef enum RemoveFlags {
+ REMOVE_ONLY_DIRECTORIES = 1,
+ REMOVE_ROOT = 2,
+ REMOVE_PHYSICAL = 4, /* if not set, only removes files on tmpfs, never physical file systems */
+ REMOVE_SUBVOLUME = 8,
+} RemoveFlags;
+
+int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
+int rm_rf(const char *path, RemoveFlags flags);
diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c
index a2233e0cfb..7c58985cd2 100644
--- a/src/shared/selinux-util.c
+++ b/src/shared/selinux-util.c
@@ -20,7 +20,6 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <malloc.h>
#include <sys/un.h>
@@ -117,6 +116,7 @@ void mac_selinux_finish(void) {
return;
selabel_close(label_hnd);
+ label_hnd = NULL;
#endif
}
@@ -146,7 +146,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
r = lsetfilecon(path, fcon);
/* If the FS doesn't support labels, then exit without warning */
- if (r < 0 && errno == ENOTSUP)
+ if (r < 0 && errno == EOPNOTSUPP)
return 0;
}
}
diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h
index a694441000..8467185291 100644
--- a/src/shared/selinux-util.h
+++ b/src/shared/selinux-util.h
@@ -22,7 +22,6 @@
***/
#include <sys/socket.h>
-#include <stdio.h>
#include <stdbool.h>
bool mac_selinux_use(void);
diff --git a/src/shared/set.h b/src/shared/set.h
index 2b49e2f287..4dffecd39d 100644
--- a/src/shared/set.h
+++ b/src/shared/set.h
@@ -57,7 +57,7 @@ static inline bool set_contains(Set *s, const void *key) {
return internal_hashmap_contains(HASHMAP_BASE(s), key);
}
-static inline void *set_remove(Set *s, void *key) {
+static inline void *set_remove(Set *s, const void *key) {
return internal_hashmap_remove(HASHMAP_BASE(s), key);
}
diff --git a/src/shared/signal-util.c b/src/shared/signal-util.c
new file mode 100644
index 0000000000..9a2973b6fd
--- /dev/null
+++ b/src/shared/signal-util.c
@@ -0,0 +1,228 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "signal-util.h"
+
+int reset_all_signal_handlers(void) {
+ int sig, r = 0;
+
+ for (sig = 1; sig < _NSIG; sig++) {
+ static const struct sigaction sa = {
+ .sa_handler = SIG_DFL,
+ .sa_flags = SA_RESTART,
+ };
+
+ /* These two cannot be caught... */
+ if (sig == SIGKILL || sig == SIGSTOP)
+ continue;
+
+ /* On Linux the first two RT signals are reserved by
+ * glibc, and sigaction() will return EINVAL for them. */
+ if ((sigaction(sig, &sa, NULL) < 0))
+ if (errno != EINVAL && r == 0)
+ r = -errno;
+ }
+
+ return r;
+}
+
+int reset_signal_mask(void) {
+ sigset_t ss;
+
+ if (sigemptyset(&ss) < 0)
+ return -errno;
+
+ if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int sigaction_many(const struct sigaction *sa, ...) {
+ va_list ap;
+ int r = 0, sig;
+
+ va_start(ap, sa);
+ while ((sig = va_arg(ap, int)) > 0)
+ if (sigaction(sig, sa, NULL) < 0)
+ r = -errno;
+ va_end(ap);
+
+ return r;
+}
+
+int ignore_signals(int sig, ...) {
+ static const struct sigaction sa = {
+ .sa_handler = SIG_IGN,
+ .sa_flags = SA_RESTART,
+ };
+ va_list ap;
+ int r = 0;
+
+ if (sigaction(sig, &sa, NULL) < 0)
+ r = -errno;
+
+ va_start(ap, sig);
+ while ((sig = va_arg(ap, int)) > 0)
+ if (sigaction(sig, &sa, NULL) < 0)
+ r = -errno;
+ va_end(ap);
+
+ return r;
+}
+
+int default_signals(int sig, ...) {
+ static const struct sigaction sa = {
+ .sa_handler = SIG_DFL,
+ .sa_flags = SA_RESTART,
+ };
+ va_list ap;
+ int r = 0;
+
+ if (sigaction(sig, &sa, NULL) < 0)
+ r = -errno;
+
+ va_start(ap, sig);
+ while ((sig = va_arg(ap, int)) > 0)
+ if (sigaction(sig, &sa, NULL) < 0)
+ r = -errno;
+ va_end(ap);
+
+ return r;
+}
+
+void sigset_add_many(sigset_t *ss, ...) {
+ va_list ap;
+ int sig;
+
+ assert(ss);
+
+ va_start(ap, ss);
+ while ((sig = va_arg(ap, int)) > 0)
+ assert_se(sigaddset(ss, sig) == 0);
+ va_end(ap);
+}
+
+int sigprocmask_many(int how, ...) {
+ va_list ap;
+ sigset_t ss;
+ int sig;
+
+ assert_se(sigemptyset(&ss) == 0);
+
+ va_start(ap, how);
+ while ((sig = va_arg(ap, int)) > 0)
+ assert_se(sigaddset(&ss, sig) == 0);
+ va_end(ap);
+
+ if (sigprocmask(how, &ss, NULL) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static const char *const __signal_table[] = {
+ [SIGHUP] = "HUP",
+ [SIGINT] = "INT",
+ [SIGQUIT] = "QUIT",
+ [SIGILL] = "ILL",
+ [SIGTRAP] = "TRAP",
+ [SIGABRT] = "ABRT",
+ [SIGBUS] = "BUS",
+ [SIGFPE] = "FPE",
+ [SIGKILL] = "KILL",
+ [SIGUSR1] = "USR1",
+ [SIGSEGV] = "SEGV",
+ [SIGUSR2] = "USR2",
+ [SIGPIPE] = "PIPE",
+ [SIGALRM] = "ALRM",
+ [SIGTERM] = "TERM",
+#ifdef SIGSTKFLT
+ [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
+#endif
+ [SIGCHLD] = "CHLD",
+ [SIGCONT] = "CONT",
+ [SIGSTOP] = "STOP",
+ [SIGTSTP] = "TSTP",
+ [SIGTTIN] = "TTIN",
+ [SIGTTOU] = "TTOU",
+ [SIGURG] = "URG",
+ [SIGXCPU] = "XCPU",
+ [SIGXFSZ] = "XFSZ",
+ [SIGVTALRM] = "VTALRM",
+ [SIGPROF] = "PROF",
+ [SIGWINCH] = "WINCH",
+ [SIGIO] = "IO",
+ [SIGPWR] = "PWR",
+ [SIGSYS] = "SYS"
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
+
+const char *signal_to_string(int signo) {
+ static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
+ const char *name;
+
+ name = __signal_to_string(signo);
+ if (name)
+ return name;
+
+ if (signo >= SIGRTMIN && signo <= SIGRTMAX)
+ snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
+ else
+ snprintf(buf, sizeof(buf), "%d", signo);
+
+ return buf;
+}
+
+int signal_from_string(const char *s) {
+ int signo;
+ int offset = 0;
+ unsigned u;
+
+ signo = __signal_from_string(s);
+ if (signo > 0)
+ return signo;
+
+ if (startswith(s, "RTMIN+")) {
+ s += 6;
+ offset = SIGRTMIN;
+ }
+ if (safe_atou(s, &u) >= 0) {
+ signo = (int) u + offset;
+ if (signo > 0 && signo < _NSIG)
+ return signo;
+ }
+ return -EINVAL;
+}
+
+int signal_from_string_try_harder(const char *s) {
+ int signo;
+ assert(s);
+
+ signo = signal_from_string(s);
+ if (signo <= 0)
+ if (startswith(s, "SIG"))
+ return signal_from_string(s+3);
+
+ return signo;
+}
diff --git a/src/shared/signal-util.h b/src/shared/signal-util.h
new file mode 100644
index 0000000000..ddf64cda76
--- /dev/null
+++ b/src/shared/signal-util.h
@@ -0,0 +1,41 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <signal.h>
+
+#include "macro.h"
+
+int reset_all_signal_handlers(void);
+int reset_signal_mask(void);
+
+int ignore_signals(int sig, ...);
+int default_signals(int sig, ...);
+int sigaction_many(const struct sigaction *sa, ...);
+
+void sigset_add_many(sigset_t *ss, ...);
+int sigprocmask_many(int how, ...);
+
+const char *signal_to_string(int i) _const_;
+int signal_from_string(const char *s) _pure_;
+
+int signal_from_string_try_harder(const char *s);
diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c
index 64e213489e..2e24b1ea99 100644
--- a/src/shared/smack-util.c
+++ b/src/shared/smack-util.c
@@ -24,6 +24,7 @@
#include <sys/xattr.h>
#include "util.h"
+#include "process-util.h"
#include "path-util.h"
#include "fileio.h"
#include "smack-util.h"
@@ -187,7 +188,7 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
r = lsetxattr(path, "security.SMACK64", label, strlen(label), 0);
/* If the FS doesn't support labels, then exit without warning */
- if (r < 0 && errno == ENOTSUP)
+ if (r < 0 && errno == EOPNOTSUPP)
return 0;
}
diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c
index 6806c51158..cbe3ff216e 100644
--- a/src/shared/socket-label.c
+++ b/src/shared/socket-label.c
@@ -19,24 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <net/if.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <stddef.h>
-#include <sys/ioctl.h>
#include "macro.h"
#include "util.h"
#include "mkdir.h"
#include "missing.h"
-#include "label.h"
#include "selinux-util.h"
#include "socket-util.h"
@@ -117,9 +109,6 @@ int socket_address_listen(
/* Enforce the right access mode for the socket */
old_mask = umask(~ socket_mode);
- /* Include the original umask in our mask */
- umask(~socket_mode | old_mask);
-
r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
if (r < 0 && errno == EADDRINUSE) {
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index c6f64876be..e8bb10dc9b 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -19,27 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <net/if.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <stddef.h>
-#include <sys/ioctl.h>
#include <netdb.h>
#include "macro.h"
-#include "util.h"
-#include "mkdir.h"
#include "path-util.h"
+#include "util.h"
#include "socket-util.h"
#include "missing.h"
#include "fileio.h"
+#include "formats-util.h"
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
@@ -55,11 +51,6 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (*s == '[') {
/* IPv6 in [x:.....:z]:p notation */
- if (!socket_ipv6_is_supported()) {
- log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
- return -EAFNOSUPPORT;
- }
-
e = strchr(s+1, ']');
if (!e)
return -EINVAL;
@@ -144,11 +135,6 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (idx == 0)
return -EINVAL;
- if (!socket_ipv6_is_supported()) {
- log_warning("Binding to interface is not available since kernel does not support IPv6.");
- return -EAFNOSUPPORT;
- }
-
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htons((uint16_t) u);
a->sockaddr.in6.sin6_scope_id = idx;
@@ -182,6 +168,25 @@ int socket_address_parse(SocketAddress *a, const char *s) {
return 0;
}
+int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
+ SocketAddress b;
+ int r;
+
+ /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
+
+ r = socket_address_parse(&b, s);
+ if (r < 0)
+ return r;
+
+ if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
+ log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
+ return -EAFNOSUPPORT;
+ }
+
+ *a = b;
+ return 0;
+}
+
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
int family;
unsigned group = 0;
@@ -302,7 +307,7 @@ int socket_address_print(const SocketAddress *a, char **ret) {
return 0;
}
- return sockaddr_pretty(&a->sockaddr.sa, a->size, false, ret);
+ return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
}
bool socket_address_can_accept(const SocketAddress *a) {
@@ -325,9 +330,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
if (a->type != b->type)
return false;
- if (a->size != b->size)
- return false;
-
if (socket_address_family(a) != socket_address_family(b))
return false;
@@ -352,14 +354,20 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
break;
case AF_UNIX:
+ if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
+ b->size <= offsetof(struct sockaddr_un, sun_path))
+ return false;
if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
return false;
if (a->sockaddr.un.sun_path[0]) {
- if (!strneq(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)))
+ if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
return false;
} else {
+ if (a->size != b->size)
+ return false;
+
if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
return false;
}
@@ -367,7 +375,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
break;
case AF_NETLINK:
-
if (a->protocol != b->protocol)
return false;
@@ -437,57 +444,55 @@ bool socket_ipv6_is_supported(void) {
}
bool socket_address_matches_fd(const SocketAddress *a, int fd) {
- union sockaddr_union sa;
- socklen_t salen = sizeof(sa), solen;
- int protocol, type;
+ SocketAddress b;
+ socklen_t solen;
assert(a);
assert(fd >= 0);
- if (getsockname(fd, &sa.sa, &salen) < 0)
+ b.size = sizeof(b.sockaddr);
+ if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
return false;
- if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
+ if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
return false;
- solen = sizeof(type);
- if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
+ solen = sizeof(b.type);
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
return false;
- if (type != a->type)
+ if (b.type != a->type)
return false;
if (a->protocol != 0) {
- solen = sizeof(protocol);
- if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
+ solen = sizeof(b.protocol);
+ if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
return false;
- if (protocol != a->protocol)
+ if (b.protocol != a->protocol)
return false;
}
- switch (sa.sa.sa_family) {
-
- case AF_INET:
- return sa.in.sin_port == a->sockaddr.in.sin_port &&
- sa.in.sin_addr.s_addr == a->sockaddr.in.sin_addr.s_addr;
+ return socket_address_equal(a, &b);
+}
- case AF_INET6:
- return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
- memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
+int sockaddr_port(const struct sockaddr *_sa) {
+ union sockaddr_union *sa = (union sockaddr_union*) _sa;
- case AF_UNIX:
- return salen == a->size &&
- memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
+ assert(sa);
- }
+ if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
+ return -EAFNOSUPPORT;
- return false;
+ return ntohs(sa->sa.sa_family == AF_INET6 ?
+ sa->in6.sin6_port :
+ sa->in.sin_port);
}
-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret) {
+int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
union sockaddr_union *sa = (union sockaddr_union*) _sa;
char *p;
+ int r;
assert(sa);
assert(salen >= sizeof(sa->sa.sa_family));
@@ -499,12 +504,17 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
a = ntohl(sa->in.sin_addr.s_addr);
- if (asprintf(&p,
- "%u.%u.%u.%u:%u",
- a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
- ntohs(sa->in.sin_port)) < 0)
+ if (include_port)
+ r = asprintf(&p,
+ "%u.%u.%u.%u:%u",
+ a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
+ ntohs(sa->in.sin_port));
+ else
+ r = asprintf(&p,
+ "%u.%u.%u.%u",
+ a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
+ if (r < 0)
return -ENOMEM;
-
break;
}
@@ -513,22 +523,37 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
};
- if (translate_ipv6 && memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
+ if (translate_ipv6 &&
+ memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
-
- if (asprintf(&p,
- "%u.%u.%u.%u:%u",
- a[0], a[1], a[2], a[3],
- ntohs(sa->in6.sin6_port)) < 0)
+ if (include_port)
+ r = asprintf(&p,
+ "%u.%u.%u.%u:%u",
+ a[0], a[1], a[2], a[3],
+ ntohs(sa->in6.sin6_port));
+ else
+ r = asprintf(&p,
+ "%u.%u.%u.%u",
+ a[0], a[1], a[2], a[3]);
+ if (r < 0)
return -ENOMEM;
} else {
char a[INET6_ADDRSTRLEN];
- if (asprintf(&p,
- "[%s]:%u",
- inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)),
- ntohs(sa->in6.sin6_port)) < 0)
- return -ENOMEM;
+ inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
+
+ if (include_port) {
+ r = asprintf(&p,
+ "[%s]:%u",
+ a,
+ ntohs(sa->in6.sin6_port));
+ if (r < 0)
+ return -ENOMEM;
+ } else {
+ p = strdup(a);
+ if (!p)
+ return -ENOMEM;
+ }
}
break;
@@ -565,7 +590,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
break;
default:
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
@@ -603,7 +628,7 @@ int getpeername_pretty(int fd, char **ret) {
/* For remote sockets we translate IPv6 addresses back to IPv4
* if applicable, since that's nicer. */
- return sockaddr_pretty(&sa.sa, salen, true, ret);
+ return sockaddr_pretty(&sa.sa, salen, true, true, ret);
}
int getsockname_pretty(int fd, char **ret) {
@@ -621,7 +646,7 @@ int getsockname_pretty(int fd, char **ret) {
* listening sockets where the difference between IPv4 and
* IPv6 matters. */
- return sockaddr_pretty(&sa.sa, salen, false, ret);
+ return sockaddr_pretty(&sa.sa, salen, false, true, ret);
}
int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
@@ -635,7 +660,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret)
if (r != 0) {
int saved_errno = errno;
- r = sockaddr_pretty(&sa->sa, salen, true, &ret);
+ r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
if (r < 0)
return log_error_errno(r, "sockadd_pretty() failed: %m");
diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h
index 07d0aff72b..538cf59174 100644
--- a/src/shared/socket-util.h
+++ b/src/shared/socket-util.h
@@ -25,7 +25,6 @@
#include <netinet/in.h>
#include <netinet/ether.h>
#include <sys/un.h>
-#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/if_packet.h>
@@ -67,6 +66,7 @@ typedef enum SocketAddressBindIPv6Only {
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
int socket_address_parse(SocketAddress *a, const char *s);
+int socket_address_parse_and_warn(SocketAddress *a, const char *s);
int socket_address_parse_netlink(SocketAddress *a, const char *s);
int socket_address_print(const SocketAddress *a, char **p);
int socket_address_verify(const SocketAddress *a) _pure_;
@@ -98,7 +98,9 @@ const char* socket_address_get_path(const SocketAddress *a);
bool socket_ipv6_is_supported(void);
-int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret);
+int sockaddr_port(const struct sockaddr *_sa) _pure_;
+
+int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
int getpeername_pretty(int fd, char **ret);
int getsockname_pretty(int fd, char **ret);
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index ee267833e6..70466d17e5 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -19,16 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
-#include <string.h>
-#include <sys/prctl.h>
#include <signal.h>
-#include <fcntl.h>
#include "log.h"
#include "util.h"
+#include "process-util.h"
#include "spawn-ask-password-agent.h"
static pid_t agent_pid = 0;
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
index 8f259a8f39..4db249e1ca 100644
--- a/src/shared/spawn-polkit-agent.c
+++ b/src/shared/spawn-polkit-agent.c
@@ -19,18 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
-#include <string.h>
-#include <sys/prctl.h>
#include <signal.h>
-#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include "log.h"
#include "util.h"
+#include "process-util.h"
#include "spawn-polkit-agent.h"
#ifdef ENABLE_POLKIT
diff --git a/src/shared/special.h b/src/shared/special.h
index b045047d36..e51310eb6d 100644
--- a/src/shared/special.h
+++ b/src/shared/special.h
@@ -42,6 +42,8 @@
/* Special boot targets */
#define SPECIAL_RESCUE_TARGET "rescue.target"
#define SPECIAL_EMERGENCY_TARGET "emergency.target"
+#define SPECIAL_MULTI_USER_TARGET "multi-user.target"
+#define SPECIAL_GRAPHICAL_TARGET "graphical.target"
/* Early boot targets */
#define SPECIAL_SYSINIT_TARGET "sysinit.target"
@@ -108,13 +110,6 @@
#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
-/* For SysV compatibility. Usually an alias for a saner target. On
- * SysV-free systems this doesn't exist. */
-#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target"
-#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
-#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
-#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
-
/* Where we add all our system units, users and machines by default */
#define SPECIAL_SYSTEM_SLICE "system.slice"
#define SPECIAL_USER_SLICE "user.slice"
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index 8fbf6db5df..85bd477f2d 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -24,6 +24,7 @@
#include "macro.h"
#include "util.h"
+#include "hostname-util.h"
#include "specifier.h"
/*
diff --git a/src/shared/strbuf.h b/src/shared/strbuf.h
index 2347fd4328..fbc4e5f2a1 100644
--- a/src/shared/strbuf.h
+++ b/src/shared/strbuf.h
@@ -21,9 +21,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdarg.h>
#include <stdint.h>
-#include <stdbool.h>
struct strbuf {
char *buf;
diff --git a/src/shared/strv.c b/src/shared/strv.c
index e27ac68151..d44a72fc48 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
@@ -81,9 +80,10 @@ void strv_clear(char **l) {
*l = NULL;
}
-void strv_free(char **l) {
+char **strv_free(char **l) {
strv_clear(l);
free(l);
+ return NULL;
}
char **strv_copy(char * const *l) {
@@ -278,7 +278,7 @@ char **strv_split_newlines(const char *s) {
return l;
}
-int strv_split_quoted(char ***t, const char *s, bool relax) {
+int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) {
size_t n = 0, allocated = 0;
_cleanup_strv_free_ char **l = NULL;
int r;
@@ -289,7 +289,7 @@ int strv_split_quoted(char ***t, const char *s, bool relax) {
for (;;) {
_cleanup_free_ char *word = NULL;
- r = unquote_first_word(&s, &word, relax);
+ r = unquote_first_word(&s, &word, flags);
if (r < 0)
return r;
if (r == 0)
diff --git a/src/shared/strv.h b/src/shared/strv.h
index 518c4c2aa8..22f8f98fda 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -31,7 +31,7 @@ char *strv_find(char **l, const char *name) _pure_;
char *strv_find_prefix(char **l, const char *name) _pure_;
char *strv_find_startswith(char **l, const char *name) _pure_;
-void strv_free(char **l);
+char **strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)
@@ -73,7 +73,7 @@ static inline bool strv_isempty(char * const *l) {
char **strv_split(const char *s, const char *separator);
char **strv_split_newlines(const char *s);
-int strv_split_quoted(char ***t, const char *s, bool relax);
+int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags);
char *strv_join(char **l, const char *separator);
char *strv_join_quoted(char **l);
diff --git a/src/shared/strxcpyx.h b/src/shared/strxcpyx.h
index 7be246d570..ccc7e52f37 100644
--- a/src/shared/strxcpyx.h
+++ b/src/shared/strxcpyx.h
@@ -21,8 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdarg.h>
-#include <stdbool.h>
#include "macro.h"
diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c
index 813641ad44..b12189cd10 100644
--- a/src/shared/switch-root.c
+++ b/src/shared/switch-root.c
@@ -29,10 +29,11 @@
#include "util.h"
#include "path-util.h"
-#include "switch-root.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "base-filesystem.h"
#include "missing.h"
+#include "switch-root.h"
int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) {
@@ -104,7 +105,7 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
* to look like. They might even boot, if they are RO and
* don't have the FS layout. Just ignore the error and
* switch_root() nevertheless. */
- (void) base_filesystem_create(new_root);
+ (void) base_filesystem_create(new_root, UID_INVALID, GID_INVALID);
if (chdir(new_root) < 0)
return log_error_errno(errno, "Failed to change directory to %s: %m", new_root);
@@ -142,7 +143,7 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
if (fstat(old_root_fd, &rb) < 0)
log_warning_errno(errno, "Failed to stat old root directory, leaving: %m");
else {
- rm_rf_children(old_root_fd, false, false, &rb);
+ (void) rm_rf_children(old_root_fd, 0, &rb);
old_root_fd = -1;
}
}
diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c
new file mode 100644
index 0000000000..55f4e48601
--- /dev/null
+++ b/src/shared/sysctl-util.c
@@ -0,0 +1,80 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+#include <getopt.h>
+
+#include "log.h"
+#include "util.h"
+#include "fileio.h"
+#include "build.h"
+#include "sysctl-util.h"
+
+char *sysctl_normalize(char *s) {
+ char *n;
+
+ n = strpbrk(s, "/.");
+ /* If the first separator is a slash, the path is
+ * assumed to be normalized and slashes remain slashes
+ * and dots remains dots. */
+ if (!n || *n == '/')
+ return s;
+
+ /* Otherwise, dots become slashes and slashes become
+ * dots. Fun. */
+ while (n) {
+ if (*n == '.')
+ *n = '/';
+ else
+ *n = '.';
+
+ n = strpbrk(n + 1, "/.");
+ }
+
+ return s;
+}
+
+int sysctl_write(const char *property, const char *value) {
+ char *p;
+
+ assert(property);
+ assert(value);
+
+ log_debug("Setting '%s' to '%s'", property, value);
+
+ p = strjoina("/proc/sys/", property);
+ return write_string_file(p, value);
+}
+
+int sysctl_read(const char *property, char **content) {
+ char *p;
+
+ assert(property);
+ assert(content);
+
+ p = strjoina("/proc/sys/", property);
+ return read_full_file(p, content, NULL);
+}
diff --git a/src/boot/boot-loader.h b/src/shared/sysctl-util.h
index b3fcdeedad..2ee6454e52 100644
--- a/src/boot/boot-loader.h
+++ b/src/shared/sysctl-util.h
@@ -5,7 +5,7 @@
/***
This file is part of systemd.
- Copyright 2013 Kay Sievers
+ Copyright 2011 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -21,7 +21,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "boot.h"
+char *sysctl_normalize(char *s);
+int sysctl_read(const char *property, char **value);
+int sysctl_write(const char *property, const char *value);
-int boot_loader_read_entries(struct boot_info *info);
-int boot_loader_find_active_entry(struct boot_info *info, const char *loader_active);
diff --git a/src/shared/terminal-util.c b/src/shared/terminal-util.c
new file mode 100644
index 0000000000..042b88f222
--- /dev/null
+++ b/src/shared/terminal-util.c
@@ -0,0 +1,1072 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <assert.h>
+#include <poll.h>
+#include <linux/vt.h>
+#include <linux/tiocl.h>
+#include <linux/kd.h>
+
+#include "terminal-util.h"
+#include "time-util.h"
+#include "process-util.h"
+#include "util.h"
+#include "fileio.h"
+#include "path-util.h"
+
+static volatile unsigned cached_columns = 0;
+static volatile unsigned cached_lines = 0;
+
+int chvt(int vt) {
+ _cleanup_close_ int fd;
+
+ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ if (vt < 0) {
+ int tiocl[2] = {
+ TIOCL_GETKMSGREDIRECT,
+ 0
+ };
+
+ if (ioctl(fd, TIOCLINUX, tiocl) < 0)
+ return -errno;
+
+ vt = tiocl[0] <= 0 ? 1 : tiocl[0];
+ }
+
+ if (ioctl(fd, VT_ACTIVATE, vt) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
+ struct termios old_termios, new_termios;
+ char c, line[LINE_MAX];
+
+ assert(f);
+ assert(ret);
+
+ if (tcgetattr(fileno(f), &old_termios) >= 0) {
+ new_termios = old_termios;
+
+ new_termios.c_lflag &= ~ICANON;
+ new_termios.c_cc[VMIN] = 1;
+ new_termios.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
+ size_t k;
+
+ if (t != USEC_INFINITY) {
+ if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
+ tcsetattr(fileno(f), TCSADRAIN, &old_termios);
+ return -ETIMEDOUT;
+ }
+ }
+
+ k = fread(&c, 1, 1, f);
+
+ tcsetattr(fileno(f), TCSADRAIN, &old_termios);
+
+ if (k <= 0)
+ return -EIO;
+
+ if (need_nl)
+ *need_nl = c != '\n';
+
+ *ret = c;
+ return 0;
+ }
+ }
+
+ if (t != USEC_INFINITY) {
+ if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
+ return -ETIMEDOUT;
+ }
+
+ errno = 0;
+ if (!fgets(line, sizeof(line), f))
+ return errno ? -errno : -EIO;
+
+ truncate_nl(line);
+
+ if (strlen(line) != 1)
+ return -EBADMSG;
+
+ if (need_nl)
+ *need_nl = false;
+
+ *ret = line[0];
+ return 0;
+}
+
+int ask_char(char *ret, const char *replies, const char *text, ...) {
+ int r;
+
+ assert(ret);
+ assert(replies);
+ assert(text);
+
+ for (;;) {
+ va_list ap;
+ char c;
+ bool need_nl = true;
+
+ if (on_tty())
+ fputs(ANSI_HIGHLIGHT_ON, stdout);
+
+ va_start(ap, text);
+ vprintf(text, ap);
+ va_end(ap);
+
+ if (on_tty())
+ fputs(ANSI_HIGHLIGHT_OFF, stdout);
+
+ fflush(stdout);
+
+ r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
+ if (r < 0) {
+
+ if (r == -EBADMSG) {
+ puts("Bad input, please try again.");
+ continue;
+ }
+
+ putchar('\n');
+ return r;
+ }
+
+ if (need_nl)
+ putchar('\n');
+
+ if (strchr(replies, c)) {
+ *ret = c;
+ return 0;
+ }
+
+ puts("Read unexpected character, please try again.");
+ }
+}
+
+int ask_string(char **ret, const char *text, ...) {
+ assert(ret);
+ assert(text);
+
+ for (;;) {
+ char line[LINE_MAX];
+ va_list ap;
+
+ if (on_tty())
+ fputs(ANSI_HIGHLIGHT_ON, stdout);
+
+ va_start(ap, text);
+ vprintf(text, ap);
+ va_end(ap);
+
+ if (on_tty())
+ fputs(ANSI_HIGHLIGHT_OFF, stdout);
+
+ fflush(stdout);
+
+ errno = 0;
+ if (!fgets(line, sizeof(line), stdin))
+ return errno ? -errno : -EIO;
+
+ if (!endswith(line, "\n"))
+ putchar('\n');
+ else {
+ char *s;
+
+ if (isempty(line))
+ continue;
+
+ truncate_nl(line);
+ s = strdup(line);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
+ }
+ }
+}
+
+int reset_terminal_fd(int fd, bool switch_to_text) {
+ struct termios termios;
+ int r = 0;
+
+ /* Set terminal to some sane defaults */
+
+ assert(fd >= 0);
+
+ /* We leave locked terminal attributes untouched, so that
+ * Plymouth may set whatever it wants to set, and we don't
+ * interfere with that. */
+
+ /* Disable exclusive mode, just in case */
+ ioctl(fd, TIOCNXCL);
+
+ /* Switch to text mode */
+ if (switch_to_text)
+ ioctl(fd, KDSETMODE, KD_TEXT);
+
+ /* Enable console unicode mode */
+ ioctl(fd, KDSKBMODE, K_UNICODE);
+
+ if (tcgetattr(fd, &termios) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ /* We only reset the stuff that matters to the software. How
+ * hardware is set up we don't touch assuming that somebody
+ * else will do that for us */
+
+ termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
+ termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
+ termios.c_oflag |= ONLCR;
+ termios.c_cflag |= CREAD;
+ termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
+
+ termios.c_cc[VINTR] = 03; /* ^C */
+ termios.c_cc[VQUIT] = 034; /* ^\ */
+ termios.c_cc[VERASE] = 0177;
+ termios.c_cc[VKILL] = 025; /* ^X */
+ termios.c_cc[VEOF] = 04; /* ^D */
+ termios.c_cc[VSTART] = 021; /* ^Q */
+ termios.c_cc[VSTOP] = 023; /* ^S */
+ termios.c_cc[VSUSP] = 032; /* ^Z */
+ termios.c_cc[VLNEXT] = 026; /* ^V */
+ termios.c_cc[VWERASE] = 027; /* ^W */
+ termios.c_cc[VREPRINT] = 022; /* ^R */
+ termios.c_cc[VEOL] = 0;
+ termios.c_cc[VEOL2] = 0;
+
+ termios.c_cc[VTIME] = 0;
+ termios.c_cc[VMIN] = 1;
+
+ if (tcsetattr(fd, TCSANOW, &termios) < 0)
+ r = -errno;
+
+finish:
+ /* Just in case, flush all crap out */
+ tcflush(fd, TCIOFLUSH);
+
+ return r;
+}
+
+int reset_terminal(const char *name) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ return reset_terminal_fd(fd, true);
+}
+
+int open_terminal(const char *name, int mode) {
+ int fd, r;
+ unsigned c = 0;
+
+ /*
+ * If a TTY is in the process of being closed opening it might
+ * cause EIO. This is horribly awful, but unlikely to be
+ * changed in the kernel. Hence we work around this problem by
+ * retrying a couple of times.
+ *
+ * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
+ */
+
+ assert(!(mode & O_CREAT));
+
+ for (;;) {
+ fd = open(name, mode, 0);
+ if (fd >= 0)
+ break;
+
+ if (errno != EIO)
+ return -errno;
+
+ /* Max 1s in total */
+ if (c >= 20)
+ return -errno;
+
+ usleep(50 * USEC_PER_MSEC);
+ c++;
+ }
+
+ r = isatty(fd);
+ if (r < 0) {
+ safe_close(fd);
+ return -errno;
+ }
+
+ if (!r) {
+ safe_close(fd);
+ return -ENOTTY;
+ }
+
+ return fd;
+}
+
+int acquire_terminal(
+ const char *name,
+ bool fail,
+ bool force,
+ bool ignore_tiocstty_eperm,
+ usec_t timeout) {
+
+ int fd = -1, notify = -1, r = 0, wd = -1;
+ usec_t ts = 0;
+
+ assert(name);
+
+ /* We use inotify to be notified when the tty is closed. We
+ * create the watch before checking if we can actually acquire
+ * it, so that we don't lose any event.
+ *
+ * Note: strictly speaking this actually watches for the
+ * device being closed, it does *not* really watch whether a
+ * tty loses its controlling process. However, unless some
+ * rogue process uses TIOCNOTTY on /dev/tty *after* closing
+ * its tty otherwise this will not become a problem. As long
+ * as the administrator makes sure not configure any service
+ * on the same tty as an untrusted user this should not be a
+ * problem. (Which he probably should not do anyway.) */
+
+ if (timeout != USEC_INFINITY)
+ ts = now(CLOCK_MONOTONIC);
+
+ if (!fail && !force) {
+ notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
+ if (notify < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ wd = inotify_add_watch(notify, name, IN_CLOSE);
+ if (wd < 0) {
+ r = -errno;
+ goto fail;
+ }
+ }
+
+ for (;;) {
+ struct sigaction sa_old, sa_new = {
+ .sa_handler = SIG_IGN,
+ .sa_flags = SA_RESTART,
+ };
+
+ if (notify >= 0) {
+ r = flush_fd(notify);
+ if (r < 0)
+ goto fail;
+ }
+
+ /* We pass here O_NOCTTY only so that we can check the return
+ * value TIOCSCTTY and have a reliable way to figure out if we
+ * successfully became the controlling process of the tty */
+ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
+ * if we already own the tty. */
+ assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
+
+ /* First, try to get the tty */
+ if (ioctl(fd, TIOCSCTTY, force) < 0)
+ r = -errno;
+
+ assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
+
+ /* Sometimes it makes sense to ignore TIOCSCTTY
+ * returning EPERM, i.e. when very likely we already
+ * are have this controlling terminal. */
+ if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
+ r = 0;
+
+ if (r < 0 && (force || fail || r != -EPERM)) {
+ goto fail;
+ }
+
+ if (r >= 0)
+ break;
+
+ assert(!fail);
+ assert(!force);
+ assert(notify >= 0);
+
+ for (;;) {
+ union inotify_event_buffer buffer;
+ struct inotify_event *e;
+ ssize_t l;
+
+ if (timeout != USEC_INFINITY) {
+ usec_t n;
+
+ n = now(CLOCK_MONOTONIC);
+ if (ts + timeout < n) {
+ r = -ETIMEDOUT;
+ goto fail;
+ }
+
+ r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
+ if (r < 0)
+ goto fail;
+
+ if (r == 0) {
+ r = -ETIMEDOUT;
+ goto fail;
+ }
+ }
+
+ l = read(notify, &buffer, sizeof(buffer));
+ if (l < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ r = -errno;
+ goto fail;
+ }
+
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
+ if (e->wd != wd || !(e->mask & IN_CLOSE)) {
+ r = -EIO;
+ goto fail;
+ }
+ }
+
+ break;
+ }
+
+ /* We close the tty fd here since if the old session
+ * ended our handle will be dead. It's important that
+ * we do this after sleeping, so that we don't enter
+ * an endless loop. */
+ fd = safe_close(fd);
+ }
+
+ safe_close(notify);
+
+ r = reset_terminal_fd(fd, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to reset terminal: %m");
+
+ return fd;
+
+fail:
+ safe_close(fd);
+ safe_close(notify);
+
+ return r;
+}
+
+int release_terminal(void) {
+ static const struct sigaction sa_new = {
+ .sa_handler = SIG_IGN,
+ .sa_flags = SA_RESTART,
+ };
+
+ _cleanup_close_ int fd = -1;
+ struct sigaction sa_old;
+ int r = 0;
+
+ fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
+ * by our own TIOCNOTTY */
+ assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
+
+ if (ioctl(fd, TIOCNOTTY) < 0)
+ r = -errno;
+
+ assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
+
+ return r;
+}
+
+int terminal_vhangup_fd(int fd) {
+ assert(fd >= 0);
+
+ if (ioctl(fd, TIOCVHANGUP) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int terminal_vhangup(const char *name) {
+ _cleanup_close_ int fd;
+
+ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ return terminal_vhangup_fd(fd);
+}
+
+int vt_disallocate(const char *name) {
+ int fd, r;
+ unsigned u;
+
+ /* Deallocate the VT if possible. If not possible
+ * (i.e. because it is the active one), at least clear it
+ * entirely (including the scrollback buffer) */
+
+ if (!startswith(name, "/dev/"))
+ return -EINVAL;
+
+ if (!tty_is_vc(name)) {
+ /* So this is not a VT. I guess we cannot deallocate
+ * it then. But let's at least clear the screen */
+
+ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ loop_write(fd,
+ "\033[r" /* clear scrolling region */
+ "\033[H" /* move home */
+ "\033[2J", /* clear screen */
+ 10, false);
+ safe_close(fd);
+
+ return 0;
+ }
+
+ if (!startswith(name, "/dev/tty"))
+ return -EINVAL;
+
+ r = safe_atou(name+8, &u);
+ if (r < 0)
+ return r;
+
+ if (u <= 0)
+ return -EINVAL;
+
+ /* Try to deallocate */
+ fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ r = ioctl(fd, VT_DISALLOCATE, u);
+ safe_close(fd);
+
+ if (r >= 0)
+ return 0;
+
+ if (errno != EBUSY)
+ return -errno;
+
+ /* Couldn't deallocate, so let's clear it fully with
+ * scrollback */
+ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ loop_write(fd,
+ "\033[r" /* clear scrolling region */
+ "\033[H" /* move home */
+ "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
+ 10, false);
+ safe_close(fd);
+
+ return 0;
+}
+
+void warn_melody(void) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return;
+
+ /* Yeah, this is synchronous. Kinda sucks. But well... */
+
+ ioctl(fd, KIOCSOUND, (int)(1193180/440));
+ usleep(125*USEC_PER_MSEC);
+
+ ioctl(fd, KIOCSOUND, (int)(1193180/220));
+ usleep(125*USEC_PER_MSEC);
+
+ ioctl(fd, KIOCSOUND, (int)(1193180/220));
+ usleep(125*USEC_PER_MSEC);
+
+ ioctl(fd, KIOCSOUND, 0);
+}
+
+int make_console_stdio(void) {
+ int fd, r;
+
+ /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
+
+ fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to acquire terminal: %m");
+
+ r = make_stdio(fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to duplicate terminal fd: %m");
+
+ return 0;
+}
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
+ static const char status_indent[] = " "; /* "[" STATUS "] " */
+ _cleanup_free_ char *s = NULL;
+ _cleanup_close_ int fd = -1;
+ struct iovec iovec[6] = {};
+ int n = 0;
+ static bool prev_ephemeral;
+
+ assert(format);
+
+ /* This is independent of logging, as status messages are
+ * optional and go exclusively to the console. */
+
+ if (vasprintf(&s, format, ap) < 0)
+ return log_oom();
+
+ fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ if (ellipse) {
+ char *e;
+ size_t emax, sl;
+ int c;
+
+ c = fd_columns(fd);
+ if (c <= 0)
+ c = 80;
+
+ sl = status ? sizeof(status_indent)-1 : 0;
+
+ emax = c - sl - 1;
+ if (emax < 3)
+ emax = 3;
+
+ e = ellipsize(s, emax, 50);
+ if (e) {
+ free(s);
+ s = e;
+ }
+ }
+
+ if (prev_ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+ prev_ephemeral = ephemeral;
+
+ if (status) {
+ if (!isempty(status)) {
+ IOVEC_SET_STRING(iovec[n++], "[");
+ IOVEC_SET_STRING(iovec[n++], status);
+ IOVEC_SET_STRING(iovec[n++], "] ");
+ } else
+ IOVEC_SET_STRING(iovec[n++], status_indent);
+ }
+
+ IOVEC_SET_STRING(iovec[n++], s);
+ if (!ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\n");
+
+ if (writev(fd, iovec, n) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
+ va_list ap;
+ int r;
+
+ assert(format);
+
+ va_start(ap, format);
+ r = status_vprintf(status, ellipse, ephemeral, format, ap);
+ va_end(ap);
+
+ return r;
+}
+
+bool tty_is_vc(const char *tty) {
+ assert(tty);
+
+ return vtnr_from_tty(tty) >= 0;
+}
+
+bool tty_is_console(const char *tty) {
+ assert(tty);
+
+ if (startswith(tty, "/dev/"))
+ tty += 5;
+
+ return streq(tty, "console");
+}
+
+int vtnr_from_tty(const char *tty) {
+ int i, r;
+
+ assert(tty);
+
+ if (startswith(tty, "/dev/"))
+ tty += 5;
+
+ if (!startswith(tty, "tty") )
+ return -EINVAL;
+
+ if (tty[3] < '0' || tty[3] > '9')
+ return -EINVAL;
+
+ r = safe_atoi(tty+3, &i);
+ if (r < 0)
+ return r;
+
+ if (i < 0 || i > 63)
+ return -EINVAL;
+
+ return i;
+}
+
+char *resolve_dev_console(char **active) {
+ char *tty;
+
+ /* Resolve where /dev/console is pointing to, if /sys is actually ours
+ * (i.e. not read-only-mounted which is a sign for container setups) */
+
+ if (path_is_read_only_fs("/sys") > 0)
+ return NULL;
+
+ if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
+ return NULL;
+
+ /* If multiple log outputs are configured the last one is what
+ * /dev/console points to */
+ tty = strrchr(*active, ' ');
+ if (tty)
+ tty++;
+ else
+ tty = *active;
+
+ if (streq(tty, "tty0")) {
+ char *tmp;
+
+ /* Get the active VC (e.g. tty1) */
+ if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
+ free(*active);
+ tty = *active = tmp;
+ }
+ }
+
+ return tty;
+}
+
+bool tty_is_vc_resolve(const char *tty) {
+ _cleanup_free_ char *active = NULL;
+
+ assert(tty);
+
+ if (startswith(tty, "/dev/"))
+ tty += 5;
+
+ if (streq(tty, "console")) {
+ tty = resolve_dev_console(&active);
+ if (!tty)
+ return false;
+ }
+
+ return tty_is_vc(tty);
+}
+
+const char *default_term_for_tty(const char *tty) {
+ assert(tty);
+
+ return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
+}
+
+int fd_columns(int fd) {
+ struct winsize ws = {};
+
+ if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+ return -errno;
+
+ if (ws.ws_col <= 0)
+ return -EIO;
+
+ return ws.ws_col;
+}
+
+unsigned columns(void) {
+ const char *e;
+ int c;
+
+ if (_likely_(cached_columns > 0))
+ return cached_columns;
+
+ c = 0;
+ e = getenv("COLUMNS");
+ if (e)
+ (void) safe_atoi(e, &c);
+
+ if (c <= 0)
+ c = fd_columns(STDOUT_FILENO);
+
+ if (c <= 0)
+ c = 80;
+
+ cached_columns = c;
+ return cached_columns;
+}
+
+int fd_lines(int fd) {
+ struct winsize ws = {};
+
+ if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+ return -errno;
+
+ if (ws.ws_row <= 0)
+ return -EIO;
+
+ return ws.ws_row;
+}
+
+unsigned lines(void) {
+ const char *e;
+ int l;
+
+ if (_likely_(cached_lines > 0))
+ return cached_lines;
+
+ l = 0;
+ e = getenv("LINES");
+ if (e)
+ (void) safe_atoi(e, &l);
+
+ if (l <= 0)
+ l = fd_lines(STDOUT_FILENO);
+
+ if (l <= 0)
+ l = 24;
+
+ cached_lines = l;
+ return cached_lines;
+}
+
+/* intended to be used as a SIGWINCH sighandler */
+void columns_lines_cache_reset(int signum) {
+ cached_columns = 0;
+ cached_lines = 0;
+}
+
+bool on_tty(void) {
+ static int cached_on_tty = -1;
+
+ if (_unlikely_(cached_on_tty < 0))
+ cached_on_tty = isatty(STDOUT_FILENO) > 0;
+
+ return cached_on_tty;
+}
+
+int make_stdio(int fd) {
+ int r, s, t;
+
+ assert(fd >= 0);
+
+ r = dup2(fd, STDIN_FILENO);
+ s = dup2(fd, STDOUT_FILENO);
+ t = dup2(fd, STDERR_FILENO);
+
+ if (fd >= 3)
+ safe_close(fd);
+
+ if (r < 0 || s < 0 || t < 0)
+ return -errno;
+
+ /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
+ * dup2() was a NOP and the bit hence possibly set. */
+ fd_cloexec(STDIN_FILENO, false);
+ fd_cloexec(STDOUT_FILENO, false);
+ fd_cloexec(STDERR_FILENO, false);
+
+ return 0;
+}
+
+int make_null_stdio(void) {
+ int null_fd;
+
+ null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
+ if (null_fd < 0)
+ return -errno;
+
+ return make_stdio(null_fd);
+}
+
+int getttyname_malloc(int fd, char **ret) {
+ size_t l = 100;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ for (;;) {
+ char path[l];
+
+ r = ttyname_r(fd, path, sizeof(path));
+ if (r == 0) {
+ const char *p;
+ char *c;
+
+ p = startswith(path, "/dev/");
+ c = strdup(p ?: path);
+ if (!c)
+ return -ENOMEM;
+
+ *ret = c;
+ return 0;
+ }
+
+ if (r != ERANGE)
+ return -r;
+
+ l *= 2;
+ }
+
+ return 0;
+}
+
+int getttyname_harder(int fd, char **r) {
+ int k;
+ char *s = NULL;
+
+ k = getttyname_malloc(fd, &s);
+ if (k < 0)
+ return k;
+
+ if (streq(s, "tty")) {
+ free(s);
+ return get_ctty(0, NULL, r);
+ }
+
+ *r = s;
+ return 0;
+}
+
+int get_ctty_devnr(pid_t pid, dev_t *d) {
+ int r;
+ _cleanup_free_ char *line = NULL;
+ const char *p;
+ unsigned long ttynr;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "stat");
+ r = read_one_line_file(p, &line);
+ if (r < 0)
+ return r;
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " "
+ "%*c " /* state */
+ "%*d " /* ppid */
+ "%*d " /* pgrp */
+ "%*d " /* session */
+ "%lu ", /* ttynr */
+ &ttynr) != 1)
+ return -EIO;
+
+ if (major(ttynr) == 0 && minor(ttynr) == 0)
+ return -ENXIO;
+
+ if (d)
+ *d = (dev_t) ttynr;
+
+ return 0;
+}
+
+int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
+ char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
+ _cleanup_free_ char *s = NULL;
+ const char *p;
+ dev_t devnr;
+ int k;
+
+ assert(r);
+
+ k = get_ctty_devnr(pid, &devnr);
+ if (k < 0)
+ return k;
+
+ sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
+
+ k = readlink_malloc(fn, &s);
+ if (k < 0) {
+
+ if (k != -ENOENT)
+ return k;
+
+ /* This is an ugly hack */
+ if (major(devnr) == 136) {
+ if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
+ return -ENOMEM;
+ } else {
+ /* Probably something like the ptys which have no
+ * symlink in /dev/char. Let's return something
+ * vaguely useful. */
+
+ b = strdup(fn + 5);
+ if (!b)
+ return -ENOMEM;
+ }
+ } else {
+ if (startswith(s, "/dev/"))
+ p = s + 5;
+ else if (startswith(s, "../"))
+ p = s + 3;
+ else
+ p = s;
+
+ b = strdup(p);
+ if (!b)
+ return -ENOMEM;
+ }
+
+ *r = b;
+ if (_devnr)
+ *_devnr = devnr;
+
+ return 0;
+}
diff --git a/src/shared/terminal-util.h b/src/shared/terminal-util.h
new file mode 100644
index 0000000000..188714f228
--- /dev/null
+++ b/src/shared/terminal-util.h
@@ -0,0 +1,109 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "macro.h"
+#include "time-util.h"
+
+#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
+#define ANSI_RED_ON "\x1B[31m"
+#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
+#define ANSI_GREEN_ON "\x1B[32m"
+#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
+#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
+#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m"
+#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
+#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
+
+int reset_terminal_fd(int fd, bool switch_to_text);
+int reset_terminal(const char *name);
+
+int open_terminal(const char *name, int mode);
+int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout);
+int release_terminal(void);
+
+int terminal_vhangup_fd(int fd);
+int terminal_vhangup(const char *name);
+
+int chvt(int vt);
+
+int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
+int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
+int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
+
+int vt_disallocate(const char *name);
+
+char *resolve_dev_console(char **active);
+bool tty_is_vc(const char *tty);
+bool tty_is_vc_resolve(const char *tty);
+bool tty_is_console(const char *tty) _pure_;
+int vtnr_from_tty(const char *tty);
+const char *default_term_for_tty(const char *tty);
+
+void warn_melody(void);
+
+int make_stdio(int fd);
+int make_null_stdio(void);
+int make_console_stdio(void);
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
+
+int fd_columns(int fd);
+unsigned columns(void);
+int fd_lines(int fd);
+unsigned lines(void);
+void columns_lines_cache_reset(int _unused_ signum);
+
+bool on_tty(void);
+
+static inline const char *ansi_highlight(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_ON : "";
+}
+
+static inline const char *ansi_highlight_red(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_RED_ON : "";
+}
+
+static inline const char *ansi_highlight_green(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : "";
+}
+
+static inline const char *ansi_highlight_yellow(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : "";
+}
+
+static inline const char *ansi_highlight_blue(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : "";
+}
+
+static inline const char *ansi_highlight_off(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_OFF : "";
+}
+
+int get_ctty_devnr(pid_t pid, dev_t *d);
+int get_ctty(pid_t, dev_t *_devnr, char **r);
+
+int getttyname_malloc(int fd, char **r);
+int getttyname_harder(int fd, char **r);
diff --git a/src/shared/time-dst.c b/src/shared/time-dst.c
deleted file mode 100644
index 1ce6f721b7..0000000000
--- a/src/shared/time-dst.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Timezone file reading code from glibc 2.16.
-
- Copyright (C) 1991-2012 Free Software Foundation, Inc.
- Copyright 2012 Kay Sievers
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-#include <ctype.h>
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <endian.h>
-#include <byteswap.h>
-#include <assert.h>
-#include <limits.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/stat.h>
-
-#include "time-dst.h"
-#include "util.h"
-
-/*
- * If tzh_version is '2' or greater, the above is followed by a second instance
- * of tzhead and a second instance of the data in which each coded transition
- * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style
- * string for use in handling instants after the last transition time stored in
- * the file * (with nothing between the newlines if there is no POSIX
- * representation for such instants).
- */
-#define TZ_MAGIC "TZif"
-struct tzhead {
- char tzh_magic[4]; /* TZ_MAGIC */
- char tzh_version[1]; /* '\0' or '2' as of 2005 */
- char tzh_reserved[15]; /* reserved--must be zero */
- char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
- char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
- char tzh_leapcnt[4]; /* coded number of leap seconds */
- char tzh_timecnt[4]; /* coded number of transition times */
- char tzh_typecnt[4]; /* coded number of local time types */
- char tzh_charcnt[4]; /* coded number of abbr. chars */
-};
-
-struct ttinfo {
- long int offset; /* Seconds east of GMT. */
- unsigned char isdst; /* Used to set tm_isdst. */
- unsigned char idx; /* Index into `zone_names'. */
- unsigned char isstd; /* Transition times are in standard time. */
- unsigned char isgmt; /* Transition times are in GMT. */
-};
-
-struct leap {
- time_t transition; /* Time the transition takes effect. */
- long int change; /* Seconds of correction to apply. */
-};
-
-static inline int decode(const void *ptr) {
- return be32toh(*(int *)ptr);
-}
-
-static inline int64_t decode64(const void *ptr) {
- return be64toh(*(int64_t *)ptr);
-}
-
-int time_get_dst(time_t date, const char *tzfile,
- time_t *switch_cur, char **zone_cur, bool *dst_cur,
- time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next) {
- unsigned char *type_idxs = 0;
- size_t num_types = 0;
- struct ttinfo *types = NULL;
- char *zone_names = NULL;
- struct stat st;
- size_t num_isstd, num_isgmt;
- struct tzhead tzhead;
- size_t chars;
- size_t i;
- size_t total_size;
- size_t types_idx;
- int trans_width = 4;
- size_t tzspec_len;
- size_t num_leaps;
- size_t lo, hi;
- size_t num_transitions = 0;
- _cleanup_free_ time_t *transitions = NULL;
- _cleanup_fclose_ FILE *f;
-
- f = fopen(tzfile, "re");
- if (f == NULL)
- return -errno;
-
- if (fstat(fileno(f), &st) < 0)
- return -errno;
-
-read_again:
- if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 ||
- memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0)
- return -EINVAL;
-
- num_transitions = (size_t)decode(tzhead.tzh_timecnt);
- num_types = (size_t)decode(tzhead.tzh_typecnt);
- chars = (size_t)decode(tzhead.tzh_charcnt);
- num_leaps = (size_t)decode(tzhead.tzh_leapcnt);
- num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt);
- num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt);
-
- /* For platforms with 64-bit time_t we use the new format if available. */
- if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') {
- size_t to_skip;
-
- /* We use the 8-byte format. */
- trans_width = 8;
-
- /* Position the stream before the second header. */
- to_skip = (num_transitions * (4 + 1)
- + num_types * 6
- + chars
- + num_leaps * 8 + num_isstd + num_isgmt);
- if (fseek(f, to_skip, SEEK_CUR) != 0)
- return -EINVAL;
-
- goto read_again;
- }
-
- if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1)))
- return -EINVAL;
-
- total_size = num_transitions * (sizeof(time_t) + 1);
- total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1));
- types_idx = total_size;
- if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo))
- return -EINVAL;
-
- total_size += num_types * sizeof(struct ttinfo);
- if (chars > SIZE_MAX - total_size)
- return -EINVAL;
-
- total_size += chars;
- if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size)
- return -EINVAL;
-
- total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1));
- if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap))
- return -EINVAL;
-
- total_size += num_leaps * sizeof(struct leap);
- tzspec_len = 0;
- if (sizeof(time_t) == 8 && trans_width == 8) {
- off_t rem = st.st_size - ftello(f);
-
- if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars))
- return -EINVAL;
- tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars);
- if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12)
- return -EINVAL;
- tzspec_len -= num_leaps * 12;
- if (tzspec_len < num_isstd)
- return -EINVAL;
- tzspec_len -= num_isstd;
- if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt)
- return -EINVAL;
- tzspec_len -= num_isgmt + 1;
- if (SIZE_MAX - total_size < tzspec_len)
- return -EINVAL;
- }
-
- /* leave space for additional zone_names zero terminator */
- transitions = malloc0(total_size + tzspec_len + 1);
- if (transitions == NULL)
- return -EINVAL;
-
- type_idxs = (unsigned char *)transitions + (num_transitions
- * sizeof(time_t));
- types = (struct ttinfo *)((char *)transitions + types_idx);
- zone_names = (char *)types + num_types * sizeof(struct ttinfo);
-
- if (sizeof(time_t) == 4 || trans_width == 8) {
- if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions)
- return -EINVAL;
- } else {
- if (fread(transitions, 4, num_transitions, f) != num_transitions ||
- fread(type_idxs, 1, num_transitions, f) != num_transitions)
- return -EINVAL;
- }
-
- /* Check for bogus indices in the data file, so we can hereafter
- safely use type_idxs[T] as indices into `types' and never crash. */
- for (i = 0; i < num_transitions; ++i)
- if (type_idxs[i] >= num_types)
- return -EINVAL;
-
- if (__BYTE_ORDER == __BIG_ENDIAN ? sizeof(time_t) == 8 && trans_width == 4
- : sizeof(time_t) == 4 || trans_width == 4) {
- /* Decode the transition times, stored as 4-byte integers in
- network (big-endian) byte order. We work from the end of
- the array so as not to clobber the next element to be
- processed when sizeof (time_t) > 4. */
- i = num_transitions;
- while (i-- > 0)
- transitions[i] = decode((char *)transitions + i * 4);
- } else if (__BYTE_ORDER != __BIG_ENDIAN && sizeof(time_t) == 8) {
- /* Decode the transition times, stored as 8-byte integers in
- network (big-endian) byte order. */
- for (i = 0; i < num_transitions; ++i)
- transitions[i] = decode64((char *)transitions + i * 8);
- }
-
- for (i = 0; i < num_types; ++i) {
- unsigned char x[4];
- int c;
-
- if (fread(x, 1, sizeof(x), f) != sizeof(x))
- return -EINVAL;
- c = getc(f);
- if ((unsigned int)c > 1u)
- return -EINVAL;
- types[i].isdst = c;
- c = getc(f);
- if ((size_t) c > chars)
- /* Bogus index in data file. */
- return -EINVAL;
- types[i].idx = c;
- types[i].offset = (long int)decode(x);
- }
-
- if (fread(zone_names, 1, chars, f) != chars)
- return -EINVAL;
-
- zone_names[chars] = '\0';
-
- for (i = 0; i < num_isstd; ++i) {
- int c = getc(f);
- if (c == EOF)
- return -EINVAL;
- types[i].isstd = c != 0;
- }
-
- while (i < num_types)
- types[i++].isstd = 0;
-
- for (i = 0; i < num_isgmt; ++i) {
- int c = getc(f);
- if (c == EOF)
- return -EINVAL;
- types[i].isgmt = c != 0;
- }
-
- while (i < num_types)
- types[i++].isgmt = 0;
-
- if (num_transitions == 0)
- return -EINVAL;
-
- if (date < transitions[0] || date >= transitions[num_transitions - 1])
- return -EINVAL;
-
- /* Find the first transition after TIMER, and
- then pick the type of the transition before it. */
- lo = 0;
- hi = num_transitions - 1;
-
- /* Assume that DST is changing twice a year and guess initial
- search spot from it.
- Half of a gregorian year has on average 365.2425 * 86400 / 2
- = 15778476 seconds. */
- i = (transitions[num_transitions - 1] - date) / 15778476;
- if (i < num_transitions) {
- i = num_transitions - 1 - i;
- if (date < transitions[i]) {
- if (i < 10 || date >= transitions[i - 10]) {
- /* Linear search. */
- while (date < transitions[i - 1])
- i--;
- goto found;
- }
- hi = i - 10;
- } else {
- if (i + 10 >= num_transitions || date < transitions[i + 10]) {
- /* Linear search. */
- while (date >= transitions[i])
- i++;
- goto found;
- }
- lo = i + 10;
- }
- }
-
- /* Binary search. */
- while (lo + 1 < hi) {
- i = (lo + hi) / 2;
- if (date < transitions[i])
- hi = i;
- else
- lo = i;
- }
- i = hi;
-
-found:
- if (switch_cur)
- *switch_cur = transitions[i-1];
- if (zone_cur)
- *zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]);
- if (dst_cur)
- *dst_cur = types[type_idxs[i-1]].isdst;
-
- if (switch_next)
- *switch_next = transitions[i];
- if (delta_next)
- *delta_next = (types[type_idxs[i]].offset - types[type_idxs[i-1]].offset) / 60;
- if (zone_next)
- *zone_next = strdup(&zone_names[types[type_idxs[i]].idx]);
- if (dst_next)
- *dst_next = types[type_idxs[i]].isdst;
-
- return 0;
-}
diff --git a/src/shared/time-util.c b/src/shared/time-util.c
index 947ac1fcfb..12f1b193be 100644
--- a/src/shared/time-util.c
+++ b/src/shared/time-util.c
@@ -398,18 +398,21 @@ void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
t->monotonic);
}
-void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
+int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
unsigned long long a, b;
assert(value);
assert(t);
- if (sscanf(value, "%llu %llu", &a, &b) != 2)
- log_debug("Failed to parse finish timestamp value %s", value);
- else {
- t->realtime = a;
- t->monotonic = b;
+ if (sscanf(value, "%llu %llu", &a, &b) != 2) {
+ log_debug("Failed to parse finish timestamp value %s.", value);
+ return -EINVAL;
}
+
+ t->realtime = a;
+ t->monotonic = b;
+
+ return 0;
}
int parse_timestamp(const char *t, usec_t *usec) {
@@ -786,7 +789,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
s = startswith(p, "infinity");
if (s) {
s += strspn(s, WHITESPACE);
- if (!*s != 0)
+ if (*s != 0)
return -EINVAL;
*nsec = NSEC_INFINITY;
diff --git a/src/shared/time-util.h b/src/shared/time-util.h
index fca8a4db9b..7a64d454a0 100644
--- a/src/shared/time-util.h
+++ b/src/shared/time-util.h
@@ -94,7 +94,7 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t);
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
-void dual_timestamp_deserialize(const char *value, dual_timestamp *t);
+int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
int parse_timestamp(const char *t, usec_t *usec);
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
index 5f09ce181f..f758ce13e4 100644
--- a/src/shared/udev-util.h
+++ b/src/shared/udev-util.h
@@ -30,6 +30,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_connection*, udev_ctrl_connection_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_msg*, udev_ctrl_msg_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref);
#define _cleanup_udev_unref_ _cleanup_(udev_unrefp)
@@ -38,5 +40,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref);
#define _cleanup_udev_event_unref_ _cleanup_(udev_event_unrefp)
#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp)
#define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp)
+#define _cleanup_udev_ctrl_connection_unref_ _cleanup_(udev_ctrl_connection_unrefp)
+#define _cleanup_udev_ctrl_msg_unref_ _cleanup_(udev_ctrl_msg_unrefp)
#define _cleanup_udev_monitor_unref_ _cleanup_(udev_monitor_unrefp)
#define _cleanup_udev_list_cleanup_ _cleanup_(udev_list_cleanup)
diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c
index 21b66913c9..bf52463d81 100644
--- a/src/shared/unit-name.c
+++ b/src/shared/unit-name.c
@@ -21,7 +21,6 @@
#include <errno.h>
#include <string.h>
-#include <assert.h>
#include "path-util.h"
#include "bus-label.h"
@@ -34,45 +33,13 @@
DIGITS LETTERS \
":-_.\\"
-static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
- [UNIT_SERVICE] = "service",
- [UNIT_SOCKET] = "socket",
- [UNIT_BUSNAME] = "busname",
- [UNIT_TARGET] = "target",
- [UNIT_SNAPSHOT] = "snapshot",
- [UNIT_DEVICE] = "device",
- [UNIT_MOUNT] = "mount",
- [UNIT_AUTOMOUNT] = "automount",
- [UNIT_SWAP] = "swap",
- [UNIT_TIMER] = "timer",
- [UNIT_PATH] = "path",
- [UNIT_SLICE] = "slice",
- [UNIT_SCOPE] = "scope"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
-
-static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
- [UNIT_STUB] = "stub",
- [UNIT_LOADED] = "loaded",
- [UNIT_NOT_FOUND] = "not-found",
- [UNIT_ERROR] = "error",
- [UNIT_MERGED] = "merged",
- [UNIT_MASKED] = "masked"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
-
-bool unit_name_is_valid(const char *n, enum template_valid template_ok) {
+bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
const char *e, *i, *at;
- /* Valid formats:
- *
- * string@instance.suffix
- * string.suffix
- */
+ assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
- assert(IN_SET(template_ok, TEMPLATE_VALID, TEMPLATE_INVALID));
+ if (_unlikely_(flags == 0))
+ return false;
if (isempty(n))
return false;
@@ -96,15 +63,32 @@ bool unit_name_is_valid(const char *n, enum template_valid template_ok) {
return false;
}
- if (at) {
- if (at == n)
- return false;
+ if (at == n)
+ return false;
- if (!template_ok == TEMPLATE_VALID && at+1 == e)
- return false;
- }
+ if (flags & UNIT_NAME_PLAIN)
+ if (!at)
+ return true;
- return true;
+ if (flags & UNIT_NAME_INSTANCE)
+ if (at && e > at + 1)
+ return true;
+
+ if (flags & UNIT_NAME_TEMPLATE)
+ if (at && e == at + 1)
+ return true;
+
+ return false;
+}
+
+bool unit_prefix_is_valid(const char *p) {
+
+ /* We don't allow additional @ in the prefix string */
+
+ if (isempty(p))
+ return false;
+
+ return in_charset(p, VALID_CHARS);
}
bool unit_instance_is_valid(const char *i) {
@@ -121,14 +105,41 @@ bool unit_instance_is_valid(const char *i) {
return in_charset(i, "@" VALID_CHARS);
}
-bool unit_prefix_is_valid(const char *p) {
+bool unit_suffix_is_valid(const char *s) {
+ if (isempty(s))
+ return false;
- /* We don't allow additional @ in the instance string */
+ if (s[0] != '.')
+ return false;
- if (isempty(p))
+ if (unit_type_from_string(s + 1) < 0)
return false;
- return in_charset(p, VALID_CHARS);
+ return true;
+}
+
+int unit_name_to_prefix(const char *n, char **ret) {
+ const char *p;
+ char *s;
+
+ assert(n);
+ assert(ret);
+
+ if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ p = strchr(n, '@');
+ if (!p)
+ p = strrchr(n, '.');
+
+ assert_se(p);
+
+ s = strndup(n, p - n);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
}
int unit_name_to_instance(const char *n, char **instance) {
@@ -138,6 +149,9 @@ int unit_name_to_instance(const char *n, char **instance) {
assert(n);
assert(instance);
+ if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+ return -EINVAL;
+
/* Everything past the first @ and before the last . is the instance */
p = strchr(n, '@');
if (!p) {
@@ -145,13 +159,13 @@ int unit_name_to_instance(const char *n, char **instance) {
return 0;
}
- d = strrchr(n, '.');
+ p++;
+
+ d = strrchr(p, '.');
if (!d)
return -EINVAL;
- if (d < p)
- return -EINVAL;
- i = strndup(p+1, d-p-1);
+ i = strndup(p, d-p);
if (!i)
return -ENOMEM;
@@ -159,55 +173,95 @@ int unit_name_to_instance(const char *n, char **instance) {
return 1;
}
-char *unit_name_to_prefix_and_instance(const char *n) {
+int unit_name_to_prefix_and_instance(const char *n, char **ret) {
const char *d;
+ char *s;
assert(n);
+ assert(ret);
- assert_se(d = strrchr(n, '.'));
- return strndup(n, d - n);
+ if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ d = strrchr(n, '.');
+ if (!d)
+ return -EINVAL;
+
+ s = strndup(n, d - n);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
}
-char *unit_name_to_prefix(const char *n) {
- const char *p;
+UnitType unit_name_to_type(const char *n) {
+ const char *e;
assert(n);
- p = strchr(n, '@');
- if (p)
- return strndup(n, p - n);
+ if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+ return _UNIT_TYPE_INVALID;
+
+ assert_se(e = strrchr(n, '.'));
- return unit_name_to_prefix_and_instance(n);
+ return unit_type_from_string(e + 1);
}
-char *unit_name_change_suffix(const char *n, const char *suffix) {
- char *e, *r;
+int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
+ char *e, *s;
size_t a, b;
assert(n);
assert(suffix);
- assert(suffix[0] == '.');
+ assert(ret);
+
+ if (!unit_name_is_valid(n, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ if (!unit_suffix_is_valid(suffix))
+ return -EINVAL;
assert_se(e = strrchr(n, '.'));
+
a = e - n;
b = strlen(suffix);
- r = new(char, a + b + 1);
- if (!r)
- return NULL;
+ s = new(char, a + b + 1);
+ if (!s)
+ return -ENOMEM;
- strcpy(mempcpy(r, n, a), suffix);
- return r;
+ strcpy(mempcpy(s, n, a), suffix);
+ *ret = s;
+
+ return 0;
}
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
+int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
+ char *s;
+
assert(prefix);
assert(suffix);
+ assert(ret);
+
+ if (!unit_prefix_is_valid(prefix))
+ return -EINVAL;
+
+ if (instance && !unit_instance_is_valid(instance))
+ return -EINVAL;
+
+ if (!unit_suffix_is_valid(suffix))
+ return -EINVAL;
if (!instance)
- return strappend(prefix, suffix);
+ s = strappend(prefix, suffix);
+ else
+ s = strjoin(prefix, "@", instance, suffix, NULL);
+ if (!s)
+ return -ENOMEM;
- return strjoin(prefix, "@", instance, suffix, NULL);
+ *ret = s;
+ return 0;
}
static char *do_escape_char(char c, char *t) {
@@ -243,30 +297,6 @@ static char *do_escape(const char *f, char *t) {
return t;
}
-static char *do_escape_mangle(const char *f, enum unit_name_mangle allow_globs, char *t) {
- const char *valid_chars;
-
- assert(f);
- assert(IN_SET(allow_globs, MANGLE_GLOB, MANGLE_NOGLOB));
- assert(t);
-
- /* We'll only escape the obvious characters here, to play
- * safe. */
-
- valid_chars = allow_globs == MANGLE_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
-
- for (; *f; f++) {
- if (*f == '/')
- *(t++) = '-';
- else if (!strchr(valid_chars, *f))
- t = do_escape_char(*f, t);
- else
- *(t++) = *f;
- }
-
- return t;
-}
-
char *unit_name_escape(const char *f) {
char *r, *t;
@@ -282,14 +312,15 @@ char *unit_name_escape(const char *f) {
return r;
}
-char *unit_name_unescape(const char *f) {
- char *r, *t;
+int unit_name_unescape(const char *f, char **ret) {
+ _cleanup_free_ char *r = NULL;
+ char *t;
assert(f);
r = strdup(f);
if (!r)
- return NULL;
+ return -ENOMEM;
for (t = r; *f; f++) {
if (*f == '-')
@@ -297,180 +328,234 @@ char *unit_name_unescape(const char *f) {
else if (*f == '\\') {
int a, b;
- if (f[1] != 'x' ||
- (a = unhexchar(f[2])) < 0 ||
- (b = unhexchar(f[3])) < 0) {
- /* Invalid escape code, let's take it literal then */
- *(t++) = '\\';
- } else {
- *(t++) = (char) ((a << 4) | b);
- f += 3;
- }
+ if (f[1] != 'x')
+ return -EINVAL;
+
+ a = unhexchar(f[2]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unhexchar(f[3]);
+ if (b < 0)
+ return -EINVAL;
+
+ *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
+ f += 3;
} else
*(t++) = *f;
}
*t = 0;
- return r;
+ *ret = r;
+ r = NULL;
+
+ return 0;
}
-char *unit_name_path_escape(const char *f) {
- _cleanup_free_ char *p = NULL;
+int unit_name_path_escape(const char *f, char **ret) {
+ char *p, *s;
assert(f);
+ assert(ret);
- p = strdup(f);
+ p = strdupa(f);
if (!p)
- return NULL;
+ return -ENOMEM;
path_kill_slashes(p);
if (STR_IN_SET(p, "/", ""))
- return strdup("-");
-
- return unit_name_escape(p[0] == '/' ? p + 1 : p);
-}
+ s = strdup("-");
+ else {
+ char *e;
-char *unit_name_path_unescape(const char *f) {
- char *e, *w;
+ if (!path_is_safe(p))
+ return -EINVAL;
- assert(f);
+ /* Truncate trailing slashes */
+ e = endswith(p, "/");
+ if (e)
+ *e = 0;
- e = unit_name_unescape(f);
- if (!e)
- return NULL;
+ /* Truncate leading slashes */
+ if (p[0] == '/')
+ p++;
- if (e[0] != '/') {
- w = strappend("/", e);
- free(e);
- return w;
+ s = unit_name_escape(p);
}
+ if (!s)
+ return -ENOMEM;
- return e;
+ *ret = s;
+ return 0;
}
-bool unit_name_is_template(const char *n) {
- const char *p, *e;
+int unit_name_path_unescape(const char *f, char **ret) {
+ char *s;
+ int r;
- assert(n);
+ assert(f);
- p = strchr(n, '@');
- if (!p)
- return false;
+ if (isempty(f))
+ return -EINVAL;
- e = strrchr(p+1, '.');
- if (!e)
- return false;
+ if (streq(f, "-")) {
+ s = strdup("/");
+ if (!s)
+ return -ENOMEM;
+ } else {
+ char *w;
- return e == p + 1;
-}
+ r = unit_name_unescape(f, &w);
+ if (r < 0)
+ return r;
-bool unit_name_is_instance(const char *n) {
- const char *p, *e;
+ /* Don't accept trailing or leading slashes */
+ if (startswith(w, "/") || endswith(w, "/")) {
+ free(w);
+ return -EINVAL;
+ }
- assert(n);
+ /* Prefix a slash again */
+ s = strappend("/", w);
+ free(w);
+ if (!s)
+ return -ENOMEM;
- p = strchr(n, '@');
- if (!p)
- return false;
+ if (!path_is_safe(s)) {
+ free(s);
+ return -EINVAL;
+ }
+ }
- e = strrchr(p+1, '.');
- if (!e)
- return false;
+ if (ret)
+ *ret = s;
+ else
+ free(s);
- return e > p + 1;
+ return 0;
}
-char *unit_name_replace_instance(const char *f, const char *i) {
+int unit_name_replace_instance(const char *f, const char *i, char **ret) {
const char *p, *e;
- char *r;
+ char *s;
size_t a, b;
assert(f);
assert(i);
+ assert(ret);
- p = strchr(f, '@');
- if (!p)
- return strdup(f);
+ if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
+ return -EINVAL;
+ if (!unit_instance_is_valid(i))
+ return -EINVAL;
- e = strrchr(f, '.');
- if (!e)
- e = strchr(f, 0);
+ assert_se(p = strchr(f, '@'));
+ assert_se(e = strrchr(f, '.'));
a = p - f;
b = strlen(i);
- r = new(char, a + 1 + b + strlen(e) + 1);
- if (!r)
- return NULL;
+ s = new(char, a + 1 + b + strlen(e) + 1);
+ if (!s)
+ return -ENOMEM;
- strcpy(mempcpy(mempcpy(r, f, a + 1), i, b), e);
- return r;
+ strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
+
+ *ret = s;
+ return 0;
}
-char *unit_name_template(const char *f) {
+int unit_name_template(const char *f, char **ret) {
const char *p, *e;
- char *r;
+ char *s;
size_t a;
assert(f);
+ assert(ret);
- p = strchr(f, '@');
- if (!p)
- return strdup(f);
+ if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
+ return -EINVAL;
- e = strrchr(f, '.');
- if (!e)
- e = strchr(f, 0);
+ assert_se(p = strchr(f, '@'));
+ assert_se(e = strrchr(f, '.'));
a = p - f;
- r = new(char, a + 1 + strlen(e) + 1);
- if (!r)
- return NULL;
+ s = new(char, a + 1 + strlen(e) + 1);
+ if (!s)
+ return -ENOMEM;
- strcpy(mempcpy(r, f, a + 1), e);
- return r;
+ strcpy(mempcpy(s, f, a + 1), e);
+
+ *ret = s;
+ return 0;
}
-char *unit_name_from_path(const char *path, const char *suffix) {
+int unit_name_from_path(const char *path, const char *suffix, char **ret) {
_cleanup_free_ char *p = NULL;
+ char *s = NULL;
+ int r;
assert(path);
assert(suffix);
+ assert(ret);
- p = unit_name_path_escape(path);
- if (!p)
- return NULL;
+ if (!unit_suffix_is_valid(suffix))
+ return -EINVAL;
+
+ r = unit_name_path_escape(path, &p);
+ if (r < 0)
+ return r;
- return strappend(p, suffix);
+ s = strappend(p, suffix);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
}
-char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
+int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
_cleanup_free_ char *p = NULL;
+ char *s;
+ int r;
assert(prefix);
assert(path);
assert(suffix);
+ assert(ret);
- p = unit_name_path_escape(path);
- if (!p)
- return NULL;
+ if (!unit_prefix_is_valid(prefix))
+ return -EINVAL;
+
+ if (!unit_suffix_is_valid(suffix))
+ return -EINVAL;
+
+ r = unit_name_path_escape(path, &p);
+ if (r < 0)
+ return r;
+
+ s = strjoin(prefix, "@", p, suffix, NULL);
+ if (!s)
+ return -ENOMEM;
- return strjoin(prefix, "@", p, suffix, NULL);
+ *ret = s;
+ return 0;
}
-char *unit_name_to_path(const char *name) {
- _cleanup_free_ char *w = NULL;
+int unit_name_to_path(const char *name, char **ret) {
+ _cleanup_free_ char *prefix = NULL;
+ int r;
assert(name);
- w = unit_name_to_prefix(name);
- if (!w)
- return NULL;
+ r = unit_name_to_prefix(name, &prefix);
+ if (r < 0)
+ return r;
- return unit_name_path_unescape(w);
+ return unit_name_path_unescape(prefix, ret);
}
char *unit_dbus_path_from_name(const char *name) {
@@ -501,6 +586,30 @@ int unit_name_from_dbus_path(const char *path, char **name) {
return 0;
}
+static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
+ const char *valid_chars;
+
+ assert(f);
+ assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB));
+ assert(t);
+
+ /* We'll only escape the obvious characters here, to play
+ * safe. */
+
+ valid_chars = allow_globs == UNIT_NAME_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
+
+ for (; *f; f++) {
+ if (*f == '/')
+ *(t++) = '-';
+ else if (!strchr(valid_chars, *f))
+ t = do_escape_char(*f, t);
+ else
+ *(t++) = *f;
+ }
+
+ return t;
+}
+
/**
* Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
* /blah/blah is converted to blah-blah.mount, anything else is left alone,
@@ -508,72 +617,191 @@ int unit_name_from_dbus_path(const char *path, char **name) {
*
* If @allow_globs, globs characters are preserved. Otherwise they are escaped.
*/
-char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix) {
- char *r, *t;
+int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
+ char *s, *t;
+ int r;
assert(name);
assert(suffix);
- assert(suffix[0] == '.');
+ assert(ret);
+
+ if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
+ return -EINVAL;
- if (is_device_path(name))
- return unit_name_from_path(name, ".device");
+ if (!unit_suffix_is_valid(suffix))
+ return -EINVAL;
- if (path_is_absolute(name))
- return unit_name_from_path(name, ".mount");
+ if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
+ /* No mangling necessary... */
+ s = strdup(name);
+ if (!s)
+ return -ENOMEM;
- r = new(char, strlen(name) * 4 + strlen(suffix) + 1);
- if (!r)
- return NULL;
+ *ret = s;
+ return 0;
+ }
- t = do_escape_mangle(name, allow_globs, r);
+ if (is_device_path(name)) {
+ r = unit_name_from_path(name, ".device", ret);
+ if (r >= 0)
+ return 1;
+ if (r != -EINVAL)
+ return r;
+ }
+
+ if (path_is_absolute(name)) {
+ r = unit_name_from_path(name, ".mount", ret);
+ if (r >= 0)
+ return 1;
+ if (r != -EINVAL)
+ return r;
+ }
- if (unit_name_to_type(name) < 0)
+ s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
+ if (!s)
+ return -ENOMEM;
+
+ t = do_escape_mangle(name, allow_globs, s);
+ *t = 0;
+
+ if (unit_name_to_type(s) < 0)
strcpy(t, suffix);
- else
- *t = 0;
- return r;
+ *ret = s;
+ return 1;
}
-UnitType unit_name_to_type(const char *n) {
- const char *e;
+int slice_build_parent_slice(const char *slice, char **ret) {
+ char *s, *dash;
- assert(n);
+ assert(slice);
+ assert(ret);
- e = strrchr(n, '.');
- if (!e)
- return _UNIT_TYPE_INVALID;
+ if (!slice_name_is_valid(slice))
+ return -EINVAL;
- return unit_type_from_string(e + 1);
+ if (streq(slice, "-.slice")) {
+ *ret = NULL;
+ return 0;
+ }
+
+ s = strdup(slice);
+ if (!s)
+ return -ENOMEM;
+
+ dash = strrchr(s, '-');
+ if (dash)
+ strcpy(dash, ".slice");
+ else {
+ free(s);
+
+ s = strdup("-.slice");
+ if (!s)
+ return -ENOMEM;
+ }
+
+ *ret = s;
+ return 1;
}
-int build_subslice(const char *slice, const char*name, char **subslice) {
- char *ret;
+int slice_build_subslice(const char *slice, const char*name, char **ret) {
+ char *subslice;
assert(slice);
assert(name);
- assert(subslice);
+ assert(ret);
+
+ if (!slice_name_is_valid(slice))
+ return -EINVAL;
+
+ if (!unit_prefix_is_valid(name))
+ return -EINVAL;
if (streq(slice, "-.slice"))
- ret = strappend(name, ".slice");
+ subslice = strappend(name, ".slice");
else {
char *e;
- e = endswith(slice, ".slice");
- if (!e)
- return -EINVAL;
+ assert_se(e = endswith(slice, ".slice"));
- ret = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
- if (!ret)
+ subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
+ if (!subslice)
return -ENOMEM;
- stpcpy(stpcpy(stpcpy(mempcpy(ret, slice, e - slice), "-"), name), ".slice");
+ stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
}
- *subslice = ret;
+ *ret = subslice;
return 0;
}
+bool slice_name_is_valid(const char *name) {
+ const char *p, *e;
+ bool dash = false;
+
+ if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
+ return false;
+
+ if (streq(name, "-.slice"))
+ return true;
+
+ e = endswith(name, ".slice");
+ if (!e)
+ return false;
+
+ for (p = name; p < e; p++) {
+
+ if (*p == '-') {
+
+ /* Don't allow initial dash */
+ if (p == name)
+ return false;
+
+ /* Don't allow multiple dashes */
+ if (dash)
+ return false;
+
+ dash = true;
+ } else
+ dash = false;
+ }
+
+ /* Don't allow trailing hash */
+ if (dash)
+ return false;
+
+ return true;
+}
+
+static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
+ [UNIT_SERVICE] = "service",
+ [UNIT_SOCKET] = "socket",
+ [UNIT_BUSNAME] = "busname",
+ [UNIT_TARGET] = "target",
+ [UNIT_SNAPSHOT] = "snapshot",
+ [UNIT_DEVICE] = "device",
+ [UNIT_MOUNT] = "mount",
+ [UNIT_AUTOMOUNT] = "automount",
+ [UNIT_SWAP] = "swap",
+ [UNIT_TIMER] = "timer",
+ [UNIT_PATH] = "path",
+ [UNIT_SLICE] = "slice",
+ [UNIT_SCOPE] = "scope"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
+
+static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
+ [UNIT_STUB] = "stub",
+ [UNIT_LOADED] = "loaded",
+ [UNIT_NOT_FOUND] = "not-found",
+ [UNIT_ERROR] = "error",
+ [UNIT_MERGED] = "merged",
+ [UNIT_MASKED] = "masked"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+
static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
[UNIT_REQUIRES] = "Requires",
[UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
@@ -584,6 +812,8 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
[UNIT_PART_OF] = "PartOf",
[UNIT_REQUIRED_BY] = "RequiredBy",
[UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
+ [UNIT_REQUISITE_OF] = "RequisiteOf",
+ [UNIT_REQUISITE_OF_OVERRIDABLE] = "RequisiteOfOverridable",
[UNIT_WANTED_BY] = "WantedBy",
[UNIT_BOUND_BY] = "BoundBy",
[UNIT_CONSISTS_OF] = "ConsistsOf",
diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h
index 6f139cc4c4..b2043d0870 100644
--- a/src/shared/unit-name.h
+++ b/src/shared/unit-name.h
@@ -71,8 +71,10 @@ enum UnitDependency {
UNIT_PART_OF,
/* Inverse of the above */
- UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */
- UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */
+ UNIT_REQUIRED_BY, /* inverse of 'requires' is 'required_by' */
+ UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' is 'required_by_overridable' */
+ UNIT_REQUISITE_OF, /* inverse of 'requisite' is 'requisite_of' */
+ UNIT_REQUISITE_OF_OVERRIDABLE,/* inverse of 'requisite_overridable' is 'requisite_of_overridable' */
UNIT_WANTED_BY, /* inverse of 'wants' */
UNIT_BOUND_BY, /* inverse of 'binds_to' */
UNIT_CONSISTS_OF, /* inverse of 'part_of' */
@@ -107,61 +109,69 @@ enum UnitDependency {
_UNIT_DEPENDENCY_INVALID = -1
};
-const char *unit_type_to_string(UnitType i) _const_;
-UnitType unit_type_from_string(const char *s) _pure_;
-
-const char *unit_load_state_to_string(UnitLoadState i) _const_;
-UnitLoadState unit_load_state_from_string(const char *s) _pure_;
+typedef enum UnitNameFlags {
+ UNIT_NAME_PLAIN = 1, /* Allow foo.service */
+ UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */
+ UNIT_NAME_TEMPLATE = 4, /* Allow foo@.service */
+ UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE,
+} UnitNameFlags;
-int unit_name_to_instance(const char *n, char **instance);
-char* unit_name_to_prefix(const char *n);
-char* unit_name_to_prefix_and_instance(const char *n);
-
-enum template_valid {
- TEMPLATE_INVALID,
- TEMPLATE_VALID,
-};
-
-bool unit_name_is_valid(const char *n, enum template_valid template_ok) _pure_;
+bool unit_name_is_valid(const char *n, UnitNameFlags flags) _pure_;
bool unit_prefix_is_valid(const char *p) _pure_;
bool unit_instance_is_valid(const char *i) _pure_;
+bool unit_suffix_is_valid(const char *s) _pure_;
+
+static inline int unit_prefix_and_instance_is_valid(const char *p) {
+ /* For prefix+instance and instance the same rules apply */
+ return unit_instance_is_valid(p);
+}
+
+int unit_name_to_prefix(const char *n, char **prefix);
+int unit_name_to_instance(const char *n, char **instance);
+int unit_name_to_prefix_and_instance(const char *n, char **ret);
UnitType unit_name_to_type(const char *n) _pure_;
-char *unit_name_change_suffix(const char *n, const char *suffix);
+int unit_name_change_suffix(const char *n, const char *suffix, char **ret);
-char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
+int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret);
char *unit_name_escape(const char *f);
-char *unit_name_unescape(const char *f);
-char *unit_name_path_escape(const char *f);
-char *unit_name_path_unescape(const char *f);
-
-bool unit_name_is_template(const char *n) _pure_;
-bool unit_name_is_instance(const char *n) _pure_;
+int unit_name_unescape(const char *f, char **ret);
+int unit_name_path_escape(const char *f, char **ret);
+int unit_name_path_unescape(const char *f, char **ret);
-char *unit_name_replace_instance(const char *f, const char *i);
+int unit_name_replace_instance(const char *f, const char *i, char **ret);
-char *unit_name_template(const char *f);
+int unit_name_template(const char *f, char **ret);
-char *unit_name_from_path(const char *path, const char *suffix);
-char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix);
-char *unit_name_to_path(const char *name);
+int unit_name_from_path(const char *path, const char *suffix, char **ret);
+int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret);
+int unit_name_to_path(const char *name, char **ret);
char *unit_dbus_path_from_name(const char *name);
int unit_name_from_dbus_path(const char *path, char **name);
-enum unit_name_mangle {
- MANGLE_NOGLOB,
- MANGLE_GLOB,
-};
+typedef enum UnitNameMangle {
+ UNIT_NAME_NOGLOB,
+ UNIT_NAME_GLOB,
+} UnitNameMangle;
+
+int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret);
-char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix);
-static inline char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs) {
- return unit_name_mangle_with_suffix(name, allow_globs, ".service");
+static inline int unit_name_mangle(const char *name, UnitNameMangle allow_globs, char **ret) {
+ return unit_name_mangle_with_suffix(name, allow_globs, ".service", ret);
}
-int build_subslice(const char *slice, const char*name, char **subslice);
+int slice_build_parent_slice(const char *slice, char **ret);
+int slice_build_subslice(const char *slice, const char*name, char **subslice);
+bool slice_name_is_valid(const char *name);
+
+const char *unit_type_to_string(UnitType i) _const_;
+UnitType unit_type_from_string(const char *s) _pure_;
+
+const char *unit_load_state_to_string(UnitLoadState i) _const_;
+UnitLoadState unit_load_state_from_string(const char *s) _pure_;
const char *unit_dependency_to_string(UnitDependency i) _const_;
UnitDependency unit_dependency_from_string(const char *s) _pure_;
diff --git a/src/shared/utf8.c b/src/shared/utf8.c
index 013c110f07..800884ffee 100644
--- a/src/shared/utf8.c
+++ b/src/shared/utf8.c
@@ -52,7 +52,7 @@
#include "utf8.h"
#include "util.h"
-static inline bool is_unicode_valid(uint32_t ch) {
+bool unichar_is_valid(uint32_t ch) {
if (ch >= 0x110000) /* End of unicode space */
return false;
@@ -66,7 +66,7 @@ static inline bool is_unicode_valid(uint32_t ch) {
return true;
}
-static bool is_unicode_control(uint32_t ch) {
+static bool unichar_is_control(uint32_t ch) {
/*
0 to ' '-1 is the C0 range.
@@ -156,7 +156,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
val = utf8_encoded_to_unichar(p);
if (val < 0 ||
- is_unicode_control(val) ||
+ unichar_is_control(val) ||
(!newline && val == '\n'))
return false;
@@ -276,6 +276,7 @@ char *ascii_is_valid(const char *str) {
* occupy.
*/
size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
+
if (g < (1 << 7)) {
if (out_utf8)
out_utf8[0] = g & 0x7f;
@@ -301,9 +302,9 @@ size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
out_utf8[3] = 0x80 | (g & 0x3f);
}
return 4;
- } else {
- return 0;
}
+
+ return 0;
}
char *utf16_to_utf8(const void *s, size_t length) {
@@ -394,7 +395,7 @@ int utf8_encoded_valid_unichar(const char *str) {
return -EINVAL;
/* check if value has valid range */
- if (!is_unicode_valid(unichar))
+ if (!unichar_is_valid(unichar))
return -EINVAL;
return len;
diff --git a/src/shared/utf8.h b/src/shared/utf8.h
index 77f663438e..e745649f06 100644
--- a/src/shared/utf8.h
+++ b/src/shared/utf8.h
@@ -27,6 +27,8 @@
#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
+bool unichar_is_valid(uint32_t c);
+
const char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
diff --git a/src/shared/util.c b/src/shared/util.c
index ba035caed0..311acbb349 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -19,12 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
+#include <libintl.h>
#include <stdio.h>
#include <syslog.h>
#include <sched.h>
@@ -35,9 +35,6 @@
#include <fcntl.h>
#include <dirent.h>
#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <termios.h>
#include <stdarg.h>
#include <poll.h>
#include <ctype.h>
@@ -45,8 +42,6 @@
#include <sys/utsname.h>
#include <pwd.h>
#include <netinet/ip.h>
-#include <linux/kd.h>
-#include <dlfcn.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <glob.h>
@@ -74,13 +69,13 @@
#include <sys/auxv.h>
#endif
+#include "config.h"
#include "macro.h"
#include "util.h"
#include "ioprio.h"
#include "missing.h"
#include "log.h"
#include "strv.h"
-#include "label.h"
#include "mkdir.h"
#include "path-util.h"
#include "exit-status.h"
@@ -93,13 +88,19 @@
#include "virt.h"
#include "def.h"
#include "sparse-endian.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "random-util.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
+
+/* Put this test here for a lack of better place */
+assert_cc(EAGAIN == EWOULDBLOCK);
int saved_argc = 0;
char **saved_argv = NULL;
-static volatile unsigned cached_columns = 0;
-static volatile unsigned cached_lines = 0;
-
size_t page_size(void) {
static thread_local size_t pgsz = 0;
long r;
@@ -148,6 +149,27 @@ char* endswith(const char *s, const char *postfix) {
return (char*) s + sl - pl;
}
+char* endswith_no_case(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (strcasecmp(s + sl - pl, postfix) != 0)
+ return NULL;
+
+ return (char*) s + sl - pl;
+}
+
char* first_word(const char *s, const char *word) {
size_t sl, wl;
const char *p;
@@ -182,7 +204,7 @@ char* first_word(const char *s, const char *word) {
return (char*) p;
}
-static size_t cescape_char(char c, char *buf) {
+size_t cescape_char(char c, char *buf) {
char * buf_old = buf;
switch (c) {
@@ -351,7 +373,6 @@ int parse_uid(const char *s, uid_t* ret_uid) {
int r;
assert(s);
- assert(ret_uid);
r = safe_atolu(s, &ul);
if (r < 0)
@@ -370,7 +391,9 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if (uid == (uid_t) 0xFFFF)
return -ENXIO;
- *ret_uid = uid;
+ if (ret_uid)
+ *ret_uid = uid;
+
return 0;
}
@@ -571,13 +594,12 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
char quotechars[2] = {*current, '\0'};
*l = strcspn_escaped(current + 1, quotechars);
- if (current[*l + 1] == '\0' ||
+ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
(current[*l + 2] && !strchr(separator, current[*l + 2]))) {
/* right quote missing or garbage at the end */
*state = current;
return NULL;
}
- assert(current[*l + 1] == quotechars[0]);
*state = current++ + *l + 2;
} else if (quoted) {
*l = strcspn_escaped(current, separator);
@@ -595,49 +617,6 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
return current;
}
-int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
- int r;
- _cleanup_free_ char *line = NULL;
- long unsigned ppid;
- const char *p;
-
- assert(pid >= 0);
- assert(_ppid);
-
- if (pid == 0) {
- *_ppid = getppid();
- return 0;
- }
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- /* Let's skip the pid and comm fields. The latter is enclosed
- * in () but does not escape any () in its value, so let's
- * skip over it manually */
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " "
- "%*c " /* state */
- "%lu ", /* ppid */
- &ppid) != 1)
- return -EIO;
-
- if ((long unsigned) (pid_t) ppid != ppid)
- return -ERANGE;
-
- *_ppid = (pid_t) ppid;
-
- return 0;
-}
-
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
@@ -656,308 +635,6 @@ char *truncate_nl(char *s) {
return s;
}
-int get_process_state(pid_t pid) {
- const char *p;
- char state;
- int r;
- _cleanup_free_ char *line = NULL;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " %c", &state) != 1)
- return -EIO;
-
- return (unsigned char) state;
-}
-
-int get_process_comm(pid_t pid, char **name) {
- const char *p;
- int r;
-
- assert(name);
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "comm");
-
- r = read_one_line_file(p, name);
- if (r == -ENOENT)
- return -ESRCH;
-
- return r;
-}
-
-int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
- _cleanup_fclose_ FILE *f = NULL;
- char *r = NULL, *k;
- const char *p;
- int c;
-
- assert(line);
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "cmdline");
-
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- if (max_length == 0) {
- size_t len = 0, allocated = 0;
-
- while ((c = getc(f)) != EOF) {
-
- if (!GREEDY_REALLOC(r, allocated, len+2)) {
- free(r);
- return -ENOMEM;
- }
-
- r[len++] = isprint(c) ? c : ' ';
- }
-
- if (len > 0)
- r[len-1] = 0;
-
- } else {
- bool space = false;
- size_t left;
-
- r = new(char, max_length);
- if (!r)
- return -ENOMEM;
-
- k = r;
- left = max_length;
- while ((c = getc(f)) != EOF) {
-
- if (isprint(c)) {
- if (space) {
- if (left <= 4)
- break;
-
- *(k++) = ' ';
- left--;
- space = false;
- }
-
- if (left <= 4)
- break;
-
- *(k++) = (char) c;
- left--;
- } else
- space = true;
- }
-
- if (left <= 4) {
- size_t n = MIN(left-1, 3U);
- memcpy(k, "...", n);
- k[n] = 0;
- } else
- *k = 0;
- }
-
- /* Kernel threads have no argv[] */
- if (isempty(r)) {
- _cleanup_free_ char *t = NULL;
- int h;
-
- free(r);
-
- if (!comm_fallback)
- return -ENOENT;
-
- h = get_process_comm(pid, &t);
- if (h < 0)
- return h;
-
- r = strjoin("[", t, "]", NULL);
- if (!r)
- return -ENOMEM;
- }
-
- *line = r;
- return 0;
-}
-
-int is_kernel_thread(pid_t pid) {
- const char *p;
- size_t count;
- char c;
- bool eof;
- FILE *f;
-
- if (pid == 0)
- return 0;
-
- assert(pid > 0);
-
- p = procfs_file_alloca(pid, "cmdline");
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- count = fread(&c, 1, 1, f);
- eof = feof(f);
- fclose(f);
-
- /* Kernel threads have an empty cmdline */
-
- if (count <= 0)
- return eof ? 1 : -errno;
-
- return 0;
-}
-
-int get_process_capeff(pid_t pid, char **capeff) {
- const char *p;
-
- assert(capeff);
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "status");
-
- return get_status_field(p, "\nCapEff:", capeff);
-}
-
-static int get_process_link_contents(const char *proc_file, char **name) {
- int r;
-
- assert(proc_file);
- assert(name);
-
- r = readlink_malloc(proc_file, name);
- if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
-
- return 0;
-}
-
-int get_process_exe(pid_t pid, char **name) {
- const char *p;
- char *d;
- int r;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "exe");
- r = get_process_link_contents(p, name);
- if (r < 0)
- return r;
-
- d = endswith(*name, " (deleted)");
- if (d)
- *d = '\0';
-
- return 0;
-}
-
-static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
- _cleanup_fclose_ FILE *f = NULL;
- char line[LINE_MAX];
- const char *p;
-
- assert(field);
- assert(uid);
-
- if (pid == 0)
- return getuid();
-
- p = procfs_file_alloca(pid, "status");
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- FOREACH_LINE(line, f, return -errno) {
- char *l;
-
- l = strstrip(line);
-
- if (startswith(l, field)) {
- l += strlen(field);
- l += strspn(l, WHITESPACE);
-
- l[strcspn(l, WHITESPACE)] = 0;
-
- return parse_uid(l, uid);
- }
- }
-
- return -EIO;
-}
-
-int get_process_uid(pid_t pid, uid_t *uid) {
- return get_process_id(pid, "Uid:", uid);
-}
-
-int get_process_gid(pid_t pid, gid_t *gid) {
- assert_cc(sizeof(uid_t) == sizeof(gid_t));
- return get_process_id(pid, "Gid:", gid);
-}
-
-int get_process_cwd(pid_t pid, char **cwd) {
- const char *p;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "cwd");
-
- return get_process_link_contents(p, cwd);
-}
-
-int get_process_root(pid_t pid, char **root) {
- const char *p;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "root");
-
- return get_process_link_contents(p, root);
-}
-
-int get_process_environ(pid_t pid, char **env) {
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *outcome = NULL;
- int c;
- const char *p;
- size_t allocated = 0, sz = 0;
-
- assert(pid >= 0);
- assert(env);
-
- p = procfs_file_alloca(pid, "environ");
-
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- while ((c = fgetc(f)) != EOF) {
- if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
- return -ENOMEM;
-
- if (c == '\0')
- outcome[sz++] = '\n';
- else
- sz += cescape_char(c, outcome + sz);
- }
-
- outcome[sz] = '\0';
- *env = outcome;
- outcome = NULL;
-
- return 0;
-}
-
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
@@ -1095,41 +772,6 @@ int readlink_and_canonicalize(const char *p, char **r) {
return 0;
}
-int reset_all_signal_handlers(void) {
- int sig, r = 0;
-
- for (sig = 1; sig < _NSIG; sig++) {
- struct sigaction sa = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_RESTART,
- };
-
- /* These two cannot be caught... */
- if (sig == SIGKILL || sig == SIGSTOP)
- continue;
-
- /* On Linux the first two RT signals are reserved by
- * glibc, and sigaction() will return EINVAL for them. */
- if ((sigaction(sig, &sa, NULL) < 0))
- if (errno != EINVAL && r == 0)
- r = -errno;
- }
-
- return r;
-}
-
-int reset_signal_mask(void) {
- sigset_t ss;
-
- if (sigemptyset(&ss) < 0)
- return -errno;
-
- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
- return -errno;
-
- return 0;
-}
-
char *strstrip(char *s) {
char *e;
@@ -1330,7 +972,8 @@ char *cescape(const char *s) {
assert(s);
- /* Does C style string escaping. */
+ /* Does C style string escaping. May be reversed with
+ * cunescape(). */
r = new(char, strlen(s)*4 + 1);
if (!r)
@@ -1344,12 +987,214 @@ char *cescape(const char *s) {
return r;
}
-char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) {
+static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
+ int r = 1;
+
+ assert(p);
+ assert(*p);
+ assert(ret);
+
+ /* Unescapes C style. Returns the unescaped character in ret,
+ * unless we encountered a \u sequence in which case the full
+ * unicode character is returned in ret_unicode, instead. */
+
+ if (length != (size_t) -1 && length < 1)
+ return -EINVAL;
+
+ switch (p[0]) {
+
+ case 'a':
+ *ret = '\a';
+ break;
+ case 'b':
+ *ret = '\b';
+ break;
+ case 'f':
+ *ret = '\f';
+ break;
+ case 'n':
+ *ret = '\n';
+ break;
+ case 'r':
+ *ret = '\r';
+ break;
+ case 't':
+ *ret = '\t';
+ break;
+ case 'v':
+ *ret = '\v';
+ break;
+ case '\\':
+ *ret = '\\';
+ break;
+ case '"':
+ *ret = '"';
+ break;
+ case '\'':
+ *ret = '\'';
+ break;
+
+ case 's':
+ /* This is an extension of the XDG syntax files */
+ *ret = ' ';
+ break;
+
+ case 'x': {
+ /* hexadecimal encoding */
+ int a, b;
+
+ if (length != (size_t) -1 && length < 3)
+ return -EINVAL;
+
+ a = unhexchar(p[1]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unhexchar(p[2]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* Don't allow NUL bytes */
+ if (a == 0 && b == 0)
+ return -EINVAL;
+
+ *ret = (char) ((a << 4U) | b);
+ r = 3;
+ break;
+ }
+
+ case 'u': {
+ /* C++11 style 16bit unicode */
+
+ int a[4];
+ unsigned i;
+ uint32_t c;
+
+ if (length != (size_t) -1 && length < 5)
+ return -EINVAL;
+
+ for (i = 0; i < 4; i++) {
+ a[i] = unhexchar(p[1 + i]);
+ if (a[i] < 0)
+ return a[i];
+ }
+
+ c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
+
+ /* Don't allow 0 chars */
+ if (c == 0)
+ return -EINVAL;
+
+ if (c < 128)
+ *ret = c;
+ else {
+ if (!ret_unicode)
+ return -EINVAL;
+
+ *ret = 0;
+ *ret_unicode = c;
+ }
+
+ r = 5;
+ break;
+ }
+
+ case 'U': {
+ /* C++11 style 32bit unicode */
+
+ int a[8];
+ unsigned i;
+ uint32_t c;
+
+ if (length != (size_t) -1 && length < 9)
+ return -EINVAL;
+
+ for (i = 0; i < 8; i++) {
+ a[i] = unhexchar(p[1 + i]);
+ if (a[i] < 0)
+ return a[i];
+ }
+
+ c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
+ ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
+
+ /* Don't allow 0 chars */
+ if (c == 0)
+ return -EINVAL;
+
+ /* Don't allow invalid code points */
+ if (!unichar_is_valid(c))
+ return -EINVAL;
+
+ if (c < 128)
+ *ret = c;
+ else {
+ if (!ret_unicode)
+ return -EINVAL;
+
+ *ret = 0;
+ *ret_unicode = c;
+ }
+
+ r = 9;
+ break;
+ }
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': {
+ /* octal encoding */
+ int a, b, c;
+ uint32_t m;
+
+ if (length != (size_t) -1 && length < 3)
+ return -EINVAL;
+
+ a = unoctchar(p[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unoctchar(p[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unoctchar(p[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ /* don't allow NUL bytes */
+ if (a == 0 && b == 0 && c == 0)
+ return -EINVAL;
+
+ /* Don't allow bytes above 255 */
+ m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
+ if (m > 255)
+ return -EINVAL;
+
+ *ret = m;
+ r = 3;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return r;
+}
+
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
char *r, *t;
const char *f;
size_t pl;
assert(s);
+ assert(ret);
/* Undoes C style string escaping, and optionally prefixes it. */
@@ -1357,135 +1202,71 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre
r = new(char, pl+length+1);
if (!r)
- return NULL;
+ return -ENOMEM;
if (prefix)
memcpy(r, prefix, pl);
for (f = s, t = r + pl; f < s + length; f++) {
- size_t remaining = s + length - f;
+ size_t remaining;
+ uint32_t u;
+ char c;
+ int k;
+
+ remaining = s + length - f;
assert(remaining > 0);
- if (*f != '\\') { /* a literal literal */
+ if (*f != '\\') {
+ /* A literal literal, copy verbatim */
*(t++) = *f;
continue;
}
- if (--remaining == 0) { /* copy trailing backslash verbatim */
- *(t++) = *f;
- break;
- }
-
- f++;
-
- switch (*f) {
-
- case 'a':
- *(t++) = '\a';
- break;
- case 'b':
- *(t++) = '\b';
- break;
- case 'f':
- *(t++) = '\f';
- break;
- case 'n':
- *(t++) = '\n';
- break;
- case 'r':
- *(t++) = '\r';
- break;
- case 't':
- *(t++) = '\t';
- break;
- case 'v':
- *(t++) = '\v';
- break;
- case '\\':
- *(t++) = '\\';
- break;
- case '"':
- *(t++) = '"';
- break;
- case '\'':
- *(t++) = '\'';
- break;
-
- case 's':
- /* This is an extension of the XDG syntax files */
- *(t++) = ' ';
- break;
-
- case 'x': {
- /* hexadecimal encoding */
- int a = -1, b = -1;
-
- if (remaining >= 2) {
- a = unhexchar(f[1]);
- b = unhexchar(f[2]);
- }
-
- if (a < 0 || b < 0 || (a == 0 && b == 0)) {
- /* Invalid escape code, let's take it literal then */
- *(t++) = '\\';
- *(t++) = 'x';
- } else {
- *(t++) = (char) ((a << 4) | b);
- f += 2;
+ if (remaining == 1) {
+ if (flags & UNESCAPE_RELAX) {
+ /* A trailing backslash, copy verbatim */
+ *(t++) = *f;
+ continue;
}
- break;
+ free(r);
+ return -EINVAL;
}
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7': {
- /* octal encoding */
- int a = -1, b = -1, c = -1;
-
- if (remaining >= 3) {
- a = unoctchar(f[0]);
- b = unoctchar(f[1]);
- c = unoctchar(f[2]);
- }
-
- if (a < 0 || b < 0 || c < 0 || (a == 0 && b == 0 && c == 0)) {
+ k = cunescape_one(f + 1, remaining - 1, &c, &u);
+ if (k < 0) {
+ if (flags & UNESCAPE_RELAX) {
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
- *(t++) = f[0];
- } else {
- *(t++) = (char) ((a << 6) | (b << 3) | c);
- f += 2;
+ continue;
}
- break;
+ free(r);
+ return k;
}
- default:
- /* Invalid escape code, let's take it literal then */
- *(t++) = '\\';
- *(t++) = *f;
- break;
- }
+ if (c != 0)
+ /* Non-Unicode? Let's encode this directly */
+ *(t++) = c;
+ else
+ /* Unicode? Then let's encode this in UTF-8 */
+ t += utf8_encode_unichar(t, u);
+
+ f += k;
}
*t = 0;
- return r;
-}
-char *cunescape_length(const char *s, size_t length) {
- return cunescape_length_with_prefix(s, length, NULL);
+ *ret = r;
+ return t - r;
}
-char *cunescape(const char *s) {
- assert(s);
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
+ return cunescape_length_with_prefix(s, length, NULL, flags, ret);
+}
- return cunescape_length(s, strlen(s));
+int cunescape(const char *s, UnescapeFlags flags, char **ret) {
+ return cunescape_length(s, strlen(s), flags, ret);
}
char *xescape(const char *s, const char *bad) {
@@ -1494,7 +1275,7 @@ char *xescape(const char *s, const char *bad) {
/* Escapes all chars in bad, in addition to \ and all special
* chars, in \xFF style escaping. May be reversed with
- * cunescape. */
+ * cunescape(). */
r = new(char, strlen(s) * 4 + 1);
if (!r)
@@ -1689,6 +1470,7 @@ bool chars_intersect(const char *a, const char *b) {
bool fstype_is_network(const char *fstype) {
static const char table[] =
+ "afs\0"
"cifs\0"
"smbfs\0"
"sshfs\0"
@@ -1709,301 +1491,6 @@ bool fstype_is_network(const char *fstype) {
return nulstr_contains(table, fstype);
}
-int chvt(int vt) {
- _cleanup_close_ int fd;
-
- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- if (vt < 0) {
- int tiocl[2] = {
- TIOCL_GETKMSGREDIRECT,
- 0
- };
-
- if (ioctl(fd, TIOCLINUX, tiocl) < 0)
- return -errno;
-
- vt = tiocl[0] <= 0 ? 1 : tiocl[0];
- }
-
- if (ioctl(fd, VT_ACTIVATE, vt) < 0)
- return -errno;
-
- return 0;
-}
-
-int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
- struct termios old_termios, new_termios;
- char c, line[LINE_MAX];
-
- assert(f);
- assert(ret);
-
- if (tcgetattr(fileno(f), &old_termios) >= 0) {
- new_termios = old_termios;
-
- new_termios.c_lflag &= ~ICANON;
- new_termios.c_cc[VMIN] = 1;
- new_termios.c_cc[VTIME] = 0;
-
- if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
- size_t k;
-
- if (t != USEC_INFINITY) {
- if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
- tcsetattr(fileno(f), TCSADRAIN, &old_termios);
- return -ETIMEDOUT;
- }
- }
-
- k = fread(&c, 1, 1, f);
-
- tcsetattr(fileno(f), TCSADRAIN, &old_termios);
-
- if (k <= 0)
- return -EIO;
-
- if (need_nl)
- *need_nl = c != '\n';
-
- *ret = c;
- return 0;
- }
- }
-
- if (t != USEC_INFINITY) {
- if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
- return -ETIMEDOUT;
- }
-
- errno = 0;
- if (!fgets(line, sizeof(line), f))
- return errno ? -errno : -EIO;
-
- truncate_nl(line);
-
- if (strlen(line) != 1)
- return -EBADMSG;
-
- if (need_nl)
- *need_nl = false;
-
- *ret = line[0];
- return 0;
-}
-
-int ask_char(char *ret, const char *replies, const char *text, ...) {
- int r;
-
- assert(ret);
- assert(replies);
- assert(text);
-
- for (;;) {
- va_list ap;
- char c;
- bool need_nl = true;
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_ON, stdout);
-
- va_start(ap, text);
- vprintf(text, ap);
- va_end(ap);
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
-
- fflush(stdout);
-
- r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
- if (r < 0) {
-
- if (r == -EBADMSG) {
- puts("Bad input, please try again.");
- continue;
- }
-
- putchar('\n');
- return r;
- }
-
- if (need_nl)
- putchar('\n');
-
- if (strchr(replies, c)) {
- *ret = c;
- return 0;
- }
-
- puts("Read unexpected character, please try again.");
- }
-}
-
-int ask_string(char **ret, const char *text, ...) {
- assert(ret);
- assert(text);
-
- for (;;) {
- char line[LINE_MAX];
- va_list ap;
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_ON, stdout);
-
- va_start(ap, text);
- vprintf(text, ap);
- va_end(ap);
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
-
- fflush(stdout);
-
- errno = 0;
- if (!fgets(line, sizeof(line), stdin))
- return errno ? -errno : -EIO;
-
- if (!endswith(line, "\n"))
- putchar('\n');
- else {
- char *s;
-
- if (isempty(line))
- continue;
-
- truncate_nl(line);
- s = strdup(line);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
- return 0;
- }
- }
-}
-
-int reset_terminal_fd(int fd, bool switch_to_text) {
- struct termios termios;
- int r = 0;
-
- /* Set terminal to some sane defaults */
-
- assert(fd >= 0);
-
- /* We leave locked terminal attributes untouched, so that
- * Plymouth may set whatever it wants to set, and we don't
- * interfere with that. */
-
- /* Disable exclusive mode, just in case */
- ioctl(fd, TIOCNXCL);
-
- /* Switch to text mode */
- if (switch_to_text)
- ioctl(fd, KDSETMODE, KD_TEXT);
-
- /* Enable console unicode mode */
- ioctl(fd, KDSKBMODE, K_UNICODE);
-
- if (tcgetattr(fd, &termios) < 0) {
- r = -errno;
- goto finish;
- }
-
- /* We only reset the stuff that matters to the software. How
- * hardware is set up we don't touch assuming that somebody
- * else will do that for us */
-
- termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
- termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
- termios.c_oflag |= ONLCR;
- termios.c_cflag |= CREAD;
- termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
-
- termios.c_cc[VINTR] = 03; /* ^C */
- termios.c_cc[VQUIT] = 034; /* ^\ */
- termios.c_cc[VERASE] = 0177;
- termios.c_cc[VKILL] = 025; /* ^X */
- termios.c_cc[VEOF] = 04; /* ^D */
- termios.c_cc[VSTART] = 021; /* ^Q */
- termios.c_cc[VSTOP] = 023; /* ^S */
- termios.c_cc[VSUSP] = 032; /* ^Z */
- termios.c_cc[VLNEXT] = 026; /* ^V */
- termios.c_cc[VWERASE] = 027; /* ^W */
- termios.c_cc[VREPRINT] = 022; /* ^R */
- termios.c_cc[VEOL] = 0;
- termios.c_cc[VEOL2] = 0;
-
- termios.c_cc[VTIME] = 0;
- termios.c_cc[VMIN] = 1;
-
- if (tcsetattr(fd, TCSANOW, &termios) < 0)
- r = -errno;
-
-finish:
- /* Just in case, flush all crap out */
- tcflush(fd, TCIOFLUSH);
-
- return r;
-}
-
-int reset_terminal(const char *name) {
- _cleanup_close_ int fd = -1;
-
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- return reset_terminal_fd(fd, true);
-}
-
-int open_terminal(const char *name, int mode) {
- int fd, r;
- unsigned c = 0;
-
- /*
- * If a TTY is in the process of being closed opening it might
- * cause EIO. This is horribly awful, but unlikely to be
- * changed in the kernel. Hence we work around this problem by
- * retrying a couple of times.
- *
- * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
- */
-
- assert(!(mode & O_CREAT));
-
- for (;;) {
- fd = open(name, mode, 0);
- if (fd >= 0)
- break;
-
- if (errno != EIO)
- return -errno;
-
- /* Max 1s in total */
- if (c >= 20)
- return -errno;
-
- usleep(50 * USEC_PER_MSEC);
- c++;
- }
-
- r = isatty(fd);
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
-
- if (!r) {
- safe_close(fd);
- return -ENOTTY;
- }
-
- return fd;
-}
-
int flush_fd(int fd) {
struct pollfd pollfd = {
.fd = fd,
@@ -2040,238 +1527,6 @@ int flush_fd(int fd) {
}
}
-int acquire_terminal(
- const char *name,
- bool fail,
- bool force,
- bool ignore_tiocstty_eperm,
- usec_t timeout) {
-
- int fd = -1, notify = -1, r = 0, wd = -1;
- usec_t ts = 0;
-
- assert(name);
-
- /* We use inotify to be notified when the tty is closed. We
- * create the watch before checking if we can actually acquire
- * it, so that we don't lose any event.
- *
- * Note: strictly speaking this actually watches for the
- * device being closed, it does *not* really watch whether a
- * tty loses its controlling process. However, unless some
- * rogue process uses TIOCNOTTY on /dev/tty *after* closing
- * its tty otherwise this will not become a problem. As long
- * as the administrator makes sure not configure any service
- * on the same tty as an untrusted user this should not be a
- * problem. (Which he probably should not do anyway.) */
-
- if (timeout != USEC_INFINITY)
- ts = now(CLOCK_MONOTONIC);
-
- if (!fail && !force) {
- notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
- if (notify < 0) {
- r = -errno;
- goto fail;
- }
-
- wd = inotify_add_watch(notify, name, IN_CLOSE);
- if (wd < 0) {
- r = -errno;
- goto fail;
- }
- }
-
- for (;;) {
- struct sigaction sa_old, sa_new = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
-
- if (notify >= 0) {
- r = flush_fd(notify);
- if (r < 0)
- goto fail;
- }
-
- /* We pass here O_NOCTTY only so that we can check the return
- * value TIOCSCTTY and have a reliable way to figure out if we
- * successfully became the controlling process of the tty */
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
- * if we already own the tty. */
- assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
- /* First, try to get the tty */
- if (ioctl(fd, TIOCSCTTY, force) < 0)
- r = -errno;
-
- assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
- /* Sometimes it makes sense to ignore TIOCSCTTY
- * returning EPERM, i.e. when very likely we already
- * are have this controlling terminal. */
- if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
- r = 0;
-
- if (r < 0 && (force || fail || r != -EPERM)) {
- goto fail;
- }
-
- if (r >= 0)
- break;
-
- assert(!fail);
- assert(!force);
- assert(notify >= 0);
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- if (timeout != USEC_INFINITY) {
- usec_t n;
-
- n = now(CLOCK_MONOTONIC);
- if (ts + timeout < n) {
- r = -ETIMEDOUT;
- goto fail;
- }
-
- r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
- if (r < 0)
- goto fail;
-
- if (r == 0) {
- r = -ETIMEDOUT;
- goto fail;
- }
- }
-
- l = read(notify, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
-
- r = -errno;
- goto fail;
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- if (e->wd != wd || !(e->mask & IN_CLOSE)) {
- r = -EIO;
- goto fail;
- }
- }
-
- break;
- }
-
- /* We close the tty fd here since if the old session
- * ended our handle will be dead. It's important that
- * we do this after sleeping, so that we don't enter
- * an endless loop. */
- fd = safe_close(fd);
- }
-
- safe_close(notify);
-
- r = reset_terminal_fd(fd, true);
- if (r < 0)
- log_warning_errno(r, "Failed to reset terminal: %m");
-
- return fd;
-
-fail:
- safe_close(fd);
- safe_close(notify);
-
- return r;
-}
-
-int release_terminal(void) {
- static const struct sigaction sa_new = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
-
- _cleanup_close_ int fd = -1;
- struct sigaction sa_old;
- int r = 0;
-
- fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
- * by our own TIOCNOTTY */
- assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
- if (ioctl(fd, TIOCNOTTY) < 0)
- r = -errno;
-
- assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
- return r;
-}
-
-int sigaction_many(const struct sigaction *sa, ...) {
- va_list ap;
- int r = 0, sig;
-
- va_start(ap, sa);
- while ((sig = va_arg(ap, int)) > 0)
- if (sigaction(sig, sa, NULL) < 0)
- r = -errno;
- va_end(ap);
-
- return r;
-}
-
-int ignore_signals(int sig, ...) {
- struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
- va_list ap;
- int r = 0;
-
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
-
- va_start(ap, sig);
- while ((sig = va_arg(ap, int)) > 0)
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
- va_end(ap);
-
- return r;
-}
-
-int default_signals(int sig, ...) {
- struct sigaction sa = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_RESTART,
- };
- va_list ap;
- int r = 0;
-
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
-
- va_start(ap, sig);
- while ((sig = va_arg(ap, int)) > 0)
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
- va_end(ap);
-
- return r;
-}
-
void safe_close_pair(int p[]) {
assert(p);
@@ -2325,6 +1580,17 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
return n;
}
+int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
+ ssize_t n;
+
+ n = loop_read(fd, buf, nbytes, do_poll);
+ if (n < 0)
+ return n;
+ if ((size_t) n != nbytes)
+ return -EIO;
+ return 0;
+}
+
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
const uint8_t *p = buf;
@@ -2333,7 +1599,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
errno = 0;
- while (nbytes > 0) {
+ do {
ssize_t k;
k = write(fd, p, nbytes);
@@ -2353,23 +1619,23 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
return -errno;
}
- if (k == 0) /* Can't really happen */
+ if (nbytes > 0 && k == 0) /* Can't really happen */
return -EIO;
p += k;
nbytes -= k;
- }
+ } while (nbytes > 0);
return 0;
}
int parse_size(const char *t, off_t base, off_t *size) {
- /* Soo, sometimes we want to parse IEC binary suffxies, and
+ /* Soo, sometimes we want to parse IEC binary suffixes, and
* sometimes SI decimal suffixes. This function can parse
* both. Which one is the right way depends on the
* context. Wikipedia suggests that SI is customary for
- * hardrware metrics and network speeds, while IEC is
+ * hardware metrics and network speeds, while IEC is
* customary for most data sizes used by software and volatile
* (RAM) memory. Hence be careful which one you pick!
*
@@ -2492,40 +1758,6 @@ int parse_size(const char *t, off_t base, off_t *size) {
return 0;
}
-int make_stdio(int fd) {
- int r, s, t;
-
- assert(fd >= 0);
-
- r = dup2(fd, STDIN_FILENO);
- s = dup2(fd, STDOUT_FILENO);
- t = dup2(fd, STDERR_FILENO);
-
- if (fd >= 3)
- safe_close(fd);
-
- if (r < 0 || s < 0 || t < 0)
- return -errno;
-
- /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
- * dup2() was a NOP and the bit hence possibly set. */
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
-
- return 0;
-}
-
-int make_null_stdio(void) {
- int null_fd;
-
- null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
- if (null_fd < 0)
- return -errno;
-
- return make_stdio(null_fd);
-}
-
bool is_device_path(const char *path) {
/* Returns true on paths that refer to a device, either in
@@ -2577,108 +1809,6 @@ char* dirname_malloc(const char *path) {
return dir;
}
-int dev_urandom(void *p, size_t n) {
- static int have_syscall = -1;
- int r, fd;
- ssize_t k;
-
- /* Gathers some randomness from the kernel. This call will
- * never block, and will always return some data from the
- * kernel, regardless if the random pool is fully initialized
- * or not. It thus makes no guarantee for the quality of the
- * returned entropy, but is good enough for or usual usecases
- * of seeding the hash functions for hashtable */
-
- /* Use the getrandom() syscall unless we know we don't have
- * it, or when the requested size is too large for it. */
- if (have_syscall != 0 || (size_t) (int) n != n) {
- r = getrandom(p, n, GRND_NONBLOCK);
- if (r == (int) n) {
- have_syscall = true;
- return 0;
- }
-
- if (r < 0) {
- if (errno == ENOSYS)
- /* we lack the syscall, continue with
- * reading from /dev/urandom */
- have_syscall = false;
- else if (errno == EAGAIN)
- /* not enough entropy for now. Let's
- * remember to use the syscall the
- * next time, again, but also read
- * from /dev/urandom for now, which
- * doesn't care about the current
- * amount of entropy. */
- have_syscall = true;
- else
- return -errno;
- } else
- /* too short read? */
- return -EIO;
- }
-
- fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return errno == ENOENT ? -ENOSYS : -errno;
-
- k = loop_read(fd, p, n, true);
- safe_close(fd);
-
- if (k < 0)
- return (int) k;
- if ((size_t) k != n)
- return -EIO;
-
- return 0;
-}
-
-void initialize_srand(void) {
- static bool srand_called = false;
- unsigned x;
-#ifdef HAVE_SYS_AUXV_H
- void *auxv;
-#endif
-
- if (srand_called)
- return;
-
- x = 0;
-
-#ifdef HAVE_SYS_AUXV_H
- /* The kernel provides us with a bit of entropy in auxv, so
- * let's try to make use of that to seed the pseudo-random
- * generator. It's better than nothing... */
-
- auxv = (void*) getauxval(AT_RANDOM);
- if (auxv)
- x ^= *(unsigned*) auxv;
-#endif
-
- x ^= (unsigned) now(CLOCK_REALTIME);
- x ^= (unsigned) gettid();
-
- srand(x);
- srand_called = true;
-}
-
-void random_bytes(void *p, size_t n) {
- uint8_t *q;
- int r;
-
- r = dev_urandom(p, n);
- if (r >= 0)
- return;
-
- /* If some idiot made /dev/urandom unavailable to us, he'll
- * get a PRNG instead. */
-
- initialize_srand();
-
- for (q = p; q < (uint8_t*) p + n; q ++)
- *q = rand();
-}
-
void rename_process(const char name[8]) {
assert(name);
@@ -2710,55 +1840,6 @@ void rename_process(const char name[8]) {
}
}
-void sigset_add_many(sigset_t *ss, ...) {
- va_list ap;
- int sig;
-
- assert(ss);
-
- va_start(ap, ss);
- while ((sig = va_arg(ap, int)) > 0)
- assert_se(sigaddset(ss, sig) == 0);
- va_end(ap);
-}
-
-int sigprocmask_many(int how, ...) {
- va_list ap;
- sigset_t ss;
- int sig;
-
- assert_se(sigemptyset(&ss) == 0);
-
- va_start(ap, how);
- while ((sig = va_arg(ap, int)) > 0)
- assert_se(sigaddset(&ss, sig) == 0);
- va_end(ap);
-
- if (sigprocmask(how, &ss, NULL) < 0)
- return -errno;
-
- return 0;
-}
-
-char* gethostname_malloc(void) {
- struct utsname u;
-
- assert_se(uname(&u) >= 0);
-
- if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
- return strdup(u.nodename);
-
- return strdup(u.sysname);
-}
-
-bool hostname_is_set(void) {
- struct utsname u;
-
- assert_se(uname(&u) >= 0);
-
- return !isempty(u.nodename) && !streq(u.nodename, "(none)");
-}
-
char *lookup_uid(uid_t uid) {
long bufsize;
char *name;
@@ -2808,243 +1889,14 @@ char *getusername_malloc(void) {
return lookup_uid(getuid());
}
-int getttyname_malloc(int fd, char **ret) {
- size_t l = 100;
- int r;
-
- assert(fd >= 0);
- assert(ret);
-
- for (;;) {
- char path[l];
-
- r = ttyname_r(fd, path, sizeof(path));
- if (r == 0) {
- const char *p;
- char *c;
-
- p = startswith(path, "/dev/");
- c = strdup(p ?: path);
- if (!c)
- return -ENOMEM;
-
- *ret = c;
- return 0;
- }
-
- if (r != ERANGE)
- return -r;
-
- l *= 2;
- }
-
- return 0;
-}
-
-int getttyname_harder(int fd, char **r) {
- int k;
- char *s;
-
- k = getttyname_malloc(fd, &s);
- if (k < 0)
- return k;
-
- if (streq(s, "tty")) {
- free(s);
- return get_ctty(0, NULL, r);
- }
-
- *r = s;
- return 0;
-}
-
-int get_ctty_devnr(pid_t pid, dev_t *d) {
- int r;
- _cleanup_free_ char *line = NULL;
- const char *p;
- unsigned long ttynr;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " "
- "%*c " /* state */
- "%*d " /* ppid */
- "%*d " /* pgrp */
- "%*d " /* session */
- "%lu ", /* ttynr */
- &ttynr) != 1)
- return -EIO;
-
- if (major(ttynr) == 0 && minor(ttynr) == 0)
- return -ENOENT;
-
- if (d)
- *d = (dev_t) ttynr;
-
- return 0;
-}
-
-int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
- char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
- _cleanup_free_ char *s = NULL;
- const char *p;
- dev_t devnr;
- int k;
-
- assert(r);
-
- k = get_ctty_devnr(pid, &devnr);
- if (k < 0)
- return k;
-
- sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
-
- k = readlink_malloc(fn, &s);
- if (k < 0) {
-
- if (k != -ENOENT)
- return k;
-
- /* This is an ugly hack */
- if (major(devnr) == 136) {
- asprintf(&b, "pts/%u", minor(devnr));
- goto finish;
- }
-
- /* Probably something like the ptys which have no
- * symlink in /dev/char. Let's return something
- * vaguely useful. */
-
- b = strdup(fn + 5);
- goto finish;
- }
-
- if (startswith(s, "/dev/"))
- p = s + 5;
- else if (startswith(s, "../"))
- p = s + 3;
- else
- p = s;
-
- b = strdup(p);
-
-finish:
- if (!b)
- return -ENOMEM;
-
- *r = b;
- if (_devnr)
- *_devnr = devnr;
-
- return 0;
-}
-
-int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
- _cleanup_closedir_ DIR *d = NULL;
- int ret = 0;
-
- assert(fd >= 0);
-
- /* This returns the first error we run into, but nevertheless
- * tries to go on. This closes the passed fd. */
-
- d = fdopendir(fd);
- if (!d) {
- safe_close(fd);
-
- return errno == ENOENT ? 0 : -errno;
- }
-
- for (;;) {
- struct dirent *de;
- bool is_dir, keep_around;
- struct stat st;
- int r;
-
- errno = 0;
- de = readdir(d);
- if (!de) {
- if (errno != 0 && ret == 0)
- ret = -errno;
- return ret;
- }
-
- if (streq(de->d_name, ".") || streq(de->d_name, ".."))
- continue;
-
- if (de->d_type == DT_UNKNOWN ||
- honour_sticky ||
- (de->d_type == DT_DIR && root_dev)) {
- if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
- }
-
- is_dir = S_ISDIR(st.st_mode);
- keep_around =
- honour_sticky &&
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
- } else {
- is_dir = de->d_type == DT_DIR;
- keep_around = false;
- }
-
- if (is_dir) {
- int subdir_fd;
-
- /* if root_dev is set, remove subdirectories only, if device is same as dir */
- if (root_dev && st.st_dev != root_dev->st_dev)
- continue;
-
- subdir_fd = openat(fd, de->d_name,
- O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
- if (subdir_fd < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
- }
-
- r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev);
- if (r < 0 && ret == 0)
- ret = r;
-
- if (!keep_around)
- if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- }
-
- } else if (!only_dirs && !keep_around) {
-
- if (unlinkat(fd, de->d_name, 0) < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- }
- }
- }
-}
-
-_pure_ static int is_temporary_fs(struct statfs *s) {
+bool is_temporary_fs(const struct statfs *s) {
assert(s);
return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
-int is_fd_on_temporary_fs(int fd) {
+int fd_is_temporary_fs(int fd) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
@@ -3053,114 +1905,6 @@ int is_fd_on_temporary_fs(int fd) {
return is_temporary_fs(&s);
}
-int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
- struct statfs s;
-
- assert(fd >= 0);
-
- if (fstatfs(fd, &s) < 0) {
- safe_close(fd);
- return -errno;
- }
-
- /* We refuse to clean disk file systems with this call. This
- * is extra paranoia just to be sure we never ever remove
- * non-state data */
- if (!is_temporary_fs(&s)) {
- log_error("Attempted to remove disk file system, and we can't allow that.");
- safe_close(fd);
- return -EPERM;
- }
-
- return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
-}
-
-static int file_is_priv_sticky(const char *p) {
- struct stat st;
-
- assert(p);
-
- if (lstat(p, &st) < 0)
- return -errno;
-
- return
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
-}
-
-static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
- int fd, r;
- struct statfs s;
-
- assert(path);
-
- /* We refuse to clean the root file system with this
- * call. This is extra paranoia to never cause a really
- * seriously broken system. */
- if (path_equal(path, "/")) {
- log_error("Attempted to remove entire root file system, and we can't allow that.");
- return -EPERM;
- }
-
- fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
- if (fd < 0) {
-
- if (errno != ENOTDIR && errno != ELOOP)
- return -errno;
-
- if (!dangerous) {
- if (statfs(path, &s) < 0)
- return -errno;
-
- if (!is_temporary_fs(&s)) {
- log_error("Attempted to remove disk file system, and we can't allow that.");
- return -EPERM;
- }
- }
-
- if (delete_root && !only_dirs)
- if (unlink(path) < 0 && errno != ENOENT)
- return -errno;
-
- return 0;
- }
-
- if (!dangerous) {
- if (fstatfs(fd, &s) < 0) {
- safe_close(fd);
- return -errno;
- }
-
- if (!is_temporary_fs(&s)) {
- log_error("Attempted to remove disk file system, and we can't allow that.");
- safe_close(fd);
- return -EPERM;
- }
- }
-
- r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL);
- if (delete_root) {
-
- if (honour_sticky && file_is_priv_sticky(path) > 0)
- return r;
-
- if (rmdir(path) < 0 && errno != ENOENT) {
- if (r == 0)
- r = -errno;
- }
- }
-
- return r;
-}
-
-int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
- return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false);
-}
-
-int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) {
- return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true);
-}
-
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
assert(path);
@@ -3225,311 +1969,6 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
}
}
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
- static const char status_indent[] = " "; /* "[" STATUS "] " */
- _cleanup_free_ char *s = NULL;
- _cleanup_close_ int fd = -1;
- struct iovec iovec[6] = {};
- int n = 0;
- static bool prev_ephemeral;
-
- assert(format);
-
- /* This is independent of logging, as status messages are
- * optional and go exclusively to the console. */
-
- if (vasprintf(&s, format, ap) < 0)
- return log_oom();
-
- fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- if (ellipse) {
- char *e;
- size_t emax, sl;
- int c;
-
- c = fd_columns(fd);
- if (c <= 0)
- c = 80;
-
- sl = status ? sizeof(status_indent)-1 : 0;
-
- emax = c - sl - 1;
- if (emax < 3)
- emax = 3;
-
- e = ellipsize(s, emax, 50);
- if (e) {
- free(s);
- s = e;
- }
- }
-
- if (prev_ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
- prev_ephemeral = ephemeral;
-
- if (status) {
- if (!isempty(status)) {
- IOVEC_SET_STRING(iovec[n++], "[");
- IOVEC_SET_STRING(iovec[n++], status);
- IOVEC_SET_STRING(iovec[n++], "] ");
- } else
- IOVEC_SET_STRING(iovec[n++], status_indent);
- }
-
- IOVEC_SET_STRING(iovec[n++], s);
- if (!ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\n");
-
- if (writev(fd, iovec, n) < 0)
- return -errno;
-
- return 0;
-}
-
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
- va_list ap;
- int r;
-
- assert(format);
-
- va_start(ap, format);
- r = status_vprintf(status, ellipse, ephemeral, format, ap);
- va_end(ap);
-
- return r;
-}
-
-char *replace_env(const char *format, char **env) {
- enum {
- WORD,
- CURLY,
- VARIABLE
- } state = WORD;
-
- const char *e, *word = format;
- char *r = NULL, *k;
-
- assert(format);
-
- for (e = format; *e; e ++) {
-
- switch (state) {
-
- case WORD:
- if (*e == '$')
- state = CURLY;
- break;
-
- case CURLY:
- if (*e == '{') {
- k = strnappend(r, word, e-word-1);
- if (!k)
- goto fail;
-
- free(r);
- r = k;
-
- word = e-1;
- state = VARIABLE;
-
- } else if (*e == '$') {
- k = strnappend(r, word, e-word);
- if (!k)
- goto fail;
-
- free(r);
- r = k;
-
- word = e+1;
- state = WORD;
- } else
- state = WORD;
- break;
-
- case VARIABLE:
- if (*e == '}') {
- const char *t;
-
- t = strempty(strv_env_get_n(env, word+2, e-word-2));
-
- k = strappend(r, t);
- if (!k)
- goto fail;
-
- free(r);
- r = k;
-
- word = e+1;
- state = WORD;
- }
- break;
- }
- }
-
- k = strnappend(r, word, e-word);
- if (!k)
- goto fail;
-
- free(r);
- return k;
-
-fail:
- free(r);
- return NULL;
-}
-
-char **replace_env_argv(char **argv, char **env) {
- char **ret, **i;
- unsigned k = 0, l = 0;
-
- l = strv_length(argv);
-
- ret = new(char*, l+1);
- if (!ret)
- return NULL;
-
- STRV_FOREACH(i, argv) {
-
- /* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$' && (*i)[1] != '{') {
- char *e;
- char **w, **m;
- unsigned q;
-
- e = strv_env_get(env, *i+1);
- if (e) {
- int r;
-
- r = strv_split_quoted(&m, e, true);
- if (r < 0) {
- ret[k] = NULL;
- strv_free(ret);
- return NULL;
- }
- } else
- m = NULL;
-
- q = strv_length(m);
- l = l + q - 1;
-
- w = realloc(ret, sizeof(char*) * (l+1));
- if (!w) {
- ret[k] = NULL;
- strv_free(ret);
- strv_free(m);
- return NULL;
- }
-
- ret = w;
- if (m) {
- memcpy(ret + k, m, q * sizeof(char*));
- free(m);
- }
-
- k += q;
- continue;
- }
-
- /* If ${FOO} appears as part of a word, replace it by the variable as-is */
- ret[k] = replace_env(*i, env);
- if (!ret[k]) {
- strv_free(ret);
- return NULL;
- }
- k++;
- }
-
- ret[k] = NULL;
- return ret;
-}
-
-int fd_columns(int fd) {
- struct winsize ws = {};
-
- if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
- return -errno;
-
- if (ws.ws_col <= 0)
- return -EIO;
-
- return ws.ws_col;
-}
-
-unsigned columns(void) {
- const char *e;
- int c;
-
- if (_likely_(cached_columns > 0))
- return cached_columns;
-
- c = 0;
- e = getenv("COLUMNS");
- if (e)
- (void) safe_atoi(e, &c);
-
- if (c <= 0)
- c = fd_columns(STDOUT_FILENO);
-
- if (c <= 0)
- c = 80;
-
- cached_columns = c;
- return cached_columns;
-}
-
-int fd_lines(int fd) {
- struct winsize ws = {};
-
- if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
- return -errno;
-
- if (ws.ws_row <= 0)
- return -EIO;
-
- return ws.ws_row;
-}
-
-unsigned lines(void) {
- const char *e;
- int l;
-
- if (_likely_(cached_lines > 0))
- return cached_lines;
-
- l = 0;
- e = getenv("LINES");
- if (e)
- (void) safe_atoi(e, &l);
-
- if (l <= 0)
- l = fd_lines(STDOUT_FILENO);
-
- if (l <= 0)
- l = 24;
-
- cached_lines = l;
- return cached_lines;
-}
-
-/* intended to be used as a SIGWINCH sighandler */
-void columns_lines_cache_reset(int signum) {
- cached_columns = 0;
- cached_lines = 0;
-}
-
-bool on_tty(void) {
- static int cached_on_tty = -1;
-
- if (_unlikely_(cached_on_tty < 0))
- cached_on_tty = isatty(STDOUT_FILENO) > 0;
-
- return cached_on_tty;
-}
-
int files_same(const char *filea, const char *fileb) {
struct stat a, b;
@@ -3705,14 +2144,15 @@ int touch(const char *path) {
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
}
-char *unquote(const char *s, const char* quotes) {
+static char *unquote(const char *s, const char* quotes) {
size_t l;
assert(s);
/* This is rather stupid, simply removes the heading and
* trailing quotes if there is one. Doesn't care about
- * escaping or anything. We should make this smarter one
- * day... */
+ * escaping or anything.
+ *
+ * DON'T USE THIS FOR NEW CODE ANYMORE!*/
l = strlen(s);
if (l < 2)
@@ -3724,103 +2164,6 @@ char *unquote(const char *s, const char* quotes) {
return strdup(s);
}
-char *normalize_env_assignment(const char *s) {
- _cleanup_free_ char *value = NULL;
- const char *eq;
- char *p, *name;
-
- eq = strchr(s, '=');
- if (!eq) {
- char *r, *t;
-
- r = strdup(s);
- if (!r)
- return NULL;
-
- t = strstrip(r);
- if (t != r)
- memmove(r, t, strlen(t) + 1);
-
- return r;
- }
-
- name = strndupa(s, eq - s);
- p = strdupa(eq + 1);
-
- value = unquote(strstrip(p), QUOTES);
- if (!value)
- return NULL;
-
- return strjoin(strstrip(name), "=", value, NULL);
-}
-
-int wait_for_terminate(pid_t pid, siginfo_t *status) {
- siginfo_t dummy;
-
- assert(pid >= 1);
-
- if (!status)
- status = &dummy;
-
- for (;;) {
- zero(*status);
-
- if (waitid(P_PID, pid, status, WEXITED) < 0) {
-
- if (errno == EINTR)
- continue;
-
- return -errno;
- }
-
- return 0;
- }
-}
-
-/*
- * Return values:
- * < 0 : wait_for_terminate() failed to get the state of the
- * process, the process was terminated by a signal, or
- * failed for an unknown reason.
- * >=0 : The process terminated normally, and its exit code is
- * returned.
- *
- * That is, success is indicated by a return value of zero, and an
- * error is indicated by a non-zero value.
- *
- * A warning is emitted if the process terminates abnormally,
- * and also if it returns non-zero unless check_exit_code is true.
- */
-int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
- int r;
- siginfo_t status;
-
- assert(name);
- assert(pid > 1);
-
- r = wait_for_terminate(pid, &status);
- if (r < 0)
- return log_warning_errno(r, "Failed to wait for %s: %m", name);
-
- if (status.si_code == CLD_EXITED) {
- if (status.si_status != 0)
- log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
- "%s failed with error code %i.", name, status.si_status);
- else
- log_debug("%s succeeded.", name);
-
- return status.si_status;
- } else if (status.si_code == CLD_KILLED ||
- status.si_code == CLD_DUMPED) {
-
- log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
- return -EPROTO;
- }
-
- log_warning("%s failed due to unknown reason.", name);
- return -EPROTO;
-}
-
noreturn void freeze(void) {
/* Make sure nobody waits for us on a socket anymore */
@@ -3885,23 +2228,11 @@ DIR *xopendirat(int fd, const char *name, int flags) {
return d;
}
-int signal_from_string_try_harder(const char *s) {
- int signo;
- assert(s);
-
- signo = signal_from_string(s);
- if (signo <= 0)
- if (startswith(s, "SIG"))
- return signal_from_string(s+3);
-
- return signo;
-}
-
static char *tag_to_udev_node(const char *tagvalue, const char *by) {
_cleanup_free_ char *t = NULL, *u = NULL;
size_t enc_len;
- u = unquote(tagvalue, "\"\'");
+ u = unquote(tagvalue, QUOTES);
if (!u)
return NULL;
@@ -3934,101 +2265,6 @@ char *fstab_node_to_udev_node(const char *p) {
return strdup(p);
}
-bool tty_is_vc(const char *tty) {
- assert(tty);
-
- return vtnr_from_tty(tty) >= 0;
-}
-
-bool tty_is_console(const char *tty) {
- assert(tty);
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- return streq(tty, "console");
-}
-
-int vtnr_from_tty(const char *tty) {
- int i, r;
-
- assert(tty);
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- if (!startswith(tty, "tty") )
- return -EINVAL;
-
- if (tty[3] < '0' || tty[3] > '9')
- return -EINVAL;
-
- r = safe_atoi(tty+3, &i);
- if (r < 0)
- return r;
-
- if (i < 0 || i > 63)
- return -EINVAL;
-
- return i;
-}
-
-char *resolve_dev_console(char **active) {
- char *tty;
-
- /* Resolve where /dev/console is pointing to, if /sys is actually ours
- * (i.e. not read-only-mounted which is a sign for container setups) */
-
- if (path_is_read_only_fs("/sys") > 0)
- return NULL;
-
- if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
- return NULL;
-
- /* If multiple log outputs are configured the last one is what
- * /dev/console points to */
- tty = strrchr(*active, ' ');
- if (tty)
- tty++;
- else
- tty = *active;
-
- if (streq(tty, "tty0")) {
- char *tmp;
-
- /* Get the active VC (e.g. tty1) */
- if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
- free(*active);
- tty = *active = tmp;
- }
- }
-
- return tty;
-}
-
-bool tty_is_vc_resolve(const char *tty) {
- _cleanup_free_ char *active = NULL;
-
- assert(tty);
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- if (streq(tty, "console")) {
- tty = resolve_dev_console(&active);
- if (!tty)
- return false;
- }
-
- return tty_is_vc(tty);
-}
-
-const char *default_term_for_tty(const char *tty) {
- assert(tty);
-
- return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
-}
-
bool dirent_is_file(const struct dirent *de) {
assert(de);
@@ -4114,8 +2350,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) {
if (null_or_empty_path(path)) {
log_debug("%s is empty (a mask).", path);
continue;
- } else
- log_debug("%s will be executed.", path);
+ }
pid = fork();
if (pid < 0) {
@@ -4198,17 +2433,6 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a
wait_for_terminate_and_warn(name, executor_pid, true);
}
-int kill_and_sigcont(pid_t pid, int sig) {
- int r;
-
- r = kill(pid, sig) < 0 ? -errno : 0;
-
- if (r >= 0)
- kill(pid, SIGCONT);
-
- return r;
-}
-
bool nulstr_contains(const char*nulstr, const char *needle) {
const char *i;
@@ -4235,79 +2459,6 @@ char* strshorten(char *s, size_t l) {
return s;
}
-static bool hostname_valid_char(char c) {
- return
- (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') ||
- (c >= '0' && c <= '9') ||
- c == '-' ||
- c == '_' ||
- c == '.';
-}
-
-bool hostname_is_valid(const char *s) {
- const char *p;
- bool dot;
-
- if (isempty(s))
- return false;
-
- /* Doesn't accept empty hostnames, hostnames with trailing or
- * leading dots, and hostnames with multiple dots in a
- * sequence. Also ensures that the length stays below
- * HOST_NAME_MAX. */
-
- for (p = s, dot = true; *p; p++) {
- if (*p == '.') {
- if (dot)
- return false;
-
- dot = true;
- } else {
- if (!hostname_valid_char(*p))
- return false;
-
- dot = false;
- }
- }
-
- if (dot)
- return false;
-
- if (p-s > HOST_NAME_MAX)
- return false;
-
- return true;
-}
-
-char* hostname_cleanup(char *s, bool lowercase) {
- char *p, *d;
- bool dot;
-
- for (p = s, d = s, dot = true; *p; p++) {
- if (*p == '.') {
- if (dot)
- continue;
-
- *(d++) = '.';
- dot = true;
- } else if (hostname_valid_char(*p)) {
- *(d++) = lowercase ? tolower(*p) : *p;
- dot = false;
- }
-
- }
-
- if (dot && d > s)
- d[-1] = 0;
- else
- *d = 0;
-
- strshorten(s, HOST_NAME_MAX);
-
- return s;
-}
-
bool machine_name_is_valid(const char *s) {
if (!hostname_is_valid(s))
@@ -4393,111 +2544,45 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
return 0;
}
-int terminal_vhangup_fd(int fd) {
- assert(fd >= 0);
-
- if (ioctl(fd, TIOCVHANGUP) < 0)
- return -errno;
-
- return 0;
-}
-
-int terminal_vhangup(const char *name) {
- _cleanup_close_ int fd;
-
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- return terminal_vhangup_fd(fd);
-}
-
-int vt_disallocate(const char *name) {
- int fd, r;
- unsigned u;
-
- /* Deallocate the VT if possible. If not possible
- * (i.e. because it is the active one), at least clear it
- * entirely (including the scrollback buffer) */
-
- if (!startswith(name, "/dev/"))
- return -EINVAL;
-
- if (!tty_is_vc(name)) {
- /* So this is not a VT. I guess we cannot deallocate
- * it then. But let's at least clear the screen */
-
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- loop_write(fd,
- "\033[r" /* clear scrolling region */
- "\033[H" /* move home */
- "\033[2J", /* clear screen */
- 10, false);
- safe_close(fd);
-
- return 0;
- }
+int symlink_atomic(const char *from, const char *to) {
+ _cleanup_free_ char *t = NULL;
+ int r;
- if (!startswith(name, "/dev/tty"))
- return -EINVAL;
+ assert(from);
+ assert(to);
- r = safe_atou(name+8, &u);
+ r = tempfn_random(to, &t);
if (r < 0)
return r;
- if (u <= 0)
- return -EINVAL;
-
- /* Try to deallocate */
- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- r = ioctl(fd, VT_DISALLOCATE, u);
- safe_close(fd);
-
- if (r >= 0)
- return 0;
-
- if (errno != EBUSY)
+ if (symlink(from, t) < 0)
return -errno;
- /* Couldn't deallocate, so let's clear it fully with
- * scrollback */
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- loop_write(fd,
- "\033[r" /* clear scrolling region */
- "\033[H" /* move home */
- "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
- 10, false);
- safe_close(fd);
+ if (rename(t, to) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
return 0;
}
-int symlink_atomic(const char *from, const char *to) {
- _cleanup_free_ char *t = NULL;
+int symlink_idempotent(const char *from, const char *to) {
+ _cleanup_free_ char *p = NULL;
int r;
assert(from);
assert(to);
- r = tempfn_random(to, &t);
- if (r < 0)
- return r;
+ if (symlink(from, to) < 0) {
+ if (errno != EEXIST)
+ return -errno;
- if (symlink(from, t) < 0)
- return -errno;
+ r = readlink_malloc(to, &p);
+ if (r < 0)
+ return r;
- if (rename(t, to) < 0) {
- unlink_noerrno(t);
- return -errno;
+ if (!streq(p, from))
+ return -EINVAL;
}
return 0;
@@ -5099,81 +3184,6 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-static const char *const __signal_table[] = {
- [SIGHUP] = "HUP",
- [SIGINT] = "INT",
- [SIGQUIT] = "QUIT",
- [SIGILL] = "ILL",
- [SIGTRAP] = "TRAP",
- [SIGABRT] = "ABRT",
- [SIGBUS] = "BUS",
- [SIGFPE] = "FPE",
- [SIGKILL] = "KILL",
- [SIGUSR1] = "USR1",
- [SIGSEGV] = "SEGV",
- [SIGUSR2] = "USR2",
- [SIGPIPE] = "PIPE",
- [SIGALRM] = "ALRM",
- [SIGTERM] = "TERM",
-#ifdef SIGSTKFLT
- [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
-#endif
- [SIGCHLD] = "CHLD",
- [SIGCONT] = "CONT",
- [SIGSTOP] = "STOP",
- [SIGTSTP] = "TSTP",
- [SIGTTIN] = "TTIN",
- [SIGTTOU] = "TTOU",
- [SIGURG] = "URG",
- [SIGXCPU] = "XCPU",
- [SIGXFSZ] = "XFSZ",
- [SIGVTALRM] = "VTALRM",
- [SIGPROF] = "PROF",
- [SIGWINCH] = "WINCH",
- [SIGIO] = "IO",
- [SIGPWR] = "PWR",
- [SIGSYS] = "SYS"
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
-
-const char *signal_to_string(int signo) {
- static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
- const char *name;
-
- name = __signal_to_string(signo);
- if (name)
- return name;
-
- if (signo >= SIGRTMIN && signo <= SIGRTMAX)
- snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
- else
- snprintf(buf, sizeof(buf), "%d", signo);
-
- return buf;
-}
-
-int signal_from_string(const char *s) {
- int signo;
- int offset = 0;
- unsigned u;
-
- signo = __signal_from_string(s);
- if (signo > 0)
- return signo;
-
- if (startswith(s, "RTMIN+")) {
- s += 6;
- offset = SIGRTMIN;
- }
- if (safe_atou(s, &u) >= 0) {
- signo = (int) u + offset;
- if (signo > 0 && signo < _NSIG)
- return signo;
- }
- return -EINVAL;
-}
-
bool kexec_loaded(void) {
bool loaded = false;
char *s;
@@ -5417,60 +3427,6 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
return 0;
}
-int getenv_for_pid(pid_t pid, const char *field, char **_value) {
- _cleanup_fclose_ FILE *f = NULL;
- char *value = NULL;
- int r;
- bool done = false;
- size_t l;
- const char *path;
-
- assert(pid >= 0);
- assert(field);
- assert(_value);
-
- path = procfs_file_alloca(pid, "environ");
-
- f = fopen(path, "re");
- if (!f)
- return -errno;
-
- l = strlen(field);
- r = 0;
-
- do {
- char line[LINE_MAX];
- unsigned i;
-
- for (i = 0; i < sizeof(line)-1; i++) {
- int c;
-
- c = getc(f);
- if (_unlikely_(c == EOF)) {
- done = true;
- break;
- } else if (c == 0)
- break;
-
- line[i] = c;
- }
- line[i] = 0;
-
- if (memcmp(line, field, l) == 0 && line[l] == '=') {
- value = strdup(line + l + 1);
- if (!value)
- return -ENOMEM;
-
- r = 1;
- break;
- }
-
- } while (!done);
-
- *_value = value;
- return r;
-}
-
bool http_etag_is_valid(const char *etag) {
if (isempty(etag))
return false;
@@ -5547,43 +3503,6 @@ bool in_initrd(void) {
return saved;
}
-void warn_melody(void) {
- _cleanup_close_ int fd = -1;
-
- fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return;
-
- /* Yeah, this is synchronous. Kinda sucks. But well... */
-
- ioctl(fd, KIOCSOUND, (int)(1193180/440));
- usleep(125*USEC_PER_MSEC);
-
- ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- ioctl(fd, KIOCSOUND, 0);
-}
-
-int make_console_stdio(void) {
- int fd, r;
-
- /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
-
- fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
- if (fd < 0)
- return log_error_errno(fd, "Failed to acquire terminal: %m");
-
- r = make_stdio(fd);
- if (r < 0)
- return log_error_errno(r, "Failed to duplicate terminal fd: %m");
-
- return 0;
-}
-
int get_home_dir(char **_h) {
struct passwd *p;
const char *e;
@@ -5746,7 +3665,7 @@ bool path_is_safe(const char *p) {
if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
return false;
- if (strlen(p) > PATH_MAX)
+ if (strlen(p)+1 > PATH_MAX)
return false;
/* The following two checks are not really dangerous, but hey, they still are confusing */
@@ -5782,6 +3701,11 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
return NULL;
}
+void init_gettext(void) {
+ setlocale(LC_ALL, "");
+ textdomain(GETTEXT_PACKAGE);
+}
+
bool is_locale_utf8(void) {
const char *set;
static int cached_answer = -1;
@@ -5993,7 +3917,7 @@ int on_ac_power(void) {
d = opendir("/sys/class/power_supply");
if (!d)
- return -errno;
+ return errno == ENOENT ? true : -errno;
for (;;) {
struct dirent *de;
@@ -6371,7 +4295,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
_cleanup_free_ char *word = NULL;
char *value = NULL;
- r = unquote_first_word(&p, &word, true);
+ r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -6411,7 +4335,7 @@ int get_proc_cmdline_key(const char *key, char **value) {
_cleanup_free_ char *word = NULL;
const char *e;
- r = unquote_first_word(&p, &word, true);
+ r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -6559,43 +4483,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
return -errno;
}
- if (setresgid(0, 0, 0) < 0)
- return -errno;
-
- if (setgroups(0, NULL) < 0)
- return -errno;
-
- if (setresuid(0, 0, 0) < 0)
- return -errno;
-
- return 0;
-}
-
-bool pid_is_unwaited(pid_t pid) {
- /* Checks whether a PID is still valid at all, including a zombie */
-
- if (pid <= 0)
- return false;
-
- if (kill(pid, 0) >= 0)
- return true;
-
- return errno != ESRCH;
-}
-
-bool pid_is_alive(pid_t pid) {
- int r;
-
- /* Checks whether a PID is still valid and not a zombie */
-
- if (pid <= 0)
- return false;
-
- r = get_process_state(pid);
- if (r == -ENOENT || r == 'Z')
- return false;
-
- return true;
+ return reset_uid_gid();
}
int getpeercred(int fd, struct ucred *ucred) {
@@ -6658,7 +4546,7 @@ int getpeersec(int fd, char **ret) {
if (isempty(s)) {
free(s);
- return -ENOTSUP;
+ return -EOPNOTSUPP;
}
*ret = s;
@@ -6689,7 +4577,7 @@ int open_tmpfile(const char *path, int flags) {
#ifdef O_TMPFILE
/* Try O_TMPFILE first, if it is supported */
- fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR);
+ fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
if (fd >= 0)
return fd;
#endif
@@ -6746,10 +4634,7 @@ unsigned long personality_from_string(const char *p) {
return PER_LINUX;
#endif
- /* personality(7) documents that 0xffffffffUL is used for
- * querying the current personality, hence let's use that here
- * as error indicator. */
- return 0xffffffffUL;
+ return PERSONALITY_INVALID;
}
const char* personality_to_string(unsigned long p) {
@@ -6884,9 +4769,9 @@ int umount_recursive(const char *prefix, int flags) {
continue;
}
- p = cunescape(path);
- if (!p)
- return -ENOMEM;
+ r = cunescape(path, UNESCAPE_RELAX, &p);
+ if (r < 0)
+ return r;
if (!path_startswith(p, prefix))
continue;
@@ -6986,9 +4871,9 @@ int bind_remount_recursive(const char *prefix, bool ro) {
continue;
}
- p = cunescape(path);
- if (!p)
- return -ENOMEM;
+ r = cunescape(path, UNESCAPE_RELAX, &p);
+ if (r < 0)
+ return r;
/* Let's ignore autofs mounts. If they aren't
* triggered yet, we want to avoid triggering
@@ -7184,23 +5069,6 @@ int tempfn_random_child(const char *p, char **ret) {
return 0;
}
-/* make sure the hostname is not "localhost" */
-bool is_localhost(const char *hostname) {
- assert(hostname);
-
- /* This tries to identify local host and domain names
- * described in RFC6761 plus the redhatism of .localdomain */
-
- return streq(hostname, "localhost") ||
- streq(hostname, "localhost.") ||
- streq(hostname, "localdomain.") ||
- streq(hostname, "localdomain") ||
- endswith(hostname, ".localhost") ||
- endswith(hostname, ".localhost.") ||
- endswith(hostname, ".localdomain") ||
- endswith(hostname, ".localdomain.");
-}
-
int take_password_lock(const char *root) {
struct flock flock = {
@@ -7264,9 +5132,19 @@ int is_dir(const char* path, bool follow) {
return !!S_ISDIR(st.st_mode);
}
-int unquote_first_word(const char **p, char **ret, bool relax) {
+int is_device_node(const char *path) {
+ struct stat info;
+
+ if (lstat(path, &info) < 0)
+ return -errno;
+
+ return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
+}
+
+int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
+ int r;
enum {
START,
@@ -7324,22 +5202,36 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
case VALUE_ESCAPE:
if (c == 0) {
- if (relax)
+ if (flags & UNQUOTE_RELAX)
goto finish;
return -EINVAL;
}
- if (!GREEDY_REALLOC(s, allocated, sz+2))
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
- s[sz++] = c;
- state = VALUE;
+ if (flags & UNQUOTE_CUNESCAPE) {
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
+ if (r < 0)
+ return -EINVAL;
+ (*p) += r - 1;
+
+ if (c != 0)
+ s[sz++] = c; /* normal explicit char */
+ else
+ sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
+ } else
+ s[sz++] = c;
+
+ state = VALUE;
break;
case SINGLE_QUOTE:
if (c == 0) {
- if (relax)
+ if (flags & UNQUOTE_RELAX)
goto finish;
return -EINVAL;
} else if (c == '\'')
@@ -7357,15 +5249,30 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
case SINGLE_QUOTE_ESCAPE:
if (c == 0) {
- if (relax)
+ if (flags & UNQUOTE_RELAX)
goto finish;
return -EINVAL;
}
- if (!GREEDY_REALLOC(s, allocated, sz+2))
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
- s[sz++] = c;
+ if (flags & UNQUOTE_CUNESCAPE) {
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
+ if (r < 0)
+ return -EINVAL;
+
+ (*p) += r - 1;
+
+ if (c != 0)
+ s[sz++] = c;
+ else
+ sz += utf8_encode_unichar(s + sz, u);
+ } else
+ s[sz++] = c;
+
state = SINGLE_QUOTE;
break;
@@ -7387,15 +5294,30 @@ int unquote_first_word(const char **p, char **ret, bool relax) {
case DOUBLE_QUOTE_ESCAPE:
if (c == 0) {
- if (relax)
+ if (flags & UNQUOTE_RELAX)
goto finish;
return -EINVAL;
}
- if (!GREEDY_REALLOC(s, allocated, sz+2))
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
- s[sz++] = c;
+ if (flags & UNQUOTE_CUNESCAPE) {
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
+ if (r < 0)
+ return -EINVAL;
+
+ (*p) += r - 1;
+
+ if (c != 0)
+ s[sz++] = c;
+ else
+ sz += utf8_encode_unichar(s + sz, u);
+ } else
+ s[sz++] = c;
+
state = DOUBLE_QUOTE;
break;
@@ -7424,7 +5346,7 @@ finish:
return 1;
}
-int unquote_many_words(const char **p, ...) {
+int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
va_list ap;
char **l;
int n = 0, i, c, r;
@@ -7435,7 +5357,7 @@ int unquote_many_words(const char **p, ...) {
assert(p);
/* Count how many words are expected */
- va_start(ap, p);
+ va_start(ap, flags);
for (;;) {
if (!va_arg(ap, char **))
break;
@@ -7450,7 +5372,7 @@ int unquote_many_words(const char **p, ...) {
l = newa0(char*, n);
for (c = 0; c < n; c++) {
- r = unquote_first_word(p, &l[c], false);
+ r = unquote_first_word(p, &l[c], flags);
if (r < 0) {
int j;
@@ -7466,7 +5388,7 @@ int unquote_many_words(const char **p, ...) {
/* If we managed to parse all words, return them in the passed
* in parameters */
- va_start(ap, p);
+ va_start(ap, flags);
for (i = 0; i < n; i++) {
char **v;
@@ -7488,6 +5410,9 @@ int free_and_strdup(char **p, const char *s) {
/* Replaces a string pointer with an strdup()ed new string,
* possibly freeing the old one. */
+ if (streq_ptr(*p, s))
+ return 0;
+
if (s) {
t = strdup(s);
if (!t)
@@ -7498,26 +5423,6 @@ int free_and_strdup(char **p, const char *s) {
free(*p);
*p = t;
- return 0;
-}
-
-int sethostname_idempotent(const char *s) {
- int r;
- char buf[HOST_NAME_MAX + 1] = {};
-
- assert(s);
-
- r = gethostname(buf, sizeof(buf));
- if (r < 0)
- return -errno;
-
- if (streq(buf, s))
- return 0;
-
- r = sethostname(s, strlen(s));
- if (r < 0)
- return -errno;
-
return 1;
}
@@ -7779,7 +5684,7 @@ int same_fd(int a, int b) {
/* The fds refer to the same inode on disk, let's also check
* if they have the same fd flags. This is useful to
- * distuingish the read and write side of a pipe created with
+ * distinguish the read and write side of a pipe created with
* pipe(). */
fa = fcntl(a, F_GETFL);
if (fa < 0)
@@ -7792,32 +5697,41 @@ int same_fd(int a, int b) {
return fa == fb;
}
-int chattr_fd(int fd, bool b, unsigned mask) {
+int chattr_fd(int fd, unsigned value, unsigned mask) {
unsigned old_attr, new_attr;
+ struct stat st;
assert(fd >= 0);
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ /* Explicitly check whether this is a regular file or
+ * directory. If it is anything else (such as a device node or
+ * fifo), then the ioctl will not hit the file systems but
+ * possibly drivers, where the ioctl might have different
+ * effects. Notably, DRM is using the same ioctl() number. */
+
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ return -ENOTTY;
+
if (mask == 0)
return 0;
if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
return -errno;
- if (b)
- new_attr = old_attr | mask;
- else
- new_attr = old_attr & ~mask;
-
+ new_attr = (old_attr & ~mask) | (value & mask);
if (new_attr == old_attr)
return 0;
if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
return -errno;
- return 0;
+ return 1;
}
-int chattr_path(const char *p, bool b, unsigned mask) {
+int chattr_path(const char *p, unsigned value, unsigned mask) {
_cleanup_close_ int fd = -1;
assert(p);
@@ -7829,12 +5743,20 @@ int chattr_path(const char *p, bool b, unsigned mask) {
if (fd < 0)
return -errno;
- return chattr_fd(fd, b, mask);
+ return chattr_fd(fd, value, mask);
}
int read_attr_fd(int fd, unsigned *ret) {
+ struct stat st;
+
assert(fd >= 0);
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ return -ENOTTY;
+
if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
return -errno;
@@ -7854,128 +5776,6 @@ int read_attr_path(const char *p, unsigned *ret) {
return read_attr_fd(fd, ret);
}
-int make_lock_file(const char *p, int operation, LockFile *ret) {
- _cleanup_close_ int fd = -1;
- _cleanup_free_ char *t = NULL;
- int r;
-
- /*
- * We use UNPOSIX locks if they are available. They have nice
- * semantics, and are mostly compatible with NFS. However,
- * they are only available on new kernels. When we detect we
- * are running on an older kernel, then we fall back to good
- * old BSD locks. They also have nice semantics, but are
- * slightly problematic on NFS, where they are upgraded to
- * POSIX locks, even though locally they are orthogonal to
- * POSIX locks.
- */
-
- t = strdup(p);
- if (!t)
- return -ENOMEM;
-
- for (;;) {
- struct flock fl = {
- .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
- .l_whence = SEEK_SET,
- };
- struct stat st;
-
- fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
- if (fd < 0)
- return -errno;
-
- r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
- if (r < 0) {
-
- /* If the kernel is too old, use good old BSD locks */
- if (errno == EINVAL)
- r = flock(fd, operation);
-
- if (r < 0)
- return errno == EAGAIN ? -EBUSY : -errno;
- }
-
- /* If we acquired the lock, let's check if the file
- * still exists in the file system. If not, then the
- * previous exclusive owner removed it and then closed
- * it. In such a case our acquired lock is worthless,
- * hence try again. */
-
- r = fstat(fd, &st);
- if (r < 0)
- return -errno;
- if (st.st_nlink > 0)
- break;
-
- fd = safe_close(fd);
- }
-
- ret->path = t;
- ret->fd = fd;
- ret->operation = operation;
-
- fd = -1;
- t = NULL;
-
- return r;
-}
-
-int make_lock_file_for(const char *p, int operation, LockFile *ret) {
- const char *fn;
- char *t;
-
- assert(p);
- assert(ret);
-
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
-
- t = newa(char, strlen(p) + 2 + 4 + 1);
- stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
-
- return make_lock_file(t, operation, ret);
-}
-
-void release_lock_file(LockFile *f) {
- int r;
-
- if (!f)
- return;
-
- if (f->path) {
-
- /* If we are the exclusive owner we can safely delete
- * the lock file itself. If we are not the exclusive
- * owner, we can try becoming it. */
-
- if (f->fd >= 0 &&
- (f->operation & ~LOCK_NB) == LOCK_SH) {
- static const struct flock fl = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- };
-
- r = fcntl(f->fd, F_OFD_SETLK, &fl);
- if (r < 0 && errno == EINVAL)
- r = flock(f->fd, LOCK_EX|LOCK_NB);
-
- if (r >= 0)
- f->operation = LOCK_EX|LOCK_NB;
- }
-
- if ((f->operation & ~LOCK_NB) == LOCK_EX)
- unlink_noerrno(f->path);
-
- free(f->path);
- f->path = NULL;
- }
-
- f->fd = safe_close(f->fd);
- f->operation = 0;
-}
-
static size_t nul_length(const uint8_t *p, size_t sz) {
size_t n = 0;
@@ -8102,3 +5902,147 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
return -1;
}
+
+void cmsg_close_all(struct msghdr *mh) {
+ struct cmsghdr *cmsg;
+
+ assert(mh);
+
+ for (cmsg = CMSG_FIRSTHDR(mh); cmsg; cmsg = CMSG_NXTHDR(mh, cmsg))
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+ close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+}
+
+int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
+ struct stat buf;
+ int ret;
+
+ ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
+ if (ret >= 0)
+ return 0;
+
+ /* Even though renameat2() exists since Linux 3.15, btrfs added
+ * support for it later. If it is not implemented, fallback to another
+ * method. */
+ if (errno != EINVAL)
+ return -errno;
+
+ /* The link()/unlink() fallback does not work on directories. But
+ * renameat() without RENAME_NOREPLACE gives the same semantics on
+ * directories, except when newpath is an *empty* directory. This is
+ * good enough. */
+ ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
+ if (ret >= 0 && S_ISDIR(buf.st_mode)) {
+ ret = renameat(olddirfd, oldpath, newdirfd, newpath);
+ return ret >= 0 ? 0 : -errno;
+ }
+
+ /* If it is not a directory, use the link()/unlink() fallback. */
+ ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
+ if (ret < 0)
+ return -errno;
+
+ ret = unlinkat(olddirfd, oldpath, 0);
+ if (ret < 0) {
+ /* backup errno before the following unlinkat() alters it */
+ ret = errno;
+ (void) unlinkat(newdirfd, newpath, 0);
+ errno = ret;
+ return -errno;
+ }
+
+ return 0;
+}
+
+char *shell_maybe_quote(const char *s) {
+ const char *p;
+ char *r, *t;
+
+ assert(s);
+
+ /* Encloses a string in double quotes if necessary to make it
+ * OK as shell string. */
+
+ for (p = s; *p; p++)
+ if (*p <= ' ' ||
+ *p >= 127 ||
+ strchr(SHELL_NEED_QUOTES, *p))
+ break;
+
+ if (!*p)
+ return strdup(s);
+
+ r = new(char, 1+strlen(s)*2+1+1);
+ if (!r)
+ return NULL;
+
+ t = r;
+ *(t++) = '"';
+ t = mempcpy(t, s, p - s);
+
+ for (; *p; p++) {
+
+ if (strchr(SHELL_NEED_ESCAPE, *p))
+ *(t++) = '\\';
+
+ *(t++) = *p;
+ }
+
+ *(t++)= '"';
+ *t = 0;
+
+ return r;
+}
+
+int parse_mode(const char *s, mode_t *ret) {
+ char *x;
+ long l;
+
+ assert(s);
+ assert(ret);
+
+ errno = 0;
+ l = strtol(s, &x, 8);
+ if (errno != 0)
+ return -errno;
+
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (l < 0 || l > 07777)
+ return -ERANGE;
+
+ *ret = (mode_t) l;
+ return 0;
+}
+
+int mount_move_root(const char *path) {
+ assert(path);
+
+ if (chdir(path) < 0)
+ return -errno;
+
+ if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
+ return -errno;
+
+ if (chroot(".") < 0)
+ return -errno;
+
+ if (chdir("/") < 0)
+ return -errno;
+
+ return 0;
+}
+
+int reset_uid_gid(void) {
+
+ if (setgroups(0, NULL) < 0)
+ return -errno;
+
+ if (setresgid(0, 0, 0) < 0)
+ return -errno;
+
+ if (setresuid(0, 0, 0) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index a83b588221..467ae234a0 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -25,69 +25,27 @@
#include <fcntl.h>
#include <inttypes.h>
#include <time.h>
-#include <sys/time.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
-#include <signal.h>
#include <sched.h>
#include <limits.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <dirent.h>
-#include <sys/resource.h>
#include <stddef.h>
#include <unistd.h>
#include <locale.h>
#include <mntent.h>
-#include <sys/socket.h>
#include <sys/inotify.h>
-
-#if SIZEOF_PID_T == 4
-# define PID_PRI PRIi32
-#elif SIZEOF_PID_T == 2
-# define PID_PRI PRIi16
-#else
-# error Unknown pid_t size
-#endif
-#define PID_FMT "%" PID_PRI
-
-#if SIZEOF_UID_T == 4
-# define UID_FMT "%" PRIu32
-#elif SIZEOF_UID_T == 2
-# define UID_FMT "%" PRIu16
-#else
-# error Unknown uid_t size
-#endif
-
-#if SIZEOF_GID_T == 4
-# define GID_FMT "%" PRIu32
-#elif SIZEOF_GID_T == 2
-# define GID_FMT "%" PRIu16
-#else
-# error Unknown gid_t size
-#endif
-
-#if SIZEOF_TIME_T == 8
-# define PRI_TIME PRIi64
-#elif SIZEOF_TIME_T == 4
-# define PRI_TIME PRIu32
-#else
-# error Unknown time_t size
-#endif
-
-#if SIZEOF_RLIM_T == 8
-# define RLIM_FMT "%" PRIu64
-#elif SIZEOF_RLIM_T == 4
-# define RLIM_FMT "%" PRIu32
-#else
-# error Unknown rlim_t size
-#endif
+#include <sys/statfs.h>
#include "macro.h"
#include "missing.h"
#include "time-util.h"
+#include "formats-util.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
@@ -104,16 +62,6 @@
#define FORMAT_BYTES_MAX 8
-#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
-#define ANSI_RED_ON "\x1B[31m"
-#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
-#define ANSI_GREEN_ON "\x1B[32m"
-#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
-#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
-#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m"
-#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
-#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
-
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
@@ -185,6 +133,7 @@ static inline char *startswith_no_case(const char *s, const char *prefix) {
}
char *endswith(const char *s, const char *postfix) _pure_;
+char *endswith_no_case(const char *s, const char *postfix) _pure_;
char *first_word(const char *s, const char *word) _pure_;
@@ -268,23 +217,15 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
-pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
-
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
-char *replace_env(const char *format, char **env);
-char **replace_env_argv(char **argv, char **env);
-
int readlinkat_malloc(int fd, const char *p, char **ret);
int readlink_malloc(const char *p, char **r);
int readlink_value(const char *p, char **ret);
int readlink_and_make_absolute(const char *p, char **r);
int readlink_and_canonicalize(const char *p, char **r);
-int reset_all_signal_handlers(void);
-int reset_signal_mask(void);
-
char *strstrip(char *s);
char *delete_chars(char *s, const char *bad);
char *truncate_nl(char *s);
@@ -293,17 +234,6 @@ char *file_in_same_dir(const char *path, const char *filename);
int rmdir_parents(const char *path, const char *stop);
-int get_process_state(pid_t pid);
-int get_process_comm(pid_t pid, char **name);
-int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
-int get_process_exe(pid_t pid, char **name);
-int get_process_uid(pid_t pid, uid_t *uid);
-int get_process_gid(pid_t pid, gid_t *gid);
-int get_process_capeff(pid_t pid, char **capeff);
-int get_process_cwd(pid_t pid, char **cwd);
-int get_process_root(pid_t pid, char **root);
-int get_process_environ(pid_t pid, char **environ);
-
char hexchar(int x) _const_;
int unhexchar(char c) _const_;
char octchar(int x) _const_;
@@ -312,9 +242,15 @@ char decchar(int x) _const_;
int undecchar(char c) _const_;
char *cescape(const char *s);
-char *cunescape(const char *s);
-char *cunescape_length(const char *s, size_t length);
-char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix);
+size_t cescape_char(char c, char *buf);
+
+typedef enum UnescapeFlags {
+ UNESCAPE_RELAX = 1,
+} UnescapeFlags;
+
+int cunescape(const char *s, UnescapeFlags flags, char **ret);
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
char *xescape(const char *s, const char *bad);
@@ -327,26 +263,6 @@ bool hidden_file(const char *filename) _pure_;
bool chars_intersect(const char *a, const char *b) _pure_;
-int make_stdio(int fd);
-int make_null_stdio(void);
-int make_console_stdio(void);
-
-int dev_urandom(void *p, size_t n);
-void random_bytes(void *p, size_t n);
-void initialize_srand(void);
-
-static inline uint64_t random_u64(void) {
- uint64_t u;
- random_bytes(&u, sizeof(u));
- return u;
-}
-
-static inline uint32_t random_u32(void) {
- uint32_t u;
- random_bytes(&u, sizeof(u));
- return u;
-}
-
/* For basic lookup tables with strictly enumerated entries */
#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
scope const char *name##_to_string(type i) { \
@@ -412,28 +328,12 @@ int close_all_fds(const int except[], unsigned n_except);
bool fstype_is_network(const char *fstype);
-int chvt(int vt);
-
-int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
-int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
-int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
-
-int reset_terminal_fd(int fd, bool switch_to_text);
-int reset_terminal(const char *name);
-
-int open_terminal(const char *name, int mode);
-int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout);
-int release_terminal(void);
-
int flush_fd(int fd);
-int ignore_signals(int sig, ...);
-int default_signals(int sig, ...);
-int sigaction_many(const struct sigaction *sa, ...);
-
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
+int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
bool is_device_path(const char *path);
@@ -441,75 +341,22 @@ bool is_device_path(const char *path);
int dir_is_empty(const char *path);
char* dirname_malloc(const char *path);
-void rename_process(const char name[8]);
-
-void sigset_add_many(sigset_t *ss, ...);
-int sigprocmask_many(int how, ...);
-
-bool hostname_is_set(void);
-
char* lookup_uid(uid_t uid);
-char* gethostname_malloc(void);
char* getlogname_malloc(void);
char* getusername_malloc(void);
-int getttyname_malloc(int fd, char **r);
-int getttyname_harder(int fd, char **r);
-
-int get_ctty_devnr(pid_t pid, dev_t *d);
-int get_ctty(pid_t, dev_t *_devnr, char **r);
-
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
-int is_fd_on_temporary_fs(int fd);
-
-int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
-int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
-int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
-int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
+bool is_temporary_fs(const struct statfs *s) _pure_;
+int fd_is_temporary_fs(int fd);
int pipe_eof(int fd);
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
-
#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
-int fd_columns(int fd);
-unsigned columns(void);
-int fd_lines(int fd);
-unsigned lines(void);
-void columns_lines_cache_reset(int _unused_ signum);
-
-bool on_tty(void);
-
-static inline const char *ansi_highlight(void) {
- return on_tty() ? ANSI_HIGHLIGHT_ON : "";
-}
-
-static inline const char *ansi_highlight_red(void) {
- return on_tty() ? ANSI_HIGHLIGHT_RED_ON : "";
-}
-
-static inline const char *ansi_highlight_green(void) {
- return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : "";
-}
-
-static inline const char *ansi_highlight_yellow(void) {
- return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : "";
-}
-
-static inline const char *ansi_highlight_blue(void) {
- return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : "";
-}
-
-static inline const char *ansi_highlight_off(void) {
- return on_tty() ? ANSI_HIGHLIGHT_OFF : "";
-}
-
int files_same(const char *filea, const char *fileb);
int running_in_chroot(void);
@@ -521,12 +368,6 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
-char *unquote(const char *s, const char *quotes);
-char *normalize_env_assignment(const char *s);
-
-int wait_for_terminate(pid_t pid, siginfo_t *status);
-int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
-
noreturn void freeze(void);
bool null_or_empty(struct stat *st) _pure_;
@@ -537,32 +378,17 @@ DIR *xopendirat(int dirfd, const char *name, int flags);
char *fstab_node_to_udev_node(const char *p);
-char *resolve_dev_console(char **active);
-bool tty_is_vc(const char *tty);
-bool tty_is_vc_resolve(const char *tty);
-bool tty_is_console(const char *tty) _pure_;
-int vtnr_from_tty(const char *tty);
-const char *default_term_for_tty(const char *tty);
-
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
-int kill_and_sigcont(pid_t pid, int sig);
-
bool nulstr_contains(const char*nulstr, const char *needle);
bool plymouth_running(void);
-bool hostname_is_valid(const char *s) _pure_;
-char* hostname_cleanup(char *s, bool lowercase);
-
bool machine_name_is_valid(const char *s) _pure_;
char* strshorten(char *s, size_t l);
-int terminal_vhangup_fd(int fd);
-int terminal_vhangup(const char *name);
-
-int vt_disallocate(const char *name);
+int symlink_idempotent(const char *from, const char *to);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
@@ -628,11 +454,6 @@ int rlimit_from_string(const char *s) _pure_;
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
-const char *signal_to_string(int i) _const_;
-int signal_from_string(const char *s) _pure_;
-
-int signal_from_string_try_harder(const char *s);
-
extern int saved_argc;
extern char **saved_argv;
@@ -646,8 +467,6 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
void* memdup(const void *p, size_t l) _alloc_(2);
-int is_kernel_thread(pid_t pid);
-
int fd_inc_sndbuf(int fd, size_t n);
int fd_inc_rcvbuf(int fd, size_t n);
@@ -655,8 +474,6 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
int setrlimit_closest(int resource, const struct rlimit *rlim);
-int getenv_for_pid(pid_t pid, const char *field, char **_value);
-
bool http_url_is_valid(const char *url) _pure_;
bool documentation_url_is_valid(const char *url) _pure_;
@@ -664,8 +481,6 @@ bool http_etag_is_valid(const char *etag);
bool in_initrd(void);
-void warn_melody(void);
-
int get_home_dir(char **ret);
int get_shell(char **_ret);
@@ -737,6 +552,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *),
void *arg);
+#define _(String) gettext (String)
+void init_gettext(void);
bool is_locale_utf8(void);
typedef enum DrawSpecialChar {
@@ -931,19 +748,6 @@ int unlink_noerrno(const char *path);
_d_; \
})
-#define procfs_file_alloca(pid, field) \
- ({ \
- pid_t _pid_ = (pid); \
- const char *_r_; \
- if (_pid_ == 0) { \
- _r_ = ("/proc/self/" field); \
- } else { \
- _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
- sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
- } \
- _r_; \
- })
-
bool id128_is_valid(const char *s) _pure_;
int split_pair(const char *s, const char *sep, char **l, char **r);
@@ -954,12 +758,27 @@ int shall_restore_state(void);
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
-static inline void qsort_safe(void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *)) {
- if (nmemb) {
- assert(base);
- qsort(base, nmemb, size, compar);
- }
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
+ if (nmemb <= 1)
+ return;
+
+ assert(base);
+ qsort(base, nmemb, size, compar);
+}
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+ if (needlelen <= 0)
+ return (void*) haystack;
+
+ if (haystacklen < needlelen)
+ return NULL;
+
+ assert(haystack);
+ assert(needle);
+
+ return memmem(haystack, haystacklen, needle, needlelen);
}
int proc_cmdline(char **ret);
@@ -971,9 +790,6 @@ int container_get_leader(const char *machine, pid_t *pid);
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd);
-bool pid_is_alive(pid_t pid);
-bool pid_is_unwaited(pid_t pid);
-
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
@@ -984,6 +800,13 @@ int open_tmpfile(const char *path, int flags);
int fd_warn_permissions(const char *path, int fd);
+#ifndef PERSONALITY_INVALID
+/* personality(7) documents that 0xffffffffUL is used for querying the
+ * current personality, hence let's use that here as error
+ * indicator. */
+#define PERSONALITY_INVALID 0xffffffffLU
+#endif
+
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
@@ -1009,19 +832,21 @@ int tempfn_xxxxxx(const char *p, char **ret);
int tempfn_random(const char *p, char **ret);
int tempfn_random_child(const char *p, char **ret);
-bool is_localhost(const char *hostname);
-
int take_password_lock(const char *root);
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
+int is_device_node(const char *path);
-int unquote_first_word(const char **p, char **ret, bool relax);
-int unquote_many_words(const char **p, ...) _sentinel_;
+typedef enum UnquoteFlags {
+ UNQUOTE_RELAX = 1,
+ UNQUOTE_CUNESCAPE = 2,
+} UnquoteFlags;
-int free_and_strdup(char **p, const char *s);
+int unquote_first_word(const char **p, char **ret, UnquoteFlags flags);
+int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_;
-int sethostname_idempotent(const char *s);
+int free_and_strdup(char **p, const char *s);
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
@@ -1050,26 +875,12 @@ int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
int same_fd(int a, int b);
-int chattr_fd(int fd, bool b, unsigned mask);
-int chattr_path(const char *p, bool b, unsigned mask);
+int chattr_fd(int fd, unsigned value, unsigned mask);
+int chattr_path(const char *p, unsigned value, unsigned mask);
int read_attr_fd(int fd, unsigned *ret);
int read_attr_path(const char *p, unsigned *ret);
-typedef struct LockFile {
- char *path;
- int fd;
- int operation;
-} LockFile;
-
-int make_lock_file(const char *p, int operation, LockFile *ret);
-int make_lock_file_for(const char *p, int operation, LockFile *ret);
-void release_lock_file(LockFile *f);
-
-#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
-
-#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
-
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
@@ -1078,3 +889,15 @@ void sigkill_wait(pid_t *pid);
#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
int syslog_parse_priority(const char **p, int *priority, bool with_facility);
+
+void cmsg_close_all(struct msghdr *mh);
+
+int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+
+char *shell_maybe_quote(const char *s);
+
+int parse_mode(const char *s, mode_t *ret);
+
+int mount_move_root(const char *path);
+
+int reset_uid_gid(void);
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index bdb962af34..8f66df7718 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -21,7 +21,6 @@
#include <utmpx.h>
#include <errno.h>
-#include <assert.h>
#include <string.h>
#include <sys/utsname.h>
#include <fcntl.h>
@@ -30,6 +29,8 @@
#include "macro.h"
#include "path-util.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
#include "utmp-wtmp.h"
int utmp_get_runlevel(int *runlevel, int *previous) {
@@ -347,8 +348,14 @@ static int write_to_terminal(const char *tty, const char *message) {
return 0;
}
-int utmp_wall(const char *message, const char *username, bool (*match_tty)(const char *tty)) {
- _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL;
+int utmp_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, void *userdata),
+ void *userdata) {
+
+ _cleanup_free_ char *text = NULL, *hn = NULL, *un = NULL, *stdin_tty = NULL;
char date[FORMAT_TIMESTAMP_MAX];
struct utmpx *u;
int r;
@@ -362,14 +369,17 @@ int utmp_wall(const char *message, const char *username, bool (*match_tty)(const
return -ENOMEM;
}
- getttyname_harder(STDIN_FILENO, &tty);
+ if (!origin_tty) {
+ getttyname_harder(STDIN_FILENO, &stdin_tty);
+ origin_tty = stdin_tty;
+ }
if (asprintf(&text,
"\a\r\n"
"Broadcast message from %s@%s%s%s (%s):\r\n\r\n"
"%s\r\n\r\n",
un ?: username, hn,
- tty ? " on " : "", strempty(tty),
+ origin_tty ? " on " : "", strempty(origin_tty),
format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)),
message) < 0)
return -ENOMEM;
@@ -396,7 +406,7 @@ int utmp_wall(const char *message, const char *username, bool (*match_tty)(const
path = buf;
}
- if (!match_tty || match_tty(path)) {
+ if (!match_tty || match_tty(path, userdata)) {
q = write_to_terminal(path, text);
if (q < 0)
r = q;
diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h
index 87d004e615..5d26ba6fb1 100644
--- a/src/shared/utmp-wtmp.h
+++ b/src/shared/utmp-wtmp.h
@@ -33,7 +33,12 @@ int utmp_put_runlevel(int runlevel, int previous);
int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line);
-int utmp_wall(const char *message, const char *username, bool (*match_tty)(const char *tty));
+int utmp_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, void *userdata),
+ void *userdata);
#else /* HAVE_UTMP */
@@ -55,8 +60,12 @@ static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int
static inline int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) {
return 0;
}
-static inline int utmp_wall(const char *message, const char *username,
- bool (*match_tty)(const char *tty)) {
+static inline int utmp_wall(
+ const char *message,
+ const char *username,
+ const char *origin_tty,
+ bool (*match_tty)(const char *tty, void *userdata),
+ void *userdata) {
return 0;
}
diff --git a/src/shared/virt.c b/src/shared/virt.c
index 7c1381f4b8..1299a75ed5 100644
--- a/src/shared/virt.c
+++ b/src/shared/virt.c
@@ -24,6 +24,7 @@
#include <unistd.h>
#include "util.h"
+#include "process-util.h"
#include "virt.h"
#include "fileio.h"
@@ -102,15 +103,35 @@ static int detect_vm_cpuid(const char **_id) {
}
static int detect_vm_devicetree(const char **_id) {
-#if defined(__powerpc__) || defined(__powerpc64__)
+#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
_cleanup_free_ char *hvtype = NULL;
int r;
- r = read_one_line_file("/sys/firmware/devicetree/base/hypervisor/compatible", &hvtype);
+ r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype);
if (r >= 0) {
if (streq(hvtype, "linux,kvm")) {
*_id = "kvm";
return 1;
+ } else if (strstr(hvtype, "xen")) {
+ *_id = "xen";
+ return 1;
+ }
+ } else if (r == -ENOENT) {
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *dent;
+
+ dir = opendir("/proc/device-tree");
+ if (!dir) {
+ if (errno == ENOENT)
+ return 0;
+ return -errno;
+ }
+
+ FOREACH_DIRENT(dent, dir, return -errno) {
+ if (strstr(dent->d_name, "fw-cfg")) {
+ *_id = "qemu";
+ return 1;
+ }
}
}
#endif
diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c
deleted file mode 100644
index 701882b96d..0000000000
--- a/src/shutdownd/shutdownd.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <poll.h>
-#include <sys/types.h>
-#include <sys/timerfd.h>
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stddef.h>
-
-#include "systemd/sd-daemon.h"
-#include "systemd/sd-shutdown.h"
-
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "utmp-wtmp.h"
-#include "mkdir.h"
-#include "fileio.h"
-
-union shutdown_buffer {
- struct sd_shutdown_command command;
- char space[offsetof(struct sd_shutdown_command, wall_message) + LINE_MAX];
-};
-
-static int read_packet(int fd, union shutdown_buffer *_b) {
- struct ucred *ucred;
- ssize_t n;
-
- union shutdown_buffer b; /* We maintain our own copy here, in
- * order not to corrupt the last message */
- struct iovec iovec = {
- .iov_base = &b,
- .iov_len = sizeof(b) - 1,
- };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control = {};
- struct msghdr msghdr = {
- .msg_iov = &iovec,
- .msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
-
- assert(fd >= 0);
- assert(_b);
-
- n = recvmsg(fd, &msghdr, MSG_DONTWAIT);
- if (n <= 0) {
- if (n == 0) {
- log_error("Short read");
- return -EIO;
- }
-
- if (errno == EAGAIN || errno == EINTR)
- return 0;
-
- log_error_errno(errno, "recvmsg(): %m");
- return -errno;
- }
-
- if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
- control.cmsghdr.cmsg_level != SOL_SOCKET ||
- control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
- control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- log_warning("Received message without credentials. Ignoring.");
- return 0;
- }
-
- ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
- if (ucred->uid != 0) {
- log_warning("Got request from unprivileged user. Ignoring.");
- return 0;
- }
-
- if ((size_t) n < offsetof(struct sd_shutdown_command, wall_message)) {
- log_warning("Message has invalid size. Ignoring.");
- return 0;
- }
-
- if (b.command.mode != SD_SHUTDOWN_NONE &&
- b.command.mode != SD_SHUTDOWN_REBOOT &&
- b.command.mode != SD_SHUTDOWN_POWEROFF &&
- b.command.mode != SD_SHUTDOWN_HALT &&
- b.command.mode != SD_SHUTDOWN_KEXEC) {
- log_warning("Message has invalid mode. Ignoring.");
- return 0;
- }
-
- b.space[n] = 0;
-
- *_b = b;
- return 1;
-}
-
-static void warn_wall(usec_t n, struct sd_shutdown_command *c) {
- char date[FORMAT_TIMESTAMP_MAX];
- const char *prefix;
- _cleanup_free_ char *l = NULL;
-
- assert(c);
- assert(c->warn_wall);
-
- if (n >= c->usec)
- return;
-
- if (c->mode == SD_SHUTDOWN_HALT)
- prefix = "The system is going down for system halt at ";
- else if (c->mode == SD_SHUTDOWN_POWEROFF)
- prefix = "The system is going down for power-off at ";
- else if (c->mode == SD_SHUTDOWN_REBOOT)
- prefix = "The system is going down for reboot at ";
- else if (c->mode == SD_SHUTDOWN_KEXEC)
- prefix = "The system is going down for kexec reboot at ";
- else if (c->mode == SD_SHUTDOWN_NONE)
- prefix = "The system shutdown has been cancelled at ";
- else
- assert_not_reached("Unknown mode!");
-
- if (asprintf(&l, "%s%s%s%s!", c->wall_message, c->wall_message[0] ? "\n" : "",
- prefix, format_timestamp(date, sizeof(date), c->usec)) >= 0)
- utmp_wall(l, NULL, NULL);
- else
- log_error("Failed to allocate wall message");
-}
-
-_const_ static usec_t when_wall(usec_t n, usec_t elapse) {
-
- static const struct {
- usec_t delay;
- usec_t interval;
- } table[] = {
- { 0, USEC_PER_MINUTE },
- { 10 * USEC_PER_MINUTE, 15 * USEC_PER_MINUTE },
- { USEC_PER_HOUR, 30 * USEC_PER_MINUTE },
- { 3 * USEC_PER_HOUR, USEC_PER_HOUR },
- };
-
- usec_t left, sub;
- unsigned i = ELEMENTSOF(table) - 1;
-
- /* If the time is already passed, then don't announce */
- if (n >= elapse)
- return 0;
-
- left = elapse - n;
- while (left < table[i].delay)
- i--;
- sub = (left / table[i].interval) * table[i].interval;
-
- assert(sub < elapse);
- return elapse - sub;
-}
-
-static usec_t when_nologin(usec_t elapse) {
- return elapse > 5*USEC_PER_MINUTE ? elapse - 5*USEC_PER_MINUTE : 1;
-}
-
-static const char *mode_to_string(enum sd_shutdown_mode m) {
- switch (m) {
- case SD_SHUTDOWN_REBOOT:
- return "reboot";
- case SD_SHUTDOWN_POWEROFF:
- return "poweroff";
- case SD_SHUTDOWN_HALT:
- return "halt";
- case SD_SHUTDOWN_KEXEC:
- return "kexec";
- default:
- return NULL;
- }
-}
-
-static int update_schedule_file(struct sd_shutdown_command *c) {
- int r;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *t = NULL, *temp_path = NULL;
-
- assert(c);
-
- r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
-
- t = cescape(c->wall_message);
- if (!t)
- return log_oom();
-
- r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
- if (r < 0)
- return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
-
- fchmod(fileno(f), 0644);
-
- fprintf(f,
- "USEC="USEC_FMT"\n"
- "WARN_WALL=%i\n"
- "MODE=%s\n",
- c->usec,
- c->warn_wall,
- mode_to_string(c->mode));
-
- if (c->dry_run)
- fputs("DRY_RUN=1\n", f);
-
- if (!isempty(t))
- fprintf(f, "WALL_MESSAGE=%s\n", t);
-
- fflush(f);
-
- if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
- log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
- r = -errno;
-
- unlink(temp_path);
- unlink("/run/systemd/shutdown/scheduled");
- }
-
- return r;
-}
-
-static bool scheduled(struct sd_shutdown_command *c) {
- return c->usec > 0 && c->mode != SD_SHUTDOWN_NONE;
-}
-
-int main(int argc, char *argv[]) {
- enum {
- FD_SOCKET,
- FD_WALL_TIMER,
- FD_NOLOGIN_TIMER,
- FD_SHUTDOWN_TIMER,
- _FD_MAX
- };
-
- int r = EXIT_FAILURE, n_fds;
- union shutdown_buffer b = {};
- struct pollfd pollfd[_FD_MAX] = {};
- bool exec_shutdown = false, unlink_nologin = false;
- unsigned i;
-
- if (getppid() != 1) {
- log_error("This program should be invoked by init only.");
- return EXIT_FAILURE;
- }
-
- if (argc > 1) {
- log_error("This program does not take arguments.");
- return EXIT_FAILURE;
- }
-
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
-
- umask(0022);
-
- n_fds = sd_listen_fds(true);
- if (n_fds < 0) {
- log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
- return EXIT_FAILURE;
- }
-
- if (n_fds != 1) {
- log_error("Need exactly one file descriptor.");
- return EXIT_FAILURE;
- }
-
- pollfd[FD_SOCKET].fd = SD_LISTEN_FDS_START;
- pollfd[FD_SOCKET].events = POLLIN;
-
- for (i = FD_WALL_TIMER; i < _FD_MAX; i++) {
- pollfd[i].events = POLLIN;
- pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
- if (pollfd[i].fd < 0) {
- log_error_errno(errno, "timerfd_create(): %m");
- goto finish;
- }
- }
-
- log_debug("systemd-shutdownd running as pid "PID_FMT, getpid());
-
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing requests...");
-
- for (;;) {
- int k;
- usec_t n;
-
- k = poll(pollfd, _FD_MAX, scheduled(&b.command) ? -1 : 0);
- if (k < 0) {
-
- if (errno == EAGAIN || errno == EINTR)
- continue;
-
- log_error_errno(errno, "poll(): %m");
- goto finish;
- }
-
- /* Exit on idle */
- if (k == 0)
- break;
-
- n = now(CLOCK_REALTIME);
-
- if (pollfd[FD_SOCKET].revents) {
-
- k = read_packet(pollfd[FD_SOCKET].fd, &b);
- if (k < 0)
- goto finish;
- else if (k > 0) {
- struct itimerspec its;
- char date[FORMAT_TIMESTAMP_MAX];
-
- if (!scheduled(&b.command)) {
- log_info("Shutdown canceled.");
- if (b.command.warn_wall)
- warn_wall(0, &b.command);
- break;
- }
-
- zero(its);
- if (b.command.warn_wall) {
- /* Send wall messages every so often */
- timespec_store(&its.it_value, when_wall(n, b.command.usec));
-
- /* Warn immediately if less than 15 minutes are left */
- if (n < b.command.usec &&
- n + 15*USEC_PER_MINUTE >= b.command.usec)
- warn_wall(n, &b.command);
- }
- if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error_errno(errno, "timerfd_settime(): %m");
- goto finish;
- }
-
- /* Disallow logins 5 minutes prior to shutdown */
- zero(its);
- timespec_store(&its.it_value, when_nologin(b.command.usec));
- if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error_errno(errno, "timerfd_settime(): %m");
- goto finish;
- }
-
- /* Shutdown after the specified time is reached */
- zero(its);
- timespec_store(&its.it_value, b.command.usec);
- if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error_errno(errno, "timerfd_settime(): %m");
- goto finish;
- }
-
- update_schedule_file(&b.command);
-
- sd_notifyf(false,
- "STATUS=Shutting down at %s (%s)...",
- format_timestamp(date, sizeof(date), b.command.usec),
- mode_to_string(b.command.mode));
-
- log_info("Shutting down at %s (%s)...", date, mode_to_string(b.command.mode));
- }
- }
-
- if (pollfd[FD_WALL_TIMER].revents) {
- struct itimerspec its = {};
-
- warn_wall(n, &b.command);
- flush_fd(pollfd[FD_WALL_TIMER].fd);
-
- /* Restart timer */
- timespec_store(&its.it_value, when_wall(n, b.command.usec));
- if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error_errno(errno, "timerfd_settime(): %m");
- goto finish;
- }
- }
-
- if (pollfd[FD_NOLOGIN_TIMER].revents) {
- int e;
-
- log_info("Creating /run/nologin, blocking further logins...");
-
- e = write_string_file_atomic("/run/nologin", "System is going down.");
- if (e < 0)
- log_error_errno(e, "Failed to create /run/nologin: %m");
- else
- unlink_nologin = true;
-
- flush_fd(pollfd[FD_NOLOGIN_TIMER].fd);
- }
-
- if (pollfd[FD_SHUTDOWN_TIMER].revents) {
- exec_shutdown = true;
- goto finish;
- }
- }
-
- r = EXIT_SUCCESS;
-
- log_debug("systemd-shutdownd stopped as pid "PID_FMT, getpid());
-
-finish:
-
- for (i = 0; i < _FD_MAX; i++)
- safe_close(pollfd[i].fd);
-
- if (unlink_nologin)
- unlink("/run/nologin");
-
- unlink("/run/systemd/shutdown/scheduled");
-
- if (exec_shutdown && !b.command.dry_run) {
- char sw[3];
-
- sw[0] = '-';
- sw[1] = b.command.mode;
- sw[2] = 0;
-
- execl(SYSTEMCTL_BINARY_PATH,
- "shutdown",
- sw,
- "now",
- (b.command.warn_wall && b.command.wall_message[0]) ? b.command.wall_message :
- (b.command.warn_wall ? NULL : "--no-wall"),
- NULL);
-
- log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
- }
-
- sd_notify(false,
- "STOPPING=\n"
- "STATUS=Exiting...");
-
- return r;
-}
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index cc1ffa63f1..eee6bc8982 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -22,10 +22,8 @@
#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <getopt.h>
-#include "sd-id128.h"
#include "sd-messages.h"
#include "log.h"
#include "util.h"
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index a3c3c87f11..715f440cb1 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <arpa/inet.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
@@ -37,7 +36,6 @@
#include "log.h"
#include "socket-util.h"
#include "util.h"
-#include "event-util.h"
#include "build.h"
#include "set.h"
#include "path-util.h"
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 275a5b74ae..fe277a2015 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -35,75 +35,30 @@
#include "conf-files.h"
#include "fileio.h"
#include "build.h"
+#include "sysctl-util.h"
static char **arg_prefixes = NULL;
static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl");
-static char* normalize_sysctl(char *s) {
- char *n;
-
- n = strpbrk(s, "/.");
- /* If the first separator is a slash, the path is
- * assumed to be normalized and slashes remain slashes
- * and dots remains dots. */
- if (!n || *n == '/')
- return s;
-
- /* Otherwise, dots become slashes and slashes become
- * dots. Fun. */
- while (n) {
- if (*n == '.')
- *n = '/';
- else
- *n = '.';
-
- n = strpbrk(n + 1, "/.");
- }
-
- return s;
-}
-
-static int apply_sysctl(const char *property, const char *value) {
- _cleanup_free_ char *p = NULL;
- char *n;
- int r = 0, k;
-
- log_debug("Setting '%s' to '%s'", property, value);
-
- p = new(char, strlen("/proc/sys/") + strlen(property) + 1);
- if (!p)
- return log_oom();
-
- n = stpcpy(p, "/proc/sys/");
- strcpy(n, property);
-
- k = write_string_file(p, value);
- if (k < 0) {
- log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
- "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
-
- if (k != -ENOENT && r == 0)
- r = k;
- }
-
- return r;
-}
-
static int apply_all(Hashmap *sysctl_options) {
- int r = 0;
char *property, *value;
Iterator i;
-
- assert(sysctl_options);
+ int r = 0;
HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
int k;
- k = apply_sysctl(property, value);
- if (k < 0 && r == 0)
- r = k;
+ k = sysctl_write(property, value);
+ if (k < 0) {
+ log_full_errno(k == -ENOENT ? LOG_DEBUG : LOG_WARNING, k,
+ "Failed to write '%s' to '%s': %m", value, property);
+
+ if (r == 0 && k != -ENOENT)
+ r = k;
+ }
}
+
return r;
}
@@ -121,7 +76,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
}
- log_debug("parse: %s", path);
+ log_debug("Parsing %s", path);
while (!feof(f)) {
char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
void *v;
@@ -154,7 +109,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
*value = 0;
value++;
- p = normalize_sysctl(strstrip(p));
+ p = sysctl_normalize(strstrip(p));
value = strstrip(value);
if (!strv_isempty(arg_prefixes)) {
@@ -176,7 +131,7 @@ found:
if (streq(value, existing))
continue;
- log_info("Overwriting earlier assignment of %s in file '%s'.", p, path);
+ log_debug("Overwriting earlier assignment of %s in file '%s'.", p, path);
free(hashmap_remove(sysctl_options, p));
free(v);
}
@@ -251,14 +206,15 @@ static int parse_argv(int argc, char *argv[]) {
* in /proc/sys in the past. This is kinda useless, but
* we need to keep compatibility. We now support any
* sysctl name available. */
- normalize_sysctl(optarg);
+ sysctl_normalize(optarg);
+
if (startswith(optarg, "/proc/sys"))
p = strdup(optarg);
else
p = strappend("/proc/sys/", optarg);
-
if (!p)
return log_oom();
+
if (strv_consume(&arg_prefixes, p) < 0)
return log_oom();
diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c
index ad34ef1366..00045150f6 100644
--- a/src/system-update-generator/system-update-generator.c
+++ b/src/system-update-generator/system-update-generator.c
@@ -24,8 +24,6 @@
#include "log.h"
#include "util.h"
-#include "unit-name.h"
-#include "path-util.h"
/*
* Implements the logic described in
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 21cb898b9a..b3d90d2c33 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -22,24 +22,18 @@
#include <sys/reboot.h>
#include <linux/reboot.h>
-#include <sys/syscall.h>
#include <stdio.h>
#include <getopt.h>
#include <locale.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
-#include <sys/ioctl.h>
-#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <stddef.h>
-#include <sys/prctl.h>
#include "sd-daemon.h"
-#include "sd-shutdown.h"
#include "sd-login.h"
#include "sd-bus.h"
#include "log.h"
@@ -55,7 +49,6 @@
#include "cgroup-util.h"
#include "list.h"
#include "path-lookup.h"
-#include "conf-parser.h"
#include "exit-status.h"
#include "build.h"
#include "unit-name.h"
@@ -74,6 +67,12 @@
#include "bus-common-errors.h"
#include "mkdir.h"
#include "dropin.h"
+#include "efivars.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -138,6 +137,8 @@ static char *arg_host = NULL;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
+static bool arg_firmware_setup = false;
+static bool arg_now = false;
static bool original_stdout_is_tty;
@@ -252,7 +253,7 @@ static void warn_wall(enum action a) {
}
if (*p) {
- utmp_wall(p, NULL, NULL);
+ utmp_wall(p, NULL, NULL, NULL, NULL);
return;
}
}
@@ -260,7 +261,7 @@ static void warn_wall(enum action a) {
if (!table[a])
return;
- utmp_wall(table[a], NULL, NULL);
+ utmp_wall(table[a], NULL, NULL, NULL, NULL);
}
static bool avoid_bus(void) {
@@ -1327,7 +1328,6 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
static int list_unit_files(sd_bus *bus, char **args) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ UnitFileList *units = NULL;
UnitFileList *unit;
size_t size = 0;
@@ -1374,6 +1374,8 @@ static int list_unit_files(sd_bus *bus, char **args) {
assert(c <= n_units);
hashmap_free(h);
} else {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -1637,13 +1639,15 @@ static int list_dependencies(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **units = NULL;
_cleanup_free_ char *unit = NULL;
const char *u;
+ int r;
assert(bus);
if (args[1]) {
- unit = unit_name_mangle(args[1], MANGLE_NOGLOB);
- if (!unit)
- return log_oom();
+ r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
+
u = unit;
} else
u = SPECIAL_DEFAULT_TARGET;
@@ -1882,7 +1886,6 @@ static int list_machines(sd_bus *bus, char **args) {
static int get_default(sd_bus *bus, char **args) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *_path = NULL;
const char *path;
int r;
@@ -1894,6 +1897,8 @@ static int get_default(sd_bus *bus, char **args) {
path = _path;
} else {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -1938,9 +1943,9 @@ static int set_default(sd_bus *bus, char **args) {
unsigned n_changes = 0;
int r;
- unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
- if (!unit)
- return log_oom();
+ r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
if (!bus || avoid_bus()) {
r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
@@ -1952,34 +1957,26 @@ static int set_default(sd_bus *bus, char **args) {
r = 0;
} else {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- r = sd_bus_message_new_method_call(
+ polkit_agent_open_if_enabled();
+
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "SetDefaultTarget");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "sb", unit, 1);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
+ "SetDefaultTarget",
+ &error,
+ &reply,
+ "sb", unit, 1);
if (r < 0) {
log_error("Failed to set default target: %s", bus_error_message(&error, -r));
return r;
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
@@ -2130,7 +2127,6 @@ static int list_jobs(sd_bus *bus, char **args) {
}
static int cancel_job(sd_bus *bus, char **args) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char **name;
int r = 0;
@@ -2139,8 +2135,10 @@ static int cancel_job(sd_bus *bus, char **args) {
if (strv_length(args) <= 1)
return daemon_reload(bus, args);
+ polkit_agent_open_if_enabled();
+
STRV_FOREACH(name, args+1) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
uint32_t id;
int q;
@@ -2148,25 +2146,15 @@ static int cancel_job(sd_bus *bus, char **args) {
if (q < 0)
return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
- q = sd_bus_message_new_method_call(
+ q = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "CancelJob");
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (q < 0)
- return bus_log_create_error(1);
-
- q = sd_bus_message_append(m, "u", id);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_call(bus, m, 0, &error, NULL);
+ "CancelJob",
+ &error,
+ NULL,
+ "u", id);
if (q < 0) {
log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
if (r == 0)
@@ -2250,12 +2238,13 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
return 0;
}
-static int unit_find_paths(sd_bus *bus,
- const char *unit_name,
- bool avoid_bus_cache,
- LookupPaths *lp,
- char **fragment_path,
- char ***dropin_paths) {
+static int unit_find_paths(
+ sd_bus *bus,
+ const char *unit_name,
+ bool avoid_bus_cache,
+ LookupPaths *lp,
+ char **fragment_path,
+ char ***dropin_paths) {
_cleanup_free_ char *path = NULL;
_cleanup_strv_free_ char **dropins = NULL;
@@ -2273,7 +2262,7 @@ static int unit_find_paths(sd_bus *bus,
assert(fragment_path);
assert(lp);
- if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
+ if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
_cleanup_free_ char *unit = NULL;
@@ -2339,24 +2328,23 @@ static int unit_find_paths(sd_bus *bus,
names = set_new(NULL);
if (!names)
- return -ENOMEM;
+ return log_oom();
r = set_put(names, unit_name);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add unit name: %m");
r = unit_file_find_path(lp, unit_name, &path);
if (r < 0)
return r;
if (r == 0) {
- _cleanup_free_ char *template;
+ _cleanup_free_ char *template = NULL;
- template = unit_name_template(unit_name);
- if (!template)
- return log_oom();
-
- if (!streq(template, unit_name)) {
+ r = unit_name_template(unit_name, &template);
+ if (r < 0 && r != -EINVAL)
+ return log_error_errno(r, "Failed to determine template name: %m");
+ if (r >= 0) {
r = unit_file_find_path(lp, template, &path);
if (r < 0)
return r;
@@ -2398,9 +2386,9 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states
assert(name);
- n = unit_name_mangle(name, MANGLE_NOGLOB);
- if (!n)
- return log_oom();
+ r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
/* We don't use unit_dbus_path_from_name() directly since we
* don't want to load the unit if it isn't loaded. */
@@ -2455,9 +2443,9 @@ static int check_triggering_units(
char **i;
int r;
- n = unit_name_mangle(name, MANGLE_NOGLOB);
- if (!n)
- return log_oom();
+ r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
path = unit_dbus_path_from_name(n);
if (!path)
@@ -2556,7 +2544,7 @@ static int start_unit_one(
sd_bus_error *error,
BusWaitForJobs *w) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *path;
int r;
@@ -2567,25 +2555,15 @@ static int start_unit_one(
log_debug("Calling manager for %s on %s, %s", method, name, mode);
- r = sd_bus_message_new_method_call(
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- method);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "ss", name, mode);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, error, &reply);
+ method,
+ error,
+ &reply,
+ "ss", name, mode);
if (r < 0) {
const char *verb;
@@ -2621,17 +2599,17 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
_cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
char **name;
- int r = 0, i;
+ int r, i;
STRV_FOREACH(name, names) {
char *t;
if (suffix)
- t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix);
+ r = unit_name_mangle_with_suffix(*name, UNIT_NAME_GLOB, suffix, &t);
else
- t = unit_name_mangle(*name, MANGLE_GLOB);
- if (!t)
- return log_oom();
+ r = unit_name_mangle(*name, UNIT_NAME_GLOB, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle name: %m");
if (string_is_glob(t))
r = strv_consume(&globs, t);
@@ -2648,7 +2626,7 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
_cleanup_free_ UnitInfo *unit_infos = NULL;
if (!bus)
- return log_error_errno(ENOTSUP, "Unit name globbing without bus is not implemented.");
+ return log_error_errno(EOPNOTSUPP, "Unit name globbing without bus is not implemented.");
r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
if (r < 0)
@@ -2674,10 +2652,10 @@ static const struct {
[ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
[ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
[ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
- [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
- [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
- [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
- [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
+ [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
[ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
[ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
[ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
@@ -2881,6 +2859,9 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
if (!sv)
return log_oom();
+ if ((pid_t) pid < 0)
+ return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
+
if (!strv_contains(sv,
a == ACTION_HALT ||
a == ACTION_POWEROFF ||
@@ -2892,7 +2873,7 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
user = uid_to_name(uid);
log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
- who, pid, strna(comm), strna(user), why);
+ who, (pid_t) pid, strna(comm), strna(user), why);
c++;
}
@@ -2938,6 +2919,46 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
#endif
}
+static int prepare_firmware_setup(sd_bus *bus) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+#endif
+ int r;
+
+ if (!arg_firmware_setup)
+ return 0;
+
+ if (arg_transport == BUS_TRANSPORT_LOCAL) {
+
+ r = efi_set_reboot_to_firmware(true);
+ if (r < 0)
+ log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
+ else
+ return r;
+ }
+
+#ifdef HAVE_LOGIND
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetRebootToFirmwareSetup",
+ &error,
+ NULL,
+ "b", true);
+ if (r < 0) {
+ log_error("Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
+ return r;
+ }
+
+ return 0;
+#else
+ log_error("Cannot remotely indicate to EFI to boot into setup mode.");
+ return -EINVAL;
+#endif
+}
+
static int start_special(sd_bus *bus, char **args) {
enum action a;
int r;
@@ -2955,6 +2976,10 @@ static int start_special(sd_bus *bus, char **args) {
return -EPERM;
}
+ r = prepare_firmware_setup(bus);
+ if (r < 0)
+ return r;
+
if (a == ACTION_REBOOT && args[1]) {
r = update_reboot_param_file(args[1]);
if (r < 0)
@@ -2983,7 +3008,7 @@ static int start_special(sd_bus *bus, char **args) {
a == ACTION_HIBERNATE ||
a == ACTION_HYBRID_SLEEP)) {
r = reboot_with_logind(bus, a);
- if (r >= 0 || IN_SET(r, -ENOTSUP, -EINPROGRESS))
+ if (r >= 0 || IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
return r;
}
@@ -3029,7 +3054,6 @@ static int check_unit_failed(sd_bus *bus, char **args) {
}
static int kill_unit(sd_bus *bus, char **args) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
char **name;
int r, q;
@@ -3047,27 +3071,17 @@ static int kill_unit(sd_bus *bus, char **args) {
log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- q = sd_bus_message_new_method_call(
+ q = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "KillUnit");
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_append(m, "ssi", *names, arg_kill_who, arg_signal);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_call(bus, m, 0, &error, NULL);
+ "KillUnit",
+ &error,
+ NULL,
+ "ssi", *names, arg_kill_who, arg_signal);
if (q < 0) {
log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
if (r == 0)
@@ -3233,6 +3247,7 @@ typedef struct UnitStatusInfo {
/* CGroup */
uint64_t memory_current;
uint64_t memory_limit;
+ uint64_t cpu_usage_nsec;
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
@@ -3503,6 +3518,11 @@ static void print_status_info(
printf("\n");
}
+ if (i->cpu_usage_nsec != (uint64_t) -1) {
+ char buf[FORMAT_TIMESPAN_MAX];
+ printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
+ }
+
if (i->control_group &&
(i->main_pid > 0 || i->control_pid > 0 ||
((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
@@ -3721,6 +3741,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->memory_current = u;
else if (streq(name, "MemoryLimit"))
i->memory_limit = u;
+ else if (streq(name, "CPUUsageNSec"))
+ i->cpu_usage_nsec = u;
break;
}
@@ -4194,6 +4216,7 @@ static int show_one(
UnitStatusInfo info = {
.memory_current = (uint64_t) -1,
.memory_limit = (uint64_t) -1,
+ .cpu_usage_nsec = (uint64_t) -1,
};
ExecStatusInfo *p;
int r;
@@ -4446,6 +4469,12 @@ static int show(sd_bus *bus, char **args) {
if (show_properties)
pager_open_if_enabled();
+ if (show_status)
+ /* Increase max number of open files to 16K if we can, we
+ * might needs this when browsing journal files, which might
+ * be split up into many files. */
+ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
+
/* If no argument is specified inspect the manager itself */
if (show_properties && strv_length(args) <= 1)
@@ -4552,6 +4581,23 @@ static int init_home_and_lookup_paths(char **user_home, char **user_runtime, Loo
return 0;
}
+static int cat_file(const char *filename, bool newline) {
+ _cleanup_close_ int fd;
+
+ fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+
+ printf("%s%s# %s%s\n",
+ newline ? "\n" : "",
+ ansi_highlight_blue(),
+ filename,
+ ansi_highlight_off());
+ fflush(stdout);
+
+ return copy_bytes(fd, STDOUT_FILENO, (off_t) -1, false);
+}
+
static int cat(sd_bus *bus, char **args) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
@@ -4559,7 +4605,7 @@ static int cat(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **names = NULL;
char **name;
bool first = true, avoid_bus_cache;
- int r = 0;
+ int r;
assert(args);
@@ -4597,36 +4643,19 @@ static int cat(sd_bus *bus, char **args) {
puts("");
if (fragment_path) {
- printf("%s# %s%s\n",
- ansi_highlight_blue(),
- fragment_path,
- ansi_highlight_off());
- fflush(stdout);
-
- r = copy_file_fd(fragment_path, STDOUT_FILENO, false);
- if (r < 0) {
- log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
- continue;
- }
+ r = cat_file(fragment_path, false);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
}
STRV_FOREACH(path, dropin_paths) {
- printf("%s%s# %s%s\n",
- isempty(fragment_path) && path == dropin_paths ? "" : "\n",
- ansi_highlight_blue(),
- *path,
- ansi_highlight_off());
- fflush(stdout);
-
- r = copy_file_fd(*path, STDOUT_FILENO, false);
- if (r < 0) {
- log_warning_errno(r, "Failed to cat %s: %m", *path);
- continue;
- }
+ r = cat_file(*path, path == dropin_paths);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to cat %s: %m", *path);
}
}
- return r < 0 ? r : 0;
+ return 0;
}
static int set_property(sd_bus *bus, char **args) {
@@ -4648,13 +4677,9 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
+ r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
if (r < 0)
- return bus_log_create_error(r);
-
- n = unit_name_mangle(args[1], MANGLE_NOGLOB);
- if (!n)
- return log_oom();
+ return log_error_errno(r, "Failed to mangle unit name: %m");
r = sd_bus_message_append(m, "sb", n, arg_runtime);
if (r < 0)
@@ -4693,39 +4718,32 @@ static int set_property(sd_bus *bus, char **args) {
static int snapshot(sd_bus *bus, char **args) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *n = NULL, *id = NULL;
const char *path;
int r;
polkit_agent_open_if_enabled();
- if (strv_length(args) > 1)
- n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
- else
+ if (strv_length(args) > 1) {
+ r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit name: %m");
+ } else {
n = strdup("");
- if (!n)
- return log_oom();
+ if (!n)
+ return log_oom();
+ }
- r = sd_bus_message_new_method_call(
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "CreateSnapshot");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(m, "sb", n, false);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
+ "CreateSnapshot",
+ &error,
+ &reply,
+ "sb", n, false);
if (r < 0) {
log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
return r;
@@ -4755,7 +4773,6 @@ static int snapshot(sd_bus *bus, char **args) {
}
static int delete_snapshot(sd_bus *bus, char **args) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
char **name;
int r;
@@ -4769,28 +4786,18 @@ static int delete_snapshot(sd_bus *bus, char **args) {
log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int q;
- q = sd_bus_message_new_method_call(
+ q = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "RemoveSnapshot");
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_append(m, "s", *name);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_call(bus, m, 0, &error, NULL);
+ "RemoveSnapshot",
+ &error,
+ NULL,
+ "s", *name);
if (q < 0) {
log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
@@ -4803,7 +4810,6 @@ static int delete_snapshot(sd_bus *bus, char **args) {
static int daemon_reload(sd_bus *bus, char **args) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
const char *method;
int r;
@@ -4829,21 +4835,15 @@ static int daemon_reload(sd_bus *bus, char **args) {
/* "daemon-reload" */ "Reload";
}
- r = sd_bus_message_new_method_call(
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- method);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, NULL);
+ method,
+ &error,
+ NULL,
+ NULL);
if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
/* There's always a fallback possible for
* legacy actions. */
@@ -4859,7 +4859,6 @@ static int daemon_reload(sd_bus *bus, char **args) {
}
static int reset_failed(sd_bus *bus, char **args) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
char **name;
int r, q;
@@ -4874,27 +4873,17 @@ static int reset_failed(sd_bus *bus, char **args) {
log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- q = sd_bus_message_new_method_call(
+ q = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "ResetFailedUnit");
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_message_append(m, "s", *name);
- if (q < 0)
- return bus_log_create_error(q);
-
- q = sd_bus_call(bus, m, 0, &error, NULL);
+ "ResetFailedUnit",
+ &error,
+ NULL,
+ "s", *name);
if (q < 0) {
log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
@@ -5013,6 +5002,8 @@ static int set_environment(sd_bus *bus, char **args) {
assert(bus);
assert(args);
+ polkit_agent_open_if_enabled();
+
method = streq(args[0], "set-environment")
? "SetEnvironment"
: "UnsetEnvironment";
@@ -5027,10 +5018,6 @@ static int set_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
r = sd_bus_message_append_strv(m, args + 1);
if (r < 0)
return bus_log_create_error(r);
@@ -5052,6 +5039,8 @@ static int import_environment(sd_bus *bus, char **args) {
assert(bus);
assert(args);
+ polkit_agent_open_if_enabled();
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5062,10 +5051,6 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
if (strv_isempty(args + 1))
r = sd_bus_message_append_strv(m, environ);
else {
@@ -5114,7 +5099,7 @@ static int import_environment(sd_bus *bus, char **args) {
static int enable_sysv_units(const char *verb, char **args) {
int r = 0;
-#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
+#if defined(HAVE_SYSV_COMPAT)
unsigned f = 0;
_cleanup_lookup_paths_free_ LookupPaths paths = {};
@@ -5129,7 +5114,7 @@ static int enable_sysv_units(const char *verb, char **args) {
/* Processes all SysV units, and reshuffles the array so that
* afterwards only the native units remain */
- r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, arg_root, NULL, NULL, NULL);
+ r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
if (r < 0)
return r;
@@ -5139,7 +5124,7 @@ static int enable_sysv_units(const char *verb, char **args) {
_cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
bool found_native = false, found_sysv;
unsigned c = 1;
- const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
+ const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
char **k;
int j;
pid_t pid;
@@ -5165,7 +5150,10 @@ static int enable_sysv_units(const char *verb, char **args) {
break;
}
- if (found_native)
+ /* If we have both a native unit and a SysV script,
+ * enable/disable them both (below); for is-enabled, prefer the
+ * native unit */
+ if (found_native && streq(verb, "is-enabled"))
continue;
p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
@@ -5177,15 +5165,16 @@ static int enable_sysv_units(const char *verb, char **args) {
if (!found_sysv)
continue;
- log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
+ if (found_native)
+ log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
+ else
+ log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
if (!isempty(arg_root))
argv[c++] = q = strappend("--root=", arg_root);
+ argv[c++] = verb;
argv[c++] = basename(p);
- argv[c++] =
- streq(verb, "enable") ? "on" :
- streq(verb, "disable") ? "off" : "--level=5";
argv[c] = NULL;
l = strv_join((char**)argv, " ");
@@ -5201,6 +5190,7 @@ static int enable_sysv_units(const char *verb, char **args) {
/* Child */
execv(argv[0], (char**) argv);
+ log_error("Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
}
@@ -5226,6 +5216,9 @@ static int enable_sysv_units(const char *verb, char **args) {
} else
return -EPROTO;
+ if (found_native)
+ continue;
+
/* Remove this entry, so that we don't try enabling it as native unit */
assert(f > 0);
f--;
@@ -5239,25 +5232,29 @@ static int enable_sysv_units(const char *verb, char **args) {
static int mangle_names(char **original_names, char ***mangled_names) {
char **i, **l, **name;
+ int r;
- l = new(char*, strv_length(original_names) + 1);
+ l = i = new(char*, strv_length(original_names) + 1);
if (!l)
return log_oom();
- i = l;
STRV_FOREACH(name, original_names) {
/* When enabling units qualified path names are OK,
* too, hence allow them explicitly. */
- if (is_path(*name))
+ if (is_path(*name)) {
*i = strdup(*name);
- else
- *i = unit_name_mangle(*name, MANGLE_NOGLOB);
-
- if (!*i) {
- strv_free(l);
- return log_oom();
+ if (!*i) {
+ strv_free(l);
+ return log_oom();
+ }
+ } else {
+ r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
+ if (r < 0) {
+ strv_free(l);
+ return log_error_errno(r, "Failed to mangle unit name: %m");
+ }
}
i++;
@@ -5370,10 +5367,6 @@ static int enable_unit(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
r = sd_bus_message_append_strv(m, names);
if (r < 0)
return bus_log_create_error(r);
@@ -5406,7 +5399,7 @@ static int enable_unit(sd_bus *bus, char **args) {
return bus_log_parse_error(r);
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
return r;
@@ -5428,6 +5421,18 @@ static int enable_unit(sd_bus *bus, char **args) {
"3) A unit may be started when needed via activation (socket, path, timer,\n"
" D-Bus, udev, scripted systemctl call, ...).\n");
+ if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
+ char *new_args[n_changes + 2];
+ unsigned i;
+
+ new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+ for (i = 0; i < n_changes; i++)
+ new_args[i + 1] = basename(changes[i].path);
+ new_args[i + 1] = NULL;
+
+ r = start_unit(bus, new_args);
+ }
+
finish:
unit_file_changes_free(changes, n_changes);
@@ -5444,9 +5449,9 @@ static int add_dependency(sd_bus *bus, char **args) {
if (!args[1])
return 0;
- target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
- if (!target)
- return log_oom();
+ r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
+ if (r < 0)
+ return log_error_errno(r, "Failed to mangle unit name: %m");
r = mangle_names(args+2, &names);
if (r < 0)
@@ -5489,10 +5494,6 @@ static int add_dependency(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
r = sd_bus_message_append_strv(m, names);
if (r < 0)
return bus_log_create_error(r);
@@ -5507,7 +5508,7 @@ static int add_dependency(sd_bus *bus, char **args) {
return r;
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
@@ -5539,41 +5540,29 @@ static int preset_all(sd_bus *bus, char **args) {
r = 0;
} else {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
polkit_agent_open_if_enabled();
- r = sd_bus_message_new_method_call(
+ r = sd_bus_call_method(
bus,
- &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "PresetAllUnitFiles");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_append(
- m,
+ "PresetAllUnitFiles",
+ &error,
+ &reply,
"sbb",
unit_file_preset_mode_to_string(arg_preset_mode),
arg_runtime,
arg_force);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to execute operation: %s", bus_error_message(&error, r));
return r;
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
@@ -5756,10 +5745,10 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
if (arg_runtime) {
if (access(path, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
+ return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
run, path);
if (path2 && access(path2, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
+ return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
run, path2);
*ret_path = run;
run = NULL;
@@ -5771,7 +5760,6 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
return 0;
}
-
static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
char *tmp_new_path, *ending;
char *tmp_tmp_path;
@@ -5798,12 +5786,14 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
return 0;
}
-static int unit_file_create_copy(const char *unit_name,
- const char *fragment_path,
- const char *user_home,
- const char *user_runtime,
- char **ret_new_path,
- char **ret_tmp_path) {
+static int unit_file_create_copy(
+ const char *unit_name,
+ const char *fragment_path,
+ const char *user_home,
+ const char *user_runtime,
+ char **ret_new_path,
+ char **ret_tmp_path) {
+
char *tmp_new_path;
char *tmp_tmp_path;
int r;
@@ -5859,9 +5849,8 @@ static int run_editor(char **paths) {
if (pid == 0) {
const char **args;
- char **backup_editors = STRV_MAKE("nano", "vim", "vi");
char *editor;
- char **tmp_path, **original_path, **p;
+ char **tmp_path, **original_path, *p;
unsigned i = 1;
size_t argc;
@@ -5890,9 +5879,9 @@ static int run_editor(char **paths) {
execvp(editor, (char* const*) args);
}
- STRV_FOREACH(p, backup_editors) {
- args[0] = *p;
- execvp(*p, (char* const*) args);
+ FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
+ args[0] = p;
+ execvp(p, (char* const*) args);
/* We do not fail if the editor doesn't exist
* because we want to try each one of them before
* failing.
@@ -5903,7 +5892,7 @@ static int run_editor(char **paths) {
}
}
- log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR or $EDITOR or $VISUAL.");
+ log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
_exit(EXIT_FAILURE);
}
@@ -6049,6 +6038,7 @@ static void systemctl_help(void) {
" When shutting down or sleeping, ignore inhibitors\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
+ " --now Start or stop unit in addition to enabling or disabling it\n"
" -q --quiet Suppress output\n"
" --no-block Do not wait until operation finished\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
@@ -6067,6 +6057,7 @@ static void systemctl_help(void) {
" -o --output=STRING Change journal output mode (short, short-iso,\n"
" short-precise, short-monotonic, verbose,\n"
" export, json, json-pretty, json-sse, cat)\n"
+ " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
" --plain Print unit dependencies as a list instead of a tree\n\n"
"Unit Commands:\n"
" list-units [PATTERN...] List loaded units\n"
@@ -6246,6 +6237,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_STATE,
ARG_JOB_MODE,
ARG_PRESET_MODE,
+ ARG_FIRMWARE_SETUP,
+ ARG_NOW,
};
static const struct option options[] = {
@@ -6288,6 +6281,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "state", required_argument, NULL, ARG_STATE },
{ "recursive", no_argument, NULL, 'r' },
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
+ { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
+ { "now", no_argument, NULL, ARG_NOW },
{}
};
@@ -6528,6 +6523,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_plain = true;
break;
+ case ARG_FIRMWARE_SETUP:
+ arg_firmware_setup = true;
+ break;
+
case ARG_STATE: {
const char *word, *state;
size_t size;
@@ -6564,6 +6563,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
+ case ARG_NOW:
+ arg_now = true;
+ break;
+
case '?':
return -EINVAL;
@@ -7207,51 +7210,6 @@ found:
return verb->dispatch(bus, argv + optind);
}
-static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
-
- struct sd_shutdown_command c = {
- .usec = t,
- .mode = mode,
- .dry_run = dry_run,
- .warn_wall = warn,
- };
-
- union sockaddr_union sockaddr = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/shutdownd",
- };
-
- struct iovec iovec[2] = {{
- .iov_base = (char*) &c,
- .iov_len = offsetof(struct sd_shutdown_command, wall_message),
- }};
-
- struct msghdr msghdr = {
- .msg_name = &sockaddr,
- .msg_namelen = offsetof(struct sockaddr_un, sun_path)
- + strlen("/run/systemd/shutdownd"),
- .msg_iov = iovec,
- .msg_iovlen = 1,
- };
-
- _cleanup_close_ int fd;
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (fd < 0)
- return -errno;
-
- if (!isempty(message)) {
- iovec[1].iov_base = (char*) message;
- iovec[1].iov_len = strlen(message);
- msghdr.msg_iovlen++;
- }
-
- if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
- return -errno;
-
- return 0;
-}
-
static int reload_with_fallback(sd_bus *bus) {
if (bus) {
@@ -7359,23 +7317,68 @@ static int halt_main(sd_bus *bus) {
}
if (arg_when > 0) {
- _cleanup_free_ char *m;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_close_unref_ sd_bus *b = NULL;
+ _cleanup_free_ char *m = NULL;
+
+ if (avoid_bus()) {
+ log_error("Unable to perform operation without bus connection.");
+ return -ENOSYS;
+ }
+
+ r = sd_bus_open_system(&b);
+ if (r < 0)
+ return log_error_errno(r, "Unable to open system bus: %m");
m = strv_join(arg_wall, " ");
if (!m)
return log_oom();
- r = send_shutdownd(arg_when,
- arg_action == ACTION_HALT ? 'H' :
- arg_action == ACTION_POWEROFF ? 'P' :
- arg_action == ACTION_KEXEC ? 'K' :
- 'r',
- arg_dry,
- !arg_no_wall,
- m);
+ r = sd_bus_set_property(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "WallMessage",
+ &error,
+ "s", m);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
+ bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+
+ r = sd_bus_set_property(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "EnableWallMessages",
+ &error,
+ "b", !arg_no_wall);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
+ bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+ r = sd_bus_call_method(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ScheduleShutdown",
+ &error,
+ NULL,
+ "st",
+ arg_action == ACTION_HALT ? "halt" :
+ arg_action == ACTION_POWEROFF ? "poweroff" :
+ arg_action == ACTION_KEXEC ? "kexec" :
+ "reboot",
+ arg_when);
if (r < 0)
- log_warning_errno(r, "Failed to talk to shutdownd, proceeding with immediate shutdown: %m");
+ log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
+ bus_error_message(&error, r));
else {
char date[FORMAT_TIMESTAMP_MAX];
@@ -7453,14 +7456,12 @@ int main(int argc, char*argv[]) {
goto finish;
}
- /* Increase max number of open files to 16K if we can, we
- * might needs this when browsing journal files, which might
- * be split up into many files. */
- setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
-
if (!avoid_bus())
r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
+ if (bus)
+ sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
+
/* systemctl_main() will print an error message for the bus
* connection, but only if it needs to */
@@ -7493,8 +7494,19 @@ int main(int argc, char*argv[]) {
break;
case ACTION_CANCEL_SHUTDOWN: {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_close_unref_ sd_bus *b = NULL;
_cleanup_free_ char *m = NULL;
+ if (avoid_bus()) {
+ log_error("Unable to perform operation without bus connection.");
+ return -ENOSYS;
+ }
+
+ r = sd_bus_open_system(&b);
+ if (r < 0)
+ return log_error_errno(r, "Unable to open system bus: %m");
+
if (arg_wall) {
m = strv_join(arg_wall, " ");
if (!m) {
@@ -7503,9 +7515,45 @@ int main(int argc, char*argv[]) {
}
}
- r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
+ r = sd_bus_set_property(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "WallMessage",
+ &error,
+ "s", arg_wall);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
+ bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+
+ r = sd_bus_set_property(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "EnableWallMessages",
+ &error,
+ "b", !arg_no_wall);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
+ bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+
+ r = sd_bus_call_method(
+ b,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CancelScheduledShutdown",
+ &error,
+ NULL, NULL);
if (r < 0)
- log_warning_errno(r, "Failed to talk to shutdownd, shutdown hasn't been cancelled: %m");
+ log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
+ bus_error_message(&error, r));
break;
}
diff --git a/src/systemctl/systemd-sysv-install.SKELETON b/src/systemctl/systemd-sysv-install.SKELETON
new file mode 100755
index 0000000000..a53a3e6221
--- /dev/null
+++ b/src/systemctl/systemd-sysv-install.SKELETON
@@ -0,0 +1,47 @@
+#!/bin/sh
+# This script is called by "systemctl enable/disable" when the given unit is a
+# SysV init.d script. It needs to call the distribution's mechanism for
+# enabling/disabling those, such as chkconfig, update-rc.d, or similar. This
+# can optionally take a --root argument for enabling a SysV init script
+# in a chroot or similar.
+set -e
+
+usage() {
+ echo "Usage: $0 [--root=path] enable|disable|is-enabled <sysv script name>" >&2
+ exit 1
+}
+
+# parse options
+eval set -- "$(getopt -o r: --long root: -- "$@")"
+while true; do
+ case "$1" in
+ -r|--root)
+ ROOT="$2"
+ shift 2 ;;
+ --) shift ; break ;;
+ *) usage ;;
+ esac
+done
+
+NAME="$2"
+[ -n "$NAME" ] || usage
+
+case "$1" in
+ enable)
+ # call the command to enable SysV init script $NAME here
+ # (consider optional $ROOT)
+ echo "IMPLEMENT ME: enabling SysV init.d script $NAME"
+ ;;
+ disable)
+ # call the command to disable SysV init script $NAME here
+ # (consider optional $ROOT)
+ echo "IMPLEMENT ME: disabling SysV init.d script $NAME"
+ ;;
+ is-enabled)
+ # exit with 0 if $NAME is enabled, non-zero if it is disabled
+ # (consider optional $ROOT)
+ echo "IMPLEMENT ME: checking SysV init.d script $NAME"
+ ;;
+ *)
+ usage ;;
+esac
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index ca2d83e0e1..e6e2ecd0b7 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -57,37 +57,40 @@ typedef struct {
enum {
SD_BUS_CREDS_PID = 1ULL << 0,
SD_BUS_CREDS_TID = 1ULL << 1,
- SD_BUS_CREDS_UID = 1ULL << 2,
- SD_BUS_CREDS_EUID = 1ULL << 3,
- SD_BUS_CREDS_SUID = 1ULL << 4,
- SD_BUS_CREDS_FSUID = 1ULL << 5,
- SD_BUS_CREDS_GID = 1ULL << 6,
- SD_BUS_CREDS_EGID = 1ULL << 7,
- SD_BUS_CREDS_SGID = 1ULL << 8,
- SD_BUS_CREDS_FSGID = 1ULL << 9,
- SD_BUS_CREDS_SUPPLEMENTARY_GIDS = 1ULL << 10,
- SD_BUS_CREDS_COMM = 1ULL << 11,
- SD_BUS_CREDS_TID_COMM = 1ULL << 12,
- SD_BUS_CREDS_EXE = 1ULL << 13,
- SD_BUS_CREDS_CMDLINE = 1ULL << 14,
- SD_BUS_CREDS_CGROUP = 1ULL << 15,
- SD_BUS_CREDS_UNIT = 1ULL << 16,
- SD_BUS_CREDS_USER_UNIT = 1ULL << 17,
+ SD_BUS_CREDS_PPID = 1ULL << 2,
+ SD_BUS_CREDS_UID = 1ULL << 3,
+ SD_BUS_CREDS_EUID = 1ULL << 4,
+ SD_BUS_CREDS_SUID = 1ULL << 5,
+ SD_BUS_CREDS_FSUID = 1ULL << 6,
+ SD_BUS_CREDS_GID = 1ULL << 7,
+ SD_BUS_CREDS_EGID = 1ULL << 8,
+ SD_BUS_CREDS_SGID = 1ULL << 9,
+ SD_BUS_CREDS_FSGID = 1ULL << 10,
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS = 1ULL << 11,
+ SD_BUS_CREDS_COMM = 1ULL << 12,
+ SD_BUS_CREDS_TID_COMM = 1ULL << 13,
+ SD_BUS_CREDS_EXE = 1ULL << 14,
+ SD_BUS_CREDS_CMDLINE = 1ULL << 15,
+ SD_BUS_CREDS_CGROUP = 1ULL << 16,
+ SD_BUS_CREDS_UNIT = 1ULL << 17,
SD_BUS_CREDS_SLICE = 1ULL << 18,
- SD_BUS_CREDS_SESSION = 1ULL << 19,
- SD_BUS_CREDS_OWNER_UID = 1ULL << 20,
- SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 21,
- SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 22,
- SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 23,
- SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 24,
- SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 25,
- SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 26,
- SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 27,
- SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 28,
- SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 29,
- SD_BUS_CREDS_DESCRIPTION = 1ULL << 30,
+ SD_BUS_CREDS_USER_UNIT = 1ULL << 19,
+ SD_BUS_CREDS_USER_SLICE = 1ULL << 20,
+ SD_BUS_CREDS_SESSION = 1ULL << 21,
+ SD_BUS_CREDS_OWNER_UID = 1ULL << 22,
+ SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 23,
+ SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 24,
+ SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 25,
+ SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 26,
+ SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 27,
+ SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 28,
+ SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 29,
+ SD_BUS_CREDS_TTY = 1ULL << 30,
+ SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 31,
+ SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32,
+ SD_BUS_CREDS_DESCRIPTION = 1ULL << 33,
SD_BUS_CREDS_AUGMENT = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */
- _SD_BUS_CREDS_ALL = (1ULL << 32) -1,
+ _SD_BUS_CREDS_ALL = (1ULL << 34) -1,
};
enum {
@@ -98,11 +101,11 @@ enum {
/* Callbacks */
-typedef int (*sd_bus_message_handler_t)(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
+typedef int (*sd_bus_message_handler_t)(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
typedef int (*sd_bus_property_get_t) (sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
typedef int (*sd_bus_property_set_t) (sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *ret_error);
typedef int (*sd_bus_object_find_t) (sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error);
-typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *path, void *userdata, char ***ret_nodes, sd_bus_error *ret_error);
+typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *prefix, void *userdata, char ***ret_nodes, sd_bus_error *ret_error);
typedef int (*sd_bus_track_handler_t) (sd_bus_track *track, void *userdata);
#include "sd-bus-protocol.h"
@@ -138,11 +141,13 @@ int sd_bus_set_monitor(sd_bus *bus, int b);
int sd_bus_is_monitor(sd_bus *bus);
int sd_bus_set_description(sd_bus *bus, const char *description);
int sd_bus_get_description(sd_bus *bus, const char **description);
+int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t creds_mask);
+int sd_bus_negotiate_timestamp(sd_bus *bus, int b);
int sd_bus_negotiate_fds(sd_bus *bus, int b);
int sd_bus_can_send(sd_bus *bus, char type);
-int sd_bus_negotiate_timestamp(sd_bus *bus, int b);
-int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t creds_mask);
int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *creds_mask);
+int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b);
+int sd_bus_get_allow_interactive_authorization(sd_bus *bus);
int sd_bus_start(sd_bus *ret);
@@ -298,7 +303,7 @@ int sd_bus_get_property(sd_bus *bus, const char *destination, const char *path,
int sd_bus_get_property_trivial(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, char type, void *ret_ptr);
int sd_bus_get_property_string(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, char **ret); /* free the result! */
int sd_bus_get_property_strv(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, char ***ret); /* free the result! */
-int sd_bus_set_property(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, const char *ret_type, ...);
+int sd_bus_set_property(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, const char *type, ...);
int sd_bus_reply_method_return(sd_bus_message *call, const char *types, ...);
int sd_bus_reply_method_error(sd_bus_message *call, const sd_bus_error *e);
@@ -327,8 +332,10 @@ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t creds_mask
sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c);
sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c);
uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c);
+uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c);
int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid);
+int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid);
int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid);
int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid);
int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid);
@@ -345,8 +352,9 @@ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **exe);
int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline);
int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **cgroup);
int sd_bus_creds_get_unit(sd_bus_creds *c, const char **unit);
-int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit);
int sd_bus_creds_get_slice(sd_bus_creds *c, const char **slice);
+int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **unit);
+int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **slice);
int sd_bus_creds_get_session(sd_bus_creds *c, const char **session);
int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid);
int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability);
@@ -356,6 +364,7 @@ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability);
int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **context);
int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid);
int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *loginuid);
+int sd_bus_creds_get_tty(sd_bus_creds *c, const char **tty);
int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **name);
int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***names);
int sd_bus_creds_get_description(sd_bus_creds *c, const char **name);
diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h
index b878b4d8a6..861dc8f1f4 100644
--- a/src/systemd/sd-daemon.h
+++ b/src/systemd/sd-daemon.h
@@ -168,7 +168,7 @@ int sd_is_mq(int fd, const char *path);
value daemons should send is "READY=1".
STATUS=... Passes a single-line status string back to systemd
- that describes the daemon state. This is free-from
+ that describes the daemon state. This is free-form
and can be used for various purposes: general state
feedback, fsck-like programs could pass completion
percentages and failing programs could pass a human
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
new file mode 100644
index 0000000000..38cb2a1102
--- /dev/null
+++ b/src/systemd/sd-device.h
@@ -0,0 +1,99 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosddevicehfoo
+#define foosddevicehfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2014-2015 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_device sd_device;
+typedef struct sd_device_enumerator sd_device_enumerator;
+
+/* device */
+
+sd_device *sd_device_ref(sd_device *device);
+sd_device *sd_device_unref(sd_device *device);
+
+int sd_device_new_from_syspath(sd_device **ret, const char *syspath);
+int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum);
+int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname);
+int sd_device_new_from_device_id(sd_device **ret, const char *id);
+
+int sd_device_get_parent(sd_device *child, sd_device **ret);
+int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret);
+
+int sd_device_get_syspath(sd_device *device, const char **ret);
+int sd_device_get_subsystem(sd_device *device, const char **ret);
+int sd_device_get_devtype(sd_device *device, const char **ret);
+int sd_device_get_devnum(sd_device *device, dev_t *devnum);
+int sd_device_get_ifindex(sd_device *device, int *ifindex);
+int sd_device_get_driver(sd_device *device, const char **ret);
+int sd_device_get_devpath(sd_device *device, const char **ret);
+int sd_device_get_devname(sd_device *device, const char **ret);
+int sd_device_get_sysname(sd_device *device, const char **ret);
+int sd_device_get_sysnum(sd_device *device, const char **ret);
+
+int sd_device_get_is_initialized(sd_device *device, int *initialized);
+int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec);
+
+const char *sd_device_get_tag_first(sd_device *device);
+const char *sd_device_get_tag_next(sd_device *device);
+const char *sd_device_get_devlink_first(sd_device *device);
+const char *sd_device_get_devlink_next(sd_device *device);
+const char *sd_device_get_property_first(sd_device *device, const char **value);
+const char *sd_device_get_property_next(sd_device *device, const char **value);
+const char *sd_device_get_sysattr_first(sd_device *device);
+const char *sd_device_get_sysattr_next(sd_device *device);
+
+int sd_device_has_tag(sd_device *device, const char *tag);
+int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
+int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
+
+int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *value);
+
+/* device enumerator */
+
+int sd_device_enumerator_new(sd_device_enumerator **ret);
+sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator);
+sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator);
+
+sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator);
+
+int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match);
+int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match);
+int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value);
+int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname);
+int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
+int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
+int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index 25a10f99ab..565de5495a 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -51,8 +51,8 @@ enum {
};
enum {
- SD_EVENT_PASSIVE,
- SD_EVENT_PREPARED,
+ SD_EVENT_INITIAL,
+ SD_EVENT_ARMED,
SD_EVENT_PENDING,
SD_EVENT_RUNNING,
SD_EVENT_EXITING,
diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h
index 48fd87671b..9f445278bb 100644
--- a/src/systemd/sd-id128.h
+++ b/src/systemd/sd-id128.h
@@ -106,6 +106,10 @@ _sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
return memcmp(&a, &b, 16) == 0;
}
+_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) {
+ return a.qwords[0] == 0 && a.qwords[1] == 0;
+}
+
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
_SD_END_DECLARATIONS;
diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h
index 24c8595064..9260396d5d 100644
--- a/src/systemd/sd-login.h
+++ b/src/systemd/sd-login.h
@@ -62,22 +62,25 @@ int sd_pid_get_session(pid_t pid, char **session);
* return an error for system processes. */
int sd_pid_get_owner_uid(pid_t pid, uid_t *uid);
-/* Get systemd unit (i.e. service) name from PID, for system
+/* Get systemd non-slice unit (i.e. service) name from PID, for system
* services. This will return an error for non-service processes. */
int sd_pid_get_unit(pid_t pid, char **unit);
-/* Get systemd unit (i.e. service) name from PID, for user
+/* Get systemd non-slice unit (i.e. service) name from PID, for user
* services. This will return an error for non-user-service
* processes. */
int sd_pid_get_user_unit(pid_t pid, char **unit);
+/* Get slice name from PID. */
+int sd_pid_get_slice(pid_t pid, char **slice);
+
+/* Get user slice name from PID. */
+int sd_pid_get_user_slice(pid_t pid, char **slice);
+
/* Get machine name from PID, for processes assigned to a VM or
* container. This will return an error for non-machine processes. */
int sd_pid_get_machine_name(pid_t pid, char **machine);
-/* Get slice name from PID. */
-int sd_pid_get_slice(pid_t pid, char **slice);
-
/* Similar to sd_pid_get_session(), but retrieves data about peer of
* connected AF_UNIX socket */
int sd_peer_get_session(int fd, char **session);
@@ -94,14 +97,18 @@ int sd_peer_get_unit(int fd, char **unit);
* connected AF_UNIX socket */
int sd_peer_get_user_unit(int fd, char **unit);
-/* Similar to sd_pid_get_machine_name(), but retrieves data about peer
- * of connected AF_UNIX socket */
-int sd_peer_get_machine_name(int fd, char **machine);
-
/* Similar to sd_pid_get_slice(), but retrieves data about peer of
* connected AF_UNIX socket */
int sd_peer_get_slice(int fd, char **slice);
+/* Similar to sd_pid_get_user_slice(), but retrieves data about peer of
+ * connected AF_UNIX socket */
+int sd_peer_get_user_slice(int fd, char **slice);
+
+/* Similar to sd_pid_get_machine_name(), but retrieves data about peer
+ * of connected AF_UNIX socket */
+int sd_peer_get_machine_name(int fd, char **machine);
+
/* Get state from UID. Possible states: offline, lingering, online, active, closing */
int sd_uid_get_state(uid_t uid, char **state);
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index a8379e098c..8aedaec6d1 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -81,7 +81,7 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_SUSPEND_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,72)
#define SD_MESSAGE_HIBERNATE_KEY SD_ID128_MAKE(b7,2e,a4,a2,88,15,45,a0,b5,0e,20,0e,55,b9,b0,73)
-#define SD_MESSAGE_CONFIG_ERROR SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
+#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
#define SD_MESSAGE_BOOTCHART SD_ID128_MAKE(9f,26,aa,56,2c,f4,40,c2,b1,6c,77,3d,04,79,b5,18)
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 027730d11d..4d96c867d9 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -116,6 +116,12 @@ int sd_network_link_get_lldp(int ifindex, char **lldp);
/* Get the DNS domain names for a given link. */
int sd_network_link_get_domains(int ifindex, char ***domains);
+/* Get the CARRIERS to which current link is bound to. */
+int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers);
+
+/* Get the CARRIERS that are bound to current link. */
+int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers);
+
/* Returns whether or not domains that don't match any link should be resolved
* on this link. 1 for yes, 0 for no and negative value for error */
int sd_network_link_get_wildcard_domain(int ifindex);
diff --git a/src/systemd/sd-shutdown.h b/src/systemd/sd-shutdown.h
deleted file mode 100644
index 9ff377f4e4..0000000000
--- a/src/systemd/sd-shutdown.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdshutdownhfoo
-#define foosdshutdownhfoo
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/* Interface for scheduling and cancelling timed shutdowns. */
-
-#include <inttypes.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _sd_packed_
-# define _sd_packed_ __attribute__((packed))
-#endif
-
-typedef enum sd_shutdown_mode {
- SD_SHUTDOWN_NONE = 0,
- SD_SHUTDOWN_REBOOT = 'r',
- SD_SHUTDOWN_POWEROFF = 'P',
- SD_SHUTDOWN_HALT = 'H',
- SD_SHUTDOWN_KEXEC = 'K'
-} sd_shutdown_mode_t;
-
-/* Calculate the size of the message as "offsetof(struct
- * sd_shutdown_command, wall_message) +
- * strlen(command.wall_message)" */
-struct sd_shutdown_command {
- /* Microseconds after the epoch 1970 UTC */
- uint64_t usec;
-
- /* H, P, r, i.e. the switches usually passed to
- * /usr/bin/shutdown to select whether to halt, power-off or
- * reboot the machine */
- sd_shutdown_mode_t mode:8;
-
- /* If non-zero, don't actually shut down, just pretend */
- unsigned dry_run:1;
-
- /* If non-zero, send our wall message */
- unsigned warn_wall:1;
-
- /* The wall message to send around. Leave empty for the
- * default wall message */
- char wall_message[];
-} _sd_packed_;
-
-/* The scheme is very simple:
- *
- * To schedule a shutdown, simply fill in and send a single
- * AF_UNIX/SOCK_DGRAM datagram with the structure above suffixed with
- * the wall message to the socket /run/systemd/shutdownd (leave an
- * empty wall message for the default shutdown message). To calculate
- * the size of the message, use "offsetof(struct sd_shutdown_command,
- * wall_message) + strlen(command.wall_message)".
- *
- * To cancel a shutdown, do the same, but send a fully zeroed-out
- * structure.
- *
- * To be notified about scheduled shutdowns, create an inotify watch
- * on /run/shutdown/. Whenever a file called "scheduled" appears, a
- * shutdown is scheduled. If it is removed, it is canceled. If it is
- * replaced, the scheduled shutdown has been changed. The file contains
- * a simple, environment-like block that contains information about
- * the scheduled shutdown:
- *
- * USEC=
- * encodes the time for the shutdown in usecs since the epoch UTC,
- * formatted as a numeric string.
- *
- * WARN_WALL=
- * is 1 if a wall message shall be sent
- *
- * DRY_RUN=
- * is 1 if a dry-run shutdown is scheduled
- *
- * MODE=
- * is the shutdown mode, one of "poweroff", "reboot", "halt", "kexec"
- *
- * WALL_MESSAGE=
- * is the wall message to use, with all special characters escaped in C-style.
- *
- * Note that some fields might be missing if they do not apply.
- *
- * Note that the file is first written to a temporary file and then
- * renamed, in order to provide atomic properties for readers: if the
- * file exists under the name "scheduled", it is guaranteed to be fully
- * written. A reader should ignore all files in that directory by any
- * other name.
- *
- * Scheduled shutdowns are only accepted from privileged processes,
- * but anyone may watch the directory and the file in it.
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index e47bcb4dca..d7ba482834 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <shadow.h>
@@ -36,10 +35,10 @@
#include "conf-files.h"
#include "copy.h"
#include "utf8.h"
-#include "label.h"
#include "fileio-label.h"
#include "uid-range.h"
#include "selinux-util.h"
+#include "formats-util.h"
typedef enum ItemType {
ADD_USER = 'u',
@@ -81,15 +80,13 @@ static uid_t search_uid = UID_INVALID;
static UidRange *uid_range = NULL;
static unsigned n_uid_range = 0;
-#define fix_root(x) (arg_root ? strjoina(arg_root, x) : x)
-
static int load_user_database(void) {
_cleanup_fclose_ FILE *f = NULL;
const char *passwd_path;
struct passwd *pw;
int r;
- passwd_path = fix_root("/etc/passwd");
+ passwd_path = prefix_roota(arg_root, "/etc/passwd");
f = fopen(passwd_path, "re");
if (!f)
return errno == ENOENT ? 0 : -errno;
@@ -141,7 +138,7 @@ static int load_group_database(void) {
struct group *gr;
int r;
- group_path = fix_root("/etc/group");
+ group_path = prefix_roota(arg_root, "/etc/group");
f = fopen(group_path, "re");
if (!f)
return errno == ENOENT ? 0 : -errno;
@@ -370,7 +367,7 @@ static int write_files(void) {
_cleanup_fclose_ FILE *original = NULL;
/* First we update the actual group list file */
- group_path = fix_root("/etc/group");
+ group_path = prefix_roota(arg_root, "/etc/group");
r = fopen_temporary_label("/etc/group", group_path, &group, &group_tmp);
if (r < 0)
goto finish;
@@ -449,7 +446,7 @@ static int write_files(void) {
}
/* OK, now also update the shadow file for the group list */
- gshadow_path = fix_root("/etc/gshadow");
+ gshadow_path = prefix_roota(arg_root, "/etc/gshadow");
r = fopen_temporary_label("/etc/gshadow", gshadow_path, &gshadow, &gshadow_tmp);
if (r < 0)
goto finish;
@@ -515,7 +512,7 @@ static int write_files(void) {
long lstchg;
/* First we update the user database itself */
- passwd_path = fix_root("/etc/passwd");
+ passwd_path = prefix_roota(arg_root, "/etc/passwd");
r = fopen_temporary_label("/etc/passwd", passwd_path, &passwd, &passwd_tmp);
if (r < 0)
goto finish;
@@ -600,11 +597,13 @@ static int write_files(void) {
}
/* The we update the shadow database */
- shadow_path = fix_root("/etc/shadow");
+ shadow_path = prefix_roota(arg_root, "/etc/shadow");
r = fopen_temporary_label("/etc/shadow", shadow_path, &shadow, &shadow_tmp);
if (r < 0)
goto finish;
+ lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
+
original = fopen(shadow_path, "re");
if (original) {
struct spwd *sp;
@@ -618,8 +617,13 @@ static int write_files(void) {
i = hashmap_get(users, sp->sp_namp);
if (i && i->todo_user) {
- r = -EEXIST;
- goto finish;
+ /* we will update the existing entry */
+ sp->sp_lstchg = lstchg;
+
+ /* only the /etc/shadow stage is left, so we can
+ * safely remove the item from the todo set */
+ i->todo_user = false;
+ hashmap_remove(todo_uids, UID_TO_PTR(i->uid));
}
errno = 0;
@@ -642,7 +646,6 @@ static int write_files(void) {
goto finish;
}
- lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
HASHMAP_FOREACH(i, todo_uids, iterator) {
struct spwd n = {
.sp_namp = i->name,
@@ -797,7 +800,7 @@ static int uid_is_ok(uid_t uid, const char *name) {
static int root_stat(const char *p, struct stat *st) {
const char *fix;
- fix = fix_root(p);
+ fix = prefix_roota(arg_root, p);
if (stat(fix, st) < 0)
return -errno;
@@ -879,7 +882,6 @@ static int add_user(Item *i) {
if (!arg_root) {
struct passwd *p;
- struct spwd *sp;
/* Also check NSS */
errno = 0;
@@ -895,16 +897,6 @@ static int add_user(Item *i) {
}
if (!IN_SET(errno, 0, ENOENT))
return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name);
-
- /* And shadow too, just to be sure */
- errno = 0;
- sp = getspnam(i->name);
- if (sp) {
- log_error("User %s already exists in shadow database, but not in user database.", i->name);
- return -EBADMSG;
- }
- if (!IN_SET(errno, 0, ENOENT))
- return log_error_errno(errno, "Failed to check if user %s already exists in shadow database: %m", i->name);
}
/* Try to use the suggested numeric uid */
@@ -1391,7 +1383,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
/* Parse columns */
p = buffer;
- r = unquote_many_words(&p, &action, &name, &id, &description, &home, NULL);
+ r = unquote_many_words(&p, 0, &action, &name, &id, &description, &home, NULL);
if (r < 0) {
log_error("[%s:%u] Syntax error.", fname, line);
return r;
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 6e39b449eb..9ae518ac4a 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -31,14 +31,11 @@
#include "path-util.h"
#include "path-lookup.h"
#include "log.h"
-#include "unit.h"
#include "unit-name.h"
#include "special.h"
-#include "exit-status.h"
-#include "def.h"
-#include "env-util.h"
-#include "fileio.h"
#include "hashmap.h"
+#include "set.h"
+#include "install.h"
typedef enum RunlevelType {
RUNLEVEL_UP,
@@ -51,11 +48,11 @@ static const struct {
const RunlevelType type;
} rcnd_table[] = {
/* Standard SysV runlevels for start-up */
- { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
- { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
- { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
- { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
- { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
+ { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
+ { "rc2.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
+ { "rc3.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
+ { "rc4.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
+ { "rc5.d", SPECIAL_GRAPHICAL_TARGET, RUNLEVEL_UP },
/* Standard SysV runlevels for shutdown */
{ "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN },
@@ -68,6 +65,8 @@ static const struct {
UP must be read before DOWN */
};
+const char *arg_dest = "/tmp";
+
typedef struct SysvStub {
char *name;
char *path;
@@ -83,7 +82,29 @@ typedef struct SysvStub {
bool reload;
} SysvStub;
-const char *arg_dest = "/tmp";
+static void free_sysvstub(SysvStub *s) {
+ free(s->name);
+ free(s->path);
+ free(s->description);
+ free(s->pid_file);
+ strv_free(s->before);
+ strv_free(s->after);
+ strv_free(s->wants);
+ strv_free(s->wanted_by);
+ strv_free(s->conflicts);
+ free(s);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub);
+
+static void free_sysvstub_hashmapp(Hashmap **h) {
+ SysvStub *stub;
+
+ while ((stub = hashmap_steal_first(*h)))
+ free_sysvstub(stub);
+
+ hashmap_free(*h);
+}
static int add_symlink(const char *service, const char *where) {
_cleanup_free_ char *from = NULL, *to = NULL;
@@ -136,37 +157,23 @@ static int add_alias(const char *service, const char *alias) {
static int generate_unit_file(SysvStub *s) {
char **p;
_cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *unit = NULL;
- _cleanup_free_ char *before = NULL;
- _cleanup_free_ char *after = NULL;
- _cleanup_free_ char *wants = NULL;
- _cleanup_free_ char *conflicts = NULL;
+ _cleanup_free_ char *unit = NULL,
+ *before = NULL, *after = NULL,
+ *wants = NULL, *conflicts = NULL;
int r;
before = strv_join(s->before, " ");
- if (!before)
- return log_oom();
-
after = strv_join(s->after, " ");
- if (!after)
- return log_oom();
-
wants = strv_join(s->wants, " ");
- if (!wants)
- return log_oom();
-
conflicts = strv_join(s->conflicts, " ");
- if (!conflicts)
- return log_oom();
-
unit = strjoin(arg_dest, "/", s->name, NULL);
- if (!unit)
+ if (!before || !after || !wants || !conflicts || !unit)
return log_oom();
/* We might already have a symlink with the same name from a Provides:,
* or from backup files like /etc/init.d/foo.bak. Real scripts always win,
* so remove an existing link */
- if (is_symlink(unit)) {
+ if (is_symlink(unit) > 0) {
log_warning("Overwriting existing symlink %s with real service", unit);
(void) unlink(unit);
}
@@ -217,7 +224,7 @@ static int generate_unit_file(SysvStub *s) {
STRV_FOREACH(p, s->wanted_by) {
r = add_symlink(s->name, *p);
if (r < 0)
- log_unit_error_errno(s->name, r, "Failed to create 'Wants' symlink to %s: %m", *p);
+ log_error_errno(r, "Failed to create 'Wants' symlink to %s: %m", *p);
}
return 0;
@@ -304,11 +311,13 @@ static int sysv_translate_facility(const char *name, const char *filename, char
* out whether something is a target or a service alias. */
if (*name == '$') {
- if (!unit_prefix_is_valid(n))
- return -EINVAL;
+ int k;
/* Facilities starting with $ are most likely targets */
- r = unit_name_build(n, NULL, ".target");
+ k = unit_name_build(n, NULL, ".target", &r);
+ if (k < 0)
+ return k;
+
} else if (streq_ptr(n, filename))
/* Names equaling the file name of the services are redundant */
return 0;
@@ -324,6 +333,93 @@ finish:
return 1;
}
+static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) {
+ const char *word, *state_;
+ size_t z;
+ int r;
+
+ FOREACH_WORD_QUOTED(word, z, text, state_) {
+ _cleanup_free_ char *n = NULL, *m = NULL;
+
+ n = strndup(word, z);
+ if (!n)
+ return log_oom();
+
+ r = sysv_translate_facility(n, basename(s->path), &m);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ continue;
+
+ if (unit_name_to_type(m) == UNIT_SERVICE) {
+ log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
+ r = add_alias(s->name, m);
+ if (r < 0)
+ log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m);
+ } else {
+ /* NB: SysV targets which are provided by a
+ * service are pulled in by the services, as
+ * an indication that the generic service is
+ * now available. This is strictly one-way.
+ * The targets do NOT pull in SysV services! */
+ r = strv_extend(&s->before, m);
+ if (r < 0)
+ return log_oom();
+ r = strv_extend(&s->wants, m);
+ if (r < 0)
+ return log_oom();
+ if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) {
+ r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
+ if (r < 0)
+ return log_oom();
+ }
+ }
+ }
+ if (!isempty(state_))
+ log_error("[%s:%u] Trailing garbage in Provides, ignoring.", s->path, line);
+ return 0;
+}
+
+static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) {
+ const char *word, *state_;
+ size_t z;
+ int r;
+
+ FOREACH_WORD_QUOTED(word, z, text, state_) {
+ _cleanup_free_ char *n = NULL, *m = NULL;
+ bool is_before;
+
+ n = strndup(word, z);
+ if (!n)
+ return log_oom();
+
+ r = sysv_translate_facility(n, basename(s->path), &m);
+ if (r < 0) {
+ log_warning_errno(r, "[%s:%u] Failed to translate LSB dependency %s, ignoring: %m", s->path, line, n);
+ continue;
+ }
+ if (r == 0)
+ continue;
+
+ is_before = startswith_no_case(full_text, "X-Start-Before:");
+
+ if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET) && !is_before) {
+ /* the network-online target is special, as it needs to be actively pulled in */
+ r = strv_extend(&s->after, m);
+ if (r < 0)
+ return log_oom();
+ r = strv_extend(&s->wants, m);
+ } else
+ r = strv_extend(is_before ? &s->before : &s->after, m);
+
+ if (r < 0)
+ return log_oom();
+ }
+ if (!isempty(state_))
+ log_warning("[%s:%u] Trailing garbage in %*s, ignoring.", s->path, line, (int)(strchr(full_text, ':') - full_text), full_text);
+ return 0;
+}
+
static int load_sysv(SysvStub *s) {
_cleanup_fclose_ FILE *f;
unsigned line = 0;
@@ -354,10 +450,7 @@ static int load_sysv(SysvStub *s) {
if (feof(f))
break;
- log_unit_error(s->name,
- "Failed to read configuration file '%s': %m",
- s->path);
- return -errno;
+ return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
}
line++;
@@ -429,9 +522,7 @@ static int load_sysv(SysvStub *s) {
fn = strstrip(t+8);
if (!path_is_absolute(fn)) {
- log_unit_error(s->name,
- "[%s:%u] PID file not absolute. Ignoring.",
- s->path, line);
+ log_error("[%s:%u] PID file not absolute. Ignoring.", s->path, line);
continue;
}
@@ -475,126 +566,22 @@ static int load_sysv(SysvStub *s) {
} else if (state == LSB || state == LSB_DESCRIPTION) {
if (startswith_no_case(t, "Provides:")) {
- const char *word, *state_;
- size_t z;
-
state = LSB;
- FOREACH_WORD_QUOTED(word, z, t+9, state_) {
- _cleanup_free_ char *n = NULL, *m = NULL;
-
- n = strndup(word, z);
- if (!n)
- return -ENOMEM;
-
- r = sysv_translate_facility(n, basename(s->path), &m);
- if (r < 0)
- return r;
- if (r == 0)
- continue;
-
- if (unit_name_to_type(m) == UNIT_SERVICE) {
- log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
- r = add_alias(s->name, m);
- } else {
- /* NB: SysV targets
- * which are provided
- * by a service are
- * pulled in by the
- * services, as an
- * indication that the
- * generic service is
- * now available. This
- * is strictly
- * one-way. The
- * targets do NOT pull
- * in the SysV
- * services! */
- r = strv_extend(&s->before, m);
- if (r < 0)
- return log_oom();
- r = strv_extend(&s->wants, m);
- if (r < 0)
- return log_oom();
- if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) {
- r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
- if (r < 0)
- return log_oom();
- }
- }
-
- if (r < 0)
- log_unit_error(s->name,
- "[%s:%u] Failed to add LSB Provides name %s, ignoring: %s",
- s->path, line, m, strerror(-r));
- }
- if (!isempty(state_))
- log_unit_error(s->name,
- "[%s:%u] Trailing garbage in Provides, ignoring.",
- s->path, line);
-
+ r = handle_provides(s, line, t, t + 9);
+ if (r < 0)
+ return r;
} else if (startswith_no_case(t, "Required-Start:") ||
startswith_no_case(t, "Should-Start:") ||
startswith_no_case(t, "X-Start-Before:") ||
startswith_no_case(t, "X-Start-After:")) {
- const char *word, *state_;
- size_t z;
state = LSB;
- FOREACH_WORD_QUOTED(word, z, strchr(t, ':')+1, state_) {
- _cleanup_free_ char *n = NULL, *m = NULL;
- bool is_before;
+ r = handle_dependencies(s, line, t, strchr(t, ':') + 1);
+ if (r < 0)
+ return r;
- n = strndup(word, z);
- if (!n)
- return -ENOMEM;
-
- r = sysv_translate_facility(n, basename(s->path), &m);
- if (r < 0) {
- log_unit_error(s->name,
- "[%s:%u] Failed to translate LSB dependency %s, ignoring: %s",
- s->path, line, n, strerror(-r));
- continue;
- }
-
- if (r == 0)
- continue;
-
- is_before = startswith_no_case(t, "X-Start-Before:");
-
- if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET) && !is_before) {
- /* the network-online target is special, as it needs to be actively pulled in */
- r = strv_extend(&s->after, m);
- if (r < 0)
- return log_oom();
- r = strv_extend(&s->wants, m);
- if (r < 0)
- return log_oom();
- }
- else {
- if (is_before) {
- r = strv_extend(&s->before, m);
- if (r < 0)
- return log_oom();
- }
- else {
- r = strv_extend(&s->after, m);
- if (r < 0)
- return log_oom();
- }
- }
-
- if (r < 0)
- log_unit_error(s->name,
- "[%s:%u] Failed to add dependency on %s, ignoring: %s",
- s->path, line, m, strerror(-r));
- }
- if (!isempty(state_))
- log_unit_error(s->name,
- "[%s:%u] Trailing garbage in %*s, ignoring.",
- s->path, line,
- (int)(strchr(t, ':') - t), t);
} else if (startswith_no_case(t, "Description:")) {
char *d, *j;
@@ -723,10 +710,10 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
return 0;
}
-static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
+static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
char **path;
- STRV_FOREACH(path, lp.sysvinit_path) {
+ STRV_FOREACH(path, lp->sysvinit_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@@ -739,7 +726,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
while ((de = readdir(d))) {
_cleanup_free_ char *fpath = NULL, *name = NULL;
- _cleanup_free_ SysvStub *service = NULL;
+ _cleanup_(free_sysvstubp) SysvStub *service = NULL;
struct stat st;
int r;
@@ -768,7 +755,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
if (!fpath)
return log_oom();
- if (unit_file_get_state(UNIT_FILE_SYSTEM, NULL, name) >= 0) {
+ if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) {
log_debug("Native unit for %s already exists, skipping", name);
continue;
}
@@ -793,18 +780,18 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
return 0;
}
-static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) {
+static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
char **p;
unsigned i;
_cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *path = NULL, *fpath = NULL, *name = NULL;
+ _cleanup_free_ char *path = NULL, *fpath = NULL;
SysvStub *service;
Iterator j;
Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
_cleanup_set_free_ Set *shutdown_services = NULL;
int r = 0;
- STRV_FOREACH(p, lp.sysvrcnd_path)
+ STRV_FOREACH(p, lp->sysvrcnd_path)
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
struct dirent *de;
@@ -825,6 +812,8 @@ static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) {
}
while ((de = readdir(d))) {
+ _cleanup_free_ char *name = NULL;
+
int a, b;
if (hidden_file(de->d_name))
@@ -923,8 +912,8 @@ finish:
int main(int argc, char *argv[]) {
int r, q;
- LookupPaths lp;
- Hashmap *all_services;
+ _cleanup_lookup_paths_free_ LookupPaths lp = {};
+ _cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL;
SysvStub *service;
Iterator j;
@@ -942,7 +931,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- r = lookup_paths_init(&lp, SYSTEMD_SYSTEM, true, NULL, NULL, NULL, NULL);
+ r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
if (r < 0) {
log_error("Failed to find lookup paths.");
return EXIT_FAILURE;
@@ -954,13 +943,13 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
- r = enumerate_sysv(lp, all_services);
+ r = enumerate_sysv(&lp, all_services);
if (r < 0) {
log_error("Failed to generate units for all init scripts.");
return EXIT_FAILURE;
}
- r = set_dependencies_from_rcnd(lp, all_services);
+ r = set_dependencies_from_rcnd(&lp, all_services);
if (r < 0) {
log_error("Failed to read runlevels from rcnd links.");
return EXIT_FAILURE;
diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c
index cb75f7314d..2d109a30e7 100644
--- a/src/test/test-barrier.c
+++ b/src/test/test-barrier.c
@@ -28,15 +28,12 @@
* increase it at the slightly cost of lengthen test-duration on other machines.
*/
-#include <errno.h>
#include <stdio.h>
-#include <string.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
#include "barrier.h"
-#include "def.h"
#include "util.h"
/* 20ms to test deadlocks; All timings use multiples of this constant as
diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c
index 150a32ad6f..838ffcba3d 100644
--- a/src/test/test-btrfs.c
+++ b/src/test/test-btrfs.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <fcntl.h>
#include "log.h"
@@ -28,8 +27,7 @@
#include "btrfs-util.h"
int main(int argc, char *argv[]) {
- int r;
- int fd;
+ int r, fd;
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
@@ -51,9 +49,9 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to get quota info: %m");
else {
- log_info("referred: %s", strna(format_bytes(bs, sizeof(bs), quota.referred)));
+ log_info("referenced: %s", strna(format_bytes(bs, sizeof(bs), quota.referenced)));
log_info("exclusive: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive)));
- log_info("referred_max: %s", strna(format_bytes(bs, sizeof(bs), quota.referred_max)));
+ log_info("referenced_max: %s", strna(format_bytes(bs, sizeof(bs), quota.referenced_max)));
log_info("exclusive_max: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive_max)));
}
@@ -74,33 +72,78 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to write file: %m");
- r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", false, false);
+ r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", 0);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", true, false);
+ r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_remove("/xxxtest");
+ r = btrfs_subvol_remove("/xxxtest", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxtest2");
+ r = btrfs_subvol_remove("/xxxtest2", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxtest3");
+ r = btrfs_subvol_remove("/xxxtest3", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_snapshot("/etc", "/etc2", true, true);
+ r = btrfs_subvol_snapshot("/etc", "/etc2", BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY);
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_remove("/etc2");
+ r = btrfs_subvol_remove("/etc2", false);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
+ r = btrfs_subvol_make("/xxxrectest");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/xxxrectest2");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/xxxrectest3");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/xxxrectest3/sub");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ if (mkdir("/xxxrectest/dir", 0755) < 0)
+ log_error_errno(errno, "Failed to make directory: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ if (mkdir("/xxxrectest/dir/xxxrectest4/dir", 0755) < 0)
+ log_error_errno(errno, "Failed to make directory: %m");
+
+ r = btrfs_subvol_make("/xxxrectest/dir/xxxrectest4/dir/xxxrectest5");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ if (mkdir("/xxxrectest/mnt", 0755) < 0)
+ log_error_errno(errno, "Failed to make directory: %m");
+
+ r = btrfs_subvol_snapshot("/xxxrectest", "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE);
+ if (r < 0)
+ log_error_errno(r, "Failed to snapshot subvolume: %m");
+
+ r = btrfs_subvol_remove("/xxxrectest", true);
+ if (r < 0)
+ log_error_errno(r, "Failed to recursively remove subvolume: %m");
+
+ r = btrfs_subvol_remove("/xxxrectest2", true);
+ if (r < 0)
+ log_error_errno(r, "Failed to recursively remove subvolume: %m");
+
return 0;
}
diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c
index 632d62ff8f..43a2d35b80 100644
--- a/src/test/test-cap-list.c
+++ b/src/test/test-cap-list.c
@@ -20,7 +20,6 @@
***/
#include "util.h"
-#include "log.h"
#include "fileio.h"
#include "cap-list.h"
#include "capability.h"
diff --git a/src/test/test-capability.c b/src/test/test-capability.c
index 43769923b0..f47452ce72 100644
--- a/src/test/test-capability.c
+++ b/src/test/test-capability.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <sys/wait.h>
#include <sys/capability.h>
#include <sys/socket.h>
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index 9e9de23e0e..289dddbaac 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -20,14 +20,9 @@
***/
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <pwd.h>
#include "manager.h"
#include "unit.h"
-#include "util.h"
#include "macro.h"
#include "test-helper.h"
@@ -40,7 +35,7 @@ static int test_cgroup_mask(void) {
/* Prepare the manager. */
assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(SYSTEMD_USER, true, &m);
+ r = manager_new(MANAGER_USER, true, &m);
if (r == -EPERM || r == -EACCES) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 67eeeb56b7..4a89f64518 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -19,11 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include "util.h"
#include "cgroup-util.h"
#include "test-helper.h"
+#include "formats-util.h"
+#include "process-util.h"
static void check_p_d_u(const char *path, int code, const char *result) {
_cleanup_free_ char *unit = NULL;
@@ -39,11 +40,11 @@ static void test_path_decode_unit(void) {
check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
- check_p_d_u("getty@.service/", -EINVAL, NULL);
- check_p_d_u("getty@.service", -EINVAL, NULL);
+ check_p_d_u("getty@.service/", -ENXIO, NULL);
+ check_p_d_u("getty@.service", -ENXIO, NULL);
check_p_d_u("getty.service", 0, "getty.service");
- check_p_d_u("getty", -EINVAL, NULL);
- check_p_d_u("getty/waldo", -EINVAL, NULL);
+ check_p_d_u("getty", -ENXIO, NULL);
+ check_p_d_u("getty/waldo", -ENXIO, NULL);
check_p_d_u("_cpu.service", 0, "cpu.service");
}
@@ -63,12 +64,12 @@ static void test_path_get_unit(void) {
check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
- check_p_g_u("sadfdsafsda", -EINVAL, NULL);
- check_p_g_u("/system.slice/getty####@tty6.service/xxx", -EINVAL, NULL);
+ check_p_g_u("sadfdsafsda", -ENXIO, NULL);
+ check_p_g_u("/system.slice/getty####@tty6.service/xxx", -ENXIO, NULL);
check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
- check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -EINVAL, NULL);
+ check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
}
static void check_p_g_u_u(const char *path, int code, const char *result) {
@@ -86,15 +87,15 @@ static void test_path_get_user_unit(void) {
check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
- check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -EINVAL, NULL);
+ check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -ENXIO, NULL);
check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
- check_p_g_u_u("/meh.service", -ENOENT, NULL);
+ check_p_g_u_u("/meh.service", -ENXIO, NULL);
check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
- check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENOENT, NULL);
+ check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
}
static void check_p_g_s(const char *path, int code, const char *result) {
@@ -107,8 +108,8 @@ static void check_p_g_s(const char *path, int code, const char *result) {
static void test_path_get_session(void) {
check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
check_p_g_s("/session-3.scope", 0, "3");
- check_p_g_s("/session-.scope", -ENOENT, NULL);
- check_p_g_s("", -ENOENT, NULL);
+ check_p_g_s("/session-.scope", -ENXIO, NULL);
+ check_p_g_s("", -ENXIO, NULL);
}
static void check_p_g_o_u(const char *path, int code, uid_t result) {
@@ -121,7 +122,48 @@ static void check_p_g_o_u(const char *path, int code, uid_t result) {
static void test_path_get_owner_uid(void) {
check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
- check_p_g_o_u("", -ENOENT, 0);
+ check_p_g_o_u("", -ENXIO, 0);
+}
+
+static void check_p_g_slice(const char *path, int code, const char *result) {
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(cg_path_get_slice(path, &s) == code);
+ assert_se(streq_ptr(s, result));
+}
+
+static void test_path_get_slice(void) {
+ check_p_g_slice("/user.slice", 0, "user.slice");
+ check_p_g_slice("/foobar", 0, "-.slice");
+ check_p_g_slice("/user.slice/user-waldo.slice", 0, "user-waldo.slice");
+ check_p_g_slice("", 0, "-.slice");
+ check_p_g_slice("foobar", 0, "-.slice");
+ check_p_g_slice("foobar.slice", 0, "foobar.slice");
+ check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
+}
+
+static void check_p_g_u_slice(const char *path, int code, const char *result) {
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(cg_path_get_user_slice(path, &s) == code);
+ assert_se(streq_ptr(s, result));
+}
+
+static void test_path_get_user_slice(void) {
+ check_p_g_u_slice("/user.slice", -ENXIO, NULL);
+ check_p_g_u_slice("/foobar", -ENXIO, NULL);
+ check_p_g_u_slice("/user.slice/user-waldo.slice", -ENXIO, NULL);
+ check_p_g_u_slice("", -ENXIO, NULL);
+ check_p_g_u_slice("foobar", -ENXIO, NULL);
+ check_p_g_u_slice("foobar.slice", -ENXIO, NULL);
+ check_p_g_u_slice("foo.slice/foo-bar.slice/waldo.service", -ENXIO, NULL);
+
+ check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service", 0, "-.slice");
+ check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/", 0, "-.slice");
+ check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service///", 0, "-.slice");
+ check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, "-.slice");
+ check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice");
+ check_p_g_u_slice("/foo.slice//foo-bar.slice/user@1000.service/piep.slice//piep-pap.slice//foo.service", 0, "piep-pap.slice");
}
static void test_get_paths(void) {
@@ -226,9 +268,14 @@ static void test_slice_to_path(void) {
test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
- test_slice_to_path_one("-.slice", NULL, -EINVAL);
+ test_slice_to_path_one("-.slice", "", 0);
+ test_slice_to_path_one("--.slice", NULL, -EINVAL);
+ test_slice_to_path_one("-", NULL, -EINVAL);
test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
+ test_slice_to_path_one("foo-.slice", NULL, -EINVAL);
+ test_slice_to_path_one("foo--bar.slice", NULL, -EINVAL);
+ test_slice_to_path_one("foo.slice/foo--bar.slice", NULL, -EINVAL);
test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
test_slice_to_path_one("a-b-c-d-e.slice", "a.slice/a-b.slice/a-b-c.slice/a-b-c-d.slice/a-b-c-d-e.slice", 0);
}
@@ -254,6 +301,8 @@ int main(void) {
test_path_get_user_unit();
test_path_get_session();
test_path_get_owner_uid();
+ test_path_get_slice();
+ test_path_get_user_slice();
TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
test_proc();
TEST_REQ_RUNNING_SYSTEMD(test_escape());
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
index 46642f92fe..4be69a408d 100644
--- a/src/test/test-cgroup.c
+++ b/src/test/test-cgroup.c
@@ -25,7 +25,6 @@
#include "cgroup-util.h"
#include "path-util.h"
#include "util.h"
-#include "log.h"
int main(int argc, char*argv[]) {
char *path;
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 88147c8e0a..b788c9532d 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -28,6 +28,7 @@
#include "ima-util.h"
#include "apparmor-util.h"
#include "smack-util.h"
+#include "hostname-util.h"
static void test_condition_test_path(void) {
Condition *condition;
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index 894c7f742f..01ece022c1 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -26,7 +26,7 @@
#include "macro.h"
#include "strv.h"
#include "util.h"
-
+#include "rm-rf.h"
static void setup_test_dir(char *tmp_dir, const char *files, ...) {
va_list ap;
@@ -74,7 +74,7 @@ static void test_conf_files_list(bool use_root) {
assert_se(streq_ptr(found_files[1], expect_b));
assert_se(found_files[2] == NULL);
- assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0);
+ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
int main(int argc, char **argv) {
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
new file mode 100644
index 0000000000..463906d304
--- /dev/null
+++ b/src/test/test-conf-parser.c
@@ -0,0 +1,234 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Ronny Chevalier
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "conf-parser.h"
+#include "macro.h"
+#include "util.h"
+#include "strv.h"
+#include "log.h"
+
+static void test_config_parse_path_one(const char *rvalue, const char *expected) {
+ char *path = NULL;
+
+ assert_se(config_parse_path("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &path, NULL) >= 0);
+ assert_se(streq_ptr(expected, path));
+
+ free(path);
+}
+
+static void test_config_parse_log_level_one(const char *rvalue, int expected) {
+ int log_level = 0;
+
+ assert_se(config_parse_log_level("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_level, NULL) >= 0);
+ assert_se(expected == log_level);
+}
+
+static void test_config_parse_log_facility_one(const char *rvalue, int expected) {
+ int log_facility = 0;
+
+ assert_se(config_parse_log_facility("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &log_facility, NULL) >= 0);
+ assert_se(expected == log_facility);
+}
+
+static void test_config_parse_iec_size_one(const char *rvalue, size_t expected) {
+ size_t iec_size = 0;
+
+ assert_se(config_parse_iec_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &iec_size, NULL) >= 0);
+ assert_se(expected == iec_size);
+}
+
+static void test_config_parse_si_size_one(const char *rvalue, size_t expected) {
+ size_t si_size = 0;
+
+ assert_se(config_parse_si_size("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &si_size, NULL) >= 0);
+ assert_se(expected == si_size);
+}
+
+static void test_config_parse_int_one(const char *rvalue, int expected) {
+ int v = -1;
+
+ assert_se(config_parse_int("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
+ assert_se(expected == v);
+}
+
+static void test_config_parse_unsigned_one(const char *rvalue, unsigned expected) {
+ unsigned v = 0;
+
+ assert_se(config_parse_unsigned("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
+ assert_se(expected == v);
+}
+
+static void test_config_parse_strv_one(const char *rvalue, char **expected) {
+ char **strv = 0;
+
+ assert_se(config_parse_strv("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &strv, NULL) >= 0);
+ assert_se(strv_equal(expected, strv));
+
+ strv_free(strv);
+}
+
+static void test_config_parse_mode_one(const char *rvalue, mode_t expected) {
+ mode_t v = 0;
+
+ assert_se(config_parse_mode("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
+ assert_se(expected == v);
+}
+
+static void test_config_parse_sec_one(const char *rvalue, usec_t expected) {
+ usec_t v = 0;
+
+ assert_se(config_parse_sec("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
+ assert_se(expected == v);
+}
+
+static void test_config_parse_nsec_one(const char *rvalue, nsec_t expected) {
+ nsec_t v = 0;
+
+ assert_se(config_parse_nsec("unit", "filename", 1, "nsection", 1, "lvalue", 0, rvalue, &v, NULL) >= 0);
+ assert_se(expected == v);
+}
+
+static void test_config_parse_path(void) {
+ test_config_parse_path_one("/path", "/path");
+ test_config_parse_path_one("/path//////////", "/path");
+ test_config_parse_path_one("///path/foo///bar////bar//", "/path/foo/bar/bar");
+
+ test_config_parse_path_one("not_absolute/path", NULL);
+}
+
+static void test_config_parse_log_level(void) {
+ test_config_parse_log_level_one("debug", LOG_DEBUG);
+ test_config_parse_log_level_one("info", LOG_INFO);
+
+ test_config_parse_log_level_one("garbage", 0);
+}
+
+static void test_config_parse_log_facility(void) {
+ test_config_parse_log_facility_one("mail", LOG_MAIL);
+ test_config_parse_log_facility_one("user", LOG_USER);
+
+ test_config_parse_log_facility_one("garbage", 0);
+}
+
+static void test_config_parse_iec_size(void) {
+ test_config_parse_iec_size_one("1024", 1024);
+ test_config_parse_iec_size_one("2K", 2048);
+ test_config_parse_iec_size_one("10M", 10 * 1024 * 1024);
+ test_config_parse_iec_size_one("1G", 1 * 1024 * 1024 * 1024);
+ test_config_parse_iec_size_one("0G", 0);
+ test_config_parse_iec_size_one("0", 0);
+
+ test_config_parse_iec_size_one("-982", 0);
+ test_config_parse_iec_size_one("49874444198739873000000G", 0);
+ test_config_parse_iec_size_one("garbage", 0);
+}
+
+static void test_config_parse_si_size(void) {
+ test_config_parse_si_size_one("1024", 1024);
+ test_config_parse_si_size_one("2K", 2000);
+ test_config_parse_si_size_one("10M", 10 * 1000 * 1000);
+ test_config_parse_si_size_one("1G", 1 * 1000 * 1000 * 1000);
+ test_config_parse_si_size_one("0G", 0);
+ test_config_parse_si_size_one("0", 0);
+
+ test_config_parse_si_size_one("-982", 0);
+ test_config_parse_si_size_one("49874444198739873000000G", 0);
+ test_config_parse_si_size_one("garbage", 0);
+}
+
+static void test_config_parse_int(void) {
+ test_config_parse_int_one("1024", 1024);
+ test_config_parse_int_one("-1024", -1024);
+ test_config_parse_int_one("0", 0);
+
+ test_config_parse_int_one("99999999999999999999999999999999999999999999999999999999", -1);
+ test_config_parse_int_one("-99999999999999999999999999999999999999999999999999999999", -1);
+ test_config_parse_int_one("1G", -1);
+ test_config_parse_int_one("garbage", -1);
+}
+
+static void test_config_parse_unsigned(void) {
+ test_config_parse_unsigned_one("10241024", 10241024);
+ test_config_parse_unsigned_one("1024", 1024);
+ test_config_parse_unsigned_one("0", 0);
+
+ test_config_parse_unsigned_one("99999999999999999999999999999999999999999999999999999999", 0);
+ test_config_parse_unsigned_one("1G", 0);
+ test_config_parse_unsigned_one("garbage", 0);
+ test_config_parse_unsigned_one("1000garbage", 0);
+}
+
+static void test_config_parse_strv(void) {
+ test_config_parse_strv_one("", STRV_MAKE_EMPTY);
+ test_config_parse_strv_one("foo", STRV_MAKE("foo"));
+ test_config_parse_strv_one("foo bar foo", STRV_MAKE("foo", "bar", "foo"));
+ test_config_parse_strv_one("\"foo bar\" foo", STRV_MAKE("foo bar", "foo"));
+}
+
+static void test_config_parse_mode(void) {
+ test_config_parse_mode_one("777", 0777);
+ test_config_parse_mode_one("644", 0644);
+
+ test_config_parse_mode_one("-777", 0);
+ test_config_parse_mode_one("999", 0);
+ test_config_parse_mode_one("garbage", 0);
+ test_config_parse_mode_one("777garbage", 0);
+ test_config_parse_mode_one("777 garbage", 0);
+}
+
+static void test_config_parse_sec(void) {
+ test_config_parse_sec_one("1", 1 * USEC_PER_SEC);
+ test_config_parse_sec_one("1s", 1 * USEC_PER_SEC);
+ test_config_parse_sec_one("100ms", 100 * USEC_PER_MSEC);
+ test_config_parse_sec_one("5min 20s", 5 * 60 * USEC_PER_SEC + 20 * USEC_PER_SEC);
+
+ test_config_parse_sec_one("-1", 0);
+ test_config_parse_sec_one("10foo", 0);
+ test_config_parse_sec_one("garbage", 0);
+}
+
+static void test_config_parse_nsec(void) {
+ test_config_parse_nsec_one("1", 1);
+ test_config_parse_nsec_one("1s", 1 * NSEC_PER_SEC);
+ test_config_parse_nsec_one("100ms", 100 * NSEC_PER_MSEC);
+ test_config_parse_nsec_one("5min 20s", 5 * 60 * NSEC_PER_SEC + 20 * NSEC_PER_SEC);
+
+ test_config_parse_nsec_one("-1", 0);
+ test_config_parse_nsec_one("10foo", 0);
+ test_config_parse_nsec_one("garbage", 0);
+}
+
+int main(int argc, char **argv) {
+ log_parse_environment();
+ log_open();
+
+ test_config_parse_path();
+ test_config_parse_log_level();
+ test_config_parse_log_facility();
+ test_config_parse_iec_size();
+ test_config_parse_si_size();
+ test_config_parse_int();
+ test_config_parse_unsigned();
+ test_config_parse_strv();
+ test_config_parse_mode();
+ test_config_parse_sec();
+ test_config_parse_nsec();
+
+ return 0;
+}
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index 5c96f61005..403d85bff0 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -26,6 +26,7 @@
#include "strv.h"
#include "macro.h"
#include "util.h"
+#include "rm-rf.h"
static void test_copy_file(void) {
_cleanup_free_ char *buf = NULL;
@@ -86,8 +87,8 @@ static void test_copy_tree(void) {
"link2", "dir1/file");
char **p, **link;
- rm_rf_dangerous(copy_dir, false, true, false);
- rm_rf_dangerous(original_dir, false, true, false);
+ (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
STRV_FOREACH(p, files) {
char *f = strjoina(original_dir, *p);
@@ -128,8 +129,8 @@ static void test_copy_tree(void) {
assert_se(copy_tree(original_dir, copy_dir, false) < 0);
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
- rm_rf_dangerous(copy_dir, false, true, false);
- rm_rf_dangerous(original_dir, false, true, false);
+ (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
}
int main(int argc, char *argv[]) {
diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c
index f97c78ebd6..27df9089c3 100644
--- a/src/test/test-ellipsize.c
+++ b/src/test/test-ellipsize.c
@@ -22,7 +22,7 @@
#include <stdio.h>
#include "util.h"
-#include "utf8.h"
+#include "terminal-util.h"
#include "def.h"
static void test_one(const char *p) {
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index 456999ca40..a7ab21a415 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -22,7 +22,6 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
-#include <unistd.h>
#include "manager.h"
#include "bus-util.h"
@@ -38,7 +37,7 @@ int main(int argc, char *argv[]) {
/* prepare the test */
assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(SYSTEMD_USER, true, &m);
+ r = manager_new(MANAGER_USER, true, &m);
if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
printf("Skipping test: manager_new: %s", strerror(-r));
return EXIT_TEST_SKIP;
@@ -66,7 +65,7 @@ int main(int argc, char *argv[]) {
manager_dump_units(m, stdout, "\t");
printf("Test2: (Cyclic Order, Unfixable)\n");
- assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -EDEADLOCK);
+ assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -EDEADLK);
manager_dump_jobs(m, stdout, "\t");
printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
@@ -82,14 +81,14 @@ int main(int argc, char *argv[]) {
manager_dump_units(m, stdout, "\t");
printf("Test5: (Colliding transaction, fail)\n");
- assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EDEADLOCK);
+ assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EDEADLK);
printf("Test6: (Colliding transaction, replace)\n");
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
printf("Test7: (Unmergeable job type, fail)\n");
- assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EDEADLOCK);
+ assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EDEADLK);
printf("Test8: (Mergeable job type, fail)\n");
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0);
diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c
index 0274e97618..2e28c0c49b 100644
--- a/src/test/test-env-replace.c
+++ b/src/test/test-env-replace.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <string.h>
#include "util.h"
@@ -137,31 +136,6 @@ static void test_replace_env_arg(void) {
assert_se(strv_length(r) == 9);
}
-static void test_one_normalize(const char *input, const char *output) {
- _cleanup_free_ char *t;
-
- t = normalize_env_assignment(input);
- assert_se(t);
- assert_se(streq(t, output));
-}
-
-static void test_normalize_env_assignment(void) {
- test_one_normalize("foo=bar", "foo=bar");
- test_one_normalize("=bar", "=bar");
- test_one_normalize("foo=", "foo=");
- test_one_normalize("=", "=");
- test_one_normalize("", "");
- test_one_normalize("a=\"waldo\"", "a=waldo");
- test_one_normalize("a=\"waldo", "a=\"waldo");
- test_one_normalize("a=waldo\"", "a=waldo\"");
- test_one_normalize("a=\'", "a='");
- test_one_normalize("a=\'\'", "a=");
- test_one_normalize(" xyz ", "xyz");
- test_one_normalize(" xyz = bar ", "xyz=bar");
- test_one_normalize(" xyz = 'bar ' ", "xyz=bar ");
- test_one_normalize(" ' xyz' = 'bar ' ", "' xyz'=bar ");
-}
-
static void test_env_clean(void) {
_cleanup_strv_free_ char **e;
@@ -210,7 +184,6 @@ int main(int argc, char *argv[]) {
test_strv_env_set();
test_strv_env_merge();
test_replace_env_arg();
- test_normalize_env_assignment();
test_env_clean();
test_env_name_is_valid();
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 91ccaf72b8..0f4172e722 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -23,8 +23,8 @@
#include "manager.h"
#include "util.h"
#include "macro.h"
-#include "strv.h"
#include "mkdir.h"
+#include "rm-rf.h"
typedef void (*test_function_t)(Manager *m);
@@ -73,7 +73,7 @@ static void test_exec_workingdirectory(Manager *m) {
test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
- rm_rf_dangerous("/tmp/test-exec_workingdirectory", false, true, false);
+ (void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_exec_personality(Manager *m) {
@@ -165,9 +165,9 @@ int main(int argc, char *argv[]) {
return EXIT_TEST_SKIP;
}
- assert_se(set_unit_path(TEST_DIR ":") >= 0);
+ assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(SYSTEMD_USER, true, &m);
+ r = manager_new(MANAGER_USER, true, &m);
if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
printf("Skipping test: manager_new: %s", strerror(-r));
return EXIT_TEST_SKIP;
diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c
index 91df7eb663..242c5d9dc2 100644
--- a/src/test/test-fdset.c
+++ b/src/test/test-fdset.c
@@ -154,6 +154,56 @@ static void test_fdset_iterate(void) {
unlink(name);
}
+static void test_fdset_isempty(void) {
+ int fd;
+ _cleanup_fdset_free_ FDSet *fdset = NULL;
+ char name[] = "/tmp/test-fdset_isempty.XXXXXX";
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+
+ fdset = fdset_new();
+ assert_se(fdset);
+
+ assert_se(fdset_isempty(fdset));
+ assert_se(fdset_put(fdset, fd) >= 0);
+ assert_se(!fdset_isempty(fdset));
+
+ unlink(name);
+}
+
+static void test_fdset_steal_first(void) {
+ int fd;
+ _cleanup_fdset_free_ FDSet *fdset = NULL;
+ char name[] = "/tmp/test-fdset_steal_first.XXXXXX";
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+
+ fdset = fdset_new();
+ assert_se(fdset);
+
+ assert_se(fdset_steal_first(fdset) < 0);
+ assert_se(fdset_put(fdset, fd) >= 0);
+ assert_se(fdset_steal_first(fdset) == fd);
+ assert_se(fdset_steal_first(fdset) < 0);
+ assert_se(fdset_put(fdset, fd) >= 0);
+
+ unlink(name);
+}
+
+static void test_fdset_new_array(void) {
+ int fds[] = {10, 11, 12, 13};
+ _cleanup_fdset_free_ FDSet *fdset = NULL;
+
+ assert_se(fdset_new_array(&fdset, fds, 4) >= 0);
+ assert_se(fdset_size(fdset) == 4);
+ assert_se(fdset_contains(fdset, 10));
+ assert_se(fdset_contains(fdset, 11));
+ assert_se(fdset_contains(fdset, 12));
+ assert_se(fdset_contains(fdset, 13));
+}
+
int main(int argc, char *argv[]) {
test_fdset_new_fill();
test_fdset_put_dup();
@@ -161,6 +211,9 @@ int main(int argc, char *argv[]) {
test_fdset_close_others();
test_fdset_remove();
test_fdset_iterate();
+ test_fdset_isempty();
+ test_fdset_steal_first();
+ test_fdset_new_array();
return 0;
}
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index 63e4a19b76..4c31b776bd 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -24,6 +24,7 @@
#include <unistd.h>
#include "util.h"
+#include "process-util.h"
#include "fileio.h"
#include "strv.h"
#include "env-util.h"
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c
index 84b508f874..c1a5ccf1f5 100644
--- a/src/test/test-hashmap-plain.c
+++ b/src/test/test-hashmap-plain.c
@@ -682,7 +682,7 @@ static void test_hashmap_get2(void) {
r = hashmap_get2(m, key_orig, &key_copy);
assert_se(streq(r, val));
assert_se(key_orig != key_copy);
- assert_se(streq(key_orig, key_orig));
+ assert_se(streq(key_orig, key_copy));
r = hashmap_get2(m, "no such key", NULL);
assert_se(r == NULL);
diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c
index 6900da9e89..767cbd90e9 100644
--- a/src/test/test-hashmap.c
+++ b/src/test/test-hashmap.c
@@ -17,8 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <inttypes.h>
-#include "strv.h"
#include "util.h"
#include "hashmap.h"
@@ -75,7 +73,7 @@ static void test_trivial_compare_func(void) {
}
static void test_string_compare_func(void) {
- assert_se(!string_compare_func("fred", "wilma") == 0);
+ assert_se(string_compare_func("fred", "wilma") != 0);
assert_se(string_compare_func("fred", "fred") == 0);
}
diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c
index 86efa1a3f7..dd50c5148c 100644
--- a/src/test/test-hostname.c
+++ b/src/test/test-hostname.c
@@ -19,11 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-
#include "hostname-setup.h"
#include "util.h"
diff --git a/src/test/test-install.c b/src/test/test-install.c
index 467970b007..5ee52e64cb 100644
--- a/src/test/test-install.c
+++ b/src/test/test-install.c
@@ -19,13 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
#include <string.h>
#include <stdio.h>
-#include <fcntl.h>
-#include "util.h"
-#include "path-util.h"
#include "install.h"
static void dump_changes(UnitFileChange *c, unsigned n) {
diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c
index 1d9d49b228..af0d76e894 100644
--- a/src/test/test-job-type.c
+++ b/src/test/test-job-type.c
@@ -20,9 +20,6 @@
***/
#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
#include "job.h"
#include "unit.h"
diff --git a/src/test/test-json.c b/src/test/test-json.c
index b09131891c..1058c583c3 100644
--- a/src/test/test-json.c
+++ b/src/test/test-json.c
@@ -21,7 +21,6 @@
#include <math.h>
-#include "log.h"
#include "util.h"
#include "json.h"
@@ -73,6 +72,97 @@ static void test_one(const char *data, ...) {
va_end(ap);
}
+typedef void (*Test)(JsonVariant *);
+
+static void test_file(const char *data, Test test) {
+ _cleanup_json_variant_unref_ JsonVariant *v = NULL;
+ int r;
+
+ r = json_parse(data, &v);
+ assert_se(r == 0);
+ assert_se(v != NULL);
+ assert_se(v->type == JSON_VARIANT_OBJECT);
+
+ if (test)
+ test(v);
+}
+
+static void test_1(JsonVariant *v) {
+ JsonVariant *p, *q;
+ unsigned i;
+
+ /* 3 keys + 3 values */
+ assert_se(v->size == 6);
+
+ /* has k */
+ p = json_variant_value(v, "k");
+ assert_se(p && p->type == JSON_VARIANT_STRING);
+
+ /* k equals v */
+ assert_se(streq(json_variant_string(p), "v"));
+
+ /* has foo */
+ p = json_variant_value(v, "foo");
+ assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 3);
+
+ /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
+ for (i = 0; i < 3; ++i) {
+ q = json_variant_element(p, i);
+ assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == (i+1));
+ }
+
+ /* has bar */
+ p = json_variant_value(v, "bar");
+ assert_se(p && p->type == JSON_VARIANT_OBJECT && p->size == 2);
+
+ /* zap is null */
+ q = json_variant_value(p, "zap");
+ assert_se(q && q->type == JSON_VARIANT_NULL);
+}
+
+static void test_2(JsonVariant *v) {
+ JsonVariant *p, *q;
+
+ /* 2 keys + 2 values */
+ assert_se(v->size == 4);
+
+ /* has mutant */
+ p = json_variant_value(v, "mutant");
+ assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 4);
+
+ /* mutant[0] == 1 */
+ q = json_variant_element(p, 0);
+ assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1);
+
+ /* mutant[1] == null */
+ q = json_variant_element(p, 1);
+ assert_se(q && q->type == JSON_VARIANT_NULL);
+
+ /* mutant[2] == "1" */
+ q = json_variant_element(p, 2);
+ assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1"));
+
+ /* mutant[3] == JSON_VARIANT_OBJECT */
+ q = json_variant_element(p, 3);
+ assert_se(q && q->type == JSON_VARIANT_OBJECT && q->size == 2);
+
+ /* has 1 */
+ p = json_variant_value(q, "1");
+ assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 2);
+
+ /* "1"[0] == 1 */
+ q = json_variant_element(p, 0);
+ assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1);
+
+ /* "1"[1] == "1" */
+ q = json_variant_element(p, 1);
+ assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1"));
+
+ /* has blah */
+ p = json_variant_value(v, "blah");
+ assert_se(p && p->type == JSON_VARIANT_REAL && fabs(json_variant_real(p) - 1.27) < 0.001);
+}
+
int main(int argc, char *argv[]) {
test_one("x", -EINVAL);
@@ -103,5 +193,10 @@ int main(int argc, char *argv[]) {
test_one("\"\\udc00\\udc00\"", -EINVAL);
test_one("\"\\ud801\\udc37\"", JSON_STRING, "\xf0\x90\x90\xb7", JSON_END);
+ test_one("[1, 2]", JSON_ARRAY_OPEN, JSON_INTEGER, (intmax_t) 1, JSON_COMMA, JSON_INTEGER, (intmax_t) 2, JSON_ARRAY_CLOSE, JSON_END);
+
+ test_file("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1);
+ test_file("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"blah\": 1.27}", test_2);
+
return 0;
}
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index 293c151d42..34c49b969a 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -19,13 +19,8 @@
***/
#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
#include <unistd.h>
-#include <errno.h>
-#include <string.h>
#include <getopt.h>
-#include <fcntl.h>
#include <sys/epoll.h>
#include "libudev.h"
@@ -309,6 +304,7 @@ static int test_queue(struct udev *udev) {
static int test_enumerate(struct udev *udev, const char *subsystem) {
struct udev_enumerate *udev_enumerate;
+ int r;
printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem);
udev_enumerate = udev_enumerate_new(udev);
@@ -344,7 +340,11 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
if (udev_enumerate == NULL)
return -1;
udev_enumerate_add_match_subsystem(udev_enumerate,"block");
- udev_enumerate_add_match_is_initialized(udev_enumerate);
+ r = udev_enumerate_add_match_is_initialized(udev_enumerate);
+ if (r < 0) {
+ udev_enumerate_unref(udev_enumerate);
+ return r;
+ }
udev_enumerate_scan_devices(udev_enumerate);
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c
index 1398a3a0b9..9765075365 100644
--- a/src/test/test-locale-util.c
+++ b/src/test/test-locale-util.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include "locale-util.h"
#include "strv.h"
diff --git a/src/test/test-log.c b/src/test/test-log.c
index ca64004b4c..9dcfa2f274 100644
--- a/src/test/test-log.c
+++ b/src/test/test-log.c
@@ -24,6 +24,7 @@
#include "log.h"
#include "util.h"
+#include "formats-util.h"
int main(int argc, char* argv[]) {
diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c
index 75fe053b63..c03bda4382 100644
--- a/src/test/test-loopback.c
+++ b/src/test/test-loopback.c
@@ -19,14 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
#include <string.h>
#include <stdio.h>
-#include <fcntl.h>
#include "loopback-setup.h"
#include "log.h"
-#include "util.h"
int main(int argc, char* argv[]) {
int r;
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 2397db5fff..7d7e08dc5d 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -23,6 +23,7 @@
#include "namespace.h"
#include "util.h"
+#include "process-util.h"
static void test_tmpdir(const char *id, const char *A, const char *B) {
_cleanup_free_ char *a, *b;
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index 7cd7b77153..3050be9e9d 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -20,13 +20,9 @@
***/
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
#include "namespace.h"
-#include "execute.h"
#include "log.h"
int main(int argc, char *argv[]) {
@@ -42,10 +38,12 @@ int main(int argc, char *argv[]) {
NULL
};
- const char * const inaccessible[] = {
+ const char *inaccessible[] = {
"/home/lennart/projects",
NULL
};
+ char *root_directory;
+ char *projects_directory;
int r;
char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
@@ -54,7 +52,20 @@ int main(int argc, char *argv[]) {
assert_se(mkdtemp(tmp_dir));
assert_se(mkdtemp(var_tmp_dir));
- r = setup_namespace((char **) writable,
+ root_directory = getenv("TEST_NS_CHROOT");
+ projects_directory = getenv("TEST_NS_PROJECTS");
+
+ if (projects_directory)
+ inaccessible[0] = projects_directory;
+
+ log_info("Inaccessible directory: '%s'", inaccessible[0]);
+ if (root_directory)
+ log_info("Chroot: '%s'", root_directory);
+ else
+ log_info("Not chrooted");
+
+ r = setup_namespace(root_directory,
+ (char **) writable,
(char **) readonly,
(char **) inaccessible,
tmp_dir,
@@ -66,6 +77,11 @@ int main(int argc, char *argv[]) {
0);
if (r < 0) {
log_error_errno(r, "Failed to setup namespace: %m");
+
+ log_info("Usage:\n"
+ " sudo TEST_NS_PROJECTS=/home/lennart/projects ./test-ns\n"
+ " sudo TEST_NS_CHROOT=/home/alban/debian-tree TEST_NS_PROJECTS=/home/alban/debian-tree/home/alban/Documents ./test-ns");
+
return 1;
}
diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c
index 38e5c93df6..aa4bac6cdd 100644
--- a/src/test/test-path-lookup.c
+++ b/src/test/test-path-lookup.c
@@ -20,13 +20,13 @@
***/
#include <sys/stat.h>
-#include <sys/types.h>
#include "path-lookup.h"
#include "log.h"
#include "strv.h"
+#include "rm-rf.h"
-static void test_paths(SystemdRunningAs running_as, bool personal) {
+static void test_paths(ManagerRunningAs running_as, bool personal) {
char template[] = "/tmp/test-path-lookup.XXXXXXX";
_cleanup_lookup_paths_free_ LookupPaths lp = {};
@@ -43,14 +43,14 @@ static void test_paths(SystemdRunningAs running_as, bool personal) {
assert_se(strv_contains(lp.unit_path, exists));
assert_se(strv_contains(lp.unit_path, not));
- assert_se(rm_rf_dangerous(template, false, true, false) >= 0);
+ assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
-static void print_generator_paths(SystemdRunningAs running_as) {
+static void print_generator_paths(ManagerRunningAs running_as) {
_cleanup_strv_free_ char **paths;
char **dir;
- log_info("Generators dirs (%s):", running_as == SYSTEMD_SYSTEM ? "system" : "user");
+ log_info("Generators dirs (%s):", running_as == MANAGER_SYSTEM ? "system" : "user");
paths = generator_paths(running_as);
STRV_FOREACH(dir, paths)
@@ -62,13 +62,13 @@ int main(int argc, char **argv) {
log_parse_environment();
log_open();
- test_paths(SYSTEMD_SYSTEM, false);
- test_paths(SYSTEMD_SYSTEM, true);
- test_paths(SYSTEMD_USER, false);
- test_paths(SYSTEMD_USER, true);
+ test_paths(MANAGER_SYSTEM, false);
+ test_paths(MANAGER_SYSTEM, true);
+ test_paths(MANAGER_USER, false);
+ test_paths(MANAGER_USER, true);
- print_generator_paths(SYSTEMD_SYSTEM);
- print_generator_paths(SYSTEMD_USER);
+ print_generator_paths(MANAGER_SYSTEM);
+ print_generator_paths(MANAGER_USER);
return EXIT_SUCCESS;
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 11aa52aaed..0045ae6824 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -21,29 +21,47 @@
#include <stdio.h>
#include <unistd.h>
+#include <sys/mount.h>
#include "path-util.h"
#include "util.h"
#include "macro.h"
#include "strv.h"
+#include "rm-rf.h"
+#define test_path_compare(a, b, result) { \
+ assert_se(path_compare(a, b) == result); \
+ assert_se(path_compare(b, a) == -result); \
+ assert_se(path_equal(a, b) == !result); \
+ assert_se(path_equal(b, a) == !result); \
+ }
static void test_path(void) {
- assert_se(path_equal("/goo", "/goo"));
- assert_se(path_equal("//goo", "/goo"));
- assert_se(path_equal("//goo/////", "/goo"));
- assert_se(path_equal("goo/////", "goo"));
+ _cleanup_close_ int fd = -1;
+
+ test_path_compare("/goo", "/goo", 0);
+ test_path_compare("/goo", "/goo", 0);
+ test_path_compare("//goo", "/goo", 0);
+ test_path_compare("//goo/////", "/goo", 0);
+ test_path_compare("goo/////", "goo", 0);
+
+ test_path_compare("/goo/boo", "/goo//boo", 0);
+ test_path_compare("//goo/boo", "/goo/boo//", 0);
- assert_se(path_equal("/goo/boo", "/goo//boo"));
- assert_se(path_equal("//goo/boo", "/goo/boo//"));
+ test_path_compare("/", "///", 0);
- assert_se(path_equal("/", "///"));
+ test_path_compare("/x", "x/", 1);
+ test_path_compare("x/", "/", -1);
- assert_se(!path_equal("/x", "x/"));
- assert_se(!path_equal("x/", "/"));
+ test_path_compare("/x/./y", "x/y", 1);
+ test_path_compare("x/.y", "x/y", -1);
- assert_se(!path_equal("/x/./y", "x/y"));
- assert_se(!path_equal("x/.y", "x/y"));
+ test_path_compare("foo", "/foo", -1);
+ test_path_compare("/foo", "/foo/bar", -1);
+ test_path_compare("/foo/aaa", "/foo/b", -1);
+ test_path_compare("/foo/aaa", "/foo/b/a", -1);
+ test_path_compare("/foo/a", "/foo/aaa", -1);
+ test_path_compare("/foo/a/b", "/foo/aaa", -1);
assert_se(path_is_absolute("/"));
assert_se(!path_is_absolute("./"));
@@ -71,8 +89,9 @@ static void test_path(void) {
test_parent("/aa///file...", "/aa///");
test_parent("file.../", NULL);
- assert_se(path_is_mount_point("/", true));
- assert_se(path_is_mount_point("/", false));
+ fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
+ assert_se(fd >= 0);
+ assert_se(fd_is_mount_point(fd, "/", 0) > 0);
{
char p1[] = "aaa/bbb////ccc";
@@ -242,7 +261,7 @@ static void test_strv_resolve(void) {
assert_se(streq(search_dirs[1], "/dir2"));
assert_se(streq(search_dirs[2], "/dir2"));
- assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0);
+ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
static void test_path_startswith(void) {
@@ -264,6 +283,94 @@ static void test_path_startswith(void) {
assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
}
+static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
+ _cleanup_free_ char *s = NULL;
+ const char *t;
+
+ assert_se(s = prefix_root(r, p));
+ assert_se(streq_ptr(s, expected));
+
+ t = prefix_roota(r, p);
+ assert_se(t);
+ assert_se(streq_ptr(t, expected));
+}
+
+static void test_prefix_root(void) {
+ test_prefix_root_one("/", "/foo", "/foo");
+ test_prefix_root_one(NULL, "/foo", "/foo");
+ test_prefix_root_one("", "/foo", "/foo");
+ test_prefix_root_one("///", "/foo", "/foo");
+ test_prefix_root_one("/", "////foo", "/foo");
+ test_prefix_root_one(NULL, "////foo", "/foo");
+
+ test_prefix_root_one("/foo", "/bar", "/foo/bar");
+ test_prefix_root_one("/foo", "bar", "/foo/bar");
+ test_prefix_root_one("foo", "bar", "foo/bar");
+ test_prefix_root_one("/foo/", "/bar", "/foo/bar");
+ test_prefix_root_one("/foo/", "//bar", "/foo/bar");
+ test_prefix_root_one("/foo///", "//bar", "/foo/bar");
+}
+
+static void test_path_is_mount_point(void) {
+ int fd, rt, rf, rlt, rlf;
+ char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
+ _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
+
+ assert_se(path_is_mount_point("/", AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/", 0) > 0);
+
+ assert_se(path_is_mount_point("/proc", AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/proc", 0) > 0);
+
+ assert_se(path_is_mount_point("/proc/1", AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point("/proc/1", 0) == 0);
+
+ assert_se(path_is_mount_point("/sys", AT_SYMLINK_FOLLOW) > 0);
+ assert_se(path_is_mount_point("/sys", 0) > 0);
+
+ /* file mountpoints */
+ assert_se(mkdtemp(tmp_dir) != NULL);
+ file1 = path_join(NULL, tmp_dir, "file1");
+ assert_se(file1);
+ file2 = path_join(NULL, tmp_dir, "file2");
+ assert_se(file2);
+ fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+ assert_se(fd > 0);
+ close(fd);
+ fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+ assert_se(fd > 0);
+ close(fd);
+ link1 = path_join(NULL, tmp_dir, "link1");
+ assert_se(link1);
+ assert_se(symlink("file1", link1) == 0);
+ link2 = path_join(NULL, tmp_dir, "link2");
+ assert_se(link1);
+ assert_se(symlink("file2", link2) == 0);
+
+ assert_se(path_is_mount_point(file1, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(file1, 0) == 0);
+ assert_se(path_is_mount_point(link1, AT_SYMLINK_FOLLOW) == 0);
+ assert_se(path_is_mount_point(link1, 0) == 0);
+
+ /* this test will only work as root */
+ if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
+ rf = path_is_mount_point(file2, 0);
+ rt = path_is_mount_point(file2, AT_SYMLINK_FOLLOW);
+ rlf = path_is_mount_point(link2, 0);
+ rlt = path_is_mount_point(link2, AT_SYMLINK_FOLLOW);
+
+ assert_se(umount(file2) == 0);
+
+ assert_se(rf == 1);
+ assert_se(rt == 1);
+ assert_se(rlf == 0);
+ assert_se(rlt == 1);
+ } else
+ printf("Skipping bind mount file test: %m\n");
+
+ assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
+}
+
int main(int argc, char **argv) {
test_path();
test_find_binary(argv[0], true);
@@ -274,6 +381,8 @@ int main(int argc, char **argv) {
test_make_relative();
test_strv_resolve();
test_path_startswith();
+ test_prefix_root();
+ test_path_is_mount_point();
return 0;
}
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 4f9f5c1344..5d190378f1 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -26,6 +26,7 @@
#include "macro.h"
#include "strv.h"
#include "mkdir.h"
+#include "rm-rf.h"
typedef void (*test_function_t)(Manager *m);
@@ -33,12 +34,12 @@ static int setup_test(Manager **m) {
char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
"directorynotempty", "makedirectory");
char **test_path;
- Manager *tmp;
+ Manager *tmp = NULL;
int r;
assert_se(m);
- r = manager_new(SYSTEMD_USER, true, &tmp);
+ r = manager_new(MANAGER_USER, true, &tmp);
if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
printf("Skipping test: manager_new: %s", strerror(-r));
return -EXIT_TEST_SKIP;
@@ -47,7 +48,12 @@ static int setup_test(Manager **m) {
assert_se(manager_startup(tmp, NULL, NULL) >= 0);
STRV_FOREACH(test_path, tests_path) {
- rm_rf_dangerous(strjoina("/tmp/test-path_", *test_path), false, true, false);
+ _cleanup_free_ char *p = NULL;
+
+ p = strjoin("/tmp/test-path_", *test_path, NULL);
+ assert_se(p);
+
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
}
*m = tmp;
@@ -104,7 +110,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con
}
assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
- rm_rf_dangerous(test_path, false, true, false);
+ (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_path_exists(Manager *m) {
@@ -228,7 +234,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
assert_se((s.st_mode & S_IRWXO) == 0004);
assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
- rm_rf_dangerous(test_path, false, true, false);
+ (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
}
int main(int argc, char *argv[]) {
@@ -248,7 +254,7 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- assert_se(set_unit_path(TEST_DIR ":") >= 0);
+ assert_se(set_unit_path(TEST_DIR) >= 0);
for (test = tests; test && *test; test++) {
int r;
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
new file mode 100644
index 0000000000..e4e2efecd5
--- /dev/null
+++ b/src/test/test-process-util.c
@@ -0,0 +1,138 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "process-util.h"
+#include "log.h"
+#include "util.h"
+#include "macro.h"
+#include "virt.h"
+#include "terminal-util.h"
+
+static void test_get_process_comm(void) {
+ struct stat st;
+ _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL;
+ _cleanup_free_ char *env = NULL;
+ pid_t e;
+ uid_t u;
+ gid_t g;
+ dev_t h;
+ int r;
+ pid_t me;
+
+ if (stat("/proc/1/comm", &st) == 0) {
+ assert_se(get_process_comm(1, &a) >= 0);
+ log_info("pid1 comm: '%s'", a);
+ } else
+ log_warning("/proc/1/comm does not exist.");
+
+ assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
+ log_info("pid1 cmdline: '%s'", c);
+
+ assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
+ log_info("pid1 cmdline truncated: '%s'", d);
+
+ assert_se(get_parent_of_pid(1, &e) >= 0);
+ log_info("pid1 ppid: "PID_FMT, e);
+ assert_se(e == 0);
+
+ assert_se(is_kernel_thread(1) == 0);
+
+ r = get_process_exe(1, &f);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("pid1 exe: '%s'", strna(f));
+
+ assert_se(get_process_uid(1, &u) == 0);
+ log_info("pid1 uid: "UID_FMT, u);
+ assert_se(u == 0);
+
+ assert_se(get_process_gid(1, &g) == 0);
+ log_info("pid1 gid: "GID_FMT, g);
+ assert_se(g == 0);
+
+ me = getpid();
+
+ r = get_process_cwd(me, &cwd);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("pid1 cwd: '%s'", cwd);
+
+ r = get_process_root(me, &root);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("pid1 root: '%s'", root);
+
+ r = get_process_environ(me, &env);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("self strlen(environ): '%zu'", strlen(env));
+
+ if (!detect_container(NULL))
+ assert_se(get_ctty_devnr(1, &h) == -ENXIO);
+
+ getenv_for_pid(1, "PATH", &i);
+ log_info("pid1 $PATH: '%s'", strna(i));
+}
+
+static void test_pid_is_unwaited(void) {
+ pid_t pid;
+
+ pid = fork();
+ assert_se(pid >= 0);
+ if (pid == 0) {
+ _exit(EXIT_SUCCESS);
+ } else {
+ int status;
+
+ waitpid(pid, &status, 0);
+ assert_se(!pid_is_unwaited(pid));
+ }
+ assert_se(pid_is_unwaited(getpid()));
+ assert_se(!pid_is_unwaited(-1));
+}
+
+static void test_pid_is_alive(void) {
+ pid_t pid;
+
+ pid = fork();
+ assert_se(pid >= 0);
+ if (pid == 0) {
+ _exit(EXIT_SUCCESS);
+ } else {
+ int status;
+
+ waitpid(pid, &status, 0);
+ assert_se(!pid_is_alive(pid));
+ }
+ assert_se(pid_is_alive(getpid()));
+ assert_se(!pid_is_alive(-1));
+}
+
+int main(int argc, char *argv[]) {
+ log_parse_environment();
+ log_open();
+
+ test_get_process_comm();
+ test_pid_is_unwaited();
+ test_pid_is_alive();
+
+ return 0;
+}
diff --git a/src/test/test-pty.c b/src/test/test-pty.c
index cab569a9da..f8807c9150 100644
--- a/src/test/test-pty.c
+++ b/src/test/test-pty.c
@@ -20,15 +20,14 @@
***/
#include <errno.h>
-#include <fcntl.h>
#include <locale.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
-#include "def.h"
#include "pty.h"
#include "util.h"
+#include "signal-util.h"
static const char sndmsg[] = "message\n";
static const char rcvmsg[] = "message\r\n";
@@ -97,7 +96,7 @@ static void run_parent(Pty *pty) {
static void test_pty(void) {
pid_t pid;
- Pty *pty;
+ Pty *pty = NULL;
rcvsiz = 0;
zero(rcvbuf);
diff --git a/src/test/test-ring.c b/src/test/test-ring.c
index a9dd01ca01..cb8a5d4e9e 100644
--- a/src/test/test-ring.c
+++ b/src/test/test-ring.c
@@ -20,14 +20,9 @@
***/
#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <locale.h>
-#include <errno.h>
#include "def.h"
#include "ring.h"
-#include "util.h"
static void test_ring(void) {
static const char buf[8192];
diff --git a/src/test/test-rtnl-manual.c b/src/test/test-rtnl-manual.c
index c8133dbad7..c406454f77 100644
--- a/src/test/test-rtnl-manual.c
+++ b/src/test/test-rtnl-manual.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/ip.h>
@@ -29,10 +28,6 @@
#include "util.h"
#include "macro.h"
#include "sd-rtnl.h"
-#include "socket-util.h"
-#include "rtnl-util.h"
-#include "event-util.h"
-#include "rtnl-internal.h"
static int load_module(const char *mod_name) {
struct kmod_ctx *ctx;
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
index 6b3128d3b7..f915539e00 100644
--- a/src/test/test-sched-prio.c
+++ b/src/test/test-sched-prio.c
@@ -34,7 +34,7 @@ int main(int argc, char *argv[]) {
/* prepare the test */
assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(SYSTEMD_USER, true, &m);
+ r = manager_new(MANAGER_USER, true, &m);
if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
printf("Skipping test: manager_new: %s", strerror(-r));
return EXIT_TEST_SKIP;
diff --git a/src/test/test-set.c b/src/test/test-set.c
index e280c8952d..0ee5ddcc9f 100644
--- a/src/test/test-set.c
+++ b/src/test/test-set.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "set.h"
static void test_set_steal_first(void) {
@@ -40,8 +39,25 @@ static void test_set_steal_first(void) {
assert_se(set_isempty(m));
}
+static void test_set_put(void) {
+ _cleanup_set_free_ Set *m = NULL;
+
+ m = set_new(&string_hash_ops);
+ assert_se(m);
+
+ assert_se(set_put(m, (void*) "1") == 1);
+ assert_se(set_put(m, (void*) "22") == 1);
+ assert_se(set_put(m, (void*) "333") == 1);
+ assert_se(set_put(m, (void*) "333") == 0);
+ assert_se(set_remove(m, (void*) "333"));
+ assert_se(set_put(m, (void*) "333") == 1);
+ assert_se(set_put(m, (void*) "333") == 0);
+ assert_se(set_put(m, (void*) "22") == 0);
+}
+
int main(int argc, const char *argv[]) {
test_set_steal_first();
+ test_set_put();
return 0;
}
diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c
index a1020ad14c..4308ddfb64 100644
--- a/src/test/test-sleep.c
+++ b/src/test/test-sleep.c
@@ -19,10 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <string.h>
#include <stdio.h>
-#include <fcntl.h>
#include "util.h"
#include "log.h"
@@ -59,7 +56,7 @@ int main(int argc, char* argv[]) {
log_open();
if (getuid() != 0)
- log_warning("This program is unlikely to work for unpriviledged users");
+ log_warning("This program is unlikely to work for unprivileged users");
test_sleep();
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 6fb4a40944..f257af445a 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -231,6 +231,24 @@ static void test_in_addr_prefix_next(void) {
}
+static void test_in_addr_to_string_one(int f, const char *addr) {
+ union in_addr_union ua;
+ _cleanup_free_ char *r = NULL;
+
+ assert_se(in_addr_from_string(f, addr, &ua) >= 0);
+ assert_se(in_addr_to_string(f, &ua, &r) >= 0);
+ printf("test_in_addr_to_string_one: %s == %s\n", addr, r);
+ assert_se(streq(addr, r));
+}
+
+static void test_in_addr_to_string(void) {
+ test_in_addr_to_string_one(AF_INET, "192.168.0.1");
+ test_in_addr_to_string_one(AF_INET, "10.11.12.13");
+ test_in_addr_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ test_in_addr_to_string_one(AF_INET6, "::1");
+ test_in_addr_to_string_one(AF_INET6, "fe80::");
+}
+
static void *connect_thread(void *arg) {
union sockaddr_union *sa = arg;
_cleanup_close_ int fd = -1;
@@ -324,6 +342,7 @@ int main(int argc, char *argv[]) {
test_in_addr_prefix_intersect();
test_in_addr_prefix_next();
+ test_in_addr_to_string();
test_nameinfo_pretty();
diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c
index 5016906ad0..358454842a 100644
--- a/src/test/test-strip-tab-ansi.c
+++ b/src/test/test-strip-tab-ansi.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include "util.h"
+#include "terminal-util.h"
int main(int argc, char *argv[]) {
char *p;
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index 5ae929c3f8..d5ea2b3fab 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -165,7 +165,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
assert_se(p);
assert_se(streq(p, quoted));
- r = strv_split_quoted(&s, quoted, false);
+ r = strv_split_quoted(&s, quoted, 0);
assert_se(r == 0);
assert_se(s);
STRV_FOREACH(t, s) {
@@ -182,7 +182,7 @@ static void test_strv_unquote(const char *quoted, char **list) {
char **t;
int r;
- r = strv_split_quoted(&s, quoted, false);
+ r = strv_split_quoted(&s, quoted, 0);
assert_se(r == 0);
assert_se(s);
j = strv_join(s, " | ");
@@ -199,7 +199,7 @@ static void test_invalid_unquote(const char *quoted) {
char **s = NULL;
int r;
- r = strv_split_quoted(&s, quoted, false);
+ r = strv_split_quoted(&s, quoted, 0);
assert_se(s == NULL);
assert_se(r == -EINVAL);
}
diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c
index a7c8e1267d..858a4081da 100644
--- a/src/test/test-strxcpyx.c
+++ b/src/test/test-strxcpyx.c
@@ -22,7 +22,6 @@
#include <string.h>
#include "util.h"
-#include "strv.h"
#include "strxcpyx.h"
static void test_strpcpy(void) {
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index bda224bec6..0e5ab1645f 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -23,14 +23,12 @@
#include "condition.h"
#include "device.h"
#include "execute.h"
-#include "exit-status.h"
#include "install.h"
#include "job.h"
#include "kill.h"
#include "log.h"
#include "logs-show.h"
#include "mount.h"
-#include "path-lookup.h"
#include "path.h"
#include "scope.h"
#include "service.h"
diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c
new file mode 100644
index 0000000000..d81fdb9923
--- /dev/null
+++ b/src/test/test-terminal-util.c
@@ -0,0 +1,84 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "terminal-util.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+
+static void test_default_term_for_tty(void) {
+ puts(default_term_for_tty("/dev/tty23"));
+ puts(default_term_for_tty("/dev/ttyS23"));
+ puts(default_term_for_tty("/dev/tty0"));
+ puts(default_term_for_tty("/dev/pty0"));
+ puts(default_term_for_tty("/dev/pts/0"));
+ puts(default_term_for_tty("/dev/console"));
+ puts(default_term_for_tty("tty23"));
+ puts(default_term_for_tty("ttyS23"));
+ puts(default_term_for_tty("tty0"));
+ puts(default_term_for_tty("pty0"));
+ puts(default_term_for_tty("pts/0"));
+ puts(default_term_for_tty("console"));
+}
+
+static void test_read_one_char(void) {
+ _cleanup_fclose_ FILE *file = NULL;
+ char r;
+ bool need_nl;
+ char name[] = "/tmp/test-read_one_char.XXXXXX";
+ int fd;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ file = fdopen(fd, "r+");
+ assert_se(file);
+ assert_se(fputs("c\n", file) >= 0);
+ rewind(file);
+
+ assert_se(read_one_char(file, &r, 1000000, &need_nl) >= 0);
+ assert_se(!need_nl);
+ assert_se(r == 'c');
+ assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
+
+ rewind(file);
+ assert_se(fputs("foobar\n", file) >= 0);
+ rewind(file);
+ assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
+
+ rewind(file);
+ assert_se(fputs("\n", file) >= 0);
+ rewind(file);
+ assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
+
+ unlink(name);
+}
+
+int main(int argc, char *argv[]) {
+ log_parse_environment();
+ log_open();
+
+ test_default_term_for_tty();
+ test_read_one_char();
+
+ return 0;
+}
diff --git a/src/test/test-time.c b/src/test/test-time.c
index 8cfc4cc4fe..3840fff061 100644
--- a/src/test/test-time.c
+++ b/src/test/test-time.c
@@ -78,12 +78,18 @@ static void test_parse_nsec(void) {
assert_se(u == 2);
assert_se(parse_nsec(".7", &u) >= 0);
assert_se(u == 0);
+ assert_se(parse_nsec("infinity", &u) >= 0);
+ assert_se(u == NSEC_INFINITY);
+ assert_se(parse_nsec(" infinity ", &u) >= 0);
+ assert_se(u == NSEC_INFINITY);
assert_se(parse_nsec(" xyz ", &u) < 0);
assert_se(parse_nsec("", &u) < 0);
assert_se(parse_nsec(" . ", &u) < 0);
assert_se(parse_nsec(" 5. ", &u) < 0);
assert_se(parse_nsec(".s ", &u) < 0);
+ assert_se(parse_nsec(" infinity .7", &u) < 0);
+ assert_se(parse_nsec(".3 infinity", &u) < 0);
}
static void test_format_timespan_one(usec_t x, usec_t accuracy) {
diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c
index 4b72c4a8fa..221dd67eb2 100644
--- a/src/test/test-tmpfiles.c
+++ b/src/test/test-tmpfiles.c
@@ -19,14 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "util.h"
+#include "formats-util.h"
int main(int argc, char** argv) {
const char *p = argv[1] ?: "/tmp";
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index b57d275efa..d1fe953071 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -19,20 +19,16 @@
***/
#include <stdio.h>
-#include <stddef.h>
#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <ctype.h>
#include <errno.h>
#include <unistd.h>
-#include <grp.h>
#include <sched.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
#include "missing.h"
#include "selinux-util.h"
+#include "signal-util.h"
#include "udev.h"
#include "udev-util.h"
@@ -84,7 +80,6 @@ int main(int argc, char *argv[]) {
char syspath[UTIL_PATH_SIZE];
const char *devpath;
const char *action;
- sigset_t mask, sigmask_orig;
int err;
err = fake_filesystems();
@@ -98,8 +93,6 @@ int main(int argc, char *argv[]) {
log_debug("version %s", VERSION);
mac_selinux_init("/dev");
- sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
-
action = argv[1];
if (action == NULL) {
log_error("action missing");
@@ -115,22 +108,15 @@ int main(int argc, char *argv[]) {
rules = udev_rules_new(udev, 1);
strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL);
- dev = udev_device_new_from_syspath(udev, syspath);
+ dev = udev_device_new_from_synthetic_event(udev, syspath, action);
if (dev == NULL) {
log_debug("unknown device '%s'", devpath);
goto out;
}
- udev_device_set_action(dev, action);
event = udev_event_new(dev);
- sigfillset(&mask);
- sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
- event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (event->fd_signal < 0) {
- fprintf(stderr, "error creating signalfd\n");
- goto out;
- }
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) == 0);
/* do what devtmpfs usually provides us */
if (udev_device_get_devnode(dev) != NULL) {
@@ -153,14 +139,10 @@ int main(int argc, char *argv[]) {
udev_event_execute_rules(event,
3 * USEC_PER_SEC, USEC_PER_SEC,
NULL,
- rules,
- &sigmask_orig);
+ rules);
udev_event_execute_run(event,
- 3 * USEC_PER_SEC, USEC_PER_SEC,
- NULL);
+ 3 * USEC_PER_SEC, USEC_PER_SEC);
out:
- if (event != NULL && event->fd_signal >= 0)
- close(event->fd_signal);
mac_selinux_finish();
return err ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index e517f571d6..a8025c825b 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -20,7 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
@@ -37,6 +36,7 @@
#include "strv.h"
#include "fileio.h"
#include "test-helper.h"
+#include "hostname-util.h"
static int test_unit_file_get_set(void) {
int r;
@@ -92,6 +92,7 @@ static void check_execcommand(ExecCommand *c,
static void test_config_parse_exec(void) {
/* int config_parse_exec(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
@@ -224,6 +225,15 @@ static void test_config_parse_exec(void) {
check_execcommand(c1,
"/sbin/find", NULL, ";", "x", false);
+ log_info("/* encoded semicolon */");
+ r = config_parse_exec(NULL, "fake", 5, "section", 1,
+ "LValue", 0,
+ "/bin/find \\073",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1, "/bin/find", NULL, ";", NULL, false);
+
log_info("/* spaces in the filename */");
r = config_parse_exec(NULL, "fake", 5, "section", 1,
"LValue", 0,
@@ -295,6 +305,16 @@ static void test_config_parse_exec(void) {
c1 = c1->command_next;
check_execcommand(c1, "/path ", NULL, NULL, NULL, false);
+ log_info("/* quoted backslashes */");
+ r = config_parse_exec(NULL, "fake", 5, "section", 1,
+ "LValue", 0,
+ "/bin/grep '\\w+\\K'",
+ &c, NULL);
+ assert_se(r >= 0);
+ c1 = c1->command_next;
+ check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false);
+
+
log_info("/* trailing backslash: \\ */");
/* backslash is invalid */
r = config_parse_exec(NULL, "fake", 4, "section", 1,
@@ -303,6 +323,41 @@ static void test_config_parse_exec(void) {
assert_se(r == 0);
assert_se(c1->command_next == NULL);
+ log_info("/* missing ending ' */");
+ r = config_parse_exec(NULL, "fake", 4, "section", 1,
+ "LValue", 0, "/path 'foo",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c1->command_next == NULL);
+
+ log_info("/* missing ending ' with trailing backslash */");
+ r = config_parse_exec(NULL, "fake", 4, "section", 1,
+ "LValue", 0, "/path 'foo\\",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c1->command_next == NULL);
+
+ log_info("/* invalid space between modifiers */");
+ r = config_parse_exec(NULL, "fake", 4, "section", 1,
+ "LValue", 0, "- /path",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c1->command_next == NULL);
+
+ log_info("/* only modifiers, no path */");
+ r = config_parse_exec(NULL, "fake", 4, "section", 1,
+ "LValue", 0, "-",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c1->command_next == NULL);
+
+ log_info("/* empty argument, reset */");
+ r = config_parse_exec(NULL, "fake", 4, "section", 1,
+ "LValue", 0, "",
+ &c, NULL);
+ assert_se(r == 0);
+ assert_se(c == NULL);
+
exec_command_free_list(c);
}
@@ -439,12 +494,12 @@ static void test_install_printf(void) {
char name[] = "name.service",
path[] = "/run/systemd/system/name.service",
user[] = "xxxx-no-such-user";
- InstallInfo i = {name, path, user};
- InstallInfo i2 = {name, path, NULL};
+ UnitFileInstallInfo i = {name, path, user};
+ UnitFileInstallInfo i2 = {name, path, NULL};
char name3[] = "name@inst.service",
path3[] = "/run/systemd/system/name.service";
- InstallInfo i3 = {name3, path3, user};
- InstallInfo i4 = {name3, path3, NULL};
+ UnitFileInstallInfo i3 = {name3, path3, user};
+ UnitFileInstallInfo i4 = {name3, path3, NULL};
_cleanup_free_ char *mid, *bid, *host;
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 5c7f8b40f7..e5405fb7f3 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -24,90 +24,166 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
#include <pwd.h>
#include "manager.h"
#include "unit.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "install.h"
#include "specifier.h"
#include "util.h"
#include "macro.h"
+#include "path-util.h"
#include "test-helper.h"
+#include "hostname-util.h"
+
+static void test_unit_name_is_valid(void) {
+ assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
+ assert_se(unit_name_is_valid("foo.service", UNIT_NAME_PLAIN));
+ assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE));
+ assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_TEMPLATE));
+ assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
+
+ assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_ANY));
+ assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_PLAIN));
+ assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE));
+ assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_TEMPLATE));
+ assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
+
+ assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_ANY));
+ assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_PLAIN));
+ assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE));
+ assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_TEMPLATE));
+ assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
+
+ assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY));
+ assert_se(!unit_name_is_valid("", UNIT_NAME_ANY));
+ assert_se(!unit_name_is_valid("foo.waldo", UNIT_NAME_ANY));
+ assert_se(!unit_name_is_valid("@.service", UNIT_NAME_ANY));
+ assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY));
+}
-static void test_replacements(void) {
-#define expect(pattern, repl, expected) \
- { \
- _cleanup_free_ char *t = \
- unit_name_replace_instance(pattern, repl); \
- puts(t); \
- assert_se(streq(t, expected)); \
- }
-
- expect("foo@.service", "waldo", "foo@waldo.service");
- expect("foo@xyz.service", "waldo", "foo@waldo.service");
- expect("xyz", "waldo", "xyz");
- expect("", "waldo", "");
- expect("foo.service", "waldo", "foo.service");
- expect(".service", "waldo", ".service");
- expect("foo@", "waldo", "foo@waldo");
- expect("@bar", "waldo", "@waldo");
+static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) {
+ _cleanup_free_ char *t = NULL;
+ assert_se(unit_name_replace_instance(pattern, repl, &t) == ret);
+ puts(strna(t));
+ assert_se(streq_ptr(t, expected));
+}
+static void test_u_n_r_i(void) {
puts("-------------------------------------------------");
-#undef expect
-#define expect(path, suffix, expected) \
- { \
- _cleanup_free_ char *k, *t = \
- unit_name_from_path(path, suffix); \
- puts(t); \
- k = unit_name_to_path(t); \
- puts(k); \
- assert_se(streq(k, expected ? expected : path)); \
- }
+ test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0);
+ test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0);
+ test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL);
+ test_u_n_r_i_one("", "waldo", NULL, -EINVAL);
+ test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL);
+ test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL);
+ test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL);
+ test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL);
+}
- expect("/waldo", ".mount", NULL);
- expect("/waldo/quuix", ".mount", NULL);
- expect("/waldo/quuix/", ".mount", "/waldo/quuix");
- expect("/", ".mount", NULL);
- expect("///", ".mount", "/");
+static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) {
+ _cleanup_free_ char *t = NULL;
- puts("-------------------------------------------------");
-#undef expect
-#define expect(pattern, path, suffix, expected) \
- { \
- _cleanup_free_ char *t = \
- unit_name_from_path_instance(pattern, path, suffix); \
- puts(t); \
- assert_se(streq(t, expected)); \
- }
+ assert_se(unit_name_from_path(path, suffix, &t) == ret);
+ puts(strna(t));
+ assert_se(streq_ptr(t, expected));
- expect("waldo", "/waldo", ".mount", "waldo@waldo.mount");
- expect("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount");
- expect("waldo", "/", ".mount", "waldo@-.mount");
- expect("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount");
+ if (t) {
+ _cleanup_free_ char *k = NULL;
+ assert_se(unit_name_to_path(t, &k) == 0);
+ puts(strna(k));
+ assert_se(path_equal(k, isempty(path) ? "/" : path));
+ }
+}
+static void test_u_n_f_p(void) {
puts("-------------------------------------------------");
-#undef expect
-#define expect(pattern) \
- { \
- _cleanup_free_ char *k, *t; \
- assert_se(t = unit_name_mangle(pattern, MANGLE_NOGLOB)); \
- assert_se(k = unit_name_mangle(t, MANGLE_NOGLOB)); \
- puts(t); \
- assert_se(streq(t, k)); \
+ test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0);
+ test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0);
+ test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0);
+ test_u_n_f_p_one("", ".mount", "-.mount", 0);
+ test_u_n_f_p_one("/", ".mount", "-.mount", 0);
+ test_u_n_f_p_one("///", ".mount", "-.mount", 0);
+ test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL);
+ test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL);
+}
+
+static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) {
+ _cleanup_free_ char *t = NULL;
+
+ assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret);
+ puts(strna(t));
+ assert_se(streq_ptr(t, expected));
+
+ if (t) {
+ _cleanup_free_ char *k = NULL, *v = NULL;
+
+ assert_se(unit_name_to_instance(t, &k) > 0);
+ assert_se(unit_name_path_unescape(k, &v) == 0);
+ assert_se(path_equal(v, isempty(path) ? "/" : path));
}
+}
- expect("/home");
- expect("/dev/sda");
- expect("üxknürz.service");
- expect("foobar-meh...waldi.service");
- expect("_____####----.....service");
- expect("_____##@;;;,,,##----.....service");
- expect("xxx@@@@/////\\\\\\\\\\yyy.service");
+static void test_u_n_f_p_i(void) {
+ puts("-------------------------------------------------");
-#undef expect
+ test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0);
+ test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0);
+ test_u_n_f_p_i_one("waldo", "/", ".mount", "waldo@-.mount", 0);
+ test_u_n_f_p_i_one("waldo", "", ".mount", "waldo@-.mount", 0);
+ test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo@-.mount", 0);
+ test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL);
+ test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL);
+ test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0);
+}
+
+static void test_u_n_t_p_one(const char *unit, const char *path, int ret) {
+ _cleanup_free_ char *p = NULL;
+
+ assert_se(unit_name_to_path(unit, &p) == ret);
+ assert_se(streq_ptr(path, p));
+}
+
+static void test_u_n_t_p(void) {
+ test_u_n_t_p_one("home.mount", "/home", 0);
+ test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0);
+ test_u_n_t_p_one("home-lennart-.mount", NULL, -EINVAL);
+ test_u_n_t_p_one("-home-lennart.mount", NULL, -EINVAL);
+ test_u_n_t_p_one("-home--lennart.mount", NULL, -EINVAL);
+ test_u_n_t_p_one("home-..-lennart.mount", NULL, -EINVAL);
+ test_u_n_t_p_one("", NULL, -EINVAL);
+ test_u_n_t_p_one("home/foo", NULL, -EINVAL);
+}
+
+static void test_u_n_m_one(const char *pattern, const char *expect, int ret) {
+ _cleanup_free_ char *t = NULL;
+
+ assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret);
+ puts(strna(t));
+ assert_se(streq_ptr(t, expect));
+
+ if (t) {
+ _cleanup_free_ char *k = NULL;
+
+ assert_se(unit_name_is_valid(t, UNIT_NAME_ANY));
+
+ assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0);
+ assert_se(streq_ptr(t, k));
+ }
+}
+
+static void test_u_n_m(void) {
+ puts("-------------------------------------------------");
+ test_u_n_m_one("foo.service", "foo.service", 0);
+ test_u_n_m_one("/home", "home.mount", 1);
+ test_u_n_m_one("/dev/sda", "dev-sda.device", 1);
+ test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1);
+ test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0);
+ test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1);
+ test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1);
+ test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1);
+ test_u_n_m_one("", NULL, -EINVAL);
}
static int test_unit_printf(void) {
@@ -125,7 +201,7 @@ static int test_unit_printf(void) {
assert_se((root = getpwnam("root")));
assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0);
- r = manager_new(SYSTEMD_USER, true, &m);
+ r = manager_new(MANAGER_USER, true, &m);
if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
@@ -226,64 +302,83 @@ static void test_unit_prefix_is_valid(void) {
}
static void test_unit_name_change_suffix(void) {
- char *r;
+ char *t;
- r = unit_name_change_suffix("foo.bar", ".service");
- assert_se(r);
- assert_se(streq(r, "foo.service"));
- free(r);
+ assert_se(unit_name_change_suffix("foo.mount", ".service", &t) == 0);
+ assert_se(streq(t, "foo.service"));
+ free(t);
- r = unit_name_change_suffix("foo@stuff.bar", ".boo");
- assert_se(r);
- assert_se(streq(r, "foo@stuff.boo"));
- free(r);
+ assert_se(unit_name_change_suffix("foo@stuff.service", ".socket", &t) == 0);
+ assert_se(streq(t, "foo@stuff.socket"));
+ free(t);
}
static void test_unit_name_build(void) {
- char *r;
+ char *t;
- r = unit_name_build("foo", "bar", ".service");
- assert_se(r);
- assert_se(streq(r, "foo@bar.service"));
- free(r);
+ assert_se(unit_name_build("foo", "bar", ".service", &t) == 0);
+ assert_se(streq(t, "foo@bar.service"));
+ free(t);
- r = unit_name_build("fo0-stUff_b", "bar", ".mount");
- assert_se(r);
- assert_se(streq(r, "fo0-stUff_b@bar.mount"));
- free(r);
+ assert_se(unit_name_build("fo0-stUff_b", "bar", ".mount", &t) == 0);
+ assert_se(streq(t, "fo0-stUff_b@bar.mount"));
+ free(t);
- r = unit_name_build("foo", NULL, ".service");
- assert_se(r);
- assert_se(streq(r, "foo.service"));
- free(r);
+ assert_se(unit_name_build("foo", NULL, ".service", &t) == 0);
+ assert_se(streq(t, "foo.service"));
+ free(t);
}
-static void test_unit_name_is_instance(void) {
- assert_se(unit_name_is_instance("a@b.service"));
- assert_se(unit_name_is_instance("a-c_c01Aj@b05Dii_-oioi.service"));
-
- assert_se(!unit_name_is_instance("a.service"));
- assert_se(!unit_name_is_instance("a@.service"));
- assert_se(!unit_name_is_instance("junk"));
- assert_se(!unit_name_is_instance(""));
+static void test_slice_name_is_valid(void) {
+ assert_se(slice_name_is_valid("-.slice"));
+ assert_se(slice_name_is_valid("foo.slice"));
+ assert_se(slice_name_is_valid("foo-bar.slice"));
+ assert_se(slice_name_is_valid("foo-bar-baz.slice"));
+ assert_se(!slice_name_is_valid("-foo-bar-baz.slice"));
+ assert_se(!slice_name_is_valid("foo-bar-baz-.slice"));
+ assert_se(!slice_name_is_valid("-foo-bar-baz-.slice"));
+ assert_se(!slice_name_is_valid("foo-bar--baz.slice"));
+ assert_se(!slice_name_is_valid("foo--bar--baz.slice"));
+ assert_se(!slice_name_is_valid(".slice"));
+ assert_se(!slice_name_is_valid(""));
+ assert_se(!slice_name_is_valid("foo.service"));
}
static void test_build_subslice(void) {
char *a;
char *b;
- assert_se(build_subslice("-.slice", "foo", &a) >= 0);
- assert_se(build_subslice(a, "bar", &b) >= 0);
+ assert_se(slice_build_subslice("-.slice", "foo", &a) >= 0);
+ assert_se(slice_build_subslice(a, "bar", &b) >= 0);
free(a);
- assert_se(build_subslice(b, "barfoo", &a) >= 0);
+ assert_se(slice_build_subslice(b, "barfoo", &a) >= 0);
free(b);
- assert_se(build_subslice(a, "foobar", &b) >= 0);
+ assert_se(slice_build_subslice(a, "foobar", &b) >= 0);
free(a);
assert_se(streq(b, "foo-bar-barfoo-foobar.slice"));
free(b);
- assert_se(build_subslice("foo.service", "bar", &a) < 0);
- assert_se(build_subslice("foo", "bar", &a) < 0);
+ assert_se(slice_build_subslice("foo.service", "bar", &a) < 0);
+ assert_se(slice_build_subslice("foo", "bar", &a) < 0);
+}
+
+static void test_build_parent_slice_one(const char *name, const char *expect, int ret) {
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(slice_build_parent_slice(name, &s) == ret);
+ assert_se(streq_ptr(s, expect));
+}
+
+static void test_build_parent_slice(void) {
+ test_build_parent_slice_one("-.slice", NULL, 0);
+ test_build_parent_slice_one("foo.slice", "-.slice", 1);
+ test_build_parent_slice_one("foo-bar.slice", "foo.slice", 1);
+ test_build_parent_slice_one("foo-bar-baz.slice", "foo-bar.slice", 1);
+ test_build_parent_slice_one("foo-bar--baz.slice", NULL, -EINVAL);
+ test_build_parent_slice_one("-foo-bar.slice", NULL, -EINVAL);
+ test_build_parent_slice_one("foo-bar-.slice", NULL, -EINVAL);
+ test_build_parent_slice_one("foo-bar.service", NULL, -EINVAL);
+ test_build_parent_slice_one(".slice", NULL, -EINVAL);
}
static void test_unit_name_to_instance(void) {
@@ -300,13 +395,13 @@ static void test_unit_name_to_instance(void) {
assert_se(streq(instance, ""));
free(instance);
- r = unit_name_to_instance("fo0-stUff_b@b.e", &instance);
+ r = unit_name_to_instance("fo0-stUff_b@b.service", &instance);
assert_se(r >= 0);
assert_se(streq(instance, "b"));
free(instance);
- r = unit_name_to_instance("foo.bar", &instance);
- assert_se(r >= 0);
+ r = unit_name_to_instance("foo.service", &instance);
+ assert_se(r == 0);
assert_se(!instance);
r = unit_name_to_instance("fooj@unk", &instance);
@@ -324,43 +419,63 @@ static void test_unit_name_escape(void) {
assert_se(streq(r, "ab\\x2b\\x2dc.a-bc\\x40foo.service"));
}
+
+static void test_u_n_t_one(const char *name, const char *expected, int ret) {
+ _cleanup_free_ char *f = NULL;
+
+ assert_se(unit_name_template(name, &f) == ret);
+ printf("got: %s, expected: %s\n", strna(f), strna(expected));
+ assert_se(streq_ptr(f, expected));
+}
+
static void test_unit_name_template(void) {
-#define expect(name, expected) \
- { \
- _cleanup_free_ char *f = NULL; \
- f = unit_name_template(name); \
- assert_se(f); \
- printf("got: %s, expected: %s\n", f, expected); \
- assert_se(streq(f, expected)); \
- }
- expect("foo@bar.service", "foo@.service")
- expect("foo.mount", "foo.mount")
-#undef expect
+ test_u_n_t_one("foo@bar.service", "foo@.service", 0);
+ test_u_n_t_one("foo.mount", NULL, -EINVAL);
}
-static void test_unit_name_is_template(void) {
- assert_se(unit_name_is_template("foo@.service"));
- assert_se(unit_name_is_template("bar@.path"));
+static void test_unit_name_path_unescape_one(const char *name, const char *path, int ret) {
+ _cleanup_free_ char *p = NULL;
+
+ assert_se(unit_name_path_unescape(name, &p) == ret);
+ assert_se(streq_ptr(path, p));
+}
- assert_se(!unit_name_is_template("bar@i.mount"));
- assert_se(!unit_name_is_template("bar@foobbbb.service"));
- assert_se(!unit_name_is_template("barfoo.service"));
+static void test_unit_name_path_unescape(void) {
+
+ test_unit_name_path_unescape_one("foo", "/foo", 0);
+ test_unit_name_path_unescape_one("foo-bar", "/foo/bar", 0);
+ test_unit_name_path_unescape_one("foo-.bar", "/foo/.bar", 0);
+ test_unit_name_path_unescape_one("foo-bar-baz", "/foo/bar/baz", 0);
+ test_unit_name_path_unescape_one("-", "/", 0);
+ test_unit_name_path_unescape_one("--", NULL, -EINVAL);
+ test_unit_name_path_unescape_one("-foo-bar", NULL, -EINVAL);
+ test_unit_name_path_unescape_one("foo--bar", NULL, -EINVAL);
+ test_unit_name_path_unescape_one("foo-bar-", NULL, -EINVAL);
+ test_unit_name_path_unescape_one(".-bar", NULL, -EINVAL);
+ test_unit_name_path_unescape_one("foo-..", NULL, -EINVAL);
+ test_unit_name_path_unescape_one("", NULL, -EINVAL);
}
int main(int argc, char* argv[]) {
int rc = 0;
- test_replacements();
+ test_unit_name_is_valid();
+ test_u_n_r_i();
+ test_u_n_f_p();
+ test_u_n_f_p_i();
+ test_u_n_m();
+ test_u_n_t_p();
TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf());
test_unit_instance_is_valid();
test_unit_prefix_is_valid();
test_unit_name_change_suffix();
test_unit_name_build();
- test_unit_name_is_instance();
+ test_slice_name_is_valid();
test_build_subslice();
+ test_build_parent_slice();
test_unit_name_to_instance();
test_unit_name_escape();
test_unit_name_template();
- test_unit_name_is_template();
+ test_unit_name_path_unescape();
return rc;
}
diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c
index befa385754..346f8524c6 100644
--- a/src/test/test-utf8.c
+++ b/src/test/test-utf8.c
@@ -95,7 +95,7 @@ static void test_utf8_escaping_printable(void) {
static void test_utf16_to_utf8(void) {
char *a = NULL;
- const uint16_t utf16[] = { 'a', 0xd800, 'b', 0xdc00, 'c', 0xd801, 0xdc37 };
+ const uint16_t utf16[] = { htole16('a'), htole16(0xd800), htole16('b'), htole16(0xdc00), htole16('c'), htole16(0xd801), htole16(0xdc37) };
const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7, 0 };
a = utf16_to_utf8(utf16, 14);
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 9515a8cbf1..9d5516a18d 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -31,11 +31,15 @@
#include "util.h"
#include "mkdir.h"
+#include "rm-rf.h"
#include "strv.h"
#include "def.h"
#include "fileio.h"
#include "conf-parser.h"
#include "virt.h"
+#include "process-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
static void test_streq_ptr(void) {
assert_se(streq_ptr(NULL, NULL));
@@ -416,24 +420,51 @@ static void test_cescape(void) {
static void test_cunescape(void) {
_cleanup_free_ char *unescaped;
- unescaped = cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00");
+ assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0);
+ assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00"));
+ free(unescaped);
+ unescaped = NULL;
/* incomplete sequences */
- unescaped = cunescape("\\x0");
+ assert_se(cunescape("\\x0", 0, &unescaped) < 0);
+ assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "\\x0"));
+ free(unescaped);
+ unescaped = NULL;
- unescaped = cunescape("\\x");
+ assert_se(cunescape("\\x", 0, &unescaped) < 0);
+ assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "\\x"));
+ free(unescaped);
+ unescaped = NULL;
- unescaped = cunescape("\\");
+ assert_se(cunescape("\\", 0, &unescaped) < 0);
+ assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "\\"));
+ free(unescaped);
+ unescaped = NULL;
- unescaped = cunescape("\\11");
+ assert_se(cunescape("\\11", 0, &unescaped) < 0);
+ assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "\\11"));
+ free(unescaped);
+ unescaped = NULL;
- unescaped = cunescape("\\1");
+ assert_se(cunescape("\\1", 0, &unescaped) < 0);
+ assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0);
assert_se(streq_ptr(unescaped, "\\1"));
+ free(unescaped);
+ unescaped = NULL;
+
+ assert_se(cunescape("\\u0000", 0, &unescaped) < 0);
+ assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "ßßΠA"));
+ free(unescaped);
+ unescaped = NULL;
+
+ assert_se(cunescape("\\073", 0, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, ";"));
}
static void test_foreach_word(void) {
@@ -498,21 +529,6 @@ static void test_foreach_word_quoted(void) {
true);
}
-static void test_default_term_for_tty(void) {
- puts(default_term_for_tty("/dev/tty23"));
- puts(default_term_for_tty("/dev/ttyS23"));
- puts(default_term_for_tty("/dev/tty0"));
- puts(default_term_for_tty("/dev/pty0"));
- puts(default_term_for_tty("/dev/pts/0"));
- puts(default_term_for_tty("/dev/console"));
- puts(default_term_for_tty("tty23"));
- puts(default_term_for_tty("ttyS23"));
- puts(default_term_for_tty("tty0"));
- puts(default_term_for_tty("pty0"));
- puts(default_term_for_tty("pts/0"));
- puts(default_term_for_tty("console"));
-}
-
static void test_memdup_multiply(void) {
int org[] = {1, 2, 3};
int *dup;
@@ -539,6 +555,59 @@ static void test_hostname_is_valid(void) {
assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
}
+static void test_read_hostname_config(void) {
+ char path[] = "/tmp/hostname.XXXXXX";
+ char *hostname;
+ int fd;
+
+ fd = mkostemp_safe(path, O_RDWR|O_CLOEXEC);
+ assert(fd > 0);
+ close(fd);
+
+ /* simple hostname */
+ write_string_file(path, "foo");
+ assert_se(read_hostname_config(path, &hostname) == 0);
+ assert_se(streq(hostname, "foo"));
+ free(hostname);
+ hostname = NULL;
+
+ /* with comment */
+ write_string_file(path, "# comment\nfoo");
+ assert_se(read_hostname_config(path, &hostname) == 0);
+ assert_se(hostname);
+ assert_se(streq(hostname, "foo"));
+ free(hostname);
+ hostname = NULL;
+
+ /* with comment and extra whitespace */
+ write_string_file(path, "# comment\n\n foo ");
+ assert_se(read_hostname_config(path, &hostname) == 0);
+ assert_se(hostname);
+ assert_se(streq(hostname, "foo"));
+ free(hostname);
+ hostname = NULL;
+
+ /* cleans up name */
+ write_string_file(path, "!foo/bar.com");
+ assert_se(read_hostname_config(path, &hostname) == 0);
+ assert_se(hostname);
+ assert_se(streq(hostname, "foobar.com"));
+ free(hostname);
+ hostname = NULL;
+
+ /* no value set */
+ hostname = (char*) 0x1234;
+ write_string_file(path, "# nothing here\n");
+ assert_se(read_hostname_config(path, &hostname) == -ENOENT);
+ assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
+
+ /* nonexisting file */
+ assert_se(read_hostname_config("/non/existing", &hostname) == -ENOENT);
+ assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
+
+ unlink(path);
+}
+
static void test_u64log2(void) {
assert_se(u64log2(0) == 0);
assert_se(u64log2(8) == 3);
@@ -549,69 +618,6 @@ static void test_u64log2(void) {
assert_se(u64log2(1024*1024+5) == 20);
}
-static void test_get_process_comm(void) {
- struct stat st;
- _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL;
- _cleanup_free_ char *env = NULL;
- pid_t e;
- uid_t u;
- gid_t g;
- dev_t h;
- int r;
- pid_t me;
-
- if (stat("/proc/1/comm", &st) == 0) {
- assert_se(get_process_comm(1, &a) >= 0);
- log_info("pid1 comm: '%s'", a);
- } else {
- log_warning("/proc/1/comm does not exist.");
- }
-
- assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
- log_info("pid1 cmdline: '%s'", c);
-
- assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
- log_info("pid1 cmdline truncated: '%s'", d);
-
- assert_se(get_parent_of_pid(1, &e) >= 0);
- log_info("pid1 ppid: "PID_FMT, e);
- assert_se(e == 0);
-
- assert_se(is_kernel_thread(1) == 0);
-
- r = get_process_exe(1, &f);
- assert_se(r >= 0 || r == -EACCES);
- log_info("pid1 exe: '%s'", strna(f));
-
- assert_se(get_process_uid(1, &u) == 0);
- log_info("pid1 uid: "UID_FMT, u);
- assert_se(u == 0);
-
- assert_se(get_process_gid(1, &g) == 0);
- log_info("pid1 gid: "GID_FMT, g);
- assert_se(g == 0);
-
- me = getpid();
-
- r = get_process_cwd(me, &cwd);
- assert_se(r >= 0 || r == -EACCES);
- log_info("pid1 cwd: '%s'", cwd);
-
- r = get_process_root(me, &root);
- assert_se(r >= 0 || r == -EACCES);
- log_info("pid1 root: '%s'", root);
-
- r = get_process_environ(me, &env);
- assert_se(r >= 0 || r == -EACCES);
- log_info("self strlen(environ): '%zu'", strlen(env));
-
- if (!detect_container(NULL))
- assert_se(get_ctty_devnr(1, &h) == -ENOENT);
-
- getenv_for_pid(1, "PATH", &i);
- log_info("pid1 $PATH: '%s'", strna(i));
-}
-
static void test_protect_errno(void) {
errno = 12;
{
@@ -1017,39 +1023,7 @@ static void test_readlink_and_make_absolute(void) {
free(r);
assert_se(unlink(name_alias) >= 0);
- assert_se(rm_rf_dangerous(tempdir, false, true, false) >= 0);
-}
-
-static void test_read_one_char(void) {
- _cleanup_fclose_ FILE *file = NULL;
- char r;
- bool need_nl;
- char name[] = "/tmp/test-read_one_char.XXXXXX";
- int fd;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- file = fdopen(fd, "r+");
- assert_se(file);
- assert_se(fputs("c\n", file) >= 0);
- rewind(file);
-
- assert_se(read_one_char(file, &r, 1000000, &need_nl) >= 0);
- assert_se(!need_nl);
- assert_se(r == 'c');
- assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
-
- rewind(file);
- assert_se(fputs("foobar\n", file) >= 0);
- rewind(file);
- assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
-
- rewind(file);
- assert_se(fputs("\n", file) >= 0);
- rewind(file);
- assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
-
- unlink(name);
+ assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
static void test_ignore_signals(void) {
@@ -1115,40 +1089,6 @@ static void test_is_symlink(void) {
unlink(name_link);
}
-static void test_pid_is_unwaited(void) {
- pid_t pid;
-
- pid = fork();
- assert_se(pid >= 0);
- if (pid == 0) {
- _exit(EXIT_SUCCESS);
- } else {
- int status;
-
- waitpid(pid, &status, 0);
- assert_se(!pid_is_unwaited(pid));
- }
- assert_se(pid_is_unwaited(getpid()));
- assert_se(!pid_is_unwaited(-1));
-}
-
-static void test_pid_is_alive(void) {
- pid_t pid;
-
- pid = fork();
- assert_se(pid >= 0);
- if (pid == 0) {
- _exit(EXIT_SUCCESS);
- } else {
- int status;
-
- waitpid(pid, &status, 0);
- assert_se(!pid_is_alive(pid));
- }
- assert_se(pid_is_alive(getpid()));
- assert_se(!pid_is_alive(-1));
-}
-
static void test_search_and_fopen(void) {
const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
char name[] = "/tmp/test-search_and_fopen.XXXXXX";
@@ -1274,8 +1214,8 @@ static void test_execute_directory(void) {
assert_se(access("it_works2", F_OK) >= 0);
assert_se(access("failed", F_OK) < 0);
- rm_rf_dangerous(template_lo, false, true, false);
- rm_rf_dangerous(template_hi, false, true, false);
+ (void) rm_rf(template_lo, REMOVE_ROOT|REMOVE_PHYSICAL);
+ (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
}
static void test_unquote_first_word(void) {
@@ -1283,64 +1223,87 @@ static void test_unquote_first_word(void) {
char *t;
p = original = "foobar waldo";
- assert_se(unquote_first_word(&p, &t, false) > 0);
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 7);
- assert_se(unquote_first_word(&p, &t, false) > 0);
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(p == original + 12);
- assert_se(unquote_first_word(&p, &t, false) == 0);
+ assert_se(unquote_first_word(&p, &t, 0) == 0);
assert_se(!t);
assert_se(p == original + 12);
p = original = "\"foobar\" \'waldo\'";
- assert_se(unquote_first_word(&p, &t, false) > 0);
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 9);
- assert_se(unquote_first_word(&p, &t, false) > 0);
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(p == original + 16);
- assert_se(unquote_first_word(&p, &t, false) == 0);
+ assert_se(unquote_first_word(&p, &t, 0) == 0);
assert_se(!t);
assert_se(p == original + 16);
p = original = "\"";
- assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
+ assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'";
- assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
+ assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'fooo";
- assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
+ assert_se(unquote_first_word(&p, &t, 0) == -EINVAL);
assert_se(p == original + 5);
p = original = "\'fooo";
- assert_se(unquote_first_word(&p, &t, true) > 0);
+ assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0);
assert_se(streq(t, "fooo"));
free(t);
assert_se(p == original + 5);
p = original = "yay\'foo\'bar";
- assert_se(unquote_first_word(&p, &t, false) > 0);
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(streq(t, "yayfoobar"));
free(t);
assert_se(p == original + 11);
p = original = " foobar ";
- assert_se(unquote_first_word(&p, &t, false) > 0);
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 12);
+
+ p = original = " foo\\ba\\x6ar ";
+ assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
+ assert_se(streq(t, "foo\ba\x6ar"));
+ free(t);
+ assert_se(p == original + 13);
+
+ p = original = " foo\\ba\\x6ar ";
+ assert_se(unquote_first_word(&p, &t, 0) > 0);
+ assert_se(streq(t, "foobax6ar"));
+ free(t);
+ assert_se(p == original + 13);
+
+ p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
+ assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
+ assert_se(streq(t, "föo"));
+ free(t);
+ assert_se(p == original + 13);
+
+ assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0);
+ assert_se(streq(t, "pi\360\237\222\251le"));
+ free(t);
+ assert_se(p == original + 32);
}
static void test_unquote_many_words(void) {
@@ -1348,7 +1311,7 @@ static void test_unquote_many_words(void) {
char *a, *b, *c;
p = original = "foobar waldi piep";
- assert_se(unquote_many_words(&p, &a, &b, &c, NULL) == 3);
+ assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 3);
assert_se(p == original + 17);
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
@@ -1358,7 +1321,7 @@ static void test_unquote_many_words(void) {
free(c);
p = original = "'foobar' wa\"ld\"i ";
- assert_se(unquote_many_words(&p, &a, &b, &c, NULL) == 2);
+ assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 2);
assert_se(p == original + 19);
assert_se(streq_ptr(a, "foobar"));
assert_se(streq_ptr(b, "waldi"));
@@ -1367,31 +1330,31 @@ static void test_unquote_many_words(void) {
free(b);
p = original = "";
- assert_se(unquote_many_words(&p, &a, &b, &c, NULL) == 0);
+ assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0);
assert_se(p == original);
assert_se(streq_ptr(a, NULL));
assert_se(streq_ptr(b, NULL));
assert_se(streq_ptr(c, NULL));
p = original = " ";
- assert_se(unquote_many_words(&p, &a, &b, &c, NULL) == 0);
+ assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0);
assert_se(p == original+2);
assert_se(streq_ptr(a, NULL));
assert_se(streq_ptr(b, NULL));
assert_se(streq_ptr(c, NULL));
p = original = "foobar";
- assert_se(unquote_many_words(&p, NULL) == 0);
+ assert_se(unquote_many_words(&p, 0, NULL) == 0);
assert_se(p == original);
p = original = "foobar waldi";
- assert_se(unquote_many_words(&p, &a, NULL) == 1);
+ assert_se(unquote_many_words(&p, 0, &a, NULL) == 1);
assert_se(p == original+7);
assert_se(streq_ptr(a, "foobar"));
free(a);
p = original = " foobar ";
- assert_se(unquote_many_words(&p, &a, NULL) == 1);
+ assert_se(unquote_many_words(&p, 0, &a, NULL) == 1);
assert_se(p == original+15);
assert_se(streq_ptr(a, "foobar"));
free(a);
@@ -1512,6 +1475,38 @@ static void test_sparse_write(void) {
test_sparse_write_one(fd, test_e, sizeof(test_e));
}
+static void test_shell_maybe_quote_one(const char *s, const char *expected) {
+ _cleanup_free_ char *r;
+
+ assert_se(r = shell_maybe_quote(s));
+ assert_se(streq(r, expected));
+}
+
+static void test_shell_maybe_quote(void) {
+
+ test_shell_maybe_quote_one("", "");
+ test_shell_maybe_quote_one("\\", "\"\\\\\"");
+ test_shell_maybe_quote_one("\"", "\"\\\"\"");
+ test_shell_maybe_quote_one("foobar", "foobar");
+ test_shell_maybe_quote_one("foo bar", "\"foo bar\"");
+ test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\"");
+ test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
+}
+
+static void test_parse_mode(void) {
+ mode_t m;
+
+ assert_se(parse_mode("-1", &m) < 0);
+ assert_se(parse_mode("", &m) < 0);
+ assert_se(parse_mode("888", &m) < 0);
+ assert_se(parse_mode("77777", &m) < 0);
+
+ assert_se(parse_mode("544", &m) >= 0 && m == 0544);
+ assert_se(parse_mode("777", &m) >= 0 && m == 0777);
+ assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
+ assert_se(parse_mode("0", &m) >= 0 && m == 0);
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -1543,11 +1538,10 @@ int main(int argc, char *argv[]) {
test_cunescape();
test_foreach_word();
test_foreach_word_quoted();
- test_default_term_for_tty();
test_memdup_multiply();
test_hostname_is_valid();
+ test_read_hostname_config();
test_u64log2();
- test_get_process_comm();
test_protect_errno();
test_parse_size();
test_config_parse_iec_off();
@@ -1571,13 +1565,10 @@ int main(int argc, char *argv[]) {
test_close_nointr();
test_unlink_noerrno();
test_readlink_and_make_absolute();
- test_read_one_char();
test_ignore_signals();
test_strshorten();
test_strjoina();
test_is_symlink();
- test_pid_is_unwaited();
- test_pid_is_alive();
test_search_and_fopen();
test_search_and_fopen_nulstr();
test_glob_exists();
@@ -1589,6 +1580,8 @@ int main(int argc, char *argv[]) {
test_same_fd();
test_uid_ptr();
test_sparse_write();
+ test_shell_maybe_quote();
+ test_parse_mode();
return 0;
}
diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c
index f6bb045c3c..2e5d0c3aae 100644
--- a/src/test/test-watchdog.c
+++ b/src/test/test-watchdog.c
@@ -20,7 +20,6 @@
***/
#include <unistd.h>
-#include <string.h>
#include "watchdog.h"
#include "log.h"
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 4d89886736..61b6e765c7 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -22,11 +22,8 @@
#include <stdlib.h>
#include <stdbool.h>
-#include <unistd.h>
#include <getopt.h>
#include <locale.h>
-#include <string.h>
-#include <sys/timex.h>
#include "sd-bus.h"
#include "bus-util.h"
@@ -36,7 +33,7 @@
#include "build.h"
#include "strv.h"
#include "pager.h"
-#include "time-dst.h"
+#include "terminal-util.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
@@ -76,51 +73,35 @@ typedef struct StatusInfo {
bool ntp_synced;
} StatusInfo;
-static const char *jump_str(int delta_minutes, char *s, size_t size) {
- if (delta_minutes == 60)
- return "one hour forward";
- if (delta_minutes == -60)
- return "one hour backwards";
- if (delta_minutes < 0) {
- snprintf(s, size, "%i minutes backwards", -delta_minutes);
- return s;
- }
- if (delta_minutes > 0) {
- snprintf(s, size, "%i minutes forward", delta_minutes);
- return s;
- }
- return "";
-}
-
static void print_status_info(const StatusInfo *i) {
char a[FORMAT_TIMESTAMP_MAX];
- char b[FORMAT_TIMESTAMP_MAX];
- char s[32];
struct tm tm;
time_t sec;
bool have_time = false;
- _cleanup_free_ char *zc = NULL, *zn = NULL;
- time_t t, tc, tn;
- int dn = 0;
- bool is_dstc = false, is_dstn = false;
+ const char *old_tz = NULL, *tz;
int r;
assert(i);
- /* Enforce the values of /etc/localtime */
- if (getenv("TZ")) {
- fprintf(stderr, "Warning: Ignoring the TZ variable. Reading the system's time zone setting only.\n\n");
- unsetenv("TZ");
- }
+ /* Save the old $TZ */
+ tz = getenv("TZ");
+ if (tz)
+ old_tz = strdupa(tz);
+
+ /* Set the new $TZ */
+ if (setenv("TZ", i->timezone, true) < 0)
+ log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
+ else
+ tzset();
if (i->time != 0) {
sec = (time_t) (i->time / USEC_PER_SEC);
have_time = true;
- } else if (arg_transport == BUS_TRANSPORT_LOCAL) {
+ } else if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
sec = time(NULL);
have_time = true;
} else
- fprintf(stderr, "Warning: Could not get time from timedated and not operating locally.\n\n");
+ log_warning("Could not get time from timedated and not operating locally, ignoring.");
if (have_time) {
xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
@@ -136,7 +117,7 @@ static void print_status_info(const StatusInfo *i) {
if (i->rtc_time > 0) {
time_t rtc_sec;
- rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC);
+ rtc_sec = (time_t) (i->rtc_time / USEC_PER_SEC);
xstrftime(a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
printf(" RTC time: %.*s\n", (int) sizeof(a), a);
} else
@@ -145,8 +126,18 @@ static void print_status_info(const StatusInfo *i) {
if (have_time)
xstrftime(a, "%Z, %z", localtime_r(&sec, &tm));
+ /* Restore the $TZ */
+ if (old_tz)
+ r = setenv("TZ", old_tz, true);
+ else
+ r = unsetenv("TZ");
+ if (r < 0)
+ log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
+ else
+ tzset();
+
printf(" Time zone: %s (%.*s)\n"
- " NTP enabled: %s\n"
+ " Network time on: %s\n"
"NTP synchronized: %s\n"
" RTC in local TZ: %s\n",
strna(i->timezone), (int) sizeof(a), have_time ? a : "n/a",
@@ -154,40 +145,6 @@ static void print_status_info(const StatusInfo *i) {
yes_no(i->ntp_synced),
yes_no(i->rtc_local));
- if (have_time) {
- r = time_get_dst(sec, "/etc/localtime",
- &tc, &zc, &is_dstc,
- &tn, &dn, &zn, &is_dstn);
- if (r < 0)
- printf(" DST active: %s\n", "n/a");
- else {
- printf(" DST active: %s\n", yes_no(is_dstc));
-
- t = tc - 1;
- xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm));
-
- xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm));
- printf(" Last DST change: DST %s at\n"
- " %.*s\n"
- " %.*s\n",
- is_dstc ? "began" : "ended",
- (int) sizeof(a), a,
- (int) sizeof(b), b);
-
- t = tn - 1;
- xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm));
- xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm));
- printf(" Next DST change: DST %s (the clock jumps %s) at\n"
- " %.*s\n"
- " %.*s\n",
- is_dstn ? "begins" : "ends",
- jump_str(dn, s, sizeof(s)),
- (int) sizeof(a), a,
- (int) sizeof(b), b);
- }
- } else
- printf(" DST active: %s\n", yes_no(is_dstc));
-
if (i->rtc_local)
fputs("\n" ANSI_HIGHLIGHT_ON
"Warning: The system is configured to read the RTC time in the local time zone. This\n"
@@ -375,7 +332,7 @@ static void help(void) {
" set-timezone ZONE Set system time zone\n"
" list-timezones Show known time zones\n"
" set-local-rtc BOOL Control whether RTC is in local time\n"
- " set-ntp BOOL Control whether NTP is enabled\n",
+ " set-ntp BOOL Enable or disable network time synchronization\n",
program_invocation_short_name);
}
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index 753c3d1d65..4e8ae94717 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -23,7 +23,6 @@
#include <string.h>
#include <unistd.h>
-#include "sd-id128.h"
#include "sd-messages.h"
#include "sd-event.h"
#include "sd-bus.h"
@@ -32,10 +31,8 @@
#include "strv.h"
#include "def.h"
#include "clock-util.h"
-#include "conf-files.h"
#include "path-util.h"
#include "fileio-label.h"
-#include "label.h"
#include "bus-util.h"
#include "bus-error.h"
#include "bus-common-errors.h"
@@ -46,7 +43,7 @@
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
static BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map timedated_errors[] = {
- SD_BUS_ERROR_MAP("org.freedesktop.timedate1.NoNTPSupport", ENOTSUP),
+ SD_BUS_ERROR_MAP("org.freedesktop.timedate1.NoNTPSupport", EOPNOTSUPP),
SD_BUS_ERROR_MAP_END
};
@@ -90,12 +87,9 @@ static int context_read_data(Context *c) {
c->zone = strdup(e);
if (!c->zone)
return log_oom();
-
- goto have_timezone;
}
}
-have_timezone:
if (isempty(c->zone)) {
free(c->zone);
c->zone = NULL;
@@ -188,7 +182,7 @@ static int context_write_data_local_rtc(Context *c) {
static int context_read_ntp(Context *c, sd_bus *bus) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *reply = NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *s;
int r;
@@ -225,38 +219,23 @@ static int context_read_ntp(Context *c, sd_bus *bus) {
return 0;
}
-static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) {
+static int context_start_ntp(sd_bus *bus, sd_bus_error *error, bool enabled) {
int r;
- assert(c);
assert(bus);
assert(error);
- if (c->use_ntp)
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartUnit",
- error,
- NULL,
- "ss",
- "systemd-timesyncd.service",
- "replace");
- else
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StopUnit",
- error,
- NULL,
- "ss",
- "systemd-timesyncd.service",
- "replace");
-
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ enabled ? "StartUnit" : "StopUnit",
+ error,
+ NULL,
+ "ss",
+ "systemd-timesyncd.service",
+ "replace");
if (r < 0) {
if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) ||
sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") ||
@@ -269,14 +248,13 @@ static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) {
return 0;
}
-static int context_enable_ntp(Context*c, sd_bus *bus, sd_bus_error *error) {
+static int context_enable_ntp(sd_bus *bus, sd_bus_error *error, bool enabled) {
int r;
- assert(c);
assert(bus);
assert(error);
- if (c->use_ntp)
+ if (enabled)
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -345,7 +323,7 @@ static int property_get_rtc_time(
log_debug("/dev/rtc not found.");
t = 0; /* no RTC found */
} else if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %s", strerror(-r));
+ return sd_bus_error_set_errnof(error, r, "Failed to read RTC: %m");
else
t = (usec_t) timegm(&tm) * USEC_PER_SEC;
@@ -376,14 +354,13 @@ static int property_get_ntp_sync(
return sd_bus_message_append(reply, "b", ntp_synced());
}
-static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_timezone(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *z;
int interactive;
char *t;
int r;
- assert(bus);
assert(m);
assert(c);
@@ -397,7 +374,14 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, s
if (streq_ptr(z, c->zone))
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-timezone", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_TIME,
+ "org.freedesktop.timedate1.set-timezone",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -414,7 +398,7 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, s
r = context_write_data_timezone(c);
if (r < 0) {
log_error_errno(r, "Failed to set time zone: %m");
- return sd_bus_error_set_errnof(error, r, "Failed to set time zone: %s", strerror(-r));
+ return sd_bus_error_set_errnof(error, r, "Failed to set time zone: %m");
}
/* 2. Tell the kernel our timezone */
@@ -436,18 +420,17 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, s
LOG_MESSAGE("Changed time zone to '%s'.", c->zone),
NULL);
- sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL);
+ (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL);
return sd_bus_reply_method_return(m, NULL);
}
-static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int lrtc, fix_system, interactive;
Context *c = userdata;
struct timespec ts;
int r;
- assert(bus);
assert(m);
assert(c);
@@ -458,7 +441,14 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata,
if (lrtc == c->local_rtc)
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-local-rtc", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_TIME,
+ "org.freedesktop.timedate1.set-local-rtc",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
@@ -470,7 +460,7 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata,
r = context_write_data_local_rtc(c);
if (r < 0) {
log_error_errno(r, "Failed to set RTC to local/UTC: %m");
- return sd_bus_error_set_errnof(error, r, "Failed to set RTC to local/UTC: %s", strerror(-r));
+ return sd_bus_error_set_errnof(error, r, "Failed to set RTC to local/UTC: %m");
}
/* 2. Tell the kernel our timezone */
@@ -519,26 +509,29 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata,
log_info("RTC configured to %s time.", c->local_rtc ? "local" : "UTC");
- sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC", NULL);
+ (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "LocalRTC", NULL);
return sd_bus_reply_method_return(m, NULL);
}
-static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
+static int method_set_time(sd_bus_message *m, void *userdata, sd_bus_error *error) {
int relative, interactive;
Context *c = userdata;
int64_t utc;
struct timespec ts;
+ usec_t start;
struct tm* tm;
int r;
- assert(bus);
assert(m);
assert(c);
if (c->use_ntp)
return sd_bus_error_setf(error, BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, "Automatic time synchronization is enabled");
+ /* this only gets used if dbus does not provide a timestamp */
+ start = now(CLOCK_MONOTONIC);
+
r = sd_bus_message_read(m, "xbb", &utc, &relative, &interactive);
if (r < 0)
return r;
@@ -563,12 +556,27 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu
} else
timespec_store(&ts, (usec_t) utc);
- r = bus_verify_polkit_async(m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-time", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_TIME,
+ "org.freedesktop.timedate1.set-time",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
return 1;
+ /* adjust ts for time spent in program */
+ r = sd_bus_message_get_monotonic_usec(m, &start);
+ /* when sd_bus_message_get_monotonic_usec() returns -ENODATA it does not modify &start */
+ if (r < 0 && r != -ENODATA)
+ return r;
+
+ timespec_store(&ts, timespec_load(&ts) + (now(CLOCK_MONOTONIC) - start));
+
/* Set system clock */
if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
log_error_errno(errno, "Failed to set local time: %m");
@@ -591,37 +599,46 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu
return sd_bus_reply_method_return(m, NULL);
}
-static int method_set_ntp(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
- int ntp, interactive;
+static int method_set_ntp(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ int enabled, interactive;
Context *c = userdata;
int r;
- r = sd_bus_message_read(m, "bb", &ntp, &interactive);
+ assert(m);
+ assert(c);
+
+ r = sd_bus_message_read(m, "bb", &enabled, &interactive);
if (r < 0)
return r;
- if ((bool)ntp == c->use_ntp)
+ if ((bool)enabled == c->use_ntp)
return sd_bus_reply_method_return(m, NULL);
- r = bus_verify_polkit_async(m, CAP_SYS_TIME, "org.freedesktop.timedate1.set-ntp", interactive, &c->polkit_registry, error);
+ r = bus_verify_polkit_async(
+ m,
+ CAP_SYS_TIME,
+ "org.freedesktop.timedate1.set-ntp",
+ interactive,
+ UID_INVALID,
+ &c->polkit_registry,
+ error);
if (r < 0)
return r;
if (r == 0)
return 1;
- c->use_ntp = ntp;
-
- r = context_enable_ntp(c, bus, error);
+ r = context_enable_ntp(sd_bus_message_get_bus(m), error, enabled);
if (r < 0)
return r;
- r = context_start_ntp(c, bus, error);
+ r = context_start_ntp(sd_bus_message_get_bus(m), error, enabled);
if (r < 0)
return r;
- log_info("Set NTP to %s", c->use_ntp ? "enabled" : "disabled");
+ c->use_ntp = enabled;
+ log_info("Set NTP to %s", enabled ? "enabled" : "disabled");
- sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
+ (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
return sd_bus_reply_method_return(m, NULL);
}
@@ -702,6 +719,8 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
+ (void) sd_bus_negotiate_timestamp(bus, true);
+
r = context_read_data(&context);
if (r < 0) {
log_error_errno(r, "Failed to read time zone data: %m");
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index be1f4bb151..df4d89a620 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "in-addr-util.h"
#include "timesyncd-manager.h"
#include "timesyncd-server.h"
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index 73ac7eecbf..88e9cf98ed 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -21,21 +21,15 @@
#include <stdlib.h>
#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
#include <time.h>
#include <math.h>
-#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/timerfd.h>
#include <sys/timex.h>
#include <sys/socket.h>
#include <resolv.h>
-#include <sys/prctl.h>
#include <sys/types.h>
-#include <grp.h>
#include "missing.h"
#include "util.h"
@@ -45,13 +39,8 @@
#include "list.h"
#include "ratelimit.h"
#include "strv.h"
-#include "conf-parser.h"
#include "sd-daemon.h"
-#include "event-util.h"
#include "network-util.h"
-#include "clock-util.h"
-#include "capability.h"
-#include "mkdir.h"
#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
#include "time-util.h"
@@ -680,6 +669,16 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm,
spike ? " (ignored)" : "");
+ if (!m->good) {
+ _cleanup_free_ char *pretty = NULL;
+
+ m->good = true;
+
+ server_address_pretty(m->current_server_address, &pretty);
+ log_info("Synchronized to time server %s (%s).", strna(pretty), m->current_server_name->string);
+ sd_notifyf(false, "STATUS=Synchronized to time server %s (%s).", strna(pretty), m->current_server_name->string);
+ }
+
r = manager_arm_timer(m, m->poll_interval_usec);
if (r < 0)
return log_error_errno(r, "Failed to rearm timer: %m");
@@ -735,13 +734,14 @@ static int manager_begin(Manager *m) {
assert_return(m->current_server_name, -EHOSTUNREACH);
assert_return(m->current_server_address, -EHOSTUNREACH);
+ m->good = false;
m->missed_replies = NTP_MAX_MISSED_REPLIES;
if (m->poll_interval_usec == 0)
m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
server_address_pretty(m->current_server_address, &pretty);
- log_debug("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string);
- sd_notifyf(false, "STATUS=Using Time Server %s (%s).", strna(pretty), m->current_server_name->string);
+ log_debug("Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
+ sd_notifyf(false, "STATUS=Connecting to time server %s (%s).", strna(pretty), m->current_server_name->string);
r = manager_clock_watch_setup(m);
if (r < 0)
diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h
index c7efdc5dfb..090b2fcba8 100644
--- a/src/timesync/timesyncd-manager.h
+++ b/src/timesync/timesyncd-manager.h
@@ -25,7 +25,6 @@
#include "sd-resolve.h"
#include "sd-network.h"
#include "list.h"
-#include "socket-util.h"
#include "ratelimit.h"
typedef struct Manager Manager;
@@ -56,6 +55,7 @@ struct Manager {
int missed_replies;
uint64_t packet_count;
sd_event_source *event_timeout;
+ bool good;
/* last sent packet */
struct timespec trans_time_mon;
diff --git a/src/timesync/timesyncd-server.h b/src/timesync/timesyncd-server.h
index 243b44a0eb..18c44445e1 100644
--- a/src/timesync/timesyncd-server.h
+++ b/src/timesync/timesyncd-server.h
@@ -59,7 +59,7 @@ struct ServerName {
int server_address_new(ServerName *n, ServerAddress **ret, const union sockaddr_union *sockaddr, socklen_t socklen);
ServerAddress* server_address_free(ServerAddress *a);
static inline int server_address_pretty(ServerAddress *a, char **pretty) {
- return sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, pretty);
+ return sockaddr_pretty(&a->sockaddr.sa, a->socklen, true, true, pretty);
}
int server_name_new(Manager *m, ServerName **ret, ServerType type,const char *string);
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 2a73dac033..d69129ee03 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -21,10 +21,10 @@
#include "sd-event.h"
#include "sd-daemon.h"
-#include "mkdir.h"
#include "capability.h"
#include "clock-util.h"
#include "network-util.h"
+#include "signal-util.h"
#include "timesyncd-manager.h"
#include "timesyncd-conf.h"
diff --git a/src/timesync/timesyncd.conf.in b/src/timesync/timesyncd.conf.in
index fc3c6c49cf..b6a2ada273 100644
--- a/src/timesync/timesyncd.conf.in
+++ b/src/timesync/timesyncd.conf.in
@@ -5,10 +5,11 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
-# You can override the directives in this file by creating files in
-# /etc/systemd/timesyncd.conf.d/*.conf.
+# Entries in this file show the compile time defaults.
+# You can change settings by editing this file.
+# Defaults can be restored by simply deleting this file.
#
-# See timesyncd.conf(5) for details
+# See timesyncd.conf(5) for details.
[Time]
#NTP=
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index c948d4d218..f7dad8491e 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -26,8 +26,6 @@
#include <string.h>
#include <limits.h>
#include <dirent.h>
-#include <grp.h>
-#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -37,9 +35,8 @@
#include <glob.h>
#include <fnmatch.h>
#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/param.h>
#include <sys/xattr.h>
+#include <linux/fs.h>
#include "log.h"
#include "util.h"
@@ -55,9 +52,11 @@
#include "specifier.h"
#include "build.h"
#include "copy.h"
+#include "rm-rf.h"
#include "selinux-util.h"
#include "btrfs-util.h"
#include "acl-util.h"
+#include "formats-util.h"
/* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
* them in the file system. This is intended to be used to create
@@ -78,18 +77,20 @@ typedef enum ItemType {
COPY_FILES = 'C',
/* These ones take globs */
+ WRITE_FILE = 'w',
SET_XATTR = 't',
RECURSIVE_SET_XATTR = 'T',
SET_ACL = 'a',
RECURSIVE_SET_ACL = 'A',
- WRITE_FILE = 'w',
+ SET_ATTRIBUTE = 'h',
+ RECURSIVE_SET_ATTRIBUTE = 'H',
IGNORE_PATH = 'x',
IGNORE_DIRECTORY_PATH = 'X',
REMOVE_PATH = 'r',
RECURSIVE_REMOVE_PATH = 'R',
- ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
RELABEL_PATH = 'z',
RECURSIVE_RELABEL_PATH = 'Z',
+ ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
} ItemType;
typedef struct Item {
@@ -108,12 +109,15 @@ typedef struct Item {
usec_t age;
dev_t major_minor;
+ unsigned attribute_value;
+ unsigned attribute_mask;
bool uid_set:1;
bool gid_set:1;
bool mode_set:1;
bool age_set:1;
bool mask_perms:1;
+ bool attribute_set:1;
bool keep_first_level:1;
@@ -141,9 +145,17 @@ static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
#define MAX_DEPTH 256
-static Hashmap *items = NULL, *globs = NULL;
+static OrderedHashmap *items = NULL, *globs = NULL;
static Set *unix_sockets = NULL;
+static const Specifier specifier_table[] = {
+ { 'm', specifier_machine_id, NULL },
+ { 'b', specifier_boot_id, NULL },
+ { 'H', specifier_host_name, NULL },
+ { 'v', specifier_kernel_release, NULL },
+ {}
+};
+
static bool needs_glob(ItemType t) {
return IN_SET(t,
WRITE_FILE,
@@ -157,7 +169,9 @@ static bool needs_glob(ItemType t) {
SET_XATTR,
RECURSIVE_SET_XATTR,
SET_ACL,
- RECURSIVE_SET_ACL);
+ RECURSIVE_SET_ACL,
+ SET_ATTRIBUTE,
+ RECURSIVE_SET_ATTRIBUTE);
}
static bool takes_ownership(ItemType t) {
@@ -172,7 +186,6 @@ static bool takes_ownership(ItemType t) {
CREATE_CHAR_DEVICE,
CREATE_BLOCK_DEVICE,
COPY_FILES,
-
WRITE_FILE,
IGNORE_PATH,
IGNORE_DIRECTORY_PATH,
@@ -180,11 +193,11 @@ static bool takes_ownership(ItemType t) {
RECURSIVE_REMOVE_PATH);
}
-static struct Item* find_glob(Hashmap *h, const char *match) {
+static struct Item* find_glob(OrderedHashmap *h, const char *match) {
ItemArray *j;
Iterator i;
- HASHMAP_FOREACH(j, h, i) {
+ ORDERED_HASHMAP_FOREACH(j, h, i) {
unsigned n;
for (n = 0; n < j->count; n++) {
@@ -312,16 +325,16 @@ static DIR* xopendirat_nomod(int dirfd, const char *path) {
DIR *dir;
dir = xopendirat(dirfd, path, O_NOFOLLOW|O_NOATIME);
- if (!dir) {
- log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m",
- dirfd == AT_FDCWD ? "" : "sub", path);
- if (errno == EPERM) {
- dir = xopendirat(dirfd, path, O_NOFOLLOW);
- if (!dir)
- log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m",
- dirfd == AT_FDCWD ? "" : "sub", path);
- }
- }
+ if (dir)
+ return dir;
+
+ log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
+ if (errno != EPERM)
+ return NULL;
+
+ dir = xopendirat(dirfd, path, O_NOFOLLOW);
+ if (!dir)
+ log_debug_errno(errno, "Cannot open %sdirectory \"%s\": %m", dirfd == AT_FDCWD ? "" : "sub", path);
return dir;
}
@@ -395,7 +408,7 @@ static int dir_cleanup(
}
/* Is there an item configured for this path? */
- if (hashmap_get(items, sub_path)) {
+ if (ordered_hashmap_get(items, sub_path)) {
log_debug("Ignoring \"%s\": a separate entry exists.", sub_path);
continue;
}
@@ -570,56 +583,73 @@ finish:
}
static int path_set_perms(Item *i, const char *path) {
+ _cleanup_close_ int fd = -1;
struct stat st;
- bool st_valid;
assert(i);
assert(path);
- st_valid = stat(path, &st) == 0;
+ /* We open the file with O_PATH here, to make the operation
+ * somewhat atomic. Also there's unfortunately no fchmodat()
+ * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
+ * O_PATH. */
- /* not using i->path directly because it may be a glob */
- if (i->mode_set) {
- mode_t m = i->mode;
+ fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME);
+ if (fd < 0)
+ return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path);
- if (i->mask_perms && st_valid) {
- if (!(st.st_mode & 0111))
- m &= ~0111;
- if (!(st.st_mode & 0222))
+ if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
+ return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+
+ if (S_ISLNK(st.st_mode))
+ log_debug("Skipping mode an owner fix for symlink %s.", path);
+ else {
+ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ xsprintf(fn, "/proc/self/fd/%i", fd);
+
+ /* not using i->path directly because it may be a glob */
+ if (i->mode_set) {
+ mode_t m = i->mode;
+
+ if (i->mask_perms) {
+ if (!(st.st_mode & 0111))
+ m &= ~0111;
+ if (!(st.st_mode & 0222))
m &= ~0222;
- if (!(st.st_mode & 0444))
- m &= ~0444;
- if (!S_ISDIR(st.st_mode))
- m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
- }
+ if (!(st.st_mode & 0444))
+ m &= ~0444;
+ if (!S_ISDIR(st.st_mode))
+ m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
+ }
- if (st_valid && m == (st.st_mode & 07777))
- log_debug("\"%s\" has right mode %o", path, st.st_mode);
- else {
- log_debug("chmod \"%s\" to mode %o", path, m);
- if (chmod(path, m) < 0)
- return log_error_errno(errno, "chmod(%s) failed: %m", path);
+ if (m == (st.st_mode & 07777))
+ log_debug("\"%s\" has right mode %o", path, st.st_mode);
+ else {
+ log_debug("chmod \"%s\" to mode %o", path, m);
+ if (chmod(fn, m) < 0)
+ return log_error_errno(errno, "chmod(%s) failed: %m", path);
+ }
}
- }
-
- if ((!st_valid || i->uid != st.st_uid || i->gid != st.st_gid) &&
- (i->uid_set || i->gid_set)) {
- log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
- path,
- i->uid_set ? i->uid : UID_INVALID,
- i->gid_set ? i->gid : GID_INVALID);
- if (chown(path,
- i->uid_set ? i->uid : UID_INVALID,
- i->gid_set ? i->gid : GID_INVALID) < 0)
+ if ((i->uid != st.st_uid || i->gid != st.st_gid) &&
+ (i->uid_set || i->gid_set)) {
+ log_debug("chown \"%s\" to "UID_FMT"."GID_FMT,
+ path,
+ i->uid_set ? i->uid : UID_INVALID,
+ i->gid_set ? i->gid : GID_INVALID);
+ if (chown(fn,
+ i->uid_set ? i->uid : UID_INVALID,
+ i->gid_set ? i->gid : GID_INVALID) < 0)
return log_error_errno(errno, "chown(%s) failed: %m", path);
+ }
}
+ fd = safe_close(fd);
+
return label_fix(path, false, false);
}
-static int get_xattrs_from_arg(Item *i) {
- char *xattr;
+static int parse_xattrs_from_arg(Item *i) {
const char *p;
int r;
@@ -628,35 +658,37 @@ static int get_xattrs_from_arg(Item *i) {
p = i->argument;
- while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
- _cleanup_free_ char *tmp = NULL, *name = NULL,
- *value = NULL, *value2 = NULL, *_xattr = xattr;
+ for (;;) {
+ _cleanup_free_ char *name = NULL, *value = NULL, *xattr = NULL, *xattr_replaced = NULL;
+
+ r = unquote_first_word(&p, &xattr, UNQUOTE_CUNESCAPE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse extended attribute '%s', ignoring: %m", p);
+ if (r <= 0)
+ break;
- r = split_pair(xattr, "=", &name, &value);
+ r = specifier_printf(xattr, specifier_table, NULL, &xattr_replaced);
+ if (r < 0)
+ return log_error_errno(r, "Failed to replace specifiers in extended attribute '%s': %m", xattr);
+
+ r = split_pair(xattr_replaced, "=", &name, &value);
if (r < 0) {
- log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
+ log_warning_errno(r, "Failed to parse extended attribute, ignoring: %s", xattr);
continue;
}
- if (strempty(name) || strempty(value)) {
- log_warning("Malformed xattr found: \"%s\" - ignoring.", xattr);
+ if (isempty(name) || isempty(value)) {
+ log_warning("Malformed extended attribute found, ignoring: %s", xattr);
continue;
}
- tmp = unquote(value, "\"");
- if (!tmp)
+ if (strv_push_pair(&i->xattrs, name, value) < 0)
return log_oom();
- value2 = cunescape(tmp);
- if (!value2)
- return log_oom();
-
- if (strv_push_pair(&i->xattrs, name, value2) < 0)
- return log_oom();
- name = value2 = NULL;
+ name = value = NULL;
}
- return r;
+ return 0;
}
static int path_set_xattrs(Item *i, const char *path) {
@@ -669,17 +701,16 @@ static int path_set_xattrs(Item *i, const char *path) {
int n;
n = strlen(*value);
- log_debug("\"%s\": setting xattr \"%s=%s\"", path, *name, *value);
+ log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
if (lsetxattr(path, *name, *value, n, 0) < 0) {
- log_error("Setting extended attribute %s=%s on %s failed: %m",
- *name, *value, path);
+ log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
return -errno;
}
}
return 0;
}
-static int get_acls_from_arg(Item *item) {
+static int parse_acls_from_arg(Item *item) {
#ifdef HAVE_ACL
int r;
@@ -687,10 +718,10 @@ static int get_acls_from_arg(Item *item) {
/* If force (= modify) is set, we will not modify the acl
* afterwards, so the mask can be added now if necessary. */
+
r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force);
if (r < 0)
- log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring",
- item->argument);
+ log_warning_errno(r, "Failed to parse ACL \"%s\": %m. Ignoring", item->argument);
#else
log_warning_errno(ENOSYS, "ACLs are not supported. Ignoring");
#endif
@@ -699,10 +730,13 @@ static int get_acls_from_arg(Item *item) {
}
#ifdef HAVE_ACL
-static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) {
+static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) {
+ _cleanup_(acl_free_charpp) char *t = NULL;
_cleanup_(acl_freep) acl_t dup = NULL;
int r;
- _cleanup_(acl_free_charpp) char *t = NULL;
+
+ /* Returns 0 for success, positive error if already warned,
+ * negative error otherwise. */
if (modify) {
r = acls_for_file(path, type, acl, &dup);
@@ -725,39 +759,204 @@ static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modif
return r;
t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
- log_debug("\"%s\": setting %s ACL \"%s\"", path,
+ log_debug("Setting %s ACL %s on %s.",
type == ACL_TYPE_ACCESS ? "access" : "default",
- strna(t));
+ strna(t), pretty);
r = acl_set_file(path, type, dup);
if (r < 0)
- return log_error_errno(-errno,
- "Setting %s ACL \"%s\" on %s failed: %m",
- type == ACL_TYPE_ACCESS ? "access" : "default",
- strna(t), path);
+ /* Return positive to indicate we already warned */
+ return -log_error_errno(errno,
+ "Setting %s ACL \"%s\" on %s failed: %m",
+ type == ACL_TYPE_ACCESS ? "access" : "default",
+ strna(t), pretty);
+
return 0;
}
#endif
static int path_set_acls(Item *item, const char *path) {
+ int r = 0;
#ifdef HAVE_ACL
- int r;
+ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ _cleanup_close_ int fd = -1;
+ struct stat st;
assert(item);
assert(path);
- if (item->acl_access) {
- r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force);
- if (r < 0)
- return r;
- }
+ fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME);
+ if (fd < 0)
+ return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
- if (item->acl_default) {
- r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
- if (r < 0)
- return r;
+ if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
+ return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
+
+ if (S_ISLNK(st.st_mode)) {
+ log_debug("Skipping ACL fix for symlink %s.", path);
+ return 0;
}
+
+ xsprintf(fn, "/proc/self/fd/%i", fd);
+
+ if (item->acl_access)
+ r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
+
+ if (r == 0 && item->acl_default)
+ r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
+
+ if (r > 0)
+ return -r; /* already warned */
+ else if (r == -EOPNOTSUPP) {
+ log_debug_errno(r, "ACLs not supported by file system at %s", path);
+ return 0;
+ } else if (r < 0)
+ log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
#endif
+ return r;
+}
+
+#define ATTRIBUTES_ALL \
+ (FS_NOATIME_FL | \
+ FS_SYNC_FL | \
+ FS_DIRSYNC_FL | \
+ FS_APPEND_FL | \
+ FS_COMPR_FL | \
+ FS_NODUMP_FL | \
+ FS_EXTENT_FL | \
+ FS_IMMUTABLE_FL | \
+ FS_JOURNAL_DATA_FL | \
+ FS_SECRM_FL | \
+ FS_UNRM_FL | \
+ FS_NOTAIL_FL | \
+ FS_TOPDIR_FL | \
+ FS_NOCOW_FL)
+
+static int parse_attribute_from_arg(Item *item) {
+
+ static const struct {
+ char character;
+ unsigned value;
+ } attributes[] = {
+ { 'A', FS_NOATIME_FL }, /* do not update atime */
+ { 'S', FS_SYNC_FL }, /* Synchronous updates */
+ { 'D', FS_DIRSYNC_FL }, /* dirsync behaviour (directories only) */
+ { 'a', FS_APPEND_FL }, /* writes to file may only append */
+ { 'c', FS_COMPR_FL }, /* Compress file */
+ { 'd', FS_NODUMP_FL }, /* do not dump file */
+ { 'e', FS_EXTENT_FL }, /* Top of directory hierarchies*/
+ { 'i', FS_IMMUTABLE_FL }, /* Immutable file */
+ { 'j', FS_JOURNAL_DATA_FL }, /* Reserved for ext3 */
+ { 's', FS_SECRM_FL }, /* Secure deletion */
+ { 'u', FS_UNRM_FL }, /* Undelete */
+ { 't', FS_NOTAIL_FL }, /* file tail should not be merged */
+ { 'T', FS_TOPDIR_FL }, /* Top of directory hierarchies*/
+ { 'C', FS_NOCOW_FL }, /* Do not cow file */
+ };
+
+ enum {
+ MODE_ADD,
+ MODE_DEL,
+ MODE_SET
+ } mode = MODE_ADD;
+
+ unsigned value = 0, mask = 0;
+ const char *p;
+
+ assert(item);
+
+ p = item->argument;
+ if (p) {
+ if (*p == '+') {
+ mode = MODE_ADD;
+ p++;
+ } else if (*p == '-') {
+ mode = MODE_DEL;
+ p++;
+ } else if (*p == '=') {
+ mode = MODE_SET;
+ p++;
+ }
+ }
+
+ if (isempty(p) && mode != MODE_SET) {
+ log_error("Setting file attribute on '%s' needs an attribute specification.", item->path);
+ return -EINVAL;
+ }
+
+ for (; p && *p ; p++) {
+ unsigned i, v;
+
+ for (i = 0; i < ELEMENTSOF(attributes); i++)
+ if (*p == attributes[i].character)
+ break;
+
+ if (i >= ELEMENTSOF(attributes)) {
+ log_error("Unknown file attribute '%c' on '%s'.", *p, item->path);
+ return -EINVAL;
+ }
+
+ v = attributes[i].value;
+
+ if (mode == MODE_ADD || mode == MODE_SET)
+ value |= v;
+ else
+ value &= ~v;
+
+ mask |= v;
+ }
+
+ if (mode == MODE_SET)
+ mask |= ATTRIBUTES_ALL;
+
+ assert(mask != 0);
+
+ item->attribute_mask = mask;
+ item->attribute_value = value;
+ item->attribute_set = true;
+
+ return 0;
+}
+
+static int path_set_attribute(Item *item, const char *path) {
+ _cleanup_close_ int fd = -1;
+ struct stat st;
+ unsigned f;
+ int r;
+
+ if (!item->attribute_set || item->attribute_mask == 0)
+ return 0;
+
+ fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOATIME|O_NOFOLLOW);
+ if (fd < 0) {
+ if (errno == ELOOP)
+ return log_error_errno(errno, "Skipping file attributes adjustment on symlink %s.", path);
+
+ return log_error_errno(errno, "Cannot open '%s': %m", path);
+ }
+
+ if (fstat(fd, &st) < 0)
+ return log_error_errno(errno, "Cannot stat '%s': %m", path);
+
+ /* Issuing the file attribute ioctls on device nodes is not
+ * safe, as that will be delivered to the drivers, not the
+ * file system containing the device node. */
+ if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
+ log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path);
+ return -EINVAL;
+ }
+
+ f = item->attribute_value & item->attribute_mask;
+
+ /* Mask away directory-specific flags */
+ if (!S_ISDIR(st.st_mode))
+ f &= ~FS_DIRSYNC_FL;
+
+ r = chattr_fd(fd, f, item->attribute_mask);
+ if (r < 0)
+ return log_error_errno(r,
+ "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
+ path, item->attribute_value, item->attribute_mask);
return 0;
}
@@ -785,21 +984,28 @@ static int write_one_file(Item *i, const char *path) {
return 0;
}
- log_error_errno(errno, "Failed to create file %s: %m", path);
- return -errno;
+ r = -errno;
+ if (!i->argument && errno == EROFS && stat(path, &st) == 0 &&
+ (i->type == CREATE_FILE || st.st_size == 0))
+ goto check_mode;
+
+ return log_error_errno(r, "Failed to create file %s: %m", path);
}
if (i->argument) {
- _cleanup_free_ char *unescaped;
+ _cleanup_free_ char *unescaped = NULL, *replaced = NULL;
- log_debug("%s to \"%s\".",
- i->type == CREATE_FILE ? "Appending" : "Writing", path);
+ log_debug("%s to \"%s\".", i->type == CREATE_FILE ? "Appending" : "Writing", path);
- unescaped = cunescape(i->argument);
- if (!unescaped)
- return log_oom();
+ r = cunescape(i->argument, 0, &unescaped);
+ if (r < 0)
+ return log_error_errno(r, "Failed to unescape parameter to write: %s", i->argument);
- r = loop_write(fd, unescaped, strlen(unescaped), false);
+ r = specifier_printf(unescaped, specifier_table, NULL, &replaced);
+ if (r < 0)
+ return log_error_errno(r, "Failed to replace specifiers in parameter to write '%s': %m", unescaped);
+
+ r = loop_write(fd, replaced, strlen(replaced), false);
if (r < 0)
return log_error_errno(r, "Failed to write file \"%s\": %m", path);
} else
@@ -810,6 +1016,7 @@ static int write_one_file(Item *i, const char *path) {
if (stat(path, &st) < 0)
return log_error_errno(errno, "stat(%s) failed: %m", path);
+ check_mode:
if (!S_ISREG(st.st_mode)) {
log_error("%s is not a file.", path);
return -EEXIST;
@@ -921,6 +1128,7 @@ static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
static int create_item(Item *i) {
+ _cleanup_free_ char *resolved = NULL;
struct stat st;
int r = 0;
CreationMode creation;
@@ -944,17 +1152,25 @@ static int create_item(Item *i) {
return r;
break;
- case COPY_FILES:
- log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
- r = copy_tree(i->argument, i->path, false);
+ case COPY_FILES: {
+ r = specifier_printf(i->argument, specifier_table, NULL, &resolved);
+ if (r < 0)
+ return log_error_errno(r, "Failed to substitute specifiers in copy source %s: %m", i->argument);
+
+ log_debug("Copying tree \"%s\" to \"%s\".", resolved, i->path);
+ r = copy_tree(resolved, i->path, false);
+
+ if (r == -EROFS && stat(i->path, &st) == 0)
+ r = -EEXIST;
+
if (r < 0) {
struct stat a, b;
if (r != -EEXIST)
return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
- if (stat(i->argument, &a) < 0)
- return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
+ if (stat(resolved, &a) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", resolved);
if (stat(i->path, &b) < 0)
return log_error_errno(errno, "stat(%s) failed: %m", i->path);
@@ -998,20 +1214,25 @@ static int create_item(Item *i) {
r = mkdir_label(i->path, i->mode);
if (r < 0) {
- if (r != -EEXIST)
- return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
+ int k;
- if (stat(i->path, &st) < 0)
- return log_error_errno(errno, "stat(%s) failed: %m", i->path);
+ if (r != -EEXIST && r != -EROFS)
+ return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
- if (!S_ISDIR(st.st_mode)) {
- log_debug("\"%s\" already exists and is not a directory.", i->path);
+ k = is_dir(i->path, false);
+ if (k == -ENOENT && r == -EROFS)
+ return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", i->path);
+ if (k < 0)
+ return log_error_errno(k, "Failed to check if %s exists: %m", i->path);
+ if (!k) {
+ log_warning("\"%s\" already exists and is not a directory.", i->path);
return 0;
}
creation = CREATION_EXISTING;
} else
creation = CREATION_NORMAL;
+
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
r = path_set_perms(i, i->path);
@@ -1032,13 +1253,12 @@ static int create_item(Item *i) {
if (errno != EEXIST)
return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
- if (stat(i->path, &st) < 0)
+ if (lstat(i->path, &st) < 0)
return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if (!S_ISFIFO(st.st_mode)) {
if (i->force) {
-
RUN_WITH_UMASK(0000) {
mac_selinux_create_file_prepare(i->path, S_IFIFO);
r = mkfifo_atomic(i->path, i->mode);
@@ -1049,7 +1269,7 @@ static int create_item(Item *i) {
return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
creation = CREATION_FORCE;
} else {
- log_debug("%s is not a fifo.", i->path);
+ log_warning("\"%s\" already exists and is not a fifo.", i->path);
return 0;
}
} else
@@ -1063,29 +1283,34 @@ static int create_item(Item *i) {
return r;
break;
+ }
- case CREATE_SYMLINK:
+ case CREATE_SYMLINK: {
+ r = specifier_printf(i->argument, specifier_table, NULL, &resolved);
+ if (r < 0)
+ return log_error_errno(r, "Failed to substitute specifiers in symlink target %s: %m", i->argument);
mac_selinux_create_file_prepare(i->path, S_IFLNK);
- r = symlink(i->argument, i->path);
+ r = symlink(resolved, i->path);
mac_selinux_create_file_clear();
if (r < 0) {
_cleanup_free_ char *x = NULL;
if (errno != EEXIST)
- return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
+ return log_error_errno(errno, "symlink(%s, %s) failed: %m", resolved, i->path);
r = readlink_malloc(i->path, &x);
- if (r < 0 || !streq(i->argument, x)) {
+ if (r < 0 || !streq(resolved, x)) {
if (i->force) {
mac_selinux_create_file_prepare(i->path, S_IFLNK);
- r = symlink_atomic(i->argument, i->path);
+ r = symlink_atomic(resolved, i->path);
mac_selinux_create_file_clear();
if (r < 0)
- return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
+ return log_error_errno(r, "symlink(%s, %s) failed: %m", resolved, i->path);
+
creation = CREATION_FORCE;
} else {
log_debug("\"%s\" is not a symlink or does not point to the correct path.", i->path);
@@ -1094,10 +1319,11 @@ static int create_item(Item *i) {
} else
creation = CREATION_EXISTING;
} else
+
creation = CREATION_NORMAL;
log_debug("%s symlink \"%s\".", creation_mode_verb_to_string(creation), i->path);
-
break;
+ }
case CREATE_BLOCK_DEVICE:
case CREATE_CHAR_DEVICE: {
@@ -1131,7 +1357,7 @@ static int create_item(Item *i) {
if (errno != EEXIST)
return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
- if (stat(i->path, &st) < 0)
+ if (lstat(i->path, &st) < 0)
return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if ((st.st_mode & S_IFMT) != file_type) {
@@ -1155,6 +1381,7 @@ static int create_item(Item *i) {
creation = CREATION_EXISTING;
} else
creation = CREATION_NORMAL;
+
log_debug("%s %s device node \"%s\" %u:%u.",
creation_mode_verb_to_string(creation),
i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
@@ -1203,9 +1430,19 @@ static int create_item(Item *i) {
if (r < 0)
return r;
break;
- }
- log_debug("%s created successfully.", i->path);
+ case SET_ATTRIBUTE:
+ r = glob_item(i, path_set_attribute, false);
+ if (r < 0)
+ return r;
+ break;
+
+ case RECURSIVE_SET_ATTRIBUTE:
+ r = glob_item(i, path_set_attribute, true);
+ if (r < 0)
+ return r;
+ break;
+ }
return 0;
}
@@ -1228,7 +1465,7 @@ static int remove_item_instance(Item *i, const char *instance) {
/* FIXME: we probably should use dir_cleanup() here
* instead of rm_rf() so that 'x' is honoured. */
log_debug("rm -rf \"%s\"", instance);
- r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
+ r = rm_rf(instance, (i->type == RECURSIVE_REMOVE_PATH ? REMOVE_ROOT : 0) | REMOVE_PHYSICAL);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "rm_rf(%s): %m", instance);
@@ -1269,6 +1506,8 @@ static int remove_item(Item *i) {
case RECURSIVE_SET_XATTR:
case SET_ACL:
case RECURSIVE_SET_ACL:
+ case SET_ATTRIBUTE:
+ case RECURSIVE_SET_ATTRIBUTE:
break;
case REMOVE_PATH:
@@ -1378,7 +1617,7 @@ static int process_item(Item *i) {
PATH_FOREACH_PREFIX(prefix, i->path) {
ItemArray *j;
- j = hashmap_get(items, prefix);
+ j = ordered_hashmap_get(items, prefix);
if (j) {
int s;
@@ -1437,6 +1676,20 @@ static void item_array_free(ItemArray *a) {
free(a);
}
+static int item_compare(const void *a, const void *b) {
+ const Item *x = a, *y = b;
+
+ /* Make sure that the ownership taking item is put first, so
+ * that we first create the node, and then can adjust it */
+
+ if (takes_ownership(x->type) && !takes_ownership(y->type))
+ return -1;
+ if (!takes_ownership(x->type) && takes_ownership(y->type))
+ return 1;
+
+ return (int) x->type - (int) y->type;
+}
+
static bool item_compatible(Item *a, Item *b) {
assert(a);
assert(b);
@@ -1494,39 +1747,40 @@ static bool should_include_path(const char *path) {
static int parse_line(const char *fname, unsigned line, const char *buffer) {
- static const Specifier specifier_table[] = {
- { 'm', specifier_machine_id, NULL },
- { 'b', specifier_boot_id, NULL },
- { 'H', specifier_host_name, NULL },
- { 'v', specifier_kernel_release, NULL },
- {}
- };
-
_cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
_cleanup_(item_free_contents) Item i = {};
ItemArray *existing;
- Hashmap *h;
- int r, c = -1, pos;
+ OrderedHashmap *h;
+ int r, pos;
bool force = false, boot = false;
assert(fname);
assert(line >= 1);
assert(buffer);
- r = sscanf(buffer,
- "%ms %ms %ms %ms %ms %ms %n",
- &action,
- &path,
- &mode,
- &user,
- &group,
- &age,
- &c);
- if (r < 2) {
+ r = unquote_many_words(
+ &buffer,
+ 0,
+ &action,
+ &path,
+ &mode,
+ &user,
+ &group,
+ &age,
+ NULL);
+ if (r < 0)
+ return log_error_errno(r, "[%s:%u] Failed to parse line: %m", fname, line);
+ else if (r < 2) {
log_error("[%s:%u] Syntax error.", fname, line);
return -EIO;
}
+ if (!isempty(buffer) && !streq(buffer, "-")) {
+ i.argument = strdup(buffer);
+ if (!i.argument)
+ return log_oom();
+ }
+
if (isempty(action)) {
log_error("[%s:%u] Command too short '%s'.", fname, line, action);
return -EINVAL;
@@ -1559,19 +1813,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
return r;
}
- if (c >= 0) {
- c += strspn(buffer+c, WHITESPACE);
- if (buffer[c] != 0 && (buffer[c] != '-' || buffer[c+1] != 0)) {
- i.argument = unquote(buffer+c, "\"");
- if (!i.argument)
- return log_oom();
- }
- }
-
switch (i.type) {
- case CREATE_FILE:
- case TRUNCATE_FILE:
case CREATE_DIRECTORY:
case CREATE_SUBVOLUME:
case TRUNCATE_DIRECTORY:
@@ -1583,6 +1826,13 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
case ADJUST_MODE:
case RELABEL_PATH:
case RECURSIVE_RELABEL_PATH:
+ if (i.argument)
+ log_warning("[%s:%u] %c lines don't take argument fields, ignoring.", fname, line, i.type);
+
+ break;
+
+ case CREATE_FILE:
+ case TRUNCATE_FILE:
break;
case CREATE_SYMLINK:
@@ -1637,7 +1887,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
return -EBADMSG;
}
- r = get_xattrs_from_arg(&i);
+ r = parse_xattrs_from_arg(&i);
if (r < 0)
return r;
break;
@@ -1648,7 +1898,18 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
log_error("[%s:%u] Set ACLs requires argument.", fname, line);
return -EBADMSG;
}
- r = get_acls_from_arg(&i);
+ r = parse_acls_from_arg(&i);
+ if (r < 0)
+ return r;
+ break;
+
+ case SET_ATTRIBUTE:
+ case RECURSIVE_SET_ATTRIBUTE:
+ if (!i.argument) {
+ log_error("[%s:%u] Set file attribute requires argument.", fname, line);
+ return -EBADMSG;
+ }
+ r = parse_attribute_from_arg(&i);
if (r < 0)
return r;
break;
@@ -1671,7 +1932,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
if (arg_root) {
char *p;
- p = strappend(arg_root, i.path);
+ p = prefix_root(arg_root, i.path);
if (!p)
return log_oom();
@@ -1679,7 +1940,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
i.path = p;
}
- if (user && !streq(user, "-")) {
+ if (!isempty(user) && !streq(user, "-")) {
const char *u = user;
r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
@@ -1691,7 +1952,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
i.uid_set = true;
}
- if (group && !streq(group, "-")) {
+ if (!isempty(group) && !streq(group, "-")) {
const char *g = group;
r = get_group_creds(&g, &i.gid);
@@ -1703,7 +1964,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
i.gid_set = true;
}
- if (mode && !streq(mode, "-")) {
+ if (!isempty(mode) && !streq(mode, "-")) {
const char *mm = mode;
unsigned m;
@@ -1712,9 +1973,9 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
mm++;
}
- if (sscanf(mm, "%o", &m) != 1) {
+ if (parse_mode(mm, &m) < 0) {
log_error("[%s:%u] Invalid mode '%s'.", fname, line, mode);
- return -ENOENT;
+ return -EBADMSG;
}
i.mode = m;
@@ -1723,7 +1984,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
? 0755 : 0644;
- if (age && !streq(age, "-")) {
+ if (!isempty(age) && !streq(age, "-")) {
const char *a = age;
if (*a == '~') {
@@ -1741,18 +2002,20 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
h = needs_glob(i.type) ? globs : items;
- existing = hashmap_get(h, i.path);
+ existing = ordered_hashmap_get(h, i.path);
if (existing) {
unsigned n;
for (n = 0; n < existing->count; n++) {
- if (!item_compatible(existing->items + n, &i))
+ if (!item_compatible(existing->items + n, &i)) {
log_warning("[%s:%u] Duplicate line for path \"%s\", ignoring.",
fname, line, i.path);
+ return 0;
+ }
}
} else {
existing = new0(ItemArray, 1);
- r = hashmap_put(h, i.path, existing);
+ r = ordered_hashmap_put(h, i.path, existing);
if (r < 0)
return log_oom();
}
@@ -1761,6 +2024,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
return log_oom();
memcpy(existing->items + existing->count++, &i, sizeof(i));
+
+ /* Sort item array, to enforce stable ordering of application */
+ qsort_safe(existing->items, existing->count, sizeof(Item), item_compare);
+
zero(i);
return 0;
}
@@ -1911,14 +2178,14 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
}
/* we have to determine age parameter for each entry of type X */
- HASHMAP_FOREACH(i, globs, iterator) {
+ ORDERED_HASHMAP_FOREACH(i, globs, iterator) {
Iterator iter;
Item *j, *candidate_item = NULL;
if (i->type != IGNORE_DIRECTORY_PATH)
continue;
- HASHMAP_FOREACH(j, items, iter) {
+ ORDERED_HASHMAP_FOREACH(j, items, iter) {
if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
continue;
@@ -1964,8 +2231,8 @@ int main(int argc, char *argv[]) {
mac_selinux_init(NULL);
- items = hashmap_new(&string_hash_ops);
- globs = hashmap_new(&string_hash_ops);
+ items = ordered_hashmap_new(&string_hash_ops);
+ globs = ordered_hashmap_new(&string_hash_ops);
if (!items || !globs) {
r = log_oom();
@@ -2000,27 +2267,31 @@ int main(int argc, char *argv[]) {
}
}
- HASHMAP_FOREACH(a, globs, iterator) {
+ /* The non-globbing ones usually create things, hence we apply
+ * them first */
+ ORDERED_HASHMAP_FOREACH(a, items, iterator) {
k = process_item_array(a);
if (k < 0 && r == 0)
r = k;
}
- HASHMAP_FOREACH(a, items, iterator) {
+ /* The globbing ones usually alter things, hence we apply them
+ * second. */
+ ORDERED_HASHMAP_FOREACH(a, globs, iterator) {
k = process_item_array(a);
if (k < 0 && r == 0)
r = k;
}
finish:
- while ((a = hashmap_steal_first(items)))
+ while ((a = ordered_hashmap_steal_first(items)))
item_array_free(a);
- while ((a = hashmap_steal_first(globs)))
+ while ((a = ordered_hashmap_steal_first(globs)))
item_array_free(a);
- hashmap_free(items);
- hashmap_free(globs);
+ ordered_hashmap_free(items);
+ ordered_hashmap_free(globs);
free(arg_include_prefixes);
free(arg_exclude_prefixes);
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 47093b850d..97251ef0aa 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -42,6 +42,9 @@
#include "strv.h"
#include "build.h"
#include "def.h"
+#include "process-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
static enum {
ACTION_LIST,
@@ -379,7 +382,7 @@ static int wall_tty_block(void) {
return fd;
}
-static bool wall_tty_match(const char *path) {
+static bool wall_tty_match(const char *path, void *userdata) {
int fd, r;
struct stat st;
_cleanup_free_ char *p = NULL;
@@ -453,7 +456,7 @@ static int show_passwords(void) {
r = q;
if (wall)
- utmp_wall(wall, NULL, wall_tty_match);
+ utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
}
return r;
diff --git a/src/udev/.gitignore b/src/udev/.gitignore
index a229430e36..ba112ce218 100644
--- a/src/udev/.gitignore
+++ b/src/udev/.gitignore
@@ -2,4 +2,4 @@
/keyboard-keys-from-name.gperf
/keyboard-keys-from-name.h
/keyboard-keys-to-name.h
-/keyboard-keys.txt
+/keyboard-keys-list.txt
diff --git a/src/udev/accelerometer/accelerometer.c b/src/udev/accelerometer/accelerometer.c
index 0f1b3c6ec3..9e2c590c15 100644
--- a/src/udev/accelerometer/accelerometer.c
+++ b/src/udev/accelerometer/accelerometer.c
@@ -46,16 +46,10 @@
#include <stdio.h>
#include <string.h>
-#include <stdbool.h>
#include <math.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <stdlib.h>
-#include <unistd.h>
#include <getopt.h>
#include <limits.h>
-#include <linux/limits.h>
#include <linux/input.h>
#include "libudev.h"
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index 9e4f674a9e..cc1bf45ae9 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -496,7 +496,7 @@ int main(int argc, char *argv[])
}
}
- memcpy (model, id.model, 40);
+ memcpy(model, id.model, 40);
model[40] = '\0';
udev_util_encode_string(model, model_enc, sizeof(model_enc));
util_replace_whitespace((char *) id.model, model, 40);
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 6052f6abd8..3d74ae50f1 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -36,6 +36,7 @@
#include "libudev.h"
#include "libudev-private.h"
+#include "random-util.h"
/* device info */
static unsigned int cd_cd_rom;
@@ -650,8 +651,8 @@ static int cd_media_info(struct udev *udev, int fd)
* write protected; we need to check the contents if it is blank */
if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) {
unsigned char buffer[32 * 2048];
- unsigned char result, len;
- int block, offset;
+ unsigned char len;
+ int offset;
if (cd_media_dvd_ram) {
/* a write protected dvd-ram may report "complete" status */
@@ -732,22 +733,23 @@ static int cd_media_info(struct udev *udev, int fd)
/* if any non-zero data is found in sector 16 (iso and udf) or
* eventually 0 (fat32 boot sector, ext2 superblock, etc), disc
* is assumed non-blank */
- result = 0;
- for (block = 32768; block >= 0 && !result; block -= 32768) {
- offset = block;
- while (offset < (block + 2048) && !result) {
- result = buffer [offset];
- offset++;
+ for (offset = 32768; offset < (32768 + 2048); offset++) {
+ if (buffer [offset]) {
+ log_debug("data in block 16, assuming complete");
+ goto determined;
}
}
- if (!result) {
- cd_media_state = media_status[0];
- log_debug("no data in blocks 0 or 16, assuming blank");
- } else {
- log_debug("data in blocks 0 or 16, assuming complete");
+ for (offset = 0; offset < 2048; offset++) {
+ if (buffer [offset]) {
+ log_debug("data in block 0, assuming complete");
+ goto determined;
+ }
}
+
+ cd_media_state = media_status[0];
+ log_debug("no data in blocks 0 or 16, assuming blank");
}
determined:
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
index 4bb6edbef1..6cf41c67bb 100644
--- a/src/udev/collect/collect.c
+++ b/src/udev/collect/collect.c
@@ -20,18 +20,10 @@
*/
#include <stdio.h>
-#include <stdlib.h>
#include <stddef.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
#include <errno.h>
-#include <string.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "libudev.h"
#include "libudev-private.h"
#include "macro.h"
diff --git a/src/gudev/Makefile b/src/udev/mtd_probe/Makefile
index d0b0e8e008..d0b0e8e008 120000
--- a/src/gudev/Makefile
+++ b/src/udev/mtd_probe/Makefile
diff --git a/src/udev/mtd_probe/mtd_probe.c b/src/udev/mtd_probe/mtd_probe.c
index 13c757bd1c..67b750c4b3 100644
--- a/src/udev/mtd_probe/mtd_probe.c
+++ b/src/udev/mtd_probe/mtd_probe.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
-#include "mtd_probe.h"
+
#include <stdio.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <stdlib.h>
+#include "mtd_probe.h"
+
int main(int argc, char** argv)
{
int mtd_fd;
diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h
index d99be9addc..caea5c2693 100644
--- a/src/udev/mtd_probe/mtd_probe.h
+++ b/src/udev/mtd_probe/mtd_probe.h
@@ -21,6 +21,8 @@
#include <mtd/mtd-user.h>
+#include "macro.h"
+
/* Full oob structure as written on the flash */
struct sm_oob {
uint32_t reserved;
@@ -30,8 +32,7 @@ struct sm_oob {
uint8_t ecc2[3];
uint8_t lba_copy2[2];
uint8_t ecc1[3];
-} __attribute__((packed));
-
+} _packed_;
/* one sector is always 512 bytes, but it can consist of two nand pages */
#define SM_SECTOR_SIZE 512
@@ -47,5 +48,4 @@ struct sm_oob {
#define SM_SMALL_PAGE 256
#define SM_SMALL_OOB_SIZE 8
-
void probe_smart_media(int mtd_fd, mtd_info_t *info);
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
index ec67126b21..927b8abc64 100644
--- a/src/udev/net/ethtool-util.c
+++ b/src/udev/net/ethtool-util.c
@@ -93,8 +93,7 @@ int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
return 0;
}
-int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex)
-{
+int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) {
struct ethtool_cmd ecmd = {
.cmd = ETHTOOL_GSET
};
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 8b3dc45d4e..5610b2808e 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -22,7 +22,6 @@
#include <netinet/ether.h>
#include <linux/netdevice.h>
-#include "sd-id128.h"
#include "missing.h"
#include "link-config.h"
@@ -36,11 +35,9 @@
#include "path-util.h"
#include "conf-parser.h"
#include "conf-files.h"
-#include "fileio.h"
-#include "hashmap.h"
#include "rtnl-util.h"
#include "network-internal.h"
-#include "siphash24.h"
+#include "random-util.h"
struct link_config_ctx {
LIST_HEAD(link_config, links);
@@ -70,9 +67,9 @@ static void link_config_free(link_config *link) {
free(link->filename);
free(link->match_mac);
- free(link->match_path);
- free(link->match_driver);
- free(link->match_type);
+ strv_free(link->match_path);
+ strv_free(link->match_driver);
+ strv_free(link->match_type);
free(link->match_name);
free(link->match_host);
free(link->match_virt);
@@ -177,6 +174,9 @@ static int load_link(link_config_ctx *ctx, const char *filename) {
else
log_debug("Parsed configuration file %s", filename);
+ if (link->mtu > UINT_MAX || link->speed > UINT_MAX)
+ return -ERANGE;
+
link->filename = strdup(filename);
LIST_PREPEND(links, ctx->links, link);
@@ -240,6 +240,10 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device,
link_config **ret) {
link_config *link;
+ assert(ctx);
+ assert(device);
+ assert(ret);
+
LIST_FOREACH(links, link, ctx->links) {
const char* attr_value;
@@ -259,7 +263,7 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device,
attr_value = udev_device_get_sysattr_value(device, "name_assign_type");
if (attr_value)
- (void)safe_atou8(attr_value, &name_assign_type);
+ (void) safe_atou8(attr_value, &name_assign_type);
if (name_assign_type == NET_NAME_ENUM) {
log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
@@ -379,10 +383,9 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
if (!old_name)
return -EINVAL;
- r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
- config->duplex);
+ r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex);
if (r < 0)
- log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
+ log_warning_errno(r, "Could not set speed or duplex of %s to %zu Mbps (%s): %m",
old_name, config->speed / 1024,
duplex_to_string(config->duplex));
@@ -461,8 +464,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
mac = config->mac;
}
- r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
- config->mtu);
+ r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
if (r < 0)
return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name);
@@ -473,7 +475,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
const char *name;
- char *driver;
+ char *driver = NULL;
int r;
name = udev_device_get_sysname(device);
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index cb434d1aee..9875057e84 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -23,7 +23,6 @@
#include "ethtool-util.h"
#include "condition.h"
-#include "util.h"
#include "list.h"
#include "libudev.h"
@@ -67,8 +66,8 @@ struct link_config {
NamePolicy *name_policy;
char *name;
char *alias;
- unsigned int mtu;
- unsigned int speed;
+ size_t mtu;
+ size_t speed;
Duplex duplex;
WakeOnLan wol;
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index dcfff1d4ea..3691a69d48 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -37,6 +37,7 @@
#include "libudev-private.h"
#include "scsi.h"
#include "scsi_id.h"
+#include "random-util.h"
/*
* A priority based list of id, naa, and binary/ascii for the identifier
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index 03e3dc2867..1dad4476f3 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -20,8 +20,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
@@ -265,7 +263,7 @@ static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool t
fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC);
if (fd < 0) {
- fprintf(stderr, "error: %s: %m\n", udev_device_get_devnode(dev));
+ err = log_debug_errno(errno, "Failure opening block device %s: %m", udev_device_get_devnode(dev));
goto out;
}
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
index 3643596a70..3352821567 100644
--- a/src/udev/udev-builtin-btrfs.c
+++ b/src/udev/udev-builtin-btrfs.c
@@ -17,12 +17,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <fcntl.h>
-#include <errno.h>
#include <sys/ioctl.h>
#ifdef HAVE_LINUX_BTRFS_H
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index 95476648f9..7dfc74e6fa 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -18,10 +18,6 @@
***/
#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <inttypes.h>
-#include <ctype.h>
#include <stdlib.h>
#include <fnmatch.h>
#include <getopt.h>
@@ -89,6 +85,8 @@ static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device
bool last = false;
int r = 0;
+ assert(dev);
+
for (d = srcdev; d && !last; d = udev_device_get_parent(d)) {
const char *dsubsys;
const char *modalias = NULL;
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index 46f1c539d2..e3fa4bc162 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -126,77 +126,122 @@ static void get_cap_mask(struct udev_device *dev,
}
/* pointer devices */
-static void test_pointers (struct udev_device *dev,
- const unsigned long* bitmask_ev,
- const unsigned long* bitmask_abs,
- const unsigned long* bitmask_key,
- const unsigned long* bitmask_rel,
- bool test) {
- int is_mouse = 0;
- int is_touchpad = 0;
-
- if (!test_bit (EV_KEY, bitmask_ev)) {
- if (test_bit (EV_ABS, bitmask_ev) &&
- test_bit (ABS_X, bitmask_abs) &&
- test_bit (ABS_Y, bitmask_abs) &&
- test_bit (ABS_Z, bitmask_abs))
- udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
- return;
+static bool test_pointers(struct udev_device *dev,
+ const unsigned long* bitmask_ev,
+ const unsigned long* bitmask_abs,
+ const unsigned long* bitmask_key,
+ const unsigned long* bitmask_rel,
+ const unsigned long* bitmask_props,
+ bool test) {
+ bool has_abs_coordinates = false;
+ bool has_rel_coordinates = false;
+ bool has_mt_coordinates = false;
+ bool has_joystick_axes_or_buttons = false;
+ bool is_direct = false;
+ bool has_touch = false;
+ bool has_3d_coordinates = false;
+ bool has_keys = false;
+ bool stylus_or_pen = false;
+ bool finger_but_no_pen = false;
+ bool has_mouse_button = false;
+ bool is_mouse = false;
+ bool is_touchpad = false;
+ bool is_touchscreen = false;
+ bool is_tablet = false;
+ bool is_joystick = false;
+ bool is_accelerometer = false;
+ bool is_pointing_stick= false;
+
+ has_keys = test_bit(EV_KEY, bitmask_ev);
+ has_abs_coordinates = test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs);
+ has_3d_coordinates = has_abs_coordinates && test_bit(ABS_Z, bitmask_abs);
+ is_accelerometer = test_bit(INPUT_PROP_ACCELEROMETER, bitmask_props);
+
+ if (!has_keys && has_3d_coordinates)
+ is_accelerometer = true;
+
+ if (is_accelerometer) {
+ udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
+ return true;
}
- if (test_bit (EV_ABS, bitmask_ev) &&
- test_bit (ABS_X, bitmask_abs) && test_bit (ABS_Y, bitmask_abs)) {
- if (test_bit (BTN_STYLUS, bitmask_key) || test_bit (BTN_TOOL_PEN, bitmask_key))
- udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
- else if (test_bit (BTN_TOOL_FINGER, bitmask_key) && !test_bit (BTN_TOOL_PEN, bitmask_key))
- is_touchpad = 1;
- else if (test_bit (BTN_MOUSE, bitmask_key))
+ is_pointing_stick = test_bit(INPUT_PROP_POINTING_STICK, bitmask_props);
+ stylus_or_pen = test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key);
+ finger_but_no_pen = test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key);
+ has_mouse_button = test_bit(BTN_LEFT, bitmask_key);
+ has_rel_coordinates = test_bit(EV_REL, bitmask_ev) && test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel);
+ has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs);
+
+ /* unset has_mt_coordinates if devices claims to have all abs axis */
+ if(has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
+ has_mt_coordinates = false;
+ is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props);
+ has_touch = test_bit(BTN_TOUCH, bitmask_key);
+ /* joysticks don't necessarily have buttons; e. g.
+ * rudders/pedals are joystick-like, but buttonless; they have
+ * other fancy axes */
+ has_joystick_axes_or_buttons = test_bit(BTN_TRIGGER, bitmask_key) ||
+ test_bit(BTN_A, bitmask_key) ||
+ test_bit(BTN_1, bitmask_key) ||
+ test_bit(ABS_RX, bitmask_abs) ||
+ test_bit(ABS_RY, bitmask_abs) ||
+ test_bit(ABS_RZ, bitmask_abs) ||
+ test_bit(ABS_THROTTLE, bitmask_abs) ||
+ test_bit(ABS_RUDDER, bitmask_abs) ||
+ test_bit(ABS_WHEEL, bitmask_abs) ||
+ test_bit(ABS_GAS, bitmask_abs) ||
+ test_bit(ABS_BRAKE, bitmask_abs);
+
+ if (has_abs_coordinates) {
+ if (stylus_or_pen)
+ is_tablet = true;
+ else if (finger_but_no_pen && !is_direct)
+ is_touchpad = true;
+ else if (has_mouse_button)
/* This path is taken by VMware's USB mouse, which has
* absolute axes, but no touch/pressure button. */
- is_mouse = 1;
- else if (test_bit (BTN_TOUCH, bitmask_key))
- udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
- /* joysticks don't necessarily have to have buttons; e. g.
- * rudders/pedals are joystick-like, but buttonless; they have
- * other fancy axes */
- else if (test_bit (BTN_TRIGGER, bitmask_key) ||
- test_bit (BTN_A, bitmask_key) ||
- test_bit (BTN_1, bitmask_key) ||
- test_bit (ABS_RX, bitmask_abs) ||
- test_bit (ABS_RY, bitmask_abs) ||
- test_bit (ABS_RZ, bitmask_abs) ||
- test_bit (ABS_THROTTLE, bitmask_abs) ||
- test_bit (ABS_RUDDER, bitmask_abs) ||
- test_bit (ABS_WHEEL, bitmask_abs) ||
- test_bit (ABS_GAS, bitmask_abs) ||
- test_bit (ABS_BRAKE, bitmask_abs))
- udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
+ is_mouse = true;
+ else if (has_touch)
+ is_touchscreen = true;
+ else if (has_joystick_axes_or_buttons)
+ is_joystick = true;
}
+ if (has_mt_coordinates && is_direct)
+ is_touchscreen = true;
- if (test_bit (EV_REL, bitmask_ev) &&
- test_bit (REL_X, bitmask_rel) && test_bit (REL_Y, bitmask_rel) &&
- test_bit (BTN_MOUSE, bitmask_key))
- is_mouse = 1;
+ if (has_rel_coordinates && has_mouse_button)
+ is_mouse = true;
+ if (is_pointing_stick)
+ udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1");
if (is_mouse)
udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1");
if (is_touchpad)
udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1");
+ if (is_touchscreen)
+ udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
+ if (is_joystick)
+ udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
+ if (is_tablet)
+ udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
+
+ return is_tablet || is_mouse || is_touchpad || is_touchscreen || is_joystick || is_pointing_stick;
}
/* key like devices */
-static void test_key (struct udev_device *dev,
- const unsigned long* bitmask_ev,
- const unsigned long* bitmask_key,
- bool test) {
+static bool test_key(struct udev_device *dev,
+ const unsigned long* bitmask_ev,
+ const unsigned long* bitmask_key,
+ bool test) {
unsigned i;
unsigned long found;
unsigned long mask;
+ bool ret = false;
/* do we have any KEY_* capability? */
- if (!test_bit (EV_KEY, bitmask_ev)) {
+ if (!test_bit(EV_KEY, bitmask_ev)) {
log_debug("test_key: no EV_KEY capability");
- return;
+ return false;
}
/* only consider KEY_* here, not BTN_* */
@@ -208,7 +253,7 @@ static void test_key (struct udev_device *dev,
/* If there are no keys in the lower block, check the higher block */
if (!found) {
for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) {
- if (test_bit (i, bitmask_key)) {
+ if (test_bit(i, bitmask_key)) {
log_debug("test_key: Found key %x in high block", i);
found = 1;
break;
@@ -216,14 +261,20 @@ static void test_key (struct udev_device *dev,
}
}
- if (found > 0)
+ if (found > 0) {
udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
+ ret = true;
+ }
/* the first 32 bits are ESC, numbers, and Q to D; if we have all of
* those, consider it a full keyboard; do not test KEY_RESERVED, though */
mask = 0xFFFFFFFE;
- if ((bitmask_key[0] & mask) == mask)
+ if ((bitmask_key[0] & mask) == mask) {
udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1");
+ ret = true;
+ }
+
+ return ret;
}
static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], bool test) {
@@ -232,7 +283,12 @@ static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], boo
unsigned long bitmask_abs[NBITS(ABS_MAX)];
unsigned long bitmask_key[NBITS(KEY_MAX)];
unsigned long bitmask_rel[NBITS(REL_MAX)];
+ unsigned long bitmask_props[NBITS(INPUT_PROP_MAX)];
const char *sysname, *devnode;
+ bool is_pointer;
+ bool is_key;
+
+ assert(dev);
/* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */
@@ -248,8 +304,15 @@ static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], boo
get_cap_mask(dev, pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), test);
get_cap_mask(dev, pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), test);
get_cap_mask(dev, pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test);
- test_pointers(dev, bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel, test);
- test_key(dev, bitmask_ev, bitmask_key, test);
+ get_cap_mask(dev, pdev, "properties", bitmask_props, sizeof(bitmask_props), test);
+ is_pointer = test_pointers(dev, bitmask_ev, bitmask_abs,
+ bitmask_key, bitmask_rel,
+ bitmask_props, test);
+ is_key = test_key(dev, bitmask_ev, bitmask_key, test);
+ /* Some evdev nodes have only a scrollwheel */
+ if (!is_pointer && !is_key && test_bit(EV_REL, bitmask_ev) &&
+ (test_bit(REL_WHEEL, bitmask_rel) || test_bit(REL_HWHEEL, bitmask_rel)))
+ udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
}
devnode = udev_device_get_devnode(dev);
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index d8ee4cbb61..01f3879f37 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -18,19 +18,15 @@
***/
#include <stdio.h>
-#include <errno.h>
#include <string.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <sys/ioctl.h>
-#include <linux/limits.h>
#include <linux/input.h>
#include "udev.h"
static const struct key *keyboard_lookup_key(const char *str, unsigned len);
#include "keyboard-keys-from-name.h"
-#include "keyboard-keys-to-name.h"
static int install_force_release(struct udev_device *dev, const unsigned *release, unsigned release_count) {
struct udev_device *atkbd;
@@ -41,6 +37,9 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas
unsigned i;
int ret;
+ assert(dev);
+ assert(release);
+
atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
if (!atkbd)
return -ENODEV;
@@ -66,99 +65,205 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas
return ret;
}
-static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct udev_list_entry *entry;
+static void map_keycode(int fd, const char *devnode, int scancode, const char *keycode)
+{
struct {
unsigned scan;
unsigned key;
- } map[1024];
- unsigned map_count = 0;
+ } map;
+ char *endptr;
+ const struct key *k;
+ unsigned keycode_num;
+
+ /* translate identifier to key code */
+ k = keyboard_lookup_key(keycode, strlen(keycode));
+ if (k) {
+ keycode_num = k->id;
+ } else {
+ /* check if it's a numeric code already */
+ keycode_num = strtoul(keycode, &endptr, 0);
+ if (endptr[0] !='\0') {
+ log_error("Unknown key identifier '%s'", keycode);
+ return;
+ }
+ }
+
+ map.scan = scancode;
+ map.key = keycode_num;
+
+ log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
+ map.scan, map.scan, map.key, map.key);
+
+ if (ioctl(fd, EVIOCSKEYCODE, &map) < 0)
+ log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode, map.scan, map.key);
+}
+
+static inline char* parse_token(const char *current, int32_t *val_out) {
+ char *next;
+ int32_t val;
+
+ if (!current)
+ return NULL;
+
+ val = strtol(current, &next, 0);
+ if (*next && *next != ':')
+ return NULL;
+
+ if (next != current)
+ *val_out = val;
+
+ if (*next)
+ next++;
+
+ return next;
+}
+
+static void override_abs(int fd, const char *devnode,
+ unsigned evcode, const char *value) {
+ struct input_absinfo absinfo;
+ int rc;
+ char *next;
+
+ rc = ioctl(fd, EVIOCGABS(evcode), &absinfo);
+ if (rc < 0) {
+ log_error_errno(errno, "Unable to EVIOCGABS device \"%s\"", devnode);
+ return;
+ }
+
+ next = parse_token(value, &absinfo.minimum);
+ next = parse_token(next, &absinfo.maximum);
+ next = parse_token(next, &absinfo.resolution);
+ next = parse_token(next, &absinfo.fuzz);
+ next = parse_token(next, &absinfo.flat);
+ if (!next) {
+ log_error("Unable to parse EV_ABS override '%s' for '%s'", value, devnode);
+ return;
+ }
+
+ log_debug("keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32" for \"%s\"",
+ evcode,
+ absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat,
+ devnode);
+ rc = ioctl(fd, EVIOCSABS(evcode), &absinfo);
+ if (rc < 0)
+ log_error_errno(errno, "Unable to EVIOCSABS device \"%s\"", devnode);
+}
+
+static void set_trackpoint_sensitivity(struct udev_device *dev, const char *value)
+{
+ struct udev_device *pdev;
+ char val_s[DECIMAL_STR_MAX(int)];
+ int r, val_i;
+
+ assert(dev);
+ assert(value);
+
+ /* The sensitivity sysfs attr belongs to the serio parent device */
+ pdev = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
+ if (!pdev) {
+ log_warning("Failed to get serio parent for '%s'", udev_device_get_devnode(dev));
+ return;
+ }
+
+ r = safe_atoi(value, &val_i);
+ if (r < 0) {
+ log_error("Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s'", value, udev_device_get_devnode(dev));
+ return;
+ }
+
+ xsprintf(val_s, "%d", val_i);
+
+ r = udev_device_set_sysattr_value(pdev, "sensitivity", val_s);
+ if (r < 0)
+ log_error_errno(r, "Failed to write 'sensitivity' attribute for '%s': %m", udev_device_get_devnode(pdev));
+}
+
+static int open_device(const char *devnode) {
+ int fd;
+
+ fd = open(devnode, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Error opening device \"%s\": %m", devnode);
+
+ return fd;
+}
+
+static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
+ struct udev_list_entry *entry;
unsigned release[1024];
unsigned release_count = 0;
+ _cleanup_close_ int fd = -1;
+ const char *node;
+
+ node = udev_device_get_devnode(dev);
+ if (!node) {
+ log_error("No device node for \"%s\"", udev_device_get_syspath(dev));
+ return EXIT_FAILURE;
+ }
udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) {
const char *key;
- unsigned scancode, keycode_num;
char *endptr;
- const char *keycode;
- const struct key *k;
key = udev_list_entry_get_name(entry);
- if (!startswith(key, "KEYBOARD_KEY_"))
- continue;
-
- /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
- scancode = strtoul(key + 13, &endptr, 16);
- if (endptr[0] != '\0') {
- log_error("Error, unable to parse scan code from '%s'", key);
- continue;
- }
+ if (startswith(key, "KEYBOARD_KEY_")) {
+ const char *keycode;
+ unsigned scancode;
+
+ /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
+ scancode = strtoul(key + 13, &endptr, 16);
+ if (endptr[0] != '\0') {
+ log_warning("Unable to parse scan code from \"%s\"", key);
+ continue;
+ }
- keycode = udev_list_entry_get_value(entry);
+ keycode = udev_list_entry_get_value(entry);
- /* a leading '!' needs a force-release entry */
- if (keycode[0] == '!') {
- keycode++;
+ /* a leading '!' needs a force-release entry */
+ if (keycode[0] == '!') {
+ keycode++;
- release[release_count] = scancode;
- if (release_count < ELEMENTSOF(release)-1)
- release_count++;
+ release[release_count] = scancode;
+ if (release_count < ELEMENTSOF(release)-1)
+ release_count++;
- if (keycode[0] == '\0')
- continue;
- }
-
- /* translate identifier to key code */
- k = keyboard_lookup_key(keycode, strlen(keycode));
- if (k) {
- keycode_num = k->id;
- } else {
- /* check if it's a numeric code already */
- keycode_num = strtoul(keycode, &endptr, 0);
- if (endptr[0] !='\0') {
- log_error("Error, unknown key identifier '%s'", keycode);
- continue;
+ if (keycode[0] == '\0')
+ continue;
}
- }
- map[map_count].scan = scancode;
- map[map_count].key = keycode_num;
- if (map_count < ELEMENTSOF(map)-1)
- map_count++;
- }
+ if (fd == -1) {
+ fd = open_device(node);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ }
- if (map_count > 0 || release_count > 0) {
- const char *node;
- int fd;
- unsigned i;
+ map_keycode(fd, node, scancode, keycode);
+ } else if (startswith(key, "EVDEV_ABS_")) {
+ unsigned evcode;
- node = udev_device_get_devnode(dev);
- if (!node) {
- log_error("Error, no device node for '%s'", udev_device_get_syspath(dev));
- return EXIT_FAILURE;
- }
+ /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
+ evcode = strtoul(key + 10, &endptr, 16);
+ if (endptr[0] != '\0') {
+ log_warning("Unable to parse EV_ABS code from \"%s\"", key);
+ continue;
+ }
- fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0) {
- log_error_errno(errno, "Error, opening device '%s': %m", node);
- return EXIT_FAILURE;
- }
+ if (fd == -1) {
+ fd = open_device(node);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ }
- /* install list of map codes */
- for (i = 0; i < map_count; i++) {
- log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
- map[i].scan, map[i].scan, map[i].key, map[i].key);
- if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0)
- log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key);
+ override_abs(fd, node, evcode, udev_list_entry_get_value(entry));
+ } else if (streq(key, "POINTINGSTICK_SENSITIVITY")) {
+ set_trackpoint_sensitivity(dev, udev_list_entry_get_value(entry));
}
-
- /* install list of force-release codes */
- if (release_count > 0)
- install_force_release(dev, release, release_count);
-
- close(fd);
}
+ /* install list of force-release codes */
+ if (release_count > 0)
+ install_force_release(dev, release, release_count);
+
return EXIT_SUCCESS;
}
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
index ad2829e500..81e78a8aa3 100644
--- a/src/udev/udev-builtin-kmod.c
+++ b/src/udev/udev-builtin-kmod.c
@@ -21,12 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
#include <libkmod.h>
#include "udev.h"
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 37ff1b8008..6e7e1271fb 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -35,7 +35,7 @@
* Type of names:
* b<number> -- BCMA bus core number
* ccw<name> -- CCW bus group name
- * o<index> -- on-board device index number
+ * o<index>[d<dev_port>] -- on-board device index number
* s<slot>[f<function>][d<dev_port>] -- hotplug slot index number
* x<MAC> -- MAC address
* [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
@@ -91,6 +91,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
+#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <net/if.h>
@@ -128,36 +129,53 @@ struct netnames {
/* retrieve on-board index number and label from firmware */
static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
- const char *index;
+ unsigned dev_port = 0;
+ size_t l;
+ char *s;
+ const char *attr;
int idx;
/* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
- index = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
+ attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
/* SMBIOS type 41 -- Onboard Devices Extended Information */
- if (!index)
- index = udev_device_get_sysattr_value(names->pcidev, "index");
- if (!index)
+ if (!attr)
+ attr = udev_device_get_sysattr_value(names->pcidev, "index");
+ if (!attr)
return -ENOENT;
- idx = strtoul(index, NULL, 0);
+
+ idx = strtoul(attr, NULL, 0);
if (idx <= 0)
return -EINVAL;
- snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx);
+
+ /* kernel provided port index for multiple ports on a single PCI function */
+ attr = udev_device_get_sysattr_value(dev, "dev_port");
+ if (attr)
+ dev_port = strtol(attr, NULL, 10);
+
+ s = names->pci_onboard;
+ l = sizeof(names->pci_onboard);
+ l = strpcpyf(&s, l, "o%d", idx);
+ if (dev_port > 0)
+ l = strpcpyf(&s, l, "d%d", dev_port);
+ if (l == 0)
+ names->pci_onboard[0] = '\0';
names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
+
return 0;
}
/* read the 256 bytes PCI configuration space to check the multi-function bit */
static bool is_pci_multifunction(struct udev_device *dev) {
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_close_ int fd = -1;
const char *filename;
uint8_t config[64];
filename = strjoina(udev_device_get_syspath(dev), "/config");
- f = fopen(filename, "re");
- if (!f)
+ fd = open(filename, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
return false;
- if (fread(&config, sizeof(config), 1, f) != 1)
+ if (read(fd, &config, sizeof(config)) != sizeof(config))
return false;
/* bit 0-6 header type, bit 7 multi/single function device */
@@ -182,7 +200,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
return -ENOENT;
- /* kernel provided multi-device index */
+ /* kernel provided port index for multiple ports on a single PCI function */
attr = udev_device_get_sysattr_value(dev, "dev_port");
if (attr)
dev_port = strtol(attr, NULL, 10);
@@ -248,7 +266,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
if (dev_port > 0)
l = strpcpyf(&s, l, "d%d", dev_port);
if (l == 0)
- names->pci_path[0] = '\0';
+ names->pci_slot[0] = '\0';
}
out:
udev_device_unref(pci);
@@ -258,6 +276,9 @@ out:
static int names_pci(struct udev_device *dev, struct netnames *names) {
struct udev_device *parent;
+ assert(dev);
+ assert(names);
+
parent = udev_device_get_parent(dev);
if (!parent)
return -ENOENT;
@@ -284,6 +305,9 @@ static int names_usb(struct udev_device *dev, struct netnames *names) {
size_t l;
char *s;
+ assert(dev);
+ assert(names);
+
usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
if (!usbdev)
return -ENOENT;
@@ -332,6 +356,9 @@ static int names_bcma(struct udev_device *dev, struct netnames *names) {
struct udev_device *bcmadev;
unsigned int core;
+ assert(dev);
+ assert(names);
+
bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
if (!bcmadev)
return -ENOENT;
@@ -353,6 +380,9 @@ static int names_ccw(struct udev_device *dev, struct netnames *names) {
size_t bus_id_len;
int rc;
+ assert(dev);
+ assert(names);
+
/* Retrieve the associated CCW device */
cdev = udev_device_get_parent(dev);
if (!cdev)
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index b6749aab76..4ca0a69d7d 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -77,6 +77,9 @@ static int format_lun_number(struct udev_device *dev, char **path) {
static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) {
struct udev_device *parent = dev;
+ assert(dev);
+ assert(subsys);
+
while (parent != NULL) {
const char *subsystem;
@@ -96,6 +99,9 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent,
const char *port;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
return NULL;
@@ -126,6 +132,9 @@ static struct udev_device *handle_scsi_sas_wide_port(struct udev_device *parent,
const char *sas_address;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
return NULL;
@@ -169,6 +178,9 @@ static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **pa
const char *phy_count;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
if (targetdev == NULL)
return NULL;
@@ -259,6 +271,9 @@ static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **
const char *port;
char *lun = NULL;
+ assert(parent);
+ assert(path);
+
/* find iscsi session */
transportdev = parent;
for (;;) {
@@ -316,6 +331,9 @@ static struct udev_device *handle_scsi_default(struct udev_device *parent, char
struct dirent *dent;
int basenum;
+ assert(parent);
+ assert(path);
+
hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
if (hostdev == NULL)
return NULL;
@@ -398,6 +416,9 @@ static struct udev_device *handle_scsi_hyperv(struct udev_device *parent, char *
char guid[38];
size_t i, k;
+ assert(parent);
+ assert(path);
+
hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
if (!hostdev)
return NULL;
@@ -555,6 +576,10 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path)
static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) {
struct udev_device *scsi_dev;
+ assert(parent);
+ assert(dev);
+ assert(path);
+
scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
if (scsi_dev != NULL) {
const char *wwpn;
@@ -582,6 +607,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
bool supported_transport = false;
bool supported_parent = false;
+ assert(dev);
+
/* S390 ccw bus */
parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
if (parent != NULL) {
@@ -638,7 +665,8 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
supported_parent = true;
}
- parent = udev_device_get_parent(parent);
+ if (parent)
+ parent = udev_device_get_parent(parent);
}
/*
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index b78c09b910..99bb91ae57 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -20,14 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
#include <errno.h>
-#include <dirent.h>
-#include <getopt.h>
#include "systemd/sd-login.h"
#include "logind-acl.h"
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index ab0d96e377..d309dc31cb 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -150,35 +150,35 @@ static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len
_cleanup_close_ int fd = -1;
ssize_t size;
unsigned char buf[18 + 65535];
- int pos = 0;
+ size_t pos = 0;
unsigned strpos = 0;
struct usb_interface_descriptor {
- u_int8_t bLength;
- u_int8_t bDescriptorType;
- u_int8_t bInterfaceNumber;
- u_int8_t bAlternateSetting;
- u_int8_t bNumEndpoints;
- u_int8_t bInterfaceClass;
- u_int8_t bInterfaceSubClass;
- u_int8_t bInterfaceProtocol;
- u_int8_t iInterface;
- } __attribute__((packed));
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+ } _packed_;
if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0)
return log_oom();
fd = open(filename, O_RDONLY|O_CLOEXEC);
- if (fd < 0) {
- fprintf(stderr, "error opening USB device 'descriptors' file\n");
- return -errno;
- }
+ if (fd < 0)
+ return log_debug_errno(errno, "Error opening USB device 'descriptors' file: %m");
size = read(fd, buf, sizeof(buf));
if (size < 18 || size == sizeof(buf))
return -EIO;
ifs_str[0] = '\0';
- while (pos < size && strpos+7 < len-2) {
+ while (pos + sizeof(struct usb_interface_descriptor) < (size_t) size &&
+ strpos + 7 < len - 2) {
+
struct usb_interface_descriptor *desc;
char if_str[8];
@@ -229,17 +229,17 @@ static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len
* is concatenated with the identification with an underscore '_'.
*/
static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool test) {
- char vendor_str[64];
+ char vendor_str[64] = "";
char vendor_str_enc[256];
const char *vendor_id;
- char model_str[64];
+ char model_str[64] = "";
char model_str_enc[256];
const char *product_id;
- char serial_str[UTIL_NAME_SIZE];
- char packed_if_str[UTIL_NAME_SIZE];
- char revision_str[64];
- char type_str[64];
- char instance_str[64];
+ char serial_str[UTIL_NAME_SIZE] = "";
+ char packed_if_str[UTIL_NAME_SIZE] = "";
+ char revision_str[64] = "";
+ char type_str[64] = "";
+ char instance_str[64] = "";
const char *ifnum = NULL;
const char *driver = NULL;
char serial[256];
@@ -252,13 +252,7 @@ static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool
size_t l;
char *s;
- vendor_str[0] = '\0';
- model_str[0] = '\0';
- serial_str[0] = '\0';
- packed_if_str[0] = '\0';
- revision_str[0] = '\0';
- type_str[0] = '\0';
- instance_str[0] = '\0';
+ assert(dev);
/* shortcut, if we are called directly for a "usb_device" type */
if (udev_device_get_devtype(dev) != NULL && streq(udev_device_get_devtype(dev), "usb_device")) {
@@ -310,7 +304,7 @@ static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool
dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));
/* mass storage : SCSI or ATAPI */
- if ((protocol == 6 || protocol == 2)) {
+ if (protocol == 6 || protocol == 2) {
struct udev_device *dev_scsi;
const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
int host, bus, target, lun;
@@ -438,10 +432,10 @@ fallback:
s = serial;
l = strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
- if (serial_str[0] != '\0')
+ if (!isempty(serial_str))
l = strpcpyl(&s, l, "_", serial_str, NULL);
- if (instance_str[0] != '\0')
+ if (!isempty(instance_str))
strpcpyl(&s, l, "-", instance_str, NULL);
udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str);
@@ -452,14 +446,14 @@ fallback:
udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id);
udev_builtin_add_property(dev, test, "ID_REVISION", revision_str);
udev_builtin_add_property(dev, test, "ID_SERIAL", serial);
- if (serial_str[0] != '\0')
+ if (!isempty(serial_str))
udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str);
- if (type_str[0] != '\0')
+ if (!isempty(type_str))
udev_builtin_add_property(dev, test, "ID_TYPE", type_str);
- if (instance_str[0] != '\0')
+ if (!isempty(instance_str))
udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str);
udev_builtin_add_property(dev, test, "ID_BUS", "usb");
- if (packed_if_str[0] != '\0')
+ if (!isempty(packed_if_str))
udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str);
if (ifnum != NULL)
udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum);
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index 1950ec23a1..fabc653800 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -17,12 +17,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
#include <string.h>
-#include <errno.h>
#include <getopt.h>
#include "udev.h"
@@ -127,12 +123,7 @@ int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const c
}
int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val) {
- struct udev_list_entry *entry;
-
- entry = udev_device_add_property(dev, key, val);
- /* store in db, skip private keys */
- if (key[0] != '.')
- udev_list_entry_set_num(entry, true);
+ udev_device_add_property(dev, key, val);
if (test)
printf("%s=%s\n", key, val);
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 7b5ef6b2a8..b0ad277f73 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -10,16 +10,16 @@
*/
#include <errno.h>
-#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
-#include <sys/types.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include "socket-util.h"
+#include "formats-util.h"
#include "udev.h"
/* wire protocol magic must match */
@@ -57,7 +57,7 @@ struct udev_ctrl {
int refcount;
struct udev *udev;
int sock;
- struct sockaddr_un saddr;
+ union sockaddr_union saddr;
socklen_t addrlen;
bool bound;
bool cleanup_socket;
@@ -96,9 +96,9 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
if (r < 0)
log_warning_errno(errno, "could not set SO_PASSCRED: %m");
- uctrl->saddr.sun_family = AF_LOCAL;
- strscpy(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path), "/run/udev/control");
- uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
+ uctrl->saddr.un.sun_family = AF_LOCAL;
+ strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), "/run/udev/control");
+ uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.un.sun_path);
return uctrl;
}
@@ -110,10 +110,10 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
int err;
if (!uctrl->bound) {
- err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
+ err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
if (err < 0 && errno == EADDRINUSE) {
- unlink(uctrl->saddr.sun_path);
- err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
+ unlink(uctrl->saddr.un.sun_path);
+ err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
}
if (err < 0) {
@@ -140,21 +140,19 @@ struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl) {
}
static struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl) {
- if (uctrl == NULL)
- return NULL;
- uctrl->refcount++;
+ if (uctrl)
+ uctrl->refcount++;
+
return uctrl;
}
struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl) {
- if (uctrl == NULL)
- return NULL;
- uctrl->refcount--;
- if (uctrl->refcount > 0)
- return uctrl;
- if (uctrl->sock >= 0)
- close(uctrl->sock);
- free(uctrl);
+ if (uctrl && -- uctrl->refcount == 0) {
+ if (uctrl->sock >= 0)
+ close(uctrl->sock);
+ free(uctrl);
+ }
+
return NULL;
}
@@ -162,7 +160,7 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
if (uctrl == NULL)
return 0;
if (uctrl->cleanup_socket)
- unlink(uctrl->saddr.sun_path);
+ unlink(uctrl->saddr.un.sun_path);
return 0;
}
@@ -224,15 +222,15 @@ struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connectio
}
struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn) {
- if (conn == NULL)
- return NULL;
- conn->refcount--;
- if (conn->refcount > 0)
- return conn;
- if (conn->sock >= 0)
- close(conn->sock);
- udev_ctrl_unref(conn->uctrl);
- free(conn);
+ if (conn && -- conn->refcount == 0) {
+ if (conn->sock >= 0)
+ close(conn->sock);
+
+ udev_ctrl_unref(conn->uctrl);
+
+ free(conn);
+ }
+
return NULL;
}
@@ -251,7 +249,7 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int
ctrl_msg_wire.intval = intval;
if (!uctrl->connected) {
- if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) {
+ if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) {
err = -errno;
goto out;
}
@@ -377,6 +375,9 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
log_error_errno(errno, "unable to receive ctrl message: %m");
goto err;
}
+
+ cmsg_close_all(&smsg);
+
cmsg = CMSG_FIRSTHDR(&smsg);
cred = (struct ucred *) CMSG_DATA(cmsg);
@@ -402,13 +403,11 @@ err:
}
struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg == NULL)
- return NULL;
- ctrl_msg->refcount--;
- if (ctrl_msg->refcount > 0)
- return ctrl_msg;
- udev_ctrl_connection_unref(ctrl_msg->conn);
- free(ctrl_msg);
+ if (ctrl_msg && -- ctrl_msg->refcount == 0) {
+ udev_ctrl_connection_unref(ctrl_msg->conn);
+ free(ctrl_msg);
+ }
+
return NULL;
}
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index bc115f112d..4dcf8f2e1c 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -23,7 +23,6 @@
#include <errno.h>
#include <ctype.h>
#include <string.h>
-#include <time.h>
#include <net/if.h>
#include <sys/prctl.h>
#include <poll.h>
@@ -31,8 +30,19 @@
#include <sys/wait.h>
#include <sys/signalfd.h>
-#include "udev.h"
#include "rtnl-util.h"
+#include "event-util.h"
+#include "formats-util.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "udev.h"
+
+typedef struct Spawn {
+ const char *cmd;
+ pid_t pid;
+ usec_t timeout_warn;
+ usec_t timeout;
+} Spawn;
struct udev_event *udev_event_new(struct udev_device *dev) {
struct udev *udev = udev_device_get_udev(dev);
@@ -45,8 +55,7 @@ struct udev_event *udev_event_new(struct udev_device *dev) {
event->udev = udev;
udev_list_init(udev, &event->run_list, false);
udev_list_init(udev, &event->seclabel_list, false);
- event->fd_signal = -1;
- event->birth_usec = now(CLOCK_MONOTONIC);
+ event->birth_usec = clock_boottime_or_monotonic();
return event;
}
@@ -110,6 +119,8 @@ size_t udev_event_apply_format(struct udev_event *event, const char *src, char *
char *s;
size_t l;
+ assert(dev);
+
from = src;
s = dest;
l = size;
@@ -374,7 +385,7 @@ out:
}
static int spawn_exec(struct udev_event *event,
- const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask,
+ const char *cmd, char *const argv[], char **envp,
int fd_stdout, int fd_stderr) {
_cleanup_close_ int fd = -1;
@@ -402,9 +413,8 @@ static int spawn_exec(struct udev_event *event,
/* terminate child in case parent goes away */
prctl(PR_SET_PDEATHSIG, SIGTERM);
- /* restore original udev sigmask before exec */
- if (sigmask)
- sigprocmask(SIG_SETMASK, sigmask, NULL);
+ /* restore sigmask before exec */
+ (void) reset_signal_mask();
execve(argv[0], argv, envp);
@@ -467,7 +477,7 @@ static void spawn_read(struct udev_event *event,
if (timeout_usec > 0) {
usec_t age_usec;
- age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
+ age_usec = clock_boottime_or_monotonic() - event->birth_usec;
if (age_usec >= timeout_usec) {
log_error("timeout '%s'", cmd);
return;
@@ -540,102 +550,116 @@ static void spawn_read(struct udev_event *event,
result[respos] = '\0';
}
+static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ Spawn *spawn = userdata;
+ char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert(spawn);
+
+ kill_and_sigcont(spawn->pid, SIGKILL);
+
+ log_error("spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
+ format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+ return 1;
+}
+
+static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+ Spawn *spawn = userdata;
+ char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
+
+ assert(spawn);
+
+ log_warning("spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
+ format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
+
+ return 1;
+}
+
+static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ Spawn *spawn = userdata;
+
+ assert(spawn);
+
+ switch (si->si_code) {
+ case CLD_EXITED:
+ if (si->si_status != 0)
+ log_warning("process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+ else {
+ log_debug("process '%s' succeeded.", spawn->cmd);
+ sd_event_exit(sd_event_source_get_event(s), 0);
+
+ return 1;
+ }
+
+ break;
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ log_warning("process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
+
+ break;
+ default:
+ log_error("process '%s' failed due to unknown reason.", spawn->cmd);
+ }
+
+ sd_event_exit(sd_event_source_get_event(s), -EIO);
+
+ return 1;
+}
+
static int spawn_wait(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
const char *cmd, pid_t pid) {
- struct pollfd pfd[1];
- int err = 0;
-
- pfd[0].events = POLLIN;
- pfd[0].fd = event->fd_signal;
+ Spawn spawn = {
+ .cmd = cmd,
+ .pid = pid,
+ };
+ _cleanup_event_unref_ sd_event *e = NULL;
+ int r, ret;
- while (pid > 0) {
- int timeout;
- int timeout_warn = 0;
- int fdcount;
+ r = sd_event_new(&e);
+ if (r < 0)
+ return r;
- if (timeout_usec > 0) {
- usec_t age_usec;
+ if (timeout_usec > 0) {
+ usec_t usec, age_usec;
- age_usec = now(CLOCK_MONOTONIC) - event->birth_usec;
- if (age_usec >= timeout_usec)
- timeout = 1000;
- else {
- if (timeout_warn_usec > 0)
- timeout_warn = ((timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+ usec = now(clock_boottime_or_monotonic());
+ age_usec = usec - event->birth_usec;
+ if (age_usec < timeout_usec) {
+ if (timeout_warn_usec > 0 && timeout_warn_usec < timeout_usec && age_usec < timeout_warn_usec) {
+ spawn.timeout_warn = timeout_warn_usec - age_usec;
- timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
+ r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+ usec + spawn.timeout_warn, USEC_PER_SEC,
+ on_spawn_timeout_warning, &spawn);
+ if (r < 0)
+ return r;
}
- } else {
- timeout = -1;
- }
- fdcount = poll(pfd, 1, timeout_warn);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
- if (fdcount == 0) {
- log_warning("slow: '%s' ["PID_FMT"]", cmd, pid);
+ spawn.timeout = timeout_usec - age_usec;
- fdcount = poll(pfd, 1, timeout);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
- if (fdcount == 0) {
- log_error("timeout: killing '%s' ["PID_FMT"]", cmd, pid);
- kill(pid, SIGKILL);
- }
+ r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
+ usec + spawn.timeout, USEC_PER_SEC, on_spawn_timeout, &spawn);
+ if (r < 0)
+ return r;
}
+ }
- if (pfd[0].revents & POLLIN) {
- struct signalfd_siginfo fdsi;
- int status;
- ssize_t size;
+ r = sd_event_add_child(e, NULL, pid, WEXITED, on_spawn_sigchld, &spawn);
+ if (r < 0)
+ return r;
- size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
- if (size != sizeof(struct signalfd_siginfo))
- continue;
+ r = sd_event_loop(e);
+ if (r < 0)
+ return r;
- switch (fdsi.ssi_signo) {
- case SIGTERM:
- event->sigterm = true;
- break;
- case SIGCHLD:
- if (waitpid(pid, &status, WNOHANG) < 0)
- break;
- if (WIFEXITED(status)) {
- log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status));
- if (WEXITSTATUS(status) != 0)
- err = -1;
- } else if (WIFSIGNALED(status)) {
- log_error("'%s' ["PID_FMT"] terminated by signal %i (%s)", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
- err = -1;
- } else if (WIFSTOPPED(status)) {
- log_error("'%s' ["PID_FMT"] stopped", cmd, pid);
- err = -1;
- } else if (WIFCONTINUED(status)) {
- log_error("'%s' ["PID_FMT"] continued", cmd, pid);
- err = -1;
- } else {
- log_error("'%s' ["PID_FMT"] exit with status 0x%04x", cmd, pid, status);
- err = -1;
- }
- pid = 0;
- break;
- }
- }
- }
-out:
- return err;
+ r = sd_event_get_exit_code(e, &ret);
+ if (r < 0)
+ return r;
+
+ return ret;
}
int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) {
@@ -674,7 +698,7 @@ out:
int udev_event_spawn(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *cmd, char **envp, const sigset_t *sigmask,
+ const char *cmd, char **envp,
char *result, size_t ressize) {
int outpipe[2] = {-1, -1};
int errpipe[2] = {-1, -1};
@@ -724,7 +748,7 @@ int udev_event_spawn(struct udev_event *event,
log_debug("starting '%s'", cmd);
- spawn_exec(event, cmd, argv, envp, sigmask,
+ spawn_exec(event, cmd, argv, envp,
outpipe[WRITE_END], errpipe[WRITE_END]);
_exit(2 );
@@ -786,59 +810,41 @@ static int rename_netif(struct udev_event *event) {
void udev_event_execute_rules(struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
struct udev_list *properties_list,
- struct udev_rules *rules,
- const sigset_t *sigmask) {
+ struct udev_rules *rules) {
struct udev_device *dev = event->dev;
if (udev_device_get_subsystem(dev) == NULL)
return;
if (streq(udev_device_get_action(dev), "remove")) {
- udev_device_read_db(dev, NULL);
- udev_device_delete_db(dev);
+ udev_device_read_db(dev);
udev_device_tag_index(dev, NULL, false);
+ udev_device_delete_db(dev);
if (major(udev_device_get_devnum(dev)) != 0)
udev_watch_end(event->udev, dev);
udev_rules_apply_to_event(rules, event,
timeout_usec, timeout_warn_usec,
- properties_list,
- sigmask);
+ properties_list);
if (major(udev_device_get_devnum(dev)) != 0)
udev_node_remove(dev);
} else {
- event->dev_db = udev_device_shallow_clone(dev);
+ event->dev_db = udev_device_clone_with_db(dev);
if (event->dev_db != NULL) {
- udev_device_read_db(event->dev_db, NULL);
- udev_device_set_info_loaded(event->dev_db);
-
/* disable watch during event processing */
if (major(udev_device_get_devnum(dev)) != 0)
udev_watch_end(event->udev, event->dev_db);
}
if (major(udev_device_get_devnum(dev)) == 0 &&
- streq(udev_device_get_action(dev), "move")) {
- struct udev_list_entry *entry;
-
- for ((entry = udev_device_get_properties_list_entry(event->dev_db)); entry; entry = udev_list_entry_get_next(entry)) {
- const char *key, *value;
- struct udev_list_entry *property;
-
- key = udev_list_entry_get_name(entry);
- value = udev_list_entry_get_value(entry);
-
- property = udev_device_add_property(dev, key, value);
- udev_list_entry_set_num(property, true);
- }
- }
+ streq(udev_device_get_action(dev), "move"))
+ udev_device_copy_properties(dev, event->dev_db);
udev_rules_apply_to_event(rules, event,
timeout_usec, timeout_warn_usec,
- properties_list,
- sigmask);
+ properties_list);
/* rename a new network interface, if needed */
if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") &&
@@ -850,20 +856,12 @@ void udev_event_execute_rules(struct udev_event *event,
log_warning_errno(r, "could not rename interface '%d' from '%s' to '%s': %m", udev_device_get_ifindex(dev),
udev_device_get_sysname(dev), event->name);
else {
- const char *interface_old;
-
- /* remember old name */
- interface_old = udev_device_get_sysname(dev);
-
r = udev_device_rename(dev, event->name);
if (r < 0)
log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m",
udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name);
- else {
- udev_device_add_property(dev, "INTERFACE_OLD", interface_old);
- udev_device_add_property(dev, "INTERFACE", event->name);
+ else
log_debug("changed devpath to '%s'", udev_device_get_devpath(dev));
- }
}
}
@@ -898,22 +896,18 @@ void udev_event_execute_rules(struct udev_event *event,
}
/* preserve old, or get new initialization timestamp */
- if (event->dev_db != NULL && udev_device_get_usec_initialized(event->dev_db) > 0)
- udev_device_set_usec_initialized(event->dev, udev_device_get_usec_initialized(event->dev_db));
- else if (udev_device_get_usec_initialized(event->dev) == 0)
- udev_device_set_usec_initialized(event->dev, now(CLOCK_MONOTONIC));
+ udev_device_ensure_usec_initialized(event->dev, event->dev_db);
/* (re)write database file */
- udev_device_update_db(dev);
udev_device_tag_index(dev, event->dev_db, true);
+ udev_device_update_db(dev);
udev_device_set_is_initialized(dev);
- udev_device_unref(event->dev_db);
- event->dev_db = NULL;
+ event->dev_db = udev_device_unref(event->dev_db);
}
}
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigmask) {
+void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) {
struct udev_list_entry *list_entry;
udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
@@ -936,7 +930,7 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_
udev_event_apply_format(event, cmd, program, sizeof(program));
envp = udev_device_get_properties_envp(event->dev);
- udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, NULL, 0);
+ udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, NULL, 0);
}
}
}
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 793b48469d..d824172b89 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
@@ -23,15 +22,13 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include <grp.h>
#include <dirent.h>
-#include <sys/time.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include "udev.h"
#include "smack-util.h"
#include "selinux-util.h"
+#include "formats-util.h"
static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
struct stat stats;
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index c9a0197534..915371525f 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -35,6 +35,7 @@
#include "strbuf.h"
#include "strv.h"
#include "util.h"
+#include "sysctl-util.h"
#define PREALLOC_TOKEN 2048
@@ -128,6 +129,7 @@ enum token_type {
TK_M_DRIVER, /* val */
TK_M_WAITFOR, /* val */
TK_M_ATTR, /* val, attr */
+ TK_M_SYSCTL, /* val, attr */
TK_M_PARENTS_MIN,
TK_M_KERNELS, /* val */
@@ -166,6 +168,7 @@ enum token_type {
TK_A_NAME, /* val */
TK_A_DEVLINK, /* val */
TK_A_ATTR, /* val, attr */
+ TK_A_SYSCTL, /* val, attr */
TK_A_RUN_BUILTIN, /* val, bool */
TK_A_RUN_PROGRAM, /* val, bool */
TK_A_GOTO, /* size_t */
@@ -262,6 +265,7 @@ static const char *token_str(enum token_type type) {
[TK_M_DRIVER] = "M DRIVER",
[TK_M_WAITFOR] = "M WAITFOR",
[TK_M_ATTR] = "M ATTR",
+ [TK_M_SYSCTL] = "M SYSCTL",
[TK_M_PARENTS_MIN] = "M PARENTS_MIN",
[TK_M_KERNELS] = "M KERNELS",
@@ -300,6 +304,7 @@ static const char *token_str(enum token_type type) {
[TK_A_NAME] = "A NAME",
[TK_A_DEVLINK] = "A DEVLINK",
[TK_A_ATTR] = "A ATTR",
+ [TK_A_SYSCTL] = "A SYSCTL",
[TK_A_RUN_BUILTIN] = "A RUN_BUILTIN",
[TK_A_RUN_PROGRAM] = "A RUN_PROGRAM",
[TK_A_GOTO] = "A GOTO",
@@ -363,9 +368,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
log_debug("%s %i '%s'", token_str(type), token->key.builtin_cmd, value);
break;
case TK_M_ATTR:
+ case TK_M_SYSCTL:
case TK_M_ATTRS:
case TK_M_ENV:
case TK_A_ATTR:
+ case TK_A_SYSCTL:
case TK_A_ENV:
log_debug("%s %s '%s' '%s'(%s)",
token_str(type), operation_str(op), attr, value, string_glob_str(glob));
@@ -555,7 +562,6 @@ static int import_property_from_string(struct udev_device *dev, char *line) {
char *key;
char *val;
size_t len;
- struct udev_list_entry *entry;
/* find key */
key = line;
@@ -606,10 +612,7 @@ static int import_property_from_string(struct udev_device *dev, char *line) {
val++;
}
- entry = udev_device_add_property(dev, key, val);
- /* store in db, skip private keys */
- if (key[0] != '.')
- udev_list_entry_set_num(entry, true);
+ udev_device_add_property(dev, key, val);
return 0;
}
@@ -630,7 +633,7 @@ static int import_file_into_properties(struct udev_device *dev, const char *file
static int import_program_into_properties(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *program, const sigset_t *sigmask) {
+ const char *program) {
struct udev_device *dev = event->dev;
char **envp;
char result[UTIL_LINE_SIZE];
@@ -638,7 +641,7 @@ static int import_program_into_properties(struct udev_event *event,
int err;
envp = udev_device_get_properties_envp(dev);
- err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result));
+ err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, result, sizeof(result));
if (err < 0)
return err;
@@ -661,6 +664,9 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
struct udev_device *dev_parent;
struct udev_list_entry *list_entry;
+ assert(dev);
+ assert(filter);
+
dev_parent = udev_device_get_parent(dev);
if (dev_parent == NULL)
return -1;
@@ -670,12 +676,7 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
const char *val = udev_list_entry_get_value(list_entry);
if (fnmatch(filter, key, 0) == 0) {
- struct udev_list_entry *entry;
-
- entry = udev_device_add_property(dev, key, val);
- /* store in db, skip private keys */
- if (key[0] != '.')
- udev_list_entry_set_num(entry, true);
+ udev_device_add_property(dev, key, val);
}
}
return 0;
@@ -906,8 +907,10 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
break;
case TK_M_ENV:
case TK_M_ATTR:
+ case TK_M_SYSCTL:
case TK_M_ATTRS:
case TK_A_ATTR:
+ case TK_A_SYSCTL:
case TK_A_ENV:
case TK_A_SECLABEL:
attr = data;
@@ -1144,11 +1147,27 @@ static int add_rule(struct udev_rules *rules, char *line,
log_error("invalid ATTR operation");
goto invalid;
}
- if (op < OP_MATCH_MAX) {
+ if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
- } else {
+ else
rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
+ continue;
+ }
+
+ if (startswith(key, "SYSCTL{")) {
+ attr = get_key_attribute(rules->udev, key + strlen("SYSCTL"));
+ if (attr == NULL) {
+ log_error("error parsing SYSCTL attribute");
+ goto invalid;
+ }
+ if (op == OP_REMOVE) {
+ log_error("invalid SYSCTL operation");
+ goto invalid;
}
+ if (op < OP_MATCH_MAX)
+ rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr);
+ else
+ rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr);
continue;
}
@@ -1876,8 +1895,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- struct udev_list *properties_list,
- const sigset_t *sigmask) {
+ struct udev_list *properties_list) {
struct token *cur;
struct token *rule;
enum escape_type esc = ESCAPE_UNSET;
@@ -1995,6 +2013,23 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
if (match_attr(rules, event->dev, event, cur) != 0)
goto nomatch;
break;
+ case TK_M_SYSCTL: {
+ char filename[UTIL_PATH_SIZE];
+ _cleanup_free_ char *value = NULL;
+ size_t len;
+
+ udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename));
+ sysctl_normalize(filename);
+ if (sysctl_read(filename, &value) < 0)
+ goto nomatch;
+
+ len = strlen(value);
+ while (len > 0 && isspace(value[--len]))
+ value[len] = '\0';
+ if (match_key(rules, cur, value) != 0)
+ goto nomatch;
+ break;
+ }
case TK_M_KERNELS:
case TK_M_SUBSYSTEMS:
case TK_M_DRIVERS:
@@ -2096,7 +2131,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off),
rule->rule.filename_line);
- if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result)) < 0) {
+ if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, result, sizeof(result)) < 0) {
if (cur->key.op != OP_NOMATCH)
goto nomatch;
} else {
@@ -2132,7 +2167,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off),
rule->rule.filename_line);
- if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import, sigmask) != 0)
+ if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import) != 0)
if (cur->key.op != OP_NOMATCH)
goto nomatch;
break;
@@ -2178,12 +2213,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
const char *value;
value = udev_device_get_property_value(event->dev_db, key);
- if (value != NULL) {
- struct udev_list_entry *entry;
-
- entry = udev_device_add_property(event->dev, key, value);
- udev_list_entry_set_num(entry, true);
- } else {
+ if (value != NULL)
+ udev_device_add_property(event->dev, key, value);
+ else {
if (cur->key.op != OP_NOMATCH)
goto nomatch;
}
@@ -2203,13 +2235,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
pos = strstr(cmdline, key);
if (pos != NULL) {
- struct udev_list_entry *entry;
-
pos += strlen(key);
if (pos[0] == '\0' || isspace(pos[0])) {
/* we import simple flags as 'FLAG=1' */
- entry = udev_device_add_property(event->dev, key, "1");
- udev_list_entry_set_num(entry, true);
+ udev_device_add_property(event->dev, key, "1");
imported = true;
} else if (pos[0] == '=') {
const char *value;
@@ -2219,8 +2248,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
while (pos[0] != '\0' && !isspace(pos[0]))
pos++;
pos[0] = '\0';
- entry = udev_device_add_property(event->dev, key, value);
- udev_list_entry_set_num(entry, true);
+ udev_device_add_property(event->dev, key, value);
imported = true;
}
}
@@ -2393,7 +2421,6 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
char *value = rules_str(rules, cur->key.value_off);
char value_new[UTIL_NAME_SIZE];
const char *value_old = NULL;
- struct udev_list_entry *entry;
if (value[0] == '\0') {
if (cur->key.op == OP_ADD)
@@ -2413,10 +2440,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
} else
udev_event_apply_format(event, value, value_new, sizeof(value_new));
- entry = udev_device_add_property(event->dev, name, value_new);
- /* store in db, skip private keys */
- if (name[0] != '.')
- udev_list_entry_set_num(entry, true);
+ udev_device_add_property(event->dev, name, value_new);
break;
}
case TK_A_TAG: {
@@ -2542,6 +2566,21 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
}
break;
}
+ case TK_A_SYSCTL: {
+ char filename[UTIL_PATH_SIZE];
+ char value[UTIL_NAME_SIZE];
+ int r;
+
+ udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename));
+ sysctl_normalize(filename);
+ udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value));
+ log_debug("SYSCTL '%s' writing '%s' %s:%u", filename, value,
+ rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
+ r = sysctl_write(filename, value);
+ if (r < 0)
+ log_error("error writing SYSCTL{%s}='%s': %s", filename, value, strerror(-r));
+ break;
+ }
case TK_A_RUN_BUILTIN:
case TK_A_RUN_PROGRAM: {
struct udev_list_entry *entry;
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index 6ba8674d77..15b76dd6ab 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -17,14 +17,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sys/types.h>
#include <errno.h>
-#include <fcntl.h>
#include <stdio.h>
#include <dirent.h>
#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
#include <sys/inotify.h>
diff --git a/src/udev/udev.h b/src/udev/udev.h
index dece6eccab..fd8504c424 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -20,7 +20,6 @@
#include <sys/types.h>
#include <sys/param.h>
-#include <signal.h>
#include "macro.h"
#include "sd-rtnl.h"
@@ -44,11 +43,9 @@ struct udev_event {
struct udev_list run_list;
int exec_delay;
usec_t birth_usec;
- int fd_signal;
sd_rtnl *rtnl;
unsigned int builtin_run;
unsigned int builtin_ret;
- bool sigterm;
bool inotify_watch;
bool inotify_watch_final;
bool group_set;
@@ -75,8 +72,7 @@ struct udev_rules *udev_rules_unref(struct udev_rules *rules);
bool udev_rules_check_timestamp(struct udev_rules *rules);
int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_list *properties_list,
- const sigset_t *sigmask);
+ struct udev_list *properties_list);
int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
/* udev-event.c */
@@ -88,14 +84,13 @@ int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
int udev_event_spawn(struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
- const char *cmd, char **envp, const sigset_t *sigmask,
+ const char *cmd, char **envp,
char *result, size_t ressize);
void udev_event_execute_rules(struct udev_event *event,
usec_t timeout_usec, usec_t timeout_warn_usec,
struct udev_list *properties_list,
- struct udev_rules *rules,
- const sigset_t *sigset);
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigset);
+ struct udev_rules *rules);
+void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec);
int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
/* udev-watch.c */
diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c
index 6af7163d47..78170463b6 100644
--- a/src/udev/udevadm-control.c
+++ b/src/udev/udevadm-control.c
@@ -12,7 +12,6 @@
* GNU General Public License for more details.
*/
-#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -20,10 +19,6 @@
#include <string.h>
#include <unistd.h>
#include <getopt.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/un.h>
#include "udev.h"
#include "udev-util.h"
diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
index d65e40c011..00609e31b5 100644
--- a/src/udev/udevadm-hwdb.c
+++ b/src/udev/udevadm-hwdb.c
@@ -18,7 +18,6 @@
***/
#include <stdlib.h>
-#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <ctype.h>
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index 0bab01a234..b3d5565c48 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -15,19 +15,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
-#include <stdarg.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include "udev.h"
#include "udev-util.h"
@@ -208,17 +205,15 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
if ((stats.st_mode & mask) != 0)
continue;
if (S_ISDIR(stats.st_mode)) {
- DIR *dir2;
+ _cleanup_closedir_ DIR *dir2;
dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
- if (dir2 != NULL) {
+ if (dir2 != NULL)
cleanup_dir(dir2, mask, depth-1);
- closedir(dir2);
- }
- unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
- } else {
- unlinkat(dirfd(dir), dent->d_name, 0);
- }
+
+ (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
+ } else
+ (void) unlinkat(dirfd(dir), dent->d_name, 0);
}
}
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index 15ded09339..5e93955186 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -15,25 +15,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <unistd.h>
#include <stdio.h>
-#include <stdlib.h>
#include <stddef.h>
#include <string.h>
-#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <getopt.h>
#include <time.h>
#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/un.h>
#include <sys/epoll.h>
-#include <linux/types.h>
-#include <linux/netlink.h>
#include "udev.h"
#include "udev-util.h"
+#include "formats-util.h"
static bool udev_exit;
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
index fff5de7a8b..79f45610db 100644
--- a/src/udev/udevadm-settle.c
+++ b/src/udev/udevadm-settle.c
@@ -23,17 +23,10 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
#include <getopt.h>
-#include <signal.h>
-#include <time.h>
#include <poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include "udev.h"
-#include "udev-util.h"
#include "util.h"
static void help(void) {
@@ -56,6 +49,7 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
{ "quiet", no_argument, NULL, 'q' }, /* removed */
{}
};
+ usec_t deadline;
const char *exists = NULL;
unsigned int timeout = 120;
struct pollfd pfd[1] = { {.fd = -1}, };
@@ -105,13 +99,15 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
return EXIT_FAILURE;
}
+ deadline = now(CLOCK_MONOTONIC) + timeout * USEC_PER_SEC;
+
/* guarantee that the udev daemon isn't pre-processing */
if (getuid() == 0) {
struct udev_ctrl *uctrl;
uctrl = udev_ctrl_new(udev);
if (uctrl != NULL) {
- if (udev_ctrl_send_ping(uctrl, timeout) < 0) {
+ if (udev_ctrl_send_ping(uctrl, MAX(5U, timeout)) < 0) {
log_debug("no connection to daemon");
udev_ctrl_unref(uctrl);
return EXIT_SUCCESS;
@@ -146,6 +142,9 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
break;
}
+ if (now(CLOCK_MONOTONIC) >= deadline)
+ break;
+
/* wake up when queue is empty */
if (poll(pfd, 1, MSEC_PER_SEC) > 0 && pfd[0].revents & POLLIN)
udev_queue_flush(queue);
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index baaeca9352..35a7349439 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -17,19 +17,9 @@
#include <stdlib.h>
#include <stddef.h>
-#include <string.h>
#include <stdio.h>
-#include <unistd.h>
#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
#include <getopt.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/inotify.h>
-#include <poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include "udev.h"
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index 4922b5b6ac..d04e618d0d 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -17,13 +17,10 @@
*/
#include <stdlib.h>
-#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
-#include <ctype.h>
-#include <fcntl.h>
#include <signal.h>
#include <getopt.h>
#include <sys/signalfd.h>
@@ -120,34 +117,25 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
strscpy(filename, sizeof(filename), syspath);
util_remove_trailing_chars(filename, '/');
- dev = udev_device_new_from_syspath(udev, filename);
+ dev = udev_device_new_from_synthetic_event(udev, filename, action);
if (dev == NULL) {
fprintf(stderr, "unable to open device '%s'\n", filename);
rc = 4;
goto out;
}
- /* skip reading of db, but read kernel parameters */
+ /* don't read info from the db */
udev_device_set_info_loaded(dev);
- udev_device_read_uevent_file(dev);
- udev_device_set_action(dev, action);
event = udev_event_new(dev);
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
- event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (event->fd_signal < 0) {
- fprintf(stderr, "error creating signalfd\n");
- rc = 5;
- goto out;
- }
udev_event_execute_rules(event,
60 * USEC_PER_SEC, 20 * USEC_PER_SEC,
NULL,
- rules,
- &sigmask_orig);
+ rules);
udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev))
printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
@@ -159,8 +147,6 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
printf("run: '%s'\n", program);
}
out:
- if (event != NULL && event->fd_signal >= 0)
- close(event->fd_signal);
udev_builtin_exit(udev);
return rc;
}
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 4dc756a28b..11e83f355f 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -15,20 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
-#include <dirent.h>
#include <fcntl.h>
-#include <fnmatch.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
#include "udev.h"
#include "udev-util.h"
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index 56cd0cd4ec..b86d8921f3 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -16,11 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <unistd.h>
#include <stdio.h>
-#include <stdlib.h>
#include <stddef.h>
-#include <string.h>
#include <errno.h>
#include <getopt.h>
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 99d4c8983a..eb43091190 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -26,58 +26,70 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
-#include <ctype.h>
#include <fcntl.h>
-#include <time.h>
#include <getopt.h>
-#include <dirent.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/prctl.h>
#include <sys/socket.h>
-#include <sys/un.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <sys/mount.h>
-#include <poll.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
-#include <sys/utsname.h>
#include "sd-daemon.h"
+#include "sd-event.h"
+
+#include "signal-util.h"
+#include "event-util.h"
#include "rtnl-util.h"
#include "cgroup-util.h"
+#include "process-util.h"
#include "dev-setup.h"
#include "fileio.h"
#include "selinux-util.h"
#include "udev.h"
#include "udev-util.h"
+#include "formats-util.h"
+#include "hashmap.h"
-static struct udev_rules *rules;
-static struct udev_ctrl *udev_ctrl;
-static struct udev_monitor *monitor;
-static int worker_watch[2] = { -1, -1 };
-static int fd_signal = -1;
-static int fd_ep = -1;
-static int fd_inotify = -1;
-static bool stop_exec_queue;
-static bool reload;
-static int children;
static bool arg_debug = false;
static int arg_daemonize = false;
static int arg_resolve_names = 1;
-static int arg_children_max;
+static unsigned arg_children_max;
static int arg_exec_delay;
static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
-static sigset_t sigmask_orig;
-static UDEV_LIST(event_list);
-static UDEV_LIST(worker_list);
-static char *udev_cgroup;
-static struct udev_list properties_list;
-static bool udev_exit;
+
+typedef struct Manager {
+ struct udev *udev;
+ sd_event *event;
+ Hashmap *workers;
+ struct udev_list_node events;
+ const char *cgroup;
+ pid_t pid; /* the process that originally allocated the manager object */
+
+ struct udev_rules *rules;
+ struct udev_list properties;
+
+ struct udev_monitor *monitor;
+ struct udev_ctrl *ctrl;
+ struct udev_ctrl_connection *ctrl_conn_blocking;
+ int fd_inotify;
+ int worker_watch[2];
+
+ sd_event_source *ctrl_event;
+ sd_event_source *uevent_event;
+ sd_event_source *inotify_event;
+
+ usec_t last_usec;
+
+ bool stop_exec_queue:1;
+ bool exit:1;
+} Manager;
enum event_state {
EVENT_UNDEF,
@@ -87,10 +99,12 @@ enum event_state {
struct event {
struct udev_list_node node;
+ Manager *manager;
struct udev *udev;
struct udev_device *dev;
+ struct udev_device *dev_kernel;
+ struct worker *worker;
enum event_state state;
- int exitcode;
unsigned long long int delaying_seqnum;
unsigned long long int seqnum;
const char *devpath;
@@ -99,13 +113,15 @@ struct event {
dev_t devnum;
int ifindex;
bool is_block;
+ sd_event_source *timeout_warning;
+ sd_event_source *timeout;
};
static inline struct event *node_to_event(struct udev_list_node *node) {
return container_of(node, struct event, node);
}
-static void event_queue_cleanup(struct udev *udev, enum event_state type);
+static void event_queue_cleanup(Manager *manager, enum event_state type);
enum worker_state {
WORKER_UNDEF,
@@ -115,67 +131,200 @@ enum worker_state {
};
struct worker {
+ Manager *manager;
struct udev_list_node node;
- struct udev *udev;
int refcount;
pid_t pid;
struct udev_monitor *monitor;
enum worker_state state;
struct event *event;
- usec_t event_start_usec;
- bool event_warned;
};
/* passed from worker to main process */
struct worker_message {
- pid_t pid;
- int exitcode;
};
-static inline struct worker *node_to_worker(struct udev_list_node *node) {
- return container_of(node, struct worker, node);
-}
+static void event_free(struct event *event) {
+ int r;
+
+ if (!event)
+ return;
-static void event_queue_delete(struct event *event) {
udev_list_node_remove(&event->node);
udev_device_unref(event->dev);
+ udev_device_unref(event->dev_kernel);
+
+ sd_event_source_unref(event->timeout_warning);
+ sd_event_source_unref(event->timeout);
+
+ if (event->worker)
+ event->worker->event = NULL;
+
+ assert(event->manager);
+
+ if (udev_list_node_is_empty(&event->manager->events)) {
+ /* only clean up the queue from the process that created it */
+ if (event->manager->pid == getpid()) {
+ r = unlink("/run/udev/queue");
+ if (r < 0)
+ log_warning_errno(errno, "could not unlink /run/udev/queue: %m");
+ }
+ }
+
free(event);
}
-static struct worker *worker_ref(struct worker *worker) {
- worker->refcount++;
- return worker;
-}
+static void worker_free(struct worker *worker) {
+ if (!worker)
+ return;
-static void worker_cleanup(struct worker *worker) {
- udev_list_node_remove(&worker->node);
+ assert(worker->manager);
+
+ hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid));
udev_monitor_unref(worker->monitor);
- children--;
+ event_free(worker->event);
+
free(worker);
}
-static void worker_unref(struct worker *worker) {
- worker->refcount--;
- if (worker->refcount > 0)
+static void manager_workers_free(Manager *manager) {
+ struct worker *worker;
+ Iterator i;
+
+ assert(manager);
+
+ HASHMAP_FOREACH(worker, manager->workers, i)
+ worker_free(worker);
+
+ manager->workers = hashmap_free(manager->workers);
+}
+
+static int worker_new(struct worker **ret, Manager *manager, struct udev_monitor *worker_monitor, pid_t pid) {
+ _cleanup_free_ struct worker *worker = NULL;
+ int r;
+
+ assert(ret);
+ assert(manager);
+ assert(worker_monitor);
+ assert(pid > 1);
+
+ worker = new0(struct worker, 1);
+ if (!worker)
+ return -ENOMEM;
+
+ worker->refcount = 1;
+ worker->manager = manager;
+ /* close monitor, but keep address around */
+ udev_monitor_disconnect(worker_monitor);
+ worker->monitor = udev_monitor_ref(worker_monitor);
+ worker->pid = pid;
+
+ r = hashmap_ensure_allocated(&manager->workers, NULL);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker);
+ if (r < 0)
+ return r;
+
+ *ret = worker;
+ worker = NULL;
+
+ return 0;
+}
+
+static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ struct event *event = userdata;
+
+ assert(event);
+ assert(event->worker);
+
+ kill_and_sigcont(event->worker->pid, SIGKILL);
+ event->worker->state = WORKER_KILLED;
+
+ log_error("seq %llu '%s' killed", udev_device_get_seqnum(event->dev), event->devpath);
+
+ return 1;
+}
+
+static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
+ struct event *event = userdata;
+
+ assert(event);
+
+ log_warning("seq %llu '%s' is taking a long time", udev_device_get_seqnum(event->dev), event->devpath);
+
+ return 1;
+}
+
+static void worker_attach_event(struct worker *worker, struct event *event) {
+ sd_event *e;
+ uint64_t usec;
+ int r;
+
+ assert(worker);
+ assert(worker->manager);
+ assert(event);
+ assert(!event->worker);
+ assert(!worker->event);
+
+ worker->state = WORKER_RUNNING;
+ worker->event = event;
+ event->state = EVENT_RUNNING;
+ event->worker = worker;
+
+ e = worker->manager->event;
+
+ r = sd_event_now(e, clock_boottime_or_monotonic(), &usec);
+ if (r < 0)
return;
- log_debug("worker ["PID_FMT"] cleaned up", worker->pid);
- worker_cleanup(worker);
+
+ (void) sd_event_add_time(e, &event->timeout_warning, clock_boottime_or_monotonic(),
+ usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event);
+
+ (void) sd_event_add_time(e, &event->timeout, clock_boottime_or_monotonic(),
+ usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event);
}
-static void worker_list_cleanup(struct udev *udev) {
- struct udev_list_node *loop, *tmp;
+static void manager_free(Manager *manager) {
+ if (!manager)
+ return;
- udev_list_node_foreach_safe(loop, tmp, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ udev_builtin_exit(manager->udev);
- worker_cleanup(worker);
- }
+ sd_event_source_unref(manager->ctrl_event);
+ sd_event_source_unref(manager->uevent_event);
+ sd_event_source_unref(manager->inotify_event);
+
+ udev_unref(manager->udev);
+ sd_event_unref(manager->event);
+ manager_workers_free(manager);
+ event_queue_cleanup(manager, EVENT_UNDEF);
+
+ udev_monitor_unref(manager->monitor);
+ udev_ctrl_unref(manager->ctrl);
+ udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
+
+ udev_list_cleanup(&manager->properties);
+ udev_rules_unref(manager->rules);
+
+ safe_close(manager->fd_inotify);
+ safe_close_pair(manager->worker_watch);
+
+ free(manager);
}
-static void worker_new(struct event *event) {
+DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
+
+static int worker_send_message(int fd) {
+ struct worker_message message = {};
+
+ return loop_write(fd, &message, sizeof(message), false);
+}
+
+static void worker_spawn(Manager *manager, struct event *event) {
struct udev *udev = event->udev;
- struct worker *worker;
- struct udev_monitor *worker_monitor;
+ _cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
pid_t pid;
/* listen for new events */
@@ -183,69 +332,62 @@ static void worker_new(struct event *event) {
if (worker_monitor == NULL)
return;
/* allow the main daemon netlink address to send devices to the worker */
- udev_monitor_allow_unicast_sender(worker_monitor, monitor);
+ udev_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
udev_monitor_enable_receiving(worker_monitor);
- worker = new0(struct worker, 1);
- if (worker == NULL) {
- udev_monitor_unref(worker_monitor);
- return;
- }
- /* worker + event reference */
- worker->refcount = 2;
- worker->udev = udev;
-
pid = fork();
switch (pid) {
case 0: {
struct udev_device *dev = NULL;
- int fd_monitor;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- struct epoll_event ep_signal, ep_monitor;
+ int fd_monitor;
+ _cleanup_close_ int fd_signal = -1, fd_ep = -1;
+ struct epoll_event ep_signal = { .events = EPOLLIN };
+ struct epoll_event ep_monitor = { .events = EPOLLIN };
sigset_t mask;
- int rc = EXIT_SUCCESS;
+ int r = 0;
/* take initial device from queue */
dev = event->dev;
event->dev = NULL;
- free(worker);
- worker_list_cleanup(udev);
- event_queue_cleanup(udev, EVENT_UNDEF);
- udev_monitor_unref(monitor);
- udev_ctrl_unref(udev_ctrl);
- close(fd_signal);
- close(fd_ep);
- close(worker_watch[READ_END]);
+ unsetenv("NOTIFY_SOCKET");
+
+ manager_workers_free(manager);
+ event_queue_cleanup(manager, EVENT_UNDEF);
+
+ manager->monitor = udev_monitor_unref(manager->monitor);
+ manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
+ manager->ctrl = udev_ctrl_unref(manager->ctrl);
+ manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
+ manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
+
+ manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
+ manager->uevent_event = sd_event_source_unref(manager->uevent_event);
+ manager->inotify_event = sd_event_source_unref(manager->inotify_event);
+
+ manager->event = sd_event_unref(manager->event);
sigfillset(&mask);
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (fd_signal < 0) {
- log_error_errno(errno, "error creating signalfd %m");
- rc = 2;
+ r = log_error_errno(errno, "error creating signalfd %m");
goto out;
}
+ ep_signal.data.fd = fd_signal;
+
+ fd_monitor = udev_monitor_get_fd(worker_monitor);
+ ep_monitor.data.fd = fd_monitor;
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
- log_error_errno(errno, "error creating epoll fd: %m");
- rc = 3;
+ r = log_error_errno(errno, "error creating epoll fd: %m");
goto out;
}
- memzero(&ep_signal, sizeof(struct epoll_event));
- ep_signal.events = EPOLLIN;
- ep_signal.data.fd = fd_signal;
-
- fd_monitor = udev_monitor_get_fd(worker_monitor);
- memzero(&ep_monitor, sizeof(struct epoll_event));
- ep_monitor.events = EPOLLIN;
- ep_monitor.data.fd = fd_monitor;
-
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
- log_error_errno(errno, "fail to add fds to epoll: %m");
- rc = 4;
+ r = log_error_errno(errno, "fail to add fds to epoll: %m");
goto out;
}
@@ -257,20 +399,17 @@ static void worker_new(struct event *event) {
for (;;) {
struct udev_event *udev_event;
- struct worker_message msg;
int fd_lock = -1;
- int err = 0;
+
+ assert(dev);
log_debug("seq %llu running", udev_device_get_seqnum(dev));
udev_event = udev_event_new(dev);
if (udev_event == NULL) {
- rc = 5;
+ r = -ENOMEM;
goto out;
}
- /* needed for SIGCHLD/SIGTERM in spawn() */
- udev_event->fd_signal = fd_signal;
-
if (arg_exec_delay > 0)
udev_event->exec_delay = arg_exec_delay;
@@ -295,8 +434,8 @@ static void worker_new(struct event *event) {
fd_lock = open(udev_device_get_devnode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
- err = -EWOULDBLOCK;
fd_lock = safe_close(fd_lock);
+ r = -EAGAIN;
goto skip;
}
}
@@ -308,13 +447,11 @@ static void worker_new(struct event *event) {
/* apply rules, create node, symlinks */
udev_event_execute_rules(udev_event,
arg_event_timeout_usec, arg_event_timeout_warn_usec,
- &properties_list,
- rules,
- &sigmask_orig);
+ &manager->properties,
+ manager->rules);
udev_event_execute_run(udev_event,
- arg_event_timeout_usec, arg_event_timeout_warn_usec,
- &sigmask_orig);
+ arg_event_timeout_usec, arg_event_timeout_warn_usec);
if (udev_event->rtnl)
/* in case rtnl was initialized */
@@ -332,22 +469,17 @@ static void worker_new(struct event *event) {
udev_monitor_send_device(worker_monitor, NULL, dev);
skip:
- /* send udevd the result of the event execution */
- memzero(&msg, sizeof(struct worker_message));
- msg.exitcode = err;
- msg.pid = getpid();
- send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
+ log_debug("seq %llu processed", udev_device_get_seqnum(dev));
- log_debug("seq %llu processed with %i", udev_device_get_seqnum(dev), err);
+ /* send udevd the result of the event execution */
+ r = worker_send_message(manager->worker_watch[WRITE_END]);
+ if (r < 0)
+ log_error_errno(r, "failed to send result of seq %llu to main daemon: %m",
+ udev_device_get_seqnum(dev));
udev_device_unref(dev);
dev = NULL;
- if (udev_event->sigterm) {
- udev_event_unref(udev_event);
- goto out;
- }
-
udev_event_unref(udev_event);
/* wait for more device messages from main udevd, or term signal */
@@ -360,7 +492,7 @@ skip:
if (fdcount < 0) {
if (errno == EINTR)
continue;
- log_error_errno(errno, "failed to poll: %m");
+ r = log_error_errno(errno, "failed to poll: %m");
goto out;
}
@@ -385,51 +517,45 @@ skip:
}
out:
udev_device_unref(dev);
- safe_close(fd_signal);
- safe_close(fd_ep);
- close(fd_inotify);
- close(worker_watch[WRITE_END]);
- udev_rules_unref(rules);
- udev_builtin_exit(udev);
- udev_monitor_unref(worker_monitor);
- udev_unref(udev);
+ manager_free(manager);
log_close();
- exit(rc);
+ _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
case -1:
- udev_monitor_unref(worker_monitor);
event->state = EVENT_QUEUED;
- free(worker);
log_error_errno(errno, "fork of child failed: %m");
break;
default:
- /* close monitor, but keep address around */
- udev_monitor_disconnect(worker_monitor);
- worker->monitor = worker_monitor;
- worker->pid = pid;
- worker->state = WORKER_RUNNING;
- worker->event_start_usec = now(CLOCK_MONOTONIC);
- worker->event_warned = false;
- worker->event = event;
- event->state = EVENT_RUNNING;
- udev_list_node_append(&worker->node, &worker_list);
- children++;
+ {
+ struct worker *worker;
+ int r;
+
+ r = worker_new(&worker, manager, worker_monitor, pid);
+ if (r < 0)
+ return;
+
+ worker_attach_event(worker, event);
+
log_debug("seq %llu forked new worker ["PID_FMT"]", udev_device_get_seqnum(event->dev), pid);
break;
}
+ }
}
-static void event_run(struct event *event) {
- struct udev_list_node *loop;
+static void event_run(Manager *manager, struct event *event) {
+ struct worker *worker;
+ Iterator i;
+
+ assert(manager);
+ assert(event);
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ HASHMAP_FOREACH(worker, manager->workers, i) {
ssize_t count;
if (worker->state != WORKER_IDLE)
continue;
- count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
+ count = udev_monitor_send_device(manager->monitor, worker->monitor, event->dev);
if (count < 0) {
log_error_errno(errno, "worker ["PID_FMT"] did not accept message %zi (%m), kill it",
worker->pid, count);
@@ -437,34 +563,42 @@ static void event_run(struct event *event) {
worker->state = WORKER_KILLED;
continue;
}
- worker_ref(worker);
- worker->event = event;
- worker->state = WORKER_RUNNING;
- worker->event_start_usec = now(CLOCK_MONOTONIC);
- worker->event_warned = false;
- event->state = EVENT_RUNNING;
+ worker_attach_event(worker, event);
return;
}
- if (children >= arg_children_max) {
+ if (hashmap_size(manager->workers) >= arg_children_max) {
if (arg_children_max > 1)
- log_debug("maximum number (%i) of children reached", children);
+ log_debug("maximum number (%i) of children reached", hashmap_size(manager->workers));
return;
}
/* start new worker and pass initial device */
- worker_new(event);
+ worker_spawn(manager, event);
}
-static int event_queue_insert(struct udev_device *dev) {
+static int event_queue_insert(Manager *manager, struct udev_device *dev) {
struct event *event;
+ int r;
+
+ assert(manager);
+ assert(dev);
+
+ /* only one process can add events to the queue */
+ if (manager->pid == 0)
+ manager->pid = getpid();
+
+ assert(manager->pid == getpid());
event = new0(struct event, 1);
- if (event == NULL)
- return -1;
+ if (!event)
+ return -ENOMEM;
event->udev = udev_device_get_udev(dev);
+ event->manager = manager;
event->dev = dev;
+ event->dev_kernel = udev_device_shallow_clone(dev);
+ udev_device_copy_properties(event->dev_kernel, dev);
event->seqnum = udev_device_get_seqnum(dev);
event->devpath = udev_device_get_devpath(dev);
event->devpath_len = strlen(event->devpath);
@@ -477,16 +611,25 @@ static int event_queue_insert(struct udev_device *dev) {
udev_device_get_action(dev), udev_device_get_subsystem(dev));
event->state = EVENT_QUEUED;
- udev_list_node_append(&event->node, &event_list);
+
+ if (udev_list_node_is_empty(&manager->events)) {
+ r = touch("/run/udev/queue");
+ if (r < 0)
+ log_warning_errno(r, "could not touch /run/udev/queue: %m");
+ }
+
+ udev_list_node_append(&event->node, &manager->events);
+
return 0;
}
-static void worker_kill(struct udev *udev) {
- struct udev_list_node *loop;
+static void manager_kill_workers(Manager *manager) {
+ struct worker *worker;
+ Iterator i;
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ assert(manager);
+ HASHMAP_FOREACH(worker, manager->workers, i) {
if (worker->state == WORKER_KILLED)
continue;
@@ -496,12 +639,12 @@ static void worker_kill(struct udev *udev) {
}
/* lookup event for identical, parent, child device */
-static bool is_devpath_busy(struct event *event) {
+static bool is_devpath_busy(Manager *manager, struct event *event) {
struct udev_list_node *loop;
size_t common;
/* check if queue contains events we depend on */
- udev_list_node_foreach(loop, &event_list) {
+ udev_list_node_foreach(loop, &manager->events) {
struct event *loop_event = node_to_event(loop);
/* we already found a later event, earlier can not block us, no need to check again */
@@ -567,111 +710,271 @@ static bool is_devpath_busy(struct event *event) {
return false;
}
-static void event_queue_start(struct udev *udev) {
+static int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ Manager *manager = userdata;
+
+ assert(manager);
+
+ log_error_errno(ETIMEDOUT, "giving up waiting for workers to finish");
+
+ sd_event_exit(manager->event, -ETIMEDOUT);
+
+ return 1;
+}
+
+static void manager_exit(Manager *manager) {
+ uint64_t usec;
+ int r;
+
+ assert(manager);
+
+ manager->exit = true;
+
+ sd_notify(false,
+ "STOPPING=1\n"
+ "STATUS=Starting shutdown...");
+
+ /* close sources of new events and discard buffered events */
+ manager->ctrl = udev_ctrl_unref(manager->ctrl);
+ manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
+
+ manager->fd_inotify = safe_close(manager->fd_inotify);
+ manager->inotify_event = sd_event_source_unref(manager->inotify_event);
+
+ manager->monitor = udev_monitor_unref(manager->monitor);
+ manager->uevent_event = sd_event_source_unref(manager->uevent_event);
+
+ /* discard queued events and kill workers */
+ event_queue_cleanup(manager, EVENT_QUEUED);
+ manager_kill_workers(manager);
+
+ r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
+ if (r < 0)
+ return;
+
+ r = sd_event_add_time(manager->event, NULL, clock_boottime_or_monotonic(),
+ usec + 30 * USEC_PER_SEC, USEC_PER_SEC, on_exit_timeout, manager);
+ if (r < 0)
+ return;
+}
+
+/* reload requested, HUP signal received, rules changed, builtin changed */
+static void manager_reload(Manager *manager) {
+
+ assert(manager);
+
+ sd_notify(false,
+ "RELOADING=1\n"
+ "STATUS=Flushing configuration...");
+
+ manager_kill_workers(manager);
+ manager->rules = udev_rules_unref(manager->rules);
+ udev_builtin_exit(manager->udev);
+
+ sd_notify(false,
+ "READY=1\n"
+ "STATUS=Processing...");
+}
+
+static void event_queue_start(Manager *manager) {
struct udev_list_node *loop;
+ usec_t usec;
+ int r;
+
+ assert(manager);
+
+ if (udev_list_node_is_empty(&manager->events) ||
+ manager->exit || manager->stop_exec_queue)
+ return;
- udev_list_node_foreach(loop, &event_list) {
+ r = sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec);
+ if (r >= 0) {
+ /* check for changed config, every 3 seconds at most */
+ if (manager->last_usec == 0 ||
+ (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
+ if (udev_rules_check_timestamp(manager->rules) ||
+ udev_builtin_validate(manager->udev))
+ manager_reload(manager);
+
+ manager->last_usec = usec;
+ }
+ }
+
+ udev_builtin_init(manager->udev);
+
+ if (!manager->rules) {
+ manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
+ if (!manager->rules)
+ return;
+ }
+
+ udev_list_node_foreach(loop, &manager->events) {
struct event *event = node_to_event(loop);
if (event->state != EVENT_QUEUED)
continue;
/* do not start event if parent or child event is still running */
- if (is_devpath_busy(event))
+ if (is_devpath_busy(manager, event))
continue;
- event_run(event);
+ event_run(manager, event);
}
}
-static void event_queue_cleanup(struct udev *udev, enum event_state match_type) {
+static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
struct udev_list_node *loop, *tmp;
- udev_list_node_foreach_safe(loop, tmp, &event_list) {
+ udev_list_node_foreach_safe(loop, tmp, &manager->events) {
struct event *event = node_to_event(loop);
if (match_type != EVENT_UNDEF && match_type != event->state)
continue;
- event_queue_delete(event);
+ event_free(event);
}
}
-static void worker_returned(int fd_worker) {
+static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ Manager *manager = userdata;
+
+ assert(manager);
+
for (;;) {
struct worker_message msg;
+ struct iovec iovec = {
+ .iov_base = &msg,
+ .iov_len = sizeof(msg),
+ };
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
+ } control = {};
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
ssize_t size;
- struct udev_list_node *loop;
+ struct ucred *ucred = NULL;
+ struct worker *worker;
- size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
- if (size != sizeof(struct worker_message))
- break;
+ size = recvmsg(fd, &msghdr, MSG_DONTWAIT);
+ if (size < 0) {
+ if (errno == EINTR)
+ continue;
+ else if (errno == EAGAIN)
+ /* nothing more to read */
+ break;
- /* lookup worker who sent the signal */
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
+ return log_error_errno(errno, "failed to receive message: %m");
+ } else if (size != sizeof(struct worker_message)) {
+ log_warning_errno(EIO, "ignoring worker message with invalid size %zi bytes", size);
+ continue;
+ }
- if (worker->pid != msg.pid)
- continue;
+ for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ }
- /* worker returned */
- if (worker->event) {
- worker->event->exitcode = msg.exitcode;
- event_queue_delete(worker->event);
- worker->event = NULL;
- }
- if (worker->state != WORKER_KILLED)
- worker->state = WORKER_IDLE;
- worker_unref(worker);
- break;
+ if (!ucred || ucred->pid <= 0) {
+ log_warning_errno(EIO, "ignoring worker message without valid PID");
+ continue;
}
+
+ /* lookup worker who sent the signal */
+ worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid));
+ if (!worker) {
+ log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
+ continue;
+ }
+
+ if (worker->state != WORKER_KILLED)
+ worker->state = WORKER_IDLE;
+
+ /* worker returned */
+ event_free(worker->event);
}
+
+ /* we have free workers, try to schedule events */
+ event_queue_start(manager);
+
+ return 1;
+}
+
+static int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ Manager *manager = userdata;
+ struct udev_device *dev;
+ int r;
+
+ assert(manager);
+
+ dev = udev_monitor_receive_device(manager->monitor);
+ if (dev) {
+ udev_device_ensure_usec_initialized(dev, NULL);
+ r = event_queue_insert(manager, dev);
+ if (r < 0)
+ udev_device_unref(dev);
+ else
+ /* we have fresh events, try to schedule them */
+ event_queue_start(manager);
+ }
+
+ return 1;
}
/* receive the udevd message from userspace */
-static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) {
- struct udev *udev = udev_ctrl_get_udev(uctrl);
- struct udev_ctrl_connection *ctrl_conn;
- struct udev_ctrl_msg *ctrl_msg = NULL;
+static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ Manager *manager = userdata;
+ _cleanup_udev_ctrl_connection_unref_ struct udev_ctrl_connection *ctrl_conn = NULL;
+ _cleanup_udev_ctrl_msg_unref_ struct udev_ctrl_msg *ctrl_msg = NULL;
const char *str;
int i;
- ctrl_conn = udev_ctrl_get_connection(uctrl);
- if (ctrl_conn == NULL)
- goto out;
+ assert(manager);
+
+ ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
+ if (!ctrl_conn)
+ return 1;
ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
- if (ctrl_msg == NULL)
- goto out;
+ if (!ctrl_msg)
+ return 1;
i = udev_ctrl_get_set_log_level(ctrl_msg);
if (i >= 0) {
log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
log_set_max_level(i);
- worker_kill(udev);
+ manager_kill_workers(manager);
}
if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
log_debug("udevd message (STOP_EXEC_QUEUE) received");
- stop_exec_queue = true;
+ manager->stop_exec_queue = true;
}
if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
log_debug("udevd message (START_EXEC_QUEUE) received");
- stop_exec_queue = false;
+ manager->stop_exec_queue = false;
+ event_queue_start(manager);
}
if (udev_ctrl_get_reload(ctrl_msg) > 0) {
log_debug("udevd message (RELOAD) received");
- reload = true;
+ manager_reload(manager);
}
str = udev_ctrl_get_set_env(ctrl_msg);
if (str != NULL) {
- char *key;
+ _cleanup_free_ char *key = NULL;
key = strdup(str);
- if (key != NULL) {
+ if (key) {
char *val;
val = strchr(key, '=');
@@ -680,17 +983,15 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) {
val = &val[1];
if (val[0] == '\0') {
log_debug("udevd message (ENV) received, unset '%s'", key);
- udev_list_entry_add(&properties_list, key, NULL);
+ udev_list_entry_add(&manager->properties, key, NULL);
} else {
log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
- udev_list_entry_add(&properties_list, key, val);
+ udev_list_entry_add(&manager->properties, key, val);
}
- } else {
+ } else
log_error("wrong key format '%s'", key);
- }
- free(key);
}
- worker_kill(udev);
+ manager_kill_workers(manager);
}
i = udev_ctrl_get_set_children_max(ctrl_msg);
@@ -704,13 +1005,13 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) {
if (udev_ctrl_get_exit(ctrl_msg) > 0) {
log_debug("udevd message (EXIT) received");
- udev_exit = true;
- /* keep reference to block the client until we exit */
- udev_ctrl_connection_ref(ctrl_conn);
+ manager_exit(manager);
+ /* keep reference to block the client until we exit
+ TODO: deal with several blocking exit requests */
+ manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
}
-out:
- udev_ctrl_msg_unref(ctrl_msg);
- return udev_ctrl_connection_unref(ctrl_conn);
+
+ return 1;
}
static int synthesize_change(struct udev_device *dev) {
@@ -817,189 +1118,284 @@ static int synthesize_change(struct udev_device *dev) {
return 0;
}
-static int handle_inotify(struct udev *udev) {
+static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ Manager *manager = userdata;
union inotify_event_buffer buffer;
struct inotify_event *e;
ssize_t l;
- l = read(fd_inotify, &buffer, sizeof(buffer));
+ assert(manager);
+
+ l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
if (errno == EAGAIN || errno == EINTR)
- return 0;
+ return 1;
return log_error_errno(errno, "Failed to read inotify fd: %m");
}
FOREACH_INOTIFY_EVENT(e, buffer, l) {
- struct udev_device *dev;
+ _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
- dev = udev_watch_lookup(udev, e->wd);
+ dev = udev_watch_lookup(manager->udev, e->wd);
if (!dev)
continue;
log_debug("inotify event: %x for %s", e->mask, udev_device_get_devnode(dev));
- if (e->mask & IN_CLOSE_WRITE)
+ if (e->mask & IN_CLOSE_WRITE) {
synthesize_change(dev);
- else if (e->mask & IN_IGNORED)
- udev_watch_end(udev, dev);
- udev_device_unref(dev);
+ /* settle might be waiting on us to determine the queue
+ * state. If we just handled an inotify event, we might have
+ * generated a "change" event, but we won't have queued up
+ * the resultant uevent yet. Do that.
+ */
+ on_uevent(NULL, -1, 0, manager);
+ } else if (e->mask & IN_IGNORED)
+ udev_watch_end(manager->udev, dev);
}
- return 0;
+ return 1;
}
-static void handle_signal(struct udev *udev, int signo) {
- switch (signo) {
- case SIGINT:
- case SIGTERM:
- udev_exit = true;
- break;
- case SIGCHLD:
- for (;;) {
- pid_t pid;
- int status;
- struct udev_list_node *loop, *tmp;
+static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *manager = userdata;
- pid = waitpid(-1, &status, WNOHANG);
- if (pid <= 0)
- break;
+ assert(manager);
- udev_list_node_foreach_safe(loop, tmp, &worker_list) {
- struct worker *worker = node_to_worker(loop);
-
- if (worker->pid != pid)
- continue;
- log_debug("worker ["PID_FMT"] exit", pid);
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0)
- log_error("worker ["PID_FMT"] exit with return code %i",
- pid, WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- log_error("worker ["PID_FMT"] terminated by signal %i (%s)",
- pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
- } else if (WIFSTOPPED(status)) {
- log_error("worker ["PID_FMT"] stopped", pid);
- } else if (WIFCONTINUED(status)) {
- log_error("worker ["PID_FMT"] continued", pid);
- } else {
- log_error("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
- }
+ manager_exit(manager);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- if (worker->event) {
- log_error("worker ["PID_FMT"] failed while handling '%s'",
- pid, worker->event->devpath);
- worker->event->exitcode = -32;
- event_queue_delete(worker->event);
+ return 1;
+}
- /* drop reference taken for state 'running' */
- worker_unref(worker);
- }
- }
- worker_unref(worker);
- break;
+static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *manager = userdata;
+
+ assert(manager);
+
+ manager_reload(manager);
+
+ return 1;
+}
+
+static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *manager = userdata;
+
+ assert(manager);
+
+ for (;;) {
+ pid_t pid;
+ int status;
+ struct worker *worker;
+
+ pid = waitpid(-1, &status, WNOHANG);
+ if (pid <= 0)
+ break;
+
+ worker = hashmap_get(manager->workers, UINT_TO_PTR(pid));
+ if (!worker) {
+ log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
+ continue;
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ log_debug("worker ["PID_FMT"] exited", pid);
+ else
+ log_warning("worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ log_warning("worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
+ } else if (WIFSTOPPED(status)) {
+ log_info("worker ["PID_FMT"] stopped", pid);
+ continue;
+ } else if (WIFCONTINUED(status)) {
+ log_info("worker ["PID_FMT"] continued", pid);
+ continue;
+ } else
+ log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ if (worker->event) {
+ log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath);
+ /* delete state from disk */
+ udev_device_delete_db(worker->event->dev);
+ udev_device_tag_index(worker->event->dev, NULL, false);
+ /* forward kernel event without amending it */
+ udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
}
}
- break;
- case SIGHUP:
- reload = true;
- break;
+
+ worker_free(worker);
}
+
+ /* we can start new workers, try to schedule events */
+ event_queue_start(manager);
+
+ return 1;
+}
+
+static int on_post(sd_event_source *s, void *userdata) {
+ Manager *manager = userdata;
+ int r;
+
+ assert(manager);
+
+ if (udev_list_node_is_empty(&manager->events)) {
+ /* no pending events */
+ if (!hashmap_isempty(manager->workers)) {
+ /* there are idle workers */
+ log_debug("cleanup idle workers");
+ manager_kill_workers(manager);
+ } else {
+ /* we are idle */
+ if (manager->exit) {
+ r = sd_event_exit(manager->event, 0);
+ if (r < 0)
+ return r;
+ } else if (manager->cgroup)
+ /* cleanup possible left-over processes in our cgroup */
+ cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, false, true, NULL);
+ }
+ }
+
+ return 1;
}
-static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
- int ctrl = -1, netlink = -1;
- int fd, n;
+static int listen_fds(int *rctrl, int *rnetlink) {
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ int ctrl_fd = -1, netlink_fd = -1;
+ int fd, n, r;
+
+ assert(rctrl);
+ assert(rnetlink);
n = sd_listen_fds(true);
- if (n <= 0)
- return -1;
+ if (n < 0)
+ return n;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
- if (ctrl >= 0)
- return -1;
- ctrl = fd;
+ if (ctrl_fd >= 0)
+ return -EINVAL;
+ ctrl_fd = fd;
continue;
}
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
- if (netlink >= 0)
- return -1;
- netlink = fd;
+ if (netlink_fd >= 0)
+ return -EINVAL;
+ netlink_fd = fd;
continue;
}
- return -1;
+ return -EINVAL;
}
- if (ctrl < 0 || netlink < 0)
- return -1;
+ if (ctrl_fd < 0) {
+ _cleanup_udev_ctrl_unref_ struct udev_ctrl *ctrl = NULL;
+
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+
+ ctrl = udev_ctrl_new(udev);
+ if (!ctrl)
+ return log_error_errno(EINVAL, "error initializing udev control socket");
+
+ r = udev_ctrl_enable_receiving(ctrl);
+ if (r < 0)
+ return log_error_errno(EINVAL, "error binding udev control socket");
+
+ fd = udev_ctrl_get_fd(ctrl);
+ if (fd < 0)
+ return log_error_errno(EIO, "could not get ctrl fd");
+
+ ctrl_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (ctrl_fd < 0)
+ return log_error_errno(errno, "could not dup ctrl fd: %m");
+ }
+
+ if (netlink_fd < 0) {
+ _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
+
+ if (!udev) {
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+ }
+
+ monitor = udev_monitor_new_from_netlink(udev, "kernel");
+ if (!monitor)
+ return log_error_errno(EINVAL, "error initializing netlink socket");
+
+ (void) udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
+
+ r = udev_monitor_enable_receiving(monitor);
+ if (r < 0)
+ return log_error_errno(EINVAL, "error binding netlink socket");
+
+ fd = udev_monitor_get_fd(monitor);
+ if (fd < 0)
+ return log_error_errno(netlink_fd, "could not get uevent fd: %m");
+
+ netlink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (ctrl_fd < 0)
+ return log_error_errno(errno, "could not dup netlink fd: %m");
+ }
+
+ *rctrl = ctrl_fd;
+ *rnetlink = netlink_fd;
- log_debug("ctrl=%i netlink=%i", ctrl, netlink);
- *rctrl = ctrl;
- *rnetlink = netlink;
return 0;
}
/*
* read the kernel command line, in case we need to get into debug mode
- * udev.log-priority=<level> syslog priority
- * udev.children-max=<number of workers> events are fully serialized if set to 1
- * udev.exec-delay=<number of seconds> delay execution of every executed program
+ * udev.log-priority=<level> syslog priority
+ * udev.children-max=<number of workers> events are fully serialized if set to 1
+ * udev.exec-delay=<number of seconds> delay execution of every executed program
+ * udev.event-timeout=<number of seconds> seconds to wait before terminating an event
*/
-static void kernel_cmdline_options(struct udev *udev) {
- _cleanup_free_ char *line = NULL;
- const char *word, *state;
- size_t l;
+static int parse_proc_cmdline_item(const char *key, const char *value) {
int r;
- r = proc_cmdline(&line);
- if (r < 0) {
- log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
- return;
- }
+ assert(key);
- FOREACH_WORD_QUOTED(word, l, line, state) {
- char *s, *opt, *value;
+ if (!value)
+ return 0;
- s = strndup(word, l);
- if (!s)
- break;
+ if (startswith(key, "rd."))
+ key += strlen("rd.");
- /* accept the same options for the initrd, prefixed with "rd." */
- if (in_initrd() && startswith(s, "rd."))
- opt = s + 3;
- else
- opt = s;
+ if (startswith(key, "udev."))
+ key += strlen("udev.");
+ else
+ return 0;
- if ((value = startswith(opt, "udev.log-priority="))) {
- int prio;
+ if (streq(key, "log-priority")) {
+ int prio;
- prio = util_log_priority(value);
- log_set_max_level(prio);
- } else if ((value = startswith(opt, "udev.children-max="))) {
- r = safe_atoi(value, &arg_children_max);
- if (r < 0)
- log_warning("Invalid udev.children-max ignored: %s", value);
- } else if ((value = startswith(opt, "udev.exec-delay="))) {
- r = safe_atoi(value, &arg_exec_delay);
- if (r < 0)
- log_warning("Invalid udev.exec-delay ignored: %s", value);
- } else if ((value = startswith(opt, "udev.event-timeout="))) {
- r = safe_atou64(value, &arg_event_timeout_usec);
- if (r < 0) {
- log_warning("Invalid udev.event-timeout ignored: %s", value);
- break;
- }
+ prio = util_log_priority(value);
+ log_set_max_level(prio);
+ } else if (streq(key, "children-max")) {
+ r = safe_atou(value, &arg_children_max);
+ if (r < 0)
+ log_warning("invalid udev.children-max ignored: %s", value);
+ } else if (streq(key, "exec-delay")) {
+ r = safe_atoi(value, &arg_exec_delay);
+ if (r < 0)
+ log_warning("invalid udev.exec-delay ignored: %s", value);
+ } else if (streq(key, "event-timeout")) {
+ r = safe_atou64(value, &arg_event_timeout_usec);
+ if (r < 0)
+ log_warning("invalid udev.event-timeout ignored: %s", value);
+ else {
arg_event_timeout_usec *= USEC_PER_SEC;
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
-
- free(s);
}
+
+ return 0;
}
static void help(void) {
@@ -1044,7 +1440,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_daemonize = true;
break;
case 'c':
- r = safe_atoi(optarg, &arg_children_max);
+ r = safe_atou(optarg, &arg_children_max);
if (r < 0)
log_warning("Invalid --children-max ignored: %s", optarg);
break;
@@ -1094,23 +1490,127 @@ static int parse_argv(int argc, char *argv[]) {
return 1;
}
+static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) {
+ _cleanup_(manager_freep) Manager *manager = NULL;
+ int r, fd_worker, one = 1;
+
+ assert(ret);
+ assert(fd_ctrl >= 0);
+ assert(fd_uevent >= 0);
+
+ manager = new0(Manager, 1);
+ if (!manager)
+ return log_oom();
+
+ manager->fd_inotify = -1;
+ manager->worker_watch[WRITE_END] = -1;
+ manager->worker_watch[READ_END] = -1;
+
+ manager->udev = udev_new();
+ if (!manager->udev)
+ return log_error_errno(errno, "could not allocate udev context: %m");
+
+ udev_builtin_init(manager->udev);
+
+ manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
+ if (!manager->rules)
+ return log_error_errno(ENOMEM, "error reading rules");
+
+ udev_list_node_init(&manager->events);
+ udev_list_init(manager->udev, &manager->properties, true);
+
+ manager->cgroup = cgroup;
+
+ manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
+ if (!manager->ctrl)
+ return log_error_errno(EINVAL, "error taking over udev control socket");
+
+ manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_uevent);
+ if (!manager->monitor)
+ return log_error_errno(EINVAL, "error taking over netlink socket");
+
+ /* unnamed socket from workers to the main daemon */
+ r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
+ if (r < 0)
+ return log_error_errno(errno, "error creating socketpair: %m");
+
+ fd_worker = manager->worker_watch[READ_END];
+
+ r = setsockopt(fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+ if (r < 0)
+ return log_error_errno(errno, "could not enable SO_PASSCRED: %m");
+
+ manager->fd_inotify = udev_watch_init(manager->udev);
+ if (manager->fd_inotify < 0)
+ return log_error_errno(ENOMEM, "error initializing inotify");
+
+ udev_watch_restore(manager->udev);
+
+ /* block and listen to all signals on signalfd */
+ assert_se(sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) == 0);
+
+ r = sd_event_default(&manager->event);
+ if (r < 0)
+ return log_error_errno(errno, "could not allocate event loop: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sigint event source: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGTERM, on_sigterm, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sigterm event source: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGHUP, on_sighup, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sighup event source: %m");
+
+ r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating sigchld event source: %m");
+
+ r = sd_event_set_watchdog(manager->event, true);
+ if (r < 0)
+ return log_error_errno(r, "error creating watchdog event source: %m");
+
+ r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating ctrl event source: %m");
+
+ /* This needs to be after the inotify and uevent handling, to make sure
+ * that the ping is send back after fully processing the pending uevents
+ * (including the synthetic ones we may create due to inotify events).
+ */
+ r = sd_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE);
+ if (r < 0)
+ return log_error_errno(r, "cold not set IDLE event priority for ctrl event source: %m");
+
+ r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating inotify event source: %m");
+
+ r = sd_event_add_io(manager->event, &manager->uevent_event, fd_uevent, EPOLLIN, on_uevent, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating uevent event source: %m");
+
+ r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating worker event source: %m");
+
+ r = sd_event_add_post(manager->event, NULL, on_post, manager);
+ if (r < 0)
+ return log_error_errno(r, "error creating post event source: %m");
+
+ *ret = manager;
+ manager = NULL;
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
- struct udev *udev;
- sigset_t mask;
- int fd_ctrl = -1;
- int fd_netlink = -1;
- int fd_worker = -1;
- struct epoll_event ep_ctrl = { .events = EPOLLIN };
- struct epoll_event ep_inotify = { .events = EPOLLIN };
- struct epoll_event ep_signal = { .events = EPOLLIN };
- struct epoll_event ep_netlink = { .events = EPOLLIN };
- struct epoll_event ep_worker = { .events = EPOLLIN };
- struct udev_ctrl_connection *ctrl_conn = NULL;
- int rc = 1, r;
-
- udev = udev_new();
- if (udev == NULL)
- goto exit;
+ _cleanup_(manager_freep) Manager *manager = NULL;
+ _cleanup_free_ char *cgroup = NULL;
+ int r, fd_ctrl, fd_uevent;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
@@ -1120,424 +1620,121 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto exit;
- kernel_cmdline_options(udev);
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "failed to parse kernel command line, ignoring: %m");
if (arg_debug)
log_set_max_level(LOG_DEBUG);
if (getuid() != 0) {
- log_error("root privileges required");
+ r = log_error_errno(EPERM, "root privileges required");
goto exit;
}
- r = mac_selinux_init("/dev");
- if (r < 0) {
- log_error_errno(r, "could not initialize labelling: %m");
- goto exit;
+ if (arg_children_max == 0) {
+ cpu_set_t cpu_set;
+
+ arg_children_max = 8;
+
+ if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) {
+ arg_children_max += CPU_COUNT(&cpu_set) * 2;
+ }
+
+ log_debug("set children_max to %u", arg_children_max);
}
/* set umask before creating any file/directory */
r = chdir("/");
if (r < 0) {
- log_error_errno(errno, "could not change dir to /: %m");
+ r = log_error_errno(errno, "could not change dir to /: %m");
goto exit;
}
umask(022);
- udev_list_init(udev, &properties_list, true);
+ r = mac_selinux_init("/dev");
+ if (r < 0) {
+ log_error_errno(r, "could not initialize labelling: %m");
+ goto exit;
+ }
r = mkdir("/run/udev", 0755);
if (r < 0 && errno != EEXIST) {
- log_error_errno(errno, "could not create /run/udev: %m");
+ r = log_error_errno(errno, "could not create /run/udev: %m");
goto exit;
}
- dev_setup(NULL);
-
- /* before opening new files, make sure std{in,out,err} fds are in a sane state */
- if (arg_daemonize) {
- int fd;
-
- fd = open("/dev/null", O_RDWR);
- if (fd >= 0) {
- if (write(STDOUT_FILENO, 0, 0) < 0)
- dup2(fd, STDOUT_FILENO);
- if (write(STDERR_FILENO, 0, 0) < 0)
- dup2(fd, STDERR_FILENO);
- if (fd > STDERR_FILENO)
- close(fd);
- } else {
- log_error("cannot open /dev/null");
- }
- }
-
- if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) {
- /* get control and netlink socket from systemd */
- udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl);
- if (udev_ctrl == NULL) {
- log_error("error taking over udev control socket");
- rc = 1;
- goto exit;
- }
-
- monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink);
- if (monitor == NULL) {
- log_error("error taking over netlink socket");
- rc = 3;
- goto exit;
- }
-
- /* get our own cgroup, we regularly kill everything udev has left behind */
- if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &udev_cgroup) < 0)
- udev_cgroup = NULL;
- } else {
- /* open control and netlink socket */
- udev_ctrl = udev_ctrl_new(udev);
- if (udev_ctrl == NULL) {
- log_error("error initializing udev control socket");
- rc = 1;
- goto exit;
- }
- fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
-
- monitor = udev_monitor_new_from_netlink(udev, "kernel");
- if (monitor == NULL) {
- log_error("error initializing netlink socket");
- rc = 3;
- goto exit;
- }
- fd_netlink = udev_monitor_get_fd(monitor);
-
- udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
- }
-
- if (udev_monitor_enable_receiving(monitor) < 0) {
- log_error("error binding netlink socket");
- rc = 3;
- goto exit;
- }
+ dev_setup(NULL, UID_INVALID, GID_INVALID);
- if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
- log_error("error binding udev control socket");
- rc = 1;
- goto exit;
+ if (getppid() == 1) {
+ /* get our own cgroup, we regularly kill everything udev has left behind
+ we only do this on systemd systems, and only if we are directly spawned
+ by PID1. otherwise we are not guaranteed to have a dedicated cgroup */
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
+ if (r < 0)
+ log_warning_errno(r, "failed to get cgroup: %m");
}
- log_info("starting version " VERSION);
-
- udev_builtin_init(udev);
-
- rules = udev_rules_new(udev, arg_resolve_names);
- if (rules == NULL) {
- log_error("error reading rules");
+ r = listen_fds(&fd_ctrl, &fd_uevent);
+ if (r < 0) {
+ r = log_error_errno(r, "could not listen on fds: %m");
goto exit;
}
- rc = udev_rules_apply_static_dev_perms(rules);
- if (rc < 0)
- log_error_errno(rc, "failed to apply permissions on static device nodes - %m");
-
if (arg_daemonize) {
pid_t pid;
+ log_info("starting version " VERSION);
+
pid = fork();
switch (pid) {
case 0:
break;
case -1:
- log_error_errno(errno, "fork of daemon failed: %m");
- rc = 4;
+ r = log_error_errno(errno, "fork of daemon failed: %m");
goto exit;
default:
- rc = EXIT_SUCCESS;
- goto exit_daemonize;
+ mac_selinux_finish();
+ log_close();
+ _exit(EXIT_SUCCESS);
}
setsid();
write_string_file("/proc/self/oom_score_adj", "-1000");
- } else {
- sd_notify(1, "READY=1");
}
- if (arg_children_max <= 0) {
- cpu_set_t cpu_set;
-
- arg_children_max = 8;
-
- if (sched_getaffinity(0, sizeof (cpu_set), &cpu_set) == 0) {
- arg_children_max += CPU_COUNT(&cpu_set) * 2;
- }
- }
- log_debug("set children_max to %u", arg_children_max);
-
- udev_list_node_init(&event_list);
- udev_list_node_init(&worker_list);
-
- fd_inotify = udev_watch_init(udev);
- if (fd_inotify < 0) {
- log_error("error initializing inotify");
- rc = 4;
- goto exit;
- }
- udev_watch_restore(udev);
-
- /* block and listen to all signals on signalfd */
- sigfillset(&mask);
- sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
- fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (fd_signal < 0) {
- log_error("error creating signalfd");
- rc = 5;
+ r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup);
+ if (r < 0) {
+ r = log_error_errno(r, "failed to allocate manager object: %m");
goto exit;
}
- /* unnamed socket from workers to the main daemon */
- if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) {
- log_error("error creating socketpair");
- rc = 6;
- goto exit;
- }
- fd_worker = worker_watch[READ_END];
+ r = udev_rules_apply_static_dev_perms(manager->rules);
+ if (r < 0)
+ log_error_errno(r, "failed to apply permissions on static device nodes: %m");
- ep_ctrl.data.fd = fd_ctrl;
- ep_inotify.data.fd = fd_inotify;
- ep_signal.data.fd = fd_signal;
- ep_netlink.data.fd = fd_netlink;
- ep_worker.data.fd = fd_worker;
+ (void) sd_notify(false,
+ "READY=1\n"
+ "STATUS=Processing...");
- fd_ep = epoll_create1(EPOLL_CLOEXEC);
- if (fd_ep < 0) {
- log_error_errno(errno, "error creating epoll fd: %m");
- goto exit;
- }
- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 ||
- epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_inotify, &ep_inotify) < 0 ||
- epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
- epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 ||
- epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) {
- log_error_errno(errno, "fail to add fds to epoll: %m");
+ r = sd_event_loop(manager->event);
+ if (r < 0) {
+ log_error_errno(r, "event loop failed: %m");
goto exit;
}
- for (;;) {
- static usec_t last_usec;
- struct epoll_event ev[8];
- int fdcount;
- int timeout;
- bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl;
- int i;
-
- if (udev_exit) {
- /* close sources of new events and discard buffered events */
- if (fd_ctrl >= 0) {
- epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL);
- fd_ctrl = -1;
- }
- if (monitor != NULL) {
- epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL);
- udev_monitor_unref(monitor);
- monitor = NULL;
- }
- if (fd_inotify >= 0) {
- epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL);
- close(fd_inotify);
- fd_inotify = -1;
- }
-
- /* discard queued events and kill workers */
- event_queue_cleanup(udev, EVENT_QUEUED);
- worker_kill(udev);
-
- /* exit after all has cleaned up */
- if (udev_list_node_is_empty(&event_list) && children == 0)
- break;
-
- /* timeout at exit for workers to finish */
- timeout = 30 * MSEC_PER_SEC;
- } else if (udev_list_node_is_empty(&event_list) && children == 0) {
- /* we are idle */
- timeout = -1;
-
- /* cleanup possible left-over processes in our cgroup */
- if (udev_cgroup)
- cg_kill(SYSTEMD_CGROUP_CONTROLLER, udev_cgroup, SIGKILL, false, true, NULL);
- } else {
- /* kill idle or hanging workers */
- timeout = 3 * MSEC_PER_SEC;
- }
-
- /* tell settle that we are busy or idle */
- if (!udev_list_node_is_empty(&event_list)) {
- int fd;
-
- fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
- if (fd >= 0)
- close(fd);
- } else {
- unlink("/run/udev/queue");
- }
-
- fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout);
- if (fdcount < 0)
- continue;
-
- if (fdcount == 0) {
- struct udev_list_node *loop;
-
- /* timeout */
- if (udev_exit) {
- log_error("timeout, giving up waiting for workers to finish");
- break;
- }
-
- /* kill idle workers */
- if (udev_list_node_is_empty(&event_list)) {
- log_debug("cleanup idle workers");
- worker_kill(udev);
- }
-
- /* check for hanging events */
- udev_list_node_foreach(loop, &worker_list) {
- struct worker *worker = node_to_worker(loop);
- usec_t ts;
-
- if (worker->state != WORKER_RUNNING)
- continue;
-
- ts = now(CLOCK_MONOTONIC);
-
- if ((ts - worker->event_start_usec) > arg_event_timeout_warn_usec) {
- if ((ts - worker->event_start_usec) > arg_event_timeout_usec) {
- log_error("worker ["PID_FMT"] %s timeout; kill it", worker->pid, worker->event->devpath);
- kill(worker->pid, SIGKILL);
- worker->state = WORKER_KILLED;
-
- /* drop reference taken for state 'running' */
- worker_unref(worker);
- log_error("seq %llu '%s' killed", udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
- worker->event->exitcode = -64;
- event_queue_delete(worker->event);
- worker->event = NULL;
- } else if (!worker->event_warned) {
- log_warning("worker ["PID_FMT"] %s is taking a long time", worker->pid, worker->event->devpath);
- worker->event_warned = true;
- }
- }
- }
+ sd_event_get_exit_code(manager->event, &r);
- }
-
- is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false;
- for (i = 0; i < fdcount; i++) {
- if (ev[i].data.fd == fd_worker && ev[i].events & EPOLLIN)
- is_worker = true;
- else if (ev[i].data.fd == fd_netlink && ev[i].events & EPOLLIN)
- is_netlink = true;
- else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN)
- is_signal = true;
- else if (ev[i].data.fd == fd_inotify && ev[i].events & EPOLLIN)
- is_inotify = true;
- else if (ev[i].data.fd == fd_ctrl && ev[i].events & EPOLLIN)
- is_ctrl = true;
- }
-
- /* check for changed config, every 3 seconds at most */
- if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
- if (udev_rules_check_timestamp(rules))
- reload = true;
- if (udev_builtin_validate(udev))
- reload = true;
-
- last_usec = now(CLOCK_MONOTONIC);
- }
-
- /* reload requested, HUP signal received, rules changed, builtin changed */
- if (reload) {
- worker_kill(udev);
- rules = udev_rules_unref(rules);
- udev_builtin_exit(udev);
- reload = false;
- }
-
- /* event has finished */
- if (is_worker)
- worker_returned(fd_worker);
-
- if (is_netlink) {
- struct udev_device *dev;
-
- dev = udev_monitor_receive_device(monitor);
- if (dev != NULL) {
- udev_device_set_usec_initialized(dev, now(CLOCK_MONOTONIC));
- if (event_queue_insert(dev) < 0)
- udev_device_unref(dev);
- }
- }
-
- /* start new events */
- if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) {
- udev_builtin_init(udev);
- if (rules == NULL)
- rules = udev_rules_new(udev, arg_resolve_names);
- if (rules != NULL)
- event_queue_start(udev);
- }
-
- if (is_signal) {
- struct signalfd_siginfo fdsi;
- ssize_t size;
-
- size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
- if (size == sizeof(struct signalfd_siginfo))
- handle_signal(udev, fdsi.ssi_signo);
- }
-
- /* we are shutting down, the events below are not handled anymore */
- if (udev_exit)
- continue;
-
- /* device node watch */
- if (is_inotify)
- handle_inotify(udev);
-
- /*
- * This needs to be after the inotify handling, to make sure,
- * that the ping is send back after the possibly generated
- * "change" events by the inotify device node watch.
- *
- * A single time we may receive a client connection which we need to
- * keep open to block the client. It will be closed right before we
- * exit.
- */
- if (is_ctrl)
- ctrl_conn = handle_ctrl_msg(udev_ctrl);
- }
-
- rc = EXIT_SUCCESS;
exit:
- udev_ctrl_cleanup(udev_ctrl);
- unlink("/run/udev/queue");
-exit_daemonize:
- if (fd_ep >= 0)
- close(fd_ep);
- worker_list_cleanup(udev);
- event_queue_cleanup(udev, EVENT_UNDEF);
- udev_rules_unref(rules);
- udev_builtin_exit(udev);
- if (fd_signal >= 0)
- close(fd_signal);
- if (worker_watch[READ_END] >= 0)
- close(worker_watch[READ_END]);
- if (worker_watch[WRITE_END] >= 0)
- close(worker_watch[WRITE_END]);
- udev_monitor_unref(monitor);
- udev_ctrl_connection_unref(ctrl_conn);
- udev_ctrl_unref(udev_ctrl);
- udev_list_cleanup(&properties_list);
+ sd_notify(false,
+ "STOPPING=1\n"
+ "STATUS=Shutting down...");
+
+ if (manager)
+ udev_ctrl_cleanup(manager->ctrl);
mac_selinux_finish();
- udev_unref(udev);
log_close();
- return rc;
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c
index 0ebe434639..5c57db44c1 100644
--- a/src/udev/v4l_id/v4l_id.c
+++ b/src/udev/v4l_id/v4l_id.c
@@ -36,29 +36,28 @@ int main(int argc, char *argv[]) {
_cleanup_close_ int fd = -1;
char *device;
struct v4l2_capability v2cap;
+ int c;
- for (;;) {
- int option;
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
- option = getopt_long(argc, argv, "h", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
+ switch (c) {
case 'h':
printf("%s [-h,--help] <device file>\n\n"
"Video4Linux device identification.\n\n"
" -h Print this message\n"
, program_invocation_short_name);
return 0;
+ case '?':
+ return -EINVAL;
+
default:
- return 1;
+ assert_not_reached("Unhandled option");
}
- }
- device = argv[optind];
+ device = argv[optind];
if (device == NULL)
return 2;
+
fd = open(device, O_RDONLY);
if (fd < 0)
return 3;
diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c
index 561963e5eb..01bbde8455 100644
--- a/src/update-done/update-done.c
+++ b/src/update-done/update-done.c
@@ -20,7 +20,6 @@
***/
#include "util.h"
-#include "label.h"
#include "selinux-util.h"
#define MESSAGE \
@@ -29,22 +28,28 @@
"was updated. See systemd-update-done.service(8).\n"
static int apply_timestamp(const char *path, struct timespec *ts) {
- struct timespec twice[2];
+ struct timespec twice[2] = {
+ *ts,
+ *ts
+ };
struct stat st;
assert(path);
assert(ts);
if (stat(path, &st) >= 0) {
- /* Is the timestamp file already newer than the OS? If so, there's nothing to do. */
- if (st.st_mtim.tv_sec > ts->tv_sec ||
- (st.st_mtim.tv_sec == ts->tv_sec && st.st_mtim.tv_nsec >= ts->tv_nsec))
+ /* Is the timestamp file already newer than the OS? If
+ * so, there's nothing to do. We ignore the nanosecond
+ * component of the timestamp, since some file systems
+ * do not support any better accuracy than 1s and we
+ * have no way to identify the accuracy
+ * available. Most notably ext4 on small disks (where
+ * 128 byte inodes are used) does not support better
+ * accuracy than 1s. */
+ if (st.st_mtim.tv_sec > ts->tv_sec)
return 0;
/* It is older? Then let's update it */
- twice[0] = *ts;
- twice[1] = *ts;
-
if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {
if (errno == EROFS)
@@ -75,9 +80,6 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
(void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);
- twice[0] = *ts;
- twice[1] = *ts;
-
if (futimens(fd, twice) < 0)
return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
} else
diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c
index 15da83193b..ea9b0c9c84 100644
--- a/src/update-utmp/update-utmp.c
+++ b/src/update-utmp/update-utmp.c
@@ -19,10 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <string.h>
-#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_AUDIT
@@ -39,6 +37,7 @@
#include "bus-util.h"
#include "bus-error.h"
#include "unit-name.h"
+#include "formats-util.h"
typedef struct Context {
sd_bus *bus;
@@ -80,11 +79,9 @@ static int get_current_runlevel(Context *c) {
* here over the others, since these are the main
* runlevels used on Fedora. It might make sense to
* change the order on some distributions. */
- { '5', SPECIAL_RUNLEVEL5_TARGET },
- { '3', SPECIAL_RUNLEVEL3_TARGET },
- { '4', SPECIAL_RUNLEVEL4_TARGET },
- { '2', SPECIAL_RUNLEVEL2_TARGET },
- { '1', SPECIAL_RESCUE_TARGET },
+ { '5', SPECIAL_GRAPHICAL_TARGET },
+ { '3', SPECIAL_MULTI_USER_TARGET },
+ { '1', SPECIAL_RESCUE_TARGET },
};
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
diff --git a/src/shutdownd/Makefile b/src/user-sessions/Makefile
index d0b0e8e008..d0b0e8e008 120000
--- a/src/shutdownd/Makefile
+++ b/src/user-sessions/Makefile
diff --git a/src/login/user-sessions.c b/src/user-sessions/user-sessions.c
index 6edb823e8c..1c31769fde 100644
--- a/src/login/user-sessions.c
+++ b/src/user-sessions/user-sessions.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <unistd.h>
#include <errno.h>
diff --git a/src/vconsole/90-vconsole.rules.in b/src/vconsole/90-vconsole.rules.in
index 062009640c..35b9ad5151 100644
--- a/src/vconsole/90-vconsole.rules.in
+++ b/src/vconsole/90-vconsole.rules.in
@@ -5,7 +5,6 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
-# Kernel resets vconsole state when changing console drivers so run
-# systemd-vconsole-setup when fbcon loads
-
-ACTION=="add", SUBSYSTEM=="graphics", KERNEL=="fbcon", RUN+="@rootlibexecdir@/systemd-vconsole-setup"
+# Each vtcon keeps its own state of fonts.
+#
+ACTION=="add", SUBSYSTEM=="vtconsole", KERNEL=="vtcon*", RUN+="@rootlibexecdir@/systemd-vconsole-setup"
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index 28371711b6..6c782b3130 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -23,23 +23,20 @@
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
-#include <ctype.h>
#include <stdbool.h>
-#include <stdarg.h>
#include <limits.h>
#include <sys/ioctl.h>
-#include <sys/wait.h>
#include <linux/tiocl.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include "util.h"
#include "log.h"
-#include "macro.h"
#include "virt.h"
#include "fileio.h"
+#include "process-util.h"
+#include "terminal-util.h"
static bool is_vconsole(int fd) {
unsigned char data[1];
@@ -101,16 +98,14 @@ static int enable_utf8(int fd) {
return r;
}
-static int keymap_load(const char *vc, const char *map, const char *map_toggle, bool utf8, pid_t *_pid) {
+static int keyboard_load_and_wait(const char *vc, const char *map, const char *map_toggle, bool utf8) {
const char *args[8];
- int i = 0;
+ int i = 0, r;
pid_t pid;
- if (isempty(map)) {
- /* An empty map means kernel map */
- *_pid = 0;
- return 0;
- }
+ /* An empty map means kernel map */
+ if (isempty(map))
+ return 1;
args[i++] = KBD_LOADKEYS;
args[i++] = "-q";
@@ -131,20 +126,21 @@ static int keymap_load(const char *vc, const char *map, const char *map_toggle,
_exit(EXIT_FAILURE);
}
- *_pid = pid;
- return 0;
+ r = wait_for_terminate_and_warn(KBD_LOADKEYS, pid, true);
+ if (r < 0)
+ return r;
+
+ return r == 0;
}
-static int font_load(const char *vc, const char *font, const char *map, const char *unimap, pid_t *_pid) {
+static int font_load_and_wait(const char *vc, const char *font, const char *map, const char *unimap) {
const char *args[9];
- int i = 0;
+ int i = 0, r;
pid_t pid;
- if (isempty(font)) {
- /* An empty font means kernel font */
- *_pid = 0;
- return 0;
- }
+ /* An empty font means kernel font */
+ if (isempty(font))
+ return 1;
args[i++] = KBD_SETFONT;
args[i++] = "-C";
@@ -168,8 +164,11 @@ static int font_load(const char *vc, const char *font, const char *map, const ch
_exit(EXIT_FAILURE);
}
- *_pid = pid;
- return 0;
+ r = wait_for_terminate_and_warn(KBD_SETFONT, pid, true);
+ if (r < 0)
+ return r;
+
+ return r == 0;
}
/*
@@ -188,11 +187,13 @@ static void font_copy_to_all_vcs(int fd) {
/* get active, and 16 bit mask of used VT numbers */
r = ioctl(fd, VT_GETSTATE, &vcs);
- if (r < 0)
+ if (r < 0) {
+ log_debug_errno(errno, "VT_GETSTATE failed, ignoring: %m");
return;
+ }
for (i = 1; i <= 15; i++) {
- char vcname[16];
+ char vcname[strlen("/dev/vcs") + DECIMAL_STR_MAX(int)];
_cleanup_close_ int vcfd = -1;
struct console_font_op cfo = {};
@@ -216,11 +217,11 @@ static void font_copy_to_all_vcs(int fd) {
/* copy map of 8bit chars */
if (ioctl(fd, GIO_SCRNMAP, map8) >= 0)
- (void) ioctl(vcfd, PIO_SCRNMAP, map8);
+ (void) ioctl(vcfd, PIO_SCRNMAP, map8);
/* copy map of 8bit chars -> 16bit Unicode values */
if (ioctl(fd, GIO_UNISCRNMAP, map16) >= 0)
- (void) ioctl(vcfd, PIO_UNISCRNMAP, map16);
+ (void) ioctl(vcfd, PIO_UNISCRNMAP, map16);
/* copy unicode translation table */
/* unimapd is a ushort count and a pointer to an
@@ -242,9 +243,7 @@ int main(int argc, char **argv) {
*vc_keymap = NULL, *vc_keymap_toggle = NULL,
*vc_font = NULL, *vc_font_map = NULL, *vc_font_unimap = NULL;
_cleanup_close_ int fd = -1;
- bool utf8;
- pid_t font_pid = 0, keymap_pid = 0;
- bool font_copy = false;
+ bool utf8, font_copy = false, font_ok, keyboard_ok;
int r = EXIT_FAILURE;
log_set_target(LOG_TARGET_AUTO);
@@ -299,31 +298,16 @@ int main(int argc, char **argv) {
}
if (utf8)
- enable_utf8(fd);
+ (void) enable_utf8(fd);
else
- disable_utf8(fd);
-
- r = font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid);
- if (r < 0) {
- log_error_errno(r, "Failed to start " KBD_SETFONT ": %m");
- return EXIT_FAILURE;
- }
-
- if (font_pid > 0)
- wait_for_terminate_and_warn(KBD_SETFONT, font_pid, true);
-
- r = keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid);
- if (r < 0) {
- log_error_errno(r, "Failed to start " KBD_LOADKEYS ": %m");
- return EXIT_FAILURE;
- }
+ (void) disable_utf8(fd);
- if (keymap_pid > 0)
- wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid, true);
+ font_ok = font_load_and_wait(vc, vc_font, vc_font_map, vc_font_unimap) > 0;
+ keyboard_ok = keyboard_load_and_wait(vc, vc_keymap, vc_keymap_toggle, utf8) > 0;
- /* Only copy the font when we started setfont successfully */
- if (font_copy && font_pid > 0)
- font_copy_to_all_vcs(fd);
+ /* Only copy the font when we executed setfont successfully */
+ if (font_copy && font_ok)
+ (void) font_copy_to_all_vcs(fd);
- return EXIT_SUCCESS;
+ return font_ok && keyboard_ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf
index f18923399b..def151bb84 100644
--- a/sysctl.d/50-default.conf
+++ b/sysctl.d/50-default.conf
@@ -5,9 +5,16 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
-# See sysctl.d(5) and core(5) for for details.
+# See sysctl.d(5) and core(5) for for documentation.
+
+# To override settings in this file, create a local file in /etc
+# (e.g. /etc/sysctl.d/90-override.conf), and put any assignments
+# there.
# System Request functionality of the kernel (SYNC)
+#
+# Use kernel.sysrq = 1 to allow all keys.
+# See http://fedoraproject.org/wiki/QA/Sysrq for a list of values and keys.
kernel.sysrq = 16
# Append the PID to the core filename
diff --git a/test/README.testsuite b/test/README.testsuite
index 2ae85a2ce1..5c7aca43a8 100644
--- a/test/README.testsuite
+++ b/test/README.testsuite
@@ -10,8 +10,6 @@ $ sudo make clean check
make[1]: Entering directory `/mnt/data/harald/git/systemd/test/TEST-01-BASIC'
Making all in .
Making all in po
-Making all in docs/libudev
-Making all in docs/gudev
TEST: Basic systemd setup [OK]
make[1]: Leaving directory `/mnt/data/harald/git/systemd/test/TEST-01-BASIC'
...
diff --git a/test/TEST-03-JOBS/test-jobs.sh b/test/TEST-03-JOBS/test-jobs.sh
index 28368b70e4..6f32c240cd 100755
--- a/test/TEST-03-JOBS/test-jobs.sh
+++ b/test/TEST-03-JOBS/test-jobs.sh
@@ -1,6 +1,6 @@
#!/bin/bash -x
-# Test merging of a --ignore-dependencies job into a previously
+# Test merging of a --job-mode=ignore-dependencies job into a previously
# installed job.
systemctl start --no-block hello-after-sleep.target
@@ -11,7 +11,7 @@ grep 'hello\.service.*waiting' /root/list-jobs.txt || exit 1
# This is supposed to finish quickly, not wait for sleep to finish.
START_SEC=$(date -u '+%s')
-systemctl start --ignore-dependencies hello
+systemctl start --job-mode=ignore-dependencies hello
END_SEC=$(date -u '+%s')
ELAPSED=$(($END_SEC-$START_SEC))
@@ -27,7 +27,7 @@ systemctl stop sleep.service hello-after-sleep.target || exit 1
systemctl start --no-block hello-after-sleep.target || exit 1
# hello.service should still be waiting, so these try-restarts will collapse
# into NOPs.
-systemctl try-restart --fail hello.service || exit 1
+systemctl try-restart --job-mode=fail hello.service || exit 1
systemctl try-restart hello.service || exit 1
systemctl stop hello.service sleep.service hello-after-sleep.target || exit 1
@@ -39,7 +39,7 @@ systemctl start unstoppable.service || exit 1
# This is expected to fail with 'job cancelled'
systemctl stop unstoppable.service && exit 1
# But this should succeed
-systemctl stop --irreversible unstoppable.service || exit 1
+systemctl stop --job-mode=replace-irreversibly unstoppable.service || exit 1
# We're going to shutdown soon. Let's see if it succeeds when
# there's an active service that tries to be unstoppable.
diff --git a/test/mocks/fsck b/test/mocks/fsck
new file mode 100755
index 0000000000..77b50d7234
--- /dev/null
+++ b/test/mocks/fsck
@@ -0,0 +1,27 @@
+#!/bin/bash
+fd=0
+
+OPTIND=1
+while getopts "C:aTlM" opt; do
+ case "$opt" in
+ C)
+ fd=$OPTARG
+ ;;
+ \?);;
+ esac
+done
+
+shift "$((OPTIND-1))"
+device=$1
+
+echo "Running fake fsck on $device"
+
+declare -a maxpass=(30 5 2 30 60)
+
+for pass in {1..5}; do
+ maxprogress=${maxpass[$((pass-1))]}
+ for (( current=0; current<=${maxprogress}; current++)); do
+ echo "$pass $current $maxprogress $device">&$fd
+ sleep 0.1
+ done
+done
diff --git a/test/splash.bmp b/test/splash.bmp
new file mode 100644
index 0000000000..27247f7a22
--- /dev/null
+++ b/test/splash.bmp
Binary files differ
diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
index 09f5c01762..e74f8533c7 100644
--- a/test/sysv-generator-test.py
+++ b/test/sysv-generator-test.py
@@ -126,18 +126,18 @@ class SysvGeneratorTest(unittest.TestCase):
return script
- def assert_enabled(self, unit, runlevels):
- '''assert that a unit is enabled in precisely the given runlevels'''
+ def assert_enabled(self, unit, targets):
+ '''assert that a unit is enabled in precisely the given targets'''
- all_runlevels = [2, 3, 4, 5]
+ all_targets = ['multi-user', 'graphical']
# should be enabled
- for runlevel in all_runlevels:
- link = os.path.join(self.out_dir, 'runlevel%i.target.wants' % runlevel, unit)
- if runlevel in runlevels:
- target = os.readlink(link)
- self.assertTrue(os.path.exists(target))
- self.assertEqual(os.path.basename(target), unit)
+ for target in all_targets:
+ link = os.path.join(self.out_dir, '%s.target.wants' % target, unit)
+ if target in targets:
+ unit_file = os.readlink(link)
+ self.assertTrue(os.path.exists(unit_file))
+ self.assertEqual(os.path.basename(unit_file), unit)
else:
self.assertFalse(os.path.exists(link),
'%s unexpectedly exists' % link)
@@ -178,13 +178,16 @@ class SysvGeneratorTest(unittest.TestCase):
self.assertEqual(s.get('Service', 'ExecStop'),
'%s stop' % init_script)
+ self.assertNotIn('Overwriting', err)
+
def test_simple_enabled_all(self):
'''simple service without dependencies, enabled in all runlevels'''
self.add_sysv('foo', {}, enable=True)
err, results = self.run_generator()
self.assertEqual(list(results), ['foo.service'])
- self.assert_enabled('foo.service', [2, 3, 4, 5])
+ self.assert_enabled('foo.service', ['multi-user', 'graphical'])
+ self.assertNotIn('Overwriting', err)
def test_simple_enabled_some(self):
'''simple service without dependencies, enabled in some runlevels'''
@@ -192,7 +195,7 @@ class SysvGeneratorTest(unittest.TestCase):
self.add_sysv('foo', {'Default-Start': '2 4'}, enable=True)
err, results = self.run_generator()
self.assertEqual(list(results), ['foo.service'])
- self.assert_enabled('foo.service', [2, 4])
+ self.assert_enabled('foo.service', ['multi-user'])
def test_lsb_macro_dep_single(self):
'''single LSB macro dependency: $network'''
@@ -270,6 +273,7 @@ class SysvGeneratorTest(unittest.TestCase):
for f in ['bar.service', 'baz.service']:
self.assertEqual(os.readlink(os.path.join(self.out_dir, f)),
'foo.service')
+ self.assertNotIn('Overwriting', err)
def test_same_provides_in_multiple_scripts(self):
'''multiple init.d scripts provide the same name'''
@@ -289,6 +293,9 @@ class SysvGeneratorTest(unittest.TestCase):
self.add_sysv('bar', {'Provides': 'bar'}, enable=True)
err, results = self.run_generator()
self.assertEqual(sorted(results), ['bar.service', 'foo.service'])
+ # we do expect an overwrite here, bar.service should overwrite the
+ # alias link from foo.service
+ self.assertIn('Overwriting', err)
def test_nonexecutable_script(self):
'''ignores non-executable init.d script'''
@@ -315,7 +322,7 @@ class SysvGeneratorTest(unittest.TestCase):
self.assertEqual(s.get('Service', 'ExecStop'),
'%s stop' % init_script)
- self.assert_enabled('foo.service', [2, 3, 4, 5])
+ self.assert_enabled('foo.service', ['multi-user', 'graphical'])
def test_sh_suffix_with_provides(self):
'''init.d script with .sh suffix and Provides:'''
@@ -323,7 +330,7 @@ class SysvGeneratorTest(unittest.TestCase):
self.add_sysv('foo.sh', {'Provides': 'foo bar'})
err, results = self.run_generator()
# ensure we don't try to create a symlink to itself
- self.assertNotIn(err, 'itself')
+ self.assertNotIn('itself', err)
self.assertEqual(list(results), ['foo.service'])
self.assertEqual(results['foo.service'].get('Unit', 'Description'),
'LSB: test foo service')
@@ -345,7 +352,7 @@ class SysvGeneratorTest(unittest.TestCase):
err, results = self.run_generator()
self.assertEqual(list(results), ['foo.service'])
- self.assert_enabled('foo.service', [2, 3, 4, 5])
+ self.assert_enabled('foo.service', ['multi-user', 'graphical'])
def test_backup_file(self):
'''init.d script with backup file'''
@@ -361,9 +368,9 @@ class SysvGeneratorTest(unittest.TestCase):
['foo.bak.service', 'foo.old.service', 'foo.service'])
# ensure we don't try to create a symlink to itself
- self.assertNotIn(err, 'itself')
+ self.assertNotIn('itself', err)
- self.assert_enabled('foo.service', [2, 3, 4, 5])
+ self.assert_enabled('foo.service', ['multi-user', 'graphical'])
self.assert_enabled('foo.bak.service', [])
self.assert_enabled('foo.old.service', [])
diff --git a/test/test-efi-create-disk.sh b/test/test-efi-create-disk.sh
new file mode 100755
index 0000000000..56dd09abd7
--- /dev/null
+++ b/test/test-efi-create-disk.sh
@@ -0,0 +1,42 @@
+#!/bin/bash -e
+
+# create GPT table with EFI System Partition
+rm -f test-efi-disk.img
+dd if=/dev/null of=test-efi-disk.img bs=1M seek=512 count=1
+parted --script test-efi-disk.img "mklabel gpt" "mkpart ESP fat32 1MiB 511MiB" "set 1 boot on"
+
+# create FAT32 file system
+LOOP=$(losetup --show -f -P test-efi-disk.img)
+mkfs.vfat -F32 ${LOOP}p1
+mkdir -p mnt
+mount ${LOOP}p1 mnt
+
+mkdir -p mnt/EFI/{Boot,systemd}
+cp systemd-bootx64.efi mnt/EFI/Boot/bootx64.efi
+
+[ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/
+
+mkdir mnt/EFI/Linux
+echo -n "foo=yes bar=no root=/dev/fakeroot debug rd.break=initqueue" > mnt/cmdline.txt
+objcopy \
+ --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \
+ --add-section .cmdline=mnt/cmdline.txt --change-section-vma .cmdline=0x30000 \
+ --add-section .splash=test/splash.bmp --change-section-vma .splash=0x40000 \
+ --add-section .linux=/boot/$(cat /etc/machine-id)/$(uname -r)/linux --change-section-vma .linux=0x2000000 \
+ --add-section .initrd=/boot/$(cat /etc/machine-id)/$(uname -r)/initrd --change-section-vma .initrd=0x3000000 \
+ linuxx64.efi.stub mnt/EFI/Linux/linux-test.efi
+
+# install entries
+mkdir -p mnt/loader/entries
+echo -e "timeout 3\n" > mnt/loader/loader.conf
+echo -e "title Test\nefi /test\n" > mnt/loader/entries/test.conf
+echo -e "title Test2\nlinux /test2\noptions option=yes word number=1000 more\n" > mnt/loader/entries/test2.conf
+echo -e "title Test3\nlinux /test3\n" > mnt/loader/entries/test3.conf
+echo -e "title Test4\nlinux /test4\n" > mnt/loader/entries/test4.conf
+echo -e "title Test5\nefi /test5\n" > mnt/loader/entries/test5.conf
+echo -e "title Test6\nlinux /test6\n" > mnt/loader/entries/test6.conf
+
+sync
+umount mnt
+rmdir mnt
+losetup -d $LOOP
diff --git a/test/test-functions b/test/test-functions
index 901ff48605..8272e52e17 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -125,7 +125,7 @@ install_systemd() {
# install compiled files
(cd $TEST_BASE_DIR/..; set -x; make DESTDIR=$initdir install)
# remove unneeded documentation
- rm -fr $initdir/usr/share/{man,doc,gtk-doc}
+ rm -fr $initdir/usr/share/{man,doc}
# we strip binaries since debug symbols increase binaries size a lot
# and it could fill the available space
strip_binaries
diff --git a/test/udev-test.pl b/test/udev-test.pl
index d9b7967004..64d7f93444 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -22,7 +22,9 @@ use strict;
my $udev_bin = "./test-udev";
my $valgrind = 0;
-my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --quiet $udev_bin";
+my $gdb = 0;
+my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --track-origins=yes --quiet $udev_bin";
+my $udev_bin_gdb = "gdb --args $udev_bin";
my $udev_dev = "test/dev";
my $udev_run = "test/run";
my $udev_rules_dir = "$udev_run/udev/rules.d";
@@ -1326,6 +1328,8 @@ sub udev {
if ($valgrind > 0) {
system("$udev_bin_valgrind $action $devpath");
+ } elsif ($gdb > 0) {
+ system("$udev_bin_gdb $action $devpath");
} else {
system("$udev_bin", "$action", "$devpath");
}
@@ -1502,6 +1506,9 @@ foreach my $arg (@ARGV) {
if ($arg =~ m/--valgrind/) {
$valgrind = 1;
printf("using valgrind\n");
+ } elsif ($arg =~ m/--gdb/) {
+ $gdb = 1;
+ printf("using gdb\n");
} else {
push(@list, $arg);
}
diff --git a/tmpfiles.d/etc.conf.m4 b/tmpfiles.d/etc.conf.m4
index 9b0e080e6f..e74b02687f 100644
--- a/tmpfiles.d/etc.conf.m4
+++ b/tmpfiles.d/etc.conf.m4
@@ -11,7 +11,9 @@ L /etc/os-release - - - - ../usr/lib/os-release
L /etc/localtime - - - - ../usr/share/zoneinfo/UTC
L+ /etc/mtab - - - - ../proc/self/mounts
m4_ifdef(`ENABLE_RESOLVED',
-L /etc/resolv.conf - - - - ../run/systemd/resolve/resolv.conf
+L! /etc/resolv.conf - - - - ../run/systemd/resolve/resolv.conf
)m4_dnl
C /etc/nsswitch.conf - - - -
+m4_ifdef(`HAVE_PAM',
C /etc/pam.d - - - -
+)m4_dnl
diff --git a/units/systemd-shutdownd.socket b/tmpfiles.d/home.conf
index 9421ce8ada..aa652b197f 100644
--- a/units/systemd-shutdownd.socket
+++ b/tmpfiles.d/home.conf
@@ -5,14 +5,7 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
-[Unit]
-Description=Delayed Shutdown Socket
-Documentation=man:systemd-shutdownd.service(8)
-DefaultDependencies=no
-Before=sockets.target
+# See tmpfiles.d(5) for details
-[Socket]
-ListenDatagram=/run/systemd/shutdownd
-SocketMode=0600
-PassCredentials=yes
-PassSecurity=yes
+v /home 0755 - - -
+v /srv 0755 - - -
diff --git a/tmpfiles.d/journal-nocow.conf b/tmpfiles.d/journal-nocow.conf
new file mode 100644
index 0000000000..e7938c8911
--- /dev/null
+++ b/tmpfiles.d/journal-nocow.conf
@@ -0,0 +1,27 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# See tmpfiles.d(5) for details
+
+# Set the NOCOW attribute for directories of journal files. This flag
+# is inheredited by their new files and sub-directories. Matters only
+# for btrfs filesystems.
+#
+# WARNING: Enabling the NOCOW attribute improves journal performance
+# substantially, but also disables the btrfs checksum logic. In
+# btrfs RAID filesystems the checksums are needed for rebuilding
+# corrupted files. Without checksums such rebuilds are not
+# possible.
+#
+# In a single-disk filesystem (or a filesystem without redundancy)
+# enabling the NOCOW attribute for journal files is safe, because
+# they have their own checksums and a rebuilding wouldn't be possible
+# in any case.
+
+h /var/log/journal - - - - +C
+h /var/log/journal/%m - - - - +C
+h /var/log/journal/remote - - - - +C
diff --git a/tmpfiles.d/legacy.conf b/tmpfiles.d/legacy.conf
index 32196723f9..3cb0c63815 100644
--- a/tmpfiles.d/legacy.conf
+++ b/tmpfiles.d/legacy.conf
@@ -26,7 +26,7 @@ d /run/lock/subsys 0755 root root -
d /run/lock/lockdev 0775 root lock -
-# /forcefsck, /fastboot and /forcequotecheck are deprecated in favor of the
+# /forcefsck, /fastboot and /forcequotacheck are deprecated in favor of the
# kernel command line options 'fsck.mode=force', 'fsck.mode=skip' and
# 'quotacheck.mode=force'
diff --git a/tmpfiles.d/systemd-nologin.conf b/tmpfiles.d/systemd-nologin.conf
index d61232b534..a30a8da604 100644
--- a/tmpfiles.d/systemd-nologin.conf
+++ b/tmpfiles.d/systemd-nologin.conf
@@ -5,7 +5,7 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
-# See tmpfiles.d(5) and systemd-forbid-user-logins.service(5).
+# See tmpfiles.d(5), systemd-user-session.service(5) and pam_nologin(8).
# This file has special suffix so it is not run by mistake.
F! /run/nologin 0644 - - - "System is booting up. See pam_nologin(8)"
diff --git a/tmpfiles.d/var.conf b/tmpfiles.d/var.conf
index 9b7644476b..814652a22c 100644
--- a/tmpfiles.d/var.conf
+++ b/tmpfiles.d/var.conf
@@ -7,7 +7,7 @@
# See tmpfiles.d(5) for details
-d /var 0755 - - -
+v /var 0755 - - -
L /var/run - - - - ../run
diff --git a/units/.gitignore b/units/.gitignore
index 6fdb629c3d..d45492d06b 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -48,6 +48,7 @@
/systemd-modules-load.service
/systemd-networkd-wait-online.service
/systemd-networkd.service
+/systemd-networkd.service.m4
/systemd-nspawn@.service
/systemd-poweroff.service
/systemd-quotacheck.service
@@ -55,9 +56,9 @@
/systemd-reboot.service
/systemd-remount-fs.service
/systemd-resolved.service
+/systemd-resolved.service.m4
/systemd-hibernate-resume@.service
/systemd-rfkill@.service
-/systemd-shutdownd.service
/systemd-suspend.service
/systemd-sysctl.service
/systemd-sysusers.service
diff --git a/units/basic.target b/units/basic.target
index abb63ec560..e0e1e604f8 100644
--- a/units/basic.target
+++ b/units/basic.target
@@ -8,8 +8,10 @@
[Unit]
Description=Basic System
Documentation=man:systemd.special(7)
-
Requires=sysinit.target
-After=sysinit.target
Wants=sockets.target timers.target paths.target slices.target
-After=sockets.target paths.target slices.target
+After=sysinit.target sockets.target paths.target slices.target
+
+# We support /var, /tmp, /var/tmp, being on NFS, but we don't pull in
+# remote-fs.target by default, hence explicitly pull /var in here.
+RequiresMountsFor=/var /tmp /var/tmp
diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in
index 8ac51a471b..413d94094b 100644
--- a/units/console-getty.service.m4.in
+++ b/units/console-getty.service.m4.in
@@ -9,6 +9,7 @@
Description=Console Getty
Documentation=man:agetty(8)
After=systemd-user-sessions.service plymouth-quit-wait.service
+ConditionPathExists=/dev/console
m4_ifdef(`HAVE_SYSV_COMPAT',
After=rc-local.service
)m4_dnl
diff --git a/units/emergency.service.in b/units/emergency.service.in
index 2695d7b7c9..52b9b1cd03 100644
--- a/units/emergency.service.in
+++ b/units/emergency.service.in
@@ -18,7 +18,7 @@ Environment=HOME=/root
WorkingDirectory=/root
ExecStartPre=-/bin/plymouth quit
ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\ntry again to boot into default mode.'
-ExecStart=-/bin/sh -c "@SULOGIN@; @SYSTEMCTL@ --fail --no-block default"
+ExecStart=-/bin/sh -c "@SULOGIN@; @SYSTEMCTL@ --job-mode=fail --no-block default"
Type=idle
StandardInput=tty-force
StandardOutput=inherit
diff --git a/units/rescue.service.in b/units/rescue.service.in
index de73fee654..432e4f3c84 100644
--- a/units/rescue.service.in
+++ b/units/rescue.service.in
@@ -18,7 +18,7 @@ Environment=HOME=/root
WorkingDirectory=/root
ExecStartPre=-/bin/plymouth quit
ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\nboot into default mode.'
-ExecStart=-/bin/sh -c "@SULOGIN@; @SYSTEMCTL@ --fail --no-block default"
+ExecStart=-/bin/sh -c "@SULOGIN@; @SYSTEMCTL@ --job-mode=fail --no-block default"
Type=idle
StandardInput=tty-force
StandardOutput=inherit
diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in
index 34a5d5237b..d53073ee61 100644
--- a/units/systemd-binfmt.service.in
+++ b/units/systemd-binfmt.service.in
@@ -24,3 +24,4 @@ ConditionDirectoryNotEmpty=|/run/binfmt.d
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-binfmt
+TimeoutSec=90s
diff --git a/units/systemd-fsck-root.service.in b/units/systemd-fsck-root.service.in
index 6d7657853e..3617abf04a 100644
--- a/units/systemd-fsck-root.service.in
+++ b/units/systemd-fsck-root.service.in
@@ -16,5 +16,4 @@ ConditionPathIsReadWrite=!/
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-fsck
-StandardOutput=journal+console
TimeoutSec=0
diff --git a/units/systemd-fsck@.service.in b/units/systemd-fsck@.service.in
index 857e625679..0468392dc4 100644
--- a/units/systemd-fsck@.service.in
+++ b/units/systemd-fsck@.service.in
@@ -17,5 +17,4 @@ Before=shutdown.target
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-fsck %f
-StandardOutput=journal+console
TimeoutSec=0
diff --git a/units/systemd-hwdb-update.service.in b/units/systemd-hwdb-update.service.in
index 791528e2b2..7135cff3d9 100644
--- a/units/systemd-hwdb-update.service.in
+++ b/units/systemd-hwdb-update.service.in
@@ -21,3 +21,4 @@ ConditionDirectoryNotEmpty=|/etc/udev/hwdb.d/
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootbindir@/systemd-hwdb update
+TimeoutSec=90s
diff --git a/units/systemd-importd.service.in b/units/systemd-importd.service.in
index 26759ea0fb..403f15316d 100644
--- a/units/systemd-importd.service.in
+++ b/units/systemd-importd.service.in
@@ -12,9 +12,7 @@ Documentation=man:systemd-importd.service(8)
[Service]
ExecStart=@rootlibexecdir@/systemd-importd
BusName=org.freedesktop.import1
-CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP
+CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP CAP_DAC_OVERRIDE
NoNewPrivileges=yes
WatchdogSec=1min
-PrivateTmp=yes
-ProtectSystem=full
-ProtectHome=yes
+KillMode=mixed
diff --git a/units/systemd-journald-audit.socket b/units/systemd-journald-audit.socket
index 35397aaeb8..541f2cf38d 100644
--- a/units/systemd-journald-audit.socket
+++ b/units/systemd-journald-audit.socket
@@ -11,6 +11,7 @@ Documentation=man:systemd-journald.service(8) man:journald.conf(5)
DefaultDependencies=no
Before=sockets.target
ConditionSecurity=audit
+ConditionCapability=CAP_AUDIT_READ
[Socket]
Service=systemd-journald.service
diff --git a/units/systemd-machine-id-commit.service.in b/units/systemd-machine-id-commit.service.in
index dd765b6608..cccbf7b626 100644
--- a/units/systemd-machine-id-commit.service.in
+++ b/units/systemd-machine-id-commit.service.in
@@ -19,3 +19,4 @@ ConditionPathIsMountPoint=/etc/machine-id
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-machine-id-commit
+TimeoutSec=30s
diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in
index 15f34d9db7..19c33959d6 100644
--- a/units/systemd-machined.service.in
+++ b/units/systemd-machined.service.in
@@ -15,10 +15,9 @@ After=machine.slice
[Service]
ExecStart=@rootlibexecdir@/systemd-machined
BusName=org.freedesktop.machine1
-CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH
+CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
WatchdogSec=1min
-PrivateTmp=yes
-PrivateDevices=yes
-PrivateNetwork=yes
-ProtectSystem=full
-ProtectHome=yes
+
+# Note that machined cannot be placed in a mount namespace, since it
+# needs access to the host's mount namespace in order to implement the
+# "machinectl bind" operation.
diff --git a/units/systemd-modules-load.service.in b/units/systemd-modules-load.service.in
index 040a0febe8..9de6d31349 100644
--- a/units/systemd-modules-load.service.in
+++ b/units/systemd-modules-load.service.in
@@ -24,3 +24,4 @@ ConditionKernelCommandLine=|rd.modules-load
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-modules-load
+TimeoutSec=90s
diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.m4.in
index 5a91b8e499..7f216f331c 100644
--- a/units/systemd-networkd.service.in
+++ b/units/systemd-networkd.service.m4.in
@@ -17,6 +17,13 @@ Before=network.target multi-user.target shutdown.target
Conflicts=shutdown.target
Wants=network.target
+m4_ifdef(`ENABLE_KDBUS',
+# On kdbus systems we pull in the busname explicitly, because it
+# carries policy that allows the daemon to acquire its name.
+Wants=org.freedesktop.network1.busname
+After=org.freedesktop.network1.busname
+
+)m4_dnl
[Service]
Type=notify
Restart=on-failure
diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in
index 3e26b53fd6..074b916d38 100644
--- a/units/systemd-nspawn@.service.in
+++ b/units/systemd-nspawn@.service.in
@@ -10,6 +10,7 @@ Description=Container %I
Documentation=man:systemd-nspawn(1)
PartOf=machines.target
Before=machines.target
+After=network.target
[Service]
ExecStart=@bindir@/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth --machine=%I
@@ -17,7 +18,22 @@ KillMode=mixed
Type=notify
RestartForceExitStatus=133
SuccessExitStatus=133
+Slice=machine.slice
Delegate=yes
+# Enforce a strict device policy, similar to the one nspawn configures
+# when it allocates its own scope unit. Make sure to keep these
+# policies in sync if you change them!
+DevicePolicy=strict
+DeviceAllow=/dev/null rwm
+DeviceAllow=/dev/zero rwm
+DeviceAllow=/dev/full rwm
+DeviceAllow=/dev/random rwm
+DeviceAllow=/dev/urandom rwm
+DeviceAllow=/dev/tty rwm
+DeviceAllow=/dev/net/tun rwm
+DeviceAllow=/dev/pts/ptmx rw
+DeviceAllow=char-pts rw
+
[Install]
WantedBy=machines.target
diff --git a/units/systemd-random-seed.service.in b/units/systemd-random-seed.service.in
index b55844b36f..115233268d 100644
--- a/units/systemd-random-seed.service.in
+++ b/units/systemd-random-seed.service.in
@@ -19,3 +19,4 @@ Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-random-seed load
ExecStop=@rootlibexecdir@/systemd-random-seed save
+TimeoutSec=30s
diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.m4.in
index b643da9a73..98ae564af6 100644
--- a/units/systemd-resolved.service.in
+++ b/units/systemd-resolved.service.m4.in
@@ -8,13 +8,15 @@
[Unit]
Description=Network Name Resolution
Documentation=man:systemd-resolved.service(8)
-After=systemd-networkd.service network.service
+After=systemd-networkd.service network.target
+m4_ifdef(`ENABLE_KDBUS',
# On kdbus systems we pull in the busname explicitly, because it
# carries policy that allows the daemon to acquire its name.
Wants=org.freedesktop.resolve1.busname
After=org.freedesktop.resolve1.busname
+)m4_dnl
[Service]
Type=notify
Restart=always
diff --git a/units/systemd-rfkill@.service.in b/units/systemd-rfkill@.service.in
index b48efe5d99..e53bf5fbba 100644
--- a/units/systemd-rfkill@.service.in
+++ b/units/systemd-rfkill@.service.in
@@ -20,3 +20,4 @@ Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-rfkill load %I
ExecStop=@rootlibexecdir@/systemd-rfkill save %I
+TimeoutSec=30s
diff --git a/units/systemd-sysctl.service.in b/units/systemd-sysctl.service.in
index fa72085f9e..d784c6426d 100644
--- a/units/systemd-sysctl.service.in
+++ b/units/systemd-sysctl.service.in
@@ -18,3 +18,4 @@ ConditionPathIsReadWrite=/proc/sys/
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-sysctl
+TimeoutSec=90s
diff --git a/units/systemd-sysusers.service.in b/units/systemd-sysusers.service.in
index ffd6d7747b..4d8309ab6b 100644
--- a/units/systemd-sysusers.service.in
+++ b/units/systemd-sysusers.service.in
@@ -18,3 +18,4 @@ ConditionNeedsUpdate=/etc
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootbindir@/systemd-sysusers
+TimeoutSec=90s
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
index 39edafc8d2..8219c95a08 100644
--- a/units/systemd-timesyncd.service.in
+++ b/units/systemd-timesyncd.service.in
@@ -9,7 +9,7 @@
Description=Network Time Synchronization
Documentation=man:systemd-timesyncd.service(8)
ConditionCapability=CAP_SYS_TIME
-ConditionVirtualization=no
+ConditionVirtualization=!container
DefaultDependencies=no
RequiresMountsFor=/var/lib/systemd/clock
After=systemd-remount-fs.service systemd-tmpfiles-setup.service systemd-sysusers.service
diff --git a/units/systemd-udev-trigger.service.in b/units/systemd-udev-trigger.service.in
index 0c33909cee..1e04d11fe3 100644
--- a/units/systemd-udev-trigger.service.in
+++ b/units/systemd-udev-trigger.service.in
@@ -10,7 +10,7 @@ Description=udev Coldplug all Devices
Documentation=man:udev(7) man:systemd-udevd.service(8)
DefaultDependencies=no
Wants=systemd-udevd.service
-After=systemd-udevd-kernel.socket systemd-udevd-control.socket
+After=systemd-udevd-kernel.socket systemd-udevd-control.socket systemd-hwdb-update.service
Before=sysinit.target
ConditionPathIsReadWrite=/sys
diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index f6acd6fe4c..e7216d61f2 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -10,7 +10,7 @@ Description=udev Kernel Device Manager
Documentation=man:systemd-udevd.service(8) man:udev(7)
DefaultDependencies=no
Wants=systemd-udevd-control.socket systemd-udevd-kernel.socket
-After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udev-hwdb-update.service systemd-sysusers.service
+After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-sysusers.service
Before=sysinit.target
ConditionPathIsReadWrite=/sys
@@ -22,3 +22,5 @@ Restart=always
RestartSec=0
ExecStart=@rootlibexecdir@/systemd-udevd
MountFlags=slave
+KillMode=mixed
+WatchdogSec=1min
diff --git a/units/systemd-user-sessions.service.in b/units/systemd-user-sessions.service.in
index 0869e73991..c09c05d4d5 100644
--- a/units/systemd-user-sessions.service.in
+++ b/units/systemd-user-sessions.service.in
@@ -8,7 +8,7 @@
[Unit]
Description=Permit User Sessions
Documentation=man:systemd-user-sessions.service(8)
-After=remote-fs.target
+After=remote-fs.target nss-user-lookup.target
[Service]
Type=oneshot
diff --git a/units/systemd-shutdownd.service.in b/units/var-lib-machines.mount
index d951742500..7eba68f214 100644
--- a/units/systemd-shutdownd.service.in
+++ b/units/var-lib-machines.mount
@@ -6,10 +6,11 @@
# (at your option) any later version.
[Unit]
-Description=Delayed Shutdown Service
-Documentation=man:systemd-shutdownd.service(8)
-DefaultDependencies=no
+Description=Virtual Machine and Container Storage
+ConditionPathExists=/var/lib/machines.raw
-[Service]
-ExecStart=@rootlibexecdir@/systemd-shutdownd
-NotifyAccess=all
+[Mount]
+What=/var/lib/machines.raw
+Where=/var/lib/machines
+Type=btrfs
+Options=loop